Commit | Line | Data |
---|---|---|
718ad8e2 | 1 | // Copyright (c) 2011 Google, Inc. |
644eff8b RK |
2 | // |
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy | |
4 | // of this software and associated documentation files (the "Software"), to deal | |
5 | // in the Software without restriction, including without limitation the rights | |
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
7 | // copies of the Software, and to permit persons to whom the Software is | |
8 | // furnished to do so, subject to the following conditions: | |
9 | // | |
10 | // The above copyright notice and this permission notice shall be included in | |
11 | // all copies or substantial portions of the Software. | |
12 | // | |
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
19 | // THE SOFTWARE. | |
20 | ||
21 | /** | |
22 | * @fileoverview Assertions and other code used to test a canvas proxy. | |
23 | * | |
24 | * @author konigsberg@google.com (Robert Konigsberg) | |
25 | */ | |
26 | ||
27 | var CanvasAssertions = {}; | |
28 | ||
29 | /** | |
30 | * Assert that a line is drawn between the two points | |
31 | * | |
32 | * This merely looks for one of these four possibilities: | |
33 | * moveTo(p1) -> lineTo(p2) | |
34 | * moveTo(p2) -> lineTo(p1) | |
35 | * lineTo(p1) -> lineTo(p2) | |
36 | * lineTo(p2) -> lineTo(p1) | |
37 | * | |
bbb9a8f3 RK |
38 | * predicate is meant to be used when you want to track things like |
39 | * color and stroke width. It can either be a hash of context properties, | |
40 | * or a function that accepts the current call. | |
644eff8b | 41 | */ |
bbb9a8f3 | 42 | CanvasAssertions.assertLineDrawn = function(proxy, p1, p2, predicate) { |
644eff8b RK |
43 | // found = 1 when prior loop found p1. |
44 | // found = 2 when prior loop found p2. | |
45 | var priorFound = 0; | |
7165f97b RK |
46 | for (var i = 0; i < proxy.calls__.length; i++) { |
47 | var call = proxy.calls__[i]; | |
644eff8b RK |
48 | |
49 | // This disables lineTo -> moveTo pairs. | |
50 | if (call.name == "moveTo" && priorFound > 0) { | |
51 | priorFound = 0; | |
52 | } | |
53 | ||
54 | var found = 0; | |
55 | if (call.name == "moveTo" || call.name == "lineTo") { | |
56 | var matchp1 = CanvasAssertions.matchPixels(p1, call.args); | |
57 | var matchp2 = CanvasAssertions.matchPixels(p2, call.args); | |
58 | if (matchp1 || matchp2) { | |
59 | if (priorFound == 1 && matchp2) { | |
bbb9a8f3 RK |
60 | if (CanvasAssertions.match(predicate, call)) { |
61 | return; | |
62 | } | |
644eff8b RK |
63 | } |
64 | if (priorFound == 2 && matchp1) { | |
bbb9a8f3 RK |
65 | if (CanvasAssertions.match(predicate, call.properties)) { |
66 | return; | |
67 | } | |
644eff8b RK |
68 | } |
69 | found = matchp1 ? 1 : 2; | |
70 | } | |
71 | } | |
72 | priorFound = found; | |
73 | } | |
74 | ||
75 | var toString = function(x) { | |
76 | var s = "{"; | |
77 | for (var prop in x) { | |
78 | if (x.hasOwnProperty(prop)) { | |
79 | if (s.length > 1) { | |
80 | s = s + ", "; | |
81 | } | |
82 | s = s + prop + ": " + x[prop]; | |
83 | } | |
84 | } | |
85 | return s + "}"; | |
86 | }; | |
87 | fail("Can't find a line drawn between " + p1 + | |
71f94616 | 88 | " and " + p2 + " with attributes " + toString(predicate)); |
6278f6fe DV |
89 | }; |
90 | ||
91 | /** | |
8337da0a RK |
92 | * Return the lines drawn with specific attributes. |
93 | * | |
94 | * This merely looks for one of these four possibilities: | |
95 | * moveTo(p1) -> lineTo(p2) | |
96 | * moveTo(p2) -> lineTo(p1) | |
97 | * lineTo(p1) -> lineTo(p2) | |
98 | * lineTo(p2) -> lineTo(p1) | |
99 | * | |
100 | * attrs is meant to be used when you want to track things like | |
101 | * color and stroke width. | |
102 | */ | |
bbb9a8f3 | 103 | CanvasAssertions.getLinesDrawn = function(proxy, predicate) { |
8337da0a RK |
104 | var lastCall; |
105 | var lines = []; | |
106 | for (var i = 0; i < proxy.calls__.length; i++) { | |
107 | var call = proxy.calls__[i]; | |
108 | ||
109 | if (call.name == "lineTo") { | |
110 | if (lastCall != null) { | |
71f94616 | 111 | if (CanvasAssertions.match(predicate, call)) { |
bbb9a8f3 RK |
112 | lines.push([lastCall, call]); |
113 | } | |
8337da0a RK |
114 | } |
115 | } | |
116 | ||
117 | lastCall = (call.name === "lineTo" || call.name === "moveTo") ? call : null; | |
118 | } | |
119 | return lines; | |
120 | }; | |
121 | ||
122 | /** | |
6278f6fe DV |
123 | * Verifies that every call to context.save() has a matching call to |
124 | * context.restore(). | |
125 | */ | |
126 | CanvasAssertions.assertBalancedSaveRestore = function(proxy) { | |
127 | var depth = 0; | |
128 | for (var i = 0; i < proxy.calls__.length; i++) { | |
129 | var call = proxy.calls__[i]; | |
130 | if (call.name == "save") depth++ | |
131 | if (call.name == "restore") { | |
132 | if (depth == 0) { | |
133 | fail("Too many calls to restore()"); | |
134 | } | |
135 | depth--; | |
136 | } | |
137 | } | |
138 | ||
139 | if (depth > 0) { | |
140 | fail("Missing matching 'context.restore()' calls."); | |
141 | } | |
142 | }; | |
644eff8b | 143 | |
063e83ba DV |
144 | /** |
145 | * Checks how many lines of the given color have been drawn. | |
146 | * @return {Integer} The number of lines of the given color. | |
147 | */ | |
bbb9a8f3 RK |
148 | // TODO(konigsberg): change 'color' to predicate? color is the |
149 | // common case. Possibly allow predicate to be function, hash, or | |
150 | // string representing color? | |
063e83ba DV |
151 | CanvasAssertions.numLinesDrawn = function(proxy, color) { |
152 | var num_lines = 0; | |
153 | for (var i = 0; i < proxy.calls__.length; i++) { | |
154 | var call = proxy.calls__[i]; | |
155 | if (call.name == "lineTo" && call.properties.strokeStyle == color) { | |
156 | num_lines++; | |
157 | } | |
158 | } | |
159 | return num_lines; | |
6278f6fe | 160 | }; |
063e83ba | 161 | |
71f94616 RK |
162 | /** |
163 | * Asserts that a series of lines are connected. For example, | |
164 | * assertConsecutiveLinesDrawn(proxy, [[x1, y1], [x2, y2], [x3, y3]], predicate) | |
165 | * is shorthand for | |
166 | * assertLineDrawn(proxy, [x1, y1], [x2, y2], predicate) | |
167 | * assertLineDrawn(proxy, [x2, y2], [x3, y3], predicate) | |
168 | */ | |
169 | CanvasAssertions.assertConsecutiveLinesDrawn = function(proxy, segments, predicate) { | |
170 | for (var i = 0; i < segments.length - 1; i++) { | |
171 | CanvasAssertions.assertLineDrawn(proxy, segments[i], segments[i+1], predicate); | |
172 | } | |
173 | } | |
174 | ||
644eff8b RK |
175 | CanvasAssertions.matchPixels = function(expected, actual) { |
176 | // Expect array of two integers. Assuming the values are within one | |
177 | // integer unit of each other. This should be tightened down by someone | |
178 | // who knows what pixel a value of 5.8888 results in. | |
179 | return Math.abs(expected[0] - actual[0]) < 1 && | |
180 | Math.abs(expected[1] - actual[1]) < 1; | |
6278f6fe | 181 | }; |
644eff8b | 182 | |
bbb9a8f3 RK |
183 | /** |
184 | * For matching a proxy call against defined conditions. | |
185 | * predicate can either by a hash of items compared against call.properties, | |
186 | * or it can be a function that accepts the call, and returns true or false. | |
71f94616 | 187 | * If it's null, this function returns true. |
bbb9a8f3 RK |
188 | */ |
189 | CanvasAssertions.match = function(predicate, call) { | |
71f94616 RK |
190 | if (predicate === null) { |
191 | return true; | |
192 | } | |
bbb9a8f3 RK |
193 | if (typeof(predicate) === "function") { |
194 | return predicate(call); | |
195 | } else { | |
196 | for (var attr in predicate) { | |
197 | if (predicate.hasOwnProperty(attr) && predicate[attr] != call.properties[attr]) { | |
198 | return false; | |
199 | } | |
644eff8b RK |
200 | } |
201 | } | |
202 | return true; | |
6278f6fe | 203 | }; |