Code

Tests for nr-compose, as well as updated tests for svg-affine and svg-length.
[inkscape.git] / src / svg / svg-affine-test.h
1 #include <cxxtest/TestSuite.h>
3 #include "svg/svg.h"
4 #include <2geom/matrix.h>
5 #include <algorithm>
6 #include <glib.h>
7 #include <iostream>
8 #include <math.h>
9 #include <utility>
11 struct streq_free2 {
12     bool operator()(char const *exp, char const *got) const
13     {
14         bool const ret = (strcmp(exp, got) == 0);
15         g_free((void*)got);
16         return ret;
17     }
18 };
20 struct approx_equal {
21     bool operator()(Geom::Matrix const &ref, Geom::Matrix const &cm) const
22     {
23         double maxabsdiff = 0;
24         for(size_t i=0; i<6; i++) {
25             maxabsdiff = std::max(std::abs(ref[i]-cm[i]), maxabsdiff);
26         }
27         return maxabsdiff < 1e-14;
28     }
29 };
31 class SvgAffineTest : public CxxTest::TestSuite
32 {
33 private:
34     struct test_t {
35         char const * str;
36         Geom::Matrix matrix;
37     };
38     static test_t const read_matrix_tests[3];
39     static test_t const read_translate_tests[3];
40     static test_t const read_scale_tests[3];
41     static test_t const read_rotate_tests[4];
42     static test_t const read_skew_tests[3];
43     static char const * read_fail_tests[25];
44     static test_t const write_matrix_tests[2];
45     static test_t const write_translate_tests[3];
46     static test_t const write_scale_tests[2];
47     static test_t const write_rotate_tests[2];
48     static test_t const write_skew_tests[3];
49 public:
50     SvgAffineTest() {
51     }
53     void testReadIdentity()
54     {
55         char const* strs[] = {
56             //0,
57             "",
58             "matrix(1,0,0,1,0,0)",
59             "translate(0,0)",
60             "scale(1,1)",
61             "rotate(0,0,0)",
62             "skewX(0)",
63             "skewY(0)"};
64         size_t n = G_N_ELEMENTS(strs);
65         for(size_t i=0; i<n; i++) {
66             Geom::Matrix cm;
67             TSM_ASSERT(strs[i] , sp_svg_transform_read(strs[i], &cm));
68             TSM_ASSERT_EQUALS(strs[i] , Geom::identity() , cm);
69         }
70     }
72     void testWriteIdentity()
73     {
74         TS_ASSERT_EQUALS(sp_svg_transform_write(Geom::identity()) , (void*)0)
75     }
77     void testReadMatrix()
78     {
79         for(size_t i=0; i<G_N_ELEMENTS(read_matrix_tests); i++) {
80             Geom::Matrix cm;
81             TSM_ASSERT(read_matrix_tests[i].str , sp_svg_transform_read(read_matrix_tests[i].str, &cm));
82             TSM_ASSERT_RELATION(read_matrix_tests[i].str , approx_equal , read_matrix_tests[i].matrix , cm);
83         }
84     }
86     void testReadTranslate()
87     {
88         for(size_t i=0; i<G_N_ELEMENTS(read_translate_tests); i++) {
89             Geom::Matrix cm;
90             TSM_ASSERT(read_translate_tests[i].str , sp_svg_transform_read(read_translate_tests[i].str, &cm));
91             TSM_ASSERT_RELATION(read_translate_tests[i].str , approx_equal , read_translate_tests[i].matrix , cm);
92         }
93     }
95     void testReadScale()
96     {
97         for(size_t i=0; i<G_N_ELEMENTS(read_scale_tests); i++) {
98             Geom::Matrix cm;
99             TSM_ASSERT(read_scale_tests[i].str , sp_svg_transform_read(read_scale_tests[i].str, &cm));
100             TSM_ASSERT_RELATION(read_scale_tests[i].str , approx_equal , read_scale_tests[i].matrix , cm);
101         }
102     }
104     void testReadRotate()
105     {
106         for(size_t i=0; i<G_N_ELEMENTS(read_rotate_tests); i++) {
107             Geom::Matrix cm;
108             TSM_ASSERT(read_rotate_tests[i].str , sp_svg_transform_read(read_rotate_tests[i].str, &cm));
109             TSM_ASSERT_RELATION(read_rotate_tests[i].str , approx_equal , read_rotate_tests[i].matrix , cm);
110         }
111     }
113     void testReadSkew()
114     {
115         for(size_t i=0; i<G_N_ELEMENTS(read_skew_tests); i++) {
116             Geom::Matrix cm;
117             TSM_ASSERT(read_skew_tests[i].str , sp_svg_transform_read(read_skew_tests[i].str, &cm));
118             TSM_ASSERT_RELATION(read_skew_tests[i].str , approx_equal , read_skew_tests[i].matrix , cm);
119         }
120     }
122     void testWriteMatrix()
123     {
124         for(size_t i=0; i<G_N_ELEMENTS(write_matrix_tests); i++) {
125             TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_matrix_tests[i].matrix) , write_matrix_tests[i].str);
126         }
127     }
129     void testWriteTranslate()
130     {
131         for(size_t i=0; i<G_N_ELEMENTS(write_translate_tests); i++) {
132             TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_translate_tests[i].matrix) , write_translate_tests[i].str);
133         }
134     }
136     void testWriteScale()
137     {
138         for(size_t i=0; i<G_N_ELEMENTS(write_scale_tests); i++) {
139             TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_scale_tests[i].matrix) , write_scale_tests[i].str);
140         }
141     }
143     void testWriteRotate()
144     {
145         for(size_t i=0; i<G_N_ELEMENTS(write_rotate_tests); i++) {
146             TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_rotate_tests[i].matrix) , write_rotate_tests[i].str);
147         }
148     }
150     void testWriteSkew()
151     {
152         for(size_t i=0; i<G_N_ELEMENTS(write_skew_tests); i++) {
153             TS_ASSERT_RELATION(streq_free2 , sp_svg_transform_write(write_skew_tests[i].matrix) , write_skew_tests[i].str);
154         }
155     }
157     void testReadConcatenation()
158     {
159         // NOTE: According to the SVG specification (see the syntax at http://www.w3.org/TR/SVG/coords.html#TransformAttribute
160         //       there should be 1 or more comma-wsp sequences between transforms... This doesn't make sense and it seems
161         //       likely that instead of a + they meant a ? (zero or one comma-wsp sequences).
162         char const * str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)";
163         Geom::Matrix ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica
164         Geom::Matrix cm;
165         TS_ASSERT(sp_svg_transform_read(str, &cm));
166         TS_ASSERT_RELATION(approx_equal , ref , cm);
167     }
169     void testReadFailures()
170     {
171         for(size_t i=0; i<G_N_ELEMENTS(read_fail_tests); i++) {
172             Geom::Matrix cm;
173             TSM_ASSERT(read_fail_tests[i] , !sp_svg_transform_read(read_fail_tests[i], &cm));
174         }
175     }
176 };
178 static double const DEGREE = M_PI/180.;
180 SvgAffineTest::test_t const SvgAffineTest::read_matrix_tests[3] = {
181     {"matrix(0,0,0,0,0,0)",Geom::Matrix(0,0,0,0,0,0)},
182     {" matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)},
183     {"matrix (1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}};
184 SvgAffineTest::test_t const SvgAffineTest::read_translate_tests[3] = {
185     {"translate(1)",Geom::Matrix(1,0,0,1,1,0)},
186     {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)},
187     {"translate(-1e3 .123e2)",Geom::Matrix(1,0,0,1,-1e3,.123e2)}};
188 SvgAffineTest::test_t const SvgAffineTest::read_scale_tests[3] = {
189     {"scale(2)",Geom::Matrix(2,0,0,2,0,0)},
190     {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)},
191     {"scale(0.1e-2 -.475e0)",Geom::Matrix(0.1e-2,0,0,-.475e0,0,0)}};
192 SvgAffineTest::test_t const SvgAffineTest::read_rotate_tests[4] = {
193     {"rotate(13 )",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
194     {"rotate(-13)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),0,0)},
195     {"rotate(373)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
196     {"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)}};
197 SvgAffineTest::test_t const SvgAffineTest::read_skew_tests[3] = {
198     {"skewX( 30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)},
199     {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)},
200     {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}};
201 char const * SvgAffineTest::read_fail_tests[25] = {
202     "matrix((1,2,3,4,5,6)",
203     "matrix((1,2,3,4,5,6))",
204     "matrix(1,2,3,4,5,6))",
205     "matrix(,1,2,3,4,5,6)",
206     "matrix(1,2,3,4,5,6,)",
207     "matrix(1,2,3,4,5,)",
208     "matrix(1,2,3,4,5)",
209     "matrix(1,2,3,4,5e6-3)", // Here numbers HAVE to be separated by a comma-wsp sequence
210     "matrix(1,2,3,4,5e6.3)", // Here numbers HAVE to be separated by a comma-wsp sequence
211     "translate()",
212     "translate(,)",
213     "translate(1,)",
214     "translate(1,6,)",
215     "translate(1,6,0)",
216     "scale()",
217     "scale(1,6,2)",
218     "rotate()",
219     "rotate(1,6)",
220     "rotate(1,6,)",
221     "rotate(1,6,3,4)",
222     "skewX()",
223     "skewX(-)",
224     "skewX(.)",
225     "skewY(,)",
226     "skewY(1,2)"};
228 SvgAffineTest::test_t const SvgAffineTest::write_matrix_tests[2] = {
229     {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)},
230     {"matrix(-1,2123,3,0.4,1e-8,1e20)",Geom::Matrix(-1,2.123e3,3+1e-14,0.4,1e-8,1e20)}};
231 SvgAffineTest::test_t const SvgAffineTest::write_translate_tests[3] = {
232     {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)},
233     {"translate(1)",Geom::Matrix(1,0,0,1,1,0)},
234     {"translate(-1345,0.123)",Geom::Matrix(1,0,0,1,-1.345e3,.123)}};
235 SvgAffineTest::test_t const SvgAffineTest::write_scale_tests[2] = {
236     {"scale(0)",Geom::Matrix(0,0,0,0,0,0)},
237     {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}};
238 SvgAffineTest::test_t const SvgAffineTest::write_rotate_tests[2] = {
239     {"rotate(13)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)},
240     {"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)}};
241 SvgAffineTest::test_t const SvgAffineTest::write_skew_tests[3] = {
242     {"skewX(30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)},
243     {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)},
244     {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}};
246 /*
247   Local Variables:
248   mode:c++
249   c-file-style:"stroustrup"
250   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
251   indent-tabs-mode:nil
252   fill-column:99
253   End:
254 */
255 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :