package eu.dnetlib.contract.spring.beans;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;

import eu.dnetlib.contract.cp.ComplexCheckPoint;
import eu.dnetlib.contract.cp.DummyCheckPoint;
import eu.dnetlib.contract.cp.EntryCheckPoint;
import eu.dnetlib.contract.cp.ExceptionCheckPoint;
import eu.dnetlib.contract.cp.ResultCheckPoint;
import eu.dnetlib.contract.cp.eval.module.NotNullEvaluatorModule;
import eu.dnetlib.contract.node.RANDDefinitionNode;
import eu.dnetlib.contract.node.SEQDefinitionNode;
import eu.dnetlib.contract.runner.ContractTestRunnerConfiguration;
import eu.dnetlib.contract.runner.InvokerData;
import eu.dnetlib.contract.utils.SpringUtils;
import eu.dnetlib.resultset.CreatePullRSType;


/**
 * Custom contract spring beans configuration test.
 * @author mhorst
 *
 */
public class ContractSpringBeansTest {

	private String springConfigLocation = "classpath:/eu/dnetlib/contract/spring/beans/" +
			"contract-spring-beans-test.xml";
	
	private ApplicationContext ctx = null;
	
	@Before
	public void init() {
		ctx = SpringUtils.getSpringContext(springConfigLocation);
	}
	
	@Test
	public void testSEQElement() {
		SEQDefinitionNode testBean = (SEQDefinitionNode) ctx.getBean("SEQBean");
		assertNotNull(testBean);
		assertEquals(3, testBean.getSequence().size());
		assertTrue(testBean.getSequence().get(0) instanceof RANDDefinitionNode);
		assertTrue(testBean.getSequence().get(1) instanceof EntryCheckPoint);
		assertTrue(testBean.getSequence().get(2) instanceof RANDDefinitionNode);
		assertEquals(3, ((RANDDefinitionNode)testBean.getSequence().get(2)).getNodes().size());
		assertTrue(((RANDDefinitionNode)testBean.getSequence().get(2)).getNodes().get(0) instanceof EntryCheckPoint);
		assertTrue(((RANDDefinitionNode)testBean.getSequence().get(2)).getNodes().get(1) instanceof EntryCheckPoint);
		assertTrue(testBean != ((RANDDefinitionNode)testBean.getSequence().get(2)).getNodes().get(2));
	}
	
	@Test
	public void testCommonCPElement() {
		EntryCheckPoint entryCP = (EntryCheckPoint) ctx.getBean("EntryCPBean");
		assertNotNull(entryCP);
		assertFalse(entryCP.isCritical());
		assertEquals("someClassName",entryCP.getClassName());
		assertEquals("someMethodName",entryCP.getMethodName());
		assertNotNull(entryCP.getTarget());
		assertTrue(entryCP.getTarget() instanceof RANDDefinitionNode);
		RANDDefinitionNode referencedTarget = (RANDDefinitionNode) ctx.getBean("ReferencedTestBean");
		assertNotNull(referencedTarget);
		assertTrue(referencedTarget != entryCP.getTarget());
	}
	
	@Test
	public void testEntryCPElement() {
		EntryCheckPoint entryCP = (EntryCheckPoint) ctx.getBean("EntryCPBean");
		assertNotNull(entryCP);
		assertNotNull(entryCP.getArgs());
		assertEquals(3,entryCP.getArgs().length);
		RANDDefinitionNode referencedBean = (RANDDefinitionNode) ctx.getBean("ReferencedTestBean");
		assertEquals(12, entryCP.getArgs()[0]);
		assertTrue(referencedBean != entryCP.getArgs()[1]);
		assertNull(entryCP.getArgs()[2]);
		assertNotNull(entryCP.getArgsStrictChecking());
		assertEquals(3,entryCP.getArgsStrictChecking().length);
		assertTrue(entryCP.getArgsStrictChecking()[0]);
		assertTrue(entryCP.getArgsStrictChecking()[1]);
		assertFalse(entryCP.getArgsStrictChecking()[2]);
	}
	
	@Test
	public void testResultCPElement() {
		ResultCheckPoint resultCPRes = (ResultCheckPoint) ctx.getBean("ResultCPBean-Result");
		assertNotNull(resultCPRes);
		assertNotNull(resultCPRes.getResultDerivedFrom());
		assertTrue(String.class == resultCPRes.getResultDerivedFrom());
		RANDDefinitionNode referencedBean = (RANDDefinitionNode) ctx.getBean("ReferencedTestBean");
		assertNotNull(resultCPRes.getResult());
		assertTrue(referencedBean != resultCPRes.getResult());
		
		ResultCheckPoint resultCPEval = (ResultCheckPoint) ctx.getBean("ResultCPBean-Evaluator");
		assertNotNull(resultCPEval);
		assertNotNull(resultCPEval.getEvaluatorModule());
		assertTrue(resultCPEval.getEvaluatorModule() instanceof NotNullEvaluatorModule);
		
		ResultCheckPoint resultCPNull = (ResultCheckPoint) ctx.getBean("ResultCPBean-NullResult");
		assertNotNull(resultCPNull);
		assertNull(resultCPNull.getResult());
	}
	
	@Test
	public void testExceptionCPElement() {
		ExceptionCheckPoint excCP = (ExceptionCheckPoint) ctx.getBean("ExceptionCPBean");
		assertNotNull(excCP);
		assertNotNull(excCP.getExceptionClassName());
		assertEquals("java.lang.ContractTestRunnerException", excCP.getExceptionClassName());
		assertNotNull(excCP.getExceptionMessage());
		assertEquals("some message", excCP.getExceptionMessage());
		assertNotNull(excCP.getExceptionDerivedFrom());
		assertTrue(Exception.class == excCP.getExceptionDerivedFrom());
	}
	
	@Test
	public void testComplexCPElement() {
		ComplexCheckPoint complexCP = (ComplexCheckPoint) ctx.getBean("ComplexCPBean");
		assertNotNull(complexCP);
		assertNotNull(complexCP.getCheckPoints());
		assertEquals(3, complexCP.getCheckPoints().size());
		assertTrue(complexCP.getCheckPoints().get(0) instanceof EntryCheckPoint);
		assertTrue(complexCP.getCheckPoints().get(1) instanceof ExceptionCheckPoint);
		assertTrue(complexCP.getCheckPoints().get(2) instanceof ComplexCheckPoint);
		assertEquals(1, ((ComplexCheckPoint)complexCP.getCheckPoints().get(2)).getCheckPoints().size());
		assertTrue(((ComplexCheckPoint)complexCP.getCheckPoints().get(2)).getCheckPoints().get(0) 
				instanceof EntryCheckPoint);
	}
	
	@Test
	public void testDummyCPElement() {
		DummyCheckPoint dummyCP = (DummyCheckPoint) ctx.getBean("DummyCPBean");
		assertNotNull(dummyCP);
		assertFalse(dummyCP.isCritical());
		assertEquals("someClassName",dummyCP.getClassName());
		assertEquals("someMethodName",dummyCP.getMethodName());
		assertNotNull(dummyCP.getTarget());
		assertTrue(dummyCP.getTarget() instanceof RANDDefinitionNode);
		RANDDefinitionNode referencedTarget = (RANDDefinitionNode) ctx.getBean("ReferencedTestBean");
		assertNotNull(referencedTarget);
		assertTrue(referencedTarget != dummyCP.getTarget());
	}
	
	@Test
	public void testInvokerDataElement() {
		{
			InvokerData invokerData = (InvokerData) ctx.getBean("InvokerDataBean-Target");
			assertNotNull(invokerData);
			assertEquals("someMethodName", invokerData.getMethodName());
			assertEquals(21, invokerData.getTarget());
			assertEquals(1, invokerData.getArgs().length);
			assertEquals("someArg", invokerData.getArgs()[0]);
			assertEquals(1, invokerData.getParameterTypes().length);
			assertEquals(Integer.class, invokerData.getParameterTypes()[0]);
		}
		{
			InvokerData invokerData = (InvokerData) ctx.getBean("InvokerDataBean-TargetRef");
			assertNotNull(invokerData);
			assertEquals("someMethodName", invokerData.getMethodName());
			assertEquals(21, invokerData.getTarget());
			assertEquals(1, invokerData.getArgs().length);
			assertEquals("someArg", invokerData.getArgs()[0]);
			assertEquals(1, invokerData.getParameterTypes().length);
			assertEquals(Integer.class, invokerData.getParameterTypes()[0]);
		}
	}
	
	@Test
	public void testTestRunnerConfigElement() {
		ContractTestRunnerConfiguration testRunnerConfig = (ContractTestRunnerConfiguration) ctx.getBean("TestRunnerConfig");
		assertNotNull(testRunnerConfig);
		
		assertNotNull(testRunnerConfig.getExecutionDataList());
		assertNotNull(testRunnerConfig.getExecutionRunnable());
		
		assertNotNull(testRunnerConfig.getBeforeDataList());
		assertEquals(2, testRunnerConfig.getBeforeDataList().size());
		assertNotNull(testRunnerConfig.getBeforeRunnable());
		
		assertNotNull(testRunnerConfig.getAfterDataList());
		assertEquals(2, testRunnerConfig.getAfterDataList().size());
		assertNotNull(testRunnerConfig.getAfterRunnable());
	}
	
	@Test
	public void testXStreamBuilderElement() {
		{
			Object complexObject = ctx.getBean("ComplexObjectBean-Content");
			assertNotNull(complexObject);
			assertTrue(complexObject instanceof CreatePullRSType);
			assertEquals(1800, ((CreatePullRSType)complexObject).getKeepAliveTime().intValue());
			assertEquals(0, ((CreatePullRSType)complexObject).getTotal().intValue());
		}
		{
			Object complexObject = ctx.getBean("ComplexObjectBean-Loc-classpath");
			assertNotNull(complexObject);
			assertTrue(complexObject instanceof CreatePullRSType);
			assertEquals(1800, ((CreatePullRSType)complexObject).getKeepAliveTime().intValue());
			assertEquals(0, ((CreatePullRSType)complexObject).getTotal().intValue());
		}
		{
			Object complexObject = ctx.getBean("ComplexObjectBean-Loc-relative");
			assertNotNull(complexObject);
			assertTrue(complexObject instanceof CreatePullRSType);
			assertEquals(1800, ((CreatePullRSType)complexObject).getKeepAliveTime().intValue());
			assertEquals(0, ((CreatePullRSType)complexObject).getTotal().intValue());
		}
	}
}
