rautomation 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d60457345affb72ade2ec56f93991a918cb39cd8
4
- data.tar.gz: d136c890f577984d093d2831aa6f19559a54a271
3
+ metadata.gz: 748478d3036c775c96382a911bccd9e8253ef1ac
4
+ data.tar.gz: e7bf598b813dd955fcbea0c2d50f143159a06380
5
5
  SHA512:
6
- metadata.gz: 562a850a9175f49764a49927a6dd86666afc248065a1c9cee6e4ba739702f613777f71fbb354074b071af979b60399d4d59abe61ed3ce283bc4e188f43b3d7ca
7
- data.tar.gz: a26f7646d7b025c58584906fc9808bd0eeca4321f3b3caf53f2a8fd4ab8e02b2fc50cb8b69976e6dbfb6e0438226aeaac30ba61ef584a7bfc9fa699b79490484
6
+ metadata.gz: b391f11900769761f78426e9ba26029b08cad3e2c68723ab32cf64026611697db96e6dfdefb93e875ecc21045ba24005b56ddfc53b56e4e7215ea389b1e8d256
7
+ data.tar.gz: 623f4f71ac5c00c18524a1bb151a5b80e2a86a3745253f6887ba85ff929acb70f1eec5662acc86b469895ffde75b64811cdfd973528ec64a900fd5ef7bd7a2c0
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rautomation (0.9.1)
4
+ rautomation (0.9.2)
5
5
  ffi
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  diff-lcs (1.1.3)
11
- ffi (1.7.0-x86-mingw32)
11
+ ffi (1.8.1-x86-mingw32)
12
12
  rake (0.9.2.2)
13
13
  rspec (2.8.0)
14
14
  rspec-core (~> 2.8.0)
@@ -18,7 +18,7 @@ GEM
18
18
  rspec-expectations (2.8.0)
19
19
  diff-lcs (~> 1.1.2)
20
20
  rspec-mocks (2.8.0)
21
- yard (0.8.3)
21
+ yard (0.8.6.1)
22
22
 
23
23
  PLATFORMS
24
24
  x86-mingw32
data/History.rdoc CHANGED
@@ -1,6 +1,23 @@
1
- == 0.9.1
1
+ == 0.9.2 / 2013-05-19
2
+
3
+ === Win32 adapter
4
+
5
+ * Window#send_keys supports now :dash, :slash and :backslash. Closes #64.
2
6
 
3
7
  === MsUia adapter
8
+
9
+ * Ability to get and set the text of a multi-line text control that only supports the TextPattern.
10
+ * Add some caching to speed up locating controls.
11
+ * Fix issue #67 that happens when clicking on controls.
12
+
13
+ === AutoIt adapter
14
+
15
+ * Add deprecation warning.
16
+
17
+ == 0.9.1 / 2013-04-26
18
+
19
+ === MsUia adapter
20
+
4
21
  * Ability to interact with controls that do not have native window handles (for example WPF applications).
5
22
 
6
23
  == 0.9.0 / 2013-04-22
data/Rakefile CHANGED
@@ -37,7 +37,7 @@ end
37
37
  task :build => "build:all"
38
38
 
39
39
  namespace :spec do
40
- adapters = %w[win_32 autoit ms_uia]
40
+ adapters = %w[win_32 ms_uia]
41
41
 
42
42
  adapters.each do |adapter|
43
43
  desc "Run RSpec code examples against #{adapter} adapter"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.1
1
+ 0.9.2
Binary file
@@ -0,0 +1,22 @@
1
+ #include "StdAfx.h"
2
+ #include "AutomatedText.h"
3
+
4
+ String^ AutomatedText::Text::get() {
5
+ if( IsValuePattern ) {
6
+ return Value;
7
+ } else {
8
+ return AsTextPattern->DocumentRange->GetText(-1);
9
+ }
10
+ }
11
+
12
+ void AutomatedText::Text::set(String^ value) {
13
+ if( IsValuePattern ) {
14
+ Value = value;
15
+ } else {
16
+ _control->SetFocus();
17
+ SendKeys::SendWait("^{HOME}"); // Move to start of control
18
+ SendKeys::SendWait("^+{END}"); // Select everything
19
+ SendKeys::SendWait("{DEL}"); // Delete selection
20
+ SendKeys::SendWait(value);
21
+ }
22
+ }
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "automationcontrol.h"
4
+
5
+ using namespace System::Windows::Automation;
6
+ using namespace System::Windows::Forms;
7
+
8
+ ref class AutomatedText : public AutomationControl
9
+ {
10
+ public:
11
+ AutomatedText(const HWND windowHandle) : AutomationControl(windowHandle) {}
12
+ AutomatedText(const FindInformation& finderInformation) : AutomationControl(finderInformation) {}
13
+
14
+ property String^ Text {
15
+ String^ get();
16
+ void set(String^ value);
17
+ }
18
+
19
+ private:
20
+ property TextPattern^ AsTextPattern {
21
+ TextPattern^ get() {
22
+ return dynamic_cast<TextPattern^>(_control->GetCurrentPattern(TextPattern::Pattern));
23
+ }
24
+ }
25
+ };
26
+
@@ -1,14 +1,21 @@
1
1
  #include "StdAfx.h"
2
2
  #include "AutomationClicker.h"
3
3
 
4
- void AutomationClicker::Click() {
5
- if( CanInvoke() ) {
6
- return Invoke();
7
- } else if( CanToggle() ) {
8
- return Toggle();
9
- } else if( CanSelect() ) {
10
- return Select();
11
- }
4
+ bool AutomationClicker::Click() {
5
+ try {
6
+ if( CanInvoke() ) {
7
+ Invoke();
8
+ } else if( CanToggle() ) {
9
+ Toggle();
10
+ } else if( CanSelect() ) {
11
+ Select();
12
+ }
13
+
14
+ return true;
15
+ } catch(Exception^ e) {
16
+ Console::WriteLine("AutomationClicker::Click - {0}", e->Message);
17
+ return false;
18
+ }
12
19
 
13
20
  throw gcnew Exception(gcnew String("AutomationElement did not support the InvokePattern, TogglePattern or the SelectionItemPattern"));
14
21
  }
@@ -10,7 +10,7 @@ ref class AutomationClicker : AutomationControl
10
10
  public:
11
11
  AutomationClicker(const HWND windowHandle) : AutomationControl(windowHandle) {}
12
12
  AutomationClicker(const FindInformation& findInformation) : AutomationControl(findInformation) {}
13
- void Click();
13
+ bool Click();
14
14
  void MouseClick();
15
15
 
16
16
  private:
@@ -25,4 +25,12 @@ void AutomationControl::Value::set(String^ value) {
25
25
 
26
26
  String^ AutomationControl::Value::get() {
27
27
  return AsValuePattern->Current.Value;
28
+ }
29
+
30
+ bool AutomationControl::IsValuePattern::get() {
31
+ try {
32
+ return nullptr != AsValuePattern;
33
+ } catch(Exception^ e) {
34
+ return false;
35
+ }
28
36
  }
@@ -51,6 +51,10 @@ public:
51
51
  bool get() { return nullptr != _control; }
52
52
  }
53
53
 
54
+ property bool IsValuePattern {
55
+ bool get();
56
+ }
57
+
54
58
  protected:
55
59
  AutomationElement^ _control;
56
60
 
@@ -0,0 +1,23 @@
1
+ #include "stdafx.h"
2
+ #include "AutomatedText.h"
3
+ #include "StringHelper.h"
4
+
5
+ extern "C" {
6
+ __declspec ( dllexport ) void Text_GetValue(const FindInformation& findInformation, char* theValue, const int maximumLength) {
7
+ try {
8
+ auto control = gcnew AutomatedText(findInformation);
9
+ StringHelper::CopyToUnmanagedString(control->Text, theValue, maximumLength);
10
+ } catch(Exception^ e) {
11
+ Console::WriteLine("Text_GetValue: {0}", e->Message);
12
+ }
13
+ }
14
+
15
+ __declspec ( dllexport ) void Text_SetValue(const FindInformation& findInformation, const char* theValue) {
16
+ try {
17
+ auto control = gcnew AutomatedText(findInformation);
18
+ control->Text = gcnew String(theValue);
19
+ } catch(Exception^ e) {
20
+ Console::WriteLine("Text_SetValue: {0}", e->Message);
21
+ }
22
+ }
23
+ }
@@ -19,6 +19,11 @@ extern "C" {
19
19
  return automationElement->Exists;
20
20
  }
21
21
 
22
+ __declspec ( dllexport ) int NativeWindowHandle(const FindInformation& findInformation) {
23
+ auto automationElement = gcnew AutomationControl(findInformation);
24
+ return automationElement->Exists ? automationElement->Element->Current.NativeWindowHandle : 0;
25
+ }
26
+
22
27
  __declspec ( dllexport ) int BoundingRectangle(const FindInformation& findInformation, long *rectangle) {
23
28
  try {
24
29
  auto automationElement = gcnew AutomationControl(findInformation);
@@ -312,13 +317,14 @@ extern "C" {
312
317
  return 1;
313
318
  }
314
319
 
315
- __declspec ( dllexport ) void RA_Click(const FindInformation& findInformation, char* errorInfo, const int errorInfoSize) {
320
+ __declspec ( dllexport ) bool RA_Click(const FindInformation& findInformation, char* errorInfo, const int errorInfoSize) {
316
321
  try {
317
322
  auto automationClicker = gcnew AutomationClicker(findInformation);
318
- automationClicker->Click();
323
+ return automationClicker->Click();
319
324
  } catch(Exception^ e) {
320
325
  if( errorInfo ) {
321
326
  StringHelper::CopyToUnmanagedString(e->ToString(), errorInfo, errorInfoSize);
327
+ return false;
322
328
  }
323
329
  }
324
330
  }
@@ -92,6 +92,7 @@
92
92
  <ClInclude Include="Stdafx.h" />
93
93
  <ClInclude Include="StringHelper.h" />
94
94
  <ClInclude Include="targetver.h" />
95
+ <ClInclude Include="AutomatedText.h" />
95
96
  <ClInclude Include="Toggle.h" />
96
97
  <ClInclude Include="UiaDll.h" />
97
98
  </ItemGroup>
@@ -116,6 +117,8 @@
116
117
  <ClCompile Include="StringHelper.cpp" />
117
118
  <ClCompile Include="StringMethods.cpp" />
118
119
  <ClCompile Include="TableMethods.cpp" />
120
+ <ClCompile Include="AutomatedText.cpp" />
121
+ <ClCompile Include="TextMethods.cpp" />
119
122
  <ClCompile Include="Toggle.cpp" />
120
123
  <ClCompile Include="UiaDll.cpp" />
121
124
  </ItemGroup>
@@ -49,6 +49,12 @@
49
49
  <Filter Include="Header Files\Control">
50
50
  <UniqueIdentifier>{90616ecb-ce19-48d6-88ac-a38a46e42687}</UniqueIdentifier>
51
51
  </Filter>
52
+ <Filter Include="Source Files\Text">
53
+ <UniqueIdentifier>{15a04b2b-04c7-44f4-8fdb-d83019eb3917}</UniqueIdentifier>
54
+ </Filter>
55
+ <Filter Include="Header Files\Text">
56
+ <UniqueIdentifier>{3b3c2b83-e423-4619-991a-ffd7f324ae62}</UniqueIdentifier>
57
+ </Filter>
52
58
  </ItemGroup>
53
59
  <ItemGroup>
54
60
  <ClInclude Include="UiaDll.h">
@@ -96,6 +102,9 @@
96
102
  <ClInclude Include="SelectionItem.h">
97
103
  <Filter>Header Files</Filter>
98
104
  </ClInclude>
105
+ <ClInclude Include="AutomatedText.h">
106
+ <Filter>Header Files\Text</Filter>
107
+ </ClInclude>
99
108
  </ItemGroup>
100
109
  <ItemGroup>
101
110
  <ClCompile Include="UiaDll.cpp">
@@ -155,6 +164,12 @@
155
164
  <ClCompile Include="SelectionItem.cpp">
156
165
  <Filter>Source Files</Filter>
157
166
  </ClCompile>
167
+ <ClCompile Include="TextMethods.cpp">
168
+ <Filter>Source Files\Text</Filter>
169
+ </ClCompile>
170
+ <ClCompile Include="AutomatedText.cpp">
171
+ <Filter>Source Files\Text</Filter>
172
+ </ClCompile>
158
173
  </ItemGroup>
159
174
  <ItemGroup>
160
175
  <None Include="ReadMe.txt" />
@@ -1,3 +1,5 @@
1
+ Kernel.warn "[WARN] RAutomation AutoIt adapter is DEPRECATED and will be removed in the future!"
2
+
1
3
  require "win32ole"
2
4
  require File.dirname(__FILE__) + "/autoit/locators"
3
5
  require File.dirname(__FILE__) + "/autoit/button"
@@ -19,6 +19,11 @@ module RAutomation
19
19
  extract(locators)
20
20
  end
21
21
 
22
+ def cached_hwnd
23
+ @cached_hwnd ||= UiaDll::cached_hwnd(UiaDll::SearchCriteria.from_locator(@window.hwnd, @locators))
24
+ @cached_hwnd == 0 ? nil : @cached_hwnd
25
+ end
26
+
22
27
  #todo - replace with UIA version
23
28
  def hwnd
24
29
  Functions.control_hwnd(@window.hwnd, @locators)
@@ -26,10 +31,11 @@ module RAutomation
26
31
 
27
32
  def search_information
28
33
  info = UiaDll::SearchCriteria.from_locator(@window.hwnd, @locators)
29
- if info.how == 0
34
+ if info.how == 0 || cached_hwnd
30
35
  info.how = :hwnd
31
- info.data = hwnd
36
+ info.data = cached_hwnd || hwnd
32
37
  end
38
+
33
39
  info
34
40
  end
35
41
 
@@ -12,7 +12,7 @@ module RAutomation
12
12
  # @see RAutomation::TextField#set
13
13
  def set(text)
14
14
  raise "Cannot set value on a disabled text field" if disabled?
15
- UiaDll::set_control_value(search_information, text)
15
+ UiaDll::set_text(search_information, text)
16
16
  end
17
17
 
18
18
  # @see RAutomation::TextField#clear
@@ -24,7 +24,7 @@ module RAutomation
24
24
  #todo - replace with UIA version
25
25
  # @see RAutomation::TextField#value
26
26
  def value
27
- UiaDll::get_control_value(search_information)
27
+ UiaDll::get_text(search_information)
28
28
  end
29
29
 
30
30
  def exist?
@@ -102,10 +102,13 @@ module RAutomation
102
102
  ffi_convention :stdcall
103
103
 
104
104
  # Generic Control methods
105
+ attach_function :cached_hwnd, :NativeWindowHandle, [SearchCriteria.by_ref], :long
105
106
  attach_function :ElementExists, [SearchCriteria.by_ref], :bool
106
107
  attach_function :process_id, :ProcessId, [SearchCriteria.by_ref], :int
107
108
  attach_function :Control_GetValue, [SearchCriteria.by_ref, :pointer, :int], :void
108
109
  attach_function :set_control_value, :Control_SetValue, [SearchCriteria.by_ref, :string], :void
110
+ attach_function :Text_GetValue, [SearchCriteria.by_ref, :pointer, :int], :void
111
+ attach_function :set_text, :Text_SetValue, [SearchCriteria.by_ref, :string], :void
109
112
  attach_function :BoundingRectangle, [SearchCriteria.by_ref, :pointer], :int
110
113
  attach_function :current_control_type, :ControlType, [SearchCriteria.by_ref], :int
111
114
  attach_function :Name, [SearchCriteria.by_ref, :pointer, :int], :void
@@ -130,6 +133,10 @@ module RAutomation
130
133
  string_from(:Control_GetValue, search_information)
131
134
  end
132
135
 
136
+ def self.get_text(search_information)
137
+ string_from(:Text_GetValue, search_information)
138
+ end
139
+
133
140
  def self.name(search_information)
134
141
  string_from(:Name, search_information)
135
142
  end
@@ -260,7 +267,7 @@ module RAutomation
260
267
  attach_function :collapse_by_index, :RA_CollapseItemByIndex,
261
268
  [SearchCriteria.by_ref, :int], :void
262
269
  attach_function :RA_Click,
263
- [SearchCriteria.by_ref, :pointer, :int], :void
270
+ [SearchCriteria.by_ref, :pointer, :int], :bool
264
271
  attach_function :control_mouse_click, :RA_PointAndClick,
265
272
  [:long, :pointer, :int], :void
266
273
 
@@ -286,10 +293,10 @@ module RAutomation
286
293
 
287
294
  def self.can_throw(method, *args)
288
295
  string_buffer = FFI::MemoryPointer.new :char, 1024
289
- send method, *(args << string_buffer << 1024)
296
+ result = send method, *(args << string_buffer << 1024)
290
297
  error_info = string_buffer.read_string
291
298
  raise error_info unless error_info.empty?
292
- true
299
+ result
293
300
  end
294
301
  end
295
302
  end
@@ -68,6 +68,9 @@ module RAutomation
68
68
  :f10 => 0x79,
69
69
  :f11 => 0x7A,
70
70
  :f12 => 0x7B,
71
+ :dash => 0xBD,
72
+ :slash => 0x6F,
73
+ :backslash => 0xDC
71
74
  }
72
75
 
73
76
  SPECIAL_KEYS = {
@@ -1,6 +1,5 @@
1
1
  require "spec_helper"
2
2
 
3
-
4
3
  describe "MsUia::Control", :if => SpecHelper.adapter == :ms_uia do
5
4
 
6
5
  it "control coordinates", :special => false do
@@ -25,4 +24,45 @@ describe "MsUia::Control", :if => SpecHelper.adapter == :ms_uia do
25
24
  control.control_class.should =~ /WindowsForms10.BUTTON.app.0.2bf8098_r1[0-9]_ad1/
26
25
  end
27
26
 
27
+ context RAutomation::Adapter::MsUia::UiaDll::SearchCriteria, :pure_unit => true do
28
+ let(:window) { double('RAutomation Window').as_null_object }
29
+ let(:locator) { {:id => 'someId'} }
30
+ let(:control) { RAutomation::Adapter::MsUia::Control.new(window, locator) }
31
+ let(:old_style_control) { RAutomation::Adapter::MsUia::Control.new(window, :class => 'someClass') }
32
+ let(:expect_a_handle) { RAutomation::Adapter::MsUia::UiaDll.should_receive(:cached_hwnd).once.and_return(456) }
33
+ let(:expect_no_handle) { RAutomation::Adapter::MsUia::UiaDll.should_receive(:cached_hwnd).once.and_return(0) }
34
+ subject { control.search_information }
35
+
36
+ before(:each) do
37
+ window.should_receive(:hwnd).at_least(:once).and_return(123)
38
+ RAutomation::Adapter::MsUia::Functions.stub(:control_hwnd)
39
+ end
40
+
41
+ it "uses the cached window handle if it has one" do
42
+ expect_a_handle
43
+ subject.how.should eq(:hwnd)
44
+ subject.data.should eq(456)
45
+ end
46
+
47
+ it "only asks for the window handle once" do
48
+ expect_a_handle
49
+ 2.times { control.search_information }
50
+ end
51
+
52
+ it "uses the locator specified when no window handle is present" do
53
+ expect_no_handle
54
+ subject.how.should eq(:id)
55
+ subject.data.should eq('someId')
56
+ end
57
+
58
+ it "tries the old way of locating the window handle if no UIA locator is provided" do
59
+ expect_no_handle
60
+ RAutomation::Adapter::MsUia::Functions.should_receive(:control_hwnd).with(window.hwnd, :index => 0, :class => 'someClass').and_return(789)
61
+ old_info = old_style_control.search_information
62
+ old_info.how.should eq(:hwnd)
63
+ old_info.data.should eq(789)
64
+ end
65
+
66
+ end
67
+
28
68
  end
@@ -28,4 +28,16 @@ describe "MsUia::TextField", :if => SpecHelper.adapter == :ms_uia do
28
28
  main_form.text_field(:id => "multiLineTextField").should exist
29
29
  end
30
30
 
31
+ it "can set the value of a multi line text field" do
32
+ text_field = main_form.text_field(:id => "multiLineTextField")
33
+
34
+ # initial
35
+ text_field.set "some dater'"
36
+ text_field.value.should eq("some dater'")
37
+
38
+ # overwrite
39
+ text_field.set "overwrite with this dater'"
40
+ text_field.value.should eq("overwrite with this dater'")
41
+ end
42
+
31
43
  end
data/spec/spec_helper.rb CHANGED
@@ -109,8 +109,10 @@ RSpec.configure do |config|
109
109
  config.before(:each) do
110
110
  RAutomation::Window.wait_timeout = 15
111
111
 
112
- @pid1 = IO.popen(SpecHelper::DATA[:window1]).pid
113
- RAutomation::WaitHelper.wait_until {RAutomation::Window.new(:pid => @pid1).present?}
112
+ unless example.metadata[:pure_unit]
113
+ @pid1 = IO.popen(SpecHelper::DATA[:window1]).pid
114
+ RAutomation::WaitHelper.wait_until { RAutomation::Window.new(:pid => @pid1).present? }
115
+ end
114
116
  end
115
117
 
116
118
  config.after(:each) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rautomation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jarmo Pertman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-26 00:00:00.000000000 Z
11
+ date: 2013-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -111,6 +111,8 @@ files:
111
111
  - ext/UiaDll/UiaDll/AutomatedSelectList.h
112
112
  - ext/UiaDll/UiaDll/AutomatedTable.cpp
113
113
  - ext/UiaDll/UiaDll/AutomatedTable.h
114
+ - ext/UiaDll/UiaDll/AutomatedText.cpp
115
+ - ext/UiaDll/UiaDll/AutomatedText.h
114
116
  - ext/UiaDll/UiaDll/AutomationClicker.cpp
115
117
  - ext/UiaDll/UiaDll/AutomationClicker.h
116
118
  - ext/UiaDll/UiaDll/AutomationControl.cpp
@@ -131,6 +133,7 @@ files:
131
133
  - ext/UiaDll/UiaDll/StringHelper.h
132
134
  - ext/UiaDll/UiaDll/StringMethods.cpp
133
135
  - ext/UiaDll/UiaDll/TableMethods.cpp
136
+ - ext/UiaDll/UiaDll/TextMethods.cpp
134
137
  - ext/UiaDll/UiaDll/Toggle.cpp
135
138
  - ext/UiaDll/UiaDll/Toggle.h
136
139
  - ext/UiaDll/UiaDll/ToggleStateHelper.h