Import sandbox antlibs

git-svn-id: https://svn.apache.org/repos/asf/ant/sandbox/antlibs/dotnet/trunk@161469 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/README b/README
new file mode 100644
index 0000000..70bc73d
--- /dev/null
+++ b/README
@@ -0,0 +1,38 @@
+dotnet sandbox README
+=====================
+
+Author:
+-------
+
+Stefan Bodewig, but feel free to go ahead and modify to your liking.
+
+Goal:
+-----
+
+Provide a simple infrastructure to execute .NET applications from
+within Ant for different VMs so that the user doesn't have to change
+the build file when she wants to run Mono on Linux and Microsoft's VM
+on Windows.
+
+This sounds far more ambitioned than it actually is.
+
+Short term goals are:
+
+* A <dotnetexec> task that can be used as
+
+  <dotnetexec executable="ExampleCsc.exe"/>
+
+  without testing for the environment (see the dotnet.xml build file
+  for Ant's tests as an example for what may become simpler with
+  this).
+
+* A <nant> task.
+
+* A <msbuild> task - if only for the fun of having it.
+
+* A <wix> task.
+
+* A <nunit> task.
+
+Those tasks should end up in an antlib of their own in order to be
+distributable independent of Ant.
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..6db1d04
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+ 
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+ 
+      http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="compile">
+
+  <target name="setup">
+    <property name="build" value="build"/>
+    <property name="build.classes" value="${build}/classes"/>
+    <property name="build.testclasses" value="${build}/test-classes"/>
+    <property name="build.lib" value="${build}/lib"/>
+    <property name="jarname" value="${build.lib}/dotnet.jar"/>
+    <mkdir dir="${build.classes}"/>
+    <mkdir dir="${build.testclasses}"/>
+    <mkdir dir="${build.lib}"/>
+  </target>
+
+  <target name="compile" depends="setup">
+    <javac 
+      srcdir="src/main"
+      destdir="${build.classes}"
+      debug="true"
+      />
+  </target>
+
+  <target name="antlib" depends="compile">
+    <copy todir="${build.classes}">
+      <fileset dir="src/main" includes="**/antlib.xml"/>
+    </copy>
+    <jar 
+      destfile="${jarname}"
+      basedir="${build.classes}"
+      />
+  </target>
+
+  <target name="setup-for-tests" depends="setup">
+    <ant 
+      antfile="../../../build.xml" 
+      target="test-jar" 
+      inheritall="false"
+      />
+  </target>
+
+  <target name="compile-tests" depends="setup-for-tests, antlib">
+    <javac 
+      srcdir="src/testcases"
+      destdir="${build.testclasses}"
+      debug="true"
+      >
+      <classpath>
+        <pathelement location="${jarname}"/>
+        <pathelement location="../../../build/lib/ant-testutil.jar"/>
+      </classpath>
+    </javac>
+  </target>
+
+  <target name="test" depends="compile-tests">
+    <junit
+      printsummary="false"
+      haltonfailure="false"
+      failureproperty="tests.failed"
+      filtertrace="false"
+      >
+      <classpath>
+        <pathelement location="${jarname}"/>
+        <pathelement location="../../../build/lib/ant-testutil.jar"/>
+        <pathelement location="${build.testclasses}"/>
+      </classpath>
+
+      <batchtest>
+        <fileset dir="src/testcases"/>
+      </batchtest>
+
+      <formatter type="plain" usefile="false"/>
+    </junit>
+
+    <fail if="tests.failed">At least one test has failed.</fail>
+  </target>
+</project>
\ No newline at end of file
diff --git a/docs/dotnetexec.html b/docs/dotnetexec.html
new file mode 100644
index 0000000..f66cd4a
--- /dev/null
+++ b/docs/dotnetexec.html
@@ -0,0 +1,32 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <title>DotNetExec Task</title>
+  </head>
+
+  <body>
+    <h2><a name="dotnetexec">DotNetExec</a></h2>
+
+    <h3>Description</h3>
+
+    <p>Executes a .NET assembly that's on your PATH or pointed to
+    directly by the executable attribute.</p>
+
+    <p>This task is an extension of Ant's <a
+    href="http://ant.apache.org/manual/CoreTasks/exec.html">exec</a>
+    task and supports all attributes and nested child elements of that
+    task.  Use the executable attribute to specify the name of the
+    assembly (including the extension).</p>
+
+    <p>This task allows you to choose the .NET framework via the
+    <code>vm</code> attribute.  The default value is "microsoft" on
+    Windows and "mono" on all other platforms.  "microsoft" is a magic
+    name that means "run the assembly as executable directly" - this
+    may also work for Mono on Linux systems with the binfmt feature
+    described in the <a
+    href="http://www.go-mono.org/faq.html#q86">Mono FAQ</a>.</p>
+
+    <hr/>
+      <p align="center">Copyright &copy; 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..f5fcb91
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,142 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <title>Dotnet Ant Library</title>
+  </head>
+
+  <body>
+    <h2>Introduction</h2>
+
+    <p>This is a library of Ant tasks that support using .NET
+    executables accross different platforms and in particular support
+    using common .NET development tools like <a
+    href="http://nant.sourceforge.net/">NAnt</a> or <a
+    href="http://www.nunit.org/">NUnit</a> from within Ant.</p>
+
+    <h2>Requirements</h2>
+
+    <p>The current version requires Ant 1.6.2 or later and may even
+    work better for a CVS build of Ant created from CVS HEAD.</p>
+
+    <h2>Where is it?</h2>
+
+    <p>The source code for the library currently lives in the
+    developer sandbox in Ant's CVS - <a
+    href="http://cvs.apache.org/viewcvs.cgi/ant/proposal/sandbox/dotnet/">http://cvs.apache.org/viewcvs.cgi/ant/proposal/sandbox/dotnet/</a>.
+    A binary can be found at <a
+    href="http://cvs.apache.org/~bodewig/dotnet/dotnet.jar">http://cvs.apache.org/~bodewig/dotnet/dotnet.jar</a>.
+    A zip file containing the docs is also <a
+    href="http://cvs.apache.org/~bodewig/dotnet/docs.zip">available</a>.</p>
+
+    <p>Note that these are temporary locations and may change later.</p>
+
+    <h2>Feedback</h2>
+
+    <p>Right now direct any feedback either directly to <a
+    href="mailto:bodewig@apache.org">me</a> or the <a
+    href="http://ant.apache.org/mail.html#Developer List">Ant
+    developer list</a>.
+
+    <h2>Installation</h2>
+
+    <p>If you are building this from sources, run the antlib target
+    and you'll get a file <code>dotnet.jar</code>.  If you've
+    downloaded <code>dotnet.jar</code>, you are already ready.</p>
+
+    <p>There are several ways to use the tasks:</p>
+
+    <ul>
+      <li>The traditional way:
+        <pre>
+          &lt;taskdef 
+            resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml"&gt;
+            &lt;classpath&gt;
+              &lt;pathelement location="YOUR-PATH-TO/dotnet.jar"/&gt;
+            &lt;/classpath&gt;
+          &lt;/taskdef&gt;
+        </pre>
+
+        With this you can use the tasks like plain Ant tasks, they'll
+        live in the default namespace.  I.e. if you can run
+        &lt;exec&gt; without any namespace prefix, you can do so for
+        &lt;dotnetexec&gt; as well.
+      </li>
+
+      <li>Similar, but assigning a namespace URI
+        <pre>
+          &lt;taskdef 
+            uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+            resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml"&gt;
+            &lt;classpath&gt;
+              &lt;pathelement location="YOUR-PATH-TO/dotnet.jar"/&gt;
+            &lt;/classpath&gt;
+          &lt;/taskdef&gt;
+        </pre>
+
+        This puts you task into a separate namespace than Ant's
+        namespace.  You would use the tasks like
+
+        <pre>
+          &lt;project
+            xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+            xmlns="antlib:org.apache.tools.ant"&gt;
+            ...
+            &lt;dn:nant&gt;
+              &lt;dn:target name="my-target"/&gt;
+            &lt;/dn:nant&gt;
+        </pre>
+
+        or
+
+        <pre>
+          &lt;nant xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"&gt;
+            &lt;target name="my-target"/&gt;
+          &lt;/nant&gt;
+        </pre>
+
+        or a variation thereof.
+      </li>
+
+      <li>Using Ant's autodiscovery.  Place <code>dotnet.jar</code>
+      into a directory and use <code>ant -lib
+      DIR-CONTAINING-THE-JAR</code> or copy it into
+      <code>ANT_HOME/lib</code> - and then in your build file, simply
+      declare the namespace on the <code>project</code> tag:
+
+        <pre>
+          &lt;project
+            xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+            xmlns="antlib:org.apache.tools.ant"&gt;
+        </pre>
+
+        And all tasks of this library will automatically be available
+        in the <code>dn</code> namespace without any
+        <code>taskdef</code>.
+      </li>
+    </ul>
+
+    <h2>Tasks</h2>
+
+    <ul>
+      <li><a href="dotnetexec.html">dotnetexec</a> - run a .NET
+      assembly that's in your PATH.  You can chose the framework that
+      is going to be used - defaults to Mono on non-Windows platforms
+      and Microsoft's on Windows.</li>
+
+      <li><a href="nant.html">nant</a> - execute the NAnt build
+      tool.</li>
+
+      <li><a href="msbuild.html">msbuild</a> - execute the MSBuild build
+      tool, untested.</li>
+
+      <li><a href="wix.html">wix</a> - execute the WiX toolset, untested.</li>
+
+      <li><a href="nunit.html">nunit</a> - execute the
+      nunit-console.exe <a href="http://www.nunit.org/">NUnit</a>
+      test runner.</li>
+    </ul>
+
+    <hr/>
+      <p align="center">Copyright &copy; 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+  </body>
+</html>
diff --git a/docs/msbuild.html b/docs/msbuild.html
new file mode 100644
index 0000000..2ac93bc
--- /dev/null
+++ b/docs/msbuild.html
@@ -0,0 +1,109 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <title>MSBuild Task</title>
+  </head>
+
+  <body>
+    <h2><a name="dotnetexec">MSBuild</a></h2>
+
+    <h3>Description</h3>
+
+    <p>Runs the MSBuild build tool presented at the 2003 PDC.  This
+    task is completely untested as the developers have no access to
+    the tool, it has been implemented by looking at the docs only.</p>
+
+    <p>You can either use an existing build file or nest a build file
+    (snippet) as a child into the task.  If you don't specify either,
+    MSBuild's default build file search algorithm will apply.</p>
+
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">buildfile</td>
+        <td valign="top">External build file to invoke MSBuild on.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">vm</td>
+        <td valign="top">Same as <a
+            href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+          Specify the framework to use.</td>
+        <td align="center">No.</td>
+      </tr>
+    </table>
+
+    <h3>Parameters specified as nested elements</h3>
+    <h4>target</h4>
+
+    <p><code>target</code> has a single required attribute name -
+    specifies a target to be run.</p>
+
+    <h4>property</h4>
+
+    <p><code>property</code> has two required attributes.  name and
+    value that specify name and value of a property that is to be
+    defined in the MSBuild invocation.</p>
+
+    <h4>build</h4>
+
+    <p>This element allows no attributes.  You can nest a MSBuild build
+    file into it and MSBuild will be executed on that.  You can also nest
+    a build file snippet instead and Ant will wrap the necessary MSBuild
+    <code>&lt;Project&gt; around it.</code></p>
+
+    <h3>Examples</h3>
+
+    <p>Let MSBuild search for a *.proj file in the (Ant) project's base
+    directory and execute the default target in it:</p>
+
+    <pre>&lt;msbuild/&gt;</pre>
+    
+    <p>Let MSBuild execute the targets named foo and bar in the build
+    file msbuild.proj in Ant's basedir and pass the property
+    <code>/property:test=testvalue</code> to it:</p>
+
+    <pre>
+      &lt;msbuild buildfile="msbuild.proj"&gt;
+        &lt;target name="foo"/&gt;
+        &lt;target name="bar"/&gt;
+        &lt;property name="test" value="testvalue"/&gt;
+      &lt;/msbuild&gt;
+    </pre>
+
+    <p>Define a build file embeded into the task, let MSBuild execute the
+    echo target of that build file.</p>
+
+    <pre>
+      &lt;msbuild&gt;
+        &lt;target name="echo"&gt;
+        &lt;build&gt;
+          &lt;Project DefaultTargets="empty"&gt;
+            &lt;Target Name="empty"/&gt;
+            &lt;Target Name="echo"&gt;
+              &lt;Task Name="Echo" Message="This is MSBuild"/&gt;
+            &lt;/Target&gt;
+          &lt;/Project&gt;
+        &lt;/build&gt;
+      &lt;/msbuild&gt;
+    </pre>
+
+    <p>Run MSBuild's Echo task (if there actually is one):</p>
+
+    <pre>
+      &lt;msbuild&gt;
+        &lt;build&gt;
+          &lt;Task Name="Echo" Message="This is MSBuild"/&gt;
+        &lt;/build&gt;
+      &lt;/msbuild&gt;
+    </pre>
+
+    <hr/>
+      <p align="center">Copyright &copy; 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/nant.html b/docs/nant.html
new file mode 100644
index 0000000..07a92a2
--- /dev/null
+++ b/docs/nant.html
@@ -0,0 +1,108 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <title>NAnt Task</title>
+  </head>
+
+  <body>
+    <h2><a name="dotnetexec">NAnt</a></h2>
+
+    <h3>Description</h3>
+
+    <p>Runs the <a href="http://nant.sourceforge.net/">NAnt</a> build
+    tool.</p>
+
+    <p>You can either use an existing build file or nest a build file
+    (snippet) as a child into the task.  If you don't specify either,
+    NAnt's default build file search algorithm will apply.</p>
+
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">buildfile</td>
+        <td valign="top">External build file to invoke NAnt on.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">vm</td>
+        <td valign="top">Same as <a
+            href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+          Specify the framework to use.</td>
+        <td align="center">No.</td>
+      </tr>
+    </table>
+
+    <h3>Parameters specified as nested elements</h3>
+    <h4>target</h4>
+
+    <p><code>target</code> has a single required attribute name -
+    specifies a target to be run.</p>
+
+    <h4>property</h4>
+
+    <p><code>property</code> has two required attributes.  name and
+    value that specify name and value of a property that is to be
+    defined in the NAnt invocation.</p>
+
+    <h4>build</h4>
+
+    <p>This element allows no attributes.  You can nest a NAnt build
+    file into it and NAnt will be executed on that.  You can also nest
+    a build file snippet instead and Ant will wrap the necessary NAnt
+    <code>&lt;project&gt; around it.</code></p>
+
+    <h3>Examples</h3>
+
+    <p>Let NAnt search for a *.build file in the (Ant) project's base
+    directory and execute the default target in it:</p>
+
+    <pre>&lt;nant/&gt;</pre>
+    
+    <p>Let NAnt execute the targets named foo and bar in the build
+    file nant.build in Ant's basedir and pass the property
+    <code>-D:test=testvalue</code> to it:</p>
+
+    <pre>
+      &lt;nant buildfile="nant.build"&gt;
+        &lt;target name="foo"/&gt;
+        &lt;target name="bar"/&gt;
+        &lt;property name="test" value="testvalue"/&gt;
+      &lt;/nant&gt;
+    </pre>
+
+    <p>Define a build file embeded into the task, let NAnt execute the
+    echo target of that build file.</p>
+
+    <pre>
+      &lt;nant&gt;
+        &lt;target name="echo"&gt;
+        &lt;build&gt;
+          &lt;project basedir="." default="empty"&gt;
+            &lt;target name="empty"/&gt;
+            &lt;target name="echo"&gt;
+              &lt;echo message="this is NAnt"/&gt;
+            &lt;/target&gt;
+          &lt;/project&gt;
+        &lt;/build&gt;
+      &lt;/nant&gt;
+    </pre>
+
+    <p>Run NAnt's echo task:</p>
+
+    <pre>
+      &lt;nant&gt;
+        &lt;build&gt;
+          &lt;echo message="this is NAnt"/&gt;
+        &lt;/build&gt;
+      &lt;/nant&gt;
+    </pre>
+
+    <hr/>
+      <p align="center">Copyright &copy; 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/nunit.html b/docs/nunit.html
new file mode 100644
index 0000000..e7ddd11
--- /dev/null
+++ b/docs/nunit.html
@@ -0,0 +1,177 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <title>NUnit Task</title>
+  </head>
+
+  <body>
+    <h2><a name="dotnetexec">NUnit</a></h2>
+
+    <h3>Description</h3>
+
+    <p>Runs the <a href="http://www.nunit.org/">NUnit</a> console
+    test runner.</p>
+
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">vm</td>
+        <td valign="top">Same as <a
+            href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+          Specify the framework to use.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">config</td>
+        <td valign="top">Config file to use</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">output</td>
+        <td valign="top">Where test output should go.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">error</td>
+        <td valign="top">Where test error output should go.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">xmlout</td>
+        <td valign="top">Where NUnit's XML output should go.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">transform</td>
+        <td valign="top">The transformation to apply.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">thread</td>
+        <td valign="top">Causes a separate thread to be created for
+        running the tests - see the NUnit documentation for
+        details.</td>
+        <td align="center">No - defaults to false.</td>
+      </tr>
+      <tr>
+        <td valign="top">noshadow</td>
+        <td valign="top">Disables shadow copying of the assembly in
+        order to provide improved performance..</td>
+        <td align="center">No - defaults to false.</td>
+      </tr>
+      <tr>
+        <td valign="top">fixture</td>
+        <td valign="top">Test fixture to run.</td>
+        <td align="center">No.</td>
+      </tr>
+      <tr>
+        <td valign="top">labels</td>
+        <td valign="top">Causes an identifying label to be displayed
+        at the start of each test case.</td>
+        <td align="center">No - defaults to false.</td>
+      </tr>
+      <tr>
+        <td valign="top">failOnError</td>
+        <td valign="top">Stops the build if NUnit returns with a code
+        indicating an error or failure.</td>
+        <td align="center">No - defaults to false.</td>
+      </tr>
+    </table>
+
+    <h3>Parameters specified as nested elements</h3>
+    <h4>testassembly</h4>
+
+    <p><code>testassembly</code> has a single required attribute name -
+    specifies an assembly or a project file holding tests.</p>
+
+    <h4>include/exclude</h4>
+
+    <p><code>in/exclude</code> have a single required attribute name -
+    specifies a category to include or exclude from the tests.</p>
+
+    <p><b>Note</b> that in current versions of NUnit (up to 2.2) you
+    may choose to either include or exclude categories in a run, but
+    not both.  This task does <b>not</b> enforce this restriction
+    since future versions of NUnit may change behavior.</p>
+
+    <h4>redirector</h4>
+
+    <p>A nested <a
+    href="http://ant.apache.org/manual/CoreTypes/redirector.html">I/O
+    Redirector</a> can be specified.  Any file mapping is done using a
+    <code>null</code> sourcefile; therefore not all <a
+    href="http://ant.apache.org/manual/CoreTypes/mapper.html">Mapper</a>
+    types will return results.</p>
+
+    <h4>env</h4> <p>It is possible to specify environment variables to
+    pass to the system command via nested <code>&lt;env&gt;</code>
+    elements.  They support the same attributes as the nested <a
+    href="http://ant.apache.org/manual/CoreTasks/exec.html#env"><code>env</code>
+    element of the <code>&lt;exec&gt;</code> task</a>.</p>
+
+    <h3>Examples</h3>
+
+    <h4>Specify an assembly or project:</h4>
+
+    <pre>
+      &lt;nunit&gt;
+        &lt;testassembly name="nunit.tests.dll"/&gt;
+      &lt;/nunit&gt;
+    </pre>
+    
+    <p>or</p>
+
+    <pre>
+      &lt;nunit&gt;
+        &lt;testassembly name="nunit.tests.csproj"/&gt;
+      &lt;/nunit&gt;
+    </pre>
+    
+    <h4>Specifying an Assembly and a Fixture</h4>
+
+    <pre>
+      &lt;nunit fixture="NUnit.Tests.AssertionTests"&gt;
+        &lt;testassembly name="nunit.tests.dll"/&gt;
+      &lt;/nunit&gt;
+    </pre>
+
+    <h4>Specifying Test Categories to Include</h4>
+
+    <pre>
+      &lt;nunit&gt;
+        &lt;testassembly name="nunit.tests.dll"/&gt;
+        &lt;include name="Baseline"/&gt;
+      &lt;/nunit&gt;
+    </pre>
+
+    <h4>Specifying the XML file name</h4>
+
+    <pre>
+      &lt;nunit xmlout="console-test.xml"&gt;
+        &lt;testassembly name="nunit.tests.dll"/&gt;
+      &lt;/nunit&gt;
+    </pre>
+
+    <p>changes the name of the output file to "console-test.xml" -
+    note that this task will resolve file names relative to the
+    project's base directory, not the current working directory.</p>
+
+    <h4>Specifying Multiple Assemblies</h4>
+
+    <pre>
+      &lt;nunit&gt;
+        &lt;testassembly name="assembly1.dll"/&gt;
+        &lt;testassembly name="assembly2.dll"/&gt;
+        &lt;testassembly name="assembly3.dll"/&gt;
+      &lt;/nunit&gt;
+    </pre>
+
+    <hr/>
+      <p align="center">Copyright &copy; 2004 The Apache Software Foundation. All rights Reserved.</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/wix.html b/docs/wix.html
new file mode 100644
index 0000000..a79ff99
--- /dev/null
+++ b/docs/wix.html
@@ -0,0 +1,177 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <title>Wix Task</title>
+  </head>
+
+  <body>
+    <h2>Wix</h2>
+
+    <h3>Description</h3>
+
+    <p>Runs the candle, light or both from the <a
+    href="http://sourceforge.net/projects/wix">Wix</a> toolset.</p>
+
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">source</td>
+        <td valign="top">The single source file to process.</td>
+        <td align="center">Either this or at least one nested
+        &lt;sources&gt; set.</td>
+      </tr>
+      <tr>
+        <td valign="top">target</td>
+        <td valign="top">The expected target file.</td>
+        <td align="center">Yes, unless you run candle without light.</td>
+      </tr>
+      <tr>
+        <td valign="top">mode</td>
+        <td valign="top">Which part of the toolset to run, one of
+        &quot;candle&quot;, &quot;light&quot; or
+        &quot;both&quot;.</td>
+        <td align="center">No, default is &quot;both&quot;.</td>
+      </tr>
+      <tr>
+        <td valign="top">vm</td>
+        <td valign="top">Same as <a
+            href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+          Specify the framework to use.</td>
+        <td align="center">No.</td>
+      </tr>
+    </table>
+
+    <h3>Parameters specified as nested elements</h3>
+
+    <h4>sources</h4>
+
+    <p>Specify source files that shall be passed on the command line.
+    This is a <a
+    href="http://ant.apache.org/manual/CoreTypes/fileset.html">fileset</a>.</p>
+
+    <h4>moresources</h4>
+
+    <p>Specify source files that shall not be passed on the command
+    line.  This is a <a
+    href="http://ant.apache.org/manual/CoreTypes/fileset.html">fileset</a>.</p>
+
+    <p>Typically this would list include files when running candle or
+    the files that vecome part of the MSI file when running light.
+    The files in this set are only used for timestamp comparisons.  If
+    neither these files nor the given &quot;normal&quot; sources are
+    newer than the expected target, the task won't do anything.</p>
+
+
+    <h3>Examples</h3>
+
+    <p>Create <code>product.wixobj</code> from <code>product.wxs</code>:</p>
+
+    <pre>
+      &lt;wix mode="candle" source="product.wxs"/&gt;
+    </pre>
+
+    <p>The same but using a nested sources element:</p>
+
+    <pre>
+      &lt;wix mode="candle"&gt;
+        &lt;sources dir="."&gt;
+          &lt;include name="product.wxs"/&gt;
+        &lt;/sources&gt;
+      &lt;/wix&gt;
+    </pre>
+
+    <p>Create <code>product.msi</code> from <code>product.wixobj</code>:</p>
+
+    <pre>
+      &lt;wix mode="light" source="product.wixobj" target="product.msi"/&gt;
+    </pre>
+
+    <p>Combine the examples into a single step:</p>
+
+    <pre>
+      &lt;wix source="product.wxs" target="product.msi"/&gt;
+    </pre>
+
+    <p>Note that the task wouldn't do anything if
+    <code>product.wxs</code> was older than
+    <code>product.wixobj</code> and <code>product.wixobj</code> was
+    older than <code>product.msi</code>.</p>
+
+    <p>Compile multiple <code>.wxs</code> files at once:</p>
+
+    <pre>
+      &lt;wix mode="candle"&gt;
+        &lt;sources dir="."&gt;
+          &lt;include name="*.wxs"/&gt;
+        &lt;/sources&gt;
+      &lt;/wix&gt;
+    </pre>
+
+    <p>Compile multiple <code>.wxs</code> files at once, specify some
+    include files in addition to that:</p>
+
+    <pre>
+      &lt;wix mode="candle"&gt;
+        &lt;sources dir="."&gt;
+          &lt;include name="*.wxs"/&gt;
+        &lt;/sources&gt;
+        &lt;moresources dir="."&gt;
+          &lt;include name="*.wxi"/&gt;
+        &lt;/moresources&gt;
+      &lt;/wix&gt;
+    </pre>
+
+    <p>Link multiple <code>.wixobj</code> files at once:</p>
+
+    <pre>
+      &lt;wix mode="light" target="product.msi"&gt;
+        &lt;sources dir="."&gt;
+          &lt;include name="*.wixobj"/&gt;
+        &lt;/sources&gt;
+      &lt;/wix&gt;
+    </pre>
+
+    <p>Link multiple <code>.wixobj</code> files at once and specify
+    that the files in directory &quot;source&quot; will become part of
+    the package:</p>
+
+    <pre>
+      &lt;wix mode="light" target="product.msi"&gt;
+        &lt;sources dir="."&gt;
+          &lt;include name="*.wixobj"/&gt;
+        &lt;/sources&gt;
+        &lt;moresources dir="source"/&gt;
+      &lt;/wix&gt;
+    </pre>
+
+    <pre>Combine multiple <code>.wxs</code> files and include files
+    into a single package and specify that the package will contain
+    files from the source directory:</pre>
+
+    <pre>
+      &lt;wix target="product.msi"&gt;
+        &lt;sources dir="."&gt;
+          &lt;include name="*.wxs"/&gt;
+        &lt;/sources&gt;
+        &lt;moresources dir="."&gt;
+          &lt;include name="*.wxi"/&gt;
+        &lt;/moresources&gt;
+        &lt;moresources dir="source"/&gt;
+      &lt;/wix&gt;
+    </pre>
+
+    <p>Again, if the intermediate <code>.wixobj</code> files are newer
+    that the corresponding <code>.wxs</code> files (and all include
+    files) the candle step will be skipped.  If
+    <code>product.msi</code> is newer than all files, the task won't
+    do anything.</p>
+
+    <hr/>
+      <p align="center">Copyright &copy; 2004 The Apache Software Foundation. All rights Reserved.</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/src/etc/testcases/dotnetexec.xml b/src/etc/testcases/dotnetexec.xml
new file mode 100644
index 0000000..2aaef4b
--- /dev/null
+++ b/src/etc/testcases/dotnetexec.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="dotnet" basedir="." default="testCSC"
+  xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+  <property environment="env"/>
+  <property name="build.dir" location="build"/>
+  <property name="src.dir" location="src"/>
+
+  <property name="out.csc" location="${src.dir}/out.cs"/>
+  <property name="out.app" location="${build.dir}/out.exe"/>
+  <property name="out.type" value="exe"/>
+
+  <taskdef 
+    uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+    resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+    <classpath>
+      <pathelement location="../../../build/lib/dotnet.jar"/>
+    </classpath>
+  </taskdef>
+
+  <target name="probe_for_apps" >
+   <condition property="csc.found">
+      <or>
+        <available file="csc"     filepath="${env.PATH}" />
+        <available file="csc.exe" filepath="${env.PATH}" />
+        <available file="csc.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> csc.found=${csc.found}</echo>
+
+   <!-- Mono C# compiler -->
+   <condition property="mcs.found">
+      <available file="mcs"     filepath="${env.PATH}" />
+    </condition>
+   <echo> mcs.found=${mcs.found}</echo>
+
+   <!-- any C# compiler -->
+   <condition property="c#.found">
+      <or>
+        <isset property="csc.found"/>
+        <isset property="mcs.found"/>
+      </or>
+   </condition>
+  </target>
+
+  <target name="init" depends="probe_for_apps">
+    <mkdir dir="${build.dir}"/>
+    <property name="testCSC.exe"
+      location="${build.dir}/ExampleCsc.exe" />
+  </target>
+
+  <target name="teardown">
+    <delete dir="${build.dir}"/>
+  </target>
+
+  <target name="validate_csc" depends="init">
+    <fail unless="c#.found">Needed C# compiler is missing</fail>
+  </target>
+
+  <target name="testCSC" depends="validate_csc">
+    <csc
+      destFile="${testCSC.exe}"
+      targetType="exe">
+      <src dir="${src.dir}" includes="ex*.cs"/>
+    </csc>
+    <available property="app.created" file="${testCSC.exe}"/>
+    <fail unless="app.created">No app ${testCSC.exe} created</fail>
+    <dn:dotnetexec executable="${testCSC.exe}" failonerror="true" />
+    <delete file="${testCSC.exe}"/>
+  </target>
+
+</project>
+
diff --git a/src/etc/testcases/msbuild.xml b/src/etc/testcases/msbuild.xml
new file mode 100644
index 0000000..dd1f136
--- /dev/null
+++ b/src/etc/testcases/msbuild.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="msbuild" basedir="." default="echo"
+  xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+  <taskdef 
+    uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+    resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+    <classpath>
+      <pathelement location="../../../build/lib/dotnet.jar"/>
+    </classpath>
+  </taskdef>
+
+  <property environment="env"/>
+  <condition property="msbuild.found">
+    <or>
+      <available file="MSBuild.exe" filepath="${env.PATH}"/>
+      <available file="MSBuild.exe" filepath="${env.Path}"/>
+      <available file="MSBuild.exe"/>
+    </or>
+  </condition>
+
+  <target name="echo">
+    <msbuild 
+      buildfile="src/msbuild.proj" 
+      xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+      >
+      <target name="echo"/>
+      <property name="foo" value="bar"/>
+    </msbuild>
+  </target>
+
+  <target name="nested-file">
+    <property name="foo" value="bar"/>
+    <msbuild 
+      xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+      >
+      <build>
+        <Project DefaultTargets="echo">
+          <Target Name="echo">
+            <Task Name="Echo" Message="foo is ${foo}"/>
+          </Target>
+        </Project>
+      </build>
+    </msbuild>
+  </target>
+
+  <target name="nested-task">
+    <property name="foo" value="bar"/>
+    <msbuild 
+      xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+      >
+      <build>
+        <Task Name="Echo" Message="foo is ${foo}"/>
+      </build>
+    </msbuild>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/src/etc/testcases/nant.xml b/src/etc/testcases/nant.xml
new file mode 100644
index 0000000..172d0e7
--- /dev/null
+++ b/src/etc/testcases/nant.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="nant" basedir="." default="echo"
+  xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+  <taskdef 
+    uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+    resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+    <classpath>
+      <pathelement location="../../../build/lib/dotnet.jar"/>
+    </classpath>
+  </taskdef>
+
+  <property environment="env"/>
+  <condition property="nant.found">
+    <or>
+      <available file="NAnt.exe" filepath="${env.PATH}"/>
+      <available file="NAnt.exe" filepath="${env.Path}"/>
+      <available file="NAnt.exe"/>
+    </or>
+  </condition>
+
+  <target name="echo">
+    <nant 
+      buildfile="src/nant.build" 
+      xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+      >
+      <target name="echo"/>
+      <property name="foo" value="bar"/>
+    </nant>
+  </target>
+
+  <target name="nested-file">
+    <property name="foo" value="bar"/>
+    <nant
+      xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+      >
+      <build>
+        <project basedir="." default="echo">
+          <target name="echo">
+            <echo message="foo is ${foo}"/>
+          </target>
+        </project>
+      </build>
+    </nant>
+  </target>
+
+  <target name="nested-task">
+    <property name="foo" value="bar"/>
+    <nant
+      xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+      >
+      <build>
+        <echo message="foo is ${foo}"/>
+      </build>
+    </nant>
+  </target>
+</project>
\ No newline at end of file
diff --git a/src/etc/testcases/nunit.xml b/src/etc/testcases/nunit.xml
new file mode 100644
index 0000000..ded9b58
--- /dev/null
+++ b/src/etc/testcases/nunit.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="nunit" basedir="." default="echo"
+  xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+  <property name="build.dir" value="build"/>
+  <property name="src.dir" location="src"/>
+
+  <taskdef 
+    uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+    resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+    <classpath>
+      <pathelement location="../../../build/lib/dotnet.jar"/>
+    </classpath>
+  </taskdef>
+
+  <property environment="env"/>
+  <condition property="nunit.found">
+    <or>
+      <available file="nunit-console.exe" filepath="${env.PATH}"/>
+      <available file="nunit-console.exe" filepath="${env.Path}"/>
+      <available file="nunit-console.exe"/>
+    </or>
+  </condition>
+
+  <target name="no-assembly">
+    <dn:nunit/>
+  </target>
+
+  <target name="compile-pass">
+    <mkdir dir="${build.dir}"/>
+    <csc destFile="${build.dir}/Pass.dll"
+      targetType="library" references="nunit.framework.dll">
+      <src dir="${src.dir}" includes="pass.cs"/>
+    </csc>
+  </target>
+
+  <target name="compile-fail">
+    <mkdir dir="${build.dir}"/>
+    <csc destFile="${build.dir}/Fail.dll" 
+      targetType="library" references="nunit.framework.dll">
+      <src dir="${src.dir}" includes="fail.cs"/>
+    </csc>
+  </target>
+
+  <target name="passing-test" depends="compile-pass">
+    <dn:nunit>
+      <testassembly name="${build.dir}/Pass.dll"/>
+    </dn:nunit>
+  </target>
+
+  <target name="failing-test" depends="compile-fail">
+    <dn:nunit>
+      <testassembly name="${build.dir}/Fail.dll"/>
+    </dn:nunit>
+  </target>
+
+  <target name="failing-test-with-fail" depends="compile-fail">
+    <dn:nunit failonerror="true">
+      <testassembly name="${build.dir}/Fail.dll"/>
+    </dn:nunit>
+  </target>
+
+  <target name="teardown">
+    <delete dir="${build.dir}"/>
+  </target>
+</project>
\ No newline at end of file
diff --git a/src/etc/testcases/src/example.cs b/src/etc/testcases/src/example.cs
new file mode 100644
index 0000000..0616e33
--- /dev/null
+++ b/src/etc/testcases/src/example.cs
@@ -0,0 +1,25 @@
+/*
+ * Copyright  2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+using System;
+
+public class Example {
+
+    public static void Main(String[] args) {
+            Example2.echo();
+    }
+}
diff --git a/src/etc/testcases/src/example2.cs b/src/etc/testcases/src/example2.cs
new file mode 100644
index 0000000..f373ec0
--- /dev/null
+++ b/src/etc/testcases/src/example2.cs
@@ -0,0 +1,31 @@
+/*
+ * Copyright  2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+using System;
+
+/**
+ * this is just here to create confusion
+ */
+public class Example2 {
+
+    public int some_variable=3;
+    
+    public static void echo() {
+        Console.WriteLine("hello, I look like Java, but I'm really .NET");
+    }
+    
+}
diff --git a/src/etc/testcases/src/fail.cs b/src/etc/testcases/src/fail.cs
new file mode 100644
index 0000000..44c1205
--- /dev/null
+++ b/src/etc/testcases/src/fail.cs
@@ -0,0 +1,30 @@
+/*
+ * Copyright  2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+using System;
+using NUnit.Framework;
+
+[TestFixture]
+public class FailingTest
+{
+
+    [Test]
+    public void Fail() 
+    {
+        Assert.IsTrue(false);
+    }
+}
diff --git a/src/etc/testcases/src/msbuild.proj b/src/etc/testcases/src/msbuild.proj
new file mode 100644
index 0000000..ded05af
--- /dev/null
+++ b/src/etc/testcases/src/msbuild.proj
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<Project DefaultTargets="empty">
+
+  <Target Name="empty"/>
+
+  <Target Name="echo">
+    <Task Name="Echo" Message="foo is ${foo}"/>
+  </Target>
+</Project>
diff --git a/src/etc/testcases/src/nant.build b/src/etc/testcases/src/nant.build
new file mode 100644
index 0000000..cf59b76
--- /dev/null
+++ b/src/etc/testcases/src/nant.build
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project basedir="." default="empty">
+
+  <target name="empty"/>
+
+  <target name="echo">
+    <echo message="foo is ${foo}"/>
+  </target>
+</project>
diff --git a/src/etc/testcases/src/pass.cs b/src/etc/testcases/src/pass.cs
new file mode 100644
index 0000000..51fabf4
--- /dev/null
+++ b/src/etc/testcases/src/pass.cs
@@ -0,0 +1,30 @@
+/*
+ * Copyright  2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+using System;
+using NUnit.Framework;
+
+[TestFixture]
+public class PassingTest
+{
+
+    [Test]
+    public void Pass() 
+    {
+        Assert.IsTrue(true);
+    }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java
new file mode 100644
index 0000000..3db5439
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.XMLFragment;
+
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for NAntTask and MSBuildTask.
+ */
+public abstract class AbstractBuildTask extends Task {
+
+    /**
+     * The buildfile to invoke the build tool for.
+     */
+    private File buildFile;
+
+    /**
+     * The targets to execute.
+     */
+    private List targets = new ArrayList();
+
+    /**
+     * Properties to set.
+     */
+    private List properties = new ArrayList(1);
+
+    /**
+     * Nested build file fragment.
+     */
+    private XMLFragment buildSnippet;
+
+    /**
+     * The vm attribute - if given.
+     */
+    private String vm;
+
+    /**
+     * Empty constructor.
+     */
+    protected AbstractBuildTask() {
+    }
+
+    /**
+     * Sets the name of the build file.
+     */
+    public final void setBuildfile(File f) {
+        buildFile = f;
+    }
+
+    /**
+     * Adds a build file fragment.
+     */
+    public void addBuild(XMLFragment f) {
+        if (buildSnippet == null) {
+            buildSnippet = f;
+        } else {
+            throw new BuildException("You must not specify more than one "
+                                     + "build element");
+        }
+    }
+
+    /**
+     * Set the name of the executable for the virtual machine.
+     *
+     * @param value the name of the executable for the virtual machine
+     */
+    public void setVm(String value) {
+        this.vm = value;
+    }
+
+    /**
+     * A target.
+     */
+    public static class Target {
+        private String name;
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+    }
+
+    /**
+     * A target to execute.
+     */
+    public final void addTarget(Target t) {
+        targets.add(t);
+    }
+
+    /**
+     * A property.
+     */
+    // XXX, could have reused Property or Environment.Variable 
+    //      - not decided so far
+    public static class Property {
+        private String name;
+        private String value;
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * A target to execute.
+     */
+    public final void addProperty(Property t) {
+        properties.add(t);
+    }
+
+    /**
+     * Must return the executable.
+     *
+     * @return must not return null
+     */
+    protected abstract String getExecutable();
+
+    /**
+     * Must return buildfile argument(s).
+     *
+     * @param buildFile the absolute File for the buildfile or null if
+     * the user didn't specify a buildfile.
+     *
+     * @return must not return null
+     */
+    protected abstract String[] getBuildfileArguments(File buildFile);
+
+    /**
+     * Must return target argument(s).
+     *
+     * @return must not return null
+     */
+    protected abstract String[] getTargetArguments(List targets);
+
+    /**
+     * Must return property argument(s).
+     *
+     * @return must not return null
+     */
+    protected abstract String[] getPropertyArguments(List properties);
+
+    /**
+     * Turn the DoucmentFragment into a DOM tree suitable as a build
+     * file when serialized.
+     *
+     * <p>Must throw a BuildException if the snippet can not be turned
+     * into a build file.</p>
+     */
+    protected abstract Element makeTree(DocumentFragment f);
+
+    /**
+     * Perform the build.
+     */
+    public void execute() {
+        if (buildFile != null && buildSnippet != null) {
+            throw new BuildException("You must not specify the build file"
+                                     + " attribute and a nested build at the"
+                                     + " same time");
+        }
+
+        DotNetExecTask exec = DotNetExecTask.getTask(this, vm, 
+                                                     getExecutable(), null);
+        String[] args = getPropertyArguments(properties);
+        for (int i = 0; i < args.length; i++) {
+            exec.createArg().setValue(args[i]);
+        }
+        args = getTargetArguments(targets);
+        for (int i = 0; i < args.length; i++) {
+            exec.createArg().setValue(args[i]);
+        }
+
+        File generatedFile = null;
+        if (buildSnippet != null) {
+            try {
+                generatedFile = getBuildFile();
+            } catch (IOException e) {
+                throw new BuildException(e);
+            }
+            args = getBuildfileArguments(generatedFile);
+        } else {
+            args = getBuildfileArguments(buildFile);
+        }        
+
+        for (int i = 0; i < args.length; i++) {
+            exec.createArg().setValue(args[i]);
+        }
+
+        try {
+            exec.execute();
+        } finally {
+            if (generatedFile != null) {
+                generatedFile.delete();
+            }
+        }
+    }
+
+    private File getBuildFile() throws IOException {
+        File f = null;
+        if (buildSnippet != null) {
+            Element e = makeTree(buildSnippet.getFragment());
+            f = FileUtils.newFileUtils().createTempFile("build", ".xml", null);
+            f.deleteOnExit();
+            FileOutputStream out = null;
+            try {
+                out = new FileOutputStream(f);
+                (new DOMElementWriter()).write(e, out);
+            } finally {
+                if (out != null) {
+                    out.close();
+                }
+            }
+        }
+        return f;
+    }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTask.java
new file mode 100644
index 0000000..e546cfd
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTask.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Environment;
+
+/**
+ * Specialized <exec> that knows how to deal with Mono vs. Microsoft's
+ * VM - and maybe Rotor at some point.
+ */
+public class DotNetExecTask extends ExecTask {
+
+    /**
+     * "Magic" VM argument for Microsoft's VM.
+     */
+    private static final String MS_VM = "microsoft";
+
+    /**
+     * The user supplied executable attribute.
+     */
+    private String executable;
+
+    /**
+     * The .NET VM to use.
+     *
+     * <p>Defaults to Microsoft's on Windows and mono on any other
+     * platform.</p>
+     */
+    private String vm = Os.isFamily("windows") ? MS_VM : "mono";
+
+    /**
+     * Empty Constructor.
+     */
+    public DotNetExecTask() {
+        super();
+    }
+
+    /**
+     * Set the name of the executable program.
+     * @param value the name of the executable program
+     */
+    public void setExecutable(String value) {
+        this.executable = value;
+    }
+
+    /**
+     * Set the name of the executable for the virtual machine or the
+     * magic name "microsoft" which implies that we can invoke the
+     * executable directly.
+     *
+     * @param value the name of the executable for the virtual machine
+     */
+    public void setVm(String value) {
+        this.vm = value;
+    }
+
+    /**
+     * Do the work.
+     *
+     * @throws BuildException if executable is empty or &lt;exec&gt;
+     * throws an exception.
+     */
+    public void execute() throws BuildException {
+        if (executable == null) {
+            throw new BuildException("The executable attribute is required");
+        }
+        setupCommandline();
+        super.execute();
+    }
+
+    /**
+     * If the inherited Commandline doesn't know about the executable
+     * yet, set it and deal with the vm attribute.
+     *
+     * <p>The inherited Commandline may know the executable already if
+     * this task instance is getting reused.</p>
+     */
+    protected void setupCommandline() {
+        if (cmdl.getExecutable() == null) {
+            if (vm.equals(MS_VM)) {
+                // can invoke executable directly
+                super.setExecutable(executable);
+            } else {
+                boolean b = getResolveExecutable();
+                // Mono wants the absolte path of the assembly
+                setResolveExecutable(b || isMono(vm));
+                super.setExecutable(vm);
+                cmdl.createArgument(true)
+                    .setValue(resolveExecutable(executable, isMono(vm)));
+                setResolveExecutable(b);
+            }
+        }
+    }
+
+    /**
+     * Whether the given vm looks like the Mono executable.
+     */
+    protected final static boolean isMono(String vm) {
+        return "mono".equals(vm) || "mint".equals(vm);
+    }
+
+    /**
+     * Creates an instance of this task based on a different tasks settings.
+     */
+    public static DotNetExecTask getTask(Task t, String vm, 
+                                         String executable,
+                                         Environment env) {
+        DotNetExecTask exec = new DotNetExecTask();
+        if (vm != null) {
+            exec.setVm(vm);
+        }
+        exec.setProject(t.getProject());
+        exec.setExecutable(executable);
+        exec.setTaskName(t.getTaskName());
+        if (env != null) {
+            String[] environment = env.getVariables();
+            if (environment != null) {
+                for (int i = 0; i < environment.length; i++) {
+                    int idx = environment[i].indexOf("=");
+                    Environment.Variable v = new Environment.Variable();
+                    v.setKey(environment[i].substring(0, idx));
+                    v.setValue(environment[i].substring(idx + 1));
+                    exec.addEnv(v);
+                }
+            }
+        }
+        
+        return exec;
+    }
+
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java
new file mode 100644
index 0000000..9fe31bc
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Runs a MSBuild build process.
+ */
+public class MSBuildTask extends AbstractBuildTask {
+
+    private static final String TARGET = "generated-by-ant";
+
+    public MSBuildTask() {
+        super();
+    }
+
+    protected String getExecutable() {
+        return "MSBuild.exe";
+    }
+
+    protected String[] getBuildfileArguments(File buildFile) {
+        if (buildFile != null) {
+            return new String[] {
+                buildFile.getAbsolutePath()
+            };
+        } else {
+            return new String[0];
+        }
+    }
+
+    protected String[] getTargetArguments(List targets) {
+        if (targets.size() > 0) {
+            StringBuffer sb = new StringBuffer("/targets:");
+            Iterator iter = targets.iterator();
+            boolean first = true;
+            while (iter.hasNext()) {
+                AbstractBuildTask.Target t = 
+                    (AbstractBuildTask.Target) iter.next();
+                if (!first) {
+                    sb.append(";");
+                }
+                sb.append(t.getName());
+            }
+            return new String[]{sb.toString()};
+        } else {
+            return new String[0];
+        }
+    }
+
+    protected String[] getPropertyArguments(List properties) {
+        if (properties.size() > 0) {
+            StringBuffer sb = new StringBuffer("/property:");
+            Iterator iter = properties.iterator();
+            boolean first = true;
+            while (iter.hasNext()) {
+                AbstractBuildTask.Property p = 
+                    (AbstractBuildTask.Property) iter.next();
+                if (!first) {
+                    sb.append(";");
+                }
+                sb.append(p.getName()).append("=").append(p.getValue());
+            }
+            return new String[]{sb.toString()};
+        } else {
+            return new String[0];
+        }
+    }
+
+    /**
+     * Turn the DocumentFragment into a DOM tree suitable as a build
+     * file when serialized.
+     *
+     * <p>If we have exactly one <Project> child, return that.
+     * Otherwise if we have only <Task> children, wrap them into a
+     * <Target> which in turn gets wrapped into a <Project>.
+     * Otherwise, fail.</p>
+     */
+    protected Element makeTree(DocumentFragment f) {
+        NodeList nl = f.getChildNodes();
+        if (nl.getLength() == 1 
+            && nl.item(0).getNodeType() == Node.ELEMENT_NODE
+            && nl.item(0).getNodeName().equals("Project")) {
+            return (Element) nl.item(0);
+        } else {
+            Element p = f.getOwnerDocument().createElement("Project");
+            p.setAttribute("DefaultTargets", TARGET);
+
+            Element t = f.getOwnerDocument().createElement("Target");
+            t.setAttribute("Name", TARGET);
+
+            p.appendChild(t);
+            t.appendChild(f);
+            return p;
+        }
+    }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java
new file mode 100644
index 0000000..274a6d8
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Runs a NAnt build process.
+ */
+public class NAntTask extends AbstractBuildTask {
+
+    public NAntTask() {
+        super();
+    }
+
+    protected String getExecutable() {
+        return "NAnt.exe";
+    }
+
+    protected String[] getBuildfileArguments(File buildFile) {
+        if (buildFile != null) {
+            return new String[] {
+                "-buildfile:" + buildFile.getAbsolutePath()
+            };
+        } else {
+            return new String[0];
+        }
+    }
+
+    protected String[] getTargetArguments(List targets) {
+        ArrayList al = new ArrayList(targets.size());
+        Iterator iter = targets.iterator();
+        while (iter.hasNext()) {
+            AbstractBuildTask.Target t = (AbstractBuildTask.Target) iter.next();
+            al.add(t.getName());
+        }
+        return (String[]) al.toArray(new String[al.size()]);
+    }
+
+    protected String[] getPropertyArguments(List properties) {
+        ArrayList al = new ArrayList(properties.size());
+        Iterator iter = properties.iterator();
+        while (iter.hasNext()) {
+            AbstractBuildTask.Property p = 
+                (AbstractBuildTask.Property) iter.next();
+            al.add("-D:" + p.getName() + "=" + p.getValue());
+        }
+        return (String[]) al.toArray(new String[al.size()]);
+    }
+
+    /**
+     * Turn the DocumentFragment into a DOM tree suitable as a build
+     * file when serialized.
+     *
+     * <p>If we have exactly one <project> child, return that.
+     * Otherwise assume that this is a valid build file snippet that
+     * just needs an empty project wrapped around it.</p>
+     */
+    protected Element makeTree(DocumentFragment f) {
+        NodeList nl = f.getChildNodes();
+        if (nl.getLength() == 1 
+            && nl.item(0).getNodeType() == Node.ELEMENT_NODE
+            && nl.item(0).getNodeName().equals("project")) {
+            return (Element) nl.item(0);
+        } else {
+            Element e = f.getOwnerDocument().createElement("project");
+            e.appendChild(f);
+            return e;
+        }
+    }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTask.java
new file mode 100644
index 0000000..97cf395
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTask.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright  2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.RedirectorElement;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Task to run the NUnit Console test runner.
+ *
+ * @see http://www.nunit.org/
+ */
+public class NUnitTask extends Task {
+
+    /**
+     * The vm attribute - if given.
+     */
+    private String vm;
+
+    /**
+     * Test assemblies.
+     */
+    private ArrayList testAssemblies = new ArrayList();
+
+    /**
+     * The /config argument.
+     */
+    private File configFile;
+
+    /**
+     * The /output argument.
+     */
+    private File out;
+
+    /**
+     * The /err argument.
+     */
+    private File err;
+
+    /**
+     * The /xml argument.
+     */
+    private File xmlOut;
+
+    /**
+     * The /transform argument.
+     */
+    private File transform;
+
+    /**
+     * The /thread argument.
+     */
+    private boolean thread = false;
+
+    /**
+     * The /fixture argument.
+     */
+    private String fixture;
+
+    /**
+     * Categories to include.
+     */
+    private ArrayList includes = new ArrayList();
+
+    /**
+     * Categories to exclude.
+     */
+    private ArrayList excludes = new ArrayList();
+
+    /**
+     * The /noshadow argument.
+     */
+    private boolean noshadow = false;
+
+    /**
+     * The /labels argument.
+     */
+    private boolean labels = false;
+
+    /**
+     * Redirects everything that NUnit wants to send to the console.
+     */
+    private RedirectorElement redirectorElement;
+
+    /**
+     * Whether a failure should stop the build.
+     */
+    private boolean failOnError = false;
+
+    /**
+     * Support for nested environment variables.
+     */
+    private Environment env = new Environment();
+
+    public NUnitTask() {
+        super();
+    }
+
+    /**
+     * Set the name of the executable for the virtual machine.
+     *
+     * @param value the name of the executable for the virtual machine
+     */
+    public void setVm(String value) {
+        this.vm = value;
+    }
+
+    /**
+     * Sets the name of the config file.
+     */
+    public void setConfig(File c) {
+        configFile = c;
+    }
+
+    /**
+     * The /output argument.
+     */
+    public void setOut(File out) {
+        this.out = out;
+    }
+
+    /**
+     * The /err argument.
+     */
+    public void setError(File err) {
+        this.err = err;
+    }
+
+    /**
+     * The /xml argument.
+     */
+    public void setXmlOut(File out) {
+        this.xmlOut = out;
+    }
+
+    /**
+     * The /transform argument.
+     */
+    public void setTransform(File transform) {
+        this.transform = transform;
+    }
+
+    /**
+     * The /thread argument.
+     */
+    public void setThread(boolean thread) {
+        this.thread = thread;
+    }
+
+    /**
+     * The /fixture argument.
+     */
+    public void setFixture(String fixture) {
+        this.fixture = fixture;
+    }
+
+    /**
+     * The /noshadow argument.
+     */
+    public void setNoshadow(boolean noshadow) {
+        this.noshadow = noshadow;
+    }
+
+    /**
+     * The /labels argument.
+     */
+    public void setLabels(boolean labels) {
+        this.labels = labels;
+    }
+
+    /**
+     * Whether a failure should stop the build.
+     */
+    public void setFailOnError(boolean b) {
+        failOnError = b;
+    }
+
+    /**
+     * Adds a test assembly by name.
+     */
+    public void addTestAssembly(NamedElement a) {
+        testAssemblies.add(a);
+    }
+
+    /**
+     * Adds a category to the include list.
+     */
+    public void addInclude(NamedElement a) {
+        includes.add(a);
+    }
+
+    /**
+     * Adds a category to the exclude list.
+     */
+    public void addExclude(NamedElement a) {
+        excludes.add(a);
+    }
+
+    /**
+     * Add an environment variable to the launched process.
+     *
+     * @param var new environment variable
+     */
+    public void addEnv(Environment.Variable var) {
+        env.addVariable(var);
+    }
+
+    /**
+     * Add a <code>RedirectorElement</code> to this task.
+     *
+     * <p>This does not use the <code>out</code> and
+     * <code>error</code> attributes, it only captures NUnits output
+     * that has not been redirected by those attributes.</p>
+     */
+    public void addConfiguredRedirector(RedirectorElement redirectorElement) {
+        if (this.redirectorElement != null) {
+            throw new BuildException("cannot have > 1 nested <redirector>s");
+        } else {
+            this.redirectorElement = redirectorElement;
+        }
+    }
+
+    public void execute() {
+        if (testAssemblies.size() == 0) {
+            throw new BuildException("You must specify at least one test "
+                                     + "assembly.");
+        }
+        
+        DotNetExecTask exec = DotNetExecTask.getTask(this, vm, 
+                                                     "nunit-console.exe",
+                                                     env);
+        Iterator iter = testAssemblies.iterator();
+        while (iter.hasNext()) {
+            NamedElement a = (NamedElement) iter.next();
+            exec.createArg().setValue(a.getName());
+        }
+        if (configFile != null) {
+            exec.createArg().setValue("/config=" 
+                                      + configFile.getAbsolutePath());
+        }
+        exec.createArg().setValue("/nologo");
+
+        if (out != null) {
+            exec.createArg().setValue("/output=" + out.getAbsolutePath());
+        }
+        if (err != null) {
+            exec.createArg().setValue("/err=" + err.getAbsolutePath());
+        }
+        if (xmlOut != null) {
+            exec.createArg().setValue("/xml=" + xmlOut.getAbsolutePath());
+        }
+        if (transform != null) {
+            exec.createArg().setValue("/transform=" 
+                                      + transform.getAbsolutePath());
+        }
+
+        if (thread) {
+            exec.createArg().setValue("/thread");
+        }
+        if (noshadow) {
+            exec.createArg().setValue("/noshadow");
+        }
+        if (labels) {
+            exec.createArg().setValue("/labels");
+        }
+        if (fixture != null) {
+            exec.createArg().setValue("/fixture=" + fixture);
+        }
+        
+        if (includes.size() > 0) {
+            StringBuffer sb = new StringBuffer("/include=");
+            iter = includes.iterator();
+            boolean first = false;
+            while (iter.hasNext()) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(",");
+                }
+                NamedElement a = (NamedElement) iter.next();
+                sb.append(a.getName());
+            }
+            exec.createArg().setValue(sb.toString());
+        }
+        if (excludes.size() > 0) {
+            StringBuffer sb = new StringBuffer("/exclude=");
+            iter = excludes.iterator();
+            boolean first = false;
+            while (iter.hasNext()) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(",");
+                }
+                NamedElement a = (NamedElement) iter.next();
+                sb.append(a.getName());
+            }
+            exec.createArg().setValue(sb.toString());
+        }
+
+        if (redirectorElement != null) {
+            exec.addConfiguredRedirector(redirectorElement);
+        }
+        exec.setFailonerror(failOnError);
+
+        exec.execute();
+    }
+
+    public static class NamedElement {
+        private String name;
+        public String getName() {return name;}
+        public void setName(String s) {name = s;}
+    }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WixTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WixTask.java
new file mode 100644
index 0000000..69a8feb
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WixTask.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright  2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Task to run the WiX utility to create MSI files from an XML description.
+ *
+ * @see http://sf.net/projects/wix
+ */
+public class WixTask extends Task {
+
+    /**
+     * The vm attribute - if given.
+     */
+    private String vm;
+
+    /**
+     * The source files.
+     */
+    private ArrayList sources = new ArrayList();
+
+    /**
+     * Additional source files (include files in the case of candle,
+     * or media/files/whatever in the case of light).
+     */
+    private ArrayList moreSources = new ArrayList();
+
+    /**
+     * A single source file.
+     */
+    private File source;
+
+    /**
+     * The target file.
+     */
+    private File target;
+
+    /**
+     * What to do.
+     */
+    private Mode mode;
+
+    public WixTask() {
+        super();
+    }
+
+    /**
+     * Set the name of the executable for the virtual machine.
+     *
+     * @param value the name of the executable for the virtual machine
+     */
+    public void setVm(String value) {
+        this.vm = value;
+    }
+
+    /**
+     * The main source file.
+     *
+     * <p><code>candle</code> may include more files than this one,
+     * the main source is the one passed on the command line.</p>
+     *
+     * @param File object of the main source file.
+     */
+    public void setSource(File f) {
+        source = f;
+    }
+
+    /**
+     * A set of source files.
+     */
+    public void addSources(FileSet fs) {
+        sources.add(fs);
+    }
+
+    /**
+     * A set of additional source files (include files in the case of
+     * candle, or media/files/whatever in the case of light).
+     *
+     * <p>Unlike the files specified as sources, these will not be
+     * passed on the command line, they only help Ant to determine
+     * whether the target is out-of-date.</p>
+     */
+    public void addMoreSources(FileSet fs) {
+        moreSources.add(fs);
+    }
+
+    public void execute() {
+        if (source == null && sources.size() == 0) {
+            throw new BuildException("You must specify at least one source"
+                                     + " file.");
+        }
+        String m = Mode.BOTH;
+        if (mode != null) {
+            m = mode.getValue();
+        }
+
+        if (target == null && !m.equals(Mode.CANDLE)) {
+            throw new BuildException("You must specify the target if you want"
+                                     + " to run light.");
+        }
+
+        List lightSources = new ArrayList();
+        if (!m.equals(Mode.LIGHT)) {
+            doCandle(lightSources);
+        } else {
+            if (source != null) {
+                lightSources.add(source);
+            }
+            if (sources.size() > 0) {
+                lightSources.addAll(grabFiles(sources));
+            }
+        }
+        List moreLightSources = new ArrayList();
+        if (moreSources.size() > 0) {
+            moreLightSources = grabFiles(moreSources);
+        }
+        if (!m.equals(Mode.CANDLE)) {
+            doLight(lightSources, moreLightSources);
+        }
+    }
+
+    /**
+     * Invoke candle on all sources that are newer than their targets.
+     *
+     * @param lightSources list that will be filled with File objects
+     * pointing to the generated object files.
+     */
+    private void doCandle(List lightSources) {
+        List s = new ArrayList();
+        if (source != null) {
+            s.add(source);
+        }
+        if (sources != null) {
+            s.addAll(grabFiles(sources));
+        }
+        List ms = new ArrayList();
+        if (moreSources != null) {
+            ms.addAll(grabFiles(moreSources));
+        }
+        Iterator iter = s.iterator();
+        List toProcess = new ArrayList();
+        while (iter.hasNext()) {
+            File thisSource = (File) iter.next();
+            File t = target;
+            if (t == null) {
+                t = getTarget(thisSource);
+            }
+            if (isOutOfDate(t, thisSource, ms)) {
+                toProcess.add(thisSource);
+                lightSources.add(t);
+            }
+        }
+        if (toProcess.size() != 0) {
+            runCandle(toProcess);
+        }
+    }
+
+    /**
+     * Invoke light on all sources that are newer than their targets.
+     */
+    private void doLight(List lightSources, List moreLightSources) {
+        List tmp = new ArrayList(lightSources);
+        tmp.addAll(moreLightSources);
+        if (isOutOfDate(target, tmp)) {
+            runLight(lightSources);
+        }
+    }
+
+    /**
+     * Run candle passing all files in list on the command line.
+     */
+    private void runCandle(List s) {
+        run("candle.exe", s, null);
+    }
+
+    /**
+     * Run light passing all files in list on the command line.
+     */
+    private void runLight(List s) {
+        run("light.exe", s, target);
+    }
+
+    /**
+     * Runs the specified command passing list on the command line an
+     * potentially adding an /out parameter.
+     */
+    private void run(String executable, List s, File target) {
+        DotNetExecTask exec = DotNetExecTask.getTask(this, vm, 
+                                                     executable, null);
+        Iterator iter = s.iterator();
+        while (iter.hasNext()) {
+            File f = (File) iter.next();
+            exec.createArg().setValue(f.getAbsolutePath());
+        }
+        if (target != null) {
+            exec.createArg().setValue("/out");
+            exec.createArg().setValue(target.getAbsolutePath());
+        }
+        
+        exec.execute();
+    }
+
+    /**
+     * Is t older than s or any of the files in list?
+     */
+    private boolean isOutOfDate(File t, File s, List l) {
+        return t.lastModified() < s.lastModified() || isOutOfDate(t, l);
+    }
+
+    /**
+     * Is t older than any of the files in list?
+     */
+    private boolean isOutOfDate(File t, List l) {
+        Iterator iter = l.iterator();
+        while (iter.hasNext()) {
+            File f = (File) iter.next();
+            if (t.lastModified() < f.lastModified()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Turn the fileset collection into a list of Files.
+     */
+    private List grabFiles(List s) {
+        List r = new ArrayList();
+        Iterator iter = s.iterator();
+        while (iter.hasNext()) {
+            FileSet fs = (FileSet) iter.next();
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            String[] f = ds.getIncludedFiles();
+            File base = fs.getDir(getProject());
+            for (int i = 0; i < f.length; i++) {
+                r.add(new File(base, f[i]));
+            }
+        }
+        return r;
+    }
+
+    /**
+     * Generates the name of a candle target from the source file.
+     *
+     * <p>Simply chops of the extension and adds .wixobj.</p>
+     */
+    private File getTarget(File s) {
+        String name = s.getAbsolutePath();
+        int dot = name.lastIndexOf(".");
+        if (dot > -1) {
+            return new File(name.substring(0, dot) + ".wixobj");
+        } else {
+            return new File(name + ".wixobj");
+        }
+    }
+
+    public static class Mode extends EnumeratedAttribute {
+        private final static String CANDLE = "candle";
+        private final static String LIGHT = "light";
+        private final static String BOTH = "both";
+
+        public Mode() {
+            super();
+        }
+
+        public String[] getValues() {
+            return new String[] {CANDLE, LIGHT, BOTH,};
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml
new file mode 100644
index 0000000..ee05e23
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+ Copyright  2003-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<antlib>
+  <taskdef
+    name="dotnetexec"
+    classname="org.apache.tools.ant.taskdefs.optional.dotnet.DotNetExecTask"
+    />
+  <taskdef
+    name="msbuild"
+    classname="org.apache.tools.ant.taskdefs.optional.dotnet.MSBuildTask"
+    />
+  <taskdef
+    name="nant"
+    classname="org.apache.tools.ant.taskdefs.optional.dotnet.NAntTask"
+    />
+  <taskdef
+    name="wix"
+    classname="org.apache.tools.ant.taskdefs.optional.dotnet.WixTask"
+    />
+  <taskdef
+    name="nunit"
+    classname="org.apache.tools.ant.taskdefs.optional.dotnet.NUnitTask"
+    />
+</antlib>
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTaskTest.java
new file mode 100644
index 0000000..665f9a1
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTaskTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the DotNetExecTask task, based off Ant's DotnetTest.
+ *
+ */
+public class DotNetExecTaskTest extends BuildFileTest {
+
+    /**
+     * Description of the Field
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+
+    /**
+     * Constructor 
+     *
+     * @param name testname
+     */
+    public DotNetExecTaskTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "dotnetexec.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("teardown");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCSC() throws Exception {
+        executeTarget("testCSC");
+    }
+}
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java
new file mode 100644
index 0000000..40dab15
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the MSBuildTask task.
+ */
+public class MSBuildTaskTest extends BuildFileTest {
+
+    /**
+     * Description of the Field
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+    /**
+     * Constructor 
+     *
+     * @param name testname
+     */
+    public MSBuildTaskTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "msbuild.xml");
+    }
+
+    public void testEcho() throws Exception {
+        if (getProject().getProperty("msbuild.found") != null) {
+            expectLogContaining("echo", "foo is bar");
+        }
+    }
+
+    public void testNestedFile() throws Exception {
+        if (getProject().getProperty("msbuild.found") != null) {
+            expectLogContaining("nested-file", "foo is bar");
+        }
+    }
+
+    public void testNestedTask() throws Exception {
+        if (getProject().getProperty("msbuild.found") != null) {
+            expectLogContaining("nested-task", "foo is bar");
+        }
+    }
+}
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java
new file mode 100644
index 0000000..edce890
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the NAntTask task.
+ */
+public class NAntTaskTest extends BuildFileTest {
+
+    /**
+     * Description of the Field
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+    /**
+     * Constructor 
+     *
+     * @param name testname
+     */
+    public NAntTaskTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "nant.xml");
+    }
+
+    public void testEcho() throws Exception {
+        if (getProject().getProperty("nant.found") != null) {
+            expectLogContaining("echo", "foo is bar");
+        }
+    }
+
+    public void testNestedFile() throws Exception {
+        if (getProject().getProperty("nant.found") != null) {
+            expectLogContaining("nested-file", "foo is bar");
+        }
+    }
+
+    public void testNestedTask() throws Exception {
+        if (getProject().getProperty("nant.found") != null) {
+            expectLogContaining("nested-task", "foo is bar");
+        }
+    }
+}
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTaskTest.java
new file mode 100644
index 0000000..3ccefb4
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTaskTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright  2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the NUnitTask task.
+ */
+public class NUnitTaskTest extends BuildFileTest {
+
+    /**
+     * Description of the Field
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+    /**
+     * Constructor 
+     *
+     * @param name testname
+     */
+    public NUnitTaskTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "nunit.xml");
+    }
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("teardown");
+    }
+
+    public void testNoAssembly() {
+        expectSpecificBuildException("no-assembly", "no assembly", 
+                                     "You must specify at least one test assembly.");
+    }
+
+    public void testPass() {
+        if (getProject().getProperty("nunit.found") != null) {
+            expectLogContaining("passing-test", 
+                                "Tests run: 1, Failures: 0, Not run: 0");
+        }
+    }
+
+    public void testFail() {
+        if (getProject().getProperty("nunit.found") != null) {
+            expectLogContaining("failing-test", 
+                                "Tests run: 1, Failures: 1, Not run: 0");
+        }
+    }
+
+    public void testFailOnFail() {
+        if (getProject().getProperty("nunit.found") != null) {
+            expectBuildException("failing-test-with-fail", "test should fail");
+        }
+    }
+
+}