Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 ////////////////////////////////////////////////////////////////////////////////
2 // Object attributes.
4 /**
5 * Test object attributes.
6 *
7 * @param aAccOrElmOrID [in] the accessible identifier
8 * @param aAttrs [in] the map of expected object attributes
9 * (name/value pairs)
10 * @param aSkipUnexpectedAttrs [in] points this function doesn't fail if
11 * unexpected attribute is encountered
12 */
13 function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs)
14 {
15 testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs);
16 }
18 /**
19 * Test object attributes that must not be present.
20 *
21 * @param aAccOrElmOrID [in] the accessible identifier
22 * @param aAbsentAttrs [in] map of attributes that should not be
23 * present (name/value pairs)
24 */
25 function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs)
26 {
27 testAttrsInternal(aAccOrElmOrID, {}, true, aAbsentAttrs);
28 }
30 /**
31 * Test CSS based object attributes.
32 */
33 function testCSSAttrs(aID)
34 {
35 var node = document.getElementById(aID);
36 var computedStyle = document.defaultView.getComputedStyle(node, "");
38 var attrs = {
39 "display": computedStyle.display,
40 "text-align": computedStyle.textAlign,
41 "text-indent": computedStyle.textIndent,
42 "margin-left": computedStyle.marginLeft,
43 "margin-right": computedStyle.marginRight,
44 "margin-top": computedStyle.marginTop,
45 "margin-bottom": computedStyle.marginBottom
46 };
47 testAttrs(aID, attrs, true);
48 }
50 /**
51 * Test the accessible that it doesn't have CSS-based object attributes.
52 */
53 function testAbsentCSSAttrs(aID)
54 {
55 var attrs = {
56 "display": "",
57 "text-align": "",
58 "text-indent": "",
59 "margin-left": "",
60 "margin-right": "",
61 "margin-top": "",
62 "margin-bottom": ""
63 };
64 testAbsentAttrs(aID, attrs);
65 }
67 /**
68 * Test group object attributes (posinset, setsize and level) and
69 * nsIAccessible::groupPosition() method.
70 *
71 * @param aAccOrElmOrID [in] the ID, DOM node or accessible
72 * @param aPosInSet [in] the value of 'posinset' attribute
73 * @param aSetSize [in] the value of 'setsize' attribute
74 * @param aLevel [in, optional] the value of 'level' attribute
75 */
76 function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
77 {
78 var acc = getAccessible(aAccOrElmOrID);
79 var levelObj = {}, posInSetObj = {}, setSizeObj = {};
80 acc.groupPosition(levelObj, setSizeObj, posInSetObj);
82 if (aPosInSet && aSetSize) {
83 is(posInSetObj.value, aPosInSet,
84 "Wrong group position (posinset) for " + prettyName(aAccOrElmOrID));
85 is(setSizeObj.value, aSetSize,
86 "Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID));
88 var attrs = {
89 "posinset": String(aPosInSet),
90 "setsize": String(aSetSize)
91 };
92 testAttrs(aAccOrElmOrID, attrs, true);
93 }
95 if (aLevel) {
96 is(levelObj.value, aLevel,
97 "Wrong group level for " + prettyName(aAccOrElmOrID));
99 var attrs = { "level" : String(aLevel) };
100 testAttrs(aAccOrElmOrID, attrs, true);
101 }
102 }
104 ////////////////////////////////////////////////////////////////////////////////
105 // Text attributes.
107 /**
108 * Test text attributes.
109 *
110 * @param aID [in] the ID of DOM element having text
111 * accessible
112 * @param aOffset [in] the offset inside text accessible to fetch
113 * text attributes
114 * @param aAttrs [in] the map of expected text attributes
115 * (name/value pairs) exposed at the offset
116 * @param aDefAttrs [in] the map of expected text attributes
117 * (name/value pairs) exposed on hyper text
118 * accessible
119 * @param aStartOffset [in] expected start offset where text attributes
120 * are applied
121 * @param aEndOffset [in] expected end offset where text attribute
122 * are applied
123 * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
124 * unexpected attribute is encountered
125 */
126 function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
127 aStartOffset, aEndOffset, aSkipUnexpectedAttrs)
128 {
129 var accessible = getAccessible(aID, [nsIAccessibleText]);
130 if (!accessible)
131 return;
133 var startOffset = { value: -1 };
134 var endOffset = { value: -1 };
136 // do not include attributes exposed on hyper text accessbile
137 var attrs = getTextAttributes(aID, accessible, false, aOffset,
138 startOffset, endOffset);
140 if (!attrs)
141 return;
143 var errorMsg = " for " + aID + " at offset " + aOffset;
145 is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg);
146 is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
148 compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
150 // include attributes exposed on hyper text accessbile
151 var expectedAttrs = {};
152 for (var name in aAttrs)
153 expectedAttrs[name] = aAttrs[name];
155 for (var name in aDefAttrs) {
156 if (!(name in expectedAttrs))
157 expectedAttrs[name] = aDefAttrs[name];
158 }
160 attrs = getTextAttributes(aID, accessible, true, aOffset,
161 startOffset, endOffset);
163 if (!attrs)
164 return;
166 compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
167 }
169 /**
170 * Test default text attributes.
171 *
172 * @param aID [in] the ID of DOM element having text
173 * accessible
174 * @param aDefAttrs [in] the map of expected text attributes
175 * (name/value pairs)
176 * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
177 * unexpected attribute is encountered
178 */
179 function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
180 {
181 var accessible = getAccessible(aID, [nsIAccessibleText]);
182 if (!accessible)
183 return;
185 var defAttrs = null;
186 try{
187 defAttrs = accessible.defaultTextAttributes;
188 } catch (e) {
189 }
191 if (!defAttrs) {
192 ok(false, "Can't get default text attributes for " + aID);
193 return;
194 }
196 var errorMsg = ". Getting default text attributes for " + aID;
197 compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs);
198 }
200 /**
201 * Test text attributes for wrong offset.
202 */
203 function testTextAttrsWrongOffset(aID, aOffset)
204 {
205 var res = false;
206 try {
207 var s = {}, e = {};
208 var acc = getAccessible(ID, [nsIAccessibleText]);
209 acc.getTextAttributes(false, 157, s, e);
210 } catch (e) {
211 res = true;
212 }
214 ok(res,
215 "text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID));
216 }
218 const kNormalFontWeight =
219 function equalsToNormal(aWeight) { return aWeight <= 400 ; }
221 const kBoldFontWeight =
222 function equalsToBold(aWeight) { return aWeight > 400; }
224 // The pt font size of the input element can vary by Linux distro.
225 const kInputFontSize = WIN ?
226 "10pt" : (MAC ? "8pt" : function() { return true; });
228 const kAbsentFontFamily =
229 function(aFontFamily) { return aFontFamily != "sans-serif"; }
230 const kInputFontFamily =
231 function(aFontFamily) { return aFontFamily != "sans-serif"; }
233 const kMonospaceFontFamily =
234 function(aFontFamily) { return aFontFamily != "monospace"; }
235 const kSansSerifFontFamily =
236 function(aFontFamily) { return aFontFamily != "sans-serif"; }
237 const kSerifFontFamily =
238 function(aFontFamily) { return aFontFamily != "serif"; }
240 const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS";
242 /**
243 * Return used font from the given computed style.
244 */
245 function fontFamily(aComputedStyle)
246 {
247 var name = aComputedStyle.fontFamily;
248 switch (name) {
249 case "monospace":
250 return kMonospaceFontFamily;
251 case "sans-serif":
252 return kSansSerifFontFamily;
253 case "serif":
254 return kSerifFontFamily;
255 default:
256 return name;
257 }
258 }
260 /**
261 * Build an object of default text attributes expected for the given accessible.
262 *
263 * @param aID [in] identifier of accessible
264 * @param aFontSize [in] font size
265 * @param aFontWeight [in, optional] kBoldFontWeight or kNormalFontWeight,
266 * default value is kNormalFontWeight
267 */
268 function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily)
269 {
270 var elm = getNode(aID);
271 var computedStyle = document.defaultView.getComputedStyle(elm, "");
272 var bgColor = computedStyle.backgroundColor == "transparent" ?
273 "rgb(255, 255, 255)" : computedStyle.backgroundColor;
275 var defAttrs = {
276 "font-style": computedStyle.fontStyle,
277 "font-size": aFontSize,
278 "background-color": bgColor,
279 "font-weight": aFontWeight ? aFontWeight : kNormalFontWeight,
280 "color": computedStyle.color,
281 "font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle),
282 "text-position": computedStyle.verticalAlign
283 };
285 return defAttrs;
286 }
288 ////////////////////////////////////////////////////////////////////////////////
289 // Private.
291 function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
292 aStartOffset, aEndOffset)
293 {
294 // This function expects the passed in accessible to already be queried for
295 // nsIAccessibleText.
296 var attrs = null;
297 try {
298 attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
299 aStartOffset, aEndOffset);
300 } catch (e) {
301 }
303 if (attrs)
304 return attrs;
306 ok(false, "Can't get text attributes for " + aID);
307 return null;
308 }
310 function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs,
311 aAbsentAttrs)
312 {
313 var accessible = getAccessible(aAccOrElmOrID);
314 if (!accessible)
315 return;
317 var attrs = null;
318 try {
319 attrs = accessible.attributes;
320 } catch (e) { }
322 if (!attrs) {
323 ok(false, "Can't get object attributes for " + prettyName(aAccOrElmOrID));
324 return;
325 }
327 var errorMsg = " for " + prettyName(aAccOrElmOrID);
328 compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs);
329 }
331 function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
332 aAbsentAttrs)
333 {
334 // Check if all obtained attributes are expected and have expected value.
335 var enumerate = aAttrs.enumerate();
336 while (enumerate.hasMoreElements()) {
337 var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
339 if (!(prop.key in aExpectedAttrs)) {
340 if (!aSkipUnexpectedAttrs)
341 ok(false, "Unexpected attribute '" + prop.key + "' having '" +
342 prop.value + "'" + aErrorMsg);
343 } else {
344 var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg;
345 var expectedValue = aExpectedAttrs[prop.key];
347 if (typeof expectedValue == "function")
348 ok(expectedValue(prop.value), msg);
349 else
350 is(prop.value, expectedValue, msg);
351 }
352 }
354 // Check if all expected attributes are presented.
355 for (var name in aExpectedAttrs) {
356 var value = "";
357 try {
358 value = aAttrs.getStringProperty(name);
359 } catch(e) { }
361 if (!value)
362 ok(false,
363 "There is no expected attribute '" + name + "' " + aErrorMsg);
364 }
366 // Check if all unexpected attributes are absent.
367 if (aAbsentAttrs) {
368 for (var name in aAbsentAttrs) {
369 var wasFound = false;
371 var enumerate = aAttrs.enumerate();
372 while (enumerate.hasMoreElements()) {
373 var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
374 if (prop.key == name)
375 wasFound = true;
376 }
377 }
379 ok(!wasFound,
380 "There is an unexpected attribute '" + name + "' " + aErrorMsg);
381 }
382 }