AXElements 0.6.0beta2 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/.yardopts +1 -2
  2. data/README.markdown +152 -88
  3. data/Rakefile +8 -103
  4. data/docs/Debugging.markdown +9 -2
  5. data/docs/KeyboardEvents.markdown +114 -49
  6. data/docs/Setting.markdown +1 -0
  7. data/docs/images/next_version.png +0 -0
  8. data/ext/accessibility/key_coder/extconf.rb +22 -0
  9. data/ext/accessibility/key_coder/key_coder.c +113 -0
  10. data/lib/AXElements.rb +2 -0
  11. data/lib/accessibility/core.rb +897 -0
  12. data/lib/accessibility/debug.rb +168 -0
  13. data/lib/accessibility/dsl.rb +697 -0
  14. data/lib/accessibility/enumerators.rb +104 -0
  15. data/lib/accessibility/errors.rb +32 -0
  16. data/lib/accessibility/factory.rb +153 -0
  17. data/lib/accessibility/graph.rb +150 -0
  18. data/lib/{ax_elements/inspector.rb → accessibility/pp_inspector.rb} +39 -28
  19. data/lib/accessibility/qualifier.rb +158 -0
  20. data/lib/accessibility/string.rb +494 -0
  21. data/lib/accessibility/translator.rb +178 -0
  22. data/lib/accessibility/version.rb +7 -0
  23. data/lib/accessibility.rb +79 -0
  24. data/lib/ax/application.rb +234 -0
  25. data/lib/{ax_elements/elements → ax}/button.rb +2 -0
  26. data/lib/ax/element.rb +518 -0
  27. data/lib/{ax_elements/elements → ax}/radio_button.rb +2 -0
  28. data/lib/ax/row.rb +37 -0
  29. data/lib/{ax_elements/elements → ax}/static_text.rb +2 -0
  30. data/lib/ax/systemwide.rb +86 -0
  31. data/lib/ax_elements/awesome_print.rb +25 -0
  32. data/lib/ax_elements/exception_workaround.rb +8 -0
  33. data/lib/ax_elements/nsarray_compat.rb +64 -0
  34. data/lib/ax_elements/vendor/inflection_data.rb +65 -0
  35. data/lib/ax_elements/vendor/inflections.rb +172 -0
  36. data/lib/ax_elements/vendor/inflector.rb +306 -0
  37. data/lib/ax_elements.rb +14 -25
  38. data/lib/minitest/ax_elements.rb +112 -12
  39. data/lib/mouse.rb +72 -46
  40. data/lib/rspec/expectations/ax_elements.rb +133 -6
  41. data/rakelib/doc.rake +13 -0
  42. data/rakelib/ext.rake +61 -0
  43. data/rakelib/gem.rake +28 -0
  44. data/rakelib/test.rake +53 -0
  45. data/test/helper.rb +11 -97
  46. data/test/integration/accessibility/test_core.rb +18 -0
  47. data/test/integration/accessibility/test_debug.rb +44 -0
  48. data/test/integration/accessibility/test_dsl.rb +225 -0
  49. data/test/integration/accessibility/test_enumerators.rb +122 -0
  50. data/test/integration/accessibility/test_errors.rb +38 -0
  51. data/test/integration/accessibility/test_notifications.rb +22 -0
  52. data/test/integration/accessibility/test_qualifier.rb +148 -0
  53. data/test/integration/ax/test_application.rb +56 -0
  54. data/test/integration/ax/test_element.rb +46 -0
  55. data/test/integration/ax/test_row.rb +23 -0
  56. data/test/integration/ax_elements/test_nsarray_compat.rb +43 -0
  57. data/test/integration/minitest/test_ax_elements.rb +98 -0
  58. data/test/integration/rspec/expectations/test_ax_elements.rb +58 -0
  59. data/test/integration/test_mouse.rb +35 -0
  60. data/test/sanity/accessibility/test_core.rb +553 -0
  61. data/test/sanity/accessibility/test_debug.rb +63 -0
  62. data/test/sanity/accessibility/test_dsl.rb +75 -0
  63. data/test/sanity/accessibility/test_errors.rb +10 -0
  64. data/test/sanity/accessibility/test_factory.rb +88 -0
  65. data/test/sanity/accessibility/test_pp_inspector.rb +110 -0
  66. data/test/sanity/accessibility/test_qualifier.rb +13 -0
  67. data/test/sanity/accessibility/test_string.rb +238 -0
  68. data/test/sanity/accessibility/test_translator.rb +145 -0
  69. data/test/sanity/ax/test_application.rb +90 -0
  70. data/test/sanity/ax/test_element.rb +80 -0
  71. data/test/sanity/ax/test_systemwide.rb +66 -0
  72. data/test/sanity/ax_elements/test_nsarray_compat.rb +16 -0
  73. data/test/sanity/ax_elements/test_nsobject_inspect.rb +11 -0
  74. data/test/sanity/minitest/test_ax_elements.rb +15 -0
  75. data/test/sanity/rspec/expectations/test_ax_elements.rb +12 -0
  76. data/test/sanity/test_ax_elements.rb +10 -0
  77. data/test/sanity/test_mouse.rb +19 -0
  78. metadata +111 -93
  79. data/LICENSE.txt +0 -25
  80. data/ext/key_coder/extconf.rb +0 -6
  81. data/ext/key_coder/key_coder.m +0 -77
  82. data/lib/ax_elements/accessibility/enumerators.rb +0 -104
  83. data/lib/ax_elements/accessibility/graph.rb +0 -118
  84. data/lib/ax_elements/accessibility/language.rb +0 -347
  85. data/lib/ax_elements/accessibility/qualifier.rb +0 -73
  86. data/lib/ax_elements/accessibility.rb +0 -166
  87. data/lib/ax_elements/core.rb +0 -541
  88. data/lib/ax_elements/element.rb +0 -593
  89. data/lib/ax_elements/elements/application.rb +0 -88
  90. data/lib/ax_elements/elements/row.rb +0 -30
  91. data/lib/ax_elements/elements/systemwide.rb +0 -46
  92. data/lib/ax_elements/macruby_extensions.rb +0 -255
  93. data/lib/ax_elements/notification.rb +0 -37
  94. data/lib/ax_elements/version.rb +0 -9
  95. data/test/elements/test_application.rb +0 -72
  96. data/test/elements/test_row.rb +0 -27
  97. data/test/elements/test_systemwide.rb +0 -38
  98. data/test/test_accessibility.rb +0 -127
  99. data/test/test_blankness.rb +0 -26
  100. data/test/test_core.rb +0 -448
  101. data/test/test_element.rb +0 -939
  102. data/test/test_enumerators.rb +0 -81
  103. data/test/test_inspector.rb +0 -130
  104. data/test/test_language.rb +0 -157
  105. data/test/test_macruby_extensions.rb +0 -303
  106. data/test/test_mouse.rb +0 -5
  107. data/test/test_search_semantics.rb +0 -143
@@ -0,0 +1,553 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'test/helper'
4
+ require 'accessibility/core'
5
+
6
+
7
+ class TestAccessibilityCore < MiniTest::Unit::TestCase
8
+
9
+ def window
10
+ @@window ||= REF.attribute(KAXMainWindowAttribute)
11
+ end
12
+
13
+ def child name
14
+ window.children.find { |item|
15
+ (block_given? ? yield(item) : true) if item.role == name
16
+ }
17
+ end
18
+
19
+ def slider; @@slider ||= child KAXSliderRole; end
20
+ def check_box; @@check_box ||= child KAXCheckBoxRole; end
21
+ def pop_up; @@pop_up ||= child KAXPopUpButtonRole; end
22
+ def search_box; @@search_box ||= child KAXTextFieldRole; end
23
+ def static_text; @@static_text ||= child(KAXStaticTextRole) { |x| x.value.match /My Little Pony/ } end
24
+ def yes_button; @@yes_button ||= child(KAXButtonRole) { |x| x.attribute(KAXTitleAttribute) == 'Yes' } end
25
+ def bye_button; @@bye_button ||= child(KAXButtonRole) { |x| x.attribute(KAXTitleAttribute) == 'Bye!' } end
26
+ def no_button; @@no_button ||= child(KAXButtonRole) { |x| x.attribute(KAXTitleAttribute) == 'No' } end
27
+ def web_area; @@web_area ||= child("AXScrollArea") { |x| x.attribute("AXDescription" ) == 'Test Web Area' }.children.first end
28
+ def text_area; @@text_area ||= child("AXScrollArea") { |x| x.attributes.include?("AXIdentifier") && x.attribute("AXIdentifier") == 'Text Area' }.children.first end
29
+
30
+ def invalid_ref
31
+ bye_button # guarantee that it is cached
32
+ @@dead ||= no_button.perform KAXPressAction
33
+ bye_button
34
+ end
35
+
36
+ def app
37
+ @@app ||= Regexp.new(Regexp.escape(REF.inspect))
38
+ end
39
+
40
+ def assert_error args, should_raise: klass, with_fragments: msgs
41
+ e = assert_raises(klass) { (@derp || REF).handle_error *args }
42
+ assert_match /test_core.rb:41/, e.backtrace.first unless RUNNING_COMPILED
43
+ msgs.each { |msg| assert_match msg, e.message }
44
+ end
45
+
46
+
47
+
48
+ ##
49
+ # AFAICT every accessibility object **MUST** have attributes, so
50
+ # there are no tests to check what happens when they do not exist;
51
+ # though I am quite sure that AXElements will raise an exception.
52
+
53
+ def test_attributes
54
+ attrs = REF.attributes
55
+ assert_includes attrs, KAXRoleAttribute
56
+ assert_includes attrs, KAXChildrenAttribute
57
+ assert_includes attrs, KAXTitleAttribute
58
+ assert_includes attrs, KAXMenuBarAttribute
59
+ end
60
+
61
+ def test_attributes_is_empty_for_dead_elements
62
+ assert_empty invalid_ref.attributes
63
+ end
64
+
65
+ def test_attribute
66
+ assert_equal 'AXElementsTester', window.attribute(KAXTitleAttribute )
67
+ assert_equal false, window.attribute(KAXFocusedAttribute)
68
+ assert_equal CGSizeMake(555,483), window.attribute(KAXSizeAttribute )
69
+ assert_equal REF, window.attribute(KAXParentAttribute )
70
+ assert_equal 10..19, window.attribute("AXPie" )
71
+ end
72
+
73
+ def test_attribute_is_nil_when_no_value
74
+ assert_nil window.attribute(KAXGrowAreaAttribute)
75
+ end
76
+
77
+ def test_attribute_when_dead
78
+ assert_nil invalid_ref.attribute(KAXRoleAttribute)
79
+ assert_empty invalid_ref.attribute(KAXChildrenAttribute)
80
+ end
81
+
82
+ def test_attribute_handles_errors
83
+ assert_raises(ArgumentError) { REF.attribute 'MADEUPATTRIBUTE' }
84
+ end
85
+
86
+ def test_role
87
+ assert_equal KAXApplicationRole, REF.role
88
+ end
89
+
90
+ def test_subrole
91
+ assert_equal KAXStandardWindowSubrole, window.subrole
92
+ assert_nil web_area.subrole
93
+ end
94
+
95
+ def test_children
96
+ assert_equal REF.attribute(KAXChildrenAttribute), REF.children
97
+ assert_equal slider.attribute(KAXChildrenAttribute), slider.children
98
+ end
99
+
100
+ def test_value
101
+ assert_equal check_box.attribute(KAXValueAttribute), check_box.value
102
+ assert_equal slider.attribute(KAXValueAttribute), slider.value
103
+ end
104
+
105
+ def test_size_of
106
+ assert_equal REF.children.size, REF.size_of(KAXChildrenAttribute)
107
+ assert_equal 0, pop_up.size_of(KAXChildrenAttribute)
108
+ end
109
+
110
+ def test_size_of_0_for_dead_element
111
+ assert_equal 0, invalid_ref.size_of(KAXChildrenAttribute)
112
+ end
113
+
114
+ def test_writable
115
+ refute REF.writable? KAXTitleAttribute
116
+ assert window.writable? KAXMainAttribute
117
+ end
118
+
119
+ def test_writable_false_for_dead_cases
120
+ refute invalid_ref.writable? KAXRoleAttribute
121
+ end
122
+
123
+ def test_writable_handles_errors
124
+ assert_raises(ArgumentError) { REF.writable? 'FAKE' }
125
+ end
126
+
127
+ def test_set_number
128
+ [25, 75, 50].each do |number|
129
+ assert_equal number, slider.set(KAXValueAttribute, number)
130
+ assert_equal number, slider.value
131
+ end
132
+ end
133
+
134
+ def test_set_string
135
+ [Time.now.to_s, ''].each do |string|
136
+ assert_equal string, search_box.set(KAXValueAttribute, string)
137
+ assert_equal string, search_box.value
138
+ end
139
+ end
140
+
141
+ def test_set_wrapped
142
+ text_area.set KAXValueAttribute, 'hey-o'
143
+
144
+ text_area.set KAXSelectedTextRangeAttribute, 0..3
145
+ assert_equal 0..3, text_area.attribute(KAXSelectedTextRangeAttribute)
146
+
147
+ text_area.set KAXSelectedTextRangeAttribute, 1...4
148
+ assert_equal 1..3, text_area.attribute(KAXSelectedTextRangeAttribute)
149
+ ensure
150
+ text_area.set KAXValueAttribute, ''
151
+ end
152
+
153
+ def test_set_attr_handles_errors
154
+ assert_raises(ArgumentError) { REF.set 'FAKE', true }
155
+ end
156
+
157
+ def test_parameterized_attributes
158
+ assert_empty REF.parameterized_attributes
159
+
160
+ attrs = static_text.parameterized_attributes
161
+ assert_includes attrs, KAXStringForRangeParameterizedAttribute
162
+ assert_includes attrs, KAXLineForIndexParameterizedAttribute
163
+ assert_includes attrs, KAXBoundsForRangeParameterizedAttribute
164
+ end
165
+
166
+ def test_parameterized_attributes_empty_for_dead_elements
167
+ assert_empty invalid_ref.parameterized_attributes
168
+ end
169
+
170
+ def test_attribute_for_parameter
171
+ expected = 'My Li'
172
+
173
+ attr = static_text.attribute KAXStringForRangeParameterizedAttribute,
174
+ for_parameter: 0..4
175
+ assert_equal expected, attr
176
+
177
+ attr = static_text.attribute KAXAttributedStringForRangeParameterizedAttribute,
178
+ for_parameter: 0..4
179
+ assert_equal expected, attr.string
180
+ end
181
+
182
+ def test_attribute_for_parameter_handles_dead_elements_and_no_value
183
+ assert_nil invalid_ref.attribute(KAXStringForRangeParameterizedAttribute, for_parameter: 0..0)
184
+
185
+ # Should add a test case to test the no value case, but it will have
186
+ # to be fabricated in the test app.
187
+ end
188
+
189
+ def test_attribute_for_parameter_handles_errors
190
+ assert_raises(ArgumentError) {
191
+ REF.attribute(KAXStringForRangeParameterizedAttribute, for_parameter: 0..1)
192
+ }
193
+ end
194
+
195
+ def test_action_names
196
+ assert_empty REF.actions
197
+ assert_equal [KAXPressAction], yes_button.actions
198
+ end
199
+
200
+ def test_perform_action
201
+ 2.times do # twice so it should be back where it started
202
+ val = check_box.value
203
+ check_box.perform KAXPressAction
204
+ refute_equal val, check_box.value
205
+ end
206
+
207
+ val = slider.value
208
+ slider.perform KAXIncrementAction
209
+ assert slider.value > val
210
+
211
+ val = slider.value
212
+ slider.perform KAXDecrementAction
213
+ assert slider.value < val
214
+ end
215
+
216
+ def test_action_handles_errors
217
+ assert_raises(ArgumentError) { REF.perform nil }
218
+ end
219
+
220
+ ##
221
+ # The keyboard simulation stuff is a bit weird...
222
+
223
+ def test_post_events_to
224
+ events = [[0x56,true], [0x56,false], [0x54,true], [0x54,false]]
225
+ string = '42'
226
+
227
+ search_box.set KAXFocusedAttribute, true
228
+ REF.post events
229
+
230
+ assert_equal string, search_box.value
231
+
232
+ ensure # reset for next test
233
+ search_box.set KAXValueAttribute, ''
234
+ end
235
+
236
+ ##
237
+ # Kind of a bad test right now because the method itself
238
+ # lacks certain functionality that needs to be added...
239
+
240
+ def test_element_at
241
+ point = no_button.attribute(KAXPositionAttribute)
242
+
243
+ element = REF.element_at point
244
+ assert_equal no_button, element, "#{no_button.inspect} and #{element.inspect}"
245
+
246
+ element = REF.system_wide.element_at point
247
+ assert_equal no_button, element, "#{no_button.inspect} and #{element.inspect}"
248
+
249
+ assert_respond_to element, :role
250
+ end
251
+
252
+ # def test_element_at_returns_nil_on_empty_space
253
+ # skip 'How do I guarantee an empty space on screen?'
254
+ # # btw, [0,0] returns something
255
+ # end
256
+
257
+ def test_application_for
258
+ # @note Should call CFEqual() under the hood, which is what we want
259
+ assert_equal REF, REF.application_for(PID)
260
+ end
261
+
262
+ def test_application_for_raises_for_bad_pid
263
+ assert_raises(ArgumentError) { REF.application_for 0 }
264
+ end
265
+
266
+ def test_observer
267
+ assert_equal AXObserverGetTypeID(), CFGetTypeID(REF.observer { })
268
+ end
269
+
270
+ def test_observer_handles_errors
271
+ assert_raises(ArgumentError) { REF.observer }
272
+ end
273
+
274
+ def test_run_loop_source_for
275
+ obsrvr = REF.observer { |_,_,_| }
276
+ assert_equal CFRunLoopSourceGetTypeID(), CFGetTypeID(REF.run_loop_source_for(obsrvr))
277
+ end
278
+
279
+ # # more than meets the eye
280
+ def test_notification_registration_and_unregistration
281
+ obsrvr = REF.observer { |_,_,_| }
282
+ assert REF.register(obsrvr, to_receive: KAXWindowCreatedNotification)
283
+ assert REF.unregister(obsrvr, from_receiving: KAXWindowCreatedNotification)
284
+ end
285
+
286
+ # integration-y
287
+ def test_notification_registers_everything_correctly
288
+ obsrvr = REF.observer do |observer, element, notif|
289
+ @notif_triple = [observer, element, notif]
290
+ end
291
+ REF.register observer, to_receive: 'Cheezburger'
292
+ source = REF.run_loop_source_for observer
293
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), source, KCFRunLoopDefaultMode)
294
+
295
+ yes_button.perform KAXPressAction
296
+ yes_button.spin_run_loop
297
+
298
+ assert_equal [obsrvr, yes_button, 'Cheezburger'], @notif_triple
299
+
300
+ ensure
301
+ return unless source
302
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, KCFRunLoopDefaultMode)
303
+ end
304
+
305
+ def test_register_handles_errors
306
+ assert_raises(ArgumentError) {
307
+ REF.register(nil, to_receive: KAXWindowCreatedNotification)
308
+ }
309
+ assert_raises(ArgumentError) {
310
+ obsrvr = REF.observer { |_,_,_| }
311
+ REF.register(obsrvr, to_receive: nil)
312
+ }
313
+ end
314
+
315
+ def test_unregister_handles_errors
316
+ assert_raises(ArgumentError) {
317
+ REF.unregister(nil, from_receiving: KAXWindowCreatedNotification)
318
+ }
319
+ assert_raises(ArgumentError) {
320
+ obsrvr = REF.observer { |_,_,_| }
321
+ REF.unregister(obsrvr, from_receiving: nil)
322
+ }
323
+ end
324
+
325
+ def test_enabled?
326
+ assert REF.enabled?
327
+ # @todo I guess that's good enough?
328
+ end
329
+
330
+ def test_pid
331
+ assert_equal PID, REF.pid
332
+ assert_equal PID, window.pid
333
+ end
334
+
335
+ def test_pid_is_zero_for_system_wide
336
+ assert_equal 0, REF.system_wide.pid
337
+ end
338
+
339
+ def test_system_wide
340
+ assert_equal AXUIElementCreateSystemWide(), REF.system_wide
341
+ end
342
+
343
+ def test_application
344
+ assert_equal REF, REF.application
345
+ assert_equal REF, window.application
346
+ end
347
+
348
+ def test_set_timeout_for
349
+ assert_equal 10, REF.set_timeout_to(10)
350
+ assert_equal 0, REF.set_timeout_to(0)
351
+ end
352
+
353
+ def test_handle_error_failsafe
354
+ assert_error [99],
355
+ should_raise: RuntimeError,
356
+ with_fragments: [/never reach this line/, /99/]
357
+ end
358
+
359
+ def test_handle_failure
360
+ assert_error [KAXErrorFailure],
361
+ should_raise: RuntimeError,
362
+ with_fragments: [/system failure/, app]
363
+ end
364
+
365
+ def test_handle_illegal_argument
366
+ assert_error [KAXErrorIllegalArgument],
367
+ should_raise: ArgumentError,
368
+ with_fragments: [/is not an AXUIElementRef/, app]
369
+
370
+ assert_error [KAXErrorIllegalArgument, :cake],
371
+ should_raise: ArgumentError,
372
+ with_fragments: [/is not a legal argument/, /the element/, app, /cake/]
373
+
374
+ assert_error [KAXErrorIllegalArgument, 'cake', 'chocolate'],
375
+ should_raise: ArgumentError,
376
+ with_fragments: [/can't get\/set "cake" with\/to "chocolate"/, app]
377
+
378
+ p = CGPointMake(1,3)
379
+ assert_error [KAXErrorIllegalArgument, p, nil, nil],
380
+ should_raise: ArgumentError,
381
+ with_fragments: [/The point #{p.inspect}/, app]
382
+
383
+ assert_error [KAXErrorIllegalArgument, 'cheezburger', 'cake', nil, nil],
384
+ should_raise: ArgumentError,
385
+ with_fragments: [/the observer "cake"/,app,/the notification "cheezburger"/]
386
+ end
387
+
388
+ def test_handle_invalid_element
389
+ assert_error [KAXErrorInvalidUIElement],
390
+ should_raise: ArgumentError,
391
+ with_fragments: [/no longer a valid reference/, app]
392
+ end
393
+
394
+ def test_handle_invalid_observer
395
+ assert_error [KAXErrorInvalidUIElementObserver, :pie, :cake],
396
+ should_raise: ArgumentError,
397
+ with_fragments: [/no longer a valid observer/, /or was never valid/, app, /cake/]
398
+ end
399
+
400
+ def test_handle_cannot_complete
401
+ assert_error [KAXErrorCannotComplete],
402
+ should_raise: RuntimeError,
403
+ with_fragments: [/An unspecified error/, app, /:\(/]
404
+
405
+ @derp = REF.application_for pid_for 'com.apple.finder'
406
+ def @derp.pid; false end
407
+ assert_error [KAXErrorCannotComplete],
408
+ should_raise: RuntimeError,
409
+ with_fragments: [/Application for pid/, /Maybe it crashed\?/]
410
+ end
411
+
412
+ def test_attr_unsupported
413
+ assert_error [KAXErrorAttributeUnsupported, :cake],
414
+ should_raise: ArgumentError,
415
+ with_fragments: [/does not have/, /:cake attribute/, app]
416
+ end
417
+
418
+ def test_action_unsupported
419
+ assert_error [KAXErrorActionUnsupported, :pie],
420
+ should_raise: ArgumentError,
421
+ with_fragments: [/does not have/, /:pie action/, app]
422
+ end
423
+
424
+ def test_notif_unsupported
425
+ assert_error [KAXErrorNotificationUnsupported, :cheese],
426
+ should_raise: ArgumentError,
427
+ with_fragments: [/does not support/, /:cheese notification/, app]
428
+ end
429
+
430
+ def test_not_implemented
431
+ assert_error [KAXErrorNotImplemented],
432
+ should_raise: NotImplementedError,
433
+ with_fragments: [/does not work with AXAPI/, app]
434
+ end
435
+
436
+ def test_notif_registered
437
+ assert_error [KAXErrorNotificationAlreadyRegistered, :lamp],
438
+ should_raise: ArgumentError,
439
+ with_fragments: [/already registered/, /:lamp/, app]
440
+ end
441
+
442
+ def test_notif_not_registered
443
+ assert_error [KAXErrorNotificationNotRegistered, :peas],
444
+ should_raise: RuntimeError,
445
+ with_fragments: [/not registered/, /:peas/, app]
446
+ end
447
+
448
+ def test_api_disabled
449
+ assert_error [KAXErrorAPIDisabled],
450
+ should_raise: RuntimeError,
451
+ with_fragments: [/AXAPI has been disabled/]
452
+ end
453
+
454
+ def test_param_attr_unsupported
455
+ assert_error [KAXErrorParameterizedAttributeUnsupported, :oscar],
456
+ should_raise: ArgumentError,
457
+ with_fragments: [/does not have/, /:oscar parameterized attribute/, app]
458
+ end
459
+
460
+ def test_not_enough_precision
461
+ assert_error [KAXErrorNotEnoughPrecision],
462
+ should_raise: RuntimeError,
463
+ with_fragments: [/not enough precision/, '¯\(°_o)/¯']
464
+ end
465
+
466
+ end
467
+
468
+
469
+ class TestToAXToRubyHooks < MiniTest::Unit::TestCase
470
+
471
+ def test_to_ax
472
+ # point_makes_a_value
473
+ value = CGPointZero.to_ax
474
+ ptr = Pointer.new CGPoint.type
475
+ AXValueGetValue(value, 1, ptr)
476
+ assert_equal CGPointZero, ptr.value
477
+
478
+ # size_makes_a_value
479
+ value = CGSizeZero.to_ax
480
+ ptr = Pointer.new CGSize.type
481
+ AXValueGetValue(value, 2, ptr)
482
+ assert_equal CGSizeZero, ptr.value
483
+
484
+ # rect_makes_a_value
485
+ value = CGRectZero.to_ax
486
+ ptr = Pointer.new CGRect.type
487
+ AXValueGetValue(value, 3, ptr)
488
+ assert_equal CGRectZero, ptr.value
489
+
490
+ # range_makes_a_value
491
+ range = CFRange.new(5, 4)
492
+ value = range.to_ax
493
+ ptr = Pointer.new CFRange.type
494
+ AXValueGetValue(value, 4, ptr)
495
+ assert_equal range, ptr.value
496
+ end
497
+
498
+ def test_to_axvalue_raises_for_unsupported_boxes
499
+ assert_raises(NotImplementedError) { NSEdgeInsets.new.to_ax }
500
+ end
501
+
502
+ def test_to_ax_for_ranges
503
+ assert_equal CFRangeMake(1,10).to_ax, (1..10 ).to_ax
504
+ assert_equal CFRangeMake(1, 9).to_ax, (1...10 ).to_ax
505
+ assert_equal CFRangeMake(0, 3).to_ax, (0..2 ).to_ax
506
+ end
507
+
508
+ def test_to_axvalue_for_ranges_raises_for_bad_ranges
509
+ assert_raises(ArgumentError) { (1..-10).to_ax }
510
+ assert_raises(ArgumentError) { (-5...10).to_ax }
511
+ end
512
+
513
+ def test_to_ax_on_other_objects
514
+ obj = Object.new
515
+ assert_equal obj.self, obj.to_ax
516
+ end
517
+
518
+
519
+ def test_to_ruby
520
+ assert_equal CGPointZero, CGPointZero .to_ax.to_ruby
521
+ assert_equal CGSizeMake(10,10), CGSizeMake(10,10).to_ax.to_ruby
522
+ assert_equal Range.new(1,10), CFRange.new(1,10).to_ax.to_ruby
523
+ end
524
+
525
+ def test_to_ruby_on_non_boxes
526
+ obj = Object.new
527
+ assert_equal obj.self, obj.to_ruby
528
+ end
529
+
530
+ end
531
+
532
+
533
+ class TestMiscCoreExtensions < MiniTest::Unit::TestCase
534
+
535
+ def test_to_point
536
+ p = CGPointMake(2,3)
537
+ assert_equal p, p.to_point
538
+
539
+ p = CGPointMake(1,3)
540
+ assert_equal p, p.to_a.to_point
541
+ end
542
+
543
+ def test_to_size
544
+ s = CGSizeMake(2,4)
545
+ assert_equal s, s.to_a.to_size
546
+ end
547
+
548
+ def test_to_rect
549
+ r = CGRectMake(6,7,8,9)
550
+ assert_equal r, r.to_a.map(&:to_a).flatten.to_rect
551
+ end
552
+
553
+ end
@@ -0,0 +1,63 @@
1
+ require 'test/runner'
2
+ require 'accessibility/debug'
3
+
4
+ class TestAccessibilityDebug < MiniTest::Unit::TestCase
5
+
6
+ def mock_element
7
+ @mock = Object.new
8
+ def @mock.bounds; CGRectMake(100,100,100,100); end
9
+ @mock
10
+ end
11
+
12
+ def test_debug_setting
13
+ assert_respond_to Accessibility::Debug, :on?
14
+ assert_respond_to Accessibility::Debug, :on=
15
+ end
16
+
17
+ def test_highlight_returns_created_window
18
+ w = Accessibility::Debug.highlight mock_element
19
+ assert_kind_of NSWindow, w
20
+ assert_respond_to w, :stop
21
+ ensure
22
+ w.close if w
23
+ end
24
+
25
+ def test_highlight_can_take_a_timeout
26
+ w = Accessibility::Debug.highlight mock_element, timeout: 0.1
27
+ assert w.visible?
28
+ sleep 0.15
29
+ refute w.visible? # Not exactly the assertion I want, but close enough
30
+ ensure
31
+ w.close if w
32
+ end
33
+
34
+ def test_highlight_can_have_custom_colour
35
+ w = Accessibility::Debug.highlight mock_element, color: NSColor.cyanColor
36
+ assert w.backgroundColor == NSColor.cyanColor
37
+ w.close
38
+
39
+ # test both spellings of colour
40
+ w = Accessibility::Debug.highlight mock_element, colour: NSColor.purpleColor
41
+ assert w.backgroundColor == NSColor.purpleColor
42
+ end
43
+
44
+ def test_highlight_highlights_correct_rect
45
+ w = Accessibility::Debug.highlight mock_element
46
+ assert_equal w.frame, mock_element.bounds.flip!
47
+ end
48
+
49
+ end
50
+
51
+ class TestCGRectExtensions < MiniTest::Unit::TestCase
52
+
53
+ def test_flipping
54
+ size = NSScreen.mainScreen.frame.size
55
+ assert_equal CGRectMake( 0, size.height, 0, 0), CGRectZero.dup.flip!
56
+ assert_equal CGRectMake(100, size.height-200,100,100), CGRectMake(100,100,100,100).flip!
57
+ end
58
+
59
+ def test_flipping_twice_returns_to_original
60
+ assert_equal CGRectZero.dup, CGRectZero.dup.flip!.flip!
61
+ end
62
+
63
+ end
@@ -0,0 +1,75 @@
1
+ require 'test/helper'
2
+ require 'accessibility/dsl'
3
+
4
+
5
+ class TestAccessibilityDSL < MiniTest::Unit::TestCase
6
+
7
+ # LSP FTW
8
+ class DSL
9
+ include Accessibility::DSL
10
+ end
11
+
12
+ class LanguageTest < AX::Element
13
+ attr_reader :called_action
14
+ def actions= value; @actions = value end
15
+ def actions; @actions end
16
+ def perform action; @called_action = action end
17
+ def search *args; @search_args = args end
18
+ end
19
+
20
+ def dsl
21
+ @dsl ||= DSL.new
22
+ end
23
+
24
+ def element
25
+ @element ||= LanguageTest.new REF
26
+ end
27
+
28
+
29
+ def test_static_actions
30
+ def static_action action
31
+ dsl.send action, element
32
+ assert_equal action, element.called_action
33
+ end
34
+
35
+ static_action :press
36
+ static_action :show_menu
37
+ static_action :pick
38
+ static_action :decrement
39
+ static_action :confirm
40
+ static_action :increment
41
+ static_action :delete
42
+ static_action :cancel
43
+ static_action :hide
44
+ static_action :unhide
45
+ static_action :terminate
46
+ static_action :raise
47
+ end
48
+
49
+ def test_method_missing_forwards
50
+ element.actions = [:purple_rain]
51
+ dsl.purple_rain element
52
+ assert_equal :purple_rain, element.called_action
53
+
54
+ e = assert_raises(ArgumentError) { dsl.hack element }
55
+ assert_match /.hack. is not an action/, e.message
56
+
57
+ e = assert_raises(NoMethodError) { dsl.purple_rain 'A string' }
58
+ assert_match /undefined method/, e.message
59
+ end
60
+
61
+ def test_raise_can_still_raise_exception
62
+ assert_raises(ArgumentError) { dsl.raise ArgumentError }
63
+ assert_raises(NoMethodError) { dsl.raise NoMethodError }
64
+ end
65
+
66
+ def test_wait_for_demands_a_parent_or_ancestor
67
+ assert_raises(ArgumentError) { dsl.wait_for :bacon }
68
+ end
69
+
70
+ def test_wait_for_allows_filtering_by_parent
71
+ result = dsl.wait_for(:dude, parent: :hippie, ancestor: element)
72
+ assert_equal [:dude, { parent: :hippie }], result
73
+ end
74
+
75
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/runner'
2
+ require 'accessibility/errors'
3
+
4
+ class TestAccessibilityErrors < MiniTest::Unit::TestCase
5
+
6
+ def test_search_failure_is_kind_of_no_method_error
7
+ assert_includes Accessibility::SearchFailure.ancestors, NoMethodError
8
+ end
9
+
10
+ end