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