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 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
- __declspec(dllexport) ElementInformationPtr Element_FindById(const char* automationId, char* errorInfo, const int errorLength) {
35
+ ElementInformationPtr ManagedFindByConditions(ElementInformationPtr element, const char* treeScope, list<SearchConditionPtr>& conditions, char* errorInfo, const int errorInfoLength) {
35
36
  try {
36
- return ElementInformation::From(Element::ById(gcnew String(automationId)));
37
- } catch(Exception^ error) {
38
- StringHelper::CopyToUnmanagedString(error->Message, errorInfo, errorLength);
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 Element_FindChildById(ElementInformationPtr parent, const char* automationId, const char* treeScope, char* errorInfo, const int errorLength) {
45
- try {
46
- auto scope = (TreeScope) Enum::Parse(TreeScope::typeid, gcnew String(treeScope));
47
- return ElementInformation::From(Find(parent)->ChildById(gcnew String(automationId), scope));
48
- } catch(Exception^ error) {
49
- StringHelper::CopyToUnmanagedString(error->Message, errorInfo, errorLength);
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 NULL;
56
+ return ManagedFindByConditions(element, treeScope, conditions, errorInfo, errorInfoLength);
53
57
  }
54
58
 
55
- __declspec(dllexport) ElementInformationPtr Element_FindByName(const char* name, char* errorInfo, const int errorLength) {
59
+ __declspec(dllexport) ElementInformationPtr Element_FindById(const char* automationId, char* errorInfo, const int errorLength) {
56
60
  try {
57
- return ElementInformation::From(Element::ByName(gcnew String(name)));
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 Element_FindChildByName(ElementInformationPtr parent, const char* name, const char* treeScope, char* errorInfo, const int errorLength) {
69
+ __declspec(dllexport) ElementInformationPtr Element_FindByName(const char* name, char* errorInfo, const int errorLength) {
66
70
  try {
67
- auto scope = (TreeScope) Enum::Parse(TreeScope::typeid, gcnew String(treeScope));
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;
@@ -13,5 +13,6 @@ using namespace UIA::Helper;
13
13
  #include "ArrayHelper.h"
14
14
  #include "ElementStructures.h"
15
15
  #include "PatternInformationStructures.h"
16
+ #include <list>
16
17
 
17
18
  extern "C" Element^ Find(ElementInformationPtr element);
@@ -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>
@@ -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
- patterns.include? value
64
+ case value
65
+ when Array
66
+ !(patterns & value).empty?
67
+ else
68
+ patterns.include? value
69
+ end
65
70
  else
66
- send(locator) == value
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[:scope] || :descendants).to_s.capitalize
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
- raise BadChildLocator, locator
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
@@ -1,4 +1,10 @@
1
1
  module Uia
2
+ class InvalidControlType < StandardError
3
+ def initialize(control_type)
4
+ super "#{control_type} is not valid"
5
+ end
6
+ end
7
+
2
8
  module Library
3
9
  module Constants
4
10
  Patterns = {
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Uia
2
- VERSION = '0.1.2.3'
2
+ VERSION = '0.1.3'
3
3
  end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Symbol do
4
+
5
+ context '#to_control_type_const' do
6
+ Then { expect(:list_item.to_control_type_const).to eq(50007) }
7
+ Then { expect { :not_a_control_type.to_control_type_const }.to raise_error InvalidControlType }
8
+ end
9
+ end
@@ -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 '#select' do
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.2.3
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-22 00:00:00.000000000 Z
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: -439398319
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: -439398319
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