]> source.dussan.org Git - poi.git/commitdiff
initial import of ExcelAnt tasks, see Bugzilla 50610
authorYegor Kozlov <yegor@apache.org>
Fri, 18 Feb 2011 20:04:50 +0000 (20:04 +0000)
committerYegor Kozlov <yegor@apache.org>
Fri, 18 Feb 2011 20:04:50 +0000 (20:04 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/excelant@1072119 13f79535-47bb-0310-9956-ffa450edef68

33 files changed:
build.xml
maven/poi-excelant.pom [new file with mode: 0755]
src/documentation/content/xdocs/spreadsheet/book.xml
src/documentation/content/xdocs/spreadsheet/excelant.xml [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntEvaluateCell.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntHandlerTask.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntPrecision.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSet.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetDoubleCell.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetFormulaCell.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetStringCell.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntTask.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntTest.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/ExcelAntUserDefinedFunction.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/IExcelAntWorkbookHandler.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntEvaluationResult.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtil.java [new file with mode: 0755]
src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtilFactory.java [new file with mode: 0755]
src/excelant/resources/org/apache/poi/ss/excelant/antlib.xml [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/examples/formula/CalculateMortgage.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/examples/formula/ExcelAntUserDefinedFunctionTestHelper.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/examples/formula/TestExcelAntUserDefinedFunction.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/BuildFileTest.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/TestBuildFile.java [new file with mode: 0644]
src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntPrecision.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntSet.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntSetDoubleCell.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtilTestHelper.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntEvaluationResult.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtil.java [new file with mode: 0755]
src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtilFactory.java [new file with mode: 0755]
test-data/spreadsheet/excelant.xls [new file with mode: 0644]
test-data/spreadsheet/mortgage-calculation.xls [new file with mode: 0644]

index 1f7e757eaae5fe644a36e654b88db08b17995558..50e17a6e5e33d69d7ab541301d42db8b17edcf15 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -109,6 +109,15 @@ under the License.
     <property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
     <property name="ooxml.lite.output.dir" location="build/ooxml-lite-classes"/>
 
+    <!-- Excelant: -->
+    <property name="excelant.resource.dir" value="src/excelant/resources"/>
+    <property name="excelant.src" location="src/excelant/java"/>
+    <property name="excelant.src.test" location="src/excelant/testcases"/>
+    <property name="excelant.reports.test" location="build/excelant-test-results"/>
+    <property name="excelant.output.dir" location="build/excelant-classes"/>
+    <property name="excelant.output.test.dir" location="build/excelant-test-classes"/>
+    <property name="excelant.testokfile" location="build/excelant-testokfile.txt"/>
+
     <!-- jars in the /lib directory, see the fetch-jars target-->
     <property name="main.commons-logging.jar" location="${main.lib}/commons-logging-1.1.jar"/>
     <property name="main.commons-logging.url"
@@ -117,6 +126,8 @@ under the License.
     <property name="main.log4j.url" value="${repository.m2}/maven2/log4j/log4j/1.2.13/log4j-1.2.13.jar"/>
     <property name="main.junit.jar" location="${main.lib}/junit-3.8.1.jar"/>
     <property name="main.junit.url" value="${repository.m2}/maven2/junit/junit/3.8.1/junit-3.8.1.jar"/>
+    <property name="main.ant.jar" location="${main.lib}/ant-1.8.2.jar"/>
+    <property name="main.ant.url" value="${repository.m2}/maven2/org/apache/ant/ant/1.8.2/ant-1.8.2.jar"/>
 
     <!-- jars in the lib-ooxml directory, see the fetch-ooxml-jars target-->
     <property name="ooxml.dom4j.jar" location="${ooxml.lib}/dom4j-1.6.1.jar"/>
@@ -155,9 +166,9 @@ under the License.
     </propertyset>
 
     <path id="main.classpath">
-        <fileset dir="${main.lib}">
-            <include name="*.jar"/>
-        </fileset>
+        <pathelement location="${main.commons-logging.jar}"/>
+        <pathelement location="${main.log4j.jar}"/>
+        <pathelement location="${main.junit.jar}"/>
     </path>
 
     <path id="scratchpad.classpath">
@@ -216,6 +227,18 @@ under the License.
         <pathelement location="${scratchpad.output.dir}"/>
     </path>
 
+    <path id="excelant.classpath">
+        <path refid="ooxml.classpath"/>
+        <pathelement location="${main.ant.jar}"/>
+        <pathelement location="${ooxml.output.dir}"/>
+    </path>
+    <path id="test.excelant.classpath">
+        <path refid="ooxml.classpath"/>
+        <pathelement location="${ooxml.output.dir}"/>
+        <pathelement location="${excelant.output.dir}"/>
+        <pathelement location="${excelant.output.test.dir}"/>
+        <pathelement location="${main.output.test.dir}"/>
+    </path>
 
     <!-- Prints POI's Ant usage help -->
     <target name="help" description="Prints Apache POI's Ant usage help">
@@ -248,6 +271,9 @@ under the License.
         <mkdir dir="${ooxml.output.dir}"/>
         <mkdir dir="${ooxml.output.test.dir}"/>
         <mkdir dir="${ooxml.reports.test}"/>
+        <mkdir dir="${excelant.output.dir}"/>
+        <mkdir dir="${excelant.output.test.dir}"/>
+        <mkdir dir="${excelant.reports.test}"/>
         <mkdir dir="${examples.output.dir}"/>
         <mkdir dir="${dist.dir}"/>
         <mkdir dir="${build.site}"/>
@@ -272,6 +298,7 @@ under the License.
                     <available file="${main.commons-logging.jar}"/>
                     <available file="${main.log4j.jar}"/>
                     <available file="${main.junit.jar}"/>
+                    <available file="${main.ant.jar}"/>
                 </and>
                 <isset property="disconnected"/>
             </or>
@@ -293,6 +320,10 @@ under the License.
             <param name="sourcefile" value="${main.junit.url}"/>
             <param name="destfile" value="${main.junit.jar}"/>
         </antcall>
+        <antcall target="downloadfile">
+            <param name="sourcefile" value="${main.ant.url}"/>
+            <param name="destfile" value="${main.ant.jar}"/>
+        </antcall>
     </target>
 
     <target name="check-ooxml-jars">
@@ -397,7 +428,7 @@ under the License.
     </target>
 
     <target name="compile" depends="init, compile-main,
-    compile-scratchpad, compile-examples"
+            compile-scratchpad, compile-examples, compile-excelant"
             description="Compiles the POI main classes, scratchpad and examples"/>
 
     <target name="compile-all" depends="compile,compile-ooxml-lite"/>
@@ -509,6 +540,36 @@ under the License.
         </javac>
     </target>
 
+    <target name="compile-excelant" depends="compile-main,compile-ooxml">
+        <javac target="${jdk.version.class}"
+               source="${jdk.version.source}"
+               destdir="${excelant.output.dir}"
+               srcdir="${excelant.src}"
+               debug="${compile.debug}"
+               encoding="${java.source.encoding}"
+               fork="yes"
+               includeantruntime="false">
+            <classpath refid="excelant.classpath"/>
+        </javac>
+        <javac target="${jdk.version.class}"
+               source="${jdk.version.source}"
+               destdir="${excelant.output.test.dir}"
+               srcdir="${excelant.src.test}"
+               debug="${compile.debug}"
+               encoding="${java.source.encoding}"
+               fork="yes"
+               includeantruntime="false">
+            <classpath>
+                <path refid="excelant.classpath"/>
+                <pathelement location="${excelant.output.dir}"/>
+                <pathelement path="${main.output.test.dir}"/>
+            </classpath>
+        </javac>
+        <copy todir="${excelant.output.dir}">
+            <fileset dir="${excelant.resource.dir}"/>
+        </copy>
+    </target>
+
     <target name="compile-version" depends="init"
             description="Compiles the version class">
         <!-- Generate the .java file -->
@@ -533,7 +594,7 @@ under the License.
         <delete file="${version.java}"/>
     </target>
 
-    <target name="test" depends="compile,test-main,test-scratchpad,test-ooxml"
+    <target name="test" depends="compile,test-main,test-scratchpad,test-ooxml,test-excelant"
             description="Tests main, scratchpad and ooxml"/>
     <target name="test-all" depends="test,test-ooxml-lite"/>
 
@@ -655,6 +716,37 @@ under the License.
         <ooxml-test-runner classpath="ooxml-lite.classpath"/>
     </target>
     
+    <target name="-test-excelant-check">
+        <uptodate property="excelant.test.notRequired" targetfile="${excelant.testokfile}">
+            <srcfiles dir="${excelant.src}"/>
+            <srcfiles dir="${excelant.src.test}"/>
+        </uptodate>
+    </target>
+
+    <target name="-test-excelant-write-testfile" unless="excelant.test.failed">
+        <echo file="${excelant.testokfile}" append="false" message="testok"/>
+    </target>
+
+    <target name="test-excelant" depends="compile-excelant,-test-excelant-check"
+            unless="excelant.test.notRequired">
+        <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
+               failureproperty="excelant.test.failed">
+            <classpath refid="test.excelant.classpath"/>
+            <syspropertyset refid="junit.properties"/>
+            <jvmarg value="${poi.test.locale}"/>
+            <formatter type="plain"/>
+            <batchtest todir="${excelant.reports.test}">
+                <fileset dir="${excelant.src.test}">
+                    <include name="**/Test*.java"/>
+                </fileset>
+            </batchtest>
+        </junit>
+        <delete file="${excelant.testokfile}"/>
+        <antcall target="-test-excelant-write-testfile"/>
+    </target>
+
+
+
     <target name="-check-docs">
         <uptodate property="main.docs.notRequired" targetfile="${build.site}/index.html">
             <srcfiles dir="${build.site.src}"/>
@@ -801,6 +893,13 @@ under the License.
                 </replacetokens>
             </filterchain>
         </copy>
+        <copy file="maven/poi-excelant.pom" tofile="${dist.dir}/poi-excelant-${version.id}.pom">
+            <filterchain>
+                <replacetokens>
+                    <token key="VERSION" value="${version.id}"/>
+                </replacetokens>
+            </filterchain>
+        </copy>
         <copy file="maven/mvn-deploy.sh" todir="${dist.dir}">
             <filterchain>
                 <replacetokens>
@@ -849,6 +948,11 @@ under the License.
             <fileset dir="${ooxml.lite.output.dir}"/>
             <metainf dir="legal/"/>
         </jar>
+        <jar destfile="${dist.dir}/${jar.name}-excelant-${version.id}-${DSTAMP}.jar"
+             manifest="build/poi-manifest.mf">
+            <fileset dir="${excelant.output.dir}"/>
+            <metainf dir="legal/"/>
+        </jar>
     </target>
 
     <target name="jar-src" description="Sources for Maven">
@@ -872,6 +976,11 @@ under the License.
             <fileset dir="${examples.src}"/>
             <metainf dir="legal/"/>
         </jar>
+        <jar destfile="${dist.dir}/${jar.name}-excelant-${version.id}-sources-${DSTAMP}.jar"
+             manifest="build/poi-manifest.mf">
+            <fileset dir="${excelant.src}"/>
+            <metainf dir="legal/"/>
+        </jar>
     </target>
 
     <target name="assemble" depends="jar,jar-src">
@@ -882,6 +991,7 @@ under the License.
             <include name="${jar.name}-ooxml-${version.id}-${DSTAMP}.jar"/>
             <include name="${jar.name}-examples-${version.id}-${DSTAMP}.jar"/>
             <include name="${jar.name}-ooxml-schemas-${version.id}-${DSTAMP}.jar"/>
+            <include name="${jar.name}-excelant-${version.id}-${DSTAMP}.jar"/>
          </patternset>  
 
         <!-- patterns to exclude from source assemblies -->         
@@ -907,7 +1017,11 @@ under the License.
 
         <zip destfile="${dist.dir}/${jar.name}-bin-${version.id}-${DSTAMP}.zip">
             <zipfileset dir="legal/" prefix="${zipdir}"/>
-            <zipfileset dir="${main.lib}" prefix="${zipdir}/lib" includes="*.jar"/>
+            <zipfileset dir="${main.lib}" prefix="${zipdir}/lib">
+              <include name="commons-logging-*.jar"/>
+              <include name="junit-*.jar"/>
+              <include name="log4j-*.jar"/>
+            </zipfileset>
             <zipfileset dir="${ooxml.lib}" prefix="${zipdir}/ooxml-lib">
               <include name="dom4j-*.jar"/>
               <include name="geronimo-stax-*.jar"/>
@@ -931,7 +1045,11 @@ under the License.
                longfile="gnu"
                compression="gzip">
             <tarfileset dir="legal/" prefix="${zipdir}"/>
-            <tarfileset dir="${main.lib}" prefix="${zipdir}/lib" includes="*.jar"/>
+            <zipfileset dir="${main.lib}" prefix="${zipdir}/lib">
+              <include name="commons-logging-*.jar"/>
+              <include name="junit-*.jar"/>
+              <include name="log4j-*.jar"/>
+            </zipfileset>
             <tarfileset dir="${ooxml.lib}" prefix="${zipdir}/ooxml-lib">
               <include name="dom4j-*.jar"/>
               <include name="geronimo-stax-*.jar"/>
@@ -1000,6 +1118,7 @@ under the License.
       <m2-install artifactId="poi-ooxml"/>
       <m2-install artifactId="poi-examples"/>
       <m2-install artifactId="poi-ooxml-schemas"/>
+      <m2-install artifactId="poi-excelant"/>
     </target>
     
     <!-- Runs Apache Rat against the source code, to spot any files -->
diff --git a/maven/poi-excelant.pom b/maven/poi-excelant.pom
new file mode 100755 (executable)
index 0000000..12b2b15
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!--
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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 xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+       <modelVersion>4.0.0</modelVersion>
+       <groupId>org.apache.poi</groupId>
+       <artifactId>poi-excelant</artifactId>
+       <version>@VERSION@</version>
+       <packaging>jar</packaging>
+       <name>Apache POI</name>
+       <url>http://poi.apache.org/</url>
+       <description>Apache POI Excel Ant Tasks</description>
+
+  <mailingLists>
+    <mailingList>
+      <name>POI Users List</name>
+      <subscribe>user-subscribe@poi.apache.org</subscribe>
+      <unsubscribe>user-unsubscribe@poi.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/poi-user/</archive>
+    </mailingList>
+    <mailingList>
+      <name>POI Developer List</name>
+      <subscribe>dev-subscribe@poi.apache.org</subscribe>
+      <unsubscribe>dev-unsubscribe@poi.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/poi-dev/</archive>
+    </mailingList>
+  </mailingLists>
+
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+    </license>
+  </licenses>
+
+  <organization>
+    <name>Apache Software Foundation</name>
+    <url>http://www.apache.org/</url>
+  </organization>
+
+  <dependencies>
+    <dependency>
+       <groupId>org.apache.poi</groupId>
+       <artifactId>poi</artifactId>
+       <version>@VERSION@</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.poi</groupId>
+      <artifactId>poi-ooxml</artifactId>
+      <version>@VERSION@</version>
+    </dependency>
+  </dependencies>
+</project>
index 09743224c6d6e63d7b44f2e3179826e6ab24e688..15ac2a26f4c2290fb3fc4fb8666b2ca3301985a3 100644 (file)
@@ -40,6 +40,7 @@
         <menu-item label="Pictorial Docs" href="diagrams.html"/>
         <menu-item label="Limitations" href="limitations.html"/>
         <menu-item label="User Defined Functions" href="user-defined-functions.html"/>
+        <menu-item label="ExcelAnt Tests" href="excelant.html"/>
     </menu>
 
     <menu label="Contributer's Guide">
diff --git a/src/documentation/content/xdocs/spreadsheet/excelant.xml b/src/documentation/content/xdocs/spreadsheet/excelant.xml
new file mode 100755 (executable)
index 0000000..6594bc1
--- /dev/null
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+   ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+   ====================================================================\r
+-->\r
+<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN" "../dtd/document-v11.dtd">\r
+\r
+<document>\r
+    <header>\r
+        <title>ExcelAnt - Ant Tasks for Validating Excel Spreadsheets</title>\r
+        <authors>\r
+            <person email="jon@loquatic.com" name="Jon Svede" id="JDS"/>\r
+            <person email="brian.bush@nrel.gov" name="Brian Bush" id="BWB"/>\r
+        </authors>\r
+    </header>\r
+  <body>\r
+    <section><title>ExcelAnt - Ant Tasks for Validating Excel Spreadsheets</title>\r
+    \r
+    <section><title>Introduction</title>\r
+            <p>ExcelAnt is a set of Ant tasks that make it possible to verify or test\r
+            a workbook without having to write Java code.  Of course, the tasks themselves\r
+            are written in Java, but to use this frame work you only need to know a little \r
+            bit about Ant.</p>\r
+            <p>This document covers the basic usage and set up of ExcelAnt.</p>\r
+            <p>This document will assume basic familiarity with Ant and Ant build files.</p>\r
+     </section>\r
+     <section><title>Setup</title>\r
+            <p>To start with, you'll need to have the POI 3.8 or higher jar files.  If you test only .xls\r
+workbooks then you need to have the following jars in your path:</p>\r
+            <ul>\r
+                <li>poi-excelant-$version-YYYYDDMM.jar</li>\r
+                <li>poi-$version-YYYYDDMM.jar</li>\r
+                <li>poi-ooxml-$version-YYYYDDMM.jar</li>\r
+            </ul>\r
+            <p> If you evaluate .xlsx workbooks then you need to add these: </p>\r
+            <ul>\r
+                <li>poi-ooxml-schemas-$version-YYYYDDMM.jar</li>\r
+                <li>xmlbeans.jar</li>\r
+                <li>dom4j.jar</li>\r
+            </ul>\r
+            <p>For example, if you have these jars in a lib/ dir in your project, your build.xml \r
+            might look like this:</p>\r
+<source><![CDATA[\r
+<property name="lib.dir" value="lib" />\r
+\r
+<path id="excelant.path">\r
+    <pathelement location="${lib.dir}/poi-excelant-3.8-beta1-20101230.jar" />\r
+    <pathelement location="${lib.dir}/poi-3.8-beta1-20101230.jar" />\r
+    <pathelement location="${lib.dir}/poi-ooxml-3.8-beta1-20101230.jar" />\r
+</path>     \r
+]]></source>       \r
+        <p>Next, you'll need to define the Ant tasks. There are several ways to use ExcelAnt:</p>\r
+\r
+<ul><li>The traditional way:</li></ul>\r
+<source><![CDATA[\r
+    <typedef resource="org/apache/poi/ss/excelant/antlib.xml" classpathref="excelant.path" />\r
+]]></source>\r
+<p>\r
+ Where excelant.path referes to the classpath with POI jars.\r
+ Using this approach the provided extensions will live in the default namespace. Note that the default task/typenames (evaluate, test) may be too generic and should either be explicitly overridden or used with a namespace.\r
+</p>\r
+<ul><li>Similar, but assigning a namespace URI:</li></ul> \r
+<source><![CDATA[\r
+<project name="excelant-demo"  xmlns:poi="antlib:org.apache.poi.ss.excelant">\r
+\r
+    <typedef resource="org/apache/poi/ss/excelant/antlib.xml"\r
+             classpathref="excelant.classpath"\r
+             uri="antlib:org.apache.poi.ss.excelant"/>\r
+\r
+    <target name="test-nofile">\r
+        <poi:excelant>\r
+\r
+        </poi:excelant>\r
+    </target>\r
+</project>\r
+]]></source>\r
+      </section>\r
\r
+      <section><title>A Simple Example</title>\r
+     <p>The simplest example of using Excel is the ability to validate that POI is giving you back\r
+     the value you expect it to. Does this mean that POI is inaccurate?  Hardly.  There are cases\r
+     where POI is unable to evaluate cells for a variety of reasons.  If you need to write code\r
+     to integrate a worksheet into an app, you may want to know that it's going to work before \r
+     you actually try to write that code.  ExcelAnt helps with that.</p>\r
+     \r
+     <p>Consider the mortgage-calculation.xls file found in the Examples \r
+     (/examples/src/org/apache/poi/ss/examples/excelant/simple-mortgage-calculation.xls).  This sheet\r
+     is shown below:</p>\r
+     \r
+     <!--img src="../resources/images/simple-xls-with-function.jpg" alt="mortgage calculation spreadsheet"/-->\r
+     \r
+          <p>This sheet calculates the principal and interest payment for a mortgage based\r
+     on the amount of the loan, term and rate. To write a simple ExcelAnt test you \r
+     need to tell ExcelAnt about the file like this:</p>\r
+<source><![CDATA[\r
+<property name="xls.file" value="" />\r
+     \r
+<target name="simpleTest">\r
+    <excelant fileName="${xls.file}">\r
+        <test name="checkValue" showFailureDetail="true">\r
+            <evaluate showDelta="true" cell="'MortgageCalculator'!$B$4" expectedValue="790.7936" precision="1.0e-4" />\r
+        </test>\r
+    </excelant>\r
+</target>   \r
+]]></source>\r
+\r
+     \r
+     <p>This code sets up ExcelAnt to access the file defined in the ant property\r
+     xls.file.  Then it creates a 'test' named 'checkValue'.  Finally it tries\r
+     to evaluate the B4 on the sheet named 'MortgageCalculator'.   There are some assumptions\r
+     here that are worth explaining.  For starters, ExcelAnt is focused on the testing\r
+     numerically oriented sheets.  The &lt;evaluate&gt; task is actually evaluating the\r
+     cell as a formula using a FormulaEvaluator instance from POI.  Therefore it will fail\r
+     if you point it to a cell that doesn't contain a formula or a test a plain old number.</p>\r
+     \r
+     <p>Having said all that, here is what the output looks like:</p>\r
+     \r
+<source><![CDATA[\r
+simpleTest:\r
+ [excelant] ExcelAnt version 0.4.0 Copyright 2011\r
+ [excelant] Using input file: resources/excelant.xls\r
+ [excelant] 1/1 tests passed.\r
+BUILD SUCCESSFUL\r
+Total time: 391 milliseconds     \r
+]]></source>\r
+\r
+               </section>\r
+               \r
+               <section><title>Setting Values into a Cell</title>\r
+     <p>So now we know that at a minimum POI can use our sheet to calculate the existing value.\r
+     This is an important point: in many cases sheets have dependencies, i.e., cells they reference.\r
+     As is often the case, these cells may have dependencies, which may have dependencies, etc.\r
+     The point is that sometimes a dependent cell may get adjusted by a macro or a function\r
+     and it may be that POI doesn't have the capabilities to do the same thing.  This test\r
+     verifies that we can rely on POI to retrieve the default value, based on the stored values\r
+     of the sheet.  Now we want to know if we can manipulate those dependencies and verify\r
+     the output.</p>\r
+     \r
+     <p>To verify that we can manipulate cell values, we need a way in ExcelAnt to set a value.\r
+     This is provided by the following task types:</p>\r
+     <ul>\r
+        <li>setDouble() - sets the specified cell as a double.</li>\r
+        <li>setFormula() - sets the specified cell as a formula.</li>\r
+        <li>setString() = sets the specified cell as a String.</li>\r
+     </ul>\r
+     \r
+     <p>For the purposes of this example we'll use the &lt;setDouble&gt; task.  Let's\r
+     start with a $240,000, 30 year loan at 11% (let's pretend it's like 1984).  Here\r
+     is how we will set that up:</p>\r
+     \r
+<source><![CDATA[\r
+<setDouble cell="'MortgageCalculator'!$B$1" value="240000"/>\r
+<setDouble cell="'MortgageCalculator'!$B$2" value ="0.11"/>\r
+<setDouble cell="'MortgageCalculator'!$B$3" value ="30"/>\r
+<evaluate showDelta="true" cell="'MortgageCalculator'!$B$4" expectedValue="2285.576149" precision="1.0e-4" />     \r
+]]></source>\r
+\r
+     <p>Don't forget that we're verifying the behavior so you need to put all this\r
+     into the sheet.  That is how I got the result of $2,285 and change. So save your\r
+     changes and run it; you should get the following: </p>\r
+     \r
+<source><![CDATA[     \r
+Buildfile: C:\opt\eclipse\workspaces\excelant\excelant.examples\build.xml\r
+simpleTest:\r
+ [excelant] ExcelAnt version 0.4.0 Copyright 2011\r
+ [excelant] Using input file: resources/excelant.xls\r
+ [excelant] 1/1 tests passed.\r
+BUILD SUCCESSFUL\r
+Total time: 406 milliseconds     \r
+]]></source>\r
+\r
+</section>\r
+               \r
+               <section><title>Getting More Details</title>\r
+\r
+      <p>This is great, it's working! However, suppose you want to see a little more detail.  The\r
+      ExcelAnt tasks leverage the Ant logging so you can add the -verbose and -debug flags to\r
+      the Ant command line to get more detail.  Try adding -verbose.  Here is what \r
+      you should see:</p>\r
+      \r
+<source><![CDATA[\r
+simpleTest:\r
+ [excelant] ExcelAnt version 0.4.0 Copyright 2011\r
+ [excelant] Using input file: resources/excelant.xls\r
+ [evaluate] test precision = 1.0E-4 global precision = 0.0\r
+ [evaluate] Using evaluate precision of 1.0E-4\r
+ [excelant] 1/1 tests passed.\r
+BUILD SUCCESSFUL\r
+Total time: 406 milliseconds     \r
+]]></source>\r
+\r
+     \r
+     <p>We see a little more detail.  Notice that we see that there is a setting for global precision.\r
+     Up until now we've been setting the precision on each evaluate that we call.  This \r
+     is obviously useful but it gets cumbersome.  It would be better if there were a way\r
+     that we could specify a global precision - and there is.  There is a &lt;precision&gt; \r
+     tag that you can specify as a child of the &lt;excelant&gt; tag.  Let's go back to \r
+     our original task we set up earlier and modify it:</p>\r
+     \r
+<source><![CDATA[\r
+<property name="xls.file" value="" />\r
+     \r
+<target name="simpleTest">\r
+    <excelant fileName="${xls.file}">\r
+        <precision value="1.0e-3"/>\r
+        <test name="checkValue" showFailureDetail="true">\r
+            <evaluate showDelta="true" cell="'MortgageCalculator'!$B$4" expectedValue="790.7936" />\r
+        </test>\r
+    </excelant>\r
+</target>   \r
+]]></source>\r
+     \r
+     <p>In this example we have set the global precision to 1.0e-3.  This means that\r
+     in the absence of something more stringent, all tests in the task will use\r
+     the global precision.  We can still override this by specifying the\r
+     precision attribute of all of our &lt;evaluate&gt; task.  Let's first run\r
+     this task with the global precision and the -verbose flag:</p>\r
+     \r
+<source><![CDATA[     \r
+simpleTest:\r
+[excelant] ExcelAnt version 0.4.0 Copyright 2011\r
+[excelant] Using input file: resources/excelant.xls\r
+[excelant] setting precision for the test checkValue\r
+    [test] setting globalPrecision to 0.0010 in the evaluator\r
+[evaluate] test precision = 0.0  global precision = 0.0010\r
+[evaluate] Using global precision of 0.0010\r
+[excelant] 1/1 tests passed.\r
+]]></source>\r
+\r
+     \r
+     <p>As the output clearly shows, the test itself has no precision but there is\r
+     the global precision.  Additionally, it tells us we're going to use that\r
+     more stringent global value. Now suppose that for this test we want \r
+     to use a more stringent precision, say 1.0e-4.  We can do that by adding\r
+     the precision attribute back to the &lt;evaluate&gt; task:</p>\r
+\r
+<source><![CDATA[\r
+<excelant fileName="${xls.file}">\r
+    <precision value="1.0e-3"/>\r
+    <test name="checkValue" showFailureDetail="true">\r
+        <setDouble cell="'MortgageCalculator'!$B$1" value="240000"/>\r
+        <setDouble cell="'MortgageCalculator'!$B$2" value ="0.11"/>\r
+        <setDouble cell="'MortgageCalculator'!$B$3" value ="30"/>\r
+        <evaluate showDelta="true" cell="'MortgageCalculator'!$B$4" expectedValue="2285.576149" precision="1.0e-4" />\r
+    </test>\r
+</excelant>\r
+]]></source>\r
+\r
+\r
+     <p>Now when you re-run this test with the verbose flag you will see that\r
+     your test ran and passed with the higher precision:</p>\r
+<source><![CDATA[\r
+simpleTest:\r
+ [excelant] ExcelAnt version 0.4.0 Copyright 2011\r
+ [excelant] Using input file: resources/excelant.xls\r
+ [excelant] setting precision for the test checkValue\r
+     [test] setting globalPrecision to 0.0010 in the evaluator\r
+ [evaluate] test precision = 1.0E-4 global precision = 0.0010\r
+ [evaluate] Using evaluate precision of 1.0E-4 over the global precision of 0.0010\r
+ [excelant] 1/1 tests passed.\r
+BUILD SUCCESSFUL\r
+Total time: 390 milliseconds     \r
+]]></source>\r
+     </section>\r
+     \r
+     <section><title>Leveraging User Defined Functions</title>\r
+     <p>POI has an excellent feature (besides ExcelAnt) called <link href="user-defined-functions.html">User Defined Functions</link>,\r
+     that allows you to write Java code that will be used in place of custom VB\r
+     code or macros is a spreadsheet.  If you have read the documentation and written\r
+     your own FreeRefFunction implmentations, ExcelAnt can make use of this code.\r
+     For each &lt;excelant&gt; task you define you can nest a &lt;udf&gt; tag \r
+     which allows you to specify the function alias and the class name.</p>\r
+     \r
+     <p>Consider the previous example of the mortgage calculator.  What if, instead\r
+     of being a formula in a cell, it was a function defined in a VB macro?  As luck\r
+     would have it, we already have an example of this in the examples from the \r
+     User Defined Functions example, so let's use that. In the example spreadsheet\r
+     there is a tab for  MortgageCalculatorFunction, which will use.  If you look in\r
+     cell B4, you see that rather than a messy cell based formula, there is only the function\r
+     call.  Let's not get bogged down in the function/Java implementation, as these\r
+     are covered in the User Defined Function documentation.  Let's just add\r
+     a new target and test to our existing build file:</p> \r
+<source><![CDATA[\r
+  <target name="functionTest">\r
+      <excelant fileName="${xls.file}">\r
+          <udf functionAlias="calculatePayment" class="org.apache.poi.ss.examples.formula.CalculateMortgage"/>\r
+          <precision value="1.0e-3"/>\r
+          <test name="checkValue" showFailureDetail="true">\r
+              <setDouble cell="'MortgageCalculator'!$B$1" value="240000"/>\r
+              <setDouble cell="'MortgageCalculator'!$B$2" value ="0.11"/>\r
+              <setDouble cell="'MortgageCalculator'!$B$3" value ="30"/>\r
+              <evaluate showDelta="true" cell="'MortgageCalculatorFunction'!$B$4" expectedValue="2285.576149" precision="1.0e-4" />\r
+          </test>\r
+       </excelant>\r
+    </target>\r
+]]></source> \r
+\r
+     <p>So if you look at this carefully it looks the same as the previous examples.  We\r
+     still use the global precision, we're still setting values, and we still want\r
+     to evaluate a cell.  The only real differences are the sheet name and the\r
+     addition of the function.</p>    \r
+     </section>\r
+ </section>\r
+</body>\r
+</document>      \r
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntEvaluateCell.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntEvaluateCell.java
new file mode 100755 (executable)
index 0000000..d35cc6a
--- /dev/null
@@ -0,0 +1,146 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import org.apache.poi.ss.excelant.util.ExcelAntEvaluationResult;
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Instances of this class are used to evaluate a single cell.  This is usually
+ * after some values have been set.  The evaluation is actually performed
+ * by a WorkbookUtil instance.  The evaluate() method of the WorkbookUtil
+ * class returns an EvaluationResult which encapsulates the results and 
+ * information from the evaluation.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+
+ *
+ */
+public class ExcelAntEvaluateCell extends Task {
+
+       private String cell ;
+       private double expectedValue ;
+       private double precision ;
+       private double precisionToUse ;
+       private double globalPrecision ;
+       private boolean requiredToPass = false ;
+       
+       
+       private ExcelAntEvaluationResult result  ;
+       
+       private ExcelAntWorkbookUtil wbUtil ;
+       
+       private boolean showDelta = false ;
+       
+       
+       public ExcelAntEvaluateCell() {}
+
+       protected void setWorkbookUtil( ExcelAntWorkbookUtil wb ) {
+               wbUtil = wb ;
+       }
+       
+       public void setShowDelta( boolean value ) {
+               showDelta = value ;
+       }
+       
+       protected boolean showDelta() {
+               return showDelta ;
+       }
+       
+       public void setCell(String cell) {
+               this.cell = cell;
+       }
+       
+       public void setRequiredToPass( boolean val ) {
+           requiredToPass = val ;
+       }
+       
+       protected boolean requiredToPass() {
+           return requiredToPass ;
+       }
+
+       public void setExpectedValue(double expectedValue) {
+               this.expectedValue = expectedValue;
+       }
+
+       public void setPrecision(double precision) {
+               this.precision = precision;
+       }
+       
+       protected void setGlobalPrecision( double prec ) {
+               globalPrecision = prec ;
+       }
+
+       protected String getCell() {
+               return cell;
+       }
+
+       protected double getExpectedValue() {
+               return expectedValue;
+       }
+
+       protected double getPrecision() {
+               return precisionToUse;
+       }
+       
+       public void execute() throws BuildException {
+               
+               precisionToUse = 0 ;
+               
+               // if there is a globalPrecision we will use it unless there is also
+               // precision set at the evaluate level, then we use that.  If there
+               // is not a globalPrecision, we will use the local precision.
+               log( "test precision = " + precision + "\tglobal precision = " + globalPrecision, Project.MSG_VERBOSE ) ;
+               if( globalPrecision > 0 ) {
+                       if( precision > 0 ) {
+                               precisionToUse = precision ;
+                               log( "Using evaluate precision of " + precision + " over the " +
+                                                 "global precision of " + globalPrecision, Project.MSG_VERBOSE ) ;
+                       } else {
+                               precisionToUse = globalPrecision ;
+                               log( "Using global precision of " + globalPrecision, Project.MSG_VERBOSE ) ;
+                       }
+               } else {
+                       precisionToUse = precision ;
+                       log( "Using evaluate precision of " + precision, Project.MSG_VERBOSE ) ;
+               }
+               result = wbUtil.evaluateCell(cell, expectedValue, precisionToUse ) ;
+               
+               StringBuffer sb = new StringBuffer() ;
+               sb.append( "evaluation of cell " ) ;
+               sb.append( cell ) ; 
+               sb.append( " resulted in " ) ;
+               sb.append( result.getReturnValue() ) ;
+               if( showDelta == true ) {
+                       sb.append( " with a delta of " + result.getDelta() ) ;
+               }
+               
+               log( sb.toString(), Project.MSG_DEBUG) ;
+
+       }
+       
+       public ExcelAntEvaluationResult getResult() {
+               return result ;
+       }
+       
+       
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntHandlerTask.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntHandlerTask.java
new file mode 100755 (executable)
index 0000000..af210f6
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.excelant;\r
+\r
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;\r
+import org.apache.tools.ant.BuildException;\r
+import org.apache.tools.ant.Project;\r
+import org.apache.tools.ant.Task;\r
+\r
+/**\r
+ * This is the class that backs the <handler> tag in the Ant task.\r
+ * \r
+ * @author Jon Svede ( jon [at] loquatic [dot] com )\r
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )\r
+ *\r
+ */\r
+public class ExcelAntHandlerTask extends Task {\r
+    \r
+    private String className ;\r
+    \r
+    private ExcelAntWorkbookUtil wbUtil ;\r
+\r
+    public void setClassName( String cName ) {\r
+        className = cName ;\r
+    }\r
+    \r
+    protected void setEAWorkbookUtil( ExcelAntWorkbookUtil wkbkUtil ) {\r
+        wbUtil = wkbkUtil ;\r
+    }\r
+    \r
+    public void execute() throws BuildException {\r
+        log( "handling the workbook with class " + className, Project.MSG_INFO ) ;\r
+        try {\r
+            Class clazz = Class.forName( className ) ;\r
+            Object handlerObj = clazz.newInstance() ;\r
+            if( handlerObj instanceof IExcelAntWorkbookHandler ) {\r
+                IExcelAntWorkbookHandler iHandler = (IExcelAntWorkbookHandler)handlerObj ;\r
+                iHandler.setWorkbook( wbUtil.getWorkbook() ) ;\r
+                iHandler.execute() ;\r
+             }\r
+        } catch( Exception e ) {\r
+            throw new BuildException( e.getMessage(), e ) ;\r
+        }\r
+    }\r
+ }\r
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntPrecision.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntPrecision.java
new file mode 100755 (executable)
index 0000000..0739ef5
--- /dev/null
@@ -0,0 +1,39 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import org.apache.tools.ant.taskdefs.Typedef;
+
+/**
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ * 
+ */
+public class ExcelAntPrecision extends Typedef {
+       
+       private double value ;
+       
+       public void setValue( double precision ) {
+               value = precision ;
+       }
+       
+       public double getValue() {
+               return value ;
+       }
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSet.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSet.java
new file mode 100755 (executable)
index 0000000..974b1b9
--- /dev/null
@@ -0,0 +1,48 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.excelant;\r
+\r
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;\r
+import org.apache.tools.ant.Task;\r
+\r
+/**\r
+ * \r
+ * @author Jon Svede ( jon [at] loquatic [dot] com )\r
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )\r
+ * \r
+ */\r
+public abstract class ExcelAntSet extends Task {\r
+    \r
+    protected String cellStr ;\r
+    \r
+    protected ExcelAntWorkbookUtil wbUtil ;\r
+    \r
+    public void setCell( String cellName ) {\r
+        cellStr = cellName ;\r
+    }\r
+    \r
+    public String getCell() {\r
+        return cellStr ;\r
+    }\r
+    \r
+    \r
+    public void setWorkbookUtil( ExcelAntWorkbookUtil wb ) {\r
+        wbUtil = wb ;\r
+    }\r
+\r
+}\r
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetDoubleCell.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetDoubleCell.java
new file mode 100755 (executable)
index 0000000..a111350
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Class for use in an Ant build script that sets the value of an Excel
+ * sheet cell using the cell id ('Sheet Name'!cellId).
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ * 
+ */
+public class ExcelAntSetDoubleCell extends ExcelAntSet {
+       
+       
+       private double cellValue ;
+       
+       public ExcelAntSetDoubleCell() {}
+       
+       /**
+        * Set the value of the specified cell as the double passed in.
+        * @param value
+        */
+       public void setValue( double value ) {
+               cellValue = value ;
+       }
+
+       /**
+        * Return the cell value as a double.
+        * @return
+        */
+       public double getCellValue() {
+               return cellValue;
+       }
+       
+       public void execute() throws BuildException {
+
+               wbUtil.setDoubleValue(cellStr, cellValue ) ;
+               
+               log( "set cell " + cellStr + " to value " + cellValue + " as double.", Project.MSG_DEBUG ) ;
+       }
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetFormulaCell.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetFormulaCell.java
new file mode 100755 (executable)
index 0000000..1b9d5f0
--- /dev/null
@@ -0,0 +1,52 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Class for use in an Ant build script that sets the formula of an Excel
+ * sheet cell using the cell id ('Sheet Name'!cellId).
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class ExcelAntSetFormulaCell extends ExcelAntSet {
+       
+       
+       private String cellValue ;
+       
+       public ExcelAntSetFormulaCell() {}
+       
+       public void setValue( String value ) {
+               cellValue = value ;
+       }
+
+       protected String getCellValue() {
+               return cellValue;
+       }
+       
+       public void execute() throws BuildException {
+               
+               wbUtil.setFormulaValue( cellStr, cellValue ) ;
+               
+               log( "set cell " + cellStr + " to formula " + cellValue, Project.MSG_DEBUG ) ;
+       }
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetStringCell.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntSetStringCell.java
new file mode 100755 (executable)
index 0000000..12221ee
--- /dev/null
@@ -0,0 +1,62 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Class for use in an Ant build script that sets the value of an Excel
+ * sheet cell using the cell id ('Sheet Name'!cellId).
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class ExcelAntSetStringCell extends ExcelAntSet {
+       
+       
+       private String stringValue ;
+       
+       
+       public ExcelAntSetStringCell() {}
+
+       
+       /**
+        * Set the value of the cell to the String passed in.
+        * @param value
+        */
+       public void setValue(String value ) {
+               stringValue = value ;
+       }
+
+       /**
+        * Return the value that will be set into the cell.
+        * @return
+        */
+       public String getCellValue() {
+               return stringValue;
+       }
+       
+       public void execute() throws BuildException {
+
+               wbUtil.setStringValue(cellStr, stringValue ) ;
+               
+               log( "set cell " + cellStr + " to value " + stringValue + " as String.", Project.MSG_DEBUG ) ;
+       }
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntTask.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntTask.java
new file mode 100755 (executable)
index 0000000..1bbbb7d
--- /dev/null
@@ -0,0 +1,193 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtilFactory;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Ant task class for testing Excel workbook cells.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class ExcelAntTask extends Task {
+    
+    public static final String VERSION = "0.5.0" ;
+       
+       private String excelFileName ;
+       
+       private boolean failOnError = false  ;
+       
+       private ExcelAntWorkbookUtil workbookUtil ;
+       
+       private ExcelAntPrecision precision ;
+       
+       private LinkedList<ExcelAntTest> tests ;
+       private LinkedList<ExcelAntUserDefinedFunction> functions ;
+       
+       public ExcelAntTask() {
+               tests = new LinkedList<ExcelAntTest>() ;
+               functions = new LinkedList<ExcelAntUserDefinedFunction>() ;
+       }
+
+       public void addPrecision( ExcelAntPrecision prec ) {
+               precision = prec ;
+       }
+       
+       public void setFailOnError( boolean value ) {
+               failOnError = value ;
+       }
+       public void setFileName( String fileName ) {
+               excelFileName = fileName ;
+       }
+       
+       public void addTest( ExcelAntTest testElement ) {
+               tests.add( testElement ) ;
+       }
+       
+       public void addUdf( ExcelAntUserDefinedFunction def ) {
+               functions.add( def ) ;
+       }
+       
+       public void execute() throws BuildException {
+        checkClassPath();
+
+               int totalCount = 0 ;
+               int successCount = 0 ;
+               
+               StringBuffer versionBffr = new StringBuffer() ;
+               versionBffr.append(  "ExcelAnt version " ) ;
+               versionBffr.append( VERSION ) ;
+               versionBffr.append( " Copyright 2011" ) ;
+               SimpleDateFormat sdf = new SimpleDateFormat( "yyyy" ) ;
+               double currYear = Double.parseDouble( sdf.format( new Date() ) );
+               if( currYear > 2011 ) {
+                   versionBffr.append( "-" ) ;
+                   versionBffr.append( currYear ) ;
+               }
+               log( versionBffr.toString(), Project.MSG_INFO ) ;
+               
+               log( "Using input file: " + excelFileName, Project.MSG_INFO ) ;
+               
+               Workbook targetWorkbook = loadWorkbook() ;
+               if( targetWorkbook == null ) {
+                       log( "Unable to load " + excelFileName + 
+                                                   ".  Verify the file exists and can be read.",
+                                                   Project.MSG_ERR ) ;
+                       return ;
+               }
+               if( tests != null && tests.size() > 0 ) {
+                       
+                       Iterator<ExcelAntTest> testsIt = tests.iterator() ;
+                       while( testsIt.hasNext() ) {
+                               ExcelAntTest test = testsIt.next();
+                               
+                               log( "executing test: " + test.getName(), Project.MSG_DEBUG ) ;
+               
+                               workbookUtil = ExcelAntWorkbookUtilFactory.getInstance( excelFileName ) ;
+                               
+                               if( functions != null ) {
+                                       Iterator<ExcelAntUserDefinedFunction> functionsIt = functions.iterator() ;
+                                       while( functionsIt.hasNext() ) {
+                                               ExcelAntUserDefinedFunction eaUdf = functionsIt.next() ;
+                                               try {
+                                                       workbookUtil.addFunction(eaUdf.getFunctionAlias(), eaUdf.getClassName() ) ;
+                                               } catch ( Exception e) {
+                                                       throw new BuildException( e.getMessage(), e ); 
+                                               }
+                                       }
+                               }
+                               test.setWorkbookUtil( workbookUtil ) ;
+                               
+                               if( precision != null && precision.getValue() > 0 ) {
+                                       log( "setting precision for the test " + test.getName(), Project.MSG_VERBOSE ) ; 
+                                       test.setPrecision( precision.getValue() ) ;
+                               }
+                               
+                               test.execute() ;
+                               
+                               if( test.didTestPass() ) {
+                                       successCount++ ;
+                               } else {
+                                       if( failOnError == true ) {
+                                               throw new BuildException( "Test " + test.getName() + " failed." ) ;
+                                       }
+                               }
+                               totalCount++ ;
+                               
+                               workbookUtil = null ;
+                       }
+                       log( successCount + "/" + totalCount + " tests passed.", Project.MSG_INFO ) ;
+                       workbookUtil = null ;
+               }
+       }
+       
+
+    private Workbook loadWorkbook() {
+        if (excelFileName == null) {
+            throw new BuildException("fileName attribute must be set!",
+                                     getLocation());
+        }
+
+               Workbook workbook;
+               File workbookFile = new File( excelFileName ) ;
+        try {
+            FileInputStream fis = new FileInputStream( workbookFile ) ;
+            workbook = WorkbookFactory.create( fis ) ;
+        } catch (Exception e) {
+            throw new BuildException("Cannot load file " + excelFileName
+                    + ". Make sure the path and file permissions are correct.", e, getLocation());
+        }
+               return workbook ;
+       }
+
+
+    /**
+     * ExcelAnt depends on external libraries not included in the Ant distribution.
+     * Give user a sensible message if any if the required jars are missing.
+     */
+    private void checkClassPath(){
+        try {
+            Class.forName("org.apache.poi.hssf.usermodel.HSSFWorkbook");
+            Class.forName("org.apache.poi.ss.usermodel.WorkbookFactory");
+        } catch (Throwable e) {
+            throw new BuildException(
+                    "The <classpath> for <excelant> must include poi.jar and poi-ooxml.jar " +
+                    "if not in Ant's own classpath. Processing .xlsx spreadsheets requires " +
+                    "additional poi-ooxml-schemas.jar, xmlbeans.jar and dom4j.jar" ,
+                    e, getLocation());
+        }
+
+    }
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntTest.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntTest.java
new file mode 100755 (executable)
index 0000000..b97d1ae
--- /dev/null
@@ -0,0 +1,224 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.apache.poi.ss.excelant.util.ExcelAntEvaluationResult;
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * This class represents a single test.  In order for the test any and all
+ * ExcelAntEvaluateCell evaluations must pass.  Therefore it is recommended
+ * that you use only 1 evaluator but you can use more if you choose.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class ExcelAntTest extends Task{
+       
+       private LinkedList<ExcelAntSet> setters ;
+       private LinkedList<ExcelAntEvaluateCell>evaluators ;
+       
+       private LinkedList<Task> testTasks ;
+       
+       private String name ;
+       
+       private double globalPrecision ;
+       
+       private boolean showSuccessDetails = false ;
+       
+       private boolean showFailureDetail = false ;
+       LinkedList<String> failureMessages ;
+       
+
+       private ExcelAntWorkbookUtil workbookUtil ;
+       
+       private boolean passed = true ;
+
+       
+       public ExcelAntTest() {
+               setters = new LinkedList<ExcelAntSet>() ;
+               evaluators = new LinkedList<ExcelAntEvaluateCell>() ;
+               failureMessages = new LinkedList<String>() ;
+               testTasks = new LinkedList<Task>() ;
+       }
+       
+       public void setPrecision( double precision ) {
+               globalPrecision = precision ;
+       }
+       
+       public void setWorkbookUtil( ExcelAntWorkbookUtil wbUtil ) {
+               workbookUtil = wbUtil ;
+       }
+       
+       
+       public void setShowFailureDetail( boolean value ) {
+               showFailureDetail = value ;
+       }
+       
+       public void setName( String nm ) {
+               name = nm ;
+       }
+       
+       public String getName() {
+               return name ;
+       }
+       
+       public void setShowSuccessDetails( boolean details ) {
+           showSuccessDetails = details ;
+       }
+       
+       public boolean showSuccessDetails() {
+           return showSuccessDetails ;
+       }
+       
+       public void addSetDouble( ExcelAntSetDoubleCell setter ) {
+           addSetter( setter ) ;
+       }
+       
+       public void addSetString( ExcelAntSetStringCell setter ){
+           addSetter( setter ) ;
+       }
+       
+       public void addSetFormula( ExcelAntSetFormulaCell setter ) {
+           addSetter( setter ) ;
+       }
+       
+       public void addHandler( ExcelAntHandlerTask handler ) {
+           testTasks.add( handler ) ;
+       }
+       
+       private void addSetter( ExcelAntSet setter ) {
+//             setters.add( setter );
+               testTasks.add( setter ) ;
+       }
+       
+       public void addEvaluate( ExcelAntEvaluateCell evaluator ) {
+//             evaluators.add( evaluator ) ;
+               testTasks.add( evaluator ) ;
+       }
+       
+//     public LinkedList<ExcelAntSet> getSetters() {
+//             return setters;
+//     }
+
+       protected LinkedList<ExcelAntEvaluateCell> getEvaluators() {
+               return evaluators;
+       }
+       
+       public void execute() throws BuildException {
+           
+           Iterator<Task> taskIt = testTasks.iterator() ;
+
+           int testCount = evaluators.size() ;
+           int failureCount = 0 ;
+               
+           // roll over all sub task elements in one loop.  This allows the
+           // ordering of the sub elements to be considered. 
+           while( taskIt.hasNext() ) {
+               Task task = taskIt.next() ;
+               
+              // log( task.getClass().getName(), Project.MSG_INFO ) ;
+               
+               if( task instanceof ExcelAntSet ) {
+                   ExcelAntSet set = (ExcelAntSet) task ;
+                   set.setWorkbookUtil(workbookUtil)  ;
+                   set.execute() ;
+               }
+               
+               if( task instanceof ExcelAntHandlerTask ) {
+                   ExcelAntHandlerTask handler = (ExcelAntHandlerTask)task ;
+                   handler.setEAWorkbookUtil(workbookUtil ) ;
+                   handler.execute() ;
+               }
+               
+               if (task instanceof ExcelAntEvaluateCell ) {
+                   ExcelAntEvaluateCell eval = (ExcelAntEvaluateCell)task ;
+                   eval.setWorkbookUtil( workbookUtil ) ;
+                   
+                   if( globalPrecision > 0 ) {
+                       log( "setting globalPrecision to " + globalPrecision + " in the evaluator", Project.MSG_VERBOSE ) ;
+                       eval.setGlobalPrecision( globalPrecision ) ;
+                   }
+
+                   try {
+                       eval.execute() ;
+                       ExcelAntEvaluationResult result = eval.getResult() ;
+                       if( result.didTestPass() && 
+                               result.evaluationCompleteWithError() == false ) {
+                           if( showSuccessDetails == true ) {
+                               log("Succeeded when evaluating " + 
+                                result.getCellName() + ".  It evaluated to " + 
+                             result.getReturnValue() + " when the value of " + 
+                             eval.getExpectedValue() + " with precision of " + 
+                             eval.getPrecision(), Project.MSG_INFO ) ;
+                           }
+                       } else {
+                           if( showFailureDetail == true ) {
+                               failureMessages.add( "\tFailed to evaluate cell " + 
+                                result.getCellName() + ".  It evaluated to " + 
+                                result.getReturnValue() + " when the value of " + 
+                                eval.getExpectedValue() + " with precision of " + 
+                                eval.getPrecision() + " was expected." ) ;
+
+                           }
+                           passed = false ;
+                           failureCount++ ;
+                           
+                           if( eval.requiredToPass() == true ) {
+                               throw new BuildException( "\tFailed to evaluate cell " + 
+                                       result.getCellName() + ".  It evaluated to " + 
+                                       result.getReturnValue() + " when the value of " + 
+                                       eval.getExpectedValue() + " with precision of " + 
+                                       eval.getPrecision() + " was expected." ) ;
+                           }
+                       }
+                   } catch( NullPointerException npe ) {
+                       // this means the cell reference in the test is bad.
+                       log( "Cell assignment " + eval.getCell() + " in test " + getName() + 
+                             " appears to point to an empy cell.  Please check the " +
+                             " reference in the ant script.", Project.MSG_ERR ) ;
+                   }
+               }
+           }
+               if( passed == false ) {
+                       log( "Test named " + name + " failed because " + failureCount + 
+                                        " of " + testCount + " evaluations failed to " + 
+                                        "evaluate correctly.", 
+                                        Project.MSG_ERR ) ;
+                       if( showFailureDetail == true && failureMessages.size() > 0 ) {
+                               Iterator<String> failures = failureMessages.iterator() ;
+                               while( failures.hasNext() ) {
+                                       log( failures.next(), Project.MSG_ERR ) ;
+                               }
+                       }
+               }
+       }
+
+       public boolean didTestPass() {
+               
+               return passed ;
+       }
+ }
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntUserDefinedFunction.java b/src/excelant/java/org/apache/poi/ss/excelant/ExcelAntUserDefinedFunction.java
new file mode 100755 (executable)
index 0000000..f69e9b6
--- /dev/null
@@ -0,0 +1,55 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import org.apache.tools.ant.taskdefs.Typedef;
+
+/**
+ * This class encapsulates the Strings necessary to create the User Defined
+ * Function instances that will be passed to POI's Evaluator instance.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class ExcelAntUserDefinedFunction extends Typedef {
+
+       
+       public String functionAlias ;
+       
+       public String className ;
+
+       
+       public ExcelAntUserDefinedFunction() {}
+
+       protected String getFunctionAlias() {
+               return functionAlias;
+       }
+
+       public void setFunctionAlias(String functionAlias) {
+               this.functionAlias = functionAlias;
+       }
+
+       protected String getClassName() {
+               return className;
+       }
+
+       public void setClassName(String className) {
+               this.className = className;
+       }
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/IExcelAntWorkbookHandler.java b/src/excelant/java/org/apache/poi/ss/excelant/IExcelAntWorkbookHandler.java
new file mode 100755 (executable)
index 0000000..3cd477a
--- /dev/null
@@ -0,0 +1,46 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.excelant;\r
+\r
+import org.apache.poi.ss.usermodel.Workbook;\r
+\r
+\r
+/**\r
+ * In Excel there are many ways to handle manipulating a workbook based \r
+ * on some arbitrary user action (onChange, etc).  You use this interface\r
+ * to create classes that will handle the workbook in whatever manner is needed\r
+ * that cannot be handled by POI.\r
+ * <p>\r
+ * For example, suppose that in Excel when you update a cell the workbook\r
+ * does some calculations and updates other cells based on that change.  In\r
+ * ExcelAnt you would set the value of the cell then write your own handler\r
+ * then call that from your Ant task after the set task.\r
+ * \r
+ * @author Jon Svede ( jon [at] loquatic [dot] com )\r
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )\r
+ *\r
+ */\r
+public interface IExcelAntWorkbookHandler {\r
+    \r
+    \r
+    public void setWorkbook( Workbook workbook ) ;\r
+    \r
+    public void execute() ;\r
+    \r
+\r
+}\r
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntEvaluationResult.java b/src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntEvaluationResult.java
new file mode 100755 (executable)
index 0000000..6633357
--- /dev/null
@@ -0,0 +1,114 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant.util;
+
+/**
+ * A simple class that encapsulates information about a cell evaluation
+ * from POI.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class ExcelAntEvaluationResult {
+       
+       /**
+        * This boolean flag is used to determine if the evaluation completed
+        * without error.  This alone doesn't ensure that the evaluation was 
+        * sucessful.
+        */
+       private boolean evaluationCompletedWithError ;
+       
+       /**
+        * This boolean flag is used to determine if the result was within
+        * the specified precision.
+        */
+       private boolean didPass ;
+       
+       /**
+        * This is the actual value returned from the evaluation.
+        */
+       private double returnValue ;
+       
+       /**
+        * Any error message String values that need to be returned.
+        */
+       private String errorMessage ;
+       
+       /**
+        * Stores the absolute value of the delta for this evaluation.
+        */
+       private double actualDelta ;
+       
+       /**
+        * This stores the fully qualified cell name (sheetName!cellId).
+        */
+       private String cellName ;
+       
+       
+
+       public ExcelAntEvaluationResult( boolean completedWithError,
+                                        boolean passed, 
+                                        double retValue, 
+                                        String errMessage, 
+                                        double delta,
+                                        String cellId ) {
+
+               evaluationCompletedWithError = completedWithError;
+               didPass = passed;
+               returnValue = retValue;
+               errorMessage = errMessage;
+               actualDelta = delta ;
+               cellName = cellId ;
+       }
+
+       public double getReturnValue() {
+               return returnValue;
+       }
+
+       public String getErrorMessage() {
+               return errorMessage;
+       }
+       
+       public boolean didTestPass() {
+               return didPass ;
+       }
+       
+       public boolean evaluationCompleteWithError() {
+               return evaluationCompletedWithError ;
+       }
+       
+       public double getDelta() {
+               return actualDelta ;
+       }
+       
+       public String getCellName() {
+               return cellName ;
+       }
+
+       @Override
+       public String toString() {
+               return "ExcelAntEvaluationResult [evaluationCompletedWithError="
+                               + evaluationCompletedWithError + ", didPass=" + didPass
+                               + ", returnValue=" + returnValue + ", errorMessage="
+                               + errorMessage + ", actualDelta=" + actualDelta + ", cellName="
+                               + cellName + "]";
+       }
+
+       
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtil.java b/src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtil.java
new file mode 100755 (executable)
index 0000000..af23d69
--- /dev/null
@@ -0,0 +1,384 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant.util;
+
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
+import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Typedef;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A general utility class that abstracts the POI details of loading the
+ * workbook, accessing and updating cells.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ * 
+ */
+public class ExcelAntWorkbookUtil extends Typedef {
+
+    private String excelFileName;
+
+    private Workbook workbook;
+
+    private HashMap<String, FreeRefFunction> xlsMacroList;
+    
+    /**
+     * Constructs an instance using a String that contains the fully qualified
+     * path of the Excel file. This constructor initializes a Workbook instance
+     * based on that file name.
+     * 
+     * @param fName
+     */
+    protected ExcelAntWorkbookUtil(String fName) {
+        excelFileName = fName;
+        xlsMacroList = new HashMap<String, FreeRefFunction>() ;
+        loadWorkbook();
+        
+    }
+
+    /**
+     * Constructs an instance based on a Workbook instance.
+     * 
+     * @param wb
+     */
+    protected ExcelAntWorkbookUtil(Workbook wb) {
+        workbook = wb;
+        xlsMacroList = new HashMap<String, FreeRefFunction>() ;
+    }
+
+    /**
+     * Loads the member variable workbook based on the fileName variable.
+     * @return
+     */
+    private Workbook loadWorkbook() {
+
+        File workbookFile = new File(excelFileName);
+        try {
+            FileInputStream fis = new FileInputStream(workbookFile);
+            workbook = WorkbookFactory.create(fis);
+        } catch(Exception e) {
+            throw new BuildException("Cannot load file " + excelFileName
+                    + ". Make sure the path and file permissions are correct.", e);
+        }
+
+        return workbook ;
+    }
+    
+    /**
+     * Used to add a UDF to the evaluator.  
+     * @param name
+     * @param clazzName
+     * @throws ClassNotFoundException
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    public void addFunction( String name, String clazzName ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+        Class clazzInst = Class.forName( clazzName ) ;
+        Object newInst = clazzInst.newInstance() ;
+        if( newInst instanceof FreeRefFunction ) {
+            addFunction( name, (FreeRefFunction)newInst ) ;
+        }
+        
+    }
+    /**
+     * Updates the internal HashMap of functions with instance and alias passed
+     * in.
+     * 
+     * @param name
+     * @param func
+     */
+    protected void addFunction(String name, FreeRefFunction func) {
+        xlsMacroList.put(name, func);
+    }
+
+    /**
+     * returns a UDFFinder that contains all of the functions added.
+     * 
+     * @return
+     */
+    protected UDFFinder getFunctions() {
+
+        String[] names = new String[xlsMacroList.size()];
+        FreeRefFunction[] functions = new FreeRefFunction[xlsMacroList.size()];
+
+        Iterator<String> keysIt = xlsMacroList.keySet().iterator();
+        int x = 0;
+        while (keysIt.hasNext()) {
+            String name = keysIt.next();
+            FreeRefFunction function = xlsMacroList.get(name);
+            names[x] = name;
+            functions[x] = function;
+        }
+
+        UDFFinder udff1 = new DefaultUDFFinder(names, functions);
+        UDFFinder udff = new AggregatingUDFFinder(udff1);
+
+        return udff;
+
+    }
+    
+    /**
+     * Returns a formula evaluator that is loaded with the functions that
+     * have been supplied.
+     * 
+     * @param excelFileName
+     * @return
+     */
+    protected FormulaEvaluator getEvaluator( String excelFileName ) {
+        FormulaEvaluator evaluator ;
+        if (excelFileName.endsWith(".xlsx")) {
+            if( xlsMacroList != null && xlsMacroList.size() > 0 ) {
+                evaluator = XSSFFormulaEvaluator.create( (XSSFWorkbook) workbook,
+                                                         null,
+                                                         getFunctions() ) ;
+            }
+            evaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);
+        } else {
+            if( xlsMacroList != null && xlsMacroList.size() > 0 ) {
+                evaluator = HSSFFormulaEvaluator.create( (HSSFWorkbook)workbook,
+                                                         null,
+                                                         getFunctions() ) ;
+            }
+
+            evaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);
+        }
+
+        return evaluator ;
+
+    }
+
+    /**
+     * Returns the Workbook instance associated with this WorkbookUtil.
+     * 
+     * @return
+     */
+    public Workbook getWorkbook() {
+        return workbook;
+    }
+
+    /**
+     * Returns the fileName that was used to initialize this instance. May
+     * return null if the instance was constructed from a Workbook object.
+     * 
+     * @return
+     */
+    public String getFileName() {
+        return excelFileName;
+    }
+    
+    /**
+     * Returns the list of sheet names.
+     * 
+     * @return
+     */
+    public ArrayList<String> getSheets() {
+       ArrayList<String> sheets = new ArrayList<String>() ;
+       
+       int sheetCount = workbook.getNumberOfSheets() ;
+       
+       for( int x=0; x<sheetCount; x++ ) {
+               sheets.add( workbook.getSheetName( x ) ) ;
+       }
+       
+       return sheets ;
+    }
+
+    /**
+     * This method uses a String in standard Excel format (SheetName!CellId) to
+     * locate the cell and set it to the value of the double in value.
+     * 
+     * @param cellName
+     * @param value
+     */
+    public void setDoubleValue(String cellName, double value) {
+        log("starting setCellValue()", Project.MSG_DEBUG);
+        Cell cell = getCell(cellName);
+        log("working on cell: " + cell, Project.MSG_DEBUG);
+        cell.setCellValue(value);
+        log("after cell.setCellValue()", Project.MSG_DEBUG);
+
+        log("set cell " + cellName + " to value " + value, Project.MSG_DEBUG);
+    }
+
+    /**
+     * Utility method for setting the value of a Cell with a String.
+     * 
+     * @param cellName
+     * @param value
+     */
+    public void setStringValue( String cellName, String value ) {
+        Cell cell = getCell(cellName);
+        cell.setCellValue(value);        
+    }
+    
+    /**
+     * Utility method for setting the value of a Cell with a Formula.
+     * 
+     * @param cellName
+     * @param formula
+     */
+    public void setFormulaValue( String cellName, String formula ) {
+        Cell cell = getCell(cellName);
+        cell.setCellFormula( formula );
+    }
+    
+    /**
+     * Utility method for setting the value of a Cell with a Date.
+     * @param cellName
+     * @param date
+     */
+    public void setDateValue( String cellName, Date date  ) {
+        Cell cell = getCell(cellName);
+        cell.setCellValue( date ) ;
+    }
+    /**
+     * Uses a String in standard Excel format (SheetName!CellId) to locate a
+     * cell and evaluate it.
+     * 
+     * @param cellName
+     * @param expectedValue
+     * @param precision
+     */
+    public ExcelAntEvaluationResult evaluateCell(String cellName, double expectedValue,
+            double precision) {
+
+        ExcelAntEvaluationResult evalResults = null;
+
+        Cell cell = getCell(cellName);
+
+        FormulaEvaluator evaluator = getEvaluator( excelFileName );
+
+
+        CellValue resultOfEval = evaluator.evaluate(cell);
+
+        if (resultOfEval.getErrorValue() == 0) {
+            // the evaluation did not encounter errors
+            double result = resultOfEval.getNumberValue();
+            double delta = Math.abs(result - expectedValue);
+            if (delta > precision) {
+                evalResults = new ExcelAntEvaluationResult(false, false,
+                        resultOfEval.getNumberValue(),
+                        "Results was out of range based on precision " + " of "
+                                + precision + ".  Delta was actually " + delta, delta, cellName );
+            } else {
+                evalResults = new ExcelAntEvaluationResult(false, true,
+                        resultOfEval.getNumberValue(),
+                        "Evaluation passed without error within in range.", delta, cellName );
+            }
+        } else {
+            String errorMeaning = null ;
+            try {
+                errorMeaning = ErrorConstants.getText( resultOfEval
+                        .getErrorValue() ) ;
+            } catch( IllegalArgumentException iae ) {
+                errorMeaning =  "unknown error code: " + 
+                                Byte.toString( resultOfEval.getErrorValue() ) ; 
+            }
+            
+            evalResults = new ExcelAntEvaluationResult(false, false,
+                    resultOfEval.getNumberValue(),
+                    "Evaluation failed due to an evaluation error of "
+                            + resultOfEval.getErrorValue()
+                            + " which is "
+                            + errorMeaning, 0, cellName );
+        }
+
+        return evalResults;
+    }
+
+    /**
+     * Returns a Cell as a String value.
+     * 
+     * @param cellName
+     * @return
+     */
+    public String getCellAsString( String cellName ) {
+       Cell cell = getCell( cellName ) ;
+       if( cell != null ) {
+               return cell.getStringCellValue() ;
+       }
+       return "" ;
+    }
+    
+    
+    /**
+     * Returns the value of the Cell as a double.
+     * 
+     * @param cellName
+     * @return
+     */
+    public double getCellAsDouble( String cellName ) {
+       Cell cell = getCell( cellName ) ;
+       if( cell != null ) {
+               return cell.getNumericCellValue() ;
+       }
+       return 0.0 ;
+    }
+    /**
+     * Returns a cell reference based on a String in standard Excel format
+     * (SheetName!CellId).  This method will create a new cell if the
+     * requested cell isn't initialized yet.
+     * 
+     * @param cellName
+     * @return
+     */
+    private Cell getCell(String cellName) {
+        
+        CellReference cellRef = new CellReference(cellName);
+        String sheetName = cellRef.getSheetName();
+        Sheet sheet = workbook.getSheet(sheetName);
+        if(sheet == null) {
+            throw new BuildException("Sheet not found: " + sheetName);
+        }
+
+        int rowIdx = cellRef.getRow();
+        int colIdx = cellRef.getCol();
+        Row row = sheet.getRow(rowIdx);
+        
+        if( row == null ) {
+               row = sheet.createRow( rowIdx ) ;
+        }
+        
+        Cell cell = row.getCell(colIdx);
+        
+        if( cell == null ) {
+               cell = row.createCell( colIdx ) ;
+        }
+
+        return cell;
+    }
+
+}
diff --git a/src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtilFactory.java b/src/excelant/java/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtilFactory.java
new file mode 100755 (executable)
index 0000000..6c29eeb
--- /dev/null
@@ -0,0 +1,63 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.excelant.util;\r
+\r
+import java.util.HashMap;\r
+\r
+\r
+/**\r
+ * This is a factory class maps file names to WorkbookUtil instances.  This\r
+ * helps ExcelAnt be more efficient when being run many times in an Ant build.\r
+ * \r
+ * @author Jon Svede ( jon [at] loquatic [dot] com )\r
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )\r
+ *\r
+ */\r
+public class ExcelAntWorkbookUtilFactory {\r
+    \r
+    private static HashMap<String, ExcelAntWorkbookUtil> workbookUtilMap ;\r
+    \r
+    private static ExcelAntWorkbookUtilFactory factory ;\r
+    \r
+    private ExcelAntWorkbookUtilFactory() {\r
+        workbookUtilMap = new HashMap<String, ExcelAntWorkbookUtil>() ; \r
+    }\r
+    \r
+    /**\r
+     * Using the fileName, check the internal map to see if an instance \r
+     * of the WorkbookUtil exists.  If not, then add an instance to the map.\r
+     * \r
+     * @param fileName\r
+     * @return\r
+     */\r
+    public static ExcelAntWorkbookUtil getInstance( String fileName ) {\r
+        \r
+        if( factory == null ) {\r
+            factory = new ExcelAntWorkbookUtilFactory() ;\r
+        }\r
+        if( workbookUtilMap != null && \r
+                workbookUtilMap.containsKey( fileName ) ) {\r
+            return workbookUtilMap.get( fileName ) ;\r
+        } else {\r
+            ExcelAntWorkbookUtil wbu = new ExcelAntWorkbookUtil( fileName ) ;\r
+            workbookUtilMap.put( fileName, wbu ) ;\r
+            return wbu ;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/excelant/resources/org/apache/poi/ss/excelant/antlib.xml b/src/excelant/resources/org/apache/poi/ss/excelant/antlib.xml
new file mode 100755 (executable)
index 0000000..31dadfa
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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>
+
+    <typedef name="excelant" classname="org.apache.poi.ss.excelant.ExcelAntTask" />
+    <typedef name="test" classname="org.apache.poi.ss.excelant.ExcelAntTest"/>
+    <typedef name="setDouble" classname="org.apache.poi.ss.excelant.ExcelAntSetDoubleCell"/>
+    <typedef name="setString" classname="org.apache.poi.ss.excelant.ExcelAntSetStringCell"/>
+    <typedef name="setFormula" classname="org.apache.poi.ss.excelant.ExcelAntSetFormulaCell"/>
+    <typedef name="evaluate" classname="org.apache.poi.ss.excelant.ExcelAntEvaluateCell"/>
+    <typedef name="udf" classname="org.apache.poi.ss.excelant.ExcelAntUserDefinedFunction"/>
+
+</antlib>
diff --git a/src/excelant/testcases/org/apache/poi/ss/examples/formula/CalculateMortgage.java b/src/excelant/testcases/org/apache/poi/ss/examples/formula/CalculateMortgage.java
new file mode 100755 (executable)
index 0000000..4b9a325
--- /dev/null
@@ -0,0 +1,93 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.examples.formula;
+
+import org.apache.poi.ss.formula.OperationEvaluationContext ;
+import org.apache.poi.ss.formula.eval.ErrorEval ;
+import org.apache.poi.ss.formula.eval.EvaluationException ;
+import org.apache.poi.ss.formula.eval.NumberEval ;
+import org.apache.poi.ss.formula.eval.OperandResolver ;
+import org.apache.poi.ss.formula.eval.ValueEval ;
+import org.apache.poi.ss.formula.functions.FreeRefFunction ;
+
+/**
+ * A simple user-defined function to calculate principal and interest.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class CalculateMortgage implements FreeRefFunction {
+
+    public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
+        
+        // verify that we have enough data
+        if (args.length != 3) {  
+            return ErrorEval.VALUE_INVALID;
+        }
+
+        // declare doubles for values
+        double principal, rate, years,  result;
+        try {
+            // extract values as ValueEval
+            ValueEval v1 = OperandResolver.getSingleValue( args[0], 
+                                                           ec.getRowIndex(), 
+                                                           ec.getColumnIndex() ) ;
+            ValueEval v2 = OperandResolver.getSingleValue( args[1], 
+                                                           ec.getRowIndex(), 
+                                                           ec.getColumnIndex() ) ;
+            ValueEval v3 = OperandResolver.getSingleValue( args[2], 
+                                                           ec.getRowIndex(), 
+                                                           ec.getColumnIndex() ) ;
+
+            // get data as doubles
+            principal  = OperandResolver.coerceValueToDouble( v1 ) ; 
+            rate  = OperandResolver.coerceValueToDouble( v2 ) ;
+            years = OperandResolver.coerceValueToDouble( v3 ) ;
+            
+            result = calculateMortgagePayment( principal, rate, years ) ;
+            System.out.println( "Result = " + result ) ;
+
+            checkValue(result);
+            
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+
+        return new NumberEval( result ) ;
+    }
+    
+    public double calculateMortgagePayment( double p, double r, double y ) {
+        double i = r / 12 ;
+        double n = y * 12 ;
+        
+        double principalAndInterest = 
+             p * (( i * Math.pow((1 + i),n ) ) / ( Math.pow((1 + i),n) - 1))  ;
+        
+        return principalAndInterest ;
+    }
+    /**
+     * Excel does not support infinities and NaNs, rather, it gives a #NUM! error in these cases
+     *
+     * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
+     */
+     private void checkValue(double result) throws EvaluationException {
+         if (Double.isNaN(result) || Double.isInfinite(result)) {
+             throw new EvaluationException(ErrorEval.NUM_ERROR);
+         }
+     }    
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/examples/formula/ExcelAntUserDefinedFunctionTestHelper.java b/src/excelant/testcases/org/apache/poi/ss/examples/formula/ExcelAntUserDefinedFunctionTestHelper.java
new file mode 100755 (executable)
index 0000000..68e4b69
--- /dev/null
@@ -0,0 +1,36 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.examples.formula;
+
+import org.apache.poi.ss.excelant.ExcelAntUserDefinedFunction;
+
+public class ExcelAntUserDefinedFunctionTestHelper extends
+               ExcelAntUserDefinedFunction {
+
+       @Override
+       protected String getFunctionAlias() {
+               // TODO Auto-generated method stub
+               return super.getFunctionAlias();
+       }
+
+       @Override
+       protected String getClassName() {
+               // TODO Auto-generated method stub
+               return super.getClassName();
+       }
+
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/examples/formula/TestExcelAntUserDefinedFunction.java b/src/excelant/testcases/org/apache/poi/ss/examples/formula/TestExcelAntUserDefinedFunction.java
new file mode 100755 (executable)
index 0000000..ad9851a
--- /dev/null
@@ -0,0 +1,51 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.examples.formula;
+
+import junit.framework.TestCase;
+
+public class TestExcelAntUserDefinedFunction extends TestCase {
+       
+       private ExcelAntUserDefinedFunctionTestHelper fixture ;
+       
+       @Override
+       public void setUp() {
+               fixture = new ExcelAntUserDefinedFunctionTestHelper() ;
+       }
+       
+       public void testSetClassName() {
+               String className = "simple.class.name" ;
+               
+               fixture.setClassName( className ) ;
+               String value = fixture.getClassName() ;
+               
+               assertNotNull( value ) ;
+               assertEquals( className, value ) ;
+       }
+       
+       public void testSetFunction() {
+               String functionAlias = "alias" ;
+               
+               fixture.setFunctionAlias( functionAlias ) ;
+               
+               String alias = fixture.getFunctionAlias() ;
+               
+               assertNotNull( alias ) ;
+               assertEquals( functionAlias, alias ) ;
+       }
+       
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/BuildFileTest.java b/src/excelant/testcases/org/apache/poi/ss/excelant/BuildFileTest.java
new file mode 100755 (executable)
index 0000000..5a30744
--- /dev/null
@@ -0,0 +1,583 @@
+/*\r
+ *  Licensed to the Apache Software Foundation (ASF) under one or more\r
+ *  contributor license agreements.  See the NOTICE file distributed with\r
+ *  this work for additional information regarding copyright ownership.\r
+ *  The ASF licenses this file to You under the Apache License, Version 2.0\r
+ *  (the "License"); you may not use this file except in compliance with\r
+ *  the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ *\r
+ */\r
+\r
+package org.apache.poi.ss.excelant;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.tools.ant.*;\r
+\r
+import java.io.File;\r
+import java.io.PrintStream;\r
+import java.net.URL;\r
+\r
+/**\r
+ * A BuildFileTest is a TestCase which executes targets from an Ant buildfile\r
+ * for testing.\r
+ * <p/>\r
+ * This class provides a number of utility methods for particular build file\r
+ * tests which extend this class.\r
+ *\r
+ * @see <a href="http://svn.apache.org/repos/asf/ant/core/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java">\r
+ *  http://svn.apache.org/repos/asf/ant/core/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java</a>\r
+ */\r
+public abstract class BuildFileTest extends TestCase {\r
+\r
+    protected Project project;\r
+\r
+    private StringBuffer logBuffer;\r
+    private StringBuffer fullLogBuffer;\r
+    private StringBuffer outBuffer;\r
+    private StringBuffer errBuffer;\r
+    private BuildException buildException;\r
+\r
+    /**\r
+     * Default constructor for the BuildFileTest object.\r
+     */\r
+    public BuildFileTest() {\r
+        super();\r
+    }\r
+\r
+    /**\r
+     * Constructor for the BuildFileTest object.\r
+     *\r
+     * @param name string to pass up to TestCase constructor\r
+     */\r
+    public BuildFileTest(String name) {\r
+        super(name);\r
+    }\r
+\r
+    /**\r
+     * Automatically calls the target called "tearDown"\r
+     * from the build file tested if it exits.\r
+     * <p/>\r
+     * This allows to use Ant tasks directly in the build file\r
+     * to clean up after each test. Note that no "setUp" target\r
+     * is automatically called, since it's trivial to have a\r
+     * test target depend on it.\r
+     */\r
+    protected void tearDown() throws Exception {\r
+        if (project == null) {\r
+            /*\r
+             * Maybe the BuildFileTest was subclassed and there is\r
+             * no initialized project. So we could avoid getting a\r
+             * NPE.\r
+             * If there is an initialized project getTargets() does\r
+             * not return null as it is initialized by an empty\r
+             * HashSet.\r
+             */\r
+            return;\r
+        }\r
+        final String tearDown = "tearDown";\r
+        if (project.getTargets().containsKey(tearDown)) {\r
+            project.executeTarget(tearDown);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * run a target, expect for any build exception\r
+     *\r
+     * @param target target to run\r
+     * @param cause  information string to reader of report\r
+     */\r
+    public void expectBuildException(String target, String cause) {\r
+        expectSpecificBuildException(target, cause, null);\r
+    }\r
+\r
+    /**\r
+     * Assert that only the given message has been logged with a\r
+     * priority &lt;= INFO when running the given target.\r
+     */\r
+    public void expectLog(String target, String log) {\r
+        executeTarget(target);\r
+        String realLog = getLog();\r
+        assertEquals(log, realLog);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given substring is in the log messages.\r
+     */\r
+    public void assertLogContaining(String substring) {\r
+        String realLog = getLog();\r
+        assertTrue("expecting log to contain \"" + substring + "\" log was \""\r
+                + realLog + "\"",\r
+                realLog.indexOf(substring) >= 0);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given substring is not in the log messages.\r
+     */\r
+    public void assertLogNotContaining(String substring) {\r
+        String realLog = getLog();\r
+        assertFalse("didn't expect log to contain \"" + substring + "\" log was \""\r
+                + realLog + "\"",\r
+                realLog.indexOf(substring) >= 0);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given substring is in the output messages.\r
+     *\r
+     * @since Ant1.7\r
+     */\r
+    public void assertOutputContaining(String substring) {\r
+        assertOutputContaining(null, substring);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given substring is in the output messages.\r
+     *\r
+     * @param message Print this message if the test fails. Defaults to\r
+     *                a meaningful text if <tt>null</tt> is passed.\r
+     * @since Ant1.7\r
+     */\r
+    public void assertOutputContaining(String message, String substring) {\r
+        String realOutput = getOutput();\r
+        String realMessage = (message != null)\r
+                ? message\r
+                : "expecting output to contain \"" + substring + "\" output was \"" + realOutput + "\"";\r
+        assertTrue(realMessage, realOutput.indexOf(substring) >= 0);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given substring is not in the output messages.\r
+     *\r
+     * @param message Print this message if the test fails. Defaults to\r
+     *                a meaningful text if <tt>null</tt> is passed.\r
+     * @since Ant1.7\r
+     */\r
+    public void assertOutputNotContaining(String message, String substring) {\r
+        String realOutput = getOutput();\r
+        String realMessage = (message != null)\r
+                ? message\r
+                : "expecting output to not contain \"" + substring + "\" output was \"" + realOutput + "\"";\r
+        assertFalse(realMessage, realOutput.indexOf(substring) >= 0);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given message has been logged with a priority &lt;= INFO when running the\r
+     * given target.\r
+     */\r
+    public void expectLogContaining(String target, String log) {\r
+        executeTarget(target);\r
+        assertLogContaining(log);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given message has not been logged with a\r
+     * priority &lt;= INFO when running the given target.\r
+     */\r
+    public void expectLogNotContaining(String target, String log) {\r
+        executeTarget(target);\r
+        assertLogNotContaining(log);\r
+    }\r
+\r
+    /**\r
+     * Gets the log the BuildFileTest object.\r
+     * Only valid if configureProject() has been called.\r
+     *\r
+     * @return The log value\r
+     * @pre logBuffer!=null\r
+     */\r
+    public String getLog() {\r
+        return logBuffer.toString();\r
+    }\r
+\r
+    /**\r
+     * Assert that the given message has been logged with a priority\r
+     * &gt;= VERBOSE when running the given target.\r
+     */\r
+    public void expectDebuglog(String target, String log) {\r
+        executeTarget(target);\r
+        String realLog = getFullLog();\r
+        assertEquals(log, realLog);\r
+    }\r
+\r
+    /**\r
+     * Assert that the given substring is in the log messages.\r
+     */\r
+    public void assertDebuglogContaining(String substring) {\r
+        String realLog = getFullLog();\r
+        assertTrue("expecting debug log to contain \"" + substring\r
+                + "\" log was \""\r
+                + realLog + "\"",\r
+                realLog.indexOf(substring) >= 0);\r
+    }\r
+\r
+    /**\r
+     * Gets the log the BuildFileTest object.\r
+     * <p/>\r
+     * Only valid if configureProject() has been called.\r
+     *\r
+     * @return The log value\r
+     * @pre fullLogBuffer!=null\r
+     */\r
+    public String getFullLog() {\r
+        return fullLogBuffer.toString();\r
+    }\r
+\r
+    /**\r
+     * execute the target, verify output matches expectations\r
+     *\r
+     * @param target target to execute\r
+     * @param output output to look for\r
+     */\r
+    public void expectOutput(String target, String output) {\r
+        executeTarget(target);\r
+        String realOutput = getOutput();\r
+        assertEquals(output, realOutput.trim());\r
+    }\r
+\r
+    /**\r
+     * Executes the target, verify output matches expectations\r
+     * and that we got the named error at the end\r
+     *\r
+     * @param target target to execute\r
+     * @param output output to look for\r
+     * @param error  Description of Parameter\r
+     */\r
+    public void expectOutputAndError(String target, String output, String error) {\r
+        executeTarget(target);\r
+        String realOutput = getOutput();\r
+        assertEquals(output, realOutput);\r
+        String realError = getError();\r
+        assertEquals(error, realError);\r
+    }\r
+\r
+    public String getOutput() {\r
+        return cleanBuffer(outBuffer);\r
+    }\r
+\r
+    public String getError() {\r
+        return cleanBuffer(errBuffer);\r
+    }\r
+\r
+    public BuildException getBuildException() {\r
+        return buildException;\r
+    }\r
+\r
+    private String cleanBuffer(StringBuffer buffer) {\r
+        StringBuffer cleanedBuffer = new StringBuffer();\r
+        for (int i = 0; i < buffer.length(); i++) {\r
+            char ch = buffer.charAt(i);\r
+            if (ch != '\r') {\r
+                cleanedBuffer.append(ch);\r
+            }\r
+        }\r
+        return cleanedBuffer.toString();\r
+    }\r
+\r
+    /**\r
+     * Sets up to run the named project\r
+     *\r
+     * @param filename name of project file to run\r
+     */\r
+    public void configureProject(String filename) throws BuildException {\r
+        configureProject(filename, Project.MSG_DEBUG);\r
+    }\r
+\r
+    /**\r
+     * Sets up to run the named project\r
+     *\r
+     * @param filename name of project file to run\r
+     */\r
+    public void configureProject(String filename, int logLevel)\r
+            throws BuildException {\r
+        logBuffer = new StringBuffer();\r
+        fullLogBuffer = new StringBuffer();\r
+        project = new Project();\r
+        project.init();\r
+        File antFile = new File(System.getProperty("root"), filename);\r
+        project.setUserProperty("ant.file", antFile.getAbsolutePath());\r
+        project.addBuildListener(new AntTestListener(logLevel));\r
+        ProjectHelper.configureProject(project, antFile);\r
+    }\r
+\r
+    /**\r
+     * Executes a target we have set up\r
+     *\r
+     * @param targetName target to run\r
+     * @pre configureProject has been called\r
+     */\r
+    public void executeTarget(String targetName) {\r
+        PrintStream sysOut = System.out;\r
+        PrintStream sysErr = System.err;\r
+        try {\r
+            sysOut.flush();\r
+            sysErr.flush();\r
+            outBuffer = new StringBuffer();\r
+            PrintStream out = new PrintStream(new AntOutputStream(outBuffer));\r
+            System.setOut(out);\r
+            errBuffer = new StringBuffer();\r
+            PrintStream err = new PrintStream(new AntOutputStream(errBuffer));\r
+            System.setErr(err);\r
+            logBuffer = new StringBuffer();\r
+            fullLogBuffer = new StringBuffer();\r
+            buildException = null;\r
+            project.executeTarget(targetName);\r
+        } finally {\r
+            System.setOut(sysOut);\r
+            System.setErr(sysErr);\r
+        }\r
+\r
+    }\r
+\r
+    /**\r
+     * Get the project which has been configured for a test.\r
+     *\r
+     * @return the Project instance for this test.\r
+     */\r
+    public Project getProject() {\r
+        return project;\r
+    }\r
+\r
+    /**\r
+     * Gets the directory of the project.\r
+     *\r
+     * @return the base dir of the project\r
+     */\r
+    public File getProjectDir() {\r
+        return project.getBaseDir();\r
+    }\r
+\r
+    /**\r
+     * Runs a target, wait for a build exception.\r
+     *\r
+     * @param target target to run\r
+     * @param cause  information string to reader of report\r
+     * @param msg    the message value of the build exception we are waiting\r
+     *               for set to null for any build exception to be valid\r
+     */\r
+    public void expectSpecificBuildException(String target, String cause, String msg) {\r
+        try {\r
+            executeTarget(target);\r
+        } catch (org.apache.tools.ant.BuildException ex) {\r
+            buildException = ex;\r
+            if ((null != msg) && (!ex.getMessage().equals(msg))) {\r
+                fail("Should throw BuildException because '" + cause\r
+                        + "' with message '" + msg\r
+                        + "' (actual message '" + ex.getMessage() + "' instead)");\r
+            }\r
+            return;\r
+        }\r
+        fail("Should throw BuildException because: " + cause);\r
+    }\r
+\r
+    /**\r
+     * run a target, expect an exception string\r
+     * containing the substring we look for (case sensitive match)\r
+     *\r
+     * @param target   target to run\r
+     * @param cause    information string to reader of report\r
+     * @param contains substring of the build exception to look for\r
+     */\r
+    public void expectBuildExceptionContaining(String target, String cause, String contains) {\r
+        try {\r
+            executeTarget(target);\r
+        } catch (org.apache.tools.ant.BuildException ex) {\r
+            buildException = ex;\r
+            if ((null != contains) && (ex.getMessage().indexOf(contains) == -1)) {\r
+                fail("Should throw BuildException because '" + cause + "' with message containing '" + contains + "' (actual message '" + ex.getMessage() + "' instead)");\r
+            }\r
+            return;\r
+        }\r
+        fail("Should throw BuildException because: " + cause);\r
+    }\r
+\r
+    /**\r
+     * call a target, verify property is as expected\r
+     *\r
+     * @param target   build file target\r
+     * @param property property name\r
+     * @param value    expected value\r
+     */\r
+    public void expectPropertySet(String target, String property, String value) {\r
+        executeTarget(target);\r
+        assertPropertyEquals(property, value);\r
+    }\r
+\r
+    /**\r
+     * assert that a property equals a value; comparison is case sensitive.\r
+     *\r
+     * @param property property name\r
+     * @param value    expected value\r
+     */\r
+    public void assertPropertyEquals(String property, String value) {\r
+        String result = project.getProperty(property);\r
+        assertEquals("property " + property, value, result);\r
+    }\r
+\r
+    /**\r
+     * assert that a property equals "true".\r
+     *\r
+     * @param property property name\r
+     */\r
+    public void assertPropertySet(String property) {\r
+        assertPropertyEquals(property, "true");\r
+    }\r
+\r
+    /**\r
+     * assert that a property is null.\r
+     *\r
+     * @param property property name\r
+     */\r
+    public void assertPropertyUnset(String property) {\r
+        String result = project.getProperty(property);\r
+        if (result != null) {\r
+            fail("Expected property " + property\r
+                    + " to be unset, but it is set to the value: " + result);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * call a target, verify named property is "true".\r
+     *\r
+     * @param target   build file target\r
+     * @param property property name\r
+     */\r
+    public void expectPropertySet(String target, String property) {\r
+        expectPropertySet(target, property, "true");\r
+    }\r
+\r
+    /**\r
+     * Call a target, verify property is null.\r
+     *\r
+     * @param target   build file target\r
+     * @param property property name\r
+     */\r
+    public void expectPropertyUnset(String target, String property) {\r
+        expectPropertySet(target, property, null);\r
+    }\r
+\r
+    /**\r
+     * Retrieve a resource from the caller classloader to avoid\r
+     * assuming a vm working directory. The resource path must be\r
+     * relative to the package name or absolute from the root path.\r
+     *\r
+     * @param resource the resource to retrieve its url.\r
+     * @throws junit.framework.AssertionFailedError\r
+     *          if the resource is not found.\r
+     */\r
+    public URL getResource(String resource) {\r
+        URL url = getClass().getResource(resource);\r
+        assertNotNull("Could not find resource :" + resource, url);\r
+        return url;\r
+    }\r
+\r
+    /**\r
+     * an output stream which saves stuff to our buffer.\r
+     */\r
+    protected static class AntOutputStream extends java.io.OutputStream {\r
+        private StringBuffer buffer;\r
+\r
+        public AntOutputStream(StringBuffer buffer) {\r
+            this.buffer = buffer;\r
+        }\r
+\r
+        public void write(int b) {\r
+            buffer.append((char) b);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Our own personal build listener.\r
+     */\r
+    private class AntTestListener implements BuildListener {\r
+        private int logLevel;\r
+\r
+        /**\r
+         * Constructs a test listener which will ignore log events\r
+         * above the given level.\r
+         */\r
+        public AntTestListener(int logLevel) {\r
+            this.logLevel = logLevel;\r
+        }\r
+\r
+        /**\r
+         * Fired before any targets are started.\r
+         */\r
+        public void buildStarted(BuildEvent event) {\r
+        }\r
+\r
+        /**\r
+         * Fired after the last target has finished. This event\r
+         * will still be thrown if an error occurred during the build.\r
+         *\r
+         * @see BuildEvent#getException()\r
+         */\r
+        public void buildFinished(BuildEvent event) {\r
+        }\r
+\r
+        /**\r
+         * Fired when a target is started.\r
+         *\r
+         * @see BuildEvent#getTarget()\r
+         */\r
+        public void targetStarted(BuildEvent event) {\r
+            //System.out.println("targetStarted " + event.getTarget().getName());\r
+        }\r
+\r
+        /**\r
+         * Fired when a target has finished. This event will\r
+         * still be thrown if an error occurred during the build.\r
+         *\r
+         * @see BuildEvent#getException()\r
+         */\r
+        public void targetFinished(BuildEvent event) {\r
+            //System.out.println("targetFinished " + event.getTarget().getName());\r
+        }\r
+\r
+        /**\r
+         * Fired when a task is started.\r
+         *\r
+         * @see BuildEvent#getTask()\r
+         */\r
+        public void taskStarted(BuildEvent event) {\r
+            //System.out.println("taskStarted " + event.getTask().getTaskName());\r
+        }\r
+\r
+        /**\r
+         * Fired when a task has finished. This event will still\r
+         * be throw if an error occurred during the build.\r
+         *\r
+         * @see BuildEvent#getException()\r
+         */\r
+        public void taskFinished(BuildEvent event) {\r
+            //System.out.println("taskFinished " + event.getTask().getTaskName());\r
+        }\r
+\r
+        /**\r
+         * Fired whenever a message is logged.\r
+         *\r
+         * @see BuildEvent#getMessage()\r
+         * @see BuildEvent#getPriority()\r
+         */\r
+        public void messageLogged(BuildEvent event) {\r
+            if (event.getPriority() > logLevel) {\r
+                // ignore event\r
+                return;\r
+            }\r
+\r
+            if (event.getPriority() == Project.MSG_INFO ||\r
+                    event.getPriority() == Project.MSG_WARN ||\r
+                    event.getPriority() == Project.MSG_ERR) {\r
+                logBuffer.append(event.getMessage());\r
+            }\r
+            fullLogBuffer.append(event.getMessage());\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/TestBuildFile.java b/src/excelant/testcases/org/apache/poi/ss/excelant/TestBuildFile.java
new file mode 100644 (file)
index 0000000..4d8f0d5
--- /dev/null
@@ -0,0 +1,74 @@
+/*\r
+ *  Licensed to the Apache Software Foundation (ASF) under one or more\r
+ *  contributor license agreements.  See the NOTICE file distributed with\r
+ *  this work for additional information regarding copyright ownership.\r
+ *  The ASF licenses this file to You under the Apache License, Version 2.0\r
+ *  (the "License"); you may not use this file except in compliance with\r
+ *  the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ *\r
+ */\r
+package org.apache.poi.ss.excelant;\r
+\r
+/**\r
+ *  JUnit test for the ExcelAnt tasks.\r
+ *  Leverages Ant's test framework.\r
+ *\r
+ * @see <a href="http://svn.apache.org/repos/asf/ant/core/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java">\r
+ *  http://svn.apache.org/repos/asf/ant/core/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java</a>\r
+ */\r
+public class TestBuildFile extends BuildFileTest {\r
+\r
+    public void setUp() {\r
+        configureProject("src/excelant/testcases/org/apache/poi/ss/excelant/tests.xml");\r
+    }\r
+\r
+    public void testMissingFilename() {\r
+        expectSpecificBuildException("test-nofile", "required argument not specified",\r
+                "fileName attribute must be set!");\r
+     }\r
+\r
+    public void testFileNotFound() {\r
+        expectSpecificBuildException("test-filenotfound", "required argument not specified",\r
+                "Cannot load file invalid.xls. Make sure the path and file permissions are correct.");\r
+     }\r
+\r
+    public void testEvaluate() {\r
+        executeTarget("test-evaluate");\r
+        assertLogContaining("Using input file: test-data/spreadsheet/excelant.xls");\r
+        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.");\r
+    }\r
+\r
+    public void testPrecision() {\r
+        executeTarget("test-precision");\r
+\r
+        assertLogContaining("Using input file: test-data/spreadsheet/excelant.xls");\r
+        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.  " +\r
+                "It evaluated to 2285.5761494145563 when the value of 2285.576149 with precision of 1.0E-4");\r
+        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.  " +\r
+                "It evaluated to 2285.5761494145563 when the value of 2285.576149 with precision of 1.0E-5");\r
+        assertLogContaining("Failed to evaluate cell 'MortgageCalculator'!$B$4.  " +\r
+                "It evaluated to 2285.5761494145563 when the value of 2285.576149 with precision of 1.0E-10 was expected.");\r
+        assertLogContaining("2/3 tests passed");\r
+    }\r
+\r
+    public void testPassOnError() {\r
+        executeTarget("test-passonerror");\r
+    }\r
+\r
+    public void testFailOnError() {\r
+        expectBuildException("test-failonerror", "fail on error");\r
+    }\r
+\r
+    public void testUdf() {\r
+        executeTarget("test-udf");\r
+        assertLogContaining("1/1 tests passed");\r
+    }\r
+}\r
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntPrecision.java b/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntPrecision.java
new file mode 100755 (executable)
index 0000000..0c6f9cb
--- /dev/null
@@ -0,0 +1,48 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import junit.framework.TestCase;
+
+public class TestExcelAntPrecision extends TestCase {
+       
+       private ExcelAntPrecision fixture ;
+
+    @Override
+       public void setUp() {
+               fixture = new ExcelAntPrecision() ;
+       }
+       
+    @Override
+       public void tearDown() {
+               fixture = null ;
+       }
+       
+       public void testVerifyPrecision() {
+               
+               double value = 1.0E-1 ;
+               
+               fixture.setValue( value ) ;
+               
+               double result = fixture.getValue() ;
+               
+               assertTrue( result > 0 ) ;
+               
+               assertEquals( value, result, 0.0 ) ;
+       }
+
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntSet.java b/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntSet.java
new file mode 100755 (executable)
index 0000000..cfba01b
--- /dev/null
@@ -0,0 +1,64 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtilFactory;
+
+public class TestExcelAntSet extends TestCase {
+
+       
+       // This is abstract in nature, so we'll use a 
+       // concrete instance to test the set methods.
+       private ExcelAntSet fixture ;
+       
+       private final String mortgageCalculatorFileName =
+        "test-data/spreadsheet/mortgage-calculation.xls" ;
+
+
+    @Override
+       public void setUp() {
+               fixture = new ExcelAntSetDoubleCell() ;
+       }
+       
+    @Override
+       public void tearDown() {
+               fixture = null ;
+       }
+       
+       public void testSetter() {
+               String cell = "simpleCellRef!$F$1" ;
+               
+               fixture.setCell( cell ) ;
+               
+               String cellStr = fixture.getCell() ;
+               
+               assertNotNull( cellStr ) ;
+               assertEquals( cell, cellStr ) ;
+       }
+       
+       public void testSetWorkbookUtil() {
+               ExcelAntWorkbookUtil util = ExcelAntWorkbookUtilFactory.getInstance(
+                                                                mortgageCalculatorFileName ) ;
+               
+               assertNotNull( util ) ;
+               
+               fixture.setWorkbookUtil( util ) ;
+       }
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntSetDoubleCell.java b/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntSetDoubleCell.java
new file mode 100755 (executable)
index 0000000..1b9e527
--- /dev/null
@@ -0,0 +1,66 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtil;
+import org.apache.poi.ss.excelant.util.ExcelAntWorkbookUtilFactory;
+
+public class TestExcelAntSetDoubleCell extends TestCase {
+       
+       private ExcelAntSetDoubleCell fixture ;
+       
+       private final String mortgageCalculatorFileName =
+        "test-data/spreadsheet/mortgage-calculation.xls" ;
+       
+       private ExcelAntWorkbookUtil util ;
+
+    @Override
+       public void setUp() {
+               fixture = new ExcelAntSetDoubleCell() ;
+               util = ExcelAntWorkbookUtilFactory.getInstance(
+                                                                 mortgageCalculatorFileName ) ;
+               fixture.setWorkbookUtil( util ) ;
+       }
+       
+    @Override
+       public void tearDown() {
+               fixture = null ;
+       }
+       
+       public void testSetDouble() {
+               String cellId = "'Sheet3'!$A$1" ;
+               double testValue = 1.1 ;
+               
+               fixture.setCell( cellId ) ;
+               fixture.setValue( testValue ) ;
+               
+               double value = fixture.getCellValue() ;
+               
+               assertTrue( value > 0 ) ;
+               assertEquals( testValue, value, 0.0 ) ;
+               
+               fixture.execute() ;
+               
+               double setValue = util.getCellAsDouble( cellId ) ;
+               
+               assertEquals( setValue, testValue, 0.0 ) ;
+       }
+       
+
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtilTestHelper.java b/src/excelant/testcases/org/apache/poi/ss/excelant/util/ExcelAntWorkbookUtilTestHelper.java
new file mode 100755 (executable)
index 0000000..cf7538c
--- /dev/null
@@ -0,0 +1,55 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant.util;
+
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * A helper class to allow testing of protected methods and constructors.
+ * 
+ * @author jsvede
+ *
+ */
+public class ExcelAntWorkbookUtilTestHelper extends ExcelAntWorkbookUtil {
+
+       public ExcelAntWorkbookUtilTestHelper(String fName) {
+               super(fName);
+               // TODO Auto-generated constructor stub
+       }
+
+       public ExcelAntWorkbookUtilTestHelper(Workbook wb) {
+               super(wb);
+               // TODO Auto-generated constructor stub
+       }
+
+       @Override
+       public UDFFinder getFunctions() {
+               // TODO Auto-generated method stub
+               return super.getFunctions();
+       }
+
+       @Override
+       public FormulaEvaluator getEvaluator(String excelFileName) {
+               // TODO Auto-generated method stub
+               return super.getEvaluator(excelFileName);
+       }
+
+       
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntEvaluationResult.java b/src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntEvaluationResult.java
new file mode 100755 (executable)
index 0000000..833dea6
--- /dev/null
@@ -0,0 +1,67 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant.util;
+
+import junit.framework.TestCase;
+
+public class TestExcelAntEvaluationResult extends TestCase {
+       
+       private ExcelAntEvaluationResult fixture ;
+       
+       private boolean completedWithError = false ;
+    private boolean passed = false ;
+    private double retValue  = 1.1 ; 
+    private String errMessage = "error message" ;  
+    private double delta = 2.2 ; 
+    private String cellId = "testCell!$F$1" ;
+    
+       public void setUp() {
+               fixture = new ExcelAntEvaluationResult( completedWithError,
+                                                               passed, 
+                                                               retValue,
+                                                               errMessage, 
+                                                               delta,
+                                                               cellId ) ;
+       }
+       
+       public void tearDown() {
+               fixture = null ;
+       }
+       
+       public void testCompletedWithErrorMessage() {
+               String errMsg = fixture.getErrorMessage() ;
+               assertNotNull( errMsg ) ;
+               assertEquals( errMsg, errMessage ) ;
+       }
+       
+       public void testPassed() {
+               boolean passedValue = fixture.didTestPass() ;
+               assertEquals( passedValue, passed ) ;
+       }
+       
+       public void testDelta() {
+               double deltaValue = fixture.getDelta() ;
+               assertEquals(deltaValue, delta, 0.0 ) ;
+       }
+       
+       public void testCellId() {
+               String cellIdValue = fixture.getCellName() ;
+               assertNotNull( cellIdValue ) ;
+               assertEquals( cellIdValue, cellId ) ;
+       }
+
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtil.java b/src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtil.java
new file mode 100755 (executable)
index 0000000..5b0d3e8
--- /dev/null
@@ -0,0 +1,140 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant.util;
+
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.ss.examples.formula.CalculateMortgage;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Workbook;
+
+public class TestExcelAntWorkbookUtil extends TestCase {
+       
+       private final String mortgageCalculatorFileName =
+                                                 "test-data/spreadsheet/excelant.xls" ;
+       private ExcelAntWorkbookUtilTestHelper fixture ;
+               
+       
+       public void tearDown() {
+               fixture = null ;
+       }
+
+       public void testStringConstructor() {
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                                                                 mortgageCalculatorFileName ) ;
+               
+               assertNotNull( fixture ) ;
+               
+       }
+       
+       public void testAddFunction() {
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+
+               assertNotNull( fixture ) ;
+               
+               fixture.addFunction("h2_ZFactor", new CalculateMortgage() ) ;
+               
+               UDFFinder functions = fixture.getFunctions() ;
+               
+               assertNotNull( functions ) ;
+       }
+
+       public void testGetWorkbook() {
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+               
+               assertNotNull( fixture ) ;
+               
+               Workbook workbook = fixture.getWorkbook() ;
+               
+               assertNotNull( workbook ) ;
+       }
+       
+       public void testFileName() {
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+               
+               assertNotNull( fixture ) ;
+
+               String fileName = fixture.getFileName() ;
+               
+               assertNotNull( fileName ) ;
+               
+               assertEquals( mortgageCalculatorFileName, fileName ) ;
+               
+       }
+       
+       public void testGetEvaluator() {
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+               
+               FormulaEvaluator evaluator = fixture.getEvaluator( 
+                                                                 mortgageCalculatorFileName ) ;
+               
+               assertNotNull( evaluator ) ;
+               
+               
+       }
+
+       public void testEvaluateCell() {
+               String cell = "'MortgageCalculator'!B4" ;
+               double expectedValue = 790.79 ;
+               double precision = 0.1 ;
+
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+
+               ExcelAntEvaluationResult result = fixture.evaluateCell( cell, 
+                                                                               expectedValue, 
+                                                                               precision ) ;
+               
+               System.out.println(  result ) ;
+               
+               assertTrue( result.didTestPass() ) ;
+       }
+       
+       public void testGetSheets() {
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+               
+               ArrayList<String> sheets = fixture.getSheets() ;
+               
+               assertNotNull( sheets ) ;
+               assertEquals( sheets.size(), 3 ) ; 
+       }
+       
+       public void testSetString() {
+               String cell = "'MortgageCalculator'!C14" ;
+               String cellValue = "testString" ;
+               
+               fixture = new ExcelAntWorkbookUtilTestHelper( 
+                mortgageCalculatorFileName ) ;
+               
+               fixture.setStringValue( cell, cellValue ) ;
+               
+               String value = fixture.getCellAsString( cell ) ;
+               
+               assertNotNull( value ) ;
+               
+               assertEquals( cellValue, value ) ;
+               
+       }
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtilFactory.java b/src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtilFactory.java
new file mode 100755 (executable)
index 0000000..79c898a
--- /dev/null
@@ -0,0 +1,69 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.poi.ss.excelant.util;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for the ExcelAntWorbookUtilFactory.
+ * 
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class TestExcelAntWorkbookUtilFactory extends TestCase{
+
+       private final String mortgageCalculatorWorkbookFile = 
+                                                "test-data/spreadsheet/mortgage-calculation.xls" ;
+       
+       
+       /**
+        * Simple test to determine if the factory properly returns an non-null
+        * instance of the ExcelAntWorkbookUtil class.
+        */
+       public void testGetNewWorkbookUtilInstance() {
+               
+               ExcelAntWorkbookUtil util = ExcelAntWorkbookUtilFactory.getInstance(
+                                                             mortgageCalculatorWorkbookFile ) ;
+               
+               assertNotNull( util ) ;
+               
+       }
+       
+       
+       /**
+        * Test whether or not the factory will properly return the same reference
+        * to an ExcelAnt WorkbookUtil when two different Strings, that point to
+        * the same resource, are passed in. 
+        */
+       public void testVerifyEquivalence() {
+               String sameFileName = "test-data/spreadsheet/mortgage-calculation.xls" ;
+               
+               ExcelAntWorkbookUtil util = ExcelAntWorkbookUtilFactory.getInstance(
+                mortgageCalculatorWorkbookFile ) ;
+
+               ExcelAntWorkbookUtil util2 = ExcelAntWorkbookUtilFactory.getInstance(
+                                                      sameFileName ) ;
+               
+               assertNotNull( util ) ;
+               assertNotNull( util2 ) ;
+               
+               assertEquals( util, util2 ) ;
+       }
+       
+}
diff --git a/test-data/spreadsheet/excelant.xls b/test-data/spreadsheet/excelant.xls
new file mode 100644 (file)
index 0000000..e41edfb
Binary files /dev/null and b/test-data/spreadsheet/excelant.xls differ
diff --git a/test-data/spreadsheet/mortgage-calculation.xls b/test-data/spreadsheet/mortgage-calculation.xls
new file mode 100644 (file)
index 0000000..92e5779
Binary files /dev/null and b/test-data/spreadsheet/mortgage-calculation.xls differ