blob: 2aa06a75db70acb16759f45a2cf5d2a5304564f3 [file] [log] [blame]
reed@android.com3abec1d2009-03-02 05:36:20 +00001#include "Test.h"
2#include "SkPath.h"
reed@google.com04863fa2011-05-15 04:08:24 +00003#include "SkParse.h"
reed@android.com60bc6d52010-02-11 11:09:39 +00004#include "SkSize.h"
reed@android.com3abec1d2009-03-02 05:36:20 +00005
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +00006static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
7 for (int i = 0; i < 2; ++i) {
8 SkPath::Iter iter(path, (bool)i);
9 SkPoint mv;
10 SkPoint pts[4];
11 SkPath::Verb v;
12 int nMT = 0;
13 int nCL = 0;
14 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
15 switch (v) {
16 case SkPath::kMove_Verb:
17 mv = pts[0];
18 ++nMT;
19 break;
20 case SkPath::kClose_Verb:
21 REPORTER_ASSERT(reporter, mv == pts[0]);
22 ++nCL;
23 break;
24 default:
25 break;
26 }
27 }
28 // if we force a close on the interator we should have a close
29 // for every moveTo
30 REPORTER_ASSERT(reporter, !i || nMT == nCL);
31 }
32}
33
34static void test_close(skiatest::Reporter* reporter) {
35 SkPath closePt;
36 closePt.moveTo(0, 0);
37 closePt.close();
38 check_close(reporter, closePt);
39
40 SkPath openPt;
41 openPt.moveTo(0, 0);
42 check_close(reporter, openPt);
43
44 SkPath empty;
45 check_close(reporter, empty);
46 empty.close();
47 check_close(reporter, empty);
48
49 SkPath rect;
50 rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
51 check_close(reporter, rect);
52 rect.close();
53 check_close(reporter, rect);
54
55 SkPath quad;
56 quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
57 check_close(reporter, quad);
58 quad.close();
59 check_close(reporter, quad);
60
61 SkPath cubic;
62 quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
63 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
64 check_close(reporter, cubic);
65 cubic.close();
66 check_close(reporter, cubic);
67
68 SkPath line;
69 line.moveTo(SK_Scalar1, SK_Scalar1);
70 line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
71 check_close(reporter, line);
72 line.close();
73 check_close(reporter, line);
74
75 SkPath rect2;
76 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
77 rect2.close();
78 rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
79 check_close(reporter, rect2);
80 rect2.close();
81 check_close(reporter, rect2);
82
83 SkPath oval3;
84 oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
85 oval3.close();
86 oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
87 check_close(reporter, oval3);
88 oval3.close();
89 check_close(reporter, oval3);
90
91 SkPath moves;
92 moves.moveTo(SK_Scalar1, SK_Scalar1);
93 moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
94 moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
95 moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
96 check_close(reporter, moves);
97}
98
reed@google.com7c424812011-05-15 04:38:34 +000099static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
100 SkPath::Convexity expected) {
101 SkPath::Convexity c = SkPath::ComputeConvexity(path);
102 REPORTER_ASSERT(reporter, c == expected);
103}
104
105static void test_convexity2(skiatest::Reporter* reporter) {
106 SkPath pt;
107 pt.moveTo(0, 0);
108 pt.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000109 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000110
111 SkPath line;
112 line.moveTo(12, 20);
113 line.lineTo(-12, -20);
114 line.close();
reed@google.comb54455e2011-05-16 14:16:04 +0000115 check_convexity(reporter, pt, SkPath::kConvex_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000116
117 SkPath triLeft;
118 triLeft.moveTo(0, 0);
119 triLeft.lineTo(1, 0);
120 triLeft.lineTo(1, 1);
121 triLeft.close();
122 check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
123
124 SkPath triRight;
125 triRight.moveTo(0, 0);
126 triRight.lineTo(-1, 0);
127 triRight.lineTo(1, 1);
128 triRight.close();
129 check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
130
131 SkPath square;
132 square.moveTo(0, 0);
133 square.lineTo(1, 0);
134 square.lineTo(1, 1);
135 square.lineTo(0, 1);
136 square.close();
137 check_convexity(reporter, square, SkPath::kConvex_Convexity);
138
139 SkPath redundantSquare;
140 redundantSquare.moveTo(0, 0);
141 redundantSquare.lineTo(0, 0);
142 redundantSquare.lineTo(0, 0);
143 redundantSquare.lineTo(1, 0);
144 redundantSquare.lineTo(1, 0);
145 redundantSquare.lineTo(1, 0);
146 redundantSquare.lineTo(1, 1);
147 redundantSquare.lineTo(1, 1);
148 redundantSquare.lineTo(1, 1);
149 redundantSquare.lineTo(0, 1);
150 redundantSquare.lineTo(0, 1);
151 redundantSquare.lineTo(0, 1);
152 redundantSquare.close();
153 check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
154
155 SkPath bowTie;
156 bowTie.moveTo(0, 0);
157 bowTie.lineTo(0, 0);
158 bowTie.lineTo(0, 0);
159 bowTie.lineTo(1, 1);
160 bowTie.lineTo(1, 1);
161 bowTie.lineTo(1, 1);
162 bowTie.lineTo(1, 0);
163 bowTie.lineTo(1, 0);
164 bowTie.lineTo(1, 0);
165 bowTie.lineTo(0, 1);
166 bowTie.lineTo(0, 1);
167 bowTie.lineTo(0, 1);
168 bowTie.close();
169 check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
170
171 SkPath spiral;
172 spiral.moveTo(0, 0);
epoger@google.com2047f002011-05-17 17:36:59 +0000173 spiral.lineTo(100, 0);
174 spiral.lineTo(100, 100);
175 spiral.lineTo(0, 100);
176 spiral.lineTo(0, 50);
177 spiral.lineTo(50, 50);
178 spiral.lineTo(50, 75);
reed@google.com7c424812011-05-15 04:38:34 +0000179 spiral.close();
reed@google.com85b6e392011-05-15 20:25:17 +0000180 check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
reed@google.com7c424812011-05-15 04:38:34 +0000181
182 SkPath dent;
epoger@google.com1f753992011-05-18 20:23:30 +0000183 dent.moveTo(SkIntToScalar(0), SkIntToScalar(0));
184 dent.lineTo(SkIntToScalar(100), SkIntToScalar(100));
185 dent.lineTo(SkIntToScalar(0), SkIntToScalar(100));
186 dent.lineTo(SkIntToScalar(-50), SkIntToScalar(200));
187 dent.lineTo(SkIntToScalar(-200), SkIntToScalar(100));
reed@google.com7c424812011-05-15 04:38:34 +0000188 dent.close();
189 check_convexity(reporter, dent, SkPath::kConcave_Convexity);
190}
191
reed@android.com6b82d1a2009-06-03 02:35:01 +0000192static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
193 const SkRect& bounds) {
194 REPORTER_ASSERT(reporter, p.isConvex());
195 REPORTER_ASSERT(reporter, p.getBounds() == bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000196
reed@android.com6b82d1a2009-06-03 02:35:01 +0000197 SkPath p2(p);
198 REPORTER_ASSERT(reporter, p2.isConvex());
199 REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
200
201 SkPath other;
202 other.swap(p2);
203 REPORTER_ASSERT(reporter, other.isConvex());
204 REPORTER_ASSERT(reporter, other.getBounds() == bounds);
205}
206
reed@google.com04863fa2011-05-15 04:08:24 +0000207static void setFromString(SkPath* path, const char str[]) {
208 bool first = true;
209 while (str) {
210 SkScalar x, y;
211 str = SkParse::FindScalar(str, &x);
212 if (NULL == str) {
213 break;
214 }
215 str = SkParse::FindScalar(str, &y);
216 SkASSERT(str);
217 if (first) {
218 path->moveTo(x, y);
219 first = false;
220 } else {
221 path->lineTo(x, y);
222 }
223 }
224}
225
226static void test_convexity(skiatest::Reporter* reporter) {
reed@google.com04863fa2011-05-15 04:08:24 +0000227 static const SkPath::Convexity C = SkPath::kConcave_Convexity;
228 static const SkPath::Convexity V = SkPath::kConvex_Convexity;
229
230 SkPath path;
231
reed@google.comb54455e2011-05-16 14:16:04 +0000232 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
reed@google.com04863fa2011-05-15 04:08:24 +0000233 path.addCircle(0, 0, 10);
234 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
235 path.addCircle(0, 0, 10); // 2nd circle
236 REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
237 path.reset();
238 path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction);
239 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
240 path.reset();
241 path.addRect(0, 0, 10, 10, SkPath::kCW_Direction);
242 REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
243
244 static const struct {
245 const char* fPathStr;
246 SkPath::Convexity fExpectedConvexity;
247 } gRec[] = {
reed@google.comb54455e2011-05-16 14:16:04 +0000248 { "", SkPath::kConvex_Convexity },
249 { "0 0", SkPath::kConvex_Convexity },
250 { "0 0 10 10", SkPath::kConvex_Convexity },
reed@google.com85b6e392011-05-15 20:25:17 +0000251 { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
reed@google.com04863fa2011-05-15 04:08:24 +0000252 { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
253 { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
254 { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
255 { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
256 };
257
258 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
259 SkPath path;
260 setFromString(&path, gRec[i].fPathStr);
261 SkPath::Convexity c = SkPath::ComputeConvexity(path);
262 REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
263 }
264}
265
caryclark@google.comf1316942011-07-26 19:54:45 +0000266// Simple isRect test is inline TestPath, below.
267// test_isRect provides more extensive testing.
268static void test_isRect(skiatest::Reporter* reporter) {
269 // passing tests (all moveTo / lineTo...
270 SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
271 SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
272 SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
273 SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
274 SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
275 SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
276 SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
277 SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
278 SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
279 SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
280 {1, 0}, {.5f, 0}};
281 SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
282 {0, 1}, {0, .5f}};
283 SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
284 SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
285 SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
286
287 // failing tests
288 SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
289 SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
290 SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
291 SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
292 SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
293 SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
294 SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
295 SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
296
297 // failing, no close
298 SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
299 SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
300
301 size_t testLen[] = {
302 sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
303 sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
304 sizeof(rd), sizeof(re),
305 sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
306 sizeof(f7), sizeof(f8),
307 sizeof(c1), sizeof(c2)
308 };
309 SkPoint* tests[] = {
310 r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
311 f1, f2, f3, f4, f5, f6, f7, f8,
312 c1, c2
313 };
314 SkPoint* lastPass = re;
315 SkPoint* lastClose = f8;
316 bool fail = false;
317 bool close = true;
318 const size_t testCount = sizeof(tests) / sizeof(tests[0]);
319 size_t index;
320 for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
321 SkPath path;
322 path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
323 for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
324 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
325 }
326 if (close) {
327 path.close();
328 }
329 REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
330 if (tests[testIndex] == lastPass) {
331 fail = true;
332 }
333 if (tests[testIndex] == lastClose) {
334 close = false;
335 }
336 }
337
338 // fail, close then line
339 SkPath path1;
340 path1.moveTo(r1[0].fX, r1[0].fY);
341 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
342 path1.lineTo(r1[index].fX, r1[index].fY);
343 }
344 path1.close();
345 path1.lineTo(1, 0);
346 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
347
348 // fail, move in the middle
349 path1.reset();
350 path1.moveTo(r1[0].fX, r1[0].fY);
351 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
352 if (index == 2) {
353 path1.moveTo(1, .5f);
354 }
355 path1.lineTo(r1[index].fX, r1[index].fY);
356 }
357 path1.close();
358 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
359
360 // fail, move on the edge
361 path1.reset();
362 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
363 path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
364 path1.lineTo(r1[index].fX, r1[index].fY);
365 }
366 path1.close();
367 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
368
369 // fail, quad
370 path1.reset();
371 path1.moveTo(r1[0].fX, r1[0].fY);
372 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
373 if (index == 2) {
374 path1.quadTo(1, .5f, 1, .5f);
375 }
376 path1.lineTo(r1[index].fX, r1[index].fY);
377 }
378 path1.close();
379 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
380
381 // fail, cubic
382 path1.reset();
383 path1.moveTo(r1[0].fX, r1[0].fY);
384 for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
385 if (index == 2) {
386 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
387 }
388 path1.lineTo(r1[index].fX, r1[index].fY);
389 }
390 path1.close();
391 REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
392}
393
reed@google.com04863fa2011-05-15 04:08:24 +0000394void TestPath(skiatest::Reporter* reporter);
395void TestPath(skiatest::Reporter* reporter) {
reed@android.com60bc6d52010-02-11 11:09:39 +0000396 {
397 SkSize size;
398 size.fWidth = 3.4f;
399 size.width();
400 size = SkSize::Make(3,4);
401 SkISize isize = SkISize::Make(3,4);
402 }
403
404 SkTSize<SkScalar>::Make(3,4);
405
reed@android.com3abec1d2009-03-02 05:36:20 +0000406 SkPath p, p2;
407 SkRect bounds, bounds2;
reed@android.com80e39a72009-04-02 16:59:40 +0000408
reed@android.com3abec1d2009-03-02 05:36:20 +0000409 REPORTER_ASSERT(reporter, p.isEmpty());
reed@google.comb54455e2011-05-16 14:16:04 +0000410 REPORTER_ASSERT(reporter, p.isConvex());
reed@android.com3abec1d2009-03-02 05:36:20 +0000411 REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
412 REPORTER_ASSERT(reporter, !p.isInverseFillType());
413 REPORTER_ASSERT(reporter, p == p2);
414 REPORTER_ASSERT(reporter, !(p != p2));
415
reed@android.comd252db02009-04-01 18:31:44 +0000416 REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
reed@android.com80e39a72009-04-02 16:59:40 +0000417
reed@android.com3abec1d2009-03-02 05:36:20 +0000418 bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
reed@android.com6b82d1a2009-06-03 02:35:01 +0000419
reed@android.com6b82d1a2009-06-03 02:35:01 +0000420 p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
421 check_convex_bounds(reporter, p, bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000422
reed@android.com6b82d1a2009-06-03 02:35:01 +0000423 p.reset();
reed@android.com6b82d1a2009-06-03 02:35:01 +0000424 p.addOval(bounds);
425 check_convex_bounds(reporter, p, bounds);
reed@google.com62047cf2011-02-07 19:39:09 +0000426
reed@android.com6b82d1a2009-06-03 02:35:01 +0000427 p.reset();
reed@android.com3abec1d2009-03-02 05:36:20 +0000428 p.addRect(bounds);
reed@android.com6b82d1a2009-06-03 02:35:01 +0000429 check_convex_bounds(reporter, p, bounds);
reed@android.com3abec1d2009-03-02 05:36:20 +0000430
431 REPORTER_ASSERT(reporter, p != p2);
432 REPORTER_ASSERT(reporter, !(p == p2));
433
434 // does getPoints return the right result
435 REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
436 SkPoint pts[4];
437 int count = p.getPoints(pts, 4);
438 REPORTER_ASSERT(reporter, count == 4);
439 bounds2.set(pts, 4);
440 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +0000441
reed@android.com3abec1d2009-03-02 05:36:20 +0000442 bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
443 p.offset(SK_Scalar1*3, SK_Scalar1*4);
reed@android.comd252db02009-04-01 18:31:44 +0000444 REPORTER_ASSERT(reporter, bounds == p.getBounds());
reed@android.com3abec1d2009-03-02 05:36:20 +0000445
reed@android.com3abec1d2009-03-02 05:36:20 +0000446 REPORTER_ASSERT(reporter, p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +0000447 bounds2.setEmpty();
reed@android.com3abec1d2009-03-02 05:36:20 +0000448 REPORTER_ASSERT(reporter, p.isRect(&bounds2));
449 REPORTER_ASSERT(reporter, bounds == bounds2);
reed@android.com80e39a72009-04-02 16:59:40 +0000450
reed@android.com3abec1d2009-03-02 05:36:20 +0000451 // now force p to not be a rect
452 bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
453 p.addRect(bounds);
454 REPORTER_ASSERT(reporter, !p.isRect(NULL));
caryclark@google.comf1316942011-07-26 19:54:45 +0000455 test_isRect(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +0000456
457 SkPoint pt;
458
459 p.moveTo(SK_Scalar1, 0);
460 p.getLastPt(&pt);
461 REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
reed@google.com62047cf2011-02-07 19:39:09 +0000462
reed@google.com04863fa2011-05-15 04:08:24 +0000463 test_convexity(reporter);
reed@google.com7c424812011-05-15 04:38:34 +0000464 test_convexity2(reporter);
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000465 test_close(reporter);
reed@android.com3abec1d2009-03-02 05:36:20 +0000466}
467
468#include "TestClassDef.h"
469DEFINE_TESTCLASS("Path", PathTestClass, TestPath)