AXElements 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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