Code

noop: svg/svg-path-geom-test.h: Change to consistent end-of-line separators, and...
authorpjrm <pjrm@users.sourceforge.net>
Tue, 7 Apr 2009 06:24:37 +0000 (06:24 +0000)
committerpjrm <pjrm@users.sourceforge.net>
Tue, 7 Apr 2009 06:24:37 +0000 (06:24 +0000)
src/svg/svg-path-geom-test.h

index 7358c6d6917c79e11631cc719b2681c9697b9e36..9a091cb86c762f7fb6a660ba4ccc311f6ba6e569 100644 (file)
-#include <cxxtest/TestSuite.h>\r
-#include "2geom/coord.h"\r
-#include "2geom/curves.h"\r
-#include "2geom/pathvector.h"\r
-#include "svg/svg.h"\r
-#include "preferences.h"\r
-#include "streq.h"\r
-#include <stdio.h>\r
-#include <string>\r
-#include <vector>\r
-#include <glib/gmem.h>\r
-\r
-class SvgPathGeomTest : public CxxTest::TestSuite\r
-{\r
-private:\r
-    std::vector<std::string> rectanglesAbsoluteClosed;\r
-    std::vector<std::string> rectanglesRelativeClosed;\r
-    std::vector<std::string> rectanglesAbsoluteOpen;\r
-    std::vector<std::string> rectanglesRelativeOpen;\r
-    std::vector<std::string> rectanglesAbsoluteClosed2;\r
-    std::vector<std::string> rectanglesRelativeClosed2;\r
-    Geom::PathVector rectanglepvopen;\r
-    Geom::PathVector rectanglepvclosed;\r
-    Geom::PathVector rectanglepvclosed2;\r
-public:\r
-    SvgPathGeomTest() {\r
-        // Lots of ways to define the same rectangle\r
-        rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");\r
-        rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");\r
-        rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");\r
-        rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");\r
-        rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");\r
-        rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");\r
-        rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");\r
-        rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");\r
-        rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");\r
-        rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");\r
-        rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");\r
-        rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");\r
-        rectanglesAbsoluteClosed2.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 z");\r
-        rectanglesAbsoluteClosed2.push_back("M 1,2 4,2 4,8 1,8 1,2 z");\r
-        rectanglesAbsoluteClosed2.push_back("M 1,2 H 4 V 8 H 1 V 2 z");\r
-        rectanglesRelativeClosed2.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6 z");\r
-        rectanglesRelativeClosed2.push_back("m 1,2 3,0 0,6 -3,0 0,-6 z");\r
-        rectanglesRelativeClosed2.push_back("m 1,2 h 3 v 6 h -3 v -6 z");\r
-        rectanglepvopen.push_back(Geom::Path(Geom::Point(1,2)));\r
-        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));\r
-        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));\r
-        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));\r
-        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));\r
-        rectanglepvclosed.push_back(Geom::Path(Geom::Point(1,2)));\r
-        rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));\r
-        rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));\r
-        rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));\r
-        rectanglepvclosed.back().close();\r
-        rectanglepvclosed2.push_back(Geom::Path(Geom::Point(1,2)));\r
-        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));\r
-        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));\r
-        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));\r
-        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));\r
-        rectanglepvclosed2.back().close();\r
-        // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs\r
-        // TODO: Should we make it mandatory that h/v in the path data results in a H/VLineSegment?\r
-        //       If so, the tests should be modified to reflect this.\r
-    }\r
-\r
-// createSuite and destroySuite get us per-suite setup and teardown\r
-// without us having to worry about static initialization order, etc.\r
-    static SvgPathGeomTest *createSuite() { return new SvgPathGeomTest(); }\r
-    static void destroySuite( SvgPathGeomTest *suite ) { delete suite; }\r
-\r
-    void testReadRectanglesAbsoluteClosed()\r
-    {\r
-        for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {\r
-            Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed[i].c_str());\r
-            TSM_ASSERT(rectanglesAbsoluteClosed[i].c_str(), bpathEqual(pv,rectanglepvclosed));\r
-        }\r
-    }\r
-\r
-    void testReadRectanglesRelativeClosed()\r
-    {\r
-        for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {\r
-            Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed[i].c_str());\r
-            TSM_ASSERT(rectanglesRelativeClosed[i].c_str(), bpathEqual(pv,rectanglepvclosed));\r
-        }\r
-    }\r
-\r
-    void testReadRectanglesAbsoluteOpen()\r
-    {\r
-        for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {\r
-            Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteOpen[i].c_str());\r
-            TSM_ASSERT(rectanglesAbsoluteOpen[i].c_str(), bpathEqual(pv,rectanglepvopen));\r
-        }\r
-    }\r
-\r
-    void testReadRectanglesRelativeOpen()\r
-    {\r
-        for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {\r
-            Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeOpen[i].c_str());\r
-            TSM_ASSERT(rectanglesRelativeOpen[i].c_str(), bpathEqual(pv,rectanglepvopen));\r
-        }\r
-    }\r
-\r
-    void testReadRectanglesAbsoluteClosed2()\r
-    {\r
-        for(size_t i=0; i<rectanglesAbsoluteClosed2.size(); i++) {\r
-            Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed2[i].c_str());\r
-            TSM_ASSERT(rectanglesAbsoluteClosed2[i].c_str(), bpathEqual(pv,rectanglepvclosed2));\r
-        }\r
-    }\r
-\r
-    void testReadRectanglesRelativeClosed2()\r
-    {\r
-        for(size_t i=0; i<rectanglesRelativeClosed2.size(); i++) {\r
-            Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed2[i].c_str());\r
-            TSM_ASSERT(rectanglesRelativeClosed2[i].c_str(), bpathEqual(pv,rectanglepvclosed2));\r
-        }\r
-    }\r
-\r
-    void testReadConcatenatedPaths()\r
-    {\r
-        // Note that finalPoint doesn't actually return the final point of the path, just the last given point... (but since this might be intentional and we're not testing lib2geom here, we just specify the final point explicitly\r
-        Geom::PathVector pv_good;\r
-        pv_good.push_back(rectanglepvclosed.back());\r
-        pv_good.push_back(rectanglepvopen.back() * Geom::Translate(1,2)/* * Geom::Translate(pv_good[0].finalPoint())*/);\r
-        pv_good.push_back(rectanglepvclosed.back() * Geom::Translate(2,4)/* *Geom::Translate(pv_good[1].finalPoint())*/);\r
-        pv_good.push_back(rectanglepvopen.back());\r
-        pv_good[0].close();\r
-        pv_good[1].close(false);\r
-        pv_good[2].close();\r
-        pv_good[3].close(false);\r
-        std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];\r
-        Geom::PathVector pv = sp_svg_read_pathv(path_str.c_str());\r
-        TS_ASSERT(bpathEqual(pv,pv_good));\r
-    }\r
-\r
-    void testReadZeroLengthSubpaths() {\r
-        // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant\r
-        Geom::PathVector pv_good;\r
-        pv_good.push_back(Geom::Path(Geom::Point(0,0)));\r
-        pv_good.push_back(Geom::Path(Geom::Point(1,1)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));\r
-        pv_good.push_back(Geom::Path(Geom::Point(3,3)));\r
-        pv_good.back().close();\r
-        pv_good.push_back(Geom::Path(Geom::Point(4,4)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(4,4),Geom::Point(5,5)));\r
-        pv_good.back().close();\r
-        pv_good.push_back(Geom::Path(Geom::Point(6,6)));\r
-        {   // Test absolute version\r
-            char const * path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
-        }\r
-        {   // Test relative version\r
-            char const * path_str = "m 0,0 m 1,1 l 1,1 m 1,1 z m 1,1 l 1,1 z m 2,2";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
-        }\r
-    }\r
-\r
-    void testReadImplicitMoveto() {\r
-        TS_WARN("Currently lib2geom (/libnr) has no way of specifying the difference between '... z M 0,0 L 1,0' and '... z L 1,0', the SVG specification does state that these should be handled differently with respect to markers however, see the description of the 'orient' attribute of the 'marker' element.");\r
-        Geom::PathVector pv_good;\r
-        pv_good.push_back(Geom::Path(Geom::Point(1,1)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));\r
-        pv_good.back().close();\r
-        pv_good.push_back(Geom::Path(Geom::Point(1,1)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(3,3)));\r
-        pv_good.back().close();\r
-        {   // Test absolute version\r
-            char const * path_str = "M 1,1 L 2,2 z L 3,3 z";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
-        }\r
-        {   // Test relative version\r
-            char const * path_str = "M 1,1 L 2,2 z L 3,3 z";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
-        }\r
-    }\r
-\r
-    void testReadFloatingPoint() {\r
-        Geom::PathVector pv_good1;\r
-        pv_good1.push_back(Geom::Path(Geom::Point(.01,.02)));\r
-        pv_good1.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));\r
-        pv_good1.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));\r
-        pv_good1.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));\r
-        pv_good1.back().append(Geom::LineSegment(Geom::Point(.01,.08),Geom::Point(.01,.02)));\r
-        pv_good1.back().close();\r
-        {   // Test decimals\r
-            char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good1));\r
-        }\r
-        Geom::PathVector pv_good2;\r
-        pv_good2.push_back(Geom::Path(Geom::Point(.01,.02)));\r
-        pv_good2.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));\r
-        pv_good2.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));\r
-        pv_good2.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));\r
-        pv_good2.back().close();\r
-        {   // Test exponent\r
-            char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good2));\r
-        }\r
-    }\r
-\r
-    void testReadImplicitSeparation() {\r
-        // Coordinates need not be separated by whitespace if they can still be read unambiguously\r
-        Geom::PathVector pv_good;\r
-        pv_good.push_back(Geom::Path(Geom::Point(.1,.2)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(.1,.2),Geom::Point(.4,.2)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.2),Geom::Point(.4,.8)));\r
-        pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.8),Geom::Point(.1,.8)));\r
-        pv_good.back().close();\r
-        {   // Test absolute\r
-            char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
-        }\r
-        {   // Test relative\r
-            char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";\r
-            Geom::PathVector pv = sp_svg_read_pathv(path_str);\r
-            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));\r
-        }\r
-    }\r
-\r
-    void testReadErrorMisplacedCharacter() {\r
-        char const * path_str;\r
-        Geom::PathVector pv;\r
-        // Comma in the wrong place (commas may only appear between parameters)\r
-        path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Comma in the wrong place (commas may only appear between parameters)\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Period in the wrong place (no numbers after a 'z')\r
-        path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Sign in the wrong place (no numbers after a 'z')\r
-        path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Digit in the wrong place (no numbers after a 'z')\r
-        path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Digit in the wrong place (no numbers after a 'z')\r
-        path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-    }\r
-\r
-    void testReadErrorUnrecognizedCharacter() {\r
-        char const * path_str;\r
-        Geom::PathVector pv;\r
-        // Unrecognized character\r
-        path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Unrecognized character\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-    }\r
-\r
-    void testReadErrorTypo() {\r
-        char const * path_str;\r
-        Geom::PathVector pv;\r
-        // Typo\r
-        path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-\r
-        // Typo\r
-        path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvopen));\r
-    }\r
-\r
-    void testReadErrorIllformedNumbers() {\r
-        char const * path_str;\r
-        Geom::PathVector pv;\r
-        // Double exponent\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Double sign\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Double sign\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // No digit\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // No digit\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m .,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // No digit\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m +,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // No digit\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-    }\r
-\r
-    void testReadErrorJunk() {\r
-        char const * path_str;\r
-        Geom::PathVector pv;\r
-        // Junk\r
-        path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-    }\r
-\r
-    void testReadErrorStopReading() {\r
-        char const * path_str;\r
-        Geom::PathVector pv;\r
-        // Unrecognized parameter\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Invalid parameter\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-        // Illformed parameter\r
-        path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));\r
-\r
-        // "Third" parameter\r
-        path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";\r
-        pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvopen));\r
-    }\r
-\r
-    void testRoundTrip() {\r
-        // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.\r
-        Geom::PathVector pv;\r
-        Geom::PathVector new_pv;\r
-        std::string org_path_str;\r
-        char * path_str;\r
-        // Rectangle (closed)\r
-        org_path_str = rectanglesAbsoluteClosed[0];\r
-        pv = sp_svg_read_pathv(org_path_str.c_str());\r
-        path_str = sp_svg_write_path(pv);\r
-        new_pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
-        g_free(path_str);\r
-        // Rectangle (open)\r
-        org_path_str = rectanglesAbsoluteOpen[0];\r
-        pv = sp_svg_read_pathv(org_path_str.c_str());\r
-        path_str = sp_svg_write_path(pv);\r
-        new_pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
-        g_free(path_str);\r
-        // Concatenated rectangles\r
-        org_path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];\r
-        pv = sp_svg_read_pathv(org_path_str.c_str());\r
-        path_str = sp_svg_write_path(pv);\r
-        new_pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
-        g_free(path_str);\r
-        // Zero-length subpaths\r
-        org_path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";\r
-        pv = sp_svg_read_pathv(org_path_str.c_str());\r
-        path_str = sp_svg_write_path(pv);\r
-        new_pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));\r
-        g_free(path_str);\r
-        // Floating-point\r
-        org_path_str = "M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z""M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z";\r
-        pv = sp_svg_read_pathv(org_path_str.c_str());\r
-        path_str = sp_svg_write_path(pv);\r
-        new_pv = sp_svg_read_pathv(path_str);\r
-        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv, new_pv, 1e-17));\r
-        g_free(path_str);\r
-    }\r
-\r
-    void testMinexpPrecision() {\r
-        Geom::PathVector pv;\r
-        char * path_str;\r
+#include <cxxtest/TestSuite.h>
+#include "2geom/coord.h"
+#include "2geom/curves.h"
+#include "2geom/pathvector.h"
+#include "svg/svg.h"
+#include "preferences.h"
+#include "streq.h"
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <glib/gmem.h>
+
+class SvgPathGeomTest : public CxxTest::TestSuite
+{
+private:
+    std::vector<std::string> rectanglesAbsoluteClosed;
+    std::vector<std::string> rectanglesRelativeClosed;
+    std::vector<std::string> rectanglesAbsoluteOpen;
+    std::vector<std::string> rectanglesRelativeOpen;
+    std::vector<std::string> rectanglesAbsoluteClosed2;
+    std::vector<std::string> rectanglesRelativeClosed2;
+    Geom::PathVector rectanglepvopen;
+    Geom::PathVector rectanglepvclosed;
+    Geom::PathVector rectanglepvclosed2;
+public:
+    SvgPathGeomTest() {
+        // Lots of ways to define the same rectangle
+        rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");
+        rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");
+        rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");
+        rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");
+        rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");
+        rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");
+        rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");
+        rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");
+        rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");
+        rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");
+        rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");
+        rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");
+        rectanglesAbsoluteClosed2.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 z");
+        rectanglesAbsoluteClosed2.push_back("M 1,2 4,2 4,8 1,8 1,2 z");
+        rectanglesAbsoluteClosed2.push_back("M 1,2 H 4 V 8 H 1 V 2 z");
+        rectanglesRelativeClosed2.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6 z");
+        rectanglesRelativeClosed2.push_back("m 1,2 3,0 0,6 -3,0 0,-6 z");
+        rectanglesRelativeClosed2.push_back("m 1,2 h 3 v 6 h -3 v -6 z");
+        rectanglepvopen.push_back(Geom::Path(Geom::Point(1,2)));
+        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));
+        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));
+        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));
+        rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));
+        rectanglepvclosed.push_back(Geom::Path(Geom::Point(1,2)));
+        rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));
+        rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));
+        rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));
+        rectanglepvclosed.back().close();
+        rectanglepvclosed2.push_back(Geom::Path(Geom::Point(1,2)));
+        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1,2),Geom::Point(4,2)));
+        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4,2),Geom::Point(4,8)));
+        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4,8),Geom::Point(1,8)));
+        rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1,8),Geom::Point(1,2)));
+        rectanglepvclosed2.back().close();
+        // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs
+        // TODO: Should we make it mandatory that h/v in the path data results in a H/VLineSegment?
+        //       If so, the tests should be modified to reflect this.
+    }
+
+// createSuite and destroySuite get us per-suite setup and teardown
+// without us having to worry about static initialization order, etc.
+    static SvgPathGeomTest *createSuite() { return new SvgPathGeomTest(); }
+    static void destroySuite( SvgPathGeomTest *suite ) { delete suite; }
+
+    void testReadRectanglesAbsoluteClosed()
+    {
+        for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {
+            Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed[i].c_str());
+            TSM_ASSERT(rectanglesAbsoluteClosed[i].c_str(), bpathEqual(pv,rectanglepvclosed));
+        }
+    }
+
+    void testReadRectanglesRelativeClosed()
+    {
+        for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {
+            Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed[i].c_str());
+            TSM_ASSERT(rectanglesRelativeClosed[i].c_str(), bpathEqual(pv,rectanglepvclosed));
+        }
+    }
+
+    void testReadRectanglesAbsoluteOpen()
+    {
+        for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {
+            Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteOpen[i].c_str());
+            TSM_ASSERT(rectanglesAbsoluteOpen[i].c_str(), bpathEqual(pv,rectanglepvopen));
+        }
+    }
+
+    void testReadRectanglesRelativeOpen()
+    {
+        for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {
+            Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeOpen[i].c_str());
+            TSM_ASSERT(rectanglesRelativeOpen[i].c_str(), bpathEqual(pv,rectanglepvopen));
+        }
+    }
+
+    void testReadRectanglesAbsoluteClosed2()
+    {
+        for(size_t i=0; i<rectanglesAbsoluteClosed2.size(); i++) {
+            Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed2[i].c_str());
+            TSM_ASSERT(rectanglesAbsoluteClosed2[i].c_str(), bpathEqual(pv,rectanglepvclosed2));
+        }
+    }
+
+    void testReadRectanglesRelativeClosed2()
+    {
+        for(size_t i=0; i<rectanglesRelativeClosed2.size(); i++) {
+            Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed2[i].c_str());
+            TSM_ASSERT(rectanglesRelativeClosed2[i].c_str(), bpathEqual(pv,rectanglepvclosed2));
+        }
+    }
+
+    void testReadConcatenatedPaths()
+    {
+        // Note that finalPoint doesn't actually return the final point of the path, just the last given point... (but since this might be intentional and we're not testing lib2geom here, we just specify the final point explicitly
+        Geom::PathVector pv_good;
+        pv_good.push_back(rectanglepvclosed.back());
+        pv_good.push_back(rectanglepvopen.back() * Geom::Translate(1,2)/* * Geom::Translate(pv_good[0].finalPoint())*/);
+        pv_good.push_back(rectanglepvclosed.back() * Geom::Translate(2,4)/* *Geom::Translate(pv_good[1].finalPoint())*/);
+        pv_good.push_back(rectanglepvopen.back());
+        pv_good[0].close();
+        pv_good[1].close(false);
+        pv_good[2].close();
+        pv_good[3].close(false);
+        std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
+        Geom::PathVector pv = sp_svg_read_pathv(path_str.c_str());
+        TS_ASSERT(bpathEqual(pv,pv_good));
+    }
+
+    void testReadZeroLengthSubpaths() {
+        // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant
+        Geom::PathVector pv_good;
+        pv_good.push_back(Geom::Path(Geom::Point(0,0)));
+        pv_good.push_back(Geom::Path(Geom::Point(1,1)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));
+        pv_good.push_back(Geom::Path(Geom::Point(3,3)));
+        pv_good.back().close();
+        pv_good.push_back(Geom::Path(Geom::Point(4,4)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(4,4),Geom::Point(5,5)));
+        pv_good.back().close();
+        pv_good.push_back(Geom::Path(Geom::Point(6,6)));
+        {   // Test absolute version
+            char const * path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
+        }
+        {   // Test relative version
+            char const * path_str = "m 0,0 m 1,1 l 1,1 m 1,1 z m 1,1 l 1,1 z m 2,2";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
+        }
+    }
+
+    void testReadImplicitMoveto() {
+        TS_WARN("Currently lib2geom (/libnr) has no way of specifying the difference between '... z M 0,0 L 1,0' and '... z L 1,0', the SVG specification does state that these should be handled differently with respect to markers however, see the description of the 'orient' attribute of the 'marker' element.");
+        Geom::PathVector pv_good;
+        pv_good.push_back(Geom::Path(Geom::Point(1,1)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(2,2)));
+        pv_good.back().close();
+        pv_good.push_back(Geom::Path(Geom::Point(1,1)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(1,1),Geom::Point(3,3)));
+        pv_good.back().close();
+        {   // Test absolute version
+            char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
+        }
+        {   // Test relative version
+            char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
+        }
+    }
+
+    void testReadFloatingPoint() {
+        Geom::PathVector pv_good1;
+        pv_good1.push_back(Geom::Path(Geom::Point(.01,.02)));
+        pv_good1.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));
+        pv_good1.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));
+        pv_good1.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));
+        pv_good1.back().append(Geom::LineSegment(Geom::Point(.01,.08),Geom::Point(.01,.02)));
+        pv_good1.back().close();
+        {   // Test decimals
+            char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good1));
+        }
+        Geom::PathVector pv_good2;
+        pv_good2.push_back(Geom::Path(Geom::Point(.01,.02)));
+        pv_good2.back().append(Geom::LineSegment(Geom::Point(.01,.02),Geom::Point(.04,.02)));
+        pv_good2.back().append(Geom::LineSegment(Geom::Point(.04,.02),Geom::Point(1.5,1.6)));
+        pv_good2.back().append(Geom::LineSegment(Geom::Point(1.5,1.6),Geom::Point(.01,.08)));
+        pv_good2.back().close();
+        {   // Test exponent
+            char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good2));
+        }
+    }
+
+    void testReadImplicitSeparation() {
+        // Coordinates need not be separated by whitespace if they can still be read unambiguously
+        Geom::PathVector pv_good;
+        pv_good.push_back(Geom::Path(Geom::Point(.1,.2)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(.1,.2),Geom::Point(.4,.2)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.2),Geom::Point(.4,.8)));
+        pv_good.back().append(Geom::LineSegment(Geom::Point(.4,.8),Geom::Point(.1,.8)));
+        pv_good.back().close();
+        {   // Test absolute
+            char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
+        }
+        {   // Test relative
+            char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";
+            Geom::PathVector pv = sp_svg_read_pathv(path_str);
+            TSM_ASSERT(path_str, bpathEqual(pv,pv_good));
+        }
+    }
+
+    void testReadErrorMisplacedCharacter() {
+        char const * path_str;
+        Geom::PathVector pv;
+        // Comma in the wrong place (commas may only appear between parameters)
+        path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Comma in the wrong place (commas may only appear between parameters)
+        path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Period in the wrong place (no numbers after a 'z')
+        path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Sign in the wrong place (no numbers after a 'z')
+        path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Digit in the wrong place (no numbers after a 'z')
+        path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Digit in the wrong place (no numbers after a 'z')
+        path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+    }
+
+    void testReadErrorUnrecognizedCharacter() {
+        char const * path_str;
+        Geom::PathVector pv;
+        // Unrecognized character
+        path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Unrecognized character
+        path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+    }
+
+    void testReadErrorTypo() {
+        char const * path_str;
+        Geom::PathVector pv;
+        // Typo
+        path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+
+        // Typo
+        path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvopen));
+    }
+
+    void testReadErrorIllformedNumbers() {
+        char const * path_str;
+        Geom::PathVector pv;
+        // Double exponent
+        path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Double sign
+        path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Double sign
+        path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // No digit
+        path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // No digit
+        path_str = "M 1,2 4,2 4,8 1,8 z m .,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // No digit
+        path_str = "M 1,2 4,2 4,8 1,8 z m +,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // No digit
+        path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+    }
+
+    void testReadErrorJunk() {
+        char const * path_str;
+        Geom::PathVector pv;
+        // Junk
+        path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+    }
+
+    void testReadErrorStopReading() {
+        char const * path_str;
+        Geom::PathVector pv;
+        // Unrecognized parameter
+        path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Invalid parameter
+        path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+        // Illformed parameter
+        path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvclosed));
+
+        // "Third" parameter
+        path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";
+        pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(path_str, bpathEqual(pv,rectanglepvopen));
+    }
+
+    void testRoundTrip() {
+        // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.
+        Geom::PathVector pv;
+        Geom::PathVector new_pv;
+        std::string org_path_str;
+        char * path_str;
+        // Rectangle (closed)
+        org_path_str = rectanglesAbsoluteClosed[0];
+        pv = sp_svg_read_pathv(org_path_str.c_str());
+        path_str = sp_svg_write_path(pv);
+        new_pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
+        g_free(path_str);
+        // Rectangle (open)
+        org_path_str = rectanglesAbsoluteOpen[0];
+        pv = sp_svg_read_pathv(org_path_str.c_str());
+        path_str = sp_svg_write_path(pv);
+        new_pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
+        g_free(path_str);
+        // Concatenated rectangles
+        org_path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
+        pv = sp_svg_read_pathv(org_path_str.c_str());
+        path_str = sp_svg_write_path(pv);
+        new_pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
+        g_free(path_str);
+        // Zero-length subpaths
+        org_path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";
+        pv = sp_svg_read_pathv(org_path_str.c_str());
+        path_str = sp_svg_write_path(pv);
+        new_pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv,new_pv));
+        g_free(path_str);
+        // Floating-point
+        org_path_str = "M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z""M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z";
+        pv = sp_svg_read_pathv(org_path_str.c_str());
+        path_str = sp_svg_write_path(pv);
+        new_pv = sp_svg_read_pathv(path_str);
+        TSM_ASSERT(org_path_str.c_str(), bpathEqual(pv, new_pv, 1e-17));
+        g_free(path_str);
+    }
+
+    void testMinexpPrecision() {
+        Geom::PathVector pv;
+        char * path_str;
         // Default values
-        Inkscape::Preferences *prefs = Inkscape::Preferences::get();\r
-        prefs->setBool("/options/svgoutput/allowrelativecoordinates", true);\r
-        prefs->setBool("/options/svgoutput/forcerepeatcommands", false);\r
-        prefs->setInt("/options/svgoutput/numericprecision", 8);\r
-        prefs->setInt("/options/svgoutput/minimumexponent", -8);\r
-        pv = sp_svg_read_pathv("M 123456781,1.23456781e-8 L 123456782,1.23456782e-8 L 123456785,1.23456785e-8 L 10123456400,1.23456785e-8 L 123456789,1.23456789e-8 L 123456789,101.234564e-8 L 123456789,1.23456789e-8");\r
-        path_str = sp_svg_write_path(pv);\r
-        TS_ASSERT_RELATION( streq_rel , "m 123456780,1.2345678e-8 0,0 10,1e-15 9999999210,0 -9999999210,0 0,9.99999921e-7 0,-9.99999921e-7" , path_str );\r
-        g_free(path_str);\r
-    }\r
-\r
-private:\r
-    bool bpathEqual(Geom::PathVector const &a, Geom::PathVector const &b, double eps = 1e-16) {\r
-        if (a.size() != b.size()) {\r
-            char temp[100];\r
-            sprintf(temp, "PathVectors not the same size: %u != %u", a.size(), b.size());\r
-            TS_FAIL(temp);\r
-            return false;\r
-        }\r
-        for(size_t i=0; i<a.size(); i++) {\r
-            Geom::Path const &pa = a[i];\r
-            Geom::Path const &pb = b[i];\r
-            if (pa.closed() && !pb.closed()) {\r
-                char temp[100];\r
-                sprintf(temp, "Left subpath is closed, right subpath is open. Subpath: %u", i);\r
-                TS_FAIL(temp);\r
-                return false;\r
-            }\r
-            if (!pa.closed() && pb.closed()) {\r
-                char temp[100];\r
-                sprintf(temp, "Right subpath is closed, left subpath is open. Subpath: %u", i);\r
-                TS_FAIL(temp);\r
-                return false;\r
-            }\r
-            if (pa.size() != pb.size()) {\r
-                char temp[100];\r
-                sprintf(temp, "Not the same number of segments: %u != %u, subpath: %u", pa.size(), pb.size(), i);\r
-                TS_FAIL(temp);\r
-                return false;\r
-            }\r
-            for(size_t j=0; j<pa.size(); j++) {\r
-                Geom::Curve const* ca = &pa[j];\r
-                Geom::Curve const* cb = &pb[j];\r
-                if (typeid(*ca) == typeid(*cb))\r
-                {\r
-                    if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))\r
-                    {\r
-                        Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb);\r
-                        if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                        if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                    }\r
-                    else if(Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca))\r
-                    {\r
-                        Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb);\r
-                        if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                        if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                    }\r
-                    else if(Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca))\r
-                    {\r
-                        Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb);\r
-                        if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                        if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                    }\r
-                    else if(Geom::CubicBezier const *la = dynamic_cast<Geom::CubicBezier const*>(ca))\r
-                    {\r
-                        Geom::CubicBezier const *lb = dynamic_cast<Geom::CubicBezier const*>(cb);\r
-                        if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                        if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different 1st control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                        if (!Geom::are_near((*la)[2],(*lb)[2], eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different 2nd control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[2][Geom::X], (*la)[2][Geom::Y], (*lb)[2][Geom::X], (*lb)[2][Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                        if (!Geom::are_near((*la)[3],(*lb)[3], eps)) {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[3][Geom::X], (*la)[3][Geom::Y], (*lb)[3][Geom::X], (*lb)[3][Geom::Y], i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                    }\r
-                    else\r
-                    {\r
-                        char temp[200];\r
-                        sprintf(temp, "Unknown curve type: %s, subpath: %u, segment: %u", typeid(*ca).name(), i, j);\r
-                        TS_FAIL(temp);\r
-                    }\r
-                }\r
-                else // not same type\r
-                {\r
-                    if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))\r
-                    {\r
-                        if (Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb)) {\r
-                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            char temp[200];\r
-                            sprintf(temp, "A LineSegment and an HLineSegment have been considered equal. Subpath: %u, segment: %u", i, j);\r
-                            TS_TRACE(temp);\r
-                        } else if (Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb)) {\r
-                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            char temp[200];\r
-                            sprintf(temp, "A LineSegment and a VLineSegment have been considered equal. Subpath: %u, segment: %u", i, j);\r
-                            TS_TRACE(temp);\r
-                        } else {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);\r
-                            TS_FAIL(temp);\r
-                        }\r
-                    }\r
-                    else if(Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb))\r
-                    {\r
-                        if (Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca)) {\r
-                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            char temp[200];\r
-                            sprintf(temp, "An HLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", i, j);\r
-                            TS_TRACE(temp);\r
-                        } else if (Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca)) {\r
-                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {\r
-                                char temp[200];\r
-                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);\r
-                                TS_FAIL(temp);\r
-                                return false;\r
-                            }\r
-                            char temp[200];\r
-                            sprintf(temp, "A VLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", i, j);\r
-                            TS_TRACE(temp);\r
-                        } else {\r
-                            char temp[200];\r
-                            sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);\r
-                            TS_FAIL(temp);\r
-                            return false;\r
-                        }\r
-                    } else {\r
-                        char temp[200];\r
-                        sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);\r
-                        TS_FAIL(temp);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        return true;\r
-    }\r
-};\r
-\r
-\r
-/*\r
-  Local Variables:\r
-  mode:c++\r
-  c-file-style:"stroustrup"\r
-  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
-  indent-tabs-mode:nil\r
-  fill-column:99\r
-  End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
+        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+        prefs->setBool("/options/svgoutput/allowrelativecoordinates", true);
+        prefs->setBool("/options/svgoutput/forcerepeatcommands", false);
+        prefs->setInt("/options/svgoutput/numericprecision", 8);
+        prefs->setInt("/options/svgoutput/minimumexponent", -8);
+        pv = sp_svg_read_pathv("M 123456781,1.23456781e-8 L 123456782,1.23456782e-8 L 123456785,1.23456785e-8 L 10123456400,1.23456785e-8 L 123456789,1.23456789e-8 L 123456789,101.234564e-8 L 123456789,1.23456789e-8");
+        path_str = sp_svg_write_path(pv);
+        TS_ASSERT_RELATION( streq_rel , "m 123456780,1.2345678e-8 0,0 10,1e-15 9999999210,0 -9999999210,0 0,9.99999921e-7 0,-9.99999921e-7" , path_str );
+        g_free(path_str);
+    }
+
+private:
+    bool bpathEqual(Geom::PathVector const &a, Geom::PathVector const &b, double eps = 1e-16) {
+        if (a.size() != b.size()) {
+            char temp[100];
+            sprintf(temp, "PathVectors not the same size: %u != %u", a.size(), b.size());
+            TS_FAIL(temp);
+            return false;
+        }
+        for(size_t i=0; i<a.size(); i++) {
+            Geom::Path const &pa = a[i];
+            Geom::Path const &pb = b[i];
+            if (pa.closed() && !pb.closed()) {
+                char temp[100];
+                sprintf(temp, "Left subpath is closed, right subpath is open. Subpath: %u", i);
+                TS_FAIL(temp);
+                return false;
+            }
+            if (!pa.closed() && pb.closed()) {
+                char temp[100];
+                sprintf(temp, "Right subpath is closed, left subpath is open. Subpath: %u", i);
+                TS_FAIL(temp);
+                return false;
+            }
+            if (pa.size() != pb.size()) {
+                char temp[100];
+                sprintf(temp, "Not the same number of segments: %u != %u, subpath: %u", pa.size(), pb.size(), i);
+                TS_FAIL(temp);
+                return false;
+            }
+            for(size_t j=0; j<pa.size(); j++) {
+                Geom::Curve const* ca = &pa[j];
+                Geom::Curve const* cb = &pb[j];
+                if (typeid(*ca) == typeid(*cb))
+                {
+                    if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))
+                    {
+                        Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb);
+                        if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                        if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                    }
+                    else if(Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca))
+                    {
+                        Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb);
+                        if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                        if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                    }
+                    else if(Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca))
+                    {
+                        Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb);
+                        if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                        if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                    }
+                    else if(Geom::CubicBezier const *la = dynamic_cast<Geom::CubicBezier const*>(ca))
+                    {
+                        Geom::CubicBezier const *lb = dynamic_cast<Geom::CubicBezier const*>(cb);
+                        if (!Geom::are_near((*la)[0],(*lb)[0], eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                        if (!Geom::are_near((*la)[1],(*lb)[1], eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different 1st control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                        if (!Geom::are_near((*la)[2],(*lb)[2], eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different 2nd control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[2][Geom::X], (*la)[2][Geom::Y], (*lb)[2][Geom::X], (*lb)[2][Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                        if (!Geom::are_near((*la)[3],(*lb)[3], eps)) {
+                            char temp[200];
+                            sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la)[3][Geom::X], (*la)[3][Geom::Y], (*lb)[3][Geom::X], (*lb)[3][Geom::Y], i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        char temp[200];
+                        sprintf(temp, "Unknown curve type: %s, subpath: %u, segment: %u", typeid(*ca).name(), i, j);
+                        TS_FAIL(temp);
+                    }
+                }
+                else // not same type
+                {
+                    if(Geom::LineSegment const *la = dynamic_cast<Geom::LineSegment const*>(ca))
+                    {
+                        if (Geom::HLineSegment const *lb = dynamic_cast<Geom::HLineSegment const*>(cb)) {
+                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            char temp[200];
+                            sprintf(temp, "A LineSegment and an HLineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
+                            TS_TRACE(temp);
+                        } else if (Geom::VLineSegment const *lb = dynamic_cast<Geom::VLineSegment const*>(cb)) {
+                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            char temp[200];
+                            sprintf(temp, "A LineSegment and a VLineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
+                            TS_TRACE(temp);
+                        } else {
+                            char temp[200];
+                            sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);
+                            TS_FAIL(temp);
+                        }
+                    }
+                    else if(Geom::LineSegment const *lb = dynamic_cast<Geom::LineSegment const*>(cb))
+                    {
+                        if (Geom::HLineSegment const *la = dynamic_cast<Geom::HLineSegment const*>(ca)) {
+                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            char temp[200];
+                            sprintf(temp, "An HLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
+                            TS_TRACE(temp);
+                        } else if (Geom::VLineSegment const *la = dynamic_cast<Geom::VLineSegment const*>(ca)) {
+                            if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) {
+                                char temp[200];
+                                sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], i, j);
+                                TS_FAIL(temp);
+                                return false;
+                            }
+                            char temp[200];
+                            sprintf(temp, "A VLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", i, j);
+                            TS_TRACE(temp);
+                        } else {
+                            char temp[200];
+                            sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);
+                            TS_FAIL(temp);
+                            return false;
+                        }
+                    } else {
+                        char temp[200];
+                        sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), i, j);
+                        TS_FAIL(temp);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+};
+
+
+/*
+  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 :