Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 ////////////////////////////////////////////////////////////////////////////////
2 // Helper functions for accessible states testing.
3 //
4 // requires:
5 // common.js
6 // role.js
7 //
8 ////////////////////////////////////////////////////////////////////////////////
10 ////////////////////////////////////////////////////////////////////////////////
11 // State constants
13 // const STATE_BUSY is defined in common.js
14 const STATE_CHECKED = nsIAccessibleStates.STATE_CHECKED;
15 const STATE_CHECKABLE = nsIAccessibleStates.STATE_CHECKABLE;
16 const STATE_COLLAPSED = nsIAccessibleStates.STATE_COLLAPSED;
17 const STATE_DEFAULT = nsIAccessibleStates.STATE_DEFAULT;
18 const STATE_EXPANDED = nsIAccessibleStates.STATE_EXPANDED;
19 const STATE_EXTSELECTABLE = nsIAccessibleStates.STATE_EXTSELECTABLE;
20 const STATE_FLOATING = nsIAccessibleStates.STATE_FLOATING;
21 const STATE_FOCUSABLE = nsIAccessibleStates.STATE_FOCUSABLE;
22 const STATE_FOCUSED = nsIAccessibleStates.STATE_FOCUSED;
23 const STATE_HASPOPUP = nsIAccessibleStates.STATE_HASPOPUP;
24 const STATE_INVALID = nsIAccessibleStates.STATE_INVALID;
25 const STATE_INVISIBLE = nsIAccessibleStates.STATE_INVISIBLE;
26 const STATE_LINKED = nsIAccessibleStates.STATE_LINKED;
27 const STATE_MIXED = nsIAccessibleStates.STATE_MIXED;
28 const STATE_MULTISELECTABLE = nsIAccessibleStates.STATE_MULTISELECTABLE;
29 const STATE_OFFSCREEN = nsIAccessibleStates.STATE_OFFSCREEN;
30 const STATE_PRESSED = nsIAccessibleStates.STATE_PRESSED;
31 const STATE_PROTECTED = nsIAccessibleStates.STATE_PROTECTED;
32 const STATE_READONLY = nsIAccessibleStates.STATE_READONLY;
33 const STATE_REQUIRED = nsIAccessibleStates.STATE_REQUIRED;
34 const STATE_SELECTABLE = nsIAccessibleStates.STATE_SELECTABLE;
35 const STATE_SELECTED = nsIAccessibleStates.STATE_SELECTED;
36 const STATE_TRAVERSED = nsIAccessibleStates.STATE_TRAVERSED;
37 const STATE_UNAVAILABLE = nsIAccessibleStates.STATE_UNAVAILABLE;
39 const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
40 const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
41 const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE;
42 const EXT_STATE_ENABLED = nsIAccessibleStates.EXT_STATE_ENABLED;
43 const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE;
44 const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
45 const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE;
46 const EXT_STATE_PINNED = nsIAccessibleStates.EXT_STATE_PINNED;
47 const EXT_STATE_SENSITIVE = nsIAccessibleStates.EXT_STATE_SENSITIVE;
48 const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE;
49 const EXT_STATE_STALE = nsIAccessibleStates.EXT_STATE_STALE;
50 const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
51 nsIAccessibleStates.EXT_STATE_SUPPORTS_AUTOCOMPLETION;
52 const EXT_STATE_VERTICAL = nsIAccessibleStates.EXT_STATE_VERTICAL;
54 const kOrdinalState = 0;
55 const kExtraState = 1;
57 ////////////////////////////////////////////////////////////////////////////////
58 // Test functions
60 /**
61 * Tests the states and extra states of the given accessible.
62 * Also tests for unwanted states and extra states.
63 * In addition, the function performs a few plausibility checks derived from the
64 * sstates and extra states passed in.
65 *
66 * @param aAccOrElmOrID The accessible, DOM element or ID to be tested.
67 * @param aState The state bits that are wanted.
68 * @param aExtraState The extra state bits that are wanted.
69 * @param aAbsentState State bits that are not wanted.
70 * @param aAbsentExtraState Extra state bits that are not wanted.
71 * @param aTestName The test name.
72 */
73 function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
74 aAbsentExtraState, aTestName)
75 {
76 var [state, extraState] = getStates(aAccOrElmOrID);
77 var role = getRole(aAccOrElmOrID);
78 var id = prettyName(aAccOrElmOrID) + (aTestName ? " [" + aTestName + "]": "");
80 // Primary test.
81 if (aState) {
82 isState(state & aState, aState, false,
83 "wrong state bits for " + id + "!");
84 }
86 if (aExtraState)
87 isState(extraState & aExtraState, aExtraState, true,
88 "wrong extra state bits for " + id + "!");
90 if (aAbsentState)
91 isState(state & aAbsentState, 0, false,
92 "state bits should not be present in ID " + id + "!");
94 if (aAbsentExtraState)
95 isState(extraState & aAbsentExtraState, 0, true,
96 "extraState bits should not be present in ID " + id + "!");
98 // Additional test.
100 // focused/focusable
101 if (state & STATE_FOCUSED)
102 isState(state & STATE_FOCUSABLE, STATE_FOCUSABLE, false,
103 "Focussed " + id + " must be focusable!");
105 if (aAbsentState && (aAbsentState & STATE_FOCUSABLE)) {
106 isState(state & STATE_FOCUSED, 0, false,
107 "Not focusable " + id + " must be not focused!");
108 }
110 // multiline/singleline
111 if (extraState & EXT_STATE_MULTI_LINE)
112 isState(extraState & EXT_STATE_SINGLE_LINE, 0, true,
113 "Multiline " + id + " cannot be singleline!");
115 if (extraState & EXT_STATE_SINGLE_LINE)
116 isState(extraState & EXT_STATE_MULTI_LINE, 0, true,
117 "Singleline " + id + " cannot be multiline!");
119 // expanded/collapsed/expandable
120 if (state & STATE_COLLAPSED || state & STATE_EXPANDED)
121 isState(extraState & EXT_STATE_EXPANDABLE, EXT_STATE_EXPANDABLE, true,
122 "Collapsed or expanded " + id + " must be expandable!");
124 if (state & STATE_COLLAPSED)
125 isState(state & STATE_EXPANDED, 0, false,
126 "Collapsed " + id + " cannot be expanded!");
128 if (state & STATE_EXPANDED)
129 isState(state & STATE_COLLAPSED, 0, false,
130 "Expanded " + id + " cannot be collapsed!");
132 if (aAbsentState && (extraState & EXT_STATE_EXPANDABLE)) {
133 if (aAbsentState & STATE_EXPANDED) {
134 isState(state & STATE_COLLAPSED, STATE_COLLAPSED, false,
135 "Not expanded " + id + " must be collapsed!");
136 } else if (aAbsentState & STATE_COLLAPSED) {
137 isState(state & STATE_EXPANDED, STATE_EXPANDED, false,
138 "Not collapsed " + id + " must be expanded!");
139 }
140 }
142 // checked/mixed/checkable
143 if (state & STATE_CHECKED || state & STATE_MIXED &&
144 role != ROLE_TOGGLE_BUTTON && role != ROLE_PROGRESSBAR)
145 isState(state & STATE_CHECKABLE, STATE_CHECKABLE, false,
146 "Checked or mixed element must be checkable!");
148 if (state & STATE_CHECKED)
149 isState(state & STATE_MIXED, 0, false,
150 "Checked element cannot be state mixed!");
152 if (state & STATE_MIXED)
153 isState(state & STATE_CHECKED, 0, false,
154 "Mixed element cannot be state checked!");
156 // selected/selectable
157 if (state & STATE_SELECTED) {
158 isState(state & STATE_SELECTABLE, STATE_SELECTABLE, false,
159 "Selected element must be selectable!");
160 }
161 }
163 /**
164 * Tests an acessible and its sub tree for the passed in state bits.
165 * Used to make sure that states are propagated to descendants, for example the
166 * STATE_UNAVAILABLE from a container to its children.
167 *
168 * @param aAccOrElmOrID The accessible, DOM element or ID to be tested.
169 * @param aState The state bits that are wanted.
170 * @param aExtraState The extra state bits that are wanted.
171 * @param aAbsentState State bits that are not wanted.
172 */
173 function testStatesInSubtree(aAccOrElmOrID, aState, aExtraState, aAbsentState)
174 {
175 // test accessible and its subtree for propagated states.
176 var acc = getAccessible(aAccOrElmOrID);
177 if (!acc)
178 return;
180 if (getRole(acc) != ROLE_TEXT_LEAF)
181 // Right now, text leafs don't get tested because the states are not being
182 // propagated.
183 testStates(acc, aState, aExtraState, aAbsentState);
185 // Iterate over its children to see if the state got propagated.
186 var children = null;
187 try {
188 children = acc.children;
189 } catch(e) {}
190 ok(children, "Could not get children for " + aAccOrElmOrID +"!");
192 if (children) {
193 for (var i = 0; i < children.length; i++) {
194 var childAcc = children.queryElementAt(i, nsIAccessible);
195 testStatesInSubtree(childAcc, aState, aExtraState, aAbsentState);
196 }
197 }
198 }
200 function getStringStates(aAccOrElmOrID)
201 {
202 var [state, extraState] = getStates(aAccOrElmOrID);
203 return statesToString(state, extraState);
204 }
206 function getStates(aAccOrElmOrID)
207 {
208 var acc = getAccessible(aAccOrElmOrID);
209 if (!acc)
210 return [0, 0];
212 var state = {}, extraState = {};
213 acc.getState(state, extraState);
215 return [state.value, extraState.value];
216 }
218 /**
219 * Return true if the accessible has given states.
220 */
221 function hasState(aAccOrElmOrID, aState, aExtraState)
222 {
223 var [state, exstate] = getStates(aAccOrElmOrID);
224 return (aState ? state & aState : true) &&
225 (aExtraState ? exstate & aExtraState : true);
226 }
228 ////////////////////////////////////////////////////////////////////////////////
229 // Private implementation details
231 /**
232 * Analogy of SimpleTest.is function used to compare states.
233 */
234 function isState(aState1, aState2, aIsExtraStates, aMsg)
235 {
236 if (aState1 == aState2) {
237 ok(true, aMsg);
238 return;
239 }
241 var got = "0";
242 if (aState1) {
243 got = statesToString(aIsExtraStates ? 0 : aState1,
244 aIsExtraStates ? aState1 : 0);
245 }
247 var expected = "0";
248 if (aState2) {
249 expected = statesToString(aIsExtraStates ? 0 : aState2,
250 aIsExtraStates ? aState2 : 0);
251 }
253 ok(false, aMsg + "got '" + got + "', expected '" + expected + "'");
254 }