uia 0.3.1 → 0.3.2

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