uia 0.3.1 → 0.3.2

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.
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ === Version 0.3.2 / 2014-05-13
2
+ * Enhancements
3
+ * added #with method to extend an Element based on ControlPatterns
4
+ * Uia::ControlPatterns::MenuItems can select a menu item by name or path
5
+
1
6
  === Version 0.3.1 / 2014-05-07
2
7
  * Enhancements
3
8
  * added Table#row_at method
Binary file
Binary file
@@ -167,6 +167,11 @@ namespace UIA.Helper
167
167
  return NullOr(AutomationElement.FromHandle(windowHandle));
168
168
  }
169
169
 
170
+ public Element MenuItem(string name)
171
+ {
172
+ return FindFirst(TreeScope.Subtree, new AndCondition(name.NameCondition(), ControlType.MenuItem.Condition()));
173
+ }
174
+
170
175
  public static Element ByRuntimeId(int[] runtimeId)
171
176
  {
172
177
  return FindFirst(new PropertyCondition(AutomationElement.RuntimeIdProperty, runtimeId), TreeScope.Descendants);
@@ -35,6 +35,11 @@ namespace UIA.Helper
35
35
  return new PropertyCondition(AutomationElement.NameProperty, name);
36
36
  }
37
37
 
38
+ public static Condition Condition(this ControlType controlType)
39
+ {
40
+ return new PropertyCondition(AutomationElement.ControlTypeProperty, controlType);
41
+ }
42
+
38
43
  public static int PropertyId(this string propertyName)
39
44
  {
40
45
  var automationField = typeof(AutomationElement).GetField(propertyName);
@@ -0,0 +1,27 @@
1
+ #include "Stdafx.h"
2
+
3
+ extern "C" {
4
+ void SelectMenuItemPath(ElementInformationPtr element, char* errorInfo, const int errorInfoLength, list<const char*>& items) {
5
+ try {
6
+ auto current = ElementFrom(element);
7
+
8
+ for(auto item = items.begin(); item != items.end(); ++item) {
9
+ auto name = gcnew String(*item);
10
+
11
+ current = current->MenuItem(name);
12
+ if( nullptr == current) {
13
+ throw gcnew Exception(String::Format("the menu item \"{0}\" was not found", name));
14
+ }
15
+
16
+ current->As<InvokePattern^>(InvokePattern::Pattern)->Invoke();
17
+ }
18
+ } catch(Exception^ e) {
19
+ StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
20
+ }
21
+ }
22
+
23
+ __declspec(dllexport) void MenuItem_SelectPath(ElementInformationPtr element, char* errorInfo, const int errorInfoLength, const int n, const char* arg0, ...) {
24
+ GRAB_VARARGS(menuItems, const char*, n);
25
+ SelectMenuItemPath(element, errorInfo, errorInfoLength, menuItems);
26
+ }
27
+ }
@@ -95,6 +95,7 @@
95
95
  <ClCompile Include="ElementMethods.cpp" />
96
96
  <ClCompile Include="ExpandCollapseMethods.cpp" />
97
97
  <ClCompile Include="InvokePatternMethods.cpp" />
98
+ <ClCompile Include="MenuItemMethods.cpp" />
98
99
  <ClCompile Include="MouseMethods.cpp" />
99
100
  <ClCompile Include="RangeValueMethods.cpp" />
100
101
  <ClCompile Include="SelectionItemMethods.cpp" />
@@ -16,6 +16,9 @@
16
16
  <Filter Include="Source Files\Patterns">
17
17
  <UniqueIdentifier>{a1dddb33-e832-4b83-b6d7-46462084fad2}</UniqueIdentifier>
18
18
  </Filter>
19
+ <Filter Include="Source Files\ControlTypes">
20
+ <UniqueIdentifier>{f17fb0d5-c4d9-44ae-9cf3-518f4f70839d}</UniqueIdentifier>
21
+ </Filter>
19
22
  </ItemGroup>
20
23
  <ItemGroup>
21
24
  <ClInclude Include="Stdafx.h">
@@ -98,5 +101,8 @@
98
101
  <ClCompile Include="ConditionMethods.cpp">
99
102
  <Filter>Source Files</Filter>
100
103
  </ClCompile>
104
+ <ClCompile Include="MenuItemMethods.cpp">
105
+ <Filter>Source Files\ControlTypes</Filter>
106
+ </ClCompile>
101
107
  </ItemGroup>
102
108
  </Project>
@@ -0,0 +1,7 @@
1
+ class Module
2
+ def const_get_path(path)
3
+ path.split('::').reduce(self) do |m, current|
4
+ m.const_get current.split('_').map(&:capitalize).join
5
+ end
6
+ end
7
+ end
@@ -9,9 +9,11 @@ class Symbol
9
9
 
10
10
  # :selection_item => Uia::Patterns::SelectionItem
11
11
  def to_pattern_const
12
- "Uia::Patterns::#{self.to_s.capitalize}".split('::').reduce(Object) do |m, current|
13
- m.const_get current.split('_').map(&:capitalize).join
14
- end
12
+ Uia::Patterns.const_get_path "#{self.capitalize}"
13
+ end
14
+
15
+ def to_control_type
16
+ Uia::ControlTypes.const_get_path "#{self.capitalize}"
15
17
  end
16
18
 
17
19
  def to_control_type_const
@@ -0,0 +1,10 @@
1
+ module Uia
2
+ module ControlTypes
3
+ module MenuItems
4
+ def select_menu_path(*path)
5
+ Library.select_menu_path @element, *path
6
+ end
7
+ alias_method :select_menu_item, :select_menu_path
8
+ end
9
+ end
10
+ end
data/lib/uia/element.rb CHANGED
@@ -91,6 +91,10 @@ module Uia
91
91
  extend pattern.to_pattern_const
92
92
  end
93
93
 
94
+ def with(control_types)
95
+ extend control_types.to_control_type
96
+ end
97
+
94
98
  def patterns
95
99
  @element.pattern_ids.map { |id| Library::Constants::Patterns.find(@default) { |_, v| v == id }.first }
96
100
  end
data/lib/uia/library.rb CHANGED
@@ -75,12 +75,10 @@ module Uia
75
75
  attach_function :Condition_ControlType, [:int, :varargs], SearchCondition.by_ref
76
76
 
77
77
  def self.pattern_condition(*patterns)
78
- string_buffer = FFI::MemoryPointer.new :char, 1024
79
- pattern_strings = patterns.flatten.map(&:to_pattern_available_property)
80
- result = Condition_Pattern string_buffer, 1024, pattern_strings.count, *pattern_strings.to_var_args(:string)
81
- error_info = string_buffer.read_string
82
- raise error_info unless error_info.empty?
83
- result
78
+ try_catch do |s, n|
79
+ pattern_strings = patterns.flatten.map(&:to_pattern_available_property)
80
+ Condition_Pattern s, n, pattern_strings.count, *pattern_strings.to_var_args(:string)
81
+ end
84
82
  end
85
83
 
86
84
  def self.control_type_condition(*control_types)
@@ -153,6 +151,12 @@ module Uia
153
151
  p.read_string
154
152
  end
155
153
 
154
+ # MenuItem methods
155
+ attach_function :MenuItem_SelectPath, [:pointer, :pointer, :int, :int, :varargs], :void
156
+ def self.select_menu_path(element, *path)
157
+ try_catch {|s, n| MenuItem_SelectPath element, s, n, path.count, *path.to_var_args(:string) }
158
+ end
159
+
156
160
  def self.find_by_runtime_id(id)
157
161
  p = FFI::MemoryPointer.new :int, id.count
158
162
  p.write_array_of_int(id)
@@ -160,35 +164,33 @@ module Uia
160
164
  Uia::Element.new(result) unless result.empty?
161
165
  end
162
166
 
163
- def self.can_throw(method, *args)
167
+ def self.try_catch(&block)
164
168
  string_buffer = FFI::MemoryPointer.new :char, 1024
165
- result = send method, *(args << string_buffer << 1024)
169
+ result = block.call(string_buffer, 1024)
166
170
  error_info = string_buffer.read_string
167
171
  raise error_info unless error_info.empty?
168
172
  result
169
173
  end
170
174
 
175
+ def self.can_throw(method, *args)
176
+ try_catch {|s, n| send method, *(args << s << n) }
177
+ end
178
+
171
179
  def self.find_first(element, scope, *conditions)
172
- string_buffer = FFI::MemoryPointer.new :char, 1024
173
- result = FindFirst element, scope, string_buffer, 1024, conditions.count, *conditions.to_var_args(:pointer)
174
- error_info = string_buffer.read_string
175
- raise error_info unless error_info.empty?
180
+ result = try_catch {|s, n| FindFirst element, scope, s, n, conditions.count, *conditions.to_var_args(:pointer) }
176
181
  Uia::Element.new(result) unless result.empty?
177
182
  end
178
183
 
179
184
  def self.find_all(element, scope, *conditions)
180
185
  elements_pointer = FFI::MemoryPointer.new :pointer
181
- string_buffer = FFI::MemoryPointer.new :char, 1024
182
- result = FindAll element, elements_pointer, scope, string_buffer, 1024, conditions.count, *conditions.to_var_args(:pointer)
183
- error_info = string_buffer.read_string
184
- raise error_info unless error_info.empty?
186
+ result = try_catch {|s, n| FindAll element, elements_pointer, scope, s, n, conditions.count, *conditions.to_var_args(:pointer) }
185
187
  result.times.collect do |which_element|
186
188
  pointer = elements_pointer.read_pointer + which_element * ManagedElementStruct.size
187
189
  Uia::Element.new(ManagedElementStruct.new(pointer))
188
190
  end
189
191
  end
190
192
 
191
- rescue LoadError => e
193
+ rescue LoadError
192
194
  raise LoadError, 'You must install the Visual Studio 2012 C++ Runtime Environment to use the Uia gem (http://www.microsoft.com/en-us/download/details.aspx?id=30679)'
193
195
  end
194
196
  end
data/lib/uia/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Uia
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
  end
data/lib/uia.rb CHANGED
@@ -6,6 +6,7 @@ require 'uia/finder'
6
6
  require 'uia/element'
7
7
 
8
8
  require_rel 'uia/patterns'
9
+ require_rel 'uia/control_types'
9
10
  require_rel 'core_ext'
10
11
 
11
12
  module Uia
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Uia::ControlTypes::MenuItems do
4
+ Given(:main) { Uia.find_element(title: 'MainFormWindow').with(:menu_items) }
5
+
6
+ after(:each) do
7
+ about = Uia.find_element(title: 'About')
8
+ about.send_keys [:alt, :f4] if about
9
+ end
10
+
11
+ context 'selecting individually' do
12
+ When { main.select_menu_item 'About' }
13
+ Then { Uia.find_element(title: 'About') != nil }
14
+ end
15
+
16
+ context 'selecting a path' do
17
+ context 'valid' do
18
+ When { main.select_menu_path 'File', 'Roundabout Way', 'To', 'About' }
19
+ Then { Uia.find_element(title: 'About') != nil }
20
+ end
21
+
22
+ context 'invalid' do
23
+ Given(:bad_path) { main.select_menu_path 'File', 'Roundabout Way', 'To', 'Something Not There' }
24
+ Then { expect { bad_path }.to raise_error(RuntimeError, /Something Not There/) }
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-07 00:00:00.000000000 Z
12
+ date: 2014-05-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
@@ -172,6 +172,7 @@ files:
172
172
  - ext/UiaDll/UiaDll/ElementStructures.h
173
173
  - ext/UiaDll/UiaDll/ExpandCollapseMethods.cpp
174
174
  - ext/UiaDll/UiaDll/InvokePatternMethods.cpp
175
+ - ext/UiaDll/UiaDll/MenuItemMethods.cpp
175
176
  - ext/UiaDll/UiaDll/MouseMethods.cpp
176
177
  - ext/UiaDll/UiaDll/PatternInformationStructures.h
177
178
  - ext/UiaDll/UiaDll/RangeValueMethods.cpp
@@ -194,9 +195,11 @@ files:
194
195
  - ext/UiaDll/UiaDll/WindowMethods.cpp
195
196
  - ext/UiaDll/UiaDll/app.rc
196
197
  - lib/core_ext/array.rb
198
+ - lib/core_ext/module.rb
197
199
  - lib/core_ext/string.rb
198
200
  - lib/core_ext/symbol.rb
199
201
  - lib/uia.rb
202
+ - lib/uia/control_types/menu_item.rb
200
203
  - lib/uia/element.rb
201
204
  - lib/uia/finder.rb
202
205
  - lib/uia/keys.rb
@@ -225,6 +228,7 @@ files:
225
228
  - spec/app/WindowsForms.exe
226
229
  - spec/core_ext/symbol_spec.rb
227
230
  - spec/spec_helper.rb
231
+ - spec/uia/control_types/menu_item_spec.rb
228
232
  - spec/uia/element_spec.rb
229
233
  - spec/uia/keys_spec.rb
230
234
  - spec/uia/patterns/expand_collapse_spec.rb
@@ -257,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
257
261
  version: '0'
258
262
  segments:
259
263
  - 0
260
- hash: 471307667
264
+ hash: 59019763
261
265
  required_rubygems_version: !ruby/object:Gem::Requirement
262
266
  none: false
263
267
  requirements:
@@ -266,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
270
  version: '0'
267
271
  segments:
268
272
  - 0
269
- hash: 471307667
273
+ hash: 59019763
270
274
  requirements: []
271
275
  rubyforge_project:
272
276
  rubygems_version: 1.8.28
@@ -279,6 +283,7 @@ test_files:
279
283
  - spec/app/WindowsForms.exe
280
284
  - spec/core_ext/symbol_spec.rb
281
285
  - spec/spec_helper.rb
286
+ - spec/uia/control_types/menu_item_spec.rb
282
287
  - spec/uia/element_spec.rb
283
288
  - spec/uia/keys_spec.rb
284
289
  - spec/uia/patterns/expand_collapse_spec.rb