<?xml version="1.0" encoding="UTF-8"?>
<!--
    File:    nbtargets-testng.xml
    Version: 0.1

    Enable NetBeans to use TestNG to run and debug project tests.

    Audience: developers who wish to use NetBeans to debug project test
    suites written using TestNG, and are comfortable editing Ant's build.xml.

    Status: useful workaround

    Effects:
    - Test Commands run TestNG tests (annotated with @Test)
      * Test Project (project context menu):
        If test/testng.xml exists, runs its tests with TestNG, not JUnit.
        Otherwise runs tests in classes test/**/*.class with TestNG, not JUnit.
      * Run File (project/test/file context menu):
        Runs tests in test class with TestNG, not JUnit.
      * Debug File (project/test/file context menu):
        Runs tests in test class with TestNG, not JUnit.
        (Tip: breakpoint on java.lang.AssertionError to debug assert failure.)
        (Advanced tip: If Ant property testng.debug.groups is set to a comma
        separated list of group names, Debug File will run only tests marked
        with those groups.  Set it in Tools/Options/Misc/Ant/Properties.  For
        example, mark a single buggy test with @Test(groups={"debug123"}) and
        set testng.debug.groups=debug123 to run just that test with debugger.)
    - Reports (View via ~Files~ pane file context menu)
      * TestNG test results are written to build/test/results/index.html

    To install:
    0. Download TestNG (site listed below).
    1. Add TestNG jar to libraries (Tools/Library Manager)
    2. Add library to project test libraries.
    3. As of Netbeans 6.5, project "Compile on Save" must be off (issue#145772)
    4. Import this file in the build.xml of a NetBeans project.
       (Import it *before* build-impl.xml: among imports, first def prevails.)
    Example:

    <project name="MyProject" default="default" basedir=".">
      <description>Builds, tests, and runs the project MyProject.</description>
      <import file="nbtargets-testng.xml" /> 
      <import file="nbproject/build-impl.xml" />
    </project>

    Tested using
    - NetBeans 5.5 - 6.5beta
      (www.netbeans.org)
    - TestNG 5.4 - 5.8
      (www.testng.org)

    Caveats of this draft
    - This file, nbtargets-testng.xml, correctly reports
      "BUILD FAILED" if there were test failures.  However, this version
      does not work with the NetBeans codecoverage module (2.2.1, 2007.02)
      (the classes are not instrumented until after the tests are run, so no
      code coverage data is recorded).
    - In contrast, nbtargets-testng-cvg.xml works with the NetBeans
      codecoverage module (2.2.1, 2007.02).  But, that version uses antcall 
      to invoke conditional targets, so the result (tests.failed) is not set,
      so NetBeans incorrectly reports "BUILD SUCCESSFUL" despite failed tests.  
    - These Ant targets refer to the default directory property names,
      but adding a source or test directory more than once per project
      may cause NetBeans to use different property names for the
      directories.

    Related work
    - TestNG Support 4.6
      * Provides a TestNG test file creator in New File.
      * Provides a Show Test Results command (user avoids files tab)
      * Does not change behavior of Test Project (uses separate command).
      * Does not change behavior of Run File or Debug File on test files.

    For more info, see "NetBeans and Alternative Test Runners"
    http://www.geocities.com/nimarukan/netbeans/nbtargets/nbtargets-alt-test-runners.html
-->
<project name="nbtargets-testng">

  <!-- OVERRIDES -->

  <!-- override -do-test-run to use TestNG, not JUnit -->
  <target name="-do-test-run" 
          depends="init,compile-test,-pre-test-run,-testng-run"
          if="have.tests" />

  <!-- override -do-test-run-single to use TestNG, not JUnit -->
  <target name="-do-test-run-single" 
          depends="init,compile-test-single,-pre-test-run-single,-testng-run-single"
          if="have.tests"/>

  <!-- override -debug-start-debuggee-test to use TestNG, not JUnit -->
  <target name="-debug-start-debuggee-test" 
          depends="init,compile-test,-testng-debug-single"
          if="have.tests" />

  <!-- TESTNG-RUN -->

  <!-- Run tests specified in test/testng.xml or if no such file, then
       run all @Test methods in classes in test directory.
       (Only one of -testngxml-run and -testngclasses-run actually runs,
       depending on testng.xml.exists) -->
  <target name="-testng-run"
          depends="-testng-run-xml,-testng-run-classes"/>

  <!-- Set testng.xml.exists if file exists in source directory -->
  <target name="-check-testng-xml">
    <available property="testng.xml"
               file="${test.src.dir}${file.separator}testng.xml"
               value="${test.src.dir}${file.separator}testng.xml"/>
  </target>

  <!-- If test/testng.xml exists, run its tests -->
  <target name="-testng-run-xml"
          depends="-check-testng-xml"
          if="testng.xml">
    <!-- Call <java> rather than <testng> so NetBeans' Ant logger
         will link output stack trace lines to source files. -->
    <java classname="org.testng.TestNG"
          classpath="${run.test.classpath}"
          fork="true" resultproperty="testng.result.code">
      <jvmarg line="-enableassertions"/> <!-- TestNG tests often assert -->
      <jvmarg value="-Dtestng.test.classpath=${build.test.classes.dir}"/>
      <arg line="-d ${build.test.results.dir}"/>
      <arg line="-log 2 -usedefaultlisteners true"/> <!-- show stack trace -->
      <arg line="-sourcedir ${test.src.dir}"/> <!-- for jdk1.4 annotations -->
      <arg line="${testng.xml}"/> <!-- must be after '-'options -->
    </java>
    <echo level="info">View test results in ${build.test.results.dir}/index.html</echo>
    <echo level="info"/>
    <condition property="tests.failed">
      <not><equals arg1="0" arg2="${testng.result.code}"/></not>
    </condition>
  </target>

  <!-- If no test/testng.xml exists, look for @Test in all test/**/classes -->
  <target name="-testng-run-classes"
          depends="-check-testng-xml"
          unless="testng.xml" >
    <pathconvert property="testng.classnames.args" pathsep=" ">
      <path>
        <fileset dir="${build.test.classes.dir}" includes="**/*.class"/>
      </path>
      <map from="${basedir}${file.separator}" to="-testclass "/>
    </pathconvert>

    <!-- Call <java> rather than <testng> so NetBeans' Ant logger
         will link output stack trace lines to source files. -->
    <java classname="org.testng.TestNG"
          classpath="${run.test.classpath}"
          fork="true" resultproperty="testng.result.code">
      <jvmarg line="-enableassertions"/> <!-- TestNG tests often assert -->
      <jvmarg value="-Dtestng.test.classpath=${build.test.classes.dir}"/>
      <arg line="-d ${build.test.results.dir}"/>
      <arg line="-log 2 -usedefaultlisteners true"/> <!-- show stack trace -->
      <arg line="-sourcedir ${test.src.dir}"/> <!-- for jdk1.4 annotations -->
      <arg value="-suitename"/> <arg value="All test classes"/>
      <arg value="-testname"/> <arg value="All test classes"/>
      <arg line="${testng.classnames.args}"/>
    </java>

    <echo level="info">View test results in ${build.test.results.dir}/index.html</echo>
    <echo level="info"/>

    <condition property="tests.failed">
      <not><equals arg1="0" arg2="${testng.result.code}"/></not>
    </condition>
  </target>

  <!-- TESTNG-RUN-SINGLE -->

  <!-- Run selected test.includes file with TestNG -->
  <target name="-testng-run-single">
    <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
    
    <!-- Convert p1/C1.java p2/C2.java to "-testclass p1.C1 -testclass p2.C2"
         (contrary to TestNG doc, -testclass prefixes each class, not list) -->
    <pathconvert property="testng.classnames.args" dirsep="." pathsep=" ">
      <path><filelist dir="." files="${test.includes}"/></path>
      <mapper type="glob" from="*.java" to="*"/>
      <map from="${basedir}${file.separator}" to="-testclass "/>
    </pathconvert>
    <!-- Convert p1/C1.java p2/C2.java to "p1.C1_p2.C2" for title -->
    <pathconvert property="testng.suitename" pathsep="_" dirsep=".">
      <path><filelist dir="." files="${test.includes}"/></path>
      <mapper type="glob" from="*.java" to="*"/>
      <map from="${basedir}${file.separator}" to=""/>
    </pathconvert>

    <!-- Call <java> rather than <testng> so NetBeans' Ant logger
         will link output stack trace lines to source files. -->
    <java classname="org.testng.TestNG"
          classpath="${run.test.classpath}"
          fork="true" resultproperty="testng.result.code">
      <jvmarg line="-enableassertions"/> <!-- TestNG tests often assert --> 
      <jvmarg value="-Dtestng.test.classpath=${build.test.classes.dir}"/>
      <arg line="-d ${build.test.results.dir}"/>
      <arg line="-log 2 -usedefaultlisteners true"/> <!-- show stack trace -->
      <arg line="-sourcedir ${test.src.dir}"/> <!-- for jdk1.4 annotations -->
      <arg line="-suitename ${testng.suitename}"/>
      <arg line="-testname ${testng.suitename}"/>
      <arg line="${testng.classnames.args}"/>
    </java>

    <echo level="info">View test results in ${build.test.results.dir}/index.html</echo>
    <echo level="info"/>

    <condition property="tests.failed">
      <not><equals arg1="0" arg2="${testng.result.code}"/></not>
    </condition>
  </target>

  <!-- TESTNG-DEBUG-SINGLE -->

  <!-- Run selected test.class with TestNG in the debugger.
       User may set property testng.debug.groups to restrict TestNG run to
       specific annotated groups.  Only one of -testng-debug-single-groups
       and -testng-debug-single-nogroups actually runs. -->
  <target name="-testng-debug-single" 
          depends="-testng-debug-single-groups,-testng-debug-single-nogroups" />

  <target name="-check-testng-debug-groups">
    <condition property="testng.debug.groups.nonempty">
      <and>
        <isset property="testng.debug.groups"/>
        <not><equals arg1="${testng.debug.groups}" arg2="" trim="true"/></not>
      </and>
    </condition>
  </target>
  
  <target name="-testng-debug-single-nogroups"
          depends="-check-testng-debug-groups"
          unless="testng.debug.groups.nonempty">
    <fail unless="test.class">Must select one file in the IDE or set test.class</fail>

    <!-- (future work: pass resultProperty, and set tests.failed if nonzero) -->
    <j3:debug xmlns:j3="http://www.netbeans.org/ns/j2se-project/3"
              classname="org.testng.TestNG" classpath="${debug.test.classpath}">
      <customize>
        <jvmarg line="-enableassertions"/> <!-- TestNG tests often assert -->
        <jvmarg value="-Dtestng.test.classpath=${build.test.classes.dir}"/>
        <arg line="-d ${build.test.results.dir}"/>
        <arg line="-log 2 -usedefaultlisteners true"/> <!-- show stack trace -->
        <arg line="-sourcedir ${test.src.dir}"/> <!-- for jdk1.4 annotations -->
        <arg line="-suitename ${test.class}"/>
        <arg line="-testname ${test.class}"/>
        <arg line="-testclass ${test.class}"/>
      </customize>
    </j3:debug>
  </target>

  <target name="-testng-debug-single-groups"
          depends="-check-testng-debug-groups"
          if="testng.debug.groups.nonempty">
    <fail unless="test.class">Must select one file in the IDE or set test.class</fail>

    <!-- For suite name, convert comma separated list of groups (not files)
         to '_' separated -->
    <pathconvert property="testng.debug.groups.name" pathsep="_">
      <path><filelist dir="." files="${testng.debug.groups}"/></path>
      <map from="${basedir}${file.separator}" to=""/>
    </pathconvert>

    <!-- (future work: pass resultProperty, and set tests.failed if nonzero) -->
    <j3:debug xmlns:j3="http://www.netbeans.org/ns/j2se-project/3"
              classname="org.testng.TestNG" classpath="${debug.test.classpath}">
      <customize>
        <jvmarg line="-enableassertions"/> <!-- TestNG tests often assert -->
        <jvmarg value="-Dtestng.test.classpath=${build.test.classes.dir}"/>
        <arg line="-d ${build.test.results.dir}"/>
        <arg line="-log 2 -usedefaultlisteners true"/> <!-- show stack trace -->
        <arg line="-sourcedir ${test.src.dir}"/> <!-- for jdk1.4 annotations -->
        <arg line="-suitename ${test.class}__${testng.debug.groups.name}"/>
        <arg line="-testname ${test.class}__${testng.debug.groups.name}"/>
        <arg line="-testclass ${test.class}"/>
        <arg line="-groups ${testng.debug.groups}"/>
      </customize>
    </j3:debug>
  </target>

</project>
