package jp.ehobby.io;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import org.junit.Test;

/**
 * SyslogWriter 単体テスト.
 */
public class SyslogWriterTest {


	/**
	 * SyslogWriter構築.
	 *
	 * @method SyslogWriter(String)
	 * @process new SyslogWriter("localhost") を実行する.
	 * @spec    SyslogWriterが構築されること.
	 *
	 * @throws IOException IOエラー
	 * @throws InterruptedException join失敗
	 */
	@Test
	public void testSyslogWriterString() throws IOException, InterruptedException {
		try (SyslogWriter writer = new SyslogWriter("localhost")) {		//$NON-NLS-1$

			TestSyslogServer server = new TestSyslogServer(514);
			server.start();

			writer.write("LOG MESSAGE");								//$NON-NLS-1$

			server.join();
			String data = server.getData();

			assertEquals("LOG MESSAGE", data);							//$NON-NLS-1$
		}
	}


	/**
	 * SyslogWriter構築(ポート指定).
	 *
	 * @method SyslogWriter(String, int)
	 * @process new SyslogWriter("localhost", 999) を実行する.
	 * @spec    999番ポートに書き出すSyslogWriterが構築されること.
	 *
	 * @throws IOException IOエラー
	 * @throws InterruptedException join失敗
	 */
	@Test
	public void testSyslogWriterStringInt() throws IOException, InterruptedException {
		try (SyslogWriter writer = new SyslogWriter("localhost", 999)) {	//$NON-NLS-1$

			TestSyslogServer server = new TestSyslogServer(999);
			server.start();

			writer.write("LOG MESSAGE");								//$NON-NLS-1$
			writer.flush();

			server.join();
			String data = server.getData();

			assertEquals("LOG MESSAGE", data);							//$NON-NLS-1$
		}
	}


	/**
	 * ログ書き込み.
	 * write(char[], int, int).
	 *
	 * @method write(char[], int, int)
	 * @process write(char[], int, int) にてログを書き出す.
	 * @spec    ログが書き出されること.
	 *
	 * @throws IOException IOエラー
	 * @throws InterruptedException join失敗
	 */
	@Test
	public void testWriteCharArrayIntInt() throws IOException, InterruptedException {
		try (SyslogWriter writer = new SyslogWriter("localhost")) {		//$NON-NLS-1$

			TestSyslogServer server = new TestSyslogServer(514);
			server.start();

			char[] wData = { 'X', 'L', 'O', 'G', ' ', 'M', 'E', 'S', 'S', 'A', 'G', 'E', 'X' };

			writer.write(wData, 1, wData.length - 2);

			server.join();
			String data = server.getData();

			assertEquals("LOG MESSAGE", data);							//$NON-NLS-1$
		}
	}


	/**
	 * ログ書き込み.
	 * write(String).
	 *
	 * @method write(String)
	 * @process write(String) にてログを書き出す.
	 * @spec    ログが書き出されること.
	 */
	@Test
	public void testWriteString() {
		// testSyslogWriterString にて実施
	}


	/**
	 * ログ書き込み(1024byteオーバー).
	 * write(String).
	 *
	 * @method write(String)
	 * @process write(String) にて1024byteを超えるデータを書き出す.
	 * @spec    1024byteまでログが書き出されること.
	 *
	 * @throws IOException IOエラー
	 * @throws InterruptedException join失敗
	 */
	@Test
	public void testWriteStringOver1024() throws IOException, InterruptedException {
		try (SyslogWriter writer = new SyslogWriter("localhost")) {		//$NON-NLS-1$

			TestSyslogServer server = new TestSyslogServer(514);
			server.start();

			char[] wData = new char[1280];
			for (int i = 0; i < wData.length; i++) {
				wData[i] = (char) i;
			}
			writer.write(new String(wData));

			server.join();
			String data = server.getData();

			byte[] bData = data.getBytes();
			assertEquals(1024, bData.length);
		}
	}


	/**
	 * flush.
	 *
	 * @method flush()
	 * @process flush()を実行する.
	 * @spec    何もおこらないこと.
	 */
	@Test
	public void testFlush() {
		// testSyslogWriterStringInt にて実施
	}


	/**
	 * Writerのclose
	 *
	 * @method close()
	 * @process close()を実行する.
	 * @spec    Writerがcloseされること..
	 */
	@Test
	public void testClose() {
		// testSyslogWriterString にて実施
	}


	////////////////////////////////////////////////////////////////////////////
	//
	// テスト用クラス
	//
	/**
	 * テスト用SyslogServer.
	 * @author kei-n
	 *
	 */
	class TestSyslogServer extends Thread {

		/** サーバポート.	*/
		private DatagramSocket servSocket;

		/** 受信データ.		*/
		private String recvData;

		/**
		 * テスト用SyslogServerを構築します.
		 *
		 * @param port ポート番号
		 * @throws SocketException ソケットエラー
		 */
		public TestSyslogServer(final int port) throws SocketException {
			this.servSocket = new DatagramSocket(port);
		}

		/**
		 * データ受信.
		 */
		@Override
		public void run() {
			try {
				byte[]         buffer = new byte[4096];
				DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
				this.servSocket.receive(packet);
				this.recvData = new String(packet.getData(), 0, packet.getLength());
			} catch (IOException e) {
				// Nothing to do.
			} finally {
				this.servSocket.close();
			}
		}

		/**
		 * 受信データを取得します.
		 * @return 受信データ
		 */
		public String getData() {
			return this.recvData;
		}

	}
}
