package test.methodinterceptors;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import org.testng.Assert;
import org.testng.ITestNGListener;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import org.testng.TestNG;
import org.testng.annotations.Test;
import org.testng.xml.XmlSuite;
import org.testng.xml.internal.Parser;
import test.SimpleBaseTest;
import test.TestHelper;

public class MethodInterceptorTest extends SimpleBaseTest {

  private static final String XML =
      TestHelper.SUITE_XML_HEADER
          + "<suite name=\"Single\" verbose=\"0\">"
          + "<listeners>"
          + "  <listener class-name=\"test.methodinterceptors.NullMethodInterceptor\" />"
          + "</listeners>"
          + "  <test name=\"Single\" >"
          + "    <classes>"
          + "      <class name=\"test.methodinterceptors.FooTest\" />"
          + "     </classes>"
          + "  </test>"
          + "</suite>";

  @Test
  public void noMethodsShouldRun() {
    TestNG tng = create();
    tng.setTestClasses(new Class[] {FooTest.class});
    testNullInterceptor(tng);
  }

  private void testNullInterceptor(TestNG tng) {
    tng.setMethodInterceptor(new NullMethodInterceptor());
    TestListenerAdapter tla = new TestListenerAdapter();
    tng.addListener((ITestNGListener) tla);
    tng.run();

    Assert.assertEquals(tla.getPassedTests().size(), 0);
    Assert.assertEquals(tla.getFailedTests().size(), 0);
    Assert.assertEquals(tla.getSkippedTests().size(), 0);
  }

  private void testFast(boolean useInterceptor) {
    TestNG tng = create();
    tng.setTestClasses(new Class[] {FooTest.class});
    if (useInterceptor) {
      tng.setMethodInterceptor(new FastTestsFirstInterceptor());
    }
    TestListenerAdapter tla = new TestListenerAdapter();
    //    tng.setParallel("methods");
    tng.addListener((ITestNGListener) tla);
    tng.run();

    Assert.assertEquals(tla.getPassedTests().size(), 3);
    ITestResult first = tla.getPassedTests().get(0);

    String method = "zzzfast";
    if (useInterceptor) {
      Assert.assertEquals(first.getMethod().getMethodName(), method);
    } else {
      Assert.assertNotSame(first.getMethod().getMethodName(), method);
    }
  }

  @Test
  public void fastShouldRunFirst() {
    testFast(true /* use interceptor */);
  }

  @Test
  public void fastShouldNotRunFirst() {
    testFast(false /* don't use interceptor */);
  }

  @Test
  public void nullMethodInterceptorWorksInTestngXml() throws IOException {

    File f = File.createTempFile("testng-tests-", "");
    f.deleteOnExit();
    BufferedWriter bw = new BufferedWriter(new FileWriter(f));
    bw.write(XML);
    bw.close();

    List<XmlSuite> xmlSuites = new Parser(f.getAbsolutePath()).parseToList();

    TestNG tng = create();
    tng.setXmlSuites(xmlSuites);
    testNullInterceptor(tng);
  }

  @Test(timeOut = 1000)
  public void shouldNotLockUpWithInterceptorThatRemovesMethods() {
    TestNG tng = create(LockUpInterceptorSampleTest.class);
    tng.setParallel(XmlSuite.ParallelMode.METHODS);
    tng.run();
  }
}
