1jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
2
3describe('PathKit\'s Path Behavior', function() {
4    // Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
5    var PathKit = null;
6    const LoadPathKit = new Promise(function(resolve, reject) {
7        if (PathKit) {
8            resolve();
9        } else {
10            PathKitInit({
11                locateFile: (file) => '/pathkit/'+file,
12            }).ready().then((_PathKit) => {
13                PathKit = _PathKit;
14                resolve();
15            });
16        }
17    });
18
19    describe('Basic Path Features', function() {
20        function drawSimplePath() {
21            let path = PathKit.NewPath();
22            path.moveTo(0, 0);
23            path.lineTo(10, 0);
24            path.lineTo(10, 10);
25            path.close();
26            return path;
27        }
28
29        it('supports.equals()', function(done) {
30            LoadPathKit.then(catchException(done, () => {
31                let path = drawSimplePath();
32                let otherPath = drawSimplePath();
33                let blank = PathKit.NewPath();
34
35                expect(path.equals(path)).toBe(true);
36                expect(otherPath.equals(path)).toBe(true);
37                expect(path.equals(otherPath)).toBe(true);
38
39                expect(path.equals(blank)).toBe(false);
40                expect(otherPath.equals(blank)).toBe(false);
41                expect(blank.equals(path)).toBe(false);
42                expect(blank.equals(otherPath)).toBe(false);
43
44                path.delete();
45                otherPath.delete();
46                blank.delete();
47                done();
48            }));
49        });
50
51        it('has a copy constructor', function(done) {
52            LoadPathKit.then(catchException(done, () => {
53                let orig = drawSimplePath();
54                let copy = new PathKit.SkPath(orig);
55
56                expect(orig.toSVGString()).toEqual(copy.toSVGString());
57                expect(orig.equals(copy)).toBe(true);
58
59                orig.delete();
60                copy.delete();
61                done();
62            }));
63        });
64
65        it('has a copy method', function(done) {
66            LoadPathKit.then(catchException(done, () => {
67                let orig = drawSimplePath();
68                let copy = orig.copy();
69
70                expect(orig.toSVGString()).toEqual(copy.toSVGString());
71                expect(orig.equals(copy)).toBe(true);
72
73                orig.delete();
74                copy.delete();
75                done();
76            }));
77        });
78
79        it('can create a copy with MakePath', function(done) {
80            LoadPathKit.then(catchException(done, () => {
81                let orig = drawSimplePath();
82                let copy = PathKit.NewPath(orig);
83
84                expect(orig.toSVGString()).toEqual(copy.toSVGString());
85                expect(orig.equals(copy)).toBe(true);
86
87                orig.delete();
88                copy.delete();
89                done();
90            }));
91        });
92    });
93
94    function ExpectRectsToBeEqual(actual, expected) {
95        if (PathKit.usingWasm) {
96            // exact match
97            expect(actual).toEqual(expected);
98        } else {
99            // floats get rounded a little bit
100            expect(actual.fLeft).toBeCloseTo(expected.fLeft, 4);
101            expect(actual.fTop).toBeCloseTo(expected.fTop, 4);
102            expect(actual.fRight).toBeCloseTo(expected.fRight, 4);
103            expect(actual.fBottom).toBeCloseTo(expected.fBottom, 4);
104        }
105    }
106
107    function bits2float(str) {
108        return PathKit.SkBits2FloatUnsigned(parseInt(str))
109    }
110
111    describe('bounds and rect', function(){
112        it('dynamically updates getBounds()', function(done){
113            LoadPathKit.then(catchException(done, () => {
114                // Based on test_bounds_crbug_513799
115                let path = PathKit.NewPath();
116                expect(path.getBounds()).toEqual(PathKit.LTRBRect(0, 0, 0, 0));
117                path.moveTo(-5, -8);
118                expect(path.getBounds()).toEqual(PathKit.LTRBRect(-5, -8, -5, -8));
119                path.rect(1, 2, 2, 2);
120                expect(path.getBounds()).toEqual(PathKit.LTRBRect(-5, -8, 3, 4));
121                path.moveTo(1, 2);
122                expect(path.getBounds()).toEqual(PathKit.LTRBRect(-5, -8, 3, 4));
123                path.delete();
124                done();
125            }));
126        });
127
128        it('has getBounds() and computeTightBounds()', function(done){
129            LoadPathKit.then(catchException(done, () => {
130                // Based on PathOpsTightBoundsIllBehaved
131                let path = PathKit.NewPath();
132                path.moveTo(1, 1);
133                path.quadraticCurveTo(4, 3, 2, 2);
134                expect(path.getBounds()).toEqual(PathKit.LTRBRect(1, 1, 4, 3));
135                ExpectRectsToBeEqual(path.computeTightBounds(),
136                                     PathKit.LTRBRect(1, 1,
137                                        bits2float("0x40333334"),  // 2.8
138                                        bits2float("0x40155556"))); // 2.3333333
139                path.delete();
140
141                done();
142            }));
143        });
144    });
145
146    function ExpectCmdsToBeEqual(actual, expected) {
147        if (PathKit.usingWasm) {
148            // exact match
149            expect(actual).toEqual(expected);
150        } else {
151            // lossy match
152            actual.every((cmd, cmdIdx) => {
153                cmd.every((arg, argIdx) => {
154                    // The asm.js code is close to the wasm/c++ output, but not quite.
155                    expect(arg).toBeCloseTo(expected[cmdIdx][argIdx], 4)
156                });
157            });
158        }
159    }
160
161    describe('Command arrays', function(){
162        it('does NOT approximates conics when dumping as toCmds', function(done) {
163            LoadPathKit.then(catchException(done, () => {
164                let path = PathKit.NewPath();
165                path.moveTo(20, 120);
166                path.arc(20, 120, 18, 0, 1.75 * Math.PI);
167                path.lineTo(20, 120);
168
169                let expectedCmds = [
170                    [PathKit.MOVE_VERB, 20, 120],
171                    [PathKit.LINE_VERB, 38, 120],
172                    [PathKit.CONIC_VERB, 38, 138, 20, 138, bits2float("0x3f3504f3)")], // 0.707107f
173                    [PathKit.CONIC_VERB, 2, 138, 2, 120, bits2float("0x3f3504f3)")],   // 0.707107f
174                    [PathKit.CONIC_VERB, 2, 102, 20, 102, bits2float("0x3f3504f3)")],  // 0.707107f
175                    [PathKit.CONIC_VERB, bits2float("0x41dba58e"), 102, bits2float("0x4202e962"), bits2float("0x42d68b4d"), bits2float("0x3f6c8361")],  // 27.4558, 102, 32.7279, 107.272, 0.92388
176                    [PathKit.LINE_VERB, 20, 120],
177                ];
178                ExpectCmdsToBeEqual(path.toCmds(), expectedCmds);
179
180                path.delete();
181                done();
182            }));
183        });
184    });
185
186});
187