diff options
| author | Jon A. Cruz <jon@joncruz.org> | 2008-07-05 05:11:28 +0000 |
|---|---|---|
| committer | joncruz <joncruz@users.sourceforge.net> | 2008-07-05 05:11:28 +0000 |
| commit | b4f137620ee8de6501e07ecbc1a8a6214662b6e8 (patch) | |
| tree | 2395c5abffb6b983fffb6029cfeaa5ce50f0745b /src/svg | |
| parent | Warning cleanup (diff) | |
| download | inkscape-b4f137620ee8de6501e07ecbc1a8a6214662b6e8.tar.gz inkscape-b4f137620ee8de6501e07ecbc1a8a6214662b6e8.zip | |
EOL fixups
(bzr r6164)
Diffstat (limited to 'src/svg')
| -rw-r--r-- | src/svg/svg-affine-test.h | 438 | ||||
| -rw-r--r-- | src/svg/svg-length-test.h | 92 | ||||
| -rw-r--r-- | src/svg/svg-path-test.h | 944 |
3 files changed, 737 insertions, 737 deletions
diff --git a/src/svg/svg-affine-test.h b/src/svg/svg-affine-test.h index 4180fcf3d..658968bce 100644 --- a/src/svg/svg-affine-test.h +++ b/src/svg/svg-affine-test.h @@ -1,219 +1,219 @@ -#include <cxxtest/TestSuite.h>
-
-#include "svg/svg.h"
-#include <2geom/matrix.h>
-#include <algorithm>
-#include <glib.h>
-#include <iostream>
-#include <math.h>
-#include <utility>
-
-struct streq_free2 {
- bool operator()(char const *exp, char const *got) const
- {
- bool const ret = (strcmp(exp, got) == 0);
- g_free((void*)got);
- return ret;
- }
-};
-
-struct approx_equal {
- bool operator()(Geom::Matrix const &ref, Geom::Matrix const &cm) const
- {
- double maxabsdiff = 0;
- for(size_t i=0; i<6; i++) {
- maxabsdiff = std::max(std::abs(ref[i]-cm[i]), maxabsdiff);
- }
- return maxabsdiff < 1e-14;
- }
-};
-
-class SvgAffineTest : public CxxTest::TestSuite
-{
-private:
- struct test_t {
- char const * str;
- Geom::Matrix matrix;
- };
- static test_t const read_matrix_tests[3];
- static test_t const read_translate_tests[3];
- static test_t const read_scale_tests[3];
- static test_t const read_rotate_tests[4];
- static test_t const read_skew_tests[3];
- static test_t const write_matrix_tests[2];
- static test_t const write_translate_tests[3];
- static test_t const write_scale_tests[2];
- static test_t const write_rotate_tests[2];
- static test_t const write_skew_tests[3];
-public:
- SvgAffineTest() {
- }
-
- void testReadIdentity()
- {
- char const* strs[] = {
- //0,
- "",
- "matrix(1,0,0,1,0,0)",
- "translate(0,0)",
- "scale(1,1)",
- "rotate(0,0,0)",
- "skewX(0)",
- "skewY(0)"};
- size_t n = G_N_ELEMENTS(strs);
- for(size_t i=0; i<n; i++) {
- Geom::Matrix cm;
- TSM_ASSERT(strs[i] , sp_svg_transform_read(strs[i], &cm));
- TSM_ASSERT_EQUALS(strs[i] , Geom::identity() , cm);
- }
- }
-
- void testWriteIdentity()
- {
- TS_ASSERT_EQUALS(sp_svg_transform_write(Geom::identity()) , (void*)0)
- }
-
- void testReadMatrix()
- {
- for(size_t i=0; i<G_N_ELEMENTS(read_matrix_tests); i++) {
- Geom::Matrix cm;
- TSM_ASSERT(read_matrix_tests[i].str , sp_svg_transform_read(read_matrix_tests[i].str, &cm));
- TSM_ASSERT_RELATION(read_matrix_tests[i].str , approx_equal , read_matrix_tests[i].matrix , cm);
- }
- }
-
- void testReadTranslate()
- {
- for(size_t i=0; i<G_N_ELEMENTS(read_translate_tests); i++) {
- Geom::Matrix cm;
- TSM_ASSERT(read_translate_tests[i].str , sp_svg_transform_read(read_translate_tests[i].str, &cm));
- TSM_ASSERT_RELATION(read_translate_tests[i].str , approx_equal , read_translate_tests[i].matrix , cm);
- }
- }
-
- void testReadScale()
- {
- for(size_t i=0; i<G_N_ELEMENTS(read_scale_tests); i++) {
- Geom::Matrix cm;
- TSM_ASSERT(read_scale_tests[i].str , sp_svg_transform_read(read_scale_tests[i].str, &cm));
- TSM_ASSERT_RELATION(read_scale_tests[i].str , approx_equal , read_scale_tests[i].matrix , cm);
- }
- }
-
- void testReadRotate()
- {
- for(size_t i=0; i<G_N_ELEMENTS(read_rotate_tests); i++) {
- Geom::Matrix cm;
- TSM_ASSERT(read_rotate_tests[i].str , sp_svg_transform_read(read_rotate_tests[i].str, &cm));
- TSM_ASSERT_RELATION(read_rotate_tests[i].str , approx_equal , read_rotate_tests[i].matrix , cm);
- }
- }
-
- void testReadSkew()
- {
- for(size_t i=0; i<G_N_ELEMENTS(read_skew_tests); i++) {
- Geom::Matrix cm;
- TSM_ASSERT(read_skew_tests[i].str , sp_svg_transform_read(read_skew_tests[i].str, &cm));
- TSM_ASSERT_RELATION(read_skew_tests[i].str , approx_equal , read_skew_tests[i].matrix , cm);
- }
- }
-
- void testWriteMatrix()
- {
- for(size_t i=0; i<G_N_ELEMENTS(write_matrix_tests); i++) {
- TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_matrix_tests[i].matrix) , write_matrix_tests[i].str);
- }
- }
-
- void testWriteTranslate()
- {
- for(size_t i=0; i<G_N_ELEMENTS(write_translate_tests); i++) {
- TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_translate_tests[i].matrix) , write_translate_tests[i].str);
- }
- }
-
- void testWriteScale()
- {
- for(size_t i=0; i<G_N_ELEMENTS(write_scale_tests); i++) {
- TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_scale_tests[i].matrix) , write_scale_tests[i].str);
- }
- }
-
- void testWriteRotate()
- {
- for(size_t i=0; i<G_N_ELEMENTS(write_rotate_tests); i++) {
- TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_rotate_tests[i].matrix) , write_rotate_tests[i].str);
- }
- }
-
- void testWriteSkew()
- {
- for(size_t i=0; i<G_N_ELEMENTS(write_skew_tests); i++) {
- TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_skew_tests[i].matrix) , write_skew_tests[i].str);
- }
- }
-
- void testReadConcatenation()
- {
- char const * str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)";
- Geom::Matrix ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica
- Geom::Matrix cm;
- TS_ASSERT(sp_svg_transform_read(str, &cm));
- TS_ASSERT_RELATION(approx_equal , ref , cm);
- }
-
- // TODO: Perhaps check faulty transforms (like "translate(1,2,3)", or "matrix(1,2,3,4,5)", or ...)
-};
-
-static double const DEGREE = M_PI/180.;
-
-SvgAffineTest::test_t const SvgAffineTest::read_matrix_tests[3] = {
- {"matrix(0,0,0,0,0,0)",Geom::Matrix(0,0,0,0,0,0)},
- {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)},
- {"matrix(1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}};
-SvgAffineTest::test_t const SvgAffineTest::read_translate_tests[3] = {
- {"translate(1)",Geom::Matrix(1,0,0,1,1,0)},
- {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)},
- {"translate(-1e3 .123e2)",Geom::Matrix(1,0,0,1,-1e3,.123e2)}};
-SvgAffineTest::test_t const SvgAffineTest::read_scale_tests[3] = {
- {"scale(2)",Geom::Matrix(2,0,0,2,0,0)},
- {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)},
- {"scale(0.1e-2 -.475e0)",Geom::Matrix(0.1e-2,0,0,-.475e0,0,0)}};
-SvgAffineTest::test_t const SvgAffineTest::read_rotate_tests[4] = {
- {"rotate(13 )",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
- {"rotate(-13)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),0,0)},
- {"rotate(373)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
- {"rotate(13,7,11)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),(1-cos(13.*DEGREE))*7+sin(13.*DEGREE)*11,(1-cos(13.*DEGREE))*11-sin(13.*DEGREE)*7)}};
-SvgAffineTest::test_t const SvgAffineTest::read_skew_tests[3] = {
- {"skewX( 30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)},
- {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)},
- {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}};
-
-SvgAffineTest::test_t const SvgAffineTest::write_matrix_tests[2] = {
- {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)},
- {"matrix(-1,2123,3,0.4,1e-8,1e20)",Geom::Matrix(-1,2.123e3,3+1e-14,0.4,1e-8,1e20)}};
-SvgAffineTest::test_t const SvgAffineTest::write_translate_tests[3] = {
- {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)},
- {"translate(1)",Geom::Matrix(1,0,0,1,1,0)},
- {"translate(-1345,0.123)",Geom::Matrix(1,0,0,1,-1.345e3,.123)}};
-SvgAffineTest::test_t const SvgAffineTest::write_scale_tests[2] = {
- {"scale(0)",Geom::Matrix(0,0,0,0,0,0)},
- {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}};
-SvgAffineTest::test_t const SvgAffineTest::write_rotate_tests[2] = {
- {"rotate(13)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
- {"rotate(-13,7,11)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),(1-cos(-13.*DEGREE))*7+sin(-13.*DEGREE)*11,(1-cos(-13.*DEGREE))*11-sin(-13.*DEGREE)*7)}};
-SvgAffineTest::test_t const SvgAffineTest::write_skew_tests[3] = {
- {"skewX(30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)},
- {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)},
- {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}};
-
-/*
- 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 :
+#include <cxxtest/TestSuite.h> + +#include "svg/svg.h" +#include <2geom/matrix.h> +#include <algorithm> +#include <glib.h> +#include <iostream> +#include <math.h> +#include <utility> + +struct streq_free2 { + bool operator()(char const *exp, char const *got) const + { + bool const ret = (strcmp(exp, got) == 0); + g_free((void*)got); + return ret; + } +}; + +struct approx_equal { + bool operator()(Geom::Matrix const &ref, Geom::Matrix const &cm) const + { + double maxabsdiff = 0; + for(size_t i=0; i<6; i++) { + maxabsdiff = std::max(std::abs(ref[i]-cm[i]), maxabsdiff); + } + return maxabsdiff < 1e-14; + } +}; + +class SvgAffineTest : public CxxTest::TestSuite +{ +private: + struct test_t { + char const * str; + Geom::Matrix matrix; + }; + static test_t const read_matrix_tests[3]; + static test_t const read_translate_tests[3]; + static test_t const read_scale_tests[3]; + static test_t const read_rotate_tests[4]; + static test_t const read_skew_tests[3]; + static test_t const write_matrix_tests[2]; + static test_t const write_translate_tests[3]; + static test_t const write_scale_tests[2]; + static test_t const write_rotate_tests[2]; + static test_t const write_skew_tests[3]; +public: + SvgAffineTest() { + } + + void testReadIdentity() + { + char const* strs[] = { + //0, + "", + "matrix(1,0,0,1,0,0)", + "translate(0,0)", + "scale(1,1)", + "rotate(0,0,0)", + "skewX(0)", + "skewY(0)"}; + size_t n = G_N_ELEMENTS(strs); + for(size_t i=0; i<n; i++) { + Geom::Matrix cm; + TSM_ASSERT(strs[i] , sp_svg_transform_read(strs[i], &cm)); + TSM_ASSERT_EQUALS(strs[i] , Geom::identity() , cm); + } + } + + void testWriteIdentity() + { + TS_ASSERT_EQUALS(sp_svg_transform_write(Geom::identity()) , (void*)0) + } + + void testReadMatrix() + { + for(size_t i=0; i<G_N_ELEMENTS(read_matrix_tests); i++) { + Geom::Matrix cm; + TSM_ASSERT(read_matrix_tests[i].str , sp_svg_transform_read(read_matrix_tests[i].str, &cm)); + TSM_ASSERT_RELATION(read_matrix_tests[i].str , approx_equal , read_matrix_tests[i].matrix , cm); + } + } + + void testReadTranslate() + { + for(size_t i=0; i<G_N_ELEMENTS(read_translate_tests); i++) { + Geom::Matrix cm; + TSM_ASSERT(read_translate_tests[i].str , sp_svg_transform_read(read_translate_tests[i].str, &cm)); + TSM_ASSERT_RELATION(read_translate_tests[i].str , approx_equal , read_translate_tests[i].matrix , cm); + } + } + + void testReadScale() + { + for(size_t i=0; i<G_N_ELEMENTS(read_scale_tests); i++) { + Geom::Matrix cm; + TSM_ASSERT(read_scale_tests[i].str , sp_svg_transform_read(read_scale_tests[i].str, &cm)); + TSM_ASSERT_RELATION(read_scale_tests[i].str , approx_equal , read_scale_tests[i].matrix , cm); + } + } + + void testReadRotate() + { + for(size_t i=0; i<G_N_ELEMENTS(read_rotate_tests); i++) { + Geom::Matrix cm; + TSM_ASSERT(read_rotate_tests[i].str , sp_svg_transform_read(read_rotate_tests[i].str, &cm)); + TSM_ASSERT_RELATION(read_rotate_tests[i].str , approx_equal , read_rotate_tests[i].matrix , cm); + } + } + + void testReadSkew() + { + for(size_t i=0; i<G_N_ELEMENTS(read_skew_tests); i++) { + Geom::Matrix cm; + TSM_ASSERT(read_skew_tests[i].str , sp_svg_transform_read(read_skew_tests[i].str, &cm)); + TSM_ASSERT_RELATION(read_skew_tests[i].str , approx_equal , read_skew_tests[i].matrix , cm); + } + } + + void testWriteMatrix() + { + for(size_t i=0; i<G_N_ELEMENTS(write_matrix_tests); i++) { + TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_matrix_tests[i].matrix) , write_matrix_tests[i].str); + } + } + + void testWriteTranslate() + { + for(size_t i=0; i<G_N_ELEMENTS(write_translate_tests); i++) { + TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_translate_tests[i].matrix) , write_translate_tests[i].str); + } + } + + void testWriteScale() + { + for(size_t i=0; i<G_N_ELEMENTS(write_scale_tests); i++) { + TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_scale_tests[i].matrix) , write_scale_tests[i].str); + } + } + + void testWriteRotate() + { + for(size_t i=0; i<G_N_ELEMENTS(write_rotate_tests); i++) { + TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_rotate_tests[i].matrix) , write_rotate_tests[i].str); + } + } + + void testWriteSkew() + { + for(size_t i=0; i<G_N_ELEMENTS(write_skew_tests); i++) { + TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_skew_tests[i].matrix) , write_skew_tests[i].str); + } + } + + void testReadConcatenation() + { + char const * str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)"; + Geom::Matrix ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica + Geom::Matrix cm; + TS_ASSERT(sp_svg_transform_read(str, &cm)); + TS_ASSERT_RELATION(approx_equal , ref , cm); + } + + // TODO: Perhaps check faulty transforms (like "translate(1,2,3)", or "matrix(1,2,3,4,5)", or ...) +}; + +static double const DEGREE = M_PI/180.; + +SvgAffineTest::test_t const SvgAffineTest::read_matrix_tests[3] = { + {"matrix(0,0,0,0,0,0)",Geom::Matrix(0,0,0,0,0,0)}, + {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, + {"matrix(1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}}; +SvgAffineTest::test_t const SvgAffineTest::read_translate_tests[3] = { + {"translate(1)",Geom::Matrix(1,0,0,1,1,0)}, + {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)}, + {"translate(-1e3 .123e2)",Geom::Matrix(1,0,0,1,-1e3,.123e2)}}; +SvgAffineTest::test_t const SvgAffineTest::read_scale_tests[3] = { + {"scale(2)",Geom::Matrix(2,0,0,2,0,0)}, + {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}, + {"scale(0.1e-2 -.475e0)",Geom::Matrix(0.1e-2,0,0,-.475e0,0,0)}}; +SvgAffineTest::test_t const SvgAffineTest::read_rotate_tests[4] = { + {"rotate(13 )",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, + {"rotate(-13)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),0,0)}, + {"rotate(373)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, + {"rotate(13,7,11)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),(1-cos(13.*DEGREE))*7+sin(13.*DEGREE)*11,(1-cos(13.*DEGREE))*11-sin(13.*DEGREE)*7)}}; +SvgAffineTest::test_t const SvgAffineTest::read_skew_tests[3] = { + {"skewX( 30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)}, + {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)}, + {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}}; + +SvgAffineTest::test_t const SvgAffineTest::write_matrix_tests[2] = { + {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, + {"matrix(-1,2123,3,0.4,1e-8,1e20)",Geom::Matrix(-1,2.123e3,3+1e-14,0.4,1e-8,1e20)}}; +SvgAffineTest::test_t const SvgAffineTest::write_translate_tests[3] = { + {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)}, + {"translate(1)",Geom::Matrix(1,0,0,1,1,0)}, + {"translate(-1345,0.123)",Geom::Matrix(1,0,0,1,-1.345e3,.123)}}; +SvgAffineTest::test_t const SvgAffineTest::write_scale_tests[2] = { + {"scale(0)",Geom::Matrix(0,0,0,0,0,0)}, + {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}}; +SvgAffineTest::test_t const SvgAffineTest::write_rotate_tests[2] = { + {"rotate(13)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, + {"rotate(-13,7,11)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),(1-cos(-13.*DEGREE))*7+sin(-13.*DEGREE)*11,(1-cos(-13.*DEGREE))*11-sin(-13.*DEGREE)*7)}}; +SvgAffineTest::test_t const SvgAffineTest::write_skew_tests[3] = { + {"skewX(30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)}, + {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)}, + {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}}; + +/* + 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 : diff --git a/src/svg/svg-length-test.h b/src/svg/svg-length-test.h index 0f628ae7c..f6c6cb4f6 100644 --- a/src/svg/svg-length-test.h +++ b/src/svg/svg-length-test.h @@ -1,46 +1,46 @@ -#include <cxxtest/TestSuite.h>
-
-#include "svg/svg-length.h"
-#include <glib.h>
-#include <utility>
-
-class SvgLengthTest : public CxxTest::TestSuite
-{
-private:
-public:
- SvgLengthTest() {
- }
-
- void testRead()
- {
- struct test_t {
- char const* str; float computed;
- test_t(char const* str, float computed) : str(str), computed(computed) {}
- };
- test_t tests[] = {
- test_t("0",0),
- test_t("1",1),
- test_t("1.00001",1.00001),
- test_t("1px",1),
- test_t(".1px",0.1)};
- size_t n = G_N_ELEMENTS(tests);
- for(size_t i=0; i<n; i++) {
- SVGLength l;
- TSM_ASSERT(tests[i].str , l.read(tests[i].str));
- TSM_ASSERT_EQUALS(tests[i].str , l.computed , tests[i].computed);
- }
- }
-
- // TODO: More tests
-};
-
-/*
- 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 :
+#include <cxxtest/TestSuite.h> + +#include "svg/svg-length.h" +#include <glib.h> +#include <utility> + +class SvgLengthTest : public CxxTest::TestSuite +{ +private: +public: + SvgLengthTest() { + } + + void testRead() + { + struct test_t { + char const* str; float computed; + test_t(char const* str, float computed) : str(str), computed(computed) {} + }; + test_t tests[] = { + test_t("0",0), + test_t("1",1), + test_t("1.00001",1.00001), + test_t("1px",1), + test_t(".1px",0.1)}; + size_t n = G_N_ELEMENTS(tests); + for(size_t i=0; i<n; i++) { + SVGLength l; + TSM_ASSERT(tests[i].str , l.read(tests[i].str)); + TSM_ASSERT_EQUALS(tests[i].str , l.computed , tests[i].computed); + } + } + + // TODO: More tests +}; + +/* + 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 : diff --git a/src/svg/svg-path-test.h b/src/svg/svg-path-test.h index 5247ace83..5e2038527 100644 --- a/src/svg/svg-path-test.h +++ b/src/svg/svg-path-test.h @@ -1,472 +1,472 @@ -#include <cxxtest/TestSuite.h>
-#include "libnr/n-art-bpath.h"
-#include "svg/svg.h"
-#include "2geom/coord.h"
-#include <string>
-#include <vector>
-#include <glib/gmem.h>
-
-class SvgPathTest : public CxxTest::TestSuite
-{
-private:
- std::vector<std::string> rectanglesAbsoluteClosed;
- std::vector<std::string> rectanglesRelativeClosed;
- std::vector<std::string> rectanglesAbsoluteOpen;
- std::vector<std::string> rectanglesRelativeOpen;
- NArtBpath rectangleBpath[5+1];
-public:
- SvgPathTest() {
- // Lots of ways to define the same rectangle
- rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 Z");
- 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");
- rectangleBpath[0].code = NR_MOVETO;
- rectangleBpath[0].x3 = 1;
- rectangleBpath[0].y3 = 2;
- rectangleBpath[1].code = NR_LINETO;
- rectangleBpath[1].x3 = 4;
- rectangleBpath[1].y3 = 2;
- rectangleBpath[2].code = NR_LINETO;
- rectangleBpath[2].x3 = 4;
- rectangleBpath[2].y3 = 8;
- rectangleBpath[3].code = NR_LINETO;
- rectangleBpath[3].x3 = 1;
- rectangleBpath[3].y3 = 8;
- rectangleBpath[4].code = NR_LINETO;
- rectangleBpath[4].x3 = 1;
- rectangleBpath[4].y3 = 2;
- rectangleBpath[5].code = NR_END;
- // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs
- }
-
- void testReadRectanglesAbsoluteClosed()
- {
- rectangleBpath[0].code = NR_MOVETO;
- for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {
- NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteClosed[i].c_str());
- TS_ASSERT(bpathEqual(bpath,rectangleBpath));
- g_free(bpath);
- }
- }
-
- void testReadRectanglesRelativeClosed()
- {
- rectangleBpath[0].code = NR_MOVETO;
- for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {
- NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeClosed[i].c_str());
- TS_ASSERT(bpathEqual(bpath,rectangleBpath));
- g_free(bpath);
- }
- }
-
- void testReadRectanglesAbsoluteOpen()
- {
- rectangleBpath[0].code = NR_MOVETO_OPEN;
- for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {
- NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteOpen[i].c_str());
- TS_ASSERT(bpathEqual(bpath,rectangleBpath));
- g_free(bpath);
- }
- }
-
- void testReadRectanglesRelativeOpen()
- {
- rectangleBpath[0].code = NR_MOVETO_OPEN;
- for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {
- NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeOpen[i].c_str());
- TS_ASSERT(bpathEqual(bpath,rectangleBpath));
- g_free(bpath);
- }
- }
-
- void testReadConcatenatedPaths()
- {
- NArtBpath bpath_good[4*5+1];
- for(size_t i=0; i<4; i++) {
- memcpy(bpath_good+i*5,rectangleBpath,sizeof(rectangleBpath[0])*5);
- }
- bpath_good[0*5].code = NR_MOVETO;
- bpath_good[1*5].code = NR_MOVETO_OPEN;
- bpath_good[2*5].code = NR_MOVETO;
- bpath_good[3*5].code = NR_MOVETO_OPEN;
- bpath_good[4*5].code = NR_END;
- for(size_t i=0; i<5; i++) {
- bpath_good[1*5+i].x3 += bpath_good[0*5+4].x3;
- bpath_good[1*5+i].y3 += bpath_good[0*5+4].y3;
- }
- for(size_t i=0; i<5; i++) {
- bpath_good[2*5+i].x3 += bpath_good[1*5+4].x3;
- bpath_good[2*5+i].y3 += bpath_good[1*5+4].y3;
- }
- std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
- NArtBpath * bpath = sp_svg_read_path(path_str.c_str());
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testReadZeroLengthSubpaths() {
- // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant
- NArtBpath bpath_good[8+1];
- bpath_good[0].code = NR_MOVETO_OPEN;
- bpath_good[0].x3 = bpath_good[0].y3 = 0;
- bpath_good[1].code = NR_MOVETO_OPEN;
- bpath_good[1].x3 = bpath_good[1].y3 = 1;
- bpath_good[2].code = NR_LINETO;
- bpath_good[2].x3 = bpath_good[2].y3 = 2;
- bpath_good[3].code = NR_MOVETO;
- bpath_good[3].x3 = bpath_good[3].y3 = 3;
- bpath_good[4].code = NR_MOVETO;
- bpath_good[4].x3 = bpath_good[4].y3 = 4;
- bpath_good[5].code = NR_LINETO;
- bpath_good[5].x3 = bpath_good[5].y3 = 5;
- bpath_good[6].code = NR_LINETO;
- bpath_good[6].x3 = bpath_good[6].y3 = 4;
- bpath_good[7].code = NR_MOVETO_OPEN;
- bpath_good[7].x3 = bpath_good[7].y3 = 6;
- bpath_good[8].code = NR_END;
- { // 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";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- { // 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";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- }
-
- void testReadImplicitMoveto() {
- NArtBpath bpath_good[6+1];
- bpath_good[0].code = NR_MOVETO;
- bpath_good[0].x3 = bpath_good[0].y3 = 1;
- bpath_good[1].code = NR_LINETO;
- bpath_good[1].x3 = bpath_good[1].y3 = 2;
- bpath_good[2].code = NR_LINETO;
- bpath_good[2].x3 = bpath_good[2].y3 = 1;
- bpath_good[3].code = NR_MOVETO;
- bpath_good[3].x3 = bpath_good[3].y3 = 1;
- bpath_good[4].code = NR_LINETO;
- bpath_good[4].x3 = bpath_good[4].y3 = 3;
- bpath_good[5].code = NR_LINETO;
- bpath_good[5].x3 = bpath_good[5].y3 = 1;
- bpath_good[6].code = NR_END;
- { // Test absolute version
- char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- { // Test relative version
- char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- }
-
- void testReadFloatingPoint() {
- NArtBpath bpath_good[5+1];
- bpath_good[0].code = NR_MOVETO;
- bpath_good[0].x3 = .01;
- bpath_good[0].y3 = .02;
- bpath_good[1].code = NR_LINETO;
- bpath_good[1].x3 = .04;
- bpath_good[1].y3 = .02;
- bpath_good[2].code = NR_LINETO;
- bpath_good[2].x3 = 1.5;
- bpath_good[2].y3 = 1.6;
- bpath_good[3].code = NR_LINETO;
- bpath_good[3].x3 = .01;
- bpath_good[3].y3 = .08;
- bpath_good[4].code = NR_LINETO;
- bpath_good[4].x3 = .01;
- bpath_good[4].y3 = .02;
- bpath_good[5].code = NR_END;
- { // Test decimals
- char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- { // 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";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- }
-
- void testReadImplicitSeparation() {
- // Coordinates need not be separated by whitespace if they can still be read unambiguously
- NArtBpath bpath_good[5+1];
- bpath_good[0].code = NR_MOVETO;
- bpath_good[0].x3 = .1;
- bpath_good[0].y3 = .2;
- bpath_good[1].code = NR_LINETO;
- bpath_good[1].x3 = .4;
- bpath_good[1].y3 = .2;
- bpath_good[2].code = NR_LINETO;
- bpath_good[2].x3 = .4;
- bpath_good[2].y3 = .8;
- bpath_good[3].code = NR_LINETO;
- bpath_good[3].x3 = .1;
- bpath_good[3].y3 = .8;
- bpath_good[4].code = NR_LINETO;
- bpath_good[4].x3 = .1;
- bpath_good[4].y3 = .2;
- bpath_good[5].code = NR_END;
- { // Test absolute
- char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- { // Test relative
- char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";
- NArtBpath * bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
- }
-
- void testReadErrorMisplacedCharacter() {
- char const * path_str;
- NArtBpath * bpath;
- NArtBpath * bpath_good = rectangleBpath;
- bpath_good[0].code = NR_MOVETO;
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testReadErrorUnrecognizedCharacter() {
- char const * path_str;
- NArtBpath * bpath;
- NArtBpath * bpath_good = rectangleBpath;
- bpath_good[0].code = NR_MOVETO;
- // Unrecognized character
- path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // Unrecognized character
- path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testReadErrorTypo() {
- char const * path_str;
- NArtBpath * bpath;
- NArtBpath * bpath_good = rectangleBpath;
- bpath_good[0].code = NR_MOVETO;
- // Typo
- path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
-
- bpath_good[0].code = NR_MOVETO_OPEN;
- // Typo
- path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testReadErrorIllformedNumbers() {
- char const * path_str;
- NArtBpath * bpath;
- NArtBpath * bpath_good = rectangleBpath;
- bpath_good[0].code = NR_MOVETO;
- // Double exponent
- path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // Double sign
- path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // Double sign
- path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // No digit
- path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // No digit
- path_str = "M 1,2 4,2 4,8 1,8 z m .,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // No digit
- path_str = "M 1,2 4,2 4,8 1,8 z m +,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // No digit
- path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testReadErrorJunk() {
- char const * path_str;
- NArtBpath * bpath;
- NArtBpath * bpath_good = rectangleBpath;
- bpath_good[0].code = NR_MOVETO;
- // 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";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testReadErrorStopReading() {
- char const * path_str;
- NArtBpath * bpath;
- NArtBpath * bpath_good = rectangleBpath;
- bpath_good[0].code = NR_MOVETO;
- // Unrecognized parameter
- path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // Invalid parameter
- path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- // Illformed parameter
- path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
-
- bpath_good[0].code = NR_MOVETO_OPEN;
- // "Third" parameter
- path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";
- bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,bpath_good));
- g_free(bpath);
- }
-
- void testRoundTrip() {
- // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.
- NArtBpath * bpath;
- NArtBpath * new_bpath;
- char * path_str;
- // Rectangle (closed)
- bpath = sp_svg_read_path(rectanglesAbsoluteClosed[0].c_str());
- path_str = sp_svg_write_path(bpath);
- new_bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,new_bpath));
- g_free(bpath); g_free(path_str); g_free(new_bpath);
- // Rectangle (open)
- bpath = sp_svg_read_path(rectanglesAbsoluteOpen[0].c_str());
- path_str = sp_svg_write_path(bpath);
- new_bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,new_bpath));
- g_free(bpath); g_free(path_str); g_free(new_bpath);
- // Concatenated rectangles
- bpath = sp_svg_read_path((rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0]).c_str());
- path_str = sp_svg_write_path(bpath);
- new_bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,new_bpath));
- g_free(bpath); g_free(path_str); g_free(new_bpath);
- // Zero-length subpaths
- bpath = sp_svg_read_path("M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6");
- path_str = sp_svg_write_path(bpath);
- new_bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath,new_bpath));
- g_free(bpath); g_free(path_str); g_free(new_bpath);
- // Floating-point
- bpath = sp_svg_read_path("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");
- path_str = sp_svg_write_path(bpath);
- new_bpath = sp_svg_read_path(path_str);
- TS_ASSERT(bpathEqual(bpath, new_bpath, 1e-17));
- g_free(bpath); g_free(path_str); g_free(new_bpath);
- }
-
-private:
- bool bpathEqual(NArtBpath const * a, NArtBpath const * b, double eps = 1e-16) {
- while(a->code != NR_END && b->code == a->code) {
- switch(a->code) {
- case NR_MOVETO:
- case NR_MOVETO_OPEN:
- case NR_LINETO:
- if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;
- break;
- case NR_CURVETO:
- if (!Geom::are_near(a->x1,b->x1, eps) || !Geom::are_near(a->y1,b->y1, eps)) return false;
- if (!Geom::are_near(a->x2,b->x2, eps) || !Geom::are_near(a->y2,b->y2, eps)) return false;
- if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;
- break;
- default:
- TS_FAIL("Unknown path code!");
- }
- a++;
- b++;
- }
- return a->code == b->code;
- }
-};
-
-
-/*
- 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 :
+#include <cxxtest/TestSuite.h> +#include "libnr/n-art-bpath.h" +#include "svg/svg.h" +#include "2geom/coord.h" +#include <string> +#include <vector> +#include <glib/gmem.h> + +class SvgPathTest : public CxxTest::TestSuite +{ +private: + std::vector<std::string> rectanglesAbsoluteClosed; + std::vector<std::string> rectanglesRelativeClosed; + std::vector<std::string> rectanglesAbsoluteOpen; + std::vector<std::string> rectanglesRelativeOpen; + NArtBpath rectangleBpath[5+1]; +public: + SvgPathTest() { + // Lots of ways to define the same rectangle + rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 Z"); + 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"); + rectangleBpath[0].code = NR_MOVETO; + rectangleBpath[0].x3 = 1; + rectangleBpath[0].y3 = 2; + rectangleBpath[1].code = NR_LINETO; + rectangleBpath[1].x3 = 4; + rectangleBpath[1].y3 = 2; + rectangleBpath[2].code = NR_LINETO; + rectangleBpath[2].x3 = 4; + rectangleBpath[2].y3 = 8; + rectangleBpath[3].code = NR_LINETO; + rectangleBpath[3].x3 = 1; + rectangleBpath[3].y3 = 8; + rectangleBpath[4].code = NR_LINETO; + rectangleBpath[4].x3 = 1; + rectangleBpath[4].y3 = 2; + rectangleBpath[5].code = NR_END; + // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs + } + + void testReadRectanglesAbsoluteClosed() + { + rectangleBpath[0].code = NR_MOVETO; + for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) { + NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteClosed[i].c_str()); + TS_ASSERT(bpathEqual(bpath,rectangleBpath)); + g_free(bpath); + } + } + + void testReadRectanglesRelativeClosed() + { + rectangleBpath[0].code = NR_MOVETO; + for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) { + NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeClosed[i].c_str()); + TS_ASSERT(bpathEqual(bpath,rectangleBpath)); + g_free(bpath); + } + } + + void testReadRectanglesAbsoluteOpen() + { + rectangleBpath[0].code = NR_MOVETO_OPEN; + for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) { + NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteOpen[i].c_str()); + TS_ASSERT(bpathEqual(bpath,rectangleBpath)); + g_free(bpath); + } + } + + void testReadRectanglesRelativeOpen() + { + rectangleBpath[0].code = NR_MOVETO_OPEN; + for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) { + NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeOpen[i].c_str()); + TS_ASSERT(bpathEqual(bpath,rectangleBpath)); + g_free(bpath); + } + } + + void testReadConcatenatedPaths() + { + NArtBpath bpath_good[4*5+1]; + for(size_t i=0; i<4; i++) { + memcpy(bpath_good+i*5,rectangleBpath,sizeof(rectangleBpath[0])*5); + } + bpath_good[0*5].code = NR_MOVETO; + bpath_good[1*5].code = NR_MOVETO_OPEN; + bpath_good[2*5].code = NR_MOVETO; + bpath_good[3*5].code = NR_MOVETO_OPEN; + bpath_good[4*5].code = NR_END; + for(size_t i=0; i<5; i++) { + bpath_good[1*5+i].x3 += bpath_good[0*5+4].x3; + bpath_good[1*5+i].y3 += bpath_good[0*5+4].y3; + } + for(size_t i=0; i<5; i++) { + bpath_good[2*5+i].x3 += bpath_good[1*5+4].x3; + bpath_good[2*5+i].y3 += bpath_good[1*5+4].y3; + } + std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0]; + NArtBpath * bpath = sp_svg_read_path(path_str.c_str()); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testReadZeroLengthSubpaths() { + // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant + NArtBpath bpath_good[8+1]; + bpath_good[0].code = NR_MOVETO_OPEN; + bpath_good[0].x3 = bpath_good[0].y3 = 0; + bpath_good[1].code = NR_MOVETO_OPEN; + bpath_good[1].x3 = bpath_good[1].y3 = 1; + bpath_good[2].code = NR_LINETO; + bpath_good[2].x3 = bpath_good[2].y3 = 2; + bpath_good[3].code = NR_MOVETO; + bpath_good[3].x3 = bpath_good[3].y3 = 3; + bpath_good[4].code = NR_MOVETO; + bpath_good[4].x3 = bpath_good[4].y3 = 4; + bpath_good[5].code = NR_LINETO; + bpath_good[5].x3 = bpath_good[5].y3 = 5; + bpath_good[6].code = NR_LINETO; + bpath_good[6].x3 = bpath_good[6].y3 = 4; + bpath_good[7].code = NR_MOVETO_OPEN; + bpath_good[7].x3 = bpath_good[7].y3 = 6; + bpath_good[8].code = NR_END; + { // 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"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + { // 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"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + } + + void testReadImplicitMoveto() { + NArtBpath bpath_good[6+1]; + bpath_good[0].code = NR_MOVETO; + bpath_good[0].x3 = bpath_good[0].y3 = 1; + bpath_good[1].code = NR_LINETO; + bpath_good[1].x3 = bpath_good[1].y3 = 2; + bpath_good[2].code = NR_LINETO; + bpath_good[2].x3 = bpath_good[2].y3 = 1; + bpath_good[3].code = NR_MOVETO; + bpath_good[3].x3 = bpath_good[3].y3 = 1; + bpath_good[4].code = NR_LINETO; + bpath_good[4].x3 = bpath_good[4].y3 = 3; + bpath_good[5].code = NR_LINETO; + bpath_good[5].x3 = bpath_good[5].y3 = 1; + bpath_good[6].code = NR_END; + { // Test absolute version + char const * path_str = "M 1,1 L 2,2 z L 3,3 z"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + { // Test relative version + char const * path_str = "M 1,1 L 2,2 z L 3,3 z"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + } + + void testReadFloatingPoint() { + NArtBpath bpath_good[5+1]; + bpath_good[0].code = NR_MOVETO; + bpath_good[0].x3 = .01; + bpath_good[0].y3 = .02; + bpath_good[1].code = NR_LINETO; + bpath_good[1].x3 = .04; + bpath_good[1].y3 = .02; + bpath_good[2].code = NR_LINETO; + bpath_good[2].x3 = 1.5; + bpath_good[2].y3 = 1.6; + bpath_good[3].code = NR_LINETO; + bpath_good[3].x3 = .01; + bpath_good[3].y3 = .08; + bpath_good[4].code = NR_LINETO; + bpath_good[4].x3 = .01; + bpath_good[4].y3 = .02; + bpath_good[5].code = NR_END; + { // Test decimals + char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + { // 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"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + } + + void testReadImplicitSeparation() { + // Coordinates need not be separated by whitespace if they can still be read unambiguously + NArtBpath bpath_good[5+1]; + bpath_good[0].code = NR_MOVETO; + bpath_good[0].x3 = .1; + bpath_good[0].y3 = .2; + bpath_good[1].code = NR_LINETO; + bpath_good[1].x3 = .4; + bpath_good[1].y3 = .2; + bpath_good[2].code = NR_LINETO; + bpath_good[2].x3 = .4; + bpath_good[2].y3 = .8; + bpath_good[3].code = NR_LINETO; + bpath_good[3].x3 = .1; + bpath_good[3].y3 = .8; + bpath_good[4].code = NR_LINETO; + bpath_good[4].x3 = .1; + bpath_good[4].y3 = .2; + bpath_good[5].code = NR_END; + { // Test absolute + char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + { // Test relative + char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z"; + NArtBpath * bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + } + + void testReadErrorMisplacedCharacter() { + char const * path_str; + NArtBpath * bpath; + NArtBpath * bpath_good = rectangleBpath; + bpath_good[0].code = NR_MOVETO; + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testReadErrorUnrecognizedCharacter() { + char const * path_str; + NArtBpath * bpath; + NArtBpath * bpath_good = rectangleBpath; + bpath_good[0].code = NR_MOVETO; + // Unrecognized character + path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // Unrecognized character + path_str = "M 1,2 4,2 4,8 1,8 z m &13,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testReadErrorTypo() { + char const * path_str; + NArtBpath * bpath; + NArtBpath * bpath_good = rectangleBpath; + bpath_good[0].code = NR_MOVETO; + // Typo + path_str = "M 1,2 4,2 4,8 1,8 z j 13,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + + bpath_good[0].code = NR_MOVETO_OPEN; + // Typo + path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testReadErrorIllformedNumbers() { + char const * path_str; + NArtBpath * bpath; + NArtBpath * bpath_good = rectangleBpath; + bpath_good[0].code = NR_MOVETO; + // Double exponent + path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // Double sign + path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // Double sign + path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m .,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m +,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testReadErrorJunk() { + char const * path_str; + NArtBpath * bpath; + NArtBpath * bpath_good = rectangleBpath; + bpath_good[0].code = NR_MOVETO; + // 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"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testReadErrorStopReading() { + char const * path_str; + NArtBpath * bpath; + NArtBpath * bpath_good = rectangleBpath; + bpath_good[0].code = NR_MOVETO; + // Unrecognized parameter + path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // Invalid parameter + path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + // Illformed parameter + path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + + bpath_good[0].code = NR_MOVETO_OPEN; + // "Third" parameter + path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23"; + bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,bpath_good)); + g_free(bpath); + } + + void testRoundTrip() { + // This is the easiest way to (also) test writing path data, as a path can be written in more than one way. + NArtBpath * bpath; + NArtBpath * new_bpath; + char * path_str; + // Rectangle (closed) + bpath = sp_svg_read_path(rectanglesAbsoluteClosed[0].c_str()); + path_str = sp_svg_write_path(bpath); + new_bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,new_bpath)); + g_free(bpath); g_free(path_str); g_free(new_bpath); + // Rectangle (open) + bpath = sp_svg_read_path(rectanglesAbsoluteOpen[0].c_str()); + path_str = sp_svg_write_path(bpath); + new_bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,new_bpath)); + g_free(bpath); g_free(path_str); g_free(new_bpath); + // Concatenated rectangles + bpath = sp_svg_read_path((rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0]).c_str()); + path_str = sp_svg_write_path(bpath); + new_bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,new_bpath)); + g_free(bpath); g_free(path_str); g_free(new_bpath); + // Zero-length subpaths + bpath = sp_svg_read_path("M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6"); + path_str = sp_svg_write_path(bpath); + new_bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath,new_bpath)); + g_free(bpath); g_free(path_str); g_free(new_bpath); + // Floating-point + bpath = sp_svg_read_path("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"); + path_str = sp_svg_write_path(bpath); + new_bpath = sp_svg_read_path(path_str); + TS_ASSERT(bpathEqual(bpath, new_bpath, 1e-17)); + g_free(bpath); g_free(path_str); g_free(new_bpath); + } + +private: + bool bpathEqual(NArtBpath const * a, NArtBpath const * b, double eps = 1e-16) { + while(a->code != NR_END && b->code == a->code) { + switch(a->code) { + case NR_MOVETO: + case NR_MOVETO_OPEN: + case NR_LINETO: + if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false; + break; + case NR_CURVETO: + if (!Geom::are_near(a->x1,b->x1, eps) || !Geom::are_near(a->y1,b->y1, eps)) return false; + if (!Geom::are_near(a->x2,b->x2, eps) || !Geom::are_near(a->y2,b->y2, eps)) return false; + if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false; + break; + default: + TS_FAIL("Unknown path code!"); + } + a++; + b++; + } + return a->code == b->code; + } +}; + + +/* + 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 : |
