Index: trunk/psModules/test/objects/tap_pmTrend2D.c
===================================================================
--- trunk/psModules/test/objects/tap_pmTrend2D.c	(revision 15726)
+++ trunk/psModules/test/objects/tap_pmTrend2D.c	(revision 15985)
@@ -5,8 +5,13 @@
 #include "tap.h"
 #include "pstap.h"
+/* STATUS:
+    All functions are tested.
+        pmTrend2DFit(): Must test the PM_TREND_MAP case.
+*/
 
 #define NUM_ROWS 8
 #define NUM_COLS 16
 #define ERR_TRACE_LEVEL 0
+#define TEST_FLOATS_EQUAL(X, Y) (abs(X - Y) < 0.01)
 
 int main(int argc, char* argv[])
@@ -15,10 +20,8 @@
     psLogSetLevel(PS_LOG_INFO);
     psTraceSetLevel("err", ERR_TRACE_LEVEL);
-    plan_tests(35);
+    plan_tests(91);
 
     // ------------------------------------------------------------------------
     // Test pmTrend2DAlloc()
-    // pmTrend2D *pmTrend2DAlloc(pmTrend2DMode mode, psImage *image,
-    //                           int nXtrend, int nYtrend, psStats *stats)
     // Call pmTrend2DAlloc() with NULL psImage input parameter (PM_TREND_MAP)
     {
@@ -121,6 +124,4 @@
     // ------------------------------------------------------------------------
     // Test pmTrend2DNoImageAlloc()
-    // pmTrend2D *pmTrend2DNoImageAlloc (pmTrend2DMode mode,
-    //          psImageBinning *binning, psStats *stats)
     // Call pmTrend2DNoImageAlloc() with NULL psImageBinning input parameter
     {
@@ -132,4 +133,5 @@
         psFree(stats);
         psFree(binning);
+        psFree(trend);
         ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
     }
@@ -192,9 +194,7 @@
     }
 
+
     // ------------------------------------------------------------------------
     // Test pmTrend2DFieldAlloc()
-    // pmTrend2D *pmTrend2DFieldAlloc (pmTrend2DMode mode, int nXfield,
-    //           int nYfield, int nXtrend, int nYtrend, psStats *stats)
-    // 
     // Call pmTrend2DFieldAlloc() with NULL psStats input parameter
     {
@@ -221,9 +221,9 @@
         ok(trend->poly->nY == 4, "pmTrend2DFieldAlloc() set trend->poly->nY correctly");
         psFree(trend);
+        trend = NULL;
 
         // Create a new pmTrend with PM_TREND_MAP
         // XXX: This currently fails due to a big in pmTrend2DFieldAlloc():
-        // psImageMapAlloc() is called with a NULL field input parameter.
-        {
+        if (0) {
             trend = pmTrend2DFieldAlloc(PM_TREND_MAP, 1, 2, 3, 4, stats);
             ok(trend->map != NULL && psMemCheckImageMap(trend->map), 
@@ -241,5 +241,5 @@
     // psString pmTrend2DModeToString (pmTrend2DMode mode)
     // Call pmTrend2DModeToString() with unallowed pmTrend2DMode.
-    // XXX: We comment this out because pmTrend2DModeToString() aborts.
+    // XX: We comment this out because pmTrend2DModeToString() aborts.
     if (0) {
         psMemId id = psMemGetId();
@@ -251,5 +251,4 @@
 
     // Call pmTrend2DModeToString() with unallowed pmTrend2DMode.
-    // XXX: We comment this out because pmTrend2DModeToString() aborts.
     {
         psMemId id = psMemGetId();
@@ -276,5 +275,4 @@
     // ------------------------------------------------------------------------
     // Test pmTrend2DModeFromString()
-    // pmTrend2DMode pmTrend2DModeFromString (psString name) {
     // Call pmTrend2DModeFromString() with NULL input parameter
     {
@@ -295,5 +293,5 @@
 
 
-    // Call pmTrend2DModeFromString() with unallowed input string
+    // Call pmTrend2DModeFromString() with acceptable input string
     {
         psMemId id = psMemGetId();
@@ -304,5 +302,5 @@
 
 
-    // Call pmTrend2DModeFromString() with unallowed input string
+    // Call pmTrend2DModeFromString() with acceptable input string
     {
         psMemId id = psMemGetId();
@@ -313,5 +311,5 @@
 
 
-    // Call pmTrend2DModeFromString() with unallowed input string
+    // Call pmTrend2DModeFromString() with acceptable input string
     {
         psMemId id = psMemGetId();
@@ -322,5 +320,5 @@
 
 
-    // Call pmTrend2DModeFromString() with unallowed input string
+    // Call pmTrend2DModeFromString() with acceptable input string
     {
         psMemId id = psMemGetId();
@@ -331,3 +329,176 @@
 
 
+    // ------------------------------------------------------------------------
+    // Test pmTrend2DFit()
+    // Call pmTrend2DFit() with bad input parameters
+    {
+        #define VEC_SIZE 9
+        psMemId id = psMemGetId();
+        psImage *img = psImageAlloc(NUM_COLS, NUM_ROWS, PS_TYPE_F32);
+        psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
+        pmTrend2D *trend = pmTrend2DAlloc(PM_TREND_POLY_ORD, img, 4, 4, stats);
+        ok(trend != NULL && psMemCheckTrend2D(trend), 
+          "pmTrend2DAlloc() returned non-NULL with acceptable input parameters");
+        psVector *x = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *y = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *f = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *mask = psVectorAlloc(VEC_SIZE, PS_TYPE_U8);
+        psVector *df = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        for (int i = 0 ; i < VEC_SIZE ; i++) {
+            x->data.F32[i] = (float) (i);
+            y->data.F32[i] = (float) (2 * i);
+            f->data.F32[i] = x->data.F32[i] * y->data.F32[i];
+            mask->data.U8[i] = 0;
+            df->data.F32[i] = 0.0;
+        }
+
+        // NULL pmTrend2D input parameter
+        bool rc = pmTrend2DFit(NULL, mask, 0, x, y, f, df);
+        ok(rc == false, "pmTrend2DFit() returned FALSE with NULL pmTrend2D input parameter");
+
+        // NULL mask input parameter
+        rc = pmTrend2DFit(trend, NULL, 0, x, y, f, df);
+        ok(rc == false, "pmTrend2DFit() returned FALSE with NULL mask input parameter");
+
+        // NULL x psVector input parameter
+        rc = pmTrend2DFit(trend, mask, 0, NULL, y, f, df);
+        ok(rc == false, "pmTrend2DFit() returned FALSE with NULL x psVector input parameter");
+
+        // NULL y psVector input parameter
+        rc = pmTrend2DFit(trend, mask, 0, x, NULL, f, df);
+        ok(rc == false, "pmTrend2DFit() returned FALSE with NULL y psVector input parameter");
+
+        // NULL f psVector input parameter
+        rc = pmTrend2DFit(trend, mask, 0, x, y, NULL, df);
+        ok(rc == false, "pmTrend2DFit() returned FALSE with NULL f psVector input parameter");
+
+        // NULL df psVector input parameter
+        rc = pmTrend2DFit(trend, mask, 0, x, y, f, NULL);
+        ok(rc == true, "pmTrend2DFit() returned TRUE with NULL df psVector input parameter");
+
+        psFree(img);
+        psFree(stats);
+        psFree(trend);
+        psFree(x);
+        psFree(y);
+        psFree(f);
+        psFree(mask);
+        psFree(df);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Test pmTrend2DEval()
+    // Call pmTrend2DEval() with bad input parameters
+    {
+        psMemId id = psMemGetId();
+        psF64 tmpD = pmTrend2DEval(NULL, 0.0, 0.0);
+        ok(TEST_FLOATS_EQUAL(tmpD, 0.0), "pmTrend2DEval() returned 0.0 with NULL pmTrend2D input parameter");
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Test pmTrend2DEvalVector()
+    // psVector *pmTrend2DEvalVector (pmTrend2D *trend, psVector *x, psVector *y)
+    // Call pmTrend2DEvalVector() with bad input parameters
+    {
+        psMemId id = psMemGetId();
+        psImage *img = psImageAlloc(NUM_COLS, NUM_ROWS, PS_TYPE_F32);
+        psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
+        pmTrend2D *trend = pmTrend2DAlloc(PM_TREND_POLY_ORD, img, 4, 4, stats);
+        psVector *x = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *y = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+
+        // NULL pmTrend2D input parameter
+        psVector *f = pmTrend2DEvalVector(NULL, x, y);
+        ok(f == NULL, "pmTrend2DEvalVector() returned NULL with NULL pmTrend2D input parameter");
+
+        // NULL x psVector input parameter
+        f = pmTrend2DEvalVector(trend, NULL, y);
+        ok(f == NULL, "pmTrend2DEvalVector() returned NULL with NULL x psVector input parameter");
+
+        // NULL y psVector input parameter
+        f = pmTrend2DEvalVector(trend, x, NULL);
+        ok(f == NULL, "pmTrend2DEvalVector() returned NULL with NULL y psVector input parameter");
+
+        psFree(img);
+        psFree(stats);
+        psFree(trend);
+        psFree(x);
+        psFree(y);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmTrend2DFit(), pmTrend2DEval(), pmTrend2DEvalVector() with acceptable input parameters
+    // NOTE: We only test with a very simple 2D polynomial fit.  This is appropriate since the
+    // polynomial testing routines are tested extensively elsewhere.
+    // XXX: Must test the PM_TREND_MAP case.
+    {
+        #define VEC_SIZE 9
+        psMemId id = psMemGetId();
+        psImage *img = psImageAlloc(NUM_COLS, NUM_ROWS, PS_TYPE_F32);
+        psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
+        pmTrend2D *trend = pmTrend2DAlloc(PM_TREND_POLY_ORD, img, 4, 4, stats);
+        ok(trend != NULL && psMemCheckTrend2D(trend), 
+          "pmTrend2DAlloc() returned non-NULL with acceptable input parameters");
+        psVector *x = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *y = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *f = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+        psVector *mask = psVectorAlloc(VEC_SIZE, PS_TYPE_U8);
+        psVector *df = psVectorAlloc(VEC_SIZE, PS_TYPE_F32);
+
+        int cnt = 0;
+        for (int i = 0 ; i < 3 ; i++) {
+            for (int j = 0 ; j < 3 ; j++) {
+                x->data.F32[cnt] = (float) i;
+                y->data.F32[cnt] = (float) j;
+                f->data.F32[cnt] = x->data.F32[cnt] * y->data.F32[cnt];
+                mask->data.U8[cnt] = 0;
+                df->data.F32[cnt] = 0.0;
+                cnt++;
+            }
+        }
+
+        bool rc = pmTrend2DFit(trend, mask, 0, x, y, f, NULL);
+        ok(rc == true, "pmTrend2DFit() returned TRUE with acceptable input parameters");
+
+        // Test pmTrend2DFit, pmTrend2DEval()
+        bool errorFlag = false;
+        for (int i = 0 ; i < VEC_SIZE ; i++) {
+            if (!TEST_FLOATS_EQUAL(pmTrend2DEval(trend, x->data.F32[i], y->data.F32[i]), f->data.F32[i])) {
+                diag("ERROR: at (%.2f %.2f), eval is %.2f, should be %.2f\n", x->data.F32[i], y->data.F32[i],
+                      pmTrend2DEval(trend, x->data.F32[i], y->data.F32[i]), f->data.F32[i]);
+                errorFlag = true;
+            }
+        }
+        ok(!errorFlag, "pmTrend2DFit() and pmTrend2DEval() set and evaluated the 2DTrend polynomial correctly");
+
+        // Test pmTrend2DEvalVector()
+        psVector *fTest = pmTrend2DEvalVector(trend, x, y);
+        errorFlag = false;
+        for (int i = 0 ; i < VEC_SIZE ; i++) {
+            if (!TEST_FLOATS_EQUAL(fTest->data.F32[i], f->data.F32[i])) {
+                diag("ERROR: at (%.2f %.2f), eval is %.2f, should be %.2f\n", 
+                      x->data.F32[i], y->data.F32[i], fTest->data.F32[i], f->data.F32[i]);
+                errorFlag = true;
+            }
+        }
+        ok(!errorFlag, "pmTrend2DFit() and pmTrend2DEval() set and evaluated the 2DTrend polynomial correctly");
+
+
+        psFree(img);
+        psFree(stats);
+        psFree(trend);
+        psFree(x);
+        psFree(y);
+        psFree(f);
+        psFree(fTest);
+        psFree(mask);
+        psFree(df);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
 }
