uia 0.0.5.1 → 0.0.6
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 +17 -2
- data/Gemfile +1 -0
- data/Rakefile +13 -0
- data/ext/UiaDll/UIA.Helper/{AutomationProperty.cs → AutomationPropertyCondition.cs} +1 -1
- data/ext/UiaDll/UIA.Helper/Element.cs +46 -6
- data/ext/UiaDll/UIA.Helper/Extensions.cs +13 -0
- data/ext/UiaDll/UIA.Helper/UIA.Helper.csproj +1 -1
- data/ext/UiaDll/UiaDll.Test/ElementInformationTest.cpp +20 -4
- data/ext/UiaDll/UiaDll.Test/ElementStub.h +16 -2
- data/ext/UiaDll/UiaDll.Test/PatternInformationTest.cpp +35 -0
- data/ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj +6 -4
- data/ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj.filters +3 -0
- data/ext/UiaDll/UiaDll/ElementMethods.cpp +62 -17
- data/ext/UiaDll/UiaDll/ElementStructures.h +19 -9
- data/ext/UiaDll/UiaDll/ExpandCollapseMethods.cpp +33 -0
- data/ext/UiaDll/UiaDll/InvokePatternMethods.cpp +11 -0
- data/ext/UiaDll/UiaDll/PatternInformationStructures.h +90 -0
- data/ext/UiaDll/UiaDll/SelectionItemMethods.cpp +40 -0
- data/ext/UiaDll/UiaDll/SelectionMethods.cpp +16 -0
- data/ext/UiaDll/UiaDll/Stdafx.h +3 -0
- data/ext/UiaDll/UiaDll/ToggleMethods.cpp +25 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj +9 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +24 -0
- data/ext/UiaDll/UiaDll/ValuePatternMethods.cpp +25 -0
- data/lib/uia.rb +14 -6
- data/lib/uia/element.rb +35 -11
- data/lib/uia/finder.rb +33 -0
- data/lib/uia/library.rb +48 -6
- data/lib/uia/library/element_attributes.rb +11 -0
- data/lib/uia/library/structs.rb +93 -5
- data/lib/uia/patterns/expand_collapse.rb +17 -0
- data/lib/uia/patterns/invoke.rb +9 -0
- data/lib/uia/patterns/selection.rb +17 -0
- data/lib/uia/patterns/selection_item.rb +25 -0
- data/lib/uia/patterns/toggle.rb +17 -0
- data/lib/uia/patterns/value.rb +22 -0
- data/lib/uia/version.rb +1 -1
- data/spec/spec_helper.rb +0 -2
- data/spec/uia/element_spec.rb +35 -8
- data/spec/uia/patterns/expand_collapse_spec.rb +24 -0
- data/spec/uia/patterns/invoke_spec.rb +15 -0
- data/spec/uia/patterns/selection_item_spec.rb +55 -0
- data/spec/uia/patterns/selection_spec.rb +30 -0
- data/spec/uia/patterns/toggle_spec.rb +41 -0
- data/spec/uia/patterns/value_spec.rb +16 -0
- data/spec/uia_spec.rb +26 -7
- metadata +37 -4
data/lib/uia/finder.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Uia
|
2
|
+
module Finder
|
3
|
+
def find_by_id(id)
|
4
|
+
find_by_property(:id, id)
|
5
|
+
end
|
6
|
+
|
7
|
+
def find_by_name(name)
|
8
|
+
find_by_property(:name, name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_by_pid(pid)
|
12
|
+
Library.find_by_pid(pid)
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_by_runtime_id(runtime_id)
|
16
|
+
Library.find_by_runtime_id(runtime_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_by_handle(handle)
|
20
|
+
Library.find_by_handle handle
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def find_by_property(property, what)
|
25
|
+
case what
|
26
|
+
when String
|
27
|
+
Library.send("find_by_#{property}", what)
|
28
|
+
when Regexp
|
29
|
+
children.find { |e| e.send(property) =~ what }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/uia/library.rb
CHANGED
@@ -17,33 +17,75 @@ module Uia
|
|
17
17
|
attach_function :init, :initialize, [:string], :void
|
18
18
|
init(uia_directory)
|
19
19
|
|
20
|
-
def self.attach_throwable_function(name_alias, name, arg_types, return_type)
|
20
|
+
def self.attach_throwable_function(name_alias, name, arg_types, return_type, &block)
|
21
21
|
attach_function name, arg_types + [:pointer, :int], return_type
|
22
22
|
define_singleton_method(name_alias) do |*args|
|
23
|
-
can_throw(name, *args)
|
23
|
+
result = can_throw(name, *args)
|
24
|
+
return block.call(result) if block
|
25
|
+
result
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
29
|
+
# returns nil rather than empty FFI::Struct for Uia::Element
|
30
|
+
element_or_nil = lambda { |e| Uia::Element.new(e) unless e.empty? }
|
31
|
+
|
27
32
|
# cleanup
|
28
33
|
attach_function :release_element, :Element_Release, [:pointer], :void
|
29
34
|
attach_function :release_elements, :Element_ReleaseMany, [:pointer], :void
|
35
|
+
attach_function :release_value_info, :Value_Release, [:pointer], :void
|
36
|
+
attach_function :release_toggle_info, :Toggle_Release, [:pointer], :void
|
37
|
+
attach_function :release_selection_info, :Selection_Release, [:pointer], :void
|
38
|
+
attach_function :release_selection_item_info, :SelectionItem_Release, [:pointer], :void
|
39
|
+
attach_function :release_expand_collapse_info, :ExpandCollapse_Release, [:pointer], :void
|
40
|
+
|
41
|
+
# root methods
|
42
|
+
attach_throwable_function :root_children, :Root_Children, [], ElementChildrenStruct.by_ref
|
30
43
|
|
31
44
|
# finding elements
|
32
|
-
attach_throwable_function :find_by_id, :Element_FindById, [:string], ElementStruct.by_ref
|
33
|
-
attach_throwable_function :
|
45
|
+
attach_throwable_function :find_by_id, :Element_FindById, [:string], ElementStruct.by_ref, &element_or_nil
|
46
|
+
attach_throwable_function :find_by_name, :Element_FindByName, [:string], ElementStruct.by_ref, &element_or_nil
|
47
|
+
attach_throwable_function :find_by_pid, :Element_FindByProcessId, [:int], ElementStruct.by_ref, &element_or_nil
|
34
48
|
attach_throwable_function :find_by_handle, :Element_FindByHandle, [:int], ElementStruct.by_ref
|
35
49
|
attach_function :Element_FindByRuntimeId, [:pointer, :int, :pointer, :int], ElementStruct.by_ref
|
36
50
|
|
37
51
|
# element methods
|
52
|
+
attach_throwable_function :find_child_by_id, :Element_FindChildById, [:pointer, :string], ElementStruct.by_ref, &element_or_nil
|
53
|
+
attach_throwable_function :find_child_by_name, :Element_FindChildByName, [:pointer, :string], ElementStruct.by_ref, &element_or_nil
|
38
54
|
attach_throwable_function :children, :Element_Children, [:pointer], ElementChildrenStruct.by_ref
|
39
|
-
attach_throwable_function :children_of_type, :Element_ChildrenOfType, [:pointer, PropertyId], ElementChildrenStruct.by_ref
|
40
55
|
attach_throwable_function :descendants, :Element_Descendants, [:pointer], ElementChildrenStruct.by_ref
|
41
56
|
attach_throwable_function :click, :Element_Click, [:pointer], :void
|
57
|
+
attach_throwable_function :refresh, :Element_Refresh, [:pointer], :void
|
58
|
+
|
59
|
+
# ValuePattern methods
|
60
|
+
attach_throwable_function :set_value, :Value_Set, [:pointer, :string], :void
|
61
|
+
attach_throwable_function :value_info, :Value_Information, [:pointer], ValueInformation.by_ref
|
62
|
+
|
63
|
+
# ExpandCollapsePattern methods
|
64
|
+
attach_throwable_function :expand_collapse_info, :ExpandCollapse_Information, [:pointer], ExpandCollapseInformation.by_ref
|
65
|
+
attach_throwable_function :expand, :ExpandCollapse_Expand, [:pointer], :void
|
66
|
+
attach_throwable_function :collapse, :ExpandCollapse_Collapse, [:pointer], :void
|
67
|
+
|
68
|
+
# InvokePattern methods
|
69
|
+
attach_throwable_function :invoke, :Invoke, [:pointer], :void
|
70
|
+
|
71
|
+
# TogglePattern methods
|
72
|
+
attach_throwable_function :toggle_information, :Toggle_Information, [:pointer], ToggleInformation.by_ref
|
73
|
+
attach_throwable_function :toggle, :Toggle, [:pointer], :void
|
74
|
+
|
75
|
+
# SelectionPattern methods
|
76
|
+
attach_throwable_function :selection_info, :Selection_Information, [:pointer], SelectionInformation.by_ref
|
77
|
+
|
78
|
+
# SelectionItemPattern methods
|
79
|
+
attach_throwable_function :selection_item_info, :SelectionItem_Information, [:pointer], SelectionItemInformation.by_ref
|
80
|
+
attach_throwable_function :select, :SelectionItem_Select, [:pointer], :void
|
81
|
+
attach_throwable_function :add_to_selection, :SelectionItem_AddToSelection, [:pointer], :void
|
82
|
+
attach_throwable_function :remove_from_selection, :SelectionItem_RemoveFromSelection, [:pointer], :void
|
42
83
|
|
43
84
|
def self.find_by_runtime_id(id)
|
44
85
|
p = FFI::MemoryPointer.new :int, id.count
|
45
86
|
p.write_array_of_int(id)
|
46
|
-
can_throw(:Element_FindByRuntimeId, p, id.count)
|
87
|
+
result = can_throw(:Element_FindByRuntimeId, p, id.count)
|
88
|
+
Uia::Element.new(result) unless result.empty?
|
47
89
|
end
|
48
90
|
|
49
91
|
def self.can_throw(method, *args)
|
data/lib/uia/library/structs.rb
CHANGED
@@ -9,10 +9,12 @@ module Uia
|
|
9
9
|
:runtime_id, :pointer,
|
10
10
|
:number_of_ids, :int,
|
11
11
|
:name, :string,
|
12
|
+
:class_name, :string,
|
12
13
|
:control_type_id, :int,
|
13
14
|
:patterns, :pointer,
|
14
15
|
:patterns_length, :int,
|
15
|
-
:id, :string
|
16
|
+
:id, :string,
|
17
|
+
:is_enabled, :bool
|
16
18
|
|
17
19
|
def id
|
18
20
|
self[:id]
|
@@ -38,15 +40,26 @@ module Uia
|
|
38
40
|
self[:patterns].read_array_of_int(self[:patterns_length])
|
39
41
|
end
|
40
42
|
|
41
|
-
def children
|
42
|
-
|
43
|
-
elements.children
|
43
|
+
def children
|
44
|
+
Library.children(self).children
|
44
45
|
end
|
45
46
|
|
46
47
|
def descendants
|
47
48
|
Library.descendants(self).children
|
48
49
|
end
|
49
50
|
|
51
|
+
def empty?
|
52
|
+
to_ptr.address == 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def enabled?
|
56
|
+
self[:is_enabled]
|
57
|
+
end
|
58
|
+
|
59
|
+
def class_name
|
60
|
+
self[:class_name]
|
61
|
+
end
|
62
|
+
|
50
63
|
private
|
51
64
|
def number_of_ids
|
52
65
|
self[:number_of_ids]
|
@@ -72,7 +85,7 @@ module Uia
|
|
72
85
|
:items, :pointer
|
73
86
|
|
74
87
|
def children
|
75
|
-
|
88
|
+
self[:length].times.collect do |i|
|
76
89
|
ElementCast.new(self[:items] + i * ElementCast.size)
|
77
90
|
end
|
78
91
|
end
|
@@ -81,5 +94,80 @@ module Uia
|
|
81
94
|
Library.release_elements(pointer)
|
82
95
|
end
|
83
96
|
end
|
97
|
+
|
98
|
+
class ValueInformation < FFI::ManagedStruct
|
99
|
+
layout :is_read_only, :bool,
|
100
|
+
:value, :string
|
101
|
+
|
102
|
+
def read_only?
|
103
|
+
self[:is_read_only]
|
104
|
+
end
|
105
|
+
|
106
|
+
def value
|
107
|
+
self[:value]
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.release(pointer)
|
111
|
+
Library.release_value_info(pointer)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class ToggleInformation < FFI::ManagedStruct
|
116
|
+
layout :state, :string
|
117
|
+
|
118
|
+
def state
|
119
|
+
self[:state]
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.release(pointer)
|
123
|
+
Library.release_toggle_info(pointer)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class SelectionInformation < FFI::ManagedStruct
|
128
|
+
layout :can_multi_select, :bool,
|
129
|
+
:is_selection_required, :bool
|
130
|
+
|
131
|
+
def multi_select?
|
132
|
+
self[:can_multi_select]
|
133
|
+
end
|
134
|
+
|
135
|
+
def selection_required?
|
136
|
+
self[:is_selection_required]
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.release(pointer)
|
140
|
+
Library.release_selection_info(pointer)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class SelectionItemInformation < FFI::ManagedStruct
|
145
|
+
layout :is_selected, :bool,
|
146
|
+
:container, ElementCast.ptr
|
147
|
+
|
148
|
+
def selected?
|
149
|
+
self[:is_selected]
|
150
|
+
end
|
151
|
+
|
152
|
+
def container
|
153
|
+
self[:container] unless self[:container].empty?
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.release(pointer)
|
157
|
+
Library.release_selection_item_info(pointer)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class ExpandCollapseInformation < FFI::ManagedStruct
|
162
|
+
layout :expand_collapse_state, :string
|
163
|
+
|
164
|
+
def expand_collapse_state
|
165
|
+
self[:expand_collapse_state]
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.release(pointer)
|
169
|
+
Library.release_expand_collapse_info(pointer)
|
170
|
+
end
|
171
|
+
end
|
84
172
|
end
|
85
173
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Uia
|
2
|
+
module Patterns
|
3
|
+
module ExpandCollapse
|
4
|
+
def expand
|
5
|
+
Library.expand(@element)
|
6
|
+
end
|
7
|
+
|
8
|
+
def collapse
|
9
|
+
Library.collapse(@element)
|
10
|
+
end
|
11
|
+
|
12
|
+
def expand_collapse_state
|
13
|
+
Library.expand_collapse_info(@element).expand_collapse_state.downcase.to_sym
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Uia
|
2
|
+
module Patterns
|
3
|
+
module Selection
|
4
|
+
def selection_items
|
5
|
+
descendants.map {|e| e.as :selection_item }
|
6
|
+
end
|
7
|
+
|
8
|
+
def multi_select?
|
9
|
+
Library.selection_info(@element).multi_select?
|
10
|
+
end
|
11
|
+
|
12
|
+
def selection_required?
|
13
|
+
Library.selection_info(@element).selection_required?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Uia
|
2
|
+
module Patterns
|
3
|
+
module SelectionItem
|
4
|
+
def select
|
5
|
+
Library.select @element
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_to_selection
|
9
|
+
Library.add_to_selection @element
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove_from_selection
|
13
|
+
Library.remove_from_selection @element
|
14
|
+
end
|
15
|
+
|
16
|
+
def selected?
|
17
|
+
Library.selection_item_info(@element).selected?
|
18
|
+
end
|
19
|
+
|
20
|
+
def container
|
21
|
+
Uia::Element.new Library.selection_item_info(@element).container
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Uia
|
2
|
+
module Patterns
|
3
|
+
module Toggle
|
4
|
+
def toggle_state
|
5
|
+
Library.toggle_information(@element).state.downcase.to_sym
|
6
|
+
end
|
7
|
+
|
8
|
+
def toggle_state=(state)
|
9
|
+
toggle unless state == toggle_state
|
10
|
+
end
|
11
|
+
|
12
|
+
def toggle
|
13
|
+
Library.toggle @element
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Uia
|
2
|
+
module Patterns
|
3
|
+
module Value
|
4
|
+
def value=(value)
|
5
|
+
Library.set_value(@element, value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def value
|
9
|
+
value_information.value
|
10
|
+
end
|
11
|
+
|
12
|
+
def read_only?
|
13
|
+
value_information.read_only?
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def value_information
|
18
|
+
Library.value_info(@element)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/uia/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/uia/element_spec.rb
CHANGED
@@ -1,19 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Element do
|
4
|
-
Given(:element) { find_element(id: 'MainFormWindow') }
|
5
|
-
Given(:about_box) { find_element(id: 'AboutBox') }
|
3
|
+
describe Uia::Element do
|
4
|
+
Given(:element) { Uia.find_element(id: 'MainFormWindow') }
|
5
|
+
Given(:about_box) { Uia.find_element(id: 'AboutBox') }
|
6
6
|
|
7
7
|
context 'properties' do
|
8
|
+
let(:raw_element) { element.instance_variable_get(:@element) }
|
8
9
|
Then { element.handle != 0 }
|
9
10
|
Then { element.name == 'MainFormWindow' }
|
10
11
|
Then { element.id == 'MainFormWindow' }
|
12
|
+
Then { element.class_name =~ /Forms.*app/i }
|
13
|
+
Then { expect(element.find(id: 'textField')).to be_enabled }
|
11
14
|
|
12
15
|
context '#control_type' do
|
13
16
|
Then { element.control_type == :window }
|
14
17
|
|
15
18
|
context 'unknown' do
|
16
|
-
Given {
|
19
|
+
Given { raw_element.stub(:control_type_id).and_return(777) }
|
17
20
|
Then { element.control_type == :unknown }
|
18
21
|
end
|
19
22
|
end
|
@@ -22,10 +25,34 @@ describe Element do
|
|
22
25
|
Then { element.patterns.should =~ [:transform, :window] }
|
23
26
|
|
24
27
|
context 'unknown' do
|
25
|
-
Given {
|
26
|
-
Then { element.patterns.should == [:unknown]}
|
28
|
+
Given { raw_element.stub(:pattern_ids).and_return([7777]) }
|
29
|
+
Then { element.patterns.should == [:unknown] }
|
27
30
|
end
|
28
31
|
end
|
32
|
+
|
33
|
+
context '#refresh' do
|
34
|
+
Given!(:check_box) do
|
35
|
+
check_box = element.find(id: 'checkBox').as :toggle
|
36
|
+
check_box.toggle_state = :off
|
37
|
+
check_box
|
38
|
+
end
|
39
|
+
|
40
|
+
Given!(:label) { element.find(id: 'checkBoxLabel') }
|
41
|
+
When { check_box.toggle_state = :on; label.refresh }
|
42
|
+
Then { label.name == 'checkBox is on' }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context '#find' do
|
47
|
+
context 'id' do
|
48
|
+
Then { element.find(id: 'textField') != nil }
|
49
|
+
Then { element.find(id: 'does not exist') == nil }
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'name' do
|
53
|
+
Then { element.find(name: 'No option selected') != nil }
|
54
|
+
Then { element.find(name: 'does not exist') == nil }
|
55
|
+
end
|
29
56
|
end
|
30
57
|
|
31
58
|
context '#click' do
|
@@ -46,11 +73,11 @@ describe Element do
|
|
46
73
|
|
47
74
|
context '#children' do
|
48
75
|
Then { element.children.count == 27 }
|
49
|
-
Then { element.children.all? { |c| c.instance_of? Element } }
|
76
|
+
Then { element.children.all? { |c| c.instance_of? Uia::Element } }
|
50
77
|
end
|
51
78
|
|
52
79
|
context '#descendants' do
|
53
80
|
Then { element.descendants.count > element.children.count }
|
54
|
-
Then { element.descendants.all? { |c| c.instance_of? Element } }
|
81
|
+
Then { element.descendants.all? { |c| c.instance_of? Uia::Element } }
|
55
82
|
end
|
56
83
|
end
|