AXElements 0.7.6 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -378,8 +378,8 @@ module Accessibility::Core
378
378
  # events).
379
379
  #
380
380
  # This is just a magic number from trial and error. Both the repeat
381
- # interval (NXKeyRepeatInterval) and threshold (NXKeyRepeatThreshold),
382
- # but both were way too big.
381
+ # interval (NXKeyRepeatInterval) and threshold (NXKeyRepeatThreshold)
382
+ # were tried, but were way too big.
383
383
  #
384
384
  # @return [Number]
385
385
  KEY_RATE = case ENV['KEY_RATE']
@@ -210,7 +210,7 @@ module Accessibility::DSL
210
210
  #
211
211
  # @param [AX::Element]
212
212
  def set_focus_to element
213
- element.set(:focused, true) if element.respond_to? :focused
213
+ element.set(:focused, true) if element.writable? :focused
214
214
  end
215
215
  alias_method :set_focus, :set_focus_to
216
216
 
@@ -242,15 +242,13 @@ module Accessibility::DSL
242
242
  #
243
243
  # @return [nil] do not rely on a return value
244
244
  def set element, change
245
- if element.respond_to? :focused
246
- if element.writable? :focused
247
- element.set :focused, true
248
- end
249
- end
245
+ set_focus_to element
250
246
 
251
- return element.set :value, change unless change.kind_of? Hash
252
- key, value = change.first
253
- return element.set key, value
247
+ if change.kind_of? Hash
248
+ element.set *change.first
249
+ else
250
+ element.set :value, change
251
+ end
254
252
  end
255
253
 
256
254
  ##
@@ -267,9 +265,10 @@ module Accessibility::DSL
267
265
  # Send input to a specific application
268
266
  # @param [#to_s]
269
267
  # @param [AX::Application]
268
+ #
270
269
  def type string, app = system_wide
271
270
  sleep 0.1
272
- app.type_string string.to_s
271
+ app.type string.to_s
273
272
  end
274
273
 
275
274
  ##
@@ -18,13 +18,11 @@ module Accessibility::Enumerators
18
18
  #
19
19
  # @yieldparam [AX::Element]
20
20
  def each
21
- # @todo Lazy-wrap element refs, might make things a bit faster
22
- # for fat trees; what is impact on thin trees?
23
- # @todo See if we can implement the method in a single loop
21
+ # @todo Mutate the queue less
24
22
  queue = [@root]
25
23
  until queue.empty?
26
24
  queue.shift.attribute(:children).each do |x|
27
- queue << x if x.attributes.include? :children
25
+ queue << x
28
26
  yield x
29
27
  end
30
28
  end
@@ -61,10 +59,8 @@ module Accessibility::Enumerators
61
59
  until stack.empty?
62
60
  current = stack.shift
63
61
  yield current
64
- if current.attributes.include? :children
65
- # need to reverse it since child ordering seems to matter in practice
66
- stack.unshift *current.attribute(:children)
67
- end
62
+ # needed to reverse it since child ordering seems to matter in practice
63
+ stack.unshift *current.attribute(:children)
68
64
  end
69
65
  end
70
66
 
@@ -92,10 +88,8 @@ module Accessibility::Enumerators
92
88
  # @param [#call]
93
89
  def recursive_each_with_level element, depth, block
94
90
  block.call element, depth
95
- if element.respond_to? :children
96
- element.attribute(:children).each do |x|
97
- recursive_each_with_level x, depth + 1, block
98
- end
91
+ element.attribute(:children).each do |x|
92
+ recursive_each_with_level x, depth + 1, block
99
93
  end
100
94
  end
101
95
 
@@ -66,11 +66,16 @@ module Accessibility::Factory
66
66
  # @param [AXUIElementRef]
67
67
  # @return [AX::Element]
68
68
  def process_element ref
69
- role = TRANSLATOR.unprefix ref.role
70
-
71
- # Some objects claim to have a subrole but return nil
72
- klass = if subrole = ref.subrole
73
- class_for TRANSLATOR.unprefix(subrole), and: role
69
+ role = TRANSLATOR.unprefix ref.role
70
+ attrs = ref.attributes
71
+ klass = if attrs.include? KAXSubroleAttribute
72
+ subrole = ref.subrole
73
+ # Some objects claim to have a subrole but return nil
74
+ if subrole
75
+ class_for TRANSLATOR.unprefix(subrole), and: role
76
+ else
77
+ class_for role
78
+ end
74
79
  else
75
80
  class_for role
76
81
  end
@@ -82,9 +87,9 @@ module Accessibility::Factory
82
87
  #
83
88
  # @return [Array]
84
89
  def process_array vals
85
- (vals.empty? && vals) ||
86
- (CFGetTypeID(vals.first) != REF_TYPE && vals) ||
87
- vals.map { |val| process_element val }
90
+ return vals if vals.empty?
91
+ return vals if CFGetTypeID(vals.first) != REF_TYPE
92
+ return vals.map { |val| process_element val }
88
93
  end
89
94
 
90
95
  ##
@@ -132,7 +137,7 @@ module Accessibility::Factory
132
137
 
133
138
  ##
134
139
  # Create a new class in the {AX} namesapce that has the given
135
- # `superklass` as the superclass.
140
+ # `superklass` as the superclass..
136
141
  #
137
142
  # @param [#to_s] name
138
143
  # @param [#to_s] superklass
@@ -56,11 +56,11 @@ class Accessibility::Graph
56
56
  end
57
57
 
58
58
  def enabled
59
- FILL if @element.respond_to?(:enabled) && !@element.enabled?
59
+ FILL if @element.enabled?
60
60
  end
61
61
 
62
62
  def focus
63
- BOLD if @element.respond_to?(:focused) && @element.focused?
63
+ BOLD if @element.focused?
64
64
  end
65
65
 
66
66
  OVAL = '[shape = oval]'
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'accessibility/translator'
2
3
 
3
4
  ##
@@ -37,9 +38,7 @@ class Accessibility::Qualifier
37
38
  #
38
39
  # @param [AX::Element]
39
40
  def qualifies? element
40
- return false unless the_right_type? element
41
- return false unless meets_criteria? element
42
- return true
41
+ the_right_type?(element) && meets_criteria?(element)
43
42
  end
44
43
 
45
44
  # @return [String]
@@ -65,18 +64,18 @@ class Accessibility::Qualifier
65
64
  def compile criteria
66
65
  @filters = criteria.map do |key, value|
67
66
  if value.kind_of? Hash
68
- [:children, [:subsearch, key, value]]
67
+ [:subsearch, key, value]
69
68
  elsif key.kind_of? Array
70
69
  filter = value.kind_of?(Regexp) ?
71
70
  :parameterized_match : :parameterized_equality
72
- [key.first, [filter, *key, value]]
71
+ [filter, *key, value]
73
72
  else
74
73
  filter = value.kind_of?(Regexp) ?
75
74
  :match : :equality
76
- [key, [filter, key, value]]
75
+ [filter, key, value]
77
76
  end
78
77
  end
79
- @filters << [:role, [:block_check]] if @block
78
+ @filters << [:block_check] if @block
80
79
  end
81
80
 
82
81
  ##
@@ -92,7 +91,7 @@ class Accessibility::Qualifier
92
91
  return false
93
92
  end
94
93
  end
95
- return element.kind_of? @const
94
+ element.kind_of? @const
96
95
  end
97
96
 
98
97
  ##
@@ -102,9 +101,7 @@ class Accessibility::Qualifier
102
101
  # @param [AX::Element]
103
102
  def meets_criteria? element
104
103
  @filters.all? do |filter|
105
- if element.respond_to? filter.first
106
- self.send *filter.last, element
107
- end
104
+ self.send *filter, element
108
105
  end
109
106
  end
110
107
 
@@ -113,7 +110,7 @@ class Accessibility::Qualifier
113
110
  end
114
111
 
115
112
  def match attr, regexp, element
116
- element.attribute(attr).match regexp
113
+ element.attribute(attr).to_s.match regexp
117
114
  end
118
115
 
119
116
  def equality attr, value, element
@@ -121,7 +118,7 @@ class Accessibility::Qualifier
121
118
  end
122
119
 
123
120
  def parameterized_match attr, param, regexp, element
124
- element.attribute(attr, for_parameter: param).match regexp
121
+ element.attribute(attr, for_parameter: param).to_s.match regexp
125
122
  end
126
123
 
127
124
  def parameterized_equality attr, param, value, element
@@ -27,8 +27,8 @@ class Accessibility::Translator
27
27
  # Initialize the caches.
28
28
  def initialize
29
29
  init_unprefixes
30
- init_normalizations
31
30
  init_rubyisms
31
+ init_cocoaifications
32
32
  init_classifications
33
33
  init_singularizations
34
34
  end
@@ -54,32 +54,18 @@ class Accessibility::Translator
54
54
  @unprefixes[key]
55
55
  end
56
56
 
57
- ##
58
- # Given a symbol, return the equivalent accessibility constant.
59
- #
60
- # @param [#to_sym]
61
- # @param [Array<String>]
62
- # @return [String]
63
- def lookup key, values
64
- @values = values
65
- @rubyisms[key.to_sym]
66
- end
67
-
68
57
  # @return [Array<Symbol>]
69
58
  def rubyize keys
70
- keys.map { |x| @normalizations[x] }
59
+ keys.map { |x| @rubyisms[x] }
71
60
  end
72
61
 
73
62
  ##
74
- # Try to turn an arbitrary symbol into a notification constant, and
75
- # then get the value of the constant.
63
+ # Given a symbol, return the equivalent accessibility constant.
76
64
  #
77
- # @param [#to_s]
65
+ # @param [#to_sym]
78
66
  # @return [String]
79
- def guess_notification_for name
80
- name = name.to_s.gsub /(?:^|_)(.)/ do $1.upcase! || $1 end
81
- const = "KAX#{name}Notification"
82
- Object.const_defined?(const) ? Object.const_get(const) : name
67
+ def cocoaify key
68
+ @cocoaifications[key.to_sym]
83
69
  end
84
70
 
85
71
  ##
@@ -114,36 +100,46 @@ class Accessibility::Translator
114
100
  @singularizations[klass]
115
101
  end
116
102
 
103
+ ##
104
+ # Try to turn an arbitrary symbol into a notification constant, and
105
+ # then get the value of the constant.
106
+ #
107
+ # @param [#to_s]
108
+ # @return [String]
109
+ def guess_notification name
110
+ name = name.to_s.gsub /(?:^|_)(.)/ do $1.upcase! || $1 end
111
+ const = "KAX#{name}Notification"
112
+ Object.const_defined?(const) ? Object.const_get(const) : name
113
+ end
114
+
117
115
 
118
116
  private
119
117
 
120
118
  # @return [Hash{String=>String}]
121
119
  def init_unprefixes
122
120
  @unprefixes = Hash.new do |hash, key|
123
- hash[key] = key.sub /^[A-Z]*?AX(?:Is)?|\s+/, EMPTY_STRING
121
+ hash[key] = key.sub /^[A-Z]*?AX|\s+/, EMPTY_STRING
124
122
  end
125
123
  end
126
124
 
127
125
  # @return [Hash{String=>Symbol}]
128
- def init_normalizations
129
- @normalizations = Hash.new do |hash, key|
126
+ def init_rubyisms
127
+ @rubyisms = Hash.new do |hash, key|
130
128
  hash[key] = Accessibility::Inflector.underscore(@unprefixes[key]).to_sym
131
129
  end
132
130
  end
133
131
 
134
132
  # @return [Hash{Symbol=>String}]
135
- def init_rubyisms
136
- @rubyisms = Hash.new do |hash, key|
137
- @values.each do |v| hash[@normalizations[v]] = v end
138
- hash.fetch(key) do |k|
139
- chomped_key = k.chomp(QUESTION_MARK).to_sym
140
- chomped_val = hash.fetch(chomped_key, nil)
141
- hash[key] = chomped_val if chomped_val
142
- end
133
+ def init_cocoaifications
134
+ @cocoaifications = Hash.new do |hash, key|
135
+ hash[key] = "AX#{Accessibility::Inflector.camelize(key.chomp QUESTION_MARK)}"
143
136
  end
144
137
  # preload the table
145
- @rubyisms[:id] = KAXIdentifierAttribute
146
- @rubyisms[:placeholder] = KAXPlaceholderValueAttribute
138
+ @cocoaifications[:id] = KAXIdentifierAttribute
139
+ @cocoaifications[:placeholder] = KAXPlaceholderValueAttribute
140
+ # workaround the one known case where AX uses "Is" for a boolean attribute
141
+ @cocoaifications[:application_running] = # let the value all fall through
142
+ @cocoaifications[:application_running?] = KAXIsApplicationRunningAttribute
147
143
  end
148
144
 
149
145
  # @return [Hash{String=>String}]
@@ -1,6 +1,6 @@
1
1
  module Accessibility
2
2
  # @return [String]
3
- VERSION = '0.7.6'
3
+ VERSION = '0.7.7'
4
4
 
5
5
  # @return [String]
6
6
  CODE_NAME = 'Clefairy'
@@ -47,15 +47,23 @@ class AX::Application < AX::Element
47
47
  # @group Attributes
48
48
 
49
49
  ##
50
- # Overridden to handle the {Accessibility::Language#set_focus} case.
50
+ # Overridden to handle the {Accessibility::DSL#set_focus} case.
51
51
  #
52
52
  # (see AX::Element#attribute)
53
53
  def attribute attr
54
54
  case attr
55
55
  when :focused?, :focused then active?
56
56
  when :hidden?, :hidden then hidden?
57
- else
58
- super
57
+ else super
58
+ end
59
+ end
60
+
61
+ ##
62
+ # Overridden to handle the {Accessibility::DSL#set_focus_to} case.
63
+ def writable? attr
64
+ case attr
65
+ when :focused?, :focused, :hidden?, :hidden then true
66
+ else super
59
67
  end
60
68
  end
61
69
 
@@ -136,7 +144,7 @@ class AX::Application < AX::Element
136
144
  # {file:docs/KeyboardEvents.markdown Keyboard} documentation.
137
145
  #
138
146
  # @return [Boolean]
139
- def type_string string
147
+ def type string
140
148
  @ref.post keyboard_events_for string
141
149
  true
142
150
  end
@@ -199,7 +207,7 @@ class AX::Application < AX::Element
199
207
  # @return [AX::Window]
200
208
  def show_preferences_window
201
209
  windows = self.children.select { |x| x.kind_of? AX::Window }
202
- type_string "\\COMMAND+,"
210
+ type "\\COMMAND+,"
203
211
  wait_for(:window, parent: self) { |window| !windows.include?(window) }
204
212
  end
205
213
 
@@ -49,10 +49,8 @@ class AX::Element
49
49
  # element.attribute :position # => #<CGPoint x=123.0 y=456.0>
50
50
  #
51
51
  # @param [#to_sym]
52
- def attribute name
53
- if rattr = TRANSLATOR.lookup(name, @ref.attributes)
54
- process @ref.attribute(rattr)
55
- end
52
+ def attribute attr
53
+ process @ref.attribute TRANSLATOR.cocoaify attr
56
54
  end
57
55
 
58
56
  ##
@@ -77,11 +75,7 @@ class AX::Element
77
75
  # @param [#to_sym]
78
76
  # @return [Number]
79
77
  def size_of attr
80
- if rattr = TRANSLATOR.lookup(attr, @ref.attributes)
81
- @ref.size_of rattr
82
- else
83
- 0
84
- end
78
+ @ref.size_of TRANSLATOR.cocoaify attr
85
79
  end
86
80
 
87
81
  ##
@@ -107,11 +101,7 @@ class AX::Element
107
101
  #
108
102
  # @param [#to_sym]
109
103
  def writable? attr
110
- if rattr = TRANSLATOR.lookup(attr, @ref.attributes)
111
- @ref.writable? rattr
112
- else
113
- false
114
- end
104
+ @ref.writable? TRANSLATOR.cocoaify attr
115
105
  end
116
106
 
117
107
  ##
@@ -129,7 +119,7 @@ class AX::Element
129
119
  raise NoMethodError, "#{attr} is read-only for #{inspect}"
130
120
  end
131
121
  value = value.relative_to(@ref.value.size) if value.kind_of? Range
132
- @ref.set TRANSLATOR.lookup(attr, @ref.attributes), value
122
+ @ref.set TRANSLATOR.cocoaify(attr), value
133
123
  end
134
124
 
135
125
 
@@ -158,7 +148,7 @@ class AX::Element
158
148
  #
159
149
  # @param [#to_sym]
160
150
  def attribute attr, for_parameter: param
161
- if rattr = TRANSLATOR.lookup(attr, @ref.parameterized_attributes)
151
+ if rattr = TRANSLATOR.cocoaify(attr)
162
152
  param = param.relative_to(@ref.value.size) if value.kind_of? Range
163
153
  process @ref.attribute(rattr, for_parameter: param)
164
154
  end
@@ -197,7 +187,7 @@ class AX::Element
197
187
  # @param [#to_sym]
198
188
  # @return [Boolean] true if successful
199
189
  def perform action
200
- if raction = TRANSLATOR.lookup(action, @ref.actions)
190
+ if raction = TRANSLATOR.cocoaify(action)
201
191
  @ref.perform raction
202
192
  else
203
193
  false
@@ -298,17 +288,17 @@ class AX::Element
298
288
  # window.application # => SearchFailure is raised
299
289
  #
300
290
  def method_missing method, *args, &block
301
- if method[-1] == EQUALS
302
- return set(method.chomp(EQUALS), args.first)
291
+ return set(method.chomp(EQUALS), args.first) if method[-1] == EQUALS
303
292
 
304
- elsif attributes.include? method
293
+ key = TRANSLATOR.cocoaify method
294
+ if @ref.attributes.include? key
305
295
  return attribute method
306
296
 
307
- elsif parameterized_attributes.include? method
308
- return attribute method, for_parameter: args.first
297
+ elsif @ref.parameterized_attributes.include? key
298
+ return attribute(method, for_parameter: args.first)
309
299
 
310
- elsif attributes.include? :children
311
- if (result = search method, *args, &block).blank?
300
+ elsif @ref.attributes.include? KAXChildrenAttribute
301
+ if (result = search(method, *args, &block)).blank?
312
302
  raise Accessibility::SearchFailure.new(self, method, args.first)
313
303
  else
314
304
  return result
@@ -359,7 +349,7 @@ class AX::Element
359
349
  # @yieldreturn [Boolean]
360
350
  # @return [Array(Observer, String, CFRunLoopSource)]
361
351
  def on_notification name, &block
362
- notif = TRANSLATOR.guess_notification_for name
352
+ notif = TRANSLATOR.guess_notification name
363
353
  observer = @ref.observer &notif_callback_for(&block)
364
354
  source = @ref.run_loop_source_for observer
365
355
  @ref.register observer, to_receive: notif
@@ -396,11 +386,10 @@ class AX::Element
396
386
  # @return [String]
397
387
  def inspect
398
388
  msg = "#<#{self.class}" << pp_identifier
399
- attrs = @ref.attributes
400
- msg << pp_position if attrs.include? KAXPositionAttribute
401
- msg << pp_children if attrs.include? KAXChildrenAttribute
402
- msg << pp_checkbox(:enabled) if attrs.include? KAXEnabledAttribute
403
- msg << pp_checkbox(:focused) if attrs.include? KAXFocusedAttribute
389
+ msg << pp_position if attributes.include? :position
390
+ msg << pp_children if attributes.include? :children
391
+ msg << pp_checkbox(:enabled) if attributes.include? :enabled
392
+ msg << pp_checkbox(:focused) if attributes.include? :focused
404
393
  msg << '>'
405
394
  end
406
395
 
@@ -418,9 +407,12 @@ class AX::Element
418
407
  ##
419
408
  # Overriden to respond properly with regards to dynamic attribute
420
409
  # lookups, but will return false for potential implicit searches.
410
+ #
411
+ # This does not work for predicate methods at the moment.
421
412
  def respond_to? name
422
- attributes.include?(name) ||
423
- parameterized_attributes.include?(name) ||
413
+ key = TRANSLATOR.cocoaify name.chomp(EQUALS)
414
+ @ref.attributes.include?(key) ||
415
+ @ref.parameterized_attributes.include?(key) ||
424
416
  super
425
417
  end
426
418
 
@@ -18,7 +18,7 @@ class AX::SystemWide < AX::Element
18
18
  end
19
19
 
20
20
  ##
21
- # @note With the `SystemWide` class, using {#type_string} will send the
21
+ # @note With the `SystemWide` class, using {#type} will send the
22
22
  # events to which ever app has focus.
23
23
  #
24
24
  # Generate keyboard events by simulating keyboard input.
@@ -27,7 +27,7 @@ class AX::SystemWide < AX::Element
27
27
  # more information on how to format strings.
28
28
  #
29
29
  # @return [Boolean]
30
- def type_string string
30
+ def type string
31
31
  @ref.post keyboard_events_for string
32
32
  true
33
33
  end
@@ -24,7 +24,7 @@ end
24
24
  namespace :ext do
25
25
  extend ExtHelpers
26
26
 
27
- desc 'Compile C extensions'
27
+ desc 'Compile the key_coder C extension'
28
28
  task :key_coder do
29
29
  dir = 'ext/accessibility/key_coder'
30
30
  ext = "#{dir}/key_coder"
@@ -12,29 +12,15 @@ class TestAccessibilityDSL < MiniTest::Unit::TestCase
12
12
  @dsl ||= DSL.new
13
13
  end
14
14
 
15
- def app
16
- @@app ||= AX::Application.new REF
17
- end
18
-
19
- def text_area
20
- @@text_area ||= app.main_window.text_area
21
- end
22
-
23
- def pref_window
24
- app.children.find { |x|
25
- x.attributes.include?(:title) && x.title == 'Preferences'
26
- }
27
- end
28
-
29
- def spelling_window
30
- app.children.find { |x|
31
- x.attributes.include?(:title) && x.title.match(/^Spelling/)
32
- }
33
- end
15
+ def app; @@app ||= AX::Application.new REF end
16
+ def text_area; @@text_area ||= app.main_window.text_area end
17
+ def pref_window; app.children.find { |x| x.attribute(:title) == 'Preferences' } end
18
+ def spelling_window; app.children.find { |x| x.attribute(:title).to_s.match(/^Spelling/) } end
34
19
 
35
20
  def try_typing string, expected = nil
36
21
  expected = string unless expected
37
22
  text_area.set :focused, true
23
+ assert text_area.focused?
38
24
  dsl.type string
39
25
  assert_equal expected, text_area.value
40
26
  ensure # reset for next test
@@ -219,16 +205,16 @@ class TestAccessibilityDSL < MiniTest::Unit::TestCase
219
205
  pop_up = app.main_window.pop_up_button
220
206
 
221
207
  pop_up.perform :press
222
- expected = pop_up.menu_item(title: '49')
223
- dsl.scroll_menu_to expected
224
- assert_equal expected, element_under_mouse
208
+ item = wait_for :menu_item, ancestor: pop_up, title: '49'
209
+ dsl.scroll_menu_to item
210
+ assert_equal item, element_under_mouse
225
211
  dsl.click
226
212
  assert_equal '49', pop_up.value
227
213
 
228
214
  pop_up.perform :press
229
- expected = pop_up.menu_item(title: 'Togusa')
230
- dsl.scroll_menu_to expected
231
- assert_equal expected, element_under_mouse
215
+ item = wait_for :menu_item, ancestor: pop_up, title: 'Togusa'
216
+ dsl.scroll_menu_to item
217
+ assert_equal item, element_under_mouse
232
218
  dsl.click
233
219
  assert_equal 'Togusa', pop_up.value
234
220
 
@@ -26,7 +26,7 @@ class TestAccessibilityEnumeratorsBreadthFirst < MiniTest::Unit::TestCase
26
26
  def enum.first
27
27
  each { |x| return x }
28
28
  end
29
- assert_instance_of AX::StandardWindow, enum.first
29
+ refute_instance_of AX::Application, enum.first
30
30
  end
31
31
 
32
32
  # this was a big performance issue, so we should make sure it
@@ -119,4 +119,3 @@ class TestAccessibilityEnumeratorsDepthFirst < MiniTest::Unit::TestCase
119
119
  end
120
120
 
121
121
  end
122
-
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'test/integration/helper'
2
3
 
3
4
  class TestAccessibilityQualifier < MiniTest::Unit::TestCase
@@ -99,7 +100,7 @@ class TestAccessibilityQualifier < MiniTest::Unit::TestCase
99
100
 
100
101
  def test_qualifiers_can_use_aliased_attributes
101
102
  id = "I'm a little teapot"
102
- q = qualifier(:Button, id: id)
103
+ q = qualifier(:Button, id: id)
103
104
  app.main_window.children.each do |kid|
104
105
  if kid.attributes.include?(:identifier) && kid.id == id
105
106
  assert q.qualifies? kid
@@ -39,4 +39,8 @@ class TestAXElement < MiniTest::Unit::TestCase
39
39
  box.set :value, '' if box
40
40
  end
41
41
 
42
+ # @todo test setting selected text
43
+ # def test_setting
44
+ # end
45
+
42
46
  end
@@ -220,7 +220,7 @@ class TestAccessibilityCore < MiniTest::Unit::TestCase
220
220
  ##
221
221
  # The keyboard simulation stuff is a bit weird...
222
222
 
223
- def test_post_events_to
223
+ def test_post
224
224
  events = [[0x56,true], [0x56,false], [0x54,true], [0x54,false]]
225
225
  string = '42'
226
226
 
@@ -12,49 +12,35 @@ class TestAccessibilityTranslator < MiniTest::Unit::TestCase
12
12
  end
13
13
 
14
14
  def test_unprefixing
15
- def prefix_test before, after
16
- assert_equal after, TRANSLATOR.unprefix(before)
17
- end
18
-
19
- prefix_test 'AXButton', 'Button'
20
- prefix_test 'MCAXButton', 'Button'
21
- prefix_test 'AXURL', 'URL'
22
- prefix_test 'AXTitleUIElement', 'TitleUIElement'
23
- prefix_test 'AXIsApplicationRunning', 'ApplicationRunning'
24
- prefix_test 'AXAX', 'AX'
25
- prefix_test 'Quick Look', 'QuickLook'
15
+ assert_equal 'Button', TRANSLATOR.unprefix('AXButton')
16
+ assert_equal 'URL', TRANSLATOR.unprefix('AXURL')
17
+ assert_equal 'TitleUIElement', TRANSLATOR.unprefix('AXTitleUIElement')
18
+ assert_equal 'AX', TRANSLATOR.unprefix('AXAX')
19
+ assert_equal 'QuickLook', TRANSLATOR.unprefix('Quick Look')
26
20
  end
27
21
 
28
- def test_lookup
29
- def lookup_test key, values, expected
30
- assert_equal expected, TRANSLATOR.lookup(key, values)
31
- end
32
-
33
- lookup_test :children, [KAXChildrenAttribute], KAXChildrenAttribute
34
- lookup_test :title_ui_element, [KAXTitleUIElementAttribute], KAXTitleUIElementAttribute
35
- lookup_test :focused?, [KAXFocusedAttribute], KAXFocusedAttribute
36
- lookup_test :flabbergast, [], nil
37
- lookup_test :totally_fake, ['AXTotallyFake'], 'AXTotallyFake'
38
- end
39
-
40
- def test_lookup_aliases
41
- def lookup_test key, values, expected
42
- assert_equal expected, TRANSLATOR.lookup(key, values)
43
- end
44
-
45
- lookup_test :id, [], KAXIdentifierAttribute
46
- lookup_test :placeholder, [], KAXPlaceholderValueAttribute
22
+ def test_cocoaification
23
+ assert_equal KAXChildrenAttribute, TRANSLATOR.cocoaify(:children)
24
+ assert_equal KAXTitleUIElementAttribute, TRANSLATOR.cocoaify(:title_ui_element)
25
+ assert_equal KAXFocusedAttribute, TRANSLATOR.cocoaify(:focused?)
26
+ assert_equal 'AXTotallyFake', TRANSLATOR.cocoaify(:totally_fake)
27
+
28
+ # also check the aliases we have added
29
+ assert_equal KAXIdentifierAttribute, TRANSLATOR.cocoaify(:id)
30
+ assert_equal KAXPlaceholderValueAttribute, TRANSLATOR.cocoaify(:placeholder)
31
+
32
+ # cover this edge case :/
33
+ assert_equal KAXIsApplicationRunningAttribute, TRANSLATOR.cocoaify(:is_application_running?)
34
+ assert_equal KAXIsApplicationRunningAttribute, TRANSLATOR.cocoaify(:is_application_running)
35
+ assert_equal KAXIsApplicationRunningAttribute, TRANSLATOR.cocoaify(:application_running?)
36
+ assert_equal KAXIsApplicationRunningAttribute, TRANSLATOR.cocoaify(:application_running)
47
37
  end
48
38
 
49
39
  def test_rubyize
50
- def rubyize_test given, expected
51
- assert_equal Array(expected), TRANSLATOR.rubyize(Array(given))
52
- end
53
-
54
- rubyize_test KAXMainWindowAttribute, :main_window
55
- rubyize_test KAXRoleAttribute, :role
56
- rubyize_test KAXStringForRangeParameterizedAttribute, :string_for_range
57
- rubyize_test [KAXSubroleAttribute, KAXChildrenAttribute], [:subrole, :children]
40
+ assert_equal [:role], TRANSLATOR.rubyize([KAXRoleAttribute])
41
+ assert_equal [:main_window], TRANSLATOR.rubyize([KAXMainWindowAttribute])
42
+ assert_equal [:string_for_range], TRANSLATOR.rubyize([KAXStringForRangeParameterizedAttribute])
43
+ assert_equal [:subrole, :children], TRANSLATOR.rubyize([KAXSubroleAttribute, KAXChildrenAttribute])
58
44
  end
59
45
 
60
46
  def test_rubyize_doesnt_eat_original_data
@@ -63,73 +49,63 @@ class TestAccessibilityTranslator < MiniTest::Unit::TestCase
63
49
  assert_equal [KAXTitleAttribute, KAXMainWindowAttribute], array
64
50
  end
65
51
 
66
- def test_guess_notification_for
67
- def notif_test actual, expected
68
- assert_equal expected, TRANSLATOR.guess_notification_for(actual)
69
- end
70
-
71
- notif_test 'window_created', KAXWindowCreatedNotification
72
- notif_test :window_created, KAXWindowCreatedNotification
73
- notif_test KAXValueChangedNotification, KAXValueChangedNotification
74
- notif_test 'Cheezburger', 'Cheezburger'
75
- end
76
-
77
52
  def test_classify
78
- def classify_test actual, expected
79
- assert_equal expected, TRANSLATOR.classify(actual)
80
- end
81
-
82
- classify_test :buttons, 'Button'
83
- classify_test :button, 'Button'
84
- classify_test :menu_item, 'MenuItem'
85
- classify_test 'floating_window', 'FloatingWindow'
86
- classify_test 'outline_rows', 'OutlineRow'
53
+ assert_equal 'Button', TRANSLATOR.classify(:buttons)
54
+ assert_equal 'Button', TRANSLATOR.classify(:button)
55
+ assert_equal 'MenuItem', TRANSLATOR.classify(:menu_item)
56
+ assert_equal 'FloatingWindow', TRANSLATOR.classify('floating_window')
57
+ assert_equal 'OutlineRow', TRANSLATOR.classify('outline_rows')
87
58
  end
88
59
 
89
60
  def test_singularize
90
- def singularize_test actual, expected
91
- assert_equal expected, TRANSLATOR.singularize(actual)
92
- end
93
-
94
- singularize_test :buttons, 'button'
95
- singularize_test :button, 'button'
96
- singularize_test :windows, 'window'
97
- singularize_test :check_boxes, 'check_box'
98
- singularize_test 'classes', 'class'
61
+ assert_equal 'button', TRANSLATOR.singularize(:buttons)
62
+ assert_equal 'button', TRANSLATOR.singularize('button')
63
+ assert_equal 'window', TRANSLATOR.singularize(:windows)
64
+ assert_equal 'check_box', TRANSLATOR.singularize(:check_boxes)
65
+ assert_equal 'class', TRANSLATOR.singularize('classes')
99
66
  end
100
67
 
68
+ def test_guess_notification
69
+ assert_equal KAXWindowCreatedNotification, TRANSLATOR.guess_notification('window_created')
70
+ assert_equal KAXWindowCreatedNotification, TRANSLATOR.guess_notification(:window_created)
71
+ assert_equal KAXValueChangedNotification, TRANSLATOR.guess_notification(KAXValueChangedNotification)
72
+ assert_equal 'Cheezburger', TRANSLATOR.guess_notification('Cheezburger')
73
+ end
101
74
 
102
75
  def test_unprefixes_are_cached
103
76
  unprefixes = TRANSLATOR.instance_variable_get :@unprefixes
77
+
104
78
  unprefixed = unprefixes['AXPieIsTheTruth']
105
79
  assert_includes unprefixes.keys, 'AXPieIsTheTruth'
106
80
  assert_equal unprefixed, unprefixes['AXPieIsTheTruth']
107
81
  end
108
82
 
109
- def test_normalizations_are_cached
110
- normalizations = TRANSLATOR.instance_variable_get :@normalizations
111
- normalized = normalizations['AXTheAnswer']
112
- assert_includes normalizations.keys, 'AXTheAnswer'
113
- assert_equal normalized, normalizations['AXTheAnswer']
114
- end
115
-
116
83
  def test_rubyisms_are_cached
117
84
  rubyisms = TRANSLATOR.instance_variable_get :@rubyisms
118
- TRANSLATOR.instance_variable_set :@values, ['AXChocolatePancake']
119
- rubyized = rubyisms[:chocolate_pancake]
120
- assert_includes rubyisms.keys, :chocolate_pancake
121
- assert_equal rubyized, rubyisms[:chocolate_pancake]
122
-
123
- rubyized = rubyisms[:chocolate_pancake?]
124
- assert_includes rubyisms.keys, :chocolate_pancake?
125
- assert_equal rubyized, rubyisms[:chocolate_pancake]
126
- assert_equal rubyized, rubyisms[:chocolate_pancake?]
85
+
86
+ rubyized = rubyisms['AXTheAnswer']
87
+ assert_includes rubyisms.keys, 'AXTheAnswer'
88
+ assert_equal rubyized, rubyisms['AXTheAnswer']
89
+ end
90
+
91
+ def test_cocoaifications_are_cached
92
+ cocoas = TRANSLATOR.instance_variable_get :@cocoaifications
93
+
94
+ cocoaed = cocoas[:chocolate_pancake]
95
+ assert_includes cocoas.keys, :chocolate_pancake
96
+ assert_equal cocoaed, cocoas[:chocolate_pancake]
97
+
98
+ cocoaed = cocoas[:chocolate_pancake?]
99
+ assert_includes cocoas.keys, :chocolate_pancake?
100
+ assert_equal cocoaed, cocoas[:chocolate_pancake?]
101
+ # make sure we didn't kill the other guy
102
+ assert_equal cocoaed, cocoas[:chocolate_pancake]
127
103
  end
128
104
 
129
105
  def test_classifications_are_cached
130
106
  classifications = TRANSLATOR.instance_variable_get :@classifications
131
107
 
132
- classified = TRANSLATOR.classify 'made_up_class_name'
108
+ classified = TRANSLATOR.classify 'made_up_class_name'
133
109
  assert_includes classifications.keys, 'made_up_class_name'
134
110
  assert_equal classified, classifications['made_up_class_name']
135
111
  end
@@ -137,7 +113,7 @@ class TestAccessibilityTranslator < MiniTest::Unit::TestCase
137
113
  def test_singularizations_are_cached
138
114
  singulars = TRANSLATOR.instance_variable_get :@singularizations
139
115
 
140
- singular = TRANSLATOR.singularize 'buttons'
116
+ singular = TRANSLATOR.singularize 'buttons'
141
117
  assert_includes singulars.keys, 'buttons'
142
118
  assert_equal singular, singulars['buttons']
143
119
  end
@@ -2,9 +2,6 @@
2
2
  require 'test/helper'
3
3
  require 'ax/application'
4
4
 
5
- class AX::Element
6
- attr_reader :ref
7
- end
8
5
 
9
6
  class TestAXApplication < MiniTest::Unit::TestCase
10
7
 
@@ -17,15 +14,13 @@ class TestAXApplication < MiniTest::Unit::TestCase
17
14
  NSRunningApplication.runningApplicationWithProcessIdentifier app.pid
18
15
  end
19
16
 
20
- def test_is_a_direct_subclass_of_element
17
+ def test_subclass_of_element
21
18
  assert_equal AX::Element, AX::Application.superclass
22
19
  end
23
20
 
24
- def test_inspect_includes_pid
21
+ def test_inspect
22
+ assert_match app.inspect, /children/
25
23
  assert_match /\spid=\d+/, app.inspect
26
- end
27
-
28
- def test_inspect_includes_focused
29
24
  assert_match /\sfocused\[(?:✔|✘)\]/, app.inspect
30
25
  end
31
26
 
@@ -35,10 +30,9 @@ class TestAXApplication < MiniTest::Unit::TestCase
35
30
  mock.define_singleton_method(:terminate) { got_called = true }
36
31
  mock.define_singleton_method(:terminated?) { false }
37
32
  app.instance_variable_set :@app, mock
33
+
38
34
  app.perform :terminate
39
35
  assert got_called
40
- ensure
41
- app.instance_variable_set :@app, running_app
42
36
  end
43
37
 
44
38
  def test_force_terminate
@@ -50,37 +44,44 @@ class TestAXApplication < MiniTest::Unit::TestCase
50
44
 
51
45
  app.perform :force_terminate
52
46
  assert got_called
53
- ensure
54
- app.instance_variable_set :@app, running_app
55
47
  end
56
48
 
57
- def test_overrides_call_super
58
- assert_match app.inspect, /children/
49
+ def test_writable_handles_focused_and_hidden
50
+ assert app.writable? :focused?
51
+ assert app.writable? :focused
52
+ assert app.writable? :hidden
53
+ assert app.writable? :hidden?
54
+ end
55
+
56
+ def test_attribute_calls_super
59
57
  assert_equal 'AXElementsTester', app.title
58
+ end
60
59
 
60
+ def test_set_calls_super
61
61
  called_super = false
62
- app.define_singleton_method :perform do |name|
63
- called_super = true if name == :some_action
62
+ app.define_singleton_method :set do |attr, value|
63
+ called_super = true if attr == :thingy && value == 'pie'
64
64
  end
65
- app.perform :some_action
65
+ app.set :thingy, 'pie'
66
66
  assert called_super
67
+ end
67
68
 
69
+ def test_writable_calls_super
68
70
  called_super = false
69
- app.define_singleton_method :set do |attr, value|
70
- called_super = true if attr == :thingy && value == 'pie'
71
+ app.define_singleton_method :writable? do |attr|
72
+ called_super = true if attr == :brain
71
73
  end
72
- app.set :thingy, 'pie'
74
+ app.writable? :brain
73
75
  assert called_super
74
76
  end
75
77
 
76
- def test_type_string_forwards_events
77
- skip "This strangely causes other tests to fail occassionally"
78
- got_callback = false
79
- app.ref.define_singleton_method :post do |events|
80
- got_callback = true if events.kind_of?(Array)
78
+ def test_perform_calls_super
79
+ called_super = false
80
+ app.define_singleton_method :perform do |name|
81
+ called_super = true if name == :some_action
81
82
  end
82
- app.type_string 'test'
83
- assert got_callback
83
+ app.perform :some_action
84
+ assert called_super
84
85
  end
85
86
 
86
87
  def test_bundle_identifier
@@ -11,21 +11,17 @@ class TestAXSystemWide < MiniTest::Unit::TestCase
11
11
  @system_wide ||= AX::SystemWide.new
12
12
  end
13
13
 
14
+ # this is more so I know if Apple ever changes how CFEqual() works on AX stuff
14
15
  def test_is_effectively_a_singleton
15
16
  assert_equal AX::SystemWide.new, AX::SystemWide.new
16
17
  end
17
18
 
18
- def test_type_string_forwards_events
19
- system = system_wide.ref
20
- meth = system.method :post
21
- got_callback = false
22
- system.define_singleton_method :post do |events|
23
- got_callback = true if events.kind_of?(Array)
24
- end
25
- system_wide.type_string 'test'
26
- assert got_callback
27
- ensure
28
- system.define_singleton_method :post, meth if meth
19
+ def test_type_forwards_events
20
+ ref = system_wide.ref
21
+ called_back = false
22
+ ref.define_singleton_method(:post) { |x| called_back = true if x.kind_of? Array }
23
+ assert system_wide.type 'test'
24
+ assert called_back
29
25
  end
30
26
 
31
27
  def test_search_not_allowed
@@ -36,13 +32,8 @@ class TestAXSystemWide < MiniTest::Unit::TestCase
36
32
  assert_raises(NoMethodError) { system_wide.on_notification }
37
33
  end
38
34
 
39
- def test_element_at
40
- system = system_wide.ref
41
- [[10,10],[500,500]].each do |point|
42
- expected = system.element_at(point)
43
- actual = system_wide.element_at(point).ref
44
- assert_equal expected, actual
45
- end
35
+ def test_element_at # returns a wrapped dude
36
+ assert_kind_of AX::Element, system_wide.element_at([10,10])
46
37
  end
47
38
 
48
39
  def test_parameterized_attributes_is_empty
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: AXElements
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.7.6
5
+ version: 0.7.7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Mark Rada
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-06 00:00:00 Z
12
+ date: 2012-04-07 00:00:00 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -59,12 +59,11 @@ dependencies:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: "1.17"
62
- description: 'AXElements is a DSL abstraction on top of the Mac OS X Accessibility
63
- Framework
62
+ description: 'AXElements is a UI automation DSL built on top of the Mac OS X Accessibility
64
63
 
65
- that allows code to be written in a very natural and declarative style that
64
+ Framework that allows code to be written in a very natural and declarative
66
65
 
67
- describes user interactions.
66
+ style that describes user interactions.
68
67
 
69
68
  '
70
69
  email: mrada@marketcircle.com
@@ -76,7 +75,6 @@ extra_rdoc_files:
76
75
  - docs/Acting.markdown
77
76
  - docs/Debugging.markdown
78
77
  - docs/images/all_the_buttons.jpg
79
- - docs/images/AX.png
80
78
  - docs/images/next_version.png
81
79
  - docs/images/ui_hierarchy.dot
82
80
  - docs/images/ui_hierarchy.png
@@ -165,7 +163,6 @@ files:
165
163
  - docs/Acting.markdown
166
164
  - docs/Debugging.markdown
167
165
  - docs/images/all_the_buttons.jpg
168
- - docs/images/AX.png
169
166
  - docs/images/next_version.png
170
167
  - docs/images/ui_hierarchy.dot
171
168
  - docs/images/ui_hierarchy.png
Binary file