1 // Copyright (c) 2011 Google, Inc.
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:
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
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
22 * @fileoverview Assertions and other code used to test a canvas proxy.
24 * @author konigsberg@google.com (Robert Konigsberg)
27 var CanvasAssertions
= {};
30 * Assert that a line is drawn between the two points
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)
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.
42 CanvasAssertions
.assertLineDrawn
= function(proxy
, p1
, p2
, predicate
) {
43 // found = 1 when prior loop found p1.
44 // found = 2 when prior loop found p2.
46 for (var i
= 0; i
< proxy
.calls__
.length
; i
++) {
47 var call
= proxy
.calls__
[i
];
49 // This disables lineTo -> moveTo pairs.
50 if (call
.name
== "moveTo" && priorFound
> 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
) {
60 if (CanvasAssertions
.match(predicate
, call
)) {
64 if (priorFound
== 2 && matchp1
) {
65 if (CanvasAssertions
.match(predicate
, call
.properties
)) {
69 found
= matchp1
? 1 : 2;
75 var toString
= function(x
) {
78 if (x
.hasOwnProperty(prop
)) {
82 s
= s
+ prop
+ ": " + x
[prop
];
87 fail("Can't find a line drawn between " + p1
+
88 " and " + p2
+ " with attributes " + toString(predicate
));
92 * Return the lines drawn with specific attributes.
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)
100 * attrs is meant to be used when you want to track things like
101 * color and stroke width.
103 CanvasAssertions
.getLinesDrawn
= function(proxy
, predicate
) {
106 for (var i
= 0; i
< proxy
.calls__
.length
; i
++) {
107 var call
= proxy
.calls__
[i
];
109 if (call
.name
== "lineTo") {
110 if (lastCall
!= null) {
111 if (CanvasAssertions
.match(predicate
, call
)) {
112 lines
.push([lastCall
, call
]);
117 lastCall
= (call
.name
=== "lineTo" || call
.name
=== "moveTo") ? call
: null;
123 * Verifies that every call to context.save() has a matching call to
126 CanvasAssertions
.assertBalancedSaveRestore
= function(proxy
) {
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") {
133 fail("Too many calls to restore()");
140 fail("Missing matching 'context.restore()' calls.");
145 * Checks how many lines of the given color have been drawn.
146 * @return {Integer} The number of lines of the given color.
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?
151 CanvasAssertions
.numLinesDrawn
= function(proxy
, color
) {
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
) {
163 * Asserts that a series of lines are connected. For example,
164 * assertConsecutiveLinesDrawn(proxy, [[x1, y1], [x2, y2], [x3, y3]], predicate)
166 * assertLineDrawn(proxy, [x1, y1], [x2, y2], predicate)
167 * assertLineDrawn(proxy, [x2, y2], [x3, y3], predicate)
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
);
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;
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.
187 * If it's null, this function returns true.
189 CanvasAssertions
.match
= function(predicate
, call
) {
190 if (predicate
=== null) {
193 if (typeof(predicate
) === "function") {
194 return predicate(call
);
196 for (var attr
in predicate
) {
197 if (predicate
.hasOwnProperty(attr
) && predicate
[attr
] != call
.properties
[attr
]) {