uia 0.1.2.3 → 0.1.3
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 +5 -0
- data/ext/UiaDll/UIA.Helper/Element.cs +5 -0
- data/ext/UiaDll/UiaDll.Test/SearchConditionTest.cpp +34 -0
- data/ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj +1 -0
- data/ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj.filters +3 -0
- data/ext/UiaDll/UiaDll/ConditionHelper.h +57 -0
- data/ext/UiaDll/UiaDll/ConditionMethods.cpp +31 -0
- data/ext/UiaDll/UiaDll/ElementMethods.cpp +19 -16
- data/ext/UiaDll/UiaDll/ElementStructures.h +61 -0
- data/ext/UiaDll/UiaDll/Stdafx.h +1 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj +2 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +6 -0
- data/lib/core_ext/symbol.rb +6 -0
- data/lib/uia/element.rb +12 -2
- data/lib/uia/finder.rb +6 -15
- data/lib/uia/library.rb +22 -2
- data/lib/uia/library/constants.rb +6 -0
- data/lib/uia/library/element_structs.rb +20 -0
- data/lib/uia/version.rb +1 -1
- data/spec/core_ext/symbol_spec.rb +9 -0
- data/spec/uia/element_spec.rb +23 -3
- metadata +9 -4
data/ChangeLog
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== Version 0.1.3 / 2014-04-29
|
2
|
+
* Enhancements
|
3
|
+
* Element#find can combine multiple locators for filtering on the .NET side
|
4
|
+
* #find by :control_type
|
5
|
+
|
1
6
|
=== Version 0.1.2.3 / 2014-04-21
|
2
7
|
* Bug Fixes
|
3
8
|
* Handles scenario when a Container is not reported from UIA for a SelectionItem element
|
@@ -142,6 +142,11 @@ namespace UIA.Helper
|
|
142
142
|
return FindFirst(scope, automationId.IdCondition());
|
143
143
|
}
|
144
144
|
|
145
|
+
public Element ChildWith(TreeScope scope, Condition condition)
|
146
|
+
{
|
147
|
+
return FindFirst(scope, condition);
|
148
|
+
}
|
149
|
+
|
145
150
|
public static Element ByName(string name)
|
146
151
|
{
|
147
152
|
return FindFirst(new PropertyCondition(AutomationElement.NameProperty, name));
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#include "stdafx.h"
|
2
|
+
#include <ElementStructures.h>
|
3
|
+
|
4
|
+
TEST(Conditions_HaveIds)
|
5
|
+
{
|
6
|
+
auto condition = SearchCondition(123, 0);
|
7
|
+
ASSERT_EQ(123, condition.propertyId);
|
8
|
+
}
|
9
|
+
|
10
|
+
TEST(Conditions_CanBeNumbers)
|
11
|
+
{
|
12
|
+
auto condition = SearchCondition(0, 456);
|
13
|
+
ASSERT_EQ(456, condition.number);
|
14
|
+
}
|
15
|
+
|
16
|
+
TEST(Conditions_CanBeStrings)
|
17
|
+
{
|
18
|
+
auto condition = SearchCondition(0, "expected value");
|
19
|
+
ASSERT_STREQ("expected value", condition.string);
|
20
|
+
ASSERT_TRUE(condition.IsString());
|
21
|
+
}
|
22
|
+
|
23
|
+
TEST(Conditions_CanHaveMultipleNumbers)
|
24
|
+
{
|
25
|
+
list<const int> numbers;
|
26
|
+
numbers.push_back(7);
|
27
|
+
numbers.push_back(6);
|
28
|
+
|
29
|
+
auto condition = SearchCondition(0, numbers);
|
30
|
+
ASSERT_EQ(2, condition.numbersCount);
|
31
|
+
ASSERT_EQ(7, condition.numbers[0]);
|
32
|
+
ASSERT_EQ(6, condition.numbers[1]);
|
33
|
+
ASSERT_TRUE(condition.HasNumbers());
|
34
|
+
}
|
@@ -106,6 +106,7 @@
|
|
106
106
|
<ClCompile Include="AssemblyInfo.cpp" />
|
107
107
|
<ClCompile Include="ElementInformationTest.cpp" />
|
108
108
|
<ClCompile Include="PatternInformationTest.cpp" />
|
109
|
+
<ClCompile Include="SearchConditionTest.cpp" />
|
109
110
|
<ClCompile Include="stdafx.cpp">
|
110
111
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
111
112
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
@@ -58,6 +58,9 @@
|
|
58
58
|
<ClCompile Include="PatternInformationTest.cpp">
|
59
59
|
<Filter>Source Files</Filter>
|
60
60
|
</ClCompile>
|
61
|
+
<ClCompile Include="SearchConditionTest.cpp">
|
62
|
+
<Filter>Source Files</Filter>
|
63
|
+
</ClCompile>
|
61
64
|
</ItemGroup>
|
62
65
|
<ItemGroup>
|
63
66
|
<Image Include="app.ico">
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#pragma once
|
2
|
+
#include "ElementStructures.h"
|
3
|
+
#include <list>
|
4
|
+
|
5
|
+
using namespace System::Collections::Generic;
|
6
|
+
using namespace std;
|
7
|
+
|
8
|
+
ref class ConditionHelper
|
9
|
+
{
|
10
|
+
public:
|
11
|
+
static Condition^ ConditionFrom(list<SearchConditionPtr>& searchConditions) {
|
12
|
+
auto conditions = gcnew List<Condition^>();
|
13
|
+
|
14
|
+
for(auto condition = searchConditions.begin(); condition != searchConditions.end(); ++condition) {
|
15
|
+
conditions->Add(ConditionFrom(*condition));
|
16
|
+
}
|
17
|
+
|
18
|
+
if(conditions->Count == 1) {
|
19
|
+
conditions->Add(Condition::TrueCondition);
|
20
|
+
}
|
21
|
+
|
22
|
+
return gcnew AndCondition(conditions->ToArray());
|
23
|
+
}
|
24
|
+
|
25
|
+
static Condition^ ConditionFrom(SearchConditionPtr searchCondition) {
|
26
|
+
auto automationProperty = AutomationProperty::LookupById(searchCondition->propertyId);
|
27
|
+
Object^ value = nullptr;
|
28
|
+
|
29
|
+
if(automationProperty == AutomationElement::ControlTypeProperty) {
|
30
|
+
return ControlTypeConditions(searchCondition->numbers, searchCondition->numbersCount);
|
31
|
+
} else if(searchCondition->IsString()) {
|
32
|
+
value = gcnew String(searchCondition->string);
|
33
|
+
} else {
|
34
|
+
value = searchCondition->number;
|
35
|
+
}
|
36
|
+
|
37
|
+
return gcnew PropertyCondition(automationProperty, value);
|
38
|
+
}
|
39
|
+
|
40
|
+
private:
|
41
|
+
static Condition^ ControlTypeConditions(const int* controlTypeIds, const int controlTypes) {
|
42
|
+
if(controlTypes == 1) {
|
43
|
+
return ControlType(controlTypeIds[0]);
|
44
|
+
}
|
45
|
+
|
46
|
+
auto conditions = gcnew List<Condition^>();
|
47
|
+
for(auto index = 0; index < controlTypes; ++index) {
|
48
|
+
conditions->Add(ControlType(controlTypeIds[index]));
|
49
|
+
}
|
50
|
+
|
51
|
+
return gcnew OrCondition(conditions->ToArray());
|
52
|
+
}
|
53
|
+
|
54
|
+
static Condition^ ControlType(const int id) {
|
55
|
+
return gcnew PropertyCondition(AutomationElement::ControlTypeProperty, ControlType::LookupById(id));
|
56
|
+
}
|
57
|
+
};
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#include "Stdafx.h"
|
2
|
+
|
3
|
+
using namespace std;
|
4
|
+
|
5
|
+
extern "C" {
|
6
|
+
__declspec(dllexport) void Condition_Release(SearchConditionPtr searchCondition) {
|
7
|
+
delete searchCondition;
|
8
|
+
}
|
9
|
+
|
10
|
+
_declspec(dllexport) SearchConditionPtr Condition_Id(const char* id) {
|
11
|
+
return new SearchCondition(AutomationElement::AutomationIdProperty->Id, id);
|
12
|
+
}
|
13
|
+
|
14
|
+
_declspec(dllexport) SearchConditionPtr Condition_Name(const char* name) {
|
15
|
+
return new SearchCondition(AutomationElement::NameProperty->Id, name);
|
16
|
+
}
|
17
|
+
|
18
|
+
__declspec(dllexport) SearchConditionPtr Condition_ControlType(const int n, const int arg0, ...) {
|
19
|
+
va_list arguments;
|
20
|
+
va_start(arguments, arg0);
|
21
|
+
|
22
|
+
list<const int> controlTypes;
|
23
|
+
controlTypes.push_back(arg0);
|
24
|
+
for(auto index = 1; index < n; index++) {
|
25
|
+
auto value = va_arg(arguments, int);
|
26
|
+
controlTypes.push_back(value);
|
27
|
+
}
|
28
|
+
|
29
|
+
return SearchCondition::FromControlTypes(controlTypes);
|
30
|
+
}
|
31
|
+
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "Stdafx.h"
|
2
2
|
|
3
|
+
#include "ConditionHelper.h"
|
3
4
|
using namespace UIA::Helper;
|
4
5
|
|
5
6
|
extern "C" {
|
@@ -31,30 +32,33 @@ extern "C" {
|
|
31
32
|
}
|
32
33
|
}
|
33
34
|
|
34
|
-
|
35
|
+
ElementInformationPtr ManagedFindByConditions(ElementInformationPtr element, const char* treeScope, list<SearchConditionPtr>& conditions, char* errorInfo, const int errorInfoLength) {
|
35
36
|
try {
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
auto scope = (TreeScope) Enum::Parse(TreeScope::typeid, gcnew String(treeScope));
|
38
|
+
return ElementInformation::From(Find(element)->ChildWith(scope, ConditionHelper::ConditionFrom(conditions)));
|
39
|
+
} catch(Exception^ e) {
|
40
|
+
StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
|
39
41
|
}
|
40
42
|
|
41
43
|
return NULL;
|
42
44
|
}
|
43
45
|
|
44
|
-
__declspec(dllexport) ElementInformationPtr
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
__declspec(dllexport) ElementInformationPtr FindByConditions(ElementInformationPtr element, const char* treeScope, char* errorInfo, const int errorInfoLength, const int count, SearchConditionPtr arg0, ...) {
|
47
|
+
va_list arguments;
|
48
|
+
va_start(arguments, arg0);
|
49
|
+
|
50
|
+
list<SearchConditionPtr> conditions;
|
51
|
+
conditions.push_back(arg0);
|
52
|
+
for(auto index = 1; index < count; index++) {
|
53
|
+
conditions.push_back(va_arg(arguments, SearchConditionPtr));
|
50
54
|
}
|
51
55
|
|
52
|
-
return
|
56
|
+
return ManagedFindByConditions(element, treeScope, conditions, errorInfo, errorInfoLength);
|
53
57
|
}
|
54
58
|
|
55
|
-
__declspec(dllexport) ElementInformationPtr
|
59
|
+
__declspec(dllexport) ElementInformationPtr Element_FindById(const char* automationId, char* errorInfo, const int errorLength) {
|
56
60
|
try {
|
57
|
-
return ElementInformation::From(Element::
|
61
|
+
return ElementInformation::From(Element::ById(gcnew String(automationId)));
|
58
62
|
} catch(Exception^ error) {
|
59
63
|
StringHelper::CopyToUnmanagedString(error->Message, errorInfo, errorLength);
|
60
64
|
}
|
@@ -62,10 +66,9 @@ extern "C" {
|
|
62
66
|
return NULL;
|
63
67
|
}
|
64
68
|
|
65
|
-
__declspec(dllexport) ElementInformationPtr
|
69
|
+
__declspec(dllexport) ElementInformationPtr Element_FindByName(const char* name, char* errorInfo, const int errorLength) {
|
66
70
|
try {
|
67
|
-
|
68
|
-
return ElementInformation::From(Find(parent)->ChildByName(gcnew String(name), scope));
|
71
|
+
return ElementInformation::From(Element::ByName(gcnew String(name)));
|
69
72
|
} catch(Exception^ error) {
|
70
73
|
StringHelper::CopyToUnmanagedString(error->Message, errorInfo, errorLength);
|
71
74
|
}
|
@@ -2,6 +2,67 @@
|
|
2
2
|
#include "ArrayHelper.h"
|
3
3
|
#include "StringHelper.h"
|
4
4
|
|
5
|
+
#include <list>
|
6
|
+
using namespace std;
|
7
|
+
|
8
|
+
typedef struct _SearchCondition {
|
9
|
+
int propertyId;
|
10
|
+
|
11
|
+
int number;
|
12
|
+
char* string;
|
13
|
+
int* numbers;
|
14
|
+
int numbersCount;
|
15
|
+
|
16
|
+
_SearchCondition(const int id, const char* s) : string(NULL), numbers(NULL) {
|
17
|
+
Reset(id);
|
18
|
+
|
19
|
+
auto length = strnlen_s(s, 10000);
|
20
|
+
auto size = length + 1;
|
21
|
+
this->string = new char[size];
|
22
|
+
strcpy_s(this->string, size, s);
|
23
|
+
}
|
24
|
+
|
25
|
+
_SearchCondition(const int id, const int number) : string(NULL), numbers(NULL) {
|
26
|
+
Reset(id);
|
27
|
+
this->number = number;
|
28
|
+
}
|
29
|
+
|
30
|
+
_SearchCondition(const int id, list<const int>& numbers) : string(NULL), numbers(NULL) {
|
31
|
+
Reset(id);
|
32
|
+
numbersCount = numbers.size();
|
33
|
+
this->numbers = new int[numbersCount];
|
34
|
+
|
35
|
+
int index = 0;
|
36
|
+
for(std::list<const int>::iterator number = numbers.begin(); number != numbers.end(); ++number, ++index) {
|
37
|
+
this->numbers[index] = *number;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
bool HasNumbers() {
|
42
|
+
return NULL != numbers;
|
43
|
+
}
|
44
|
+
|
45
|
+
bool IsString() {
|
46
|
+
return NULL != string;
|
47
|
+
}
|
48
|
+
|
49
|
+
static _SearchCondition* FromControlTypes(list<const int>& controlTypes) {
|
50
|
+
return new SearchCondition(System::Windows::Automation::AutomationElement::ControlTypeProperty->Id, controlTypes);
|
51
|
+
}
|
52
|
+
|
53
|
+
void Reset(const int id) {
|
54
|
+
propertyId = id;
|
55
|
+
delete[] string; delete[] numbers;
|
56
|
+
string = NULL; numbers = NULL;
|
57
|
+
number = 0; numbersCount = 0;
|
58
|
+
}
|
59
|
+
|
60
|
+
~_SearchCondition() {
|
61
|
+
Reset(propertyId);
|
62
|
+
}
|
63
|
+
|
64
|
+
} SearchCondition, *SearchConditionPtr;
|
65
|
+
|
5
66
|
typedef struct _ElementInformation {
|
6
67
|
int nativeWindowHandle;
|
7
68
|
int* runtimeId;
|
data/ext/UiaDll/UiaDll/Stdafx.h
CHANGED
@@ -80,6 +80,7 @@
|
|
80
80
|
</ItemGroup>
|
81
81
|
<ItemGroup>
|
82
82
|
<ClInclude Include="ArrayHelper.h" />
|
83
|
+
<ClInclude Include="ConditionHelper.h" />
|
83
84
|
<ClInclude Include="DynamicAssemblyResolver.h" />
|
84
85
|
<ClInclude Include="ElementStructures.h" />
|
85
86
|
<ClInclude Include="PatternInformationStructures.h" />
|
@@ -88,6 +89,7 @@
|
|
88
89
|
</ItemGroup>
|
89
90
|
<ItemGroup>
|
90
91
|
<ClCompile Include="AssemblyInfo.cpp" />
|
92
|
+
<ClCompile Include="ConditionMethods.cpp" />
|
91
93
|
<ClCompile Include="DynamicAssemblyResolver.cpp" />
|
92
94
|
<ClCompile Include="ElementMethods.cpp" />
|
93
95
|
<ClCompile Include="ExpandCollapseMethods.cpp" />
|
@@ -36,6 +36,9 @@
|
|
36
36
|
<ClInclude Include="PatternInformationStructures.h">
|
37
37
|
<Filter>Header Files</Filter>
|
38
38
|
</ClInclude>
|
39
|
+
<ClInclude Include="ConditionHelper.h">
|
40
|
+
<Filter>Header Files</Filter>
|
41
|
+
</ClInclude>
|
39
42
|
</ItemGroup>
|
40
43
|
<ItemGroup>
|
41
44
|
<ClCompile Include="UiaDll.cpp">
|
@@ -89,5 +92,8 @@
|
|
89
92
|
<ClCompile Include="MouseMethods.cpp">
|
90
93
|
<Filter>Source Files</Filter>
|
91
94
|
</ClCompile>
|
95
|
+
<ClCompile Include="ConditionMethods.cpp">
|
96
|
+
<Filter>Source Files</Filter>
|
97
|
+
</ClCompile>
|
92
98
|
</ItemGroup>
|
93
99
|
</Project>
|
data/lib/core_ext/symbol.rb
CHANGED
@@ -9,4 +9,10 @@ class Symbol
|
|
9
9
|
m.const_get current.split('_').map(&:capitalize).join
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def to_control_type_const
|
14
|
+
control_type = Uia::Library::Constants::ControlTypes[self]
|
15
|
+
raise InvalidControlType.new(self) unless control_type
|
16
|
+
control_type
|
17
|
+
end
|
12
18
|
end
|
data/lib/uia/element.rb
CHANGED
@@ -61,9 +61,19 @@ module Uia
|
|
61
61
|
locator.all? do |locator, value|
|
62
62
|
case locator
|
63
63
|
when :pattern
|
64
|
-
|
64
|
+
case value
|
65
|
+
when Array
|
66
|
+
!(patterns & value).empty?
|
67
|
+
else
|
68
|
+
patterns.include? value
|
69
|
+
end
|
65
70
|
else
|
66
|
-
|
71
|
+
case value
|
72
|
+
when Array
|
73
|
+
value.include? send(locator)
|
74
|
+
else
|
75
|
+
send(locator) == value
|
76
|
+
end
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|
data/lib/uia/finder.rb
CHANGED
@@ -29,20 +29,19 @@ module Uia
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def find_child(parent, locator)
|
32
|
-
scope = (locator
|
32
|
+
scope = (locator.delete(:scope) || :descendants).to_s.capitalize
|
33
|
+
|
34
|
+
valid_locators = [:title, :handle, :id, :name, :value, :control_type, :scope]
|
35
|
+
raise BadChildLocator, locator unless (locator.keys - valid_locators).empty?
|
33
36
|
|
34
37
|
case
|
35
|
-
when locator[:id]
|
36
|
-
find_child_by_id parent, locator[:id], scope
|
37
|
-
when locator[:name], locator[:value]
|
38
|
-
name_or_value = locator[:name] || locator[:value]
|
39
|
-
find_child_by_name parent, name_or_value, scope
|
40
38
|
when locator[:title]
|
41
39
|
find_by_title locator[:title], parent.handle
|
42
40
|
when locator[:handle]
|
43
41
|
find_by_handle locator[:handle]
|
44
42
|
else
|
45
|
-
|
43
|
+
conditions = locator.collect {|k, v| Library.send("#{k}_condition", v) }
|
44
|
+
Library.find_by_conditions parent, scope, *conditions
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -51,18 +50,10 @@ module Uia
|
|
51
50
|
find_by_property(:id, id)
|
52
51
|
end
|
53
52
|
|
54
|
-
def find_child_by_id(parent, id, scope)
|
55
|
-
Library.find_child_by_id(parent, id, (scope || :descendants).to_s.capitalize)
|
56
|
-
end
|
57
|
-
|
58
53
|
def find_by_name(name)
|
59
54
|
find_by_property(:name, name)
|
60
55
|
end
|
61
56
|
|
62
|
-
def find_child_by_name(parent, name, scope)
|
63
|
-
Library.find_child_by_name(parent, name, (scope || :descendants).to_s.capitalize)
|
64
|
-
end
|
65
|
-
|
66
57
|
def find_by_pid(pid)
|
67
58
|
Library.find_by_pid(pid)
|
68
59
|
end
|
data/lib/uia/library.rb
CHANGED
@@ -63,11 +63,22 @@ module Uia
|
|
63
63
|
attach_throwable_function :find_by_pid, :Element_FindByProcessId, [:int], ManagedElementStruct.by_ref, &element_or_nil
|
64
64
|
attach_throwable_function :find_by_handle, :Element_FindByHandle, [:int], ManagedElementStruct.by_ref, &element_or_nil
|
65
65
|
attach_function :Element_FindByRuntimeId, [:pointer, :int, :pointer, :int], ManagedElementStruct.by_ref
|
66
|
+
attach_function :FindByConditions, [:pointer, :string, :pointer, :int, :int, :varargs], ManagedElementStruct.by_ref
|
67
|
+
|
68
|
+
## conditions
|
69
|
+
attach_function :release_condition, :Condition_Release, [:pointer], :void
|
70
|
+
attach_function :id_condition, :Condition_Id, [:string], SearchCondition.by_ref
|
71
|
+
attach_function :name_condition, :Condition_Name, [:string], SearchCondition.by_ref
|
72
|
+
self.singleton_class.send(:alias_method, :value_condition, :name_condition)
|
73
|
+
attach_function :Condition_ControlType, [:int, :varargs], SearchCondition.by_ref
|
74
|
+
|
75
|
+
def self.control_type_condition(*control_types)
|
76
|
+
args = control_types.flatten.map(&:to_control_type_const).reduce([]) { |a, n| a << :int << n }
|
77
|
+
Condition_ControlType control_types.count, *args
|
78
|
+
end
|
66
79
|
|
67
80
|
# element methods
|
68
81
|
attach_throwable_function :send_keys, :Element_SendKeys, [:pointer, :string], :void
|
69
|
-
attach_throwable_function :find_child_by_id, :Element_FindChildById, [:pointer, :string, :string], ManagedElementStruct.by_ref, &element_or_nil
|
70
|
-
attach_throwable_function :find_child_by_name, :Element_FindChildByName, [:pointer, :string, :string], ManagedElementStruct.by_ref, &element_or_nil
|
71
82
|
elements_from :children, :Element_Children, [:pointer]
|
72
83
|
elements_from :descendants, :Element_Descendants, [:pointer]
|
73
84
|
attach_throwable_function :click, :Element_ClickClickablePoint, [:pointer], :void
|
@@ -145,6 +156,15 @@ module Uia
|
|
145
156
|
result
|
146
157
|
end
|
147
158
|
|
159
|
+
def self.find_by_conditions(element, scope, *args)
|
160
|
+
string_buffer = FFI::MemoryPointer.new :char, 1024
|
161
|
+
conditions = args.reduce([]) { |a, c| a << :pointer << c }
|
162
|
+
result = FindByConditions element, scope, string_buffer, 1024, args.count, *conditions
|
163
|
+
error_info = string_buffer.read_string
|
164
|
+
raise error_info unless error_info.empty?
|
165
|
+
Uia::Element.new(result) unless result.empty?
|
166
|
+
end
|
167
|
+
|
148
168
|
rescue LoadError => e
|
149
169
|
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)'
|
150
170
|
end
|
@@ -69,5 +69,25 @@ module Uia
|
|
69
69
|
class ElementStruct < FFI::Struct
|
70
70
|
include ElementLayout
|
71
71
|
end
|
72
|
+
|
73
|
+
class SearchCondition < FFI::ManagedStruct
|
74
|
+
extend StructAttributes
|
75
|
+
|
76
|
+
layout :property_id, :int,
|
77
|
+
:int_value, :int,
|
78
|
+
:string_value, :string,
|
79
|
+
:numbers, :pointer,
|
80
|
+
:numbers_count, :int
|
81
|
+
|
82
|
+
struct_attr :property_id, :int_value, :string_value
|
83
|
+
|
84
|
+
def numbers
|
85
|
+
self[:numbers].read_array_of_int self[:numbers_count]
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.release(pointer)
|
89
|
+
Library.release_condition(pointer)
|
90
|
+
end
|
91
|
+
end
|
72
92
|
end
|
73
93
|
end
|
data/lib/uia/version.rb
CHANGED
data/spec/uia/element_spec.rb
CHANGED
@@ -33,7 +33,7 @@ describe Uia::Element do
|
|
33
33
|
Then { expect(element.find(id: 'textField')).to be_enabled }
|
34
34
|
Then do
|
35
35
|
expect(element.bounding_rectangle.count).to eq(4)
|
36
|
-
expect(element.bounding_rectangle).to be_all {|e| e.instance_of? Fixnum }
|
36
|
+
expect(element.bounding_rectangle).to be_all { |e| e.instance_of? Fixnum }
|
37
37
|
end
|
38
38
|
|
39
39
|
context 'visibility' do
|
@@ -93,7 +93,7 @@ describe Uia::Element do
|
|
93
93
|
context '#send_keys' do
|
94
94
|
Given(:text_field) { element.find(id: 'textField').as :value }
|
95
95
|
When { text_field.send_keys 'abcde', [:left] * 3, ' fgh ' }
|
96
|
-
Then { text_field.value == 'ab fgh cde'}
|
96
|
+
Then { text_field.value == 'ab fgh cde' }
|
97
97
|
end
|
98
98
|
|
99
99
|
context '#find' do
|
@@ -117,6 +117,18 @@ describe Uia::Element do
|
|
117
117
|
Then { element.find(handle: child_handle).id == 'textField' }
|
118
118
|
end
|
119
119
|
|
120
|
+
context 'control_type' do
|
121
|
+
Then { element.find(control_type: :custom).id == 'automatableMonthCalendar1' }
|
122
|
+
Then { element.find(control_type: [:custom, :semantic_zoom]).id == 'automatableMonthCalendar1' }
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'combinations' do
|
126
|
+
Then { element.find(control_type: :list, name: 'linkLabel1').id == 'FruitListBox' }
|
127
|
+
Then { element.find(control_type: :button, name: 'Forward', scope: :children) == nil }
|
128
|
+
Then { element.find(control_type: :custom, id: 'automatableMonthCalendar1').name == 'linkLabel1'}
|
129
|
+
Then { element.find(value: 'linkLabel1', id: 'automatableMonthCalendar1').control_type == :custom }
|
130
|
+
end
|
131
|
+
|
120
132
|
context 'invalid' do
|
121
133
|
When(:bad_locator) { element.find(bad_locator: 123) }
|
122
134
|
Then { bad_locator.should have_failed BadLocator, "{:bad_locator=>123} is not a valid locator" }
|
@@ -127,7 +139,7 @@ describe Uia::Element do
|
|
127
139
|
end
|
128
140
|
end
|
129
141
|
|
130
|
-
context '#
|
142
|
+
context '#filter' do
|
131
143
|
context 'control_type' do
|
132
144
|
When(:buttons) { element.filter(control_type: :radio_button) }
|
133
145
|
Then { buttons.map(&:control_type) == [:radio_button] * 3 }
|
@@ -140,6 +152,14 @@ describe Uia::Element do
|
|
140
152
|
context 'combinations' do
|
141
153
|
Then { element.filter(control_type: :button, name: 'About')[0].id == 'aboutButton' }
|
142
154
|
end
|
155
|
+
|
156
|
+
context 'multiple' do
|
157
|
+
When(:radio_or_value) { element.filter(control_type: [:radio_button, :text]) }
|
158
|
+
Then { expect(radio_or_value.count).to eq(8) }
|
159
|
+
|
160
|
+
When(:value_or_invoke) { element.filter(pattern: [:value, :text]) }
|
161
|
+
Then { expect(value_or_invoke.count).to eq(5) }
|
162
|
+
end
|
143
163
|
end
|
144
164
|
|
145
165
|
context '#click' do
|
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.1.
|
4
|
+
version: 0.1.3
|
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-04-
|
12
|
+
date: 2014-04-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -151,6 +151,7 @@ files:
|
|
151
151
|
- ext/UiaDll/UiaDll.Test/MemoryLeakDetector.h
|
152
152
|
- ext/UiaDll/UiaDll.Test/PatternInformationTest.cpp
|
153
153
|
- ext/UiaDll/UiaDll.Test/ReadMe.txt
|
154
|
+
- ext/UiaDll/UiaDll.Test/SearchConditionTest.cpp
|
154
155
|
- ext/UiaDll/UiaDll.Test/StringHelperTest.cpp
|
155
156
|
- ext/UiaDll/UiaDll.Test/UiaDll.Test.cpp
|
156
157
|
- ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj
|
@@ -163,6 +164,8 @@ files:
|
|
163
164
|
- ext/UiaDll/UiaDll.sln
|
164
165
|
- ext/UiaDll/UiaDll/ArrayHelper.h
|
165
166
|
- ext/UiaDll/UiaDll/AssemblyInfo.cpp
|
167
|
+
- ext/UiaDll/UiaDll/ConditionHelper.h
|
168
|
+
- ext/UiaDll/UiaDll/ConditionMethods.cpp
|
166
169
|
- ext/UiaDll/UiaDll/DynamicAssemblyResolver.cpp
|
167
170
|
- ext/UiaDll/UiaDll/DynamicAssemblyResolver.h
|
168
171
|
- ext/UiaDll/UiaDll/ElementMethods.cpp
|
@@ -218,6 +221,7 @@ files:
|
|
218
221
|
- spec/app/FizzWare.NBuilder.dll
|
219
222
|
- spec/app/UIA.Extensions.dll
|
220
223
|
- spec/app/WindowsForms.exe
|
224
|
+
- spec/core_ext/symbol_spec.rb
|
221
225
|
- spec/spec_helper.rb
|
222
226
|
- spec/uia/element_spec.rb
|
223
227
|
- spec/uia/keys_spec.rb
|
@@ -251,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
251
255
|
version: '0'
|
252
256
|
segments:
|
253
257
|
- 0
|
254
|
-
hash: -
|
258
|
+
hash: -604577939
|
255
259
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
256
260
|
none: false
|
257
261
|
requirements:
|
@@ -260,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
264
|
version: '0'
|
261
265
|
segments:
|
262
266
|
- 0
|
263
|
-
hash: -
|
267
|
+
hash: -604577939
|
264
268
|
requirements: []
|
265
269
|
rubyforge_project:
|
266
270
|
rubygems_version: 1.8.28
|
@@ -271,6 +275,7 @@ test_files:
|
|
271
275
|
- spec/app/FizzWare.NBuilder.dll
|
272
276
|
- spec/app/UIA.Extensions.dll
|
273
277
|
- spec/app/WindowsForms.exe
|
278
|
+
- spec/core_ext/symbol_spec.rb
|
274
279
|
- spec/spec_helper.rb
|
275
280
|
- spec/uia/element_spec.rb
|
276
281
|
- spec/uia/keys_spec.rb
|