package com.github.visgeek.utils.testing;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Objects;

import org.junit.Assert;

import com.github.visgeek.utils.Action0;

public class Assert2 {
	private Assert2() {
	}

	public static <T> void assertSequanceEquals(Iterable<T> actual, Iterable<T> expected) {
		Assert2.assertSequanceEquals(null, actual, expected);
	}

	@SuppressWarnings("unchecked")
	public static <T> void assertSequanceEquals(String message, Iterable<T> actual, Iterable<T> expected) {
		LinkedList<T> list = new LinkedList<>();
		for (T item : expected) {
			list.add(item);
		}

		Assert2.assertSequanceEquals(message, actual, (T[]) list.toArray());
	}

	@SafeVarargs
	public static <T> void assertSequanceEquals(Iterable<T> actual, T... expected) {
		Assert2.assertSequanceEquals(null, actual, expected);
	}

	@SafeVarargs
	public static <T> void assertSequanceEquals(String message, Iterable<T> actual, T... expected) {
		Iterator<T> itr = actual.iterator();

		int count = 0;
		while (itr.hasNext()) {
			count++;

			Assert.assertTrue(message, count <= expected.length);

			T item = itr.next();
			Assert.assertTrue(message, Objects.equals(item, expected[count - 1]));
		}

		Assert.assertTrue(message, expected.length <= count);
	}

	public static void assertExceptionThrown(Class<? extends Exception> expectedExceptionClass, Action0 action) {
		Throwable raised = null;

		try {
			action.action();
		} catch (Throwable e) {
			raised = e;
		}

		Assert.assertTrue("exception was not thorwn", raised != null);
		Assert.assertTrue(String.format("expected:<%s> but was:<%s>", expectedExceptionClass.getName(), raised.getClass().getName()), Objects.equals(raised.getClass(), expectedExceptionClass));
	}

	public static void assertNullPointerExceptionThrown(String expectedMessage, Action0 action) {
		Throwable raised = null;

		try {
			action.action();
		} catch (Throwable e) {
			raised = e;
		}

		Class<NullPointerException> npeClass = NullPointerException.class;

		Assert.assertTrue("exception was not thorwn", raised != null);
		Assert.assertTrue(String.format("expected:<%s> but was:<%s>", npeClass.getName(), raised.getClass().getName()), Objects.equals(raised.getClass(), npeClass));
		Assert.assertEquals(expectedMessage, raised.getMessage());
	}

	static {
		// このクラスのカバレッジのためのコード
		new Assert2();

		for (Sequences seqs : new Sequences[] {
			new Sequences(Arrays.asList(1), 1),
			new Sequences(Arrays.asList(1), 2),
			new Sequences(Arrays.asList(1, 2), 1),
			new Sequences(Arrays.asList(1, 2), 1, 2, 3),
		}) {
			try {
				Assert2.assertSequanceEquals(seqs.seq1, seqs.seq2);
			} catch (AssertionError e) {
			  //
			}
		}

		for (ExceptionAndAction action : new ExceptionAndAction[] {
			new ExceptionAndAction(RuntimeException.class, () -> {
			}),
			new ExceptionAndAction(RuntimeException.class, () -> {
				throw new RuntimeException();
			}),
		}) {
			try {
				Assert2.assertExceptionThrown(action.expectedExceptionClass, action.action);
			} catch (AssertionError e) {
			  //
			}
		}
	}

	private static class Sequences {
		public Sequences(Iterable<Integer> seq1, Integer... seq2) {
			this.seq1 = seq1;
			this.seq2 = seq2;
		}

		private final Iterable<Integer> seq1;

		private final Integer[] seq2;
	}

	private static class ExceptionAndAction {
		public ExceptionAndAction(Class<? extends Exception> expectedExceptionClass, Action0 action) {
			this.expectedExceptionClass = expectedExceptionClass;
			this.action = action;
		}

		public final Class<? extends Exception> expectedExceptionClass;

		public final Action0 action;
	}
}

@@ -2408,16 +2408,251 @@
 %0D%0A%09%7D%0D%0A%0D%0A
+%09public static void assertExceptionNotThrown(Action0 action) %7B%0D%0A%09%09try %7B%0D%0A%09%09%09action.action();%0D%0A%09%09%7D catch (Throwable e) %7B%0D%0A%09%09%09String message = String.format(%22%25s was thorwn%22, e.getClass().getName());%0D%0A%09%09%09Assert.fail(message);%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A%0D%0A
 %09static 

テスト用メソッドを追加した。