/*
 * jHears, acoustic fingerprinting framework.
 * Copyright (C) 2009-2010  Juha Heljoranta.
 *
 * This file is part of jHears.
 *
 * jHears is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * jHears is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with jHears.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.jhears.tuple;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Random;

import org.junit.Assert;
import org.junit.Test;

public class TupleTest {

	@SuppressWarnings("unchecked")
	@Test
	public void testTuplesFrom1to16() throws Exception {
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		String className = Tuple.class.getCanonicalName();

		Class<Tuple> tClass;
		Constructor<Tuple> constructor;
		Method method;
		Tuple tuple, copy;
		Integer actual;
		Random r;
		Integer[] initArgs;

		for (int i = 1; i < 17; i++) {
			long seed = new Random().nextLong();

			tClass = (Class<Tuple>) cl.loadClass(className + i);

			// instantiate
			constructor = (Constructor<Tuple>) tClass.getConstructors()[0];
			r = new Random(seed);
			initArgs = new Integer[i];
			for (int j = 0; j < i; j++) {
				initArgs[j] = Integer.valueOf(r.nextInt());
			}
			tuple = constructor.newInstance((Object[]) initArgs);

			// test size()
			Assert.assertEquals(i, tuple.size());

			// test get(int index);
			r = new Random(seed);
			for (int j = 0; j < i; j++) {
				Assert.assertEquals(r.nextInt(), tuple.get(j));
			}

			// test getX()
			r = new Random(seed);
			for (int j = 0; j < i; j++) {
				method = tClass.getMethod("get" + (j + 1), (Class[]) null);
				actual = (Integer) method.invoke(tuple, (Object[]) null);
				Assert.assertEquals(Integer.valueOf(r.nextInt()), actual);
			}

			// test head()
			r = new Random(seed);
			Integer expected = Integer.valueOf(r.nextInt());
			r = new Random(seed);
			for (int j = 0; j < i; j++) {
				method = tClass.getMethod("head", (Class[]) null);
				actual = (Integer) method.invoke(tuple, (Object[]) null);
				Assert.assertEquals(expected, actual);
			}

			// test tail()
			List<Object> tail = tuple.tail();
			Assert.assertEquals(i - 1, tail.size());
			r = new Random(seed);
			r.nextInt(); // take a head away
			for (int j = 0; j < i - 1; j++) {
				actual = (Integer) tail.get(j);
				Assert.assertEquals(Integer.valueOf(r.nextInt()), actual);
			}

			// test values()
			List<Object> values = tuple.values();
			Assert.assertEquals(i, values.size());
			r = new Random(seed);
			for (int j = 0; j < i; j++) {
				actual = (Integer) values.get(j);
				Assert.assertEquals(Integer.valueOf(r.nextInt()), actual);
			}

			// create identical tuple
			r = new Random(seed);
			initArgs = new Integer[i];
			for (int j = 0; j < i; j++) {
				initArgs[j] = Integer.valueOf(r.nextInt());
			}
			copy = constructor.newInstance((Object[]) initArgs);

			// test equals()
			Assert.assertEquals(tuple, copy);

			// test hashCode()
			Assert.assertEquals(tuple.hashCode(), copy.hashCode());
		}
	}

}
