summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 8555d59)
raw | patch | inline | side by side (parent: 8555d59)
author | jaspervdg <jaspervdg@users.sourceforge.net> | |
Tue, 1 Jul 2008 18:18:32 +0000 (18:18 +0000) | ||
committer | jaspervdg <jaspervdg@users.sourceforge.net> | |
Tue, 1 Jul 2008 18:18:32 +0000 (18:18 +0000) |
build.xml | patch | blob | history | |
buildtool.cpp | patch | blob | history | |
src/display/bezier-utils-test.h | [new file with mode: 0644] | patch | blob |
src/helper/units-test.h | [new file with mode: 0644] | patch | blob |
src/xml/quote-test.h | patch | blob | history | |
src/xml/repr-action-test.h | patch | blob | history |
diff --git a/build.xml b/build.xml
index fdbc3c2e77e136146a6d6dd3807de38f271756e5..0355b98bc5049559d62f6adf5357b366b68fa25d 100644 (file)
--- a/build.xml
+++ b/build.xml
<property name="arch" value="mingw32-"/>
<property name="archutil" value=""/>
<property name="devlibs" location="c:/devlibs"/>
+ <property name="cxxtest" location="cxxtest"/>
<!-- -->
<!-- Use these settings for the cross compiler -->
</target>
+ <!--
+ ########################################################################
+ ## T A R G E T : C X X T E S T
+ ########################################################################
+ -->
+ <target name="cxxtest" depends="init"
+ description="generate test files" >
+
+ <!-- Generate CxxTest files -->
+ <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/test-src.cpp">
+ <fileset dir="${src}">
+ <include name="attributes-test.h"/>
+ <include name="color-profile-test.h"/>
+ <include name="dir-util-test.h"/>
+ <include name="extract-uri-test.h"/>
+ <include name="mod360-test.h"/>
+ <include name="round-test.h"/>
+ <include name="sp-gradient-test.h"/>
+ <include name="sp-style-elem-test.h"/>
+ <include name="syle-test.h"/>
+ <include name="test-helpers.h"/>
+ <include name="verbs-test.h"/>
+ </fileset>
+ </cxxtestpart>
+ <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/display/test-display.cpp">
+ <fileset dir="${src}/display">
+ <include name="bezier-utils-test.h"/>
+ </fileset>
+ </cxxtestpart>
+ <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/helper/test-helper.cpp">
+ <fileset dir="${src}/helper">
+ <include name="units-test.h"/>
+ </fileset>
+ </cxxtestpart>
+ <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/libnr/test-nr.cpp">
+ <fileset dir="${src}/libnr">
+ <include name="nr-types-test.h"/>
+ <include name="nr-translate-test.h"/>
+ <include name="nr-rotate-test.h"/>
+ <include name="nr-scale-test.h"/>
+ <include name="nr-point-fns-test.h"/>
+ <include name="nr-rotate-fns-test.h"/>
+ <include name="in-svg-plane-test.h"/>
+ <include name="nr-matrix-test.h"/>
+ </fileset>
+ </cxxtestpart>
+ <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/svg/test-svg.cpp">
+ <fileset dir="${src}/svg">
+ <include name="css-ostringstream-test.h"/>
+ <include name="stringstream-test.h"/>
+ <include name="svg-color-test.h"/>
+ <include name="svg-path-test.h"/>
+ </fileset>
+ </cxxtestpart>
+ <cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/xml/test-xml.cpp">
+ <fileset dir="${src}/xml">
+ <include name="repr-action-test.h"/>
+ <include name="quote-test.h"/>
+ </fileset>
+ </cxxtestpart>
+ <cxxtestroot command="python ${cxxtest}/cxxtestgen.py"
+ out="${src}/test-main.cpp"
+ template="${src}/selfname.tpl">
+ <fileset dir="${src}">
+ <include name="MultiPrinter.h"/>
+ <include name="PylogFormatter.h"/>
+ <include name="TRPIFormatter.h"/>
+ </fileset>
+ </cxxtestroot>
+ </target>
+
+
<!--
########################################################################
## T A R G E T : C O M P I L E
########################################################################
-->
- <target name="compile" depends="init"
+ <target name="compile" depends="cxxtest"
description="compile the source to .o" >
<!-- Compile from source to build -->
<exclude name="ast/.*"/>
<exclude name="bonobo/.*"/>
<exclude name="deptool.cpp"/>
- <exclude name="test-all.cpp"/>
+ <!--<exclude name="test-main.cpp"/>-->
+ <!--<exclude name="test-src.cpp"/>-->
<exclude name="display/testnr.cpp"/>
<exclude name="display/bezier-utils-test.cpp"/>
<exclude name="dom/work/.*"/>
<exclude name="extract-uri-test.cpp"/>
<exclude name="helper/units-test.cpp"/>
<!-- exclude name="inkview.cpp"/-->
- <exclude name="libnr/test-nr.cpp"/>
+ <!--<exclude name="libnr/test-nr.cpp"/>-->
<exclude name="libnr/test-nr-main.cpp"/>
<exclude name="libnr/testnr.cpp"/>
<exclude name="libnr/in-svg-plane-test.cpp"/>
<exclude name="trace/potrace/potest.cpp"/>
<exclude name="round-test.cpp"/>
<exclude name="sp-gradient-test.cpp"/>
+ <exclude name="style-test.cpp"/>
<exclude name="svg/ftos.cpp"/>
- <exclude name="svg/test-svg.cpp"/>
+ <!--<exclude name="svg/test-svg.cpp"/>-->
<exclude name="svg/test-svg-main.cpp"/>
+ <exclude name="svg/test-stubs.cpp"/>
<exclude name="utest/.*"/>
+ <exclude name="util/list-container-test.cpp"/>
<exclude name="widgets/test-widgets.cpp"/>
<exclude name="xml/quote-test.cpp"/>
<exclude name="xml/repr-action-test.cpp"/>
- <exclude name="xml/test-xml.cpp"/>
+ <!--<exclude name="xml/test-xml.cpp"/>-->
<exclude name="xml/test-xml-main.cpp"/>
<exclude name="io/streamtest.cpp"/>
<!--JABBER-->
${pcc.poppler}
-I${devlibs}/include/gc
${pcc.libwpg-0.1} ${pcc.libwpg-stream-0.1}
+ -I${cxxtest}
<!-- PERL -->
<!-- -Wno-comment -I${devlibs}/perl/lib/CORE -->
<!-- PYTHON -->
<exclude name="main.o"/>
<exclude name="winmain.o"/>
<exclude name="inkview.o"/>
+ <!-- CxxTest -->
+ <exclude name="obj/test-main.o"/>
+ <exclude name="obj/test-src.o"/>
+ <exclude name="obj/display/test-display.o"/>
+ <exclude name="obj/helper/test-helper.o"/>
+ <exclude name="obj/libnr/test-nr.o"/>
+ <exclude name="obj/svg/test-svg.o"/>
+ <exclude name="obj/xml/test-xml.o"/>
</fileset>
</staticlib>
</target>
+ <!--
+ ########################################################################
+ ## T A R G E T : L I N K C X X T E S T S
+ ########################################################################
+ -->
+ <target name="linkcxxtests" depends="lib"
+ description="link objects and library to create executable">
+
+ <link command="${arch}g++" out="${build}/cxxtests.exe"
+ strip="true" symfile="${build}/cxxtests.dbg"
+ stripcommand="${archutil}strip"
+ objcopycommand="${archutil}objcopy">
+ <flags>
+ </flags>
+ <fileset dir="${build}">
+ <include name="obj/test-main.o"/>
+ <include name="obj/test-src.o"/>
+ <include name="obj/display/test-display.o"/>
+ <include name="obj/helper/test-helper.o"/>
+ <include name="obj/libnr/test-nr.o"/>
+ <include name="obj/svg/test-svg.o"/>
+ <include name="obj/xml/test-xml.o"/>
+ <include name="libinkscape.a"/>
+ </fileset>
+ <libs>
+ -L${devlibs}/lib
+ ${pcl.poppler-cairo} ${pcl.poppler-glib} ${pcl.poppler}
+ ${pcl.gtkmm-2.4} ${pcl.pangoft2} ${pcl.gthread-2.0}
+ ${devlibs}/bin/libxml2.dll
+ ${devlibs}/bin/libxslt.dll
+ ${pcl.cairo} ${pcl.cairomm-1.0}
+ ${pcl.libwpg-0.1} ${pcl.libwpg-stream-0.1}
+ ${devlibs}/lib/iconv.lib
+ ${pcl.ImageMagick++}
+ ${pcl.fontconfig} ${pcl.freetype2}
+ -lssl -lcrypto
+ ${pcl.lcms}
+ ${pcl.gsl}
+ -lpng -ljpeg.dll -ltiff.dll -lpopt ${devlibs}/lib/zdll.lib
+ -lgc
+ -lws2_32 -lintl -lgdi32 -lcomdlg32 -lm
+ </libs>
+ </link>
+ </target>
+
+
<!--
########################################################################
## T A R G E T : D I S T
<delete file="build.dep"/>
<delete file="config.h"/>
+ <delete file="${src}/test-main.cpp"/>
+ <delete file="${src}/test-src.cpp"/>
+ <delete file="${src}/display/test-display.cpp"/>
+ <delete file="${src}/helper/test-helper.cpp"/>
+ <delete file="${src}/libnr/test-nr.cpp"/>
+ <delete file="${src}/svg/test-svg.cpp"/>
+ <delete file="${src}/xml/test-xml.cpp"/>
+
</target>
diff --git a/buildtool.cpp b/buildtool.cpp
index 852e651247c4548088af574053ddebe0e4781d4c..c3b0a29530cc9b8e079104e02b387fca4b9ac9b3 100644 (file)
--- a/buildtool.cpp
+++ b/buildtool.cpp
*
* Authors:
* Bob Jamison
+ * Jasper van de Gronde
*
* Copyright (C) 2006-2008 Bob Jamison
*
/**
*
*/
- String getDirectory()
+ String getDirectory() const
{ return directory; }
/**
/**
*
*/
- std::vector<String> getFiles()
+ std::vector<String> getFiles() const
{ return files; }
/**
/**
*
*/
- std::vector<String> getIncludes()
+ std::vector<String> getIncludes() const
{ return includes; }
/**
/**
*
*/
- std::vector<String> getExcludes()
+ std::vector<String> getExcludes() const
{ return excludes; }
/**
*
*/
- unsigned int size()
+ unsigned int size() const
{ return files.size(); }
/**
*
*/
- String operator[](int index)
+ String operator[](int index) const
{ return files[index]; }
/**
TASK_NONE,
TASK_CC,
TASK_COPY,
+ TASK_CXXTEST_PART,
+ TASK_CXXTEST_ROOT,
TASK_DELETE,
TASK_ECHO,
TASK_JAR,
};
+/**
+ * Generate CxxTest files
+ */
+class TaskCxxTestPart: public Task
+{
+public:
+
+ TaskCxxTestPart(MakeBase &par) : Task(par)
+ {
+ type = TASK_CXXTEST_PART;
+ name = "cxxtestpart";
+ }
+
+ virtual ~TaskCxxTestPart()
+ {}
+
+ virtual bool execute()
+ {
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = parent.eval(fileSet.getDirectory(), ".");
+
+ String fullDest = parent.resolve(parent.eval(destPathOpt, "."));
+ String cmd = parent.eval(commandOpt, "cxxtestgen.py");
+ cmd.append(" --part -o ");
+ cmd.append(fullDest);
+
+ unsigned int newFiles = 0;
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fileName = fileSet[i];
+ if (getSuffix(fileName) != "h")
+ continue;
+ String sourcePath;
+ if (fileSetDir.size()>0)
+ {
+ sourcePath.append(fileSetDir);
+ sourcePath.append("/");
+ }
+ sourcePath.append(fileName);
+ String fullSource = parent.resolve(sourcePath);
+
+ cmd.append(" ");
+ cmd.append(fullSource);
+ if (isNewerThan(fullSource, fullDest)) newFiles++;
+ }
+
+ if (newFiles>0) {
+ size_t const lastSlash = fullDest.find_last_of('/');
+ if (lastSlash != fullDest.npos) {
+ String directory(fullDest, 0, lastSlash);
+ if (!createDirectory(directory))
+ return false;
+ }
+
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("<cxxtestpart> problem: %s", errString.c_str());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ if (!parent.getAttribute(elem, "command", commandOpt))
+ return false;
+ if (!parent.getAttribute(elem, "out", destPathOpt))
+ return false;
+
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "fileset")
+ {
+ if (!parseFileSet(child, parent, fileSet))
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+
+ String commandOpt;
+ String destPathOpt;
+ FileSet fileSet;
+
+};
+
+
+/**
+ * Generate the CxxTest root file
+ */
+class TaskCxxTestRoot: public Task
+{
+public:
+
+ TaskCxxTestRoot(MakeBase &par) : Task(par)
+ {
+ type = TASK_CXXTEST_ROOT;
+ name = "cxxtestroot";
+ }
+
+ virtual ~TaskCxxTestRoot()
+ {}
+
+ virtual bool execute()
+ {
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = parent.eval(fileSet.getDirectory(), ".");
+ unsigned int newFiles = 0;
+
+ String fullDest = parent.resolve(parent.eval(destPathOpt, "."));
+ String cmd = parent.eval(commandOpt, "cxxtestgen.py");
+ cmd.append(" --root -o ");
+ cmd.append(fullDest);
+ String templateFile = parent.eval(templateFileOpt, "");
+ if (templateFile.size()>0) {
+ String fullTemplate = parent.resolve(templateFile);
+ cmd.append(" --template=");
+ cmd.append(fullTemplate);
+ if (isNewerThan(fullTemplate, fullDest)) newFiles++;
+ }
+
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fileName = fileSet[i];
+ if (getSuffix(fileName) != "h")
+ continue;
+ String sourcePath;
+ if (fileSetDir.size()>0)
+ {
+ sourcePath.append(fileSetDir);
+ sourcePath.append("/");
+ }
+ sourcePath.append(fileName);
+ String fullSource = parent.resolve(sourcePath);
+
+ cmd.append(" ");
+ cmd.append(fullSource);
+ if (isNewerThan(fullSource, fullDest)) newFiles++;
+ }
+
+ if (newFiles>0) {
+ size_t const lastSlash = fullDest.find_last_of('/');
+ if (lastSlash != fullDest.npos) {
+ String directory(fullDest, 0, lastSlash);
+ if (!createDirectory(directory))
+ return false;
+ }
+
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("<cxxtestroot> problem: %s", errString.c_str());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ if (!parent.getAttribute(elem, "command", commandOpt))
+ return false;
+ if (!parent.getAttribute(elem, "template", templateFileOpt))
+ return false;
+ if (!parent.getAttribute(elem, "out", destPathOpt))
+ return false;
+
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "fileset")
+ {
+ if (!parseFileSet(child, parent, fileSet))
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+
+ String commandOpt;
+ String templateFileOpt;
+ String destPathOpt;
+ FileSet fileSet;
+
+};
+
+
/**
*
*/
task = new TaskCC(parent);
else if (tagName == "copy")
task = new TaskCopy(parent);
+ else if (tagName == "cxxtestpart")
+ task = new TaskCxxTestPart(parent);
+ else if (tagName == "cxxtestroot")
+ task = new TaskCxxTestRoot(parent);
else if (tagName == "delete")
task = new TaskDelete(parent);
else if (tagName == "echo")
diff --git a/src/display/bezier-utils-test.h b/src/display/bezier-utils-test.h
--- /dev/null
@@ -0,0 +1,347 @@
+#include <cxxtest/TestSuite.h>\r
+\r
+#include <glib.h>\r
+#include <libnr/nr-macros.h> /* NR_DF_TEST_CLOSE */\r
+#include <sstream>\r
+\r
+/* mental disclaims all responsibility for this evil idea for testing\r
+ static functions. The main disadvantages are that we retain the\r
+ #define's and `using' directives of the included file. */\r
+#include "bezier-utils.cpp"\r
+\r
+using NR::Point;\r
+\r
+/* (Returns false if NaN encountered.) */\r
+static bool range_approx_equal(double const a[], double const b[], unsigned const len) {\r
+ for (unsigned i = 0; i < len; ++i) {\r
+ if (!( fabs( a[i] - b[i] ) < 1e-4 )) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+}\r
+\r
+static inline bool point_approx_equal(NR::Point const &a, NR::Point const &b, double const eps)\r
+{\r
+ using NR::X; using NR::Y;\r
+ return ( NR_DF_TEST_CLOSE(a[X], b[X], eps) &&\r
+ NR_DF_TEST_CLOSE(a[Y], b[Y], eps) );\r
+}\r
+\r
+static inline double square(double const x) {\r
+ return x * x;\r
+}\r
+\r
+/** Determine whether the found control points are the same as previously found on some developer's\r
+ machine. Doesn't call utest__fail, just writes a message to stdout for diagnostic purposes:\r
+ the most important test is that the root-mean-square of errors in the estimation are low rather\r
+ than that the control points found are the same.\r
+**/\r
+static void compare_ctlpts(Point const est_b[], Point const exp_est_b[])\r
+{\r
+ unsigned diff_mask = 0;\r
+ for (unsigned i = 0; i < 4; ++i) {\r
+ for (unsigned d = 0; d < 2; ++d) {\r
+ if ( fabs( est_b[i][d] - exp_est_b[i][d] ) > 1.1e-5 ) {\r
+ diff_mask |= 1 << ( i * 2 + d );\r
+ }\r
+ }\r
+ }\r
+ if ( diff_mask != 0 ) {\r
+ std::stringstream msg;\r
+ msg << "Got different control points from previously-coded (diffs=0x" << std::hex << diff_mask << "\n";\r
+ msg << " Previous:";\r
+ for (unsigned i = 0; i < 4; ++i) {\r
+ msg << " (" << exp_est_b[i][0] << ", " << exp_est_b[i][1] << ")"; // localizing ok\r
+ }\r
+ msg << "\n";\r
+ msg << " Found: ";\r
+ for (unsigned i = 0; i < 4; ++i) {\r
+ msg << " (" << est_b[i][0] << ", " << est_b[i][1] << ")"; // localizing ok\r
+ }\r
+ msg << "\n";\r
+ TS_WARN(msg.str().c_str());\r
+ }\r
+}\r
+\r
+static void compare_rms(Point const est_b[], double const t[], Point const d[], unsigned const n,\r
+ double const exp_rms_error)\r
+{\r
+ double sum_errsq = 0.0;\r
+ for (unsigned i = 0; i < n; ++i) {\r
+ Point const fit_pt = bezier_pt(3, est_b, t[i]);\r
+ Point const diff = fit_pt - d[i];\r
+ sum_errsq += dot(diff, diff);\r
+ }\r
+ double const rms_error = sqrt( sum_errsq / n );\r
+ TS_ASSERT_LESS_THAN_EQUALS( rms_error , exp_rms_error + 1.1e-6 );\r
+ if ( rms_error < exp_rms_error - 1.1e-6 ) {\r
+ /* The fitter code appears to have improved [or the floating point calculations differ\r
+ on this machine from the machine where exp_rms_error was calculated]. */\r
+ char msg[200];\r
+ sprintf(msg, "N.B. rms_error regression requirement can be decreased: have rms_error=%g.", rms_error); // localizing ok\r
+ TS_TRACE(msg);\r
+ }\r
+}\r
+\r
+class BezierUtilsTest : public CxxTest::TestSuite {\r
+public:\r
+ static Point const c[4];\r
+ static double const t[24];\r
+ static unsigned const n;\r
+ Point d[24];\r
+ static Point const src_b[4];\r
+ static Point const tHat1;\r
+ static Point const tHat2;\r
+\r
+ BezierUtilsTest()\r
+ {\r
+ /* Feed it some points that can be fit exactly with a single bezier segment, and see how\r
+ well it manages. */\r
+ for (unsigned i = 0; i < n; ++i) {\r
+ d[i] = bezier_pt(3, src_b, t[i]);\r
+ }\r
+ }\r
+ virtual ~BezierUtilsTest() {}\r
+\r
+ void testCopyWithoutNansOrAdjacentDuplicates()\r
+ {\r
+ NR::Point const src[] = {\r
+ Point(2., 3.),\r
+ Point(2., 3.),\r
+ Point(0., 0.),\r
+ Point(2., 3.),\r
+ Point(2., 3.),\r
+ Point(1., 9.),\r
+ Point(1., 9.)\r
+ };\r
+ Point const exp_dest[] = {\r
+ Point(2., 3.),\r
+ Point(0., 0.),\r
+ Point(2., 3.),\r
+ Point(1., 9.)\r
+ };\r
+ g_assert( G_N_ELEMENTS(src) == 7 );\r
+ Point dest[7];\r
+ struct tst {\r
+ unsigned src_ix0;\r
+ unsigned src_len;\r
+ unsigned exp_dest_ix0;\r
+ unsigned exp_dest_len;\r
+ } const test_data[] = {\r
+ /* src start ix, src len, exp_dest start ix, exp dest len */\r
+ {0, 0, 0, 0},\r
+ {2, 1, 1, 1},\r
+ {0, 1, 0, 1},\r
+ {0, 2, 0, 1},\r
+ {0, 3, 0, 2},\r
+ {1, 3, 0, 3},\r
+ {0, 5, 0, 3},\r
+ {0, 6, 0, 4},\r
+ {0, 7, 0, 4}\r
+ };\r
+ for (unsigned i = 0 ; i < G_N_ELEMENTS(test_data) ; ++i) {\r
+ tst const &t = test_data[i];\r
+ TS_ASSERT_EQUALS( t.exp_dest_len,\r
+ copy_without_nans_or_adjacent_duplicates(src + t.src_ix0,\r
+ t.src_len,\r
+ dest) );\r
+ TS_ASSERT_SAME_DATA(dest,\r
+ exp_dest + t.exp_dest_ix0,\r
+ t.exp_dest_len);\r
+ }\r
+ }\r
+\r
+ void testBezierPt1()\r
+ {\r
+ Point const a[] = {Point(2.0, 4.0),\r
+ Point(1.0, 8.0)};\r
+ TS_ASSERT_EQUALS( bezier_pt(1, a, 0.0) , a[0] );\r
+ TS_ASSERT_EQUALS( bezier_pt(1, a, 1.0) , a[1] );\r
+ TS_ASSERT_EQUALS( bezier_pt(1, a, 0.5) , Point(1.5, 6.0) );\r
+ double const t[] = {0.5, 0.25, 0.3, 0.6};\r
+ for (unsigned i = 0; i < G_N_ELEMENTS(t); ++i) {\r
+ double const ti = t[i], si = 1.0 - ti;\r
+ TS_ASSERT_EQUALS( bezier_pt(1, a, ti) , si * a[0] + ti * a[1] );\r
+ }\r
+ }\r
+\r
+ void testBezierPt2()\r
+ {\r
+ Point const b[] = {Point(1.0, 2.0),\r
+ Point(8.0, 4.0),\r
+ Point(3.0, 1.0)};\r
+ TS_ASSERT_EQUALS( bezier_pt(2, b, 0.0) , b[0] );\r
+ TS_ASSERT_EQUALS( bezier_pt(2, b, 1.0) , b[2] );\r
+ TS_ASSERT_EQUALS( bezier_pt(2, b, 0.5) , Point(5.0, 2.75) );\r
+ double const t[] = {0.5, 0.25, 0.3, 0.6};\r
+ for (unsigned i = 0; i < G_N_ELEMENTS(t); ++i) {\r
+ double const ti = t[i], si = 1.0 - ti;\r
+ Point const exp_pt( si*si * b[0] + 2*si*ti * b[1] + ti*ti * b[2] );\r
+ Point const pt(bezier_pt(2, b, ti));\r
+ TS_ASSERT(point_approx_equal(pt, exp_pt, 1e-11));\r
+ }\r
+ }\r
+\r
+ void testBezierPt3()\r
+ {\r
+ TS_ASSERT_EQUALS( bezier_pt(3, c, 0.0) , c[0] );\r
+ TS_ASSERT_EQUALS( bezier_pt(3, c, 1.0) , c[3] );\r
+ TS_ASSERT_EQUALS( bezier_pt(3, c, 0.5) , Point(4.0, 13.0/8.0) );\r
+ double const t[] = {0.5, 0.25, 0.3, 0.6};\r
+ for (unsigned i = 0; i < G_N_ELEMENTS(t); ++i) {\r
+ double const ti = t[i], si = 1.0 - ti;\r
+ TS_ASSERT( LInfty( bezier_pt(3, c, ti)\r
+ - ( si*si*si * c[0] +\r
+ 3*si*si*ti * c[1] +\r
+ 3*si*ti*ti * c[2] +\r
+ ti*ti*ti * c[3] ) )\r
+ < 1e-4 );\r
+ }\r
+ }\r
+\r
+ void testComputeMaxErrorRatio()\r
+ {\r
+ struct Err_tst {\r
+ Point pt;\r
+ double u;\r
+ double err;\r
+ } const err_tst[] = {\r
+ {c[0], 0.0, 0.0},\r
+ {Point(4.0, 13.0/8.0), 0.5, 0.0},\r
+ {Point(4.0, 2.0), 0.5, 9.0/64.0},\r
+ {Point(3.0, 2.0), 0.5, 1.0 + 9.0/64.0},\r
+ {Point(6.0, 2.0), 0.5, 4.0 + 9.0/64.0},\r
+ {c[3], 1.0, 0.0},\r
+ };\r
+ Point d[G_N_ELEMENTS(err_tst)];\r
+ double u[G_N_ELEMENTS(err_tst)];\r
+ for (unsigned i = 0; i < G_N_ELEMENTS(err_tst); ++i) {\r
+ Err_tst const &t = err_tst[i];\r
+ d[i] = t.pt;\r
+ u[i] = t.u;\r
+ }\r
+ g_assert( G_N_ELEMENTS(u) == G_N_ELEMENTS(d) );\r
+ unsigned max_ix = ~0u;\r
+ double const err_ratio = compute_max_error_ratio(d, u, G_N_ELEMENTS(d), c, 1.0, &max_ix);\r
+ TS_ASSERT_LESS_THAN( fabs( sqrt(err_tst[4].err) - err_ratio ) , 1e-12 );\r
+ TS_ASSERT_EQUALS( max_ix , 4 );\r
+ }\r
+\r
+ void testChordLengthParameterize()\r
+ {\r
+ /* n == 2 */\r
+ {\r
+ Point const d[] = {Point(2.9415, -5.8149),\r
+ Point(23.021, 4.9814)};\r
+ double u[G_N_ELEMENTS(d)];\r
+ double const exp_u[] = {0.0, 1.0};\r
+ g_assert( G_N_ELEMENTS(u) == G_N_ELEMENTS(exp_u) );\r
+ chord_length_parameterize(d, u, G_N_ELEMENTS(d));\r
+ TS_ASSERT_SAME_DATA(u, exp_u, G_N_ELEMENTS(exp_u));\r
+ }\r
+\r
+ /* Straight line. */\r
+ {\r
+ double const exp_u[] = {0.0, 0.1829, 0.2105, 0.2105, 0.619, 0.815, 0.999, 1.0};\r
+ unsigned const n = G_N_ELEMENTS(exp_u);\r
+ Point d[n];\r
+ double u[n];\r
+ Point const a(-23.985, 4.915), b(4.9127, 5.203);\r
+ for (unsigned i = 0; i < n; ++i) {\r
+ double bi = exp_u[i], ai = 1.0 - bi;\r
+ d[i] = ai * a + bi * b;\r
+ }\r
+ chord_length_parameterize(d, u, n);\r
+ TS_ASSERT(range_approx_equal(u, exp_u, n));\r
+ }\r
+ }\r
+\r
+ void testGenerateBezier()\r
+ {\r
+ Point est_b[4];\r
+ generate_bezier(est_b, d, t, n, tHat1, tHat2, 1.0);\r
+\r
+ compare_ctlpts(est_b, src_b);\r
+\r
+ /* We're being unfair here in using our t[] rather than best t[] for est_b: we\r
+ may over-estimate RMS of errors. */\r
+ compare_rms(est_b, t, d, n, 1e-8);\r
+ }\r
+\r
+ void testSpBezierFitCubicFull()\r
+ {\r
+ Point est_b[4];\r
+ int splitpoints[2];\r
+ gint const succ = sp_bezier_fit_cubic_full(est_b, splitpoints, d, n, tHat1, tHat2, square(1.2), 1);\r
+ TS_ASSERT_EQUALS( succ , 1 );\r
+\r
+ Point const exp_est_b[4] = {\r
+ Point(5.000000, -3.000000),\r
+ Point(7.5753, -0.4247),\r
+ Point(4.77533, 1.22467),\r
+ Point(3, 3)\r
+ };\r
+ compare_ctlpts(est_b, exp_est_b);\r
+\r
+ /* We're being unfair here in using our t[] rather than best t[] for est_b: we\r
+ may over-estimate RMS of errors. */\r
+ compare_rms(est_b, t, d, n, .307911);\r
+ }\r
+\r
+ void testSpBezierFitCubic()\r
+ {\r
+ Point est_b[4];\r
+ gint const succ = sp_bezier_fit_cubic(est_b, d, n, square(1.2));\r
+ TS_ASSERT_EQUALS( succ , 1 );\r
+\r
+ Point const exp_est_b[4] = {\r
+ Point(5.000000, -3.000000),\r
+ Point(7.57134, -0.423509),\r
+ Point(4.77929, 1.22426),\r
+ Point(3, 3)\r
+ };\r
+ compare_ctlpts(est_b, exp_est_b);\r
+\r
+#if 1 /* A change has been made to right_tangent. I believe that usually this change\r
+ will result in better fitting, but it won't do as well for this example where\r
+ we happen to be feeding a t=0.999 point to the fitter. */\r
+ TS_WARN("TODO: Update this test case for revised right_tangent implementation.");\r
+ /* In particular, have a test case to show whether the new implementation\r
+ really is likely to be better on average. */\r
+#else\r
+ /* We're being unfair here in using our t[] rather than best t[] for est_b: we\r
+ may over-estimate RMS of errors. */\r
+ compare_rms(est_b, t, d, n, .307983);\r
+#endif\r
+ }\r
+};\r
+\r
+// This is not very neat, but since we know this header is only included by the generated CxxTest file it shouldn't give any problems\r
+Point const BezierUtilsTest::c[4] = {\r
+ Point(1.0, 2.0),\r
+ Point(8.0, 4.0),\r
+ Point(3.0, 1.0),\r
+ Point(-2.0, -4.0)};\r
+double const BezierUtilsTest::t[24] = {\r
+ 0.0, .001, .03, .05, .09, .13, .18, .25, .29, .33, .39, .44,\r
+ .51, .57, .62, .69, .75, .81, .91, .93, .97, .98, .999, 1.0};\r
+unsigned const BezierUtilsTest::n = G_N_ELEMENTS(BezierUtilsTest::t);\r
+Point const BezierUtilsTest::src_b[4] = {\r
+ Point(5., -3.),\r
+ Point(8., 0.),\r
+ Point(4., 2.),\r
+ Point(3., 3.)};\r
+Point const BezierUtilsTest::tHat1(unit_vector( BezierUtilsTest::src_b[1] - BezierUtilsTest::src_b[0] ));\r
+Point const BezierUtilsTest::tHat2(unit_vector( BezierUtilsTest::src_b[2] - BezierUtilsTest::src_b[3] ));\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
diff --git a/src/helper/units-test.h b/src/helper/units-test.h
--- /dev/null
+++ b/src/helper/units-test.h
@@ -0,0 +1,88 @@
+#include <cxxtest/TestSuite.h>\r
+\r
+#include <helper/units.h>\r
+#include <glibmm/i18n.h>\r
+#include <math.h>\r
+\r
+\r
+/* N.B. Wrongly returns false if both near 0. (Not a problem for current users.) */\r
+static bool\r
+approx_equal(double const x, double const y)\r
+{\r
+ return fabs(x / y - 1) < 1e-15;\r
+}\r
+\r
+static double\r
+sp_units_get_points(double const x, SPUnit const &unit)\r
+{\r
+ SPUnit const &pt_unit = sp_unit_get_by_id(SP_UNIT_PT);\r
+ double const px = sp_units_get_pixels(x, unit);\r
+ return sp_pixels_get_units(px, pt_unit);\r
+}\r
+\r
+static double\r
+sp_points_get_units(double const pts, SPUnit const &unit)\r
+{\r
+ SPUnit const &pt_unit = sp_unit_get_by_id(SP_UNIT_PT);\r
+ double const px = sp_units_get_pixels(pts, pt_unit);\r
+ return sp_pixels_get_units(px, unit);\r
+}\r
+\r
+class UnitsTest : public CxxTest::TestSuite {\r
+public:\r
+\r
+ UnitsTest()\r
+ {\r
+ }\r
+ virtual ~UnitsTest() {}\r
+\r
+ void testConversions()\r
+ {\r
+ struct Case { double x; char const *abbr; double pts; } const tests[] = {\r
+ { 1.0, "pt", 1.0 },\r
+ { 5.0, "pt", 5.0 },\r
+ { 1.0, "in", 72.0 },\r
+ { 2.0, "in", 144.0 },\r
+ { 254., "mm", 720.0 },\r
+ { 254., "cm", 7200. },\r
+ { 254., "m", 720000. },\r
+ { 1.5, "mm", (15 * 72. / 254) }\r
+ };\r
+ for (unsigned i = 0; i < G_N_ELEMENTS(tests); ++i) {\r
+ Case const &c = tests[i];\r
+ SPUnit const &unit = *sp_unit_get_by_abbreviation(N_(c.abbr));\r
+\r
+ double const calc_pts = sp_units_get_points(c.x, unit);\r
+ TS_ASSERT(approx_equal(calc_pts, c.pts));\r
+\r
+ double const calc_x = sp_points_get_units(c.pts, unit);\r
+ TS_ASSERT(approx_equal(calc_x, c.x));\r
+\r
+ double tmp = c.x;\r
+ bool const converted_to_pts = sp_convert_distance(&tmp, &unit, SP_PS_UNIT);\r
+ TS_ASSERT(converted_to_pts);\r
+ TS_ASSERT(approx_equal(tmp, c.pts));\r
+\r
+ tmp = c.pts;\r
+ bool const converted_from_pts = sp_convert_distance(&tmp, SP_PS_UNIT, &unit);\r
+ TS_ASSERT(converted_from_pts);\r
+ TS_ASSERT(approx_equal(tmp, c.x));\r
+ }\r
+ }\r
+\r
+ void testUnitTable()\r
+ {\r
+ TS_ASSERT(sp_units_table_sane());\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
diff --git a/src/xml/quote-test.h b/src/xml/quote-test.h
index 39f7e616784d8d1b7dad48eb5e4c9a43d191a1fb..7f53728446500cf853c6c5b75a09d168df7ddf56 100644 (file)
--- a/src/xml/quote-test.h
+++ b/src/xml/quote-test.h
#include <cxxtest/TestSuite.h>
+/* Initial author: Peter Moulder.
+ Hereby released into the Public Domain. */
+
+#include <cstring>
+#include <functional>
+
+/* mental disclaims all responsibility for this evil idea for testing
+ static functions. The main disadvantages are that we retain any
+ #define's and `using' directives of the included file. */
+#include "quote.cpp"
+
+struct streq_free2 {
+ bool operator()(char const *exp, char *got) const
+ {
+ bool const ret = (strcmp(exp, got) == 0);
+ g_free(got);
+ return ret;
+ }
+};
+
class XmlQuoteTest : public CxxTest::TestSuite
{
public:
static XmlQuoteTest *createSuite() { return new XmlQuoteTest(); }
static void destroySuite( XmlQuoteTest *suite ) { delete suite; }
- void testFoo()
+ void testXmlQuotedStrlen()
+ {
+ struct {
+ char const *s;
+ size_t len;
+ } cases[] = {
+ {"", 0},
+ {"x", 1},
+ {"Foo", 3},
+ {"\"", 6},
+ {"&", 5},
+ {"<", 4},
+ {">", 4},
+ {"a\"b", 8},
+ {"a\"b<c>d;!@#$%^*(\\)?", 30}
+ };
+ for(size_t i=0; i<G_N_ELEMENTS(cases); i++) {
+ TS_ASSERT_EQUALS( xml_quoted_strlen(cases[i].s) , cases[i].len );
+ }
+ }
+
+ void testXmlQuoteStrdup()
{
+ struct {
+ char const * s1;
+ char const * s2;
+ } cases[] = {
+ {"", ""},
+ {"x", "x"},
+ {"Foo", "Foo"},
+ {"\"", """},
+ {"&", "&"},
+ {"<", "<"},
+ {">", ">"},
+ {"a\"b<c>d;!@#$%^*(\\)?", "a"b<c>d;!@#$%^*(\\)?"}
+ };
+ for(size_t i=0; i<G_N_ELEMENTS(cases); i++) {
+ TS_ASSERT_RELATION( streq_free2, cases[i].s2, xml_quote_strdup(cases[i].s1) );
+ }
}
};
index 10f7d52f13b03d11fd220dada9a86566d532cb8c..8fe1327aff29e11551f8f084c6e8f62ac03a7b83 100644 (file)
#include <cxxtest/TestSuite.h>
+#include <cstdlib>
+#include <glib.h>
+
+#include "repr.h"
+#include "event-fns.h"
+
+static void * const null_ptr = 0;
+
class XmlReprActionTest : public CxxTest::TestSuite
{
+ Inkscape::XML::Document *document;
+ Inkscape::XML::Node *a, *b, *c, *root;
+
public:
XmlReprActionTest()
{
+ Inkscape::GC::init();
+
+ document = sp_repr_document_new("test");
+ root = document->root();
+
+ a = document->createElement("a");
+ b = document->createElement("b");
+ c = document->createElement("c");
}
virtual ~XmlReprActionTest() {}
static XmlReprActionTest *createSuite() { return new XmlReprActionTest(); }
static void destroySuite( XmlReprActionTest *suite ) { delete suite; }
- void testFoo()
+ void testRollbackOfNodeAddition()
+ {
+ sp_repr_begin_transaction(document);
+ TS_ASSERT_EQUALS(sp_repr_parent(a) , null_ptr);
+
+ root->appendChild(a);
+ TS_ASSERT_EQUALS(sp_repr_parent(a) , root);
+
+ sp_repr_rollback(document);
+ TS_ASSERT_EQUALS(sp_repr_parent(a) , null_ptr);
+ }
+
+ void testRollbackOfNodeRemoval()
+ {
+ root->appendChild(a);
+
+ sp_repr_begin_transaction(document);
+ TS_ASSERT_EQUALS(sp_repr_parent(a) , root);
+
+ sp_repr_unparent(a);
+ TS_ASSERT_EQUALS(sp_repr_parent(a) , null_ptr);
+
+ sp_repr_rollback(document);
+ TS_ASSERT_EQUALS(sp_repr_parent(a) , root);
+
+ sp_repr_unparent(a);
+ }
+
+ void testRollbackOfNodeReordering()
{
+ root->appendChild(a);
+ root->appendChild(b);
+ root->appendChild(c);
+
+ sp_repr_begin_transaction(document);
+ TS_ASSERT_EQUALS(sp_repr_next(a) , b);
+ TS_ASSERT_EQUALS(sp_repr_next(b) , c);
+ TS_ASSERT_EQUALS(sp_repr_next(c) , null_ptr);
+
+ root->changeOrder(b, c);
+ TS_ASSERT_EQUALS(sp_repr_next(a) , c);
+ TS_ASSERT_EQUALS(sp_repr_next(b) , null_ptr);
+ TS_ASSERT_EQUALS(sp_repr_next(c) , b);
+
+ sp_repr_rollback(document);
+ TS_ASSERT_EQUALS(sp_repr_next(a) , b);
+ TS_ASSERT_EQUALS(sp_repr_next(b) , c);
+ TS_ASSERT_EQUALS(sp_repr_next(c) , null_ptr);
+
+ sp_repr_unparent(a);
+ sp_repr_unparent(b);
+ sp_repr_unparent(c);
}
+
+ /* lots more tests needed ... */
+
};
/*