Code

SPCurve unit tests
authorjaspervdg <jaspervdg@users.sourceforge.net>
Sat, 2 Aug 2008 14:25:08 +0000 (14:25 +0000)
committerjaspervdg <jaspervdg@users.sourceforge.net>
Sat, 2 Aug 2008 14:25:08 +0000 (14:25 +0000)
build.xml
src/display/Makefile_insert
src/display/bezier-utils-test.h
src/display/curve-test.h [new file with mode: 0644]

index 224892d1ada665ebc6029c40a60b35fc629f15ea..c8a65cab3625a2f1219c56a374e026754187cf41 100644 (file)
--- a/build.xml
+++ b/build.xml
         description="generate test files" >
 
     <!-- Generate CxxTest files -->
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/test-src.cpp">
         <fileset dir="${src}">
             <include name="attributes-test.h"/>
             <include name="verbs-test.h"/>
         </fileset>
     </cxxtestpart>
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/display/test-display.cpp">
         <fileset dir="${src}/display">
             <include name="bezier-utils-test.h"/>
+            <include name="curve-test.h"/>
         </fileset>
     </cxxtestpart>
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/helper/test-helper.cpp">
         <fileset dir="${src}/helper">
             <include name="units-test.h"/>
         </fileset>
     </cxxtestpart>
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/libnr/test-nr.cpp">
         <fileset dir="${src}/libnr">
             <include name="nr-compose-test.h"/>
             <include name="nr-matrix-test.h"/>
         </fileset>
     </cxxtestpart>
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/svg/test-svg.cpp">
         <fileset dir="${src}/svg">
             <include name="css-ostringstream-test.h"/>
             <include name="svg-path-test.h"/>
         </fileset>
     </cxxtestpart>
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/util/test-util.cpp">
         <fileset dir="${src}/util">
             <include name="list-container-test.h"/>
         </fileset>
     </cxxtestpart>
-    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py
+    <cxxtestpart command="python ${cxxtest}/cxxtestgen.py --have-eh"
                  out="${src}/xml/test-xml.cpp">
         <fileset dir="${src}/xml">
             <include name="repr-action-test.h"/>
index bc74c6f227ec4a894d26300c62ddd604c525f076..7db15cf397a3118c9c73ec5e80b6ac0f861b1209 100644 (file)
@@ -139,7 +139,8 @@ display/test-display.cpp: $(display_test_display_includes)
        $(top_srcdir)/cxxtest/cxxtestgen.pl -part -o display/test-display.cpp $(display_test_display_includes)
 
 display_test_display_includes = \
-       $(srcdir)/display/bezier-utils-test.h
+       $(srcdir)/display/bezier-utils-test.h \
+       $(srcdir)/display/curve-test.h
 
 display_libtest_display_a_SOURCES = \
        display/test-display.cpp \
index 4e5788983fe0dd0cb230d3732da37e2e9c78c34c..eb2b13d7b5cf6d7c95208cc2441a4fdcc7139e9f 100644 (file)
@@ -9,8 +9,6 @@
    #define's and `using' directives of the included file. */
 #include "bezier-utils.cpp"
 
-using NR::Point;
-
 /* (Returns false if NaN encountered.) */
 static bool range_approx_equal(double const a[], double const b[], unsigned const len) {
     for (unsigned i = 0; i < len; ++i) {
@@ -37,7 +35,7 @@ static inline double square(double const x) {
     the most important test is that the root-mean-square of errors in the estimation are low rather
     than that the control points found are the same.
 **/
-static void compare_ctlpts(Point const est_b[], Point const exp_est_b[])
+static void compare_ctlpts(NR::Point const est_b[], NR::Point const exp_est_b[])
 {
     unsigned diff_mask = 0;
     for (unsigned i = 0; i < 4; ++i) {
@@ -64,13 +62,13 @@ static void compare_ctlpts(Point const est_b[], Point const exp_est_b[])
     }
 }
 
-static void compare_rms(Point const est_b[], double const t[], Point const d[], unsigned const n,
+static void compare_rms(NR::Point const est_b[], double const t[], NR::Point const d[], unsigned const n,
                         double const exp_rms_error)
 {
     double sum_errsq = 0.0;
     for (unsigned i = 0; i < n; ++i) {
-        Point const fit_pt = bezier_pt(3, est_b, t[i]);
-        Point const diff = fit_pt - d[i];
+        NR::Point const fit_pt = bezier_pt(3, est_b, t[i]);
+        NR::Point const diff = fit_pt - d[i];
         sum_errsq += dot(diff, diff);
     }
     double const rms_error = sqrt( sum_errsq / n );
@@ -86,13 +84,13 @@ static void compare_rms(Point const est_b[], double const t[], Point const d[],
 
 class BezierUtilsTest : public CxxTest::TestSuite {
 public:
-    static Point const c[4];
+    static NR::Point const c[4];
     static double const t[24];
     static unsigned const n;
-    Point d[24];
-    static Point const src_b[4];
-    static Point const tHat1;
-    static Point const tHat2;
+    NR::Point d[24];
+    static NR::Point const src_b[4];
+    static NR::Point const tHat1;
+    static NR::Point const tHat2;
 
     BezierUtilsTest()
     {
@@ -112,22 +110,22 @@ public:
     void testCopyWithoutNansOrAdjacentDuplicates()
     {
         NR::Point const src[] = {
-            Point(2., 3.),
-            Point(2., 3.),
-            Point(0., 0.),
-            Point(2., 3.),
-            Point(2., 3.),
-            Point(1., 9.),
-            Point(1., 9.)
+            NR::Point(2., 3.),
+            NR::Point(2., 3.),
+            NR::Point(0., 0.),
+            NR::Point(2., 3.),
+            NR::Point(2., 3.),
+            NR::Point(1., 9.),
+            NR::Point(1., 9.)
         };
-        Point const exp_dest[] = {
-            Point(2., 3.),
-            Point(0., 0.),
-            Point(2., 3.),
-            Point(1., 9.)
+        NR::Point const exp_dest[] = {
+            NR::Point(2., 3.),
+            NR::Point(0., 0.),
+            NR::Point(2., 3.),
+            NR::Point(1., 9.)
         };
         g_assert( G_N_ELEMENTS(src) == 7 );
-        Point dest[7];
+        NR::Point dest[7];
         struct tst {
             unsigned src_ix0;
             unsigned src_len;
@@ -159,11 +157,11 @@ public:
 
     void testBezierPt1()
     {
-        Point const a[] = {Point(2.0, 4.0),
-                           Point(1.0, 8.0)};
+        NR::Point const a[] = {NR::Point(2.0, 4.0),
+                               NR::Point(1.0, 8.0)};
         TS_ASSERT_EQUALS( bezier_pt(1, a, 0.0) , a[0] );
         TS_ASSERT_EQUALS( bezier_pt(1, a, 1.0) , a[1] );
-        TS_ASSERT_EQUALS( bezier_pt(1, a, 0.5) , Point(1.5, 6.0) );
+        TS_ASSERT_EQUALS( bezier_pt(1, a, 0.5) , NR::Point(1.5, 6.0) );
         double const t[] = {0.5, 0.25, 0.3, 0.6};
         for (unsigned i = 0; i < G_N_ELEMENTS(t); ++i) {
             double const ti = t[i], si = 1.0 - ti;
@@ -173,17 +171,17 @@ public:
 
     void testBezierPt2()
     {
-        Point const b[] = {Point(1.0, 2.0),
-                           Point(8.0, 4.0),
-                           Point(3.0, 1.0)};
+        NR::Point const b[] = {NR::Point(1.0, 2.0),
+                               NR::Point(8.0, 4.0),
+                               NR::Point(3.0, 1.0)};
         TS_ASSERT_EQUALS( bezier_pt(2, b, 0.0) , b[0] );
         TS_ASSERT_EQUALS( bezier_pt(2, b, 1.0) , b[2] );
-        TS_ASSERT_EQUALS( bezier_pt(2, b, 0.5) , Point(5.0, 2.75) );
+        TS_ASSERT_EQUALS( bezier_pt(2, b, 0.5) , NR::Point(5.0, 2.75) );
         double const t[] = {0.5, 0.25, 0.3, 0.6};
         for (unsigned i = 0; i < G_N_ELEMENTS(t); ++i) {
             double const ti = t[i], si = 1.0 - ti;
-            Point const exp_pt( si*si * b[0] + 2*si*ti * b[1] + ti*ti * b[2] );
-            Point const pt(bezier_pt(2, b, ti));
+            NR::Point const exp_pt( si*si * b[0] + 2*si*ti * b[1] + ti*ti * b[2] );
+            NR::Point const pt(bezier_pt(2, b, ti));
             TS_ASSERT(point_approx_equal(pt, exp_pt, 1e-11));
         }
     }
@@ -192,7 +190,7 @@ public:
     {
         TS_ASSERT_EQUALS( bezier_pt(3, c, 0.0) , c[0] );
         TS_ASSERT_EQUALS( bezier_pt(3, c, 1.0) , c[3] );
-        TS_ASSERT_EQUALS( bezier_pt(3, c, 0.5) , Point(4.0, 13.0/8.0) );
+        TS_ASSERT_EQUALS( bezier_pt(3, c, 0.5) , NR::Point(4.0, 13.0/8.0) );
         double const t[] = {0.5, 0.25, 0.3, 0.6};
         for (unsigned i = 0; i < G_N_ELEMENTS(t); ++i) {
             double const ti = t[i], si = 1.0 - ti;
@@ -208,18 +206,18 @@ public:
     void testComputeMaxErrorRatio()
     {
         struct Err_tst {
-            Point pt;
+            NR::Point pt;
             double u;
             double err;
         } const err_tst[] = {
             {c[0], 0.0, 0.0},
-            {Point(4.0, 13.0/8.0), 0.5, 0.0},
-            {Point(4.0, 2.0), 0.5, 9.0/64.0},
-            {Point(3.0, 2.0), 0.5, 1.0 + 9.0/64.0},
-            {Point(6.0, 2.0), 0.5, 4.0 + 9.0/64.0},
+            {NR::Point(4.0, 13.0/8.0), 0.5, 0.0},
+            {NR::Point(4.0, 2.0), 0.5, 9.0/64.0},
+            {NR::Point(3.0, 2.0), 0.5, 1.0 + 9.0/64.0},
+            {NR::Point(6.0, 2.0), 0.5, 4.0 + 9.0/64.0},
             {c[3], 1.0, 0.0},
         };
-        Point d[G_N_ELEMENTS(err_tst)];
+        NR::Point d[G_N_ELEMENTS(err_tst)];
         double u[G_N_ELEMENTS(err_tst)];
         for (unsigned i = 0; i < G_N_ELEMENTS(err_tst); ++i) {
             Err_tst const &t = err_tst[i];
@@ -230,15 +228,15 @@ public:
         unsigned max_ix = ~0u;
         double const err_ratio = compute_max_error_ratio(d, u, G_N_ELEMENTS(d), c, 1.0, &max_ix);
         TS_ASSERT_LESS_THAN( fabs( sqrt(err_tst[4].err) - err_ratio ) , 1e-12 );
-        TS_ASSERT_EQUALS( max_ix , 4 );
+        TS_ASSERT_EQUALS( max_ix , 4u );
     }
 
     void testChordLengthParameterize()
     {
         /* n == 2 */
         {
-            Point const d[] = {Point(2.9415, -5.8149),
-                               Point(23.021, 4.9814)};
+            NR::Point const d[] = {NR::Point(2.9415, -5.8149),
+                                   NR::Point(23.021, 4.9814)};
             double u[G_N_ELEMENTS(d)];
             double const exp_u[] = {0.0, 1.0};
             g_assert( G_N_ELEMENTS(u) == G_N_ELEMENTS(exp_u) );
@@ -250,9 +248,9 @@ public:
         {
             double const exp_u[] = {0.0, 0.1829, 0.2105, 0.2105, 0.619, 0.815, 0.999, 1.0};
             unsigned const n = G_N_ELEMENTS(exp_u);
-            Point d[n];
+            NR::Point d[n];
             double u[n];
-            Point const a(-23.985, 4.915), b(4.9127, 5.203);
+            NR::Point const a(-23.985, 4.915), b(4.9127, 5.203);
             for (unsigned i = 0; i < n; ++i) {
                 double bi = exp_u[i], ai = 1.0 - bi;
                 d[i] = ai * a  +  bi * b;
@@ -264,7 +262,7 @@ public:
 
     void testGenerateBezier()
     {
-        Point est_b[4];
+        NR::Point est_b[4];
         generate_bezier(est_b, d, t, n, tHat1, tHat2, 1.0);
 
         compare_ctlpts(est_b, src_b);
@@ -276,16 +274,16 @@ public:
 
     void testSpBezierFitCubicFull()
     {
-        Point est_b[4];
+        NR::Point est_b[4];
         int splitpoints[2];
         gint const succ = sp_bezier_fit_cubic_full(est_b, splitpoints, d, n, tHat1, tHat2, square(1.2), 1);
         TS_ASSERT_EQUALS( succ , 1 );
 
-        Point const exp_est_b[4] = {
-            Point(5.000000, -3.000000),
-            Point(7.5753, -0.4247),
-            Point(4.77533, 1.22467),
-            Point(3, 3)
+        NR::Point const exp_est_b[4] = {
+            NR::Point(5.000000, -3.000000),
+            NR::Point(7.5753, -0.4247),
+            NR::Point(4.77533, 1.22467),
+            NR::Point(3, 3)
         };
         compare_ctlpts(est_b, exp_est_b);
 
@@ -296,15 +294,15 @@ public:
 
     void testSpBezierFitCubic()
     {
-        Point est_b[4];
+        NR::Point est_b[4];
         gint const succ = sp_bezier_fit_cubic(est_b, d, n, square(1.2));
         TS_ASSERT_EQUALS( succ , 1 );
 
-        Point const exp_est_b[4] = {
-            Point(5.000000, -3.000000),
-            Point(7.57134, -0.423509),
-            Point(4.77929, 1.22426),
-            Point(3, 3)
+        NR::Point const exp_est_b[4] = {
+            NR::Point(5.000000, -3.000000),
+            NR::Point(7.57134, -0.423509),
+            NR::Point(4.77929, 1.22426),
+            NR::Point(3, 3)
         };
         compare_ctlpts(est_b, exp_est_b);
 
@@ -323,22 +321,22 @@ public:
 };
 
 // This is not very neat, but since we know this header is only included by the generated CxxTest file it shouldn't give any problems
-Point const BezierUtilsTest::c[4] = {
-    Point(1.0, 2.0),
-    Point(8.0, 4.0),
-    Point(3.0, 1.0),
-    Point(-2.0, -4.0)};
+NR::Point const BezierUtilsTest::c[4] = {
+    NR::Point(1.0, 2.0),
+    NR::Point(8.0, 4.0),
+    NR::Point(3.0, 1.0),
+    NR::Point(-2.0, -4.0)};
 double const BezierUtilsTest::t[24] = {
     0.0, .001, .03, .05, .09, .13, .18, .25, .29, .33,  .39, .44,
     .51,  .57, .62, .69, .75, .81, .91, .93, .97, .98, .999, 1.0};
 unsigned const BezierUtilsTest::n = G_N_ELEMENTS(BezierUtilsTest::t);
-Point const BezierUtilsTest::src_b[4] = {
-    Point(5., -3.),
-    Point(8., 0.),
-    Point(4., 2.),
-    Point(3., 3.)};
-Point const BezierUtilsTest::tHat1(unit_vector( BezierUtilsTest::src_b[1] - BezierUtilsTest::src_b[0] ));
-Point const BezierUtilsTest::tHat2(unit_vector( BezierUtilsTest::src_b[2] - BezierUtilsTest::src_b[3] ));
+NR::Point const BezierUtilsTest::src_b[4] = {
+    NR::Point(5., -3.),
+    NR::Point(8., 0.),
+    NR::Point(4., 2.),
+    NR::Point(3., 3.)};
+NR::Point const BezierUtilsTest::tHat1(unit_vector( BezierUtilsTest::src_b[1] - BezierUtilsTest::src_b[0] ));
+NR::Point const BezierUtilsTest::tHat2(unit_vector( BezierUtilsTest::src_b[2] - BezierUtilsTest::src_b[3] ));
 
 /*
   Local Variables:
diff --git a/src/display/curve-test.h b/src/display/curve-test.h
new file mode 100644 (file)
index 0000000..cca77e0
--- /dev/null
@@ -0,0 +1,254 @@
+#include <cxxtest/TestSuite.h>
+
+#include "display/curve.h"
+#include <2geom/curves.h>
+#include <2geom/path.h>
+#include <2geom/pathvector.h>
+
+class CurveTest : public CxxTest::TestSuite {
+private:
+    Geom::Path path1;
+    Geom::Path path2;
+    Geom::Path path3;
+    Geom::Path path4;
+
+public:
+    CurveTest() : path4(Geom::Point(3,5)) // Just a moveto
+    {
+        // Closed path which needs a closing segment
+        path1.append(Geom::HLineSegment(Geom::Point(0,0),1));
+        path1.append(Geom::VLineSegment(Geom::Point(1,0),1));
+        path1.close();
+        // Closed path that doesn't need a closing segment
+        path2.append(Geom::LineSegment(Geom::Point(2,0),Geom::Point(3,0)));
+        path2.append(Geom::BezierCurve<3>(Geom::Point(3,0),Geom::Point(2,1),Geom::Point(1,1),Geom::Point(2,0)));
+        path2.close();
+        // Open path
+        path3.append(Geom::SVGEllipticalArc(Geom::Point(4,0),1,2,M_PI,false,false,Geom::Point(5,1)));
+        path3.append(Geom::VLineSegment(Geom::Point(5,1),2), Geom::Path::STITCH_DISCONTINUOUS);
+        path3.append(Geom::HLineSegment(Geom::Point(6,4),2), Geom::Path::STITCH_DISCONTINUOUS);
+    }
+    virtual ~CurveTest() {}
+
+// createSuite and destroySuite get us per-suite setup and teardown
+// without us having to worry about static initialization order, etc.
+    static CurveTest *createSuite() { return new CurveTest(); }
+    static void destroySuite( CurveTest *suite ) { delete suite; }
+
+    void testGetSegmentCount()
+    {
+        { // Zero segments
+            Geom::PathVector pv;
+            SPCurve curve(pv);
+            TS_ASSERT_EQUALS(curve.get_segment_count() , 0u);
+        }
+        { // Zero segments
+            Geom::PathVector pv;
+            pv.push_back(Geom::Path());
+            SPCurve curve(pv);
+            TS_ASSERT_EQUALS(curve.get_segment_count() , 0u);
+        }
+        { // Individual paths
+            Geom::PathVector pv(1, Geom::Path());
+            pv[0] = path1;
+            TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 3u);
+            pv[0] = path2;
+            TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 2u);
+            pv[0] = path3;
+            TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 4u);
+            pv[0] = path4;
+            TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 0u);
+        }
+        { // Combination
+            Geom::PathVector pv;
+            pv.push_back(path1);
+            pv.push_back(path2);
+            pv.push_back(path3);
+            pv.push_back(path4);
+            SPCurve curve(pv);
+            TS_ASSERT_EQUALS(curve.get_segment_count() , 9u);
+        }
+    }
+
+    void testNodesInPath()
+    {
+        { // Zero segments
+            Geom::PathVector pv;
+            SPCurve curve(pv);
+            TS_ASSERT_EQUALS(curve.nodes_in_path() , 0u);
+        }
+        { // Zero segments
+            Geom::PathVector pv;
+            pv.push_back(Geom::Path());
+            SPCurve curve(pv);
+            TS_ASSERT_EQUALS(curve.nodes_in_path() , 1u);
+        }
+        { // Individual paths
+            Geom::PathVector pv(1, Geom::Path());
+            pv[0] = path1;
+            TS_ASSERT_EQUALS(SPCurve(pv).nodes_in_path() , 3u);
+            pv[0] = path2;
+            TS_ASSERT_EQUALS(SPCurve(pv).nodes_in_path() , 2u);
+            pv[0] = path3;
+            TS_ASSERT_EQUALS(SPCurve(pv).nodes_in_path() , 5u);
+            pv[0] = path4;
+            TS_ASSERT_EQUALS(SPCurve(pv).nodes_in_path() , 1u);
+        }
+        { // Combination
+            Geom::PathVector pv;
+            pv.push_back(path1);
+            pv.push_back(path2);
+            pv.push_back(path3);
+            pv.push_back(path4);
+            SPCurve curve(pv);
+            TS_ASSERT_EQUALS(curve.nodes_in_path() , 11u);
+        }
+    }
+
+    void testIsEmpty()
+    {
+        TS_ASSERT(SPCurve(Geom::PathVector()).is_empty());
+        TS_ASSERT(!SPCurve(Geom::PathVector(1, path1)).is_empty());
+        TS_ASSERT(!SPCurve(Geom::PathVector(1, path2)).is_empty());
+        TS_ASSERT(!SPCurve(Geom::PathVector(1, path3)).is_empty());
+        TS_ASSERT(!SPCurve(Geom::PathVector(1, path4)).is_empty());
+    }
+
+    void testIsClosed()
+    {
+        TS_ASSERT(SPCurve(Geom::PathVector()).is_closed()); // An empty conjuction is true
+        Geom::PathVector pv(1, Geom::Path());
+        TS_ASSERT(!SPCurve(pv).is_closed());
+        pv[0].close();
+        TS_ASSERT(SPCurve(pv).is_closed());
+        TS_ASSERT(SPCurve(Geom::PathVector(1, path1)).is_closed());
+        TS_ASSERT(SPCurve(Geom::PathVector(1, path2)).is_closed());
+        TS_ASSERT(!SPCurve(Geom::PathVector(1, path3)).is_closed());
+        TS_ASSERT(!SPCurve(Geom::PathVector(1, path4)).is_closed());
+    }
+
+    void testLastFirstSegment()
+    {
+        Geom::PathVector pv(1, path4);
+        TS_ASSERT_EQUALS(SPCurve(pv).first_segment() , (void*)0);
+        TS_ASSERT_EQUALS(SPCurve(pv).last_segment()  , (void*)0);
+        pv[0].close();
+        TS_ASSERT_DIFFERS(SPCurve(pv).first_segment() , (void*)0);
+        TS_ASSERT_DIFFERS(SPCurve(pv).last_segment()  , (void*)0);
+        /* Geom::Curve can't be compared very easily (?)
+        Geom::PathVector pv(1, path4);
+        pv[0].close();
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_segment() , pv[0][0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_segment()  , pv[0][0]);
+        pv[0] = path1;
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_segment() , pv[0][0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_segment()  , pv[0][2]);
+        pv[0] = path2;
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_segment() , pv[0][0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_segment()  , pv[0][1]);
+        pv[0] = path3;
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_segment() , pv[0][0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_segment()  , pv[0][3]);
+        pv[0] = path4;
+        TS_ASSERT_EQUALS(SPCurve(pv).first_segment() , (void*)0);
+        TS_ASSERT_EQUALS(SPCurve(pv).last_segment()  , (void*)0);
+        pv.clear();
+        pv.push_back(path1);
+        pv.push_back(path2);
+        pv.push_back(path3);
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_segment() , pv[0][0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_segment()  , pv[2][3]);*/
+    }
+
+    void testLastFirstPath()
+    {
+        Geom::PathVector pv;
+        TS_ASSERT_EQUALS(SPCurve(pv).first_path() , (void*)0);
+        TS_ASSERT_EQUALS(SPCurve(pv).last_path()  , (void*)0);
+        pv.push_back(path1);
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_path() , pv[0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_path()  , pv[0]);
+        pv.push_back(path2);
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_path() , pv[0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_path()  , pv[1]);
+        pv.push_back(path3);
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_path() , pv[0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_path()  , pv[2]);
+        pv.push_back(path4);
+        TS_ASSERT_EQUALS(*SPCurve(pv).first_path() , pv[0]);
+        TS_ASSERT_EQUALS(*SPCurve(pv).last_path()  , pv[3]);
+    }
+
+    void testFirstPoint()
+    {
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path1)).first_point() , Geom::Point(0,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path2)).first_point() , Geom::Point(2,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path3)).first_point() , Geom::Point(4,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path4)).first_point() , Geom::Point(3,5));
+        Geom::PathVector pv;
+        pv.push_back(path1);
+        pv.push_back(path2);
+        pv.push_back(path3);
+        TS_ASSERT_EQUALS(SPCurve(pv).first_point() , Geom::Point(0,0));
+        pv.insert(pv.begin(), path4);
+        TS_ASSERT_EQUALS(SPCurve(pv).first_point() , Geom::Point(3,5));
+    }
+
+    void testLastPoint()
+    {
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path1)).last_point() , Geom::Point(0,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path2)).last_point() , Geom::Point(2,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path3)).last_point() , Geom::Point(8,4));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path4)).last_point() , Geom::Point(3,5));
+        Geom::PathVector pv;
+        pv.push_back(path1);
+        pv.push_back(path2);
+        pv.push_back(path3);
+        TS_ASSERT_EQUALS(SPCurve(pv).last_point() , Geom::Point(8,4));
+        pv.push_back(path4);
+        TS_ASSERT_EQUALS(SPCurve(pv).last_point() , Geom::Point(3,5));
+    }
+
+    void testSecondPoint()
+    {
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path1)).second_point() , Geom::Point(1,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path2)).second_point() , Geom::Point(3,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path3)).second_point() , Geom::Point(5,1));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path4)).second_point() , Geom::Point(3,5));
+        Geom::PathVector pv;
+        pv.push_back(path1);
+        pv.push_back(path2);
+        pv.push_back(path3);
+        TS_ASSERT_EQUALS(SPCurve(pv).second_point() , Geom::Point(1,0));
+        pv.insert(pv.begin(), path4);
+        TS_ASSERT_EQUALS(SPCurve(pv).second_point() , Geom::Point(0,0));
+    }
+
+    void testPenultimatePoint()
+    {
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path1)).penultimate_point() , Geom::Point(1,1));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path2)).penultimate_point() , Geom::Point(3,0));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path3)).penultimate_point() , Geom::Point(6,4));
+        TS_ASSERT_EQUALS(SPCurve(Geom::PathVector(1, path4)).penultimate_point() , Geom::Point(3,5));
+        Geom::PathVector pv;
+        pv.push_back(path1);
+        pv.push_back(path2);
+        pv.push_back(path3);
+        TS_ASSERT_EQUALS(SPCurve(pv).penultimate_point() , Geom::Point(6,4));
+        pv.push_back(path4);
+        TS_ASSERT_EQUALS(SPCurve(pv).penultimate_point() , Geom::Point(8,4));
+    }
+
+    // TODO: Rest of the methods
+};
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :