AXElements 0.9.0 → 1.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.yardopts +0 -4
  2. data/README.markdown +22 -17
  3. data/Rakefile +1 -1
  4. data/ext/accessibility/key_coder/extconf.rb +1 -1
  5. data/ext/accessibility/key_coder/key_coder.c +2 -4
  6. data/lib/accessibility.rb +3 -3
  7. data/lib/accessibility/core.rb +948 -0
  8. data/lib/accessibility/dsl.rb +30 -186
  9. data/lib/accessibility/enumerators.rb +1 -0
  10. data/lib/accessibility/factory.rb +78 -134
  11. data/lib/accessibility/graph.rb +5 -9
  12. data/lib/accessibility/highlighter.rb +86 -0
  13. data/lib/accessibility/{pretty_printer.rb → pp_inspector.rb} +4 -3
  14. data/lib/accessibility/qualifier.rb +3 -5
  15. data/lib/accessibility/screen_recorder.rb +217 -0
  16. data/lib/accessibility/statistics.rb +57 -0
  17. data/lib/accessibility/translator.rb +23 -32
  18. data/lib/accessibility/version.rb +2 -22
  19. data/lib/ax/application.rb +20 -159
  20. data/lib/ax/element.rb +42 -32
  21. data/lib/ax/scroll_area.rb +5 -6
  22. data/lib/ax/systemwide.rb +1 -33
  23. data/lib/ax_elements.rb +1 -9
  24. data/lib/ax_elements/core_graphics_workaround.rb +5 -0
  25. data/lib/ax_elements/nsarray_compat.rb +17 -97
  26. data/lib/ax_elements/vendor/inflection_data.rb +66 -0
  27. data/lib/ax_elements/vendor/inflections.rb +176 -0
  28. data/lib/ax_elements/vendor/inflector.rb +306 -0
  29. data/lib/minitest/ax_elements.rb +180 -0
  30. data/lib/mouse.rb +227 -0
  31. data/lib/rspec/expectations/ax_elements.rb +234 -0
  32. data/rakelib/gem.rake +3 -12
  33. data/rakelib/test.rake +15 -0
  34. data/test/helper.rb +20 -10
  35. data/test/integration/accessibility/test_core.rb +18 -0
  36. data/test/integration/accessibility/test_dsl.rb +40 -38
  37. data/test/integration/accessibility/test_enumerators.rb +1 -0
  38. data/test/integration/accessibility/test_graph.rb +0 -1
  39. data/test/integration/accessibility/test_qualifier.rb +2 -2
  40. data/test/integration/ax/test_application.rb +2 -9
  41. data/test/integration/ax/test_element.rb +0 -40
  42. data/test/integration/minitest/test_ax_elements.rb +89 -0
  43. data/test/integration/rspec/expectations/test_ax_elements.rb +102 -0
  44. data/test/sanity/accessibility/test_factory.rb +2 -2
  45. data/test/sanity/accessibility/test_highlighter.rb +56 -0
  46. data/test/sanity/accessibility/{test_pretty_printer.rb → test_pp_inspector.rb} +9 -9
  47. data/test/sanity/accessibility/test_statistics.rb +57 -0
  48. data/test/sanity/ax/test_application.rb +1 -16
  49. data/test/sanity/ax/test_element.rb +2 -2
  50. data/test/sanity/ax_elements/test_nsobject_inspect.rb +2 -4
  51. data/test/sanity/minitest/test_ax_elements.rb +17 -0
  52. data/test/sanity/rspec/expectations/test_ax_elements.rb +15 -0
  53. data/test/sanity/test_mouse.rb +22 -0
  54. data/test/test_core.rb +454 -0
  55. metadata +44 -69
  56. data/History.markdown +0 -41
  57. data/lib/accessibility/system_info.rb +0 -230
  58. data/lib/ax_elements/active_support_selections.rb +0 -10
  59. data/lib/ax_elements/mri.rb +0 -57
  60. data/test/sanity/accessibility/test_version.rb +0 -15
@@ -5,13 +5,13 @@ require 'ax/application'
5
5
  class TestAccessibilityElementFactory < MiniTest::Unit::TestCase
6
6
 
7
7
  def window
8
- @@window ||= REF.to_ruby.children.find { |x| x.role == KAXWindowRole }
8
+ @@window ||= REF.children.find { |x| x.role == KAXWindowRole }
9
9
  end
10
10
 
11
11
  def scroll_area
12
12
  @@scroll_area ||= window.children.find { |x|
13
13
  x.attributes.include?(:description) &&
14
- x.description == 'Test Web Area'
14
+ x.attribute(:description) == 'Test Web Area'
15
15
  }
16
16
  end
17
17
 
@@ -0,0 +1,56 @@
1
+ require 'test/runner'
2
+ require 'accessibility/highlighter'
3
+
4
+ class TestHighlighter < MiniTest::Unit::TestCase
5
+
6
+ def bounds
7
+ CGRectMake(100, 100, 100, 100)
8
+ end
9
+
10
+ def test_highlight_returns_created_window
11
+ w = Accessibility::Highlighter.new bounds
12
+ assert_kind_of NSWindow, w
13
+ assert_respond_to w, :stop
14
+ ensure
15
+ w.close if w
16
+ end
17
+
18
+ def test_highlight_can_take_a_timeout
19
+ w = Accessibility::Highlighter.new bounds, timeout: 0.1
20
+ assert w.visible?
21
+ sleep 0.15
22
+ refute w.visible? # Not exactly the assertion I want, but close enough
23
+ ensure
24
+ w.close if w
25
+ end
26
+
27
+ def test_highlight_can_have_custom_colour
28
+ w = Accessibility::Highlighter.new bounds, color: NSColor.cyanColor
29
+ assert w.backgroundColor == NSColor.cyanColor
30
+ w.close
31
+
32
+ # test both spellings of colour
33
+ w = Accessibility::Highlighter.new bounds, colour: NSColor.purpleColor
34
+ assert w.backgroundColor == NSColor.purpleColor
35
+ end
36
+
37
+ def test_highlight_highlights_correct_rect
38
+ w = Accessibility::Highlighter.new bounds
39
+ assert_equal w.frame, bounds.flip!
40
+ end
41
+
42
+ end
43
+
44
+ class TestCGRectExtensions < MiniTest::Unit::TestCase
45
+
46
+ def test_flipping
47
+ size = NSScreen.mainScreen.frame.size
48
+ assert_equal CGRectMake(0, size.height, 0, 0), CGRectZero.dup.flip!
49
+ assert_equal CGRectMake(100, size.height-200, 100, 100), CGRectMake(100,100,100,100).flip!
50
+ end
51
+
52
+ def test_flipping_twice_returns_to_original
53
+ assert_equal CGRectZero.dup, CGRectZero.dup.flip!.flip!
54
+ end
55
+
56
+ end
@@ -1,9 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
4
- include Accessibility::PrettyPrinter
3
+ class TestAccessibilityPPInspector < MiniTest::Unit::TestCase
4
+ include Accessibility::PPInspector
5
5
 
6
- # expected API for PrettyPrinter module
6
+ # expected API for PPInspector module
7
7
  attr_reader :attributes
8
8
  def attribute attr; @attribute; end
9
9
  def size_of attr; @size_of; end
@@ -18,10 +18,10 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
18
18
  assert_match /value=3.14/, pp_identifier
19
19
 
20
20
  @attribute = ''
21
- assert_match EMPTY_STRING, pp_identifier.to_s
21
+ assert_match EMPTY_STRING, pp_identifier
22
22
 
23
23
  @attribute = nil
24
- assert_match EMPTY_STRING, pp_identifier.to_s
24
+ assert_match EMPTY_STRING, pp_identifier
25
25
  end
26
26
 
27
27
  def test_identifier_using_title
@@ -43,8 +43,8 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
43
43
  @attribute = 'roflcopter'
44
44
  assert_match /roflcopter/, pp_identifier
45
45
 
46
- @attribute = ''
47
- assert_equal EMPTY_STRING, pp_identifier.to_s
46
+ @attribute = NSString.string
47
+ assert_equal EMPTY_STRING, pp_identifier
48
48
 
49
49
  @attribute = 26
50
50
  assert_match /26/, pp_identifier
@@ -62,11 +62,11 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
62
62
 
63
63
  def test_identifier_empty_string_as_final_fallback
64
64
  @attributes = NSArray.array
65
- assert_equal EMPTY_STRING, pp_identifier.to_s
65
+ assert_equal EMPTY_STRING, pp_identifier
66
66
  end
67
67
 
68
68
  def test_position
69
- @attribute = CGPoint.new
69
+ @attribute = CGPointZero
70
70
  assert_match /\(0\.0, 0\.0\)/, pp_position
71
71
 
72
72
  @attribute = CGPoint.new(3.14, -5)
@@ -0,0 +1,57 @@
1
+ require 'test/runner'
2
+ require 'accessibility/statistics'
3
+
4
+ class TestAccessibilityStatistics < MiniTest::Unit::TestCase
5
+
6
+ def setup
7
+ @stats = Accessibility::Statistics.new
8
+ @q = @stats.instance_variable_get :@q
9
+ @s = @stats.instance_variable_get :@stats
10
+ end
11
+
12
+ def test_global_constant
13
+ assert_instance_of Accessibility::Statistics, STATS
14
+ end
15
+
16
+ def test_collects_stats
17
+ assert_equal 0, @s[:pie]
18
+ assert_equal 0, @s[:cake]
19
+ @stats.increment :cake
20
+ @q.sync { }
21
+ assert_equal 1, @s[:cake]
22
+ assert_equal 0, @s[:pie]
23
+ @stats.increment :cake
24
+ @q.sync { }
25
+ assert_equal 2, @s[:cake]
26
+ assert_equal 0, @s[:pie]
27
+ @stats.increment :pie
28
+ @q.sync { }
29
+ assert_equal 2, @s[:cake]
30
+ assert_equal 1, @s[:pie]
31
+ end
32
+
33
+ def test_concurrency
34
+ loops = 1_000_000
35
+ loops.times do @stats.increment :pie end
36
+ @q.sync { }
37
+ assert_equal loops, @s[:pie]
38
+ end
39
+
40
+ def test_to_s
41
+ 100.times do @stats.increment :cake end
42
+ 2.times do @stats.increment :pie end
43
+ 50.times do @stats.increment :long_attribute_name end
44
+ expected = <<-EOS
45
+ ######################
46
+ # AX Call Statistics #
47
+ ######################
48
+ cake...................100
49
+ long_attribute_name.....50
50
+ pie......................2
51
+ EOS
52
+ assert_equal expected, @stats.to_s
53
+ end
54
+
55
+ # @todo bench_increment
56
+
57
+ end
@@ -24,17 +24,6 @@ class TestAXApplication < MiniTest::Unit::TestCase
24
24
  assert_match /\sfocused\[(?:✔|✘)\]/, app.inspect
25
25
  end
26
26
 
27
- def tset_action_methods_forward_to_perform
28
- def app.perform name
29
- [:cracker_jacks, name]
30
- end
31
-
32
- assert_equal [:cracker_jacks, :terminate], app.terminate
33
- assert_equal [:cracker_jacks, :force_terminate], app.terminate!
34
- assert_equal [:cracker_jacks, :hide], app.hide
35
- assert_equal [:cracker_jacks, :unhide], app.unhide
36
- end
37
-
38
27
  def test_terminate
39
28
  got_called = false
40
29
  mock = Object.new
@@ -100,15 +89,11 @@ class TestAXApplication < MiniTest::Unit::TestCase
100
89
  end
101
90
 
102
91
  def test_info_plist
103
- assert_equal 'transmute', app.info_plist['CFBundleIconFile']
92
+ assert_equal 'hmmmmm.icns', app.info_plist['CFBundleIconFile']
104
93
  end
105
94
 
106
95
  def test_version
107
96
  assert_equal '1.0', app.version
108
97
  end
109
98
 
110
- def test_ancestor
111
- assert_nil app.ancestor(:menu)
112
- end
113
-
114
99
  end
@@ -51,7 +51,7 @@ class TestAXElement < MiniTest::Unit::TestCase
51
51
  end
52
52
 
53
53
  # the nil case
54
- center_test CGPoint.new, CGSize.new, CGPoint.new
54
+ center_test CGPointZero, CGSizeZero, CGPointZero
55
55
  # simple square with origin at zero
56
56
  center_test [0,0], [2,2], [1,1]
57
57
  # simple square in positive positive quadrant
@@ -71,7 +71,7 @@ class TestSearchResultBlankness < MiniTest::Unit::TestCase
71
71
 
72
72
  def test_array_blank
73
73
  [
74
- Array.new,
74
+ NSArray.array,
75
75
  [true]
76
76
  ].each do |ary|
77
77
  assert_equal ary.empty?, ary.blank?
@@ -1,13 +1,11 @@
1
1
  require 'test/runner'
2
2
 
3
- if on_macruby?
4
3
  class TestNSObjectExtensions < MiniTest::Unit::TestCase
5
4
  # keeping this test just to make sure the version of MacRuby
6
5
  # being used is new enough
7
6
  def test_inspecting
8
- url = NSURL.URLWithString('http://marketcircle.com/')
9
- assert_equal url.description, url.inspect
7
+ url = NSURL.URLWithString('http://marketcircle.com/')
8
+ assert_equal url.description, url.inspect
10
9
  end
11
10
  end
12
- end
13
11
 
@@ -0,0 +1,17 @@
1
+ require 'test/runner'
2
+ require 'minitest/ax_elements'
3
+
4
+ class TestMiniTestAssertions < MiniTest::Unit::TestCase
5
+
6
+ def test_methods_are_loaded
7
+ assert_respond_to self, :assert_has_child
8
+ assert_respond_to self, :assert_has_descendent
9
+ assert_respond_to self, :assert_has_descendant
10
+ assert_respond_to self, :assert_shortly_has
11
+ assert_respond_to self, :refute_has_child
12
+ assert_respond_to self, :refute_has_descendent
13
+ assert_respond_to self, :refute_has_descendant
14
+ assert_respond_to self, :refute_shortly_has
15
+ end
16
+
17
+ end
@@ -0,0 +1,15 @@
1
+ require 'test/runner'
2
+ require 'rspec/expectations/ax_elements'
3
+
4
+ class TestRSpecMatchers < MiniTest::Unit::TestCase
5
+
6
+ def test_defined
7
+ assert TopLevel.method(:have_child)
8
+ assert TopLevel.method(:have_descendent)
9
+ assert TopLevel.method(:have_descendant)
10
+ assert TopLevel.method(:shortly_have_child)
11
+ assert TopLevel.method(:shortly_have_descendent)
12
+ assert TopLevel.method(:shortly_have_descendant)
13
+ end
14
+
15
+ end
@@ -0,0 +1,22 @@
1
+ require 'test/runner'
2
+ require 'mouse'
3
+
4
+ class TestMouseModule < MiniTest::Unit::TestCase
5
+
6
+ def distance point1, point2
7
+ x = point1.x - point2.x
8
+ y = point1.y - point2.y
9
+ Math.sqrt((x**2) + (y**2))
10
+ end
11
+
12
+ def test_move_to
13
+ point = CGPoint.new(100, 100)
14
+ Mouse.move_to point
15
+ assert_in_delta 0, distance(point,Mouse.current_position), 1.0
16
+
17
+ point = CGPoint.new(rand(700)+150, rand(500)+100)
18
+ Mouse.move_to point
19
+ assert_in_delta 0, distance(point,Mouse.current_position), 1.0
20
+ end
21
+
22
+ end
data/test/test_core.rb ADDED
@@ -0,0 +1,454 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'test/helper'
4
+ require 'accessibility/core'
5
+
6
+
7
+ class TestAccessibilityElement < MiniTest::Unit::TestCase
8
+
9
+ def child name
10
+ window.children.find { |item|
11
+ (block_given? ? yield(item) : true) if item.role == name
12
+ }
13
+ end
14
+
15
+ def app; @@app ||= REF end
16
+ def window; @@window ||= app.attribute(KAXWindowsAttribute).first end
17
+ def slider; @@slider ||= child KAXSliderRole end
18
+ def check_box; @@check_box ||= child KAXCheckBoxRole end
19
+ def pop_up; @@pop_up ||= child KAXPopUpButtonRole end
20
+ def search_box; @@search_box ||= child KAXTextFieldRole end
21
+ def static_text; @@static_text ||= child(KAXStaticTextRole) { |x| x.value.match /My Little Pony/ } end
22
+ def yes_button; @@yes_button ||= child(KAXButtonRole) { |x| x.attribute(KAXTitleAttribute) == 'Yes' } end
23
+ def bye_button; @@bye_button ||= child(KAXButtonRole) { |x| x.attribute(KAXTitleAttribute) == 'Bye!' } end
24
+ def no_button; @@no_button ||= child(KAXButtonRole) { |x| x.attribute(KAXTitleAttribute) == 'No' } end
25
+ def web_area; @@web_area ||= child("AXScrollArea") { |x| x.attribute('AXDescription' ) == 'Test Web Area' }.children.first end
26
+ def text_area; @@text_area ||= child("AXScrollArea") { |x| x.attributes.include?('AXIdentifier') && x.attribute('AXIdentifier') == 'Text Area' }.children.first end
27
+
28
+ def invalid_ref
29
+ bye_button # guarantee that it is cached
30
+ @@dead ||= no_button.perform KAXPressAction
31
+ bye_button
32
+ end
33
+
34
+
35
+ def test_equality
36
+ assert_equal app, app
37
+ assert_equal app, REF
38
+ assert_equal window, window
39
+ refute_equal app, window
40
+ end
41
+
42
+ ##
43
+ # AFAICT every accessibility object **MUST** have attributes, so
44
+ # there are no tests to check what happens when they do not exist;
45
+ # though I am quite sure that AXElements will raise an exception.
46
+
47
+ def test_attributes
48
+ attrs = app.attributes
49
+ assert_includes attrs, KAXRoleAttribute
50
+ assert_includes attrs, KAXChildrenAttribute
51
+ assert_includes attrs, KAXTitleAttribute
52
+ assert_includes attrs, KAXMenuBarAttribute
53
+
54
+ assert_empty invalid_ref.attributes, 'Dead elements should have no attrs'
55
+ end
56
+
57
+ def test_attribute
58
+ assert_equal 'AXElementsTester', window.attribute(KAXTitleAttribute )
59
+ assert_equal false, window.attribute(KAXFocusedAttribute)
60
+ assert_equal CGSize.new(555,529), window.attribute(KAXSizeAttribute )
61
+ assert_equal app, window.attribute(KAXParentAttribute )
62
+ assert_equal 10..19, window.attribute("AXPie" )
63
+
64
+ assert_nil window.attribute(KAXGrowAreaAttribute), 'KAXErrorNoValue == nil'
65
+
66
+ assert_nil invalid_ref.attribute(KAXRoleAttribute), 'Dead element == nil'
67
+ assert_empty invalid_ref.attribute(KAXChildrenAttribute)
68
+
69
+ assert_raises(ArgumentError) { app.attribute('MADE_UP_ATTR') }
70
+ end
71
+
72
+ def test_role
73
+ assert_equal KAXApplicationRole, app.role
74
+ assert_equal KAXWindowRole, window.role
75
+ end
76
+
77
+ def test_subrole
78
+ assert_equal KAXStandardWindowSubrole, window.subrole
79
+ assert_nil web_area.subrole
80
+ end
81
+
82
+ def test_children
83
+ assert_equal app.attribute(KAXChildrenAttribute), app.children
84
+ end
85
+
86
+ def test_value
87
+ assert_equal check_box.attribute(KAXValueAttribute), check_box.value
88
+ assert_equal slider.attribute(KAXValueAttribute), slider.value
89
+ end
90
+
91
+ def test_pid
92
+ assert_equal PID, app.pid
93
+ assert_equal PID, window.pid
94
+ assert_equal 0, Accessibility::Element.system_wide.pid # special case
95
+ end
96
+
97
+ def test_invalid?
98
+ assert_equal false, app.invalid?
99
+ assert_equal true, invalid_ref.invalid?
100
+ assert_equal false, window.invalid?
101
+ end
102
+
103
+ def test_size_of
104
+ assert_equal app.children.size, app.size_of(KAXChildrenAttribute)
105
+ assert_equal 0, pop_up.size_of(KAXChildrenAttribute)
106
+
107
+ assert_equal 0, invalid_ref.size_of(KAXChildrenAttribute), 'Dead == 0'
108
+ end
109
+
110
+ def test_writable?
111
+ refute app.writable? KAXTitleAttribute
112
+ assert window.writable? KAXMainAttribute
113
+
114
+ refute invalid_ref.writable?(KAXRoleAttribute), 'Dead is always false'
115
+ end
116
+
117
+ def test_set_number
118
+ [25, 75, 50].each do |number|
119
+ assert_equal number, slider.set(KAXValueAttribute, number)
120
+ assert_equal number, slider.value
121
+ end
122
+ end
123
+
124
+ def test_set_string
125
+ [Time.now.to_s, ''].each do |string|
126
+ assert_equal string, search_box.set(KAXValueAttribute, string)
127
+ assert_equal string, search_box.value
128
+ end
129
+ end
130
+
131
+ def test_set_wrapped
132
+ text_area.set KAXValueAttribute, 'hey-o'
133
+
134
+ text_area.set KAXSelectedTextRangeAttribute, 0..3
135
+ assert_equal 0..3, text_area.attribute(KAXSelectedTextRangeAttribute)
136
+
137
+ text_area.set KAXSelectedTextRangeAttribute, 1...4
138
+ assert_equal 1..3, text_area.attribute(KAXSelectedTextRangeAttribute)
139
+ ensure
140
+ text_area.set KAXValueAttribute, ''
141
+ end
142
+
143
+ def test_set_attr_handles_errors
144
+ assert_raises(ArgumentError) { app.set 'FAKE', true }
145
+ assert_raises(ArgumentError) { invalid_ref.set KAXTitleAttribute, 'hi' }
146
+ end
147
+
148
+ def test_parameterized_attributes
149
+ assert_empty app.parameterized_attributes
150
+
151
+ attrs = static_text.parameterized_attributes
152
+ assert_includes attrs, KAXStringForRangeParameterizedAttribute
153
+ assert_includes attrs, KAXLineForIndexParameterizedAttribute
154
+ assert_includes attrs, KAXBoundsForRangeParameterizedAttribute
155
+
156
+ assert_empty invalid_ref.parameterized_attributes, 'Dead should always be empty'
157
+ end
158
+
159
+ def test_parameterized_attribute
160
+ expected = 'My Li'
161
+
162
+ attr = static_text.parameterized_attribute(KAXStringForRangeParameterizedAttribute, 0..4)
163
+ assert_equal expected, attr
164
+
165
+ attr = static_text.parameterized_attribute(KAXAttributedStringForRangeParameterizedAttribute, 0..4)
166
+ assert_equal expected, attr.string
167
+
168
+ assert_nil invalid_ref.parameterized_attribute(KAXStringForRangeParameterizedAttribute, 0..0),
169
+ 'dead elements should return nil for any parameterized attribute'
170
+
171
+ # Should add a test case to test the no value case, but it will have
172
+ # to be fabricated in the test app.
173
+
174
+ assert_raises(ArgumentError) {
175
+ app.parameterized_attribute(KAXStringForRangeParameterizedAttribute, 0..1)
176
+ }
177
+ end
178
+
179
+ def test_actions
180
+ assert_empty app.actions
181
+ assert_equal [KAXPressAction], yes_button.actions
182
+ end
183
+
184
+ def test_perform_action
185
+ 2.times do # twice so it should be back where it started
186
+ val = check_box.value
187
+ check_box.perform KAXPressAction
188
+ refute_equal val, check_box.value
189
+ end
190
+
191
+ val = slider.value
192
+ slider.perform KAXIncrementAction
193
+ assert slider.value > val
194
+
195
+ val = slider.value
196
+ slider.perform KAXDecrementAction
197
+ assert slider.value < val
198
+
199
+ assert_raises(ArgumentError) { app.perform nil }
200
+ end
201
+
202
+ ##
203
+ # The keyboard simulation stuff is a bit weird...
204
+
205
+ def test_post
206
+ events = [[0x56,true], [0x56,false], [0x54,true], [0x54,false]]
207
+ string = '42'
208
+
209
+ search_box.set KAXFocusedAttribute, true
210
+ app.post events
211
+
212
+ assert_equal string, search_box.value
213
+
214
+ ensure # reset for next test
215
+ search_box.set KAXValueAttribute, ''
216
+ end
217
+
218
+ def test_key_rate
219
+ assert_equal 0.009, Accessibility::Element.key_rate
220
+ [
221
+ [0.9, :very_slow],
222
+ [0.09, :slow],
223
+ [0.009, :normal],
224
+ [0.0009, :fast],
225
+ [0.00009, :zomg]
226
+ ].each do |num, name|
227
+ Accessibility::Element.key_rate = name
228
+ assert_equal num, Accessibility::Element.key_rate
229
+ end
230
+ ensure
231
+ Accessibility::Element.key_rate = :default
232
+ end
233
+
234
+ def test_element_at
235
+ point = no_button.attribute(KAXPositionAttribute)
236
+
237
+ element = app.element_at point
238
+ assert_equal no_button, element, "#{no_button.inspect} and #{element.inspect}"
239
+
240
+ element = Accessibility::Element.system_wide.element_at point
241
+ assert_equal no_button, element, "#{no_button.inspect} and #{element.inspect}"
242
+
243
+ assert_respond_to element, :role
244
+
245
+ # skip 'Need to find a way to guarantee an empty spot on the screen to return nil'
246
+ # test manually for now :(
247
+ end
248
+
249
+ def test_application_for
250
+ assert_equal app, Accessibility::Element.application_for(PID)
251
+
252
+ assert_raises(ArgumentError) { Accessibility::Element.application_for 0 }
253
+ end
254
+
255
+ def test_system_wide
256
+ assert_equal AXUIElementCreateSystemWide(), Accessibility::Element.system_wide
257
+ end
258
+
259
+ def test_application
260
+ assert_equal app, app.application
261
+ assert_equal app, window.application
262
+ end
263
+
264
+ def test_set_timeout_for
265
+ assert_equal 10, app.set_timeout_to(10)
266
+ assert_equal 0, app.set_timeout_to(0)
267
+ end
268
+
269
+
270
+
271
+ def assert_error args, should_raise: klass, with_fragments: msgs
272
+ e = assert_raises(klass) { (@derp || app).handle_error *args }
273
+ assert_match /test_core.rb:272/, e.backtrace.first unless RUNNING_COMPILED
274
+ msgs.each { |msg| assert_match msg, e.message }
275
+ end
276
+
277
+ def test_handle_errors
278
+ app_inspect = Regexp.new(Regexp.escape(app.inspect))
279
+
280
+ assert_error [KAXErrorFailure],
281
+ should_raise: RuntimeError,
282
+ with_fragments: [/system failure/, app_inspect]
283
+
284
+ assert_error [KAXErrorIllegalArgument],
285
+ should_raise: ArgumentError,
286
+ with_fragments: [/is not an AXUIElementRef/, app_inspect]
287
+
288
+ assert_error [KAXErrorIllegalArgument, :cake],
289
+ should_raise: ArgumentError,
290
+ with_fragments: [/is not a legal argument/, /the element/, app_inspect, /cake/]
291
+
292
+ assert_error [KAXErrorIllegalArgument, 'cake', 'chocolate'],
293
+ should_raise: ArgumentError,
294
+ with_fragments: [/can't get\/set "cake" with\/to "chocolate"/, app_inspect]
295
+
296
+ p = CGPoint.new(1,3)
297
+ assert_error [KAXErrorIllegalArgument, p, nil, nil],
298
+ should_raise: ArgumentError,
299
+ with_fragments: [/The point #{p.inspect}/, app_inspect]
300
+
301
+ assert_error [KAXErrorInvalidUIElement],
302
+ should_raise: ArgumentError,
303
+ with_fragments: [/no longer a valid reference/, app_inspect]
304
+
305
+ assert_error [KAXErrorInvalidUIElementObserver, :pie, :cake],
306
+ should_raise: ArgumentError,
307
+ with_fragments: [/no longer support/]
308
+
309
+ assert_error [KAXErrorCannotComplete],
310
+ should_raise: RuntimeError,
311
+ with_fragments: [/An unspecified error/, app_inspect, /:\(/]
312
+
313
+ @derp = Accessibility::Element.application_for pid_for 'com.apple.finder'
314
+ def @derp.pid; false end
315
+ assert_error [KAXErrorCannotComplete],
316
+ should_raise: RuntimeError,
317
+ with_fragments: [/Application for pid/, /Maybe it crashed\?/]
318
+ @derp = nil
319
+
320
+ assert_error [KAXErrorAttributeUnsupported, :cake],
321
+ should_raise: ArgumentError,
322
+ with_fragments: [/does not have/, /:cake attribute/, app_inspect]
323
+
324
+ assert_error [KAXErrorActionUnsupported, :pie],
325
+ should_raise: ArgumentError,
326
+ with_fragments: [/does not have/, /:pie action/, app_inspect]
327
+
328
+ assert_error [KAXErrorNotificationUnsupported, :cheese],
329
+ should_raise: ArgumentError,
330
+ with_fragments: [/no longer support/]
331
+
332
+ assert_error [KAXErrorNotImplemented],
333
+ should_raise: NotImplementedError,
334
+ with_fragments: [/does not work with AXAPI/, app_inspect]
335
+
336
+ assert_error [KAXErrorNotificationAlreadyRegistered, :lamp],
337
+ should_raise: ArgumentError,
338
+ with_fragments: [/no longer support/]
339
+
340
+ assert_error [KAXErrorNotificationNotRegistered, :peas],
341
+ should_raise: RuntimeError,
342
+ with_fragments: [/no longer support/]
343
+
344
+ assert_error [KAXErrorAPIDisabled],
345
+ should_raise: RuntimeError,
346
+ with_fragments: [/AXAPI has been disabled/]
347
+
348
+ assert_error [KAXErrorNoValue],
349
+ should_raise: RuntimeError,
350
+ with_fragments: [/internal error/]
351
+
352
+ assert_error [KAXErrorParameterizedAttributeUnsupported, :oscar],
353
+ should_raise: ArgumentError,
354
+ with_fragments: [/does not have/, /:oscar parameterized attribute/, app_inspect]
355
+
356
+ assert_error [KAXErrorNotEnoughPrecision],
357
+ should_raise: RuntimeError,
358
+ with_fragments: [/not enough precision/, '¯\(°_o)/¯']
359
+
360
+ exception = assert_raises(RuntimeError) { app.send(:handle_error, 0) }
361
+ assert_match /assertion failed/, exception.message
362
+
363
+ assert_error [99],
364
+ should_raise: RuntimeError,
365
+ with_fragments: [/unknown error code/, /99/, app_inspect]
366
+ end
367
+
368
+ end
369
+
370
+
371
+ class TestToAXToRubyHooks < MiniTest::Unit::TestCase
372
+
373
+ def test_to_ax
374
+ value = CGPointZero.to_ax
375
+ ptr = Pointer.new CGPoint.type
376
+ AXValueGetValue(value, 1, ptr)
377
+ assert_equal CGPointZero, ptr.value, 'point makes a value'
378
+
379
+ value = CGSizeZero.to_ax
380
+ ptr = Pointer.new CGSize.type
381
+ AXValueGetValue(value, 2, ptr)
382
+ assert_equal CGSizeZero, ptr.value, 'size makes a value'
383
+
384
+ value = CGRectZero.to_ax
385
+ ptr = Pointer.new CGRect.type
386
+ AXValueGetValue(value, 3, ptr)
387
+ assert_equal CGRectZero, ptr.value, 'rect makes a value'
388
+
389
+ range = CFRange.new(5, 4)
390
+ value = range.to_ax
391
+ ptr = Pointer.new CFRange.type
392
+ AXValueGetValue(value, 4, ptr)
393
+ assert_equal range, ptr.value, 'range makes a value'
394
+
395
+ assert_equal CFRangeMake(1,10).to_ax, (1..10 ).to_ax
396
+ assert_equal CFRangeMake(1, 9).to_ax, (1...10 ).to_ax
397
+ assert_equal CFRangeMake(0, 3).to_ax, (0..2 ).to_ax
398
+
399
+ assert_raises(ArgumentError) { (1..-10).to_ax }
400
+ assert_raises(ArgumentError) { (-5...10).to_ax }
401
+ assert_raises(NotImplementedError) { NSEdgeInsets.new.to_ax }
402
+
403
+ assert_equal Object, Object.to_ax
404
+ assert_equal 10, 10.to_ax
405
+ end
406
+
407
+ def test_to_ruby
408
+ assert_equal CGPointZero, CGPointZero .to_ax.to_ruby
409
+ assert_equal CGSize.new(10,10), CGSize.new(10,10) .to_ax.to_ruby
410
+ assert_equal CGRectMake(1,2,3,4), CGRectMake(1,2,3,4).to_ax.to_ruby
411
+ assert_equal 1..10, CFRange.new(1, 10) .to_ax.to_ruby
412
+ assert_equal Range.new(1,10), CFRange.new(1,10) .to_ax.to_ruby
413
+ assert_equal Object, Object.to_ruby
414
+ end
415
+
416
+ end
417
+
418
+
419
+ class TestMiscCoreExtensions < MiniTest::Unit::TestCase
420
+
421
+ def test_to_point
422
+ p = CGPoint.new(2,3)
423
+ assert_equal p, p.to_point
424
+
425
+ p = CGPoint.new(1,3)
426
+ assert_equal p, p.to_a.to_point
427
+ end
428
+
429
+ def test_to_size
430
+ s = CGSize.new(2,4)
431
+ assert_equal s, s.to_a.to_size
432
+ end
433
+
434
+ def test_to_rect
435
+ r = CGRectMake(6, 7, 8, 9)
436
+ assert_equal r, r.to_a.map(&:to_a).flatten.to_rect
437
+ end
438
+
439
+ def test_to_url
440
+ site = 'http://marketcircle.com/'
441
+ url = site.to_url
442
+ refute_nil url
443
+ assert_equal NSURL.URLWithString(site), url
444
+
445
+ file = 'file://localhost/Applications/Calculator.app/'
446
+ url = file.to_url
447
+ refute_nil url
448
+ assert_equal NSURL.fileURLWithPath('/Applications/Calculator.app/'), url
449
+
450
+ void = "not a url at all"
451
+ assert_nil void.to_url
452
+ end
453
+
454
+ end