AXElements 0.6.0beta2 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -2
- data/README.markdown +152 -88
- data/Rakefile +8 -103
- data/docs/Debugging.markdown +9 -2
- data/docs/KeyboardEvents.markdown +114 -49
- data/docs/Setting.markdown +1 -0
- data/docs/images/next_version.png +0 -0
- data/ext/accessibility/key_coder/extconf.rb +22 -0
- data/ext/accessibility/key_coder/key_coder.c +113 -0
- data/lib/AXElements.rb +2 -0
- data/lib/accessibility/core.rb +897 -0
- data/lib/accessibility/debug.rb +168 -0
- data/lib/accessibility/dsl.rb +697 -0
- data/lib/accessibility/enumerators.rb +104 -0
- data/lib/accessibility/errors.rb +32 -0
- data/lib/accessibility/factory.rb +153 -0
- data/lib/accessibility/graph.rb +150 -0
- data/lib/{ax_elements/inspector.rb → accessibility/pp_inspector.rb} +39 -28
- data/lib/accessibility/qualifier.rb +158 -0
- data/lib/accessibility/string.rb +494 -0
- data/lib/accessibility/translator.rb +178 -0
- data/lib/accessibility/version.rb +7 -0
- data/lib/accessibility.rb +79 -0
- data/lib/ax/application.rb +234 -0
- data/lib/{ax_elements/elements → ax}/button.rb +2 -0
- data/lib/ax/element.rb +518 -0
- data/lib/{ax_elements/elements → ax}/radio_button.rb +2 -0
- data/lib/ax/row.rb +37 -0
- data/lib/{ax_elements/elements → ax}/static_text.rb +2 -0
- data/lib/ax/systemwide.rb +86 -0
- data/lib/ax_elements/awesome_print.rb +25 -0
- data/lib/ax_elements/exception_workaround.rb +8 -0
- data/lib/ax_elements/nsarray_compat.rb +64 -0
- data/lib/ax_elements/vendor/inflection_data.rb +65 -0
- data/lib/ax_elements/vendor/inflections.rb +172 -0
- data/lib/ax_elements/vendor/inflector.rb +306 -0
- data/lib/ax_elements.rb +14 -25
- data/lib/minitest/ax_elements.rb +112 -12
- data/lib/mouse.rb +72 -46
- data/lib/rspec/expectations/ax_elements.rb +133 -6
- data/rakelib/doc.rake +13 -0
- data/rakelib/ext.rake +61 -0
- data/rakelib/gem.rake +28 -0
- data/rakelib/test.rake +53 -0
- data/test/helper.rb +11 -97
- data/test/integration/accessibility/test_core.rb +18 -0
- data/test/integration/accessibility/test_debug.rb +44 -0
- data/test/integration/accessibility/test_dsl.rb +225 -0
- data/test/integration/accessibility/test_enumerators.rb +122 -0
- data/test/integration/accessibility/test_errors.rb +38 -0
- data/test/integration/accessibility/test_notifications.rb +22 -0
- data/test/integration/accessibility/test_qualifier.rb +148 -0
- data/test/integration/ax/test_application.rb +56 -0
- data/test/integration/ax/test_element.rb +46 -0
- data/test/integration/ax/test_row.rb +23 -0
- data/test/integration/ax_elements/test_nsarray_compat.rb +43 -0
- data/test/integration/minitest/test_ax_elements.rb +98 -0
- data/test/integration/rspec/expectations/test_ax_elements.rb +58 -0
- data/test/integration/test_mouse.rb +35 -0
- data/test/sanity/accessibility/test_core.rb +553 -0
- data/test/sanity/accessibility/test_debug.rb +63 -0
- data/test/sanity/accessibility/test_dsl.rb +75 -0
- data/test/sanity/accessibility/test_errors.rb +10 -0
- data/test/sanity/accessibility/test_factory.rb +88 -0
- data/test/sanity/accessibility/test_pp_inspector.rb +110 -0
- data/test/sanity/accessibility/test_qualifier.rb +13 -0
- data/test/sanity/accessibility/test_string.rb +238 -0
- data/test/sanity/accessibility/test_translator.rb +145 -0
- data/test/sanity/ax/test_application.rb +90 -0
- data/test/sanity/ax/test_element.rb +80 -0
- data/test/sanity/ax/test_systemwide.rb +66 -0
- data/test/sanity/ax_elements/test_nsarray_compat.rb +16 -0
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +11 -0
- data/test/sanity/minitest/test_ax_elements.rb +15 -0
- data/test/sanity/rspec/expectations/test_ax_elements.rb +12 -0
- data/test/sanity/test_ax_elements.rb +10 -0
- data/test/sanity/test_mouse.rb +19 -0
- metadata +111 -93
- data/LICENSE.txt +0 -25
- data/ext/key_coder/extconf.rb +0 -6
- data/ext/key_coder/key_coder.m +0 -77
- data/lib/ax_elements/accessibility/enumerators.rb +0 -104
- data/lib/ax_elements/accessibility/graph.rb +0 -118
- data/lib/ax_elements/accessibility/language.rb +0 -347
- data/lib/ax_elements/accessibility/qualifier.rb +0 -73
- data/lib/ax_elements/accessibility.rb +0 -166
- data/lib/ax_elements/core.rb +0 -541
- data/lib/ax_elements/element.rb +0 -593
- data/lib/ax_elements/elements/application.rb +0 -88
- data/lib/ax_elements/elements/row.rb +0 -30
- data/lib/ax_elements/elements/systemwide.rb +0 -46
- data/lib/ax_elements/macruby_extensions.rb +0 -255
- data/lib/ax_elements/notification.rb +0 -37
- data/lib/ax_elements/version.rb +0 -9
- data/test/elements/test_application.rb +0 -72
- data/test/elements/test_row.rb +0 -27
- data/test/elements/test_systemwide.rb +0 -38
- data/test/test_accessibility.rb +0 -127
- data/test/test_blankness.rb +0 -26
- data/test/test_core.rb +0 -448
- data/test/test_element.rb +0 -939
- data/test/test_enumerators.rb +0 -81
- data/test/test_inspector.rb +0 -130
- data/test/test_language.rb +0 -157
- data/test/test_macruby_extensions.rb +0 -303
- data/test/test_mouse.rb +0 -5
- data/test/test_search_semantics.rb +0 -143
data/lib/minitest/ax_elements.rb
CHANGED
@@ -1,19 +1,119 @@
|
|
1
|
+
require 'ax/element'
|
2
|
+
require 'accessibility/qualifier'
|
3
|
+
|
1
4
|
##
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
# AXElements assertions for MiniTest.
|
6
|
+
# [Learn more about minitest.](https://github.com/seattlerb/minitest)
|
7
|
+
class MiniTest::Assertions
|
8
|
+
|
9
|
+
##
|
10
|
+
# Test that an element has a specific child. For example, test
|
11
|
+
# that a table has a row with certain contents. You can pass any
|
12
|
+
# filters that you normally would during a search, including a block.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# assert_has_child table, :row, static_text: { value: 'Mark' }
|
17
|
+
#
|
18
|
+
# @param [AX::Element]
|
19
|
+
# @param [#to_s]
|
20
|
+
# @param [Hash]
|
21
|
+
# @return [AX::Element]
|
22
|
+
def assert_has_child parent, kind, filters = {}, &block
|
23
|
+
msg = message {
|
24
|
+
child = ax_search_id kind, filters, block
|
25
|
+
"Expected #{parent.inspect} to have #{child} as a child"
|
26
|
+
}
|
27
|
+
result = ax_check_children parent, kind, filters, block
|
28
|
+
refute result.blank?, msg
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Test that an element has a specifc descendent. For example, test
|
34
|
+
# that a window contains a specific label. You can pass any filters
|
35
|
+
# that you normally would during a search, including a block.
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
#
|
39
|
+
# assert_has_descendent window, :static_text, value: /Cake/
|
40
|
+
#
|
41
|
+
# @param [AX::Element]
|
42
|
+
# @param [#to_s]
|
43
|
+
# @param [Hash]
|
44
|
+
# @return [AX::Element]
|
45
|
+
def assert_has_descendent ancestor, kind, filters = {}, &block
|
46
|
+
msg = message {
|
47
|
+
descendent = ax_search_id kind, filters, block
|
48
|
+
"Expected #{ancestor.inspect} to have #{descendent} as a descendent"
|
49
|
+
}
|
50
|
+
result = ax_check_descendent ancestor, kind, filters, block
|
51
|
+
refute result.blank?, msg
|
52
|
+
result
|
13
53
|
end
|
54
|
+
alias_method :assert_has_descendant, :assert_has_descendent
|
14
55
|
|
15
|
-
|
56
|
+
##
|
57
|
+
# Test that an element _does not_ have a specific child. For example,
|
58
|
+
# test that a row is no longer in a table. You can pass any filters
|
59
|
+
# that you normally would during a search, including a block.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
#
|
63
|
+
# refute_has_child table, :row, id: 'MyRow'
|
64
|
+
#
|
65
|
+
# @param [AX::Element]
|
66
|
+
# @param [#to_s]
|
67
|
+
# @param [Hash]
|
68
|
+
# @return [nil]
|
69
|
+
def refute_has_child parent, kind, filters = {}, &block
|
70
|
+
result = ax_check_children parent, kind, filters, block
|
71
|
+
msg = message {
|
72
|
+
"Expected #{parent.inspect} not to have #{result} as a child"
|
73
|
+
}
|
74
|
+
assert result.blank?, msg
|
75
|
+
result
|
16
76
|
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Test that an element _does not_ have a specific descendent. For
|
80
|
+
# example, test that a window does not contain a spinning progress
|
81
|
+
# indicator anymore.
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
#
|
85
|
+
# refute_has_descendent window, :busy_indicator
|
86
|
+
#
|
87
|
+
# @param [AX::Element]
|
88
|
+
# @param [#to_s]
|
89
|
+
# @param [Hash]
|
90
|
+
# @return [nil,Array()]
|
91
|
+
def refute_has_descendent ancestor, kind, filters = {}, &block
|
92
|
+
result = ax_check_descendent ancestor, kind, filters, block
|
93
|
+
msg = message {
|
94
|
+
"Expected #{ancestor.inspect} not to have #{result} as a descendent"
|
95
|
+
}
|
96
|
+
assert result.blank?, msg
|
97
|
+
result
|
98
|
+
end
|
99
|
+
alias_method :refute_has_descendant, :refute_has_descendent
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def ax_search_id kind, filters, block
|
105
|
+
Accessibility::Qualifier.new(kind, filters, &block).describe
|
106
|
+
end
|
107
|
+
|
108
|
+
def ax_check_children parent, kind, filters, block
|
109
|
+
q = Accessibility::Qualifier.new(kind, filters, &block)
|
110
|
+
parent.attribute(:children).find { |x| q.qualifies? x }
|
111
|
+
end
|
112
|
+
|
113
|
+
def ax_check_descendent ancestor, kind, filters, block
|
114
|
+
ancestor.search(kind, filters, &block)
|
115
|
+
end
|
116
|
+
|
17
117
|
end
|
18
118
|
|
19
119
|
# @todo assertions for minitest/spec
|
data/lib/mouse.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
+
framework 'ApplicationServices'
|
2
|
+
|
1
3
|
##
|
2
4
|
# [Reference](http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html).
|
3
5
|
#
|
4
6
|
# @todo Inertial scrolling
|
5
7
|
# @todo Bezier paths
|
6
8
|
# @todo More intelligent default duration
|
7
|
-
# @todo Point arguments should accept a pair tuple...or should they?
|
8
9
|
# @todo Refactor to try and reuse the same event for a single action
|
9
10
|
# instead of creating new events.
|
10
11
|
# @todo Pause between down/up clicks
|
11
|
-
module Mouse
|
12
|
-
|
13
|
-
class << Mouse
|
12
|
+
module Mouse
|
13
|
+
extend self
|
14
14
|
|
15
15
|
##
|
16
16
|
# Number of animation steps per second.
|
@@ -60,11 +60,11 @@ class << Mouse
|
|
60
60
|
# @param [CGPoint]
|
61
61
|
# @param [Float] duration animation duration, in seconds
|
62
62
|
def drag_to point, duration = 0.2
|
63
|
-
|
64
|
-
|
63
|
+
post new_event(KCGEventLeftMouseDown, current_position, KCGMouseButtonLeft)
|
64
|
+
|
65
65
|
animate KCGEventLeftMouseDragged, KCGMouseButtonLeft, current_position, point, duration
|
66
|
-
|
67
|
-
|
66
|
+
|
67
|
+
post new_event(KCGEventLeftMouseUp, current_position, KCGMouseButtonLeft)
|
68
68
|
end
|
69
69
|
|
70
70
|
##
|
@@ -78,18 +78,15 @@ class << Mouse
|
|
78
78
|
# @param [Fixnum] amount number of units to scroll; positive to scroll
|
79
79
|
# up or negative to scroll down
|
80
80
|
# @param [Float] duration animation duration, in seconds
|
81
|
-
# @param [
|
81
|
+
# @param [Symbol] units `:line` scrolls by line, `:pixel` scrolls by pixel
|
82
82
|
def scroll amount, duration = 0.2, units = :line
|
83
83
|
units = UNIT[units] || raise(ArgumentError, "#{units} is not a valid unit")
|
84
|
-
steps = (FPS * duration).
|
84
|
+
steps = (FPS * duration).round
|
85
85
|
current = 0.0
|
86
86
|
steps.times do |step|
|
87
87
|
done = (step+1).to_f / steps
|
88
88
|
scroll = ((done - current)*amount).floor
|
89
|
-
|
90
|
-
# on the mouse we are simulating (up to 3)
|
91
|
-
event = CGEventCreateScrollWheelEvent(nil, units, 1, scroll)
|
92
|
-
CGEventPost(KCGHIDEventTap, event)
|
89
|
+
post new_scroll_event(units, 1, scroll)
|
93
90
|
sleep QUANTUM
|
94
91
|
current += scroll.to_f / amount
|
95
92
|
end
|
@@ -99,24 +96,24 @@ class << Mouse
|
|
99
96
|
# A standard click. Default position is the current position.
|
100
97
|
#
|
101
98
|
# @param [CGPoint]
|
102
|
-
def click point = current_position
|
103
|
-
event =
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
CGEventPost(KCGHIDEventTap, event)
|
99
|
+
def click point = current_position, duration = 12
|
100
|
+
event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
|
101
|
+
post event
|
102
|
+
duration.times { sleep QUANTUM }
|
103
|
+
set event, to: KCGEventLeftMouseUp
|
104
|
+
post event
|
109
105
|
end
|
110
106
|
|
111
107
|
##
|
112
108
|
# Standard secondary click. Default position is the current position.
|
113
109
|
#
|
114
110
|
# @param [CGPoint]
|
115
|
-
def secondary_click point = current_position
|
116
|
-
event =
|
117
|
-
|
118
|
-
|
119
|
-
|
111
|
+
def secondary_click point = current_position, duration = 12
|
112
|
+
event = new_event KCGEventRightMouseDown, point, KCGMouseButtonRight
|
113
|
+
post event
|
114
|
+
duration.times { sleep QUANTUM }
|
115
|
+
set event, to: KCGEventRightMouseUp
|
116
|
+
post event
|
120
117
|
end
|
121
118
|
alias_method :right_click, :secondary_click
|
122
119
|
|
@@ -125,16 +122,16 @@ class << Mouse
|
|
125
122
|
#
|
126
123
|
# @param [CGPoint]
|
127
124
|
def double_click point = current_position
|
128
|
-
event =
|
129
|
-
|
130
|
-
|
131
|
-
|
125
|
+
event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
|
126
|
+
post event
|
127
|
+
set event, to: KCGEventLeftMouseUp
|
128
|
+
post event
|
132
129
|
|
133
130
|
CGEventSetIntegerValueField(event, KCGMouseEventClickState, 2)
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
131
|
+
set event, to: KCGEventLeftMouseDown
|
132
|
+
post event
|
133
|
+
set event, to: KCGEventLeftMouseUp
|
134
|
+
post event
|
138
135
|
end
|
139
136
|
|
140
137
|
##
|
@@ -151,9 +148,10 @@ class << Mouse
|
|
151
148
|
#
|
152
149
|
# @param [CGPoint]
|
153
150
|
# @param [Number]
|
154
|
-
def arbitrary_click point = current_position, button = KCGMouseButtonCenter
|
151
|
+
def arbitrary_click point = current_position, button = KCGMouseButtonCenter, duration = 12
|
155
152
|
event = CGEventCreateMouseEvent(nil, KCGEventOtherMouseDown, point, button)
|
156
153
|
CGEventPost(KCGHIDEventTap, event)
|
154
|
+
duration.times do sleep QUANTUM end
|
157
155
|
CGEventSetType(event, KCGEventOtherMouseUp)
|
158
156
|
CGEventPost(KCGHIDEventTap, event)
|
159
157
|
end
|
@@ -166,20 +164,48 @@ class << Mouse
|
|
166
164
|
# Executes a mouse movement animation. It can be a simple cursor
|
167
165
|
# move or a drag depending on what is passed to `type`.
|
168
166
|
def animate type, button, from, to, duration
|
169
|
-
|
170
|
-
xstep
|
171
|
-
ystep
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
167
|
+
current = current_position
|
168
|
+
xstep = (to.x - current.x) / (FPS * duration)
|
169
|
+
ystep = (to.y - current.y) / (FPS * duration)
|
170
|
+
start = NSDate.date
|
171
|
+
|
172
|
+
until close_enough?(current, to)
|
173
|
+
remaining = to.x - current.x
|
174
|
+
current.x += xstep.abs > remaining.abs ? remaining : xstep
|
175
|
+
|
176
|
+
remaining = to.y - current.y
|
177
|
+
current.y += ystep.abs > remaining.abs ? remaining : ystep
|
178
|
+
|
179
|
+
post new_event(type, current, button)
|
180
|
+
|
177
181
|
sleep QUANTUM
|
182
|
+
break if NSDate.date.timeIntervalSinceDate(start) > 5.0
|
183
|
+
current = current_position
|
178
184
|
end
|
179
|
-
|
180
|
-
|
185
|
+
end
|
186
|
+
|
187
|
+
def close_enough? current, target
|
188
|
+
x = current.x - target.x
|
189
|
+
y = current.y - target.y
|
190
|
+
delta = Math.sqrt((x**2) + (y**2))
|
191
|
+
delta <= 1.0
|
192
|
+
end
|
193
|
+
|
194
|
+
def new_event event, position, button
|
195
|
+
CGEventCreateMouseEvent(nil, event, position, button)
|
196
|
+
end
|
197
|
+
|
198
|
+
# @param [Fixnum] wheel which scroll wheel to use (value between 1-3)
|
199
|
+
def new_scroll_event units, wheel, amount
|
200
|
+
CGEventCreateScrollWheelEvent(nil, units, wheel, amount)
|
201
|
+
end
|
202
|
+
|
203
|
+
def post event
|
181
204
|
CGEventPost(KCGHIDEventTap, event)
|
182
|
-
|
205
|
+
end
|
206
|
+
|
207
|
+
def set event, to: state
|
208
|
+
CGEventSetType(event, state)
|
183
209
|
end
|
184
210
|
|
185
211
|
end
|
@@ -1,15 +1,142 @@
|
|
1
|
-
require '
|
1
|
+
require 'accessibility/qualifier'
|
2
|
+
require 'ax/element'
|
2
3
|
|
3
4
|
##
|
4
|
-
# Custom RSpec
|
5
|
-
|
5
|
+
# Custom matcher for RSpec to check if an element has the specified
|
6
|
+
# child element.
|
7
|
+
class Accessibility::HasChildMatcher
|
8
|
+
|
9
|
+
# @param [#to_s]
|
10
|
+
# @param [Hash]
|
11
|
+
# @yield
|
12
|
+
def initialize kind, filters, &block
|
13
|
+
@qualifier = Accessibility::Qualifier.new(kind, filters, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [AX::Element]
|
17
|
+
def matches? parent
|
18
|
+
!search(parent).blank?
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String]
|
22
|
+
def failure_message_for_should
|
23
|
+
"Expected #@parent to have child #{@qualifier.describe}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param [AX::Element]
|
27
|
+
def does_not_match? parent
|
28
|
+
search(parent).blank?
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
def failure_message_for_should_not
|
33
|
+
"Expected #@parent to NOT have child #@result"
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Implemented to override `NSObject#description`.
|
38
|
+
#
|
39
|
+
# @return [String]
|
40
|
+
def description
|
41
|
+
"should have a child that matches #{@qualifier.describe}"
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def search parent
|
48
|
+
@parent = parent
|
49
|
+
@result = parent.attribute(:children).find { |x| @qualifier.qualifies? x }
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Assert that the receiving element has the specified child element. You
|
56
|
+
# can use any filters you would normally use in a search, including
|
57
|
+
# a block.
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
#
|
61
|
+
# window.toolbar.should have_child(:search_field)
|
62
|
+
# table.should have_child(:row, static_text: { value: /42/ })
|
63
|
+
#
|
64
|
+
# search_field.should_not have_child(:busy_indicator)
|
65
|
+
#
|
66
|
+
# @param [#to_s]
|
67
|
+
# @param [Hash]
|
68
|
+
# @yield An optional block to be used as part of the search qualifier
|
69
|
+
def have_child kind, filters = {}, &block
|
70
|
+
Accessibility::HasChildMatcher.new kind, filters, &block
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
##
|
75
|
+
# Custom matcher for RSpec to check if an element has the specified
|
76
|
+
# descendent element.
|
77
|
+
class Accessibility::HasDescendentMatcher
|
78
|
+
|
79
|
+
# @param [#to_s]
|
80
|
+
# @param [Hash]
|
81
|
+
# @yield
|
82
|
+
def initialize kind, filters, &block
|
83
|
+
@kind, @filters, @block = kind, filters, block
|
84
|
+
@qualifier = Accessibility::Qualifier.new(@kind, @filters, &@block)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @param [AX::Element]
|
88
|
+
def matches? ancestor
|
89
|
+
!search(ancestor).blank?
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [String]
|
93
|
+
def failure_message_for_should
|
94
|
+
"Expected #@ancestor to have descendent #{@qualifier.describe}"
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param [AX::Element]
|
98
|
+
def does_not_match? ancestor
|
99
|
+
search(ancestor).blank?
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [String]
|
103
|
+
def failure_message_for_should_not
|
104
|
+
"Expected #@ancestor to NOT have descendent #@result"
|
105
|
+
end
|
6
106
|
|
7
107
|
##
|
8
|
-
#
|
9
|
-
|
108
|
+
# Implemented to override `NSObject#description`.
|
109
|
+
#
|
110
|
+
# @return [String]
|
111
|
+
def description
|
112
|
+
"should have a descendent matching #{@qualifier.describe}"
|
10
113
|
end
|
11
114
|
|
12
|
-
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def search ancestor
|
119
|
+
@ancestor = ancestor
|
120
|
+
@result = ancestor.search(@kind, @filters, &@block)
|
13
121
|
end
|
14
122
|
|
15
123
|
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Assert that the given element has the specified descendent. You can
|
127
|
+
# pass any parameters you normally would use during a search,
|
128
|
+
# including a block.
|
129
|
+
#
|
130
|
+
# @example
|
131
|
+
#
|
132
|
+
# app.main_window.should have_descendent(:button, title: 'Press Me')
|
133
|
+
#
|
134
|
+
# row.should_not have_descendent(:check_box)
|
135
|
+
#
|
136
|
+
# @param [#to_s]
|
137
|
+
# @param [Hash]
|
138
|
+
# @yield An optional block to be used as part of the search qualifier
|
139
|
+
def have_descendent kind, filters = {}, &block
|
140
|
+
Accessibility::HasDescendentMatcher.new kind, filters, &block
|
141
|
+
end
|
142
|
+
alias :have_descendant :have_descendent
|
data/rakelib/doc.rake
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# begin
|
2
|
+
# require 'yard'
|
3
|
+
# YARD::Rake::YardocTask.new
|
4
|
+
# rescue LoadError => e
|
5
|
+
# $stderr.puts 'It seems as though you do not have yard installed.'
|
6
|
+
# command = ENV['RUBY_VERSION'] ? 'rake' : 'sudo macrake'
|
7
|
+
# $stderr.puts "You can install it by running `#{command} setup_dev`"
|
8
|
+
# end
|
9
|
+
|
10
|
+
# desc 'Generate Graphviz object graph'
|
11
|
+
# task :garden => :yard do
|
12
|
+
# sh 'yard graph --full --dependencies --dot="-Tpng:quartz" -f docs/images/AX.dot'
|
13
|
+
# end
|
data/rakelib/ext.rake
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module ExtHelpers
|
2
|
+
def macruby?
|
3
|
+
defined? MACRUBY_REVISION
|
4
|
+
end
|
5
|
+
|
6
|
+
def cruby?
|
7
|
+
RUBY_ENGINE == 'ruby'
|
8
|
+
end
|
9
|
+
|
10
|
+
def needs_regeneration? source, bundle
|
11
|
+
return true unless File.exists? bundle
|
12
|
+
return true unless File.mtime(bundle) > File.mtime(source)
|
13
|
+
return true if macruby? && ext_platform(bundle) == :cruby
|
14
|
+
return true if cruby? && ext_platform(bundle) == :macruby
|
15
|
+
end
|
16
|
+
|
17
|
+
def ext_platform bundle
|
18
|
+
return :macruby if `otool -L #{bundle}`.match /MacRuby/
|
19
|
+
return :cruby
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
namespace :ext do
|
25
|
+
extend ExtHelpers
|
26
|
+
|
27
|
+
desc 'Compile C extensions'
|
28
|
+
task :key_coder do
|
29
|
+
dir = 'ext/accessibility/key_coder'
|
30
|
+
ext = "#{dir}/key_coder"
|
31
|
+
if needs_regeneration? "#{ext}.c", "#{ext}.bundle"
|
32
|
+
Rake::Task['clobber_key_coder'].execute
|
33
|
+
Dir.chdir(dir) do
|
34
|
+
ruby 'extconf.rb'
|
35
|
+
sh 'make'
|
36
|
+
end
|
37
|
+
cp "#{ext}.bundle", 'lib/accessibility'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
desc 'Remove files generated by compiling key_coder'
|
44
|
+
task :clobber_key_coder do
|
45
|
+
Dir.glob('{lib,ext}/**/*{.bundle,.o}').each do |file|
|
46
|
+
$stdout.puts "rm #{file}"
|
47
|
+
rm_f file
|
48
|
+
end
|
49
|
+
file = 'rm ext/accessibility/key_coder/Makefile'
|
50
|
+
$stdout.puts file
|
51
|
+
rm_f file
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'Remove files generated by compiling extensions'
|
55
|
+
task :clobber_ext => [:clobber_key_coder]
|
56
|
+
|
57
|
+
|
58
|
+
if RUBY_ENGINE == 'macruby'
|
59
|
+
require 'rake/compiletask'
|
60
|
+
Rake::CompileTask.new
|
61
|
+
end
|
data/rakelib/gem.rake
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems/package_task'
|
2
|
+
|
3
|
+
ax_elements = Gem::Specification.load('AXElements.gemspec')
|
4
|
+
Gem::PackageTask.new(ax_elements) { }
|
5
|
+
|
6
|
+
desc 'Build and install gem (not including deps)'
|
7
|
+
task :install => :gem do
|
8
|
+
require 'rubygems/installer'
|
9
|
+
Gem::Installer.new("pkg/#{ax_elements.file_name}").install
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Install dependencies for development'
|
13
|
+
task :setup_dev do
|
14
|
+
require 'rubygems/dependency_installer'
|
15
|
+
spec.development_dependencies.each do |dep|
|
16
|
+
puts "Installing #{dep.name} (#{dep.requirement})"
|
17
|
+
Gem::DependencyInstaller.new.install(dep.name, dep.requirement)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ax_typer = Gem::Specification.load('AXTyper.gemspec')
|
22
|
+
Gem::PackageTask.new(ax_typer) { }
|
23
|
+
|
24
|
+
desc 'Build and install AXTyper'
|
25
|
+
task :install_typer => :gem do
|
26
|
+
require 'rubygems/installer'
|
27
|
+
Gem::Installer.new("pkg/#{ax_typer.file_name}").install
|
28
|
+
end
|
data/rakelib/test.rake
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
desc 'Start up irb with AXElements loaded'
|
2
|
+
task :console => :ext do
|
3
|
+
irb = ENV['RUBY_VERSION'] ? 'irb' : 'macirb'
|
4
|
+
sh "#{irb} -Ilib -rubygems -rax_elements"
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Open the fixture app'
|
8
|
+
task :run_fixture => :fixture do
|
9
|
+
sh 'open test/fixture/Release/AXElementsTester.app'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Build the test fixture'
|
13
|
+
task :fixture do
|
14
|
+
sh 'cd test/AXElementsTester && xcodebuild'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Remove the built fixture app'
|
18
|
+
task :clobber_fixture do
|
19
|
+
$stdout.puts 'rm -rf test/fixture'
|
20
|
+
rm_rf 'test/fixture'
|
21
|
+
end
|
22
|
+
task :clobber => :clobber_fixture
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
namespace :test do
|
26
|
+
Rake::TestTask.new(:sanity) do |t|
|
27
|
+
t.libs << '.'
|
28
|
+
t.pattern = "test/sanity/**/test_*.rb"
|
29
|
+
end
|
30
|
+
task :sanity => [:ext, :fixture]
|
31
|
+
|
32
|
+
Rake::TestTask.new(:integration) do |t|
|
33
|
+
t.libs << '.'
|
34
|
+
t.pattern = "test/integration/**/test_*.rb"
|
35
|
+
end
|
36
|
+
task :integration => [:ext, :fixture]
|
37
|
+
|
38
|
+
desc 'Run tests for the string parser'
|
39
|
+
Rake::TestTask.new(:string) do |t|
|
40
|
+
t.libs << '.'
|
41
|
+
t.pattern = "test/sanity/accessibility/test_string.rb"
|
42
|
+
end
|
43
|
+
task :string => :ext
|
44
|
+
|
45
|
+
desc 'Run tests under CRuby (where applicable)'
|
46
|
+
task :cruby do
|
47
|
+
if ENV['RUBY_VERSION'] # using rvm
|
48
|
+
puts sh 'rvm 1.9.3 do rake test:string'
|
49
|
+
else
|
50
|
+
sh 'rake test:string'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|