rautomation 0.13.0 → 0.14.0

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: 5e50cb69e80b4659265b0edfc11904e064efee3b
4
- data.tar.gz: 6ea9b5a0d4cfc8c2c43ddd995c7a0c8b07ccff7e
3
+ metadata.gz: 9f790814402e5dff056890bfd0bc89e90025b5ab
4
+ data.tar.gz: f0a96181d6654fd874cfa2e7c05da15f139bdf56
5
5
  SHA512:
6
- metadata.gz: 6bbe2f8ed80c1dff85044ce04fba2e62fac3489045d4cadaf792322f70eac4a9f06e08a4d86e6ec0e3afabc9ac6559e166f75397976b1af1f3ed76874976e88f
7
- data.tar.gz: 2400713a652d47652e93249c2a38dcd8e809f46a619ea986762bada8d561f13e2eed3dff293eb2fc84020654efdf728599492a431026a6729b97543bd545578f
6
+ metadata.gz: c258b23e4d6b47cc5708590cbdf36a991ce51c30924e2d547f88066a097a2585447359daef244e34153c350bb8577e0287d8e9fc15acbc82575edde0e36931d8
7
+ data.tar.gz: b74d867f6e09501da80d26cc1852145b8206fc1b21d46165cd92cd9c7c96589cdb887f4298629e6779c0ad16ab2c616cc7e92263e72d9ca2eb94f77de89d4deb
data/.gitignore CHANGED
@@ -33,3 +33,4 @@ ipch
33
33
  *.user
34
34
  *.opensdf
35
35
  _ReSharper*/
36
+ packages/
@@ -1,23 +1,23 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rautomation (0.13.0)
4
+ rautomation (0.14.0)
5
5
  ffi
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- diff-lcs (1.1.3)
10
+ diff-lcs (1.2.4)
11
11
  ffi (1.9.0-x86-mingw32)
12
12
  rake (0.9.2.2)
13
- rspec (2.8.0)
14
- rspec-core (~> 2.8.0)
15
- rspec-expectations (~> 2.8.0)
16
- rspec-mocks (~> 2.8.0)
17
- rspec-core (2.8.0)
18
- rspec-expectations (2.8.0)
19
- diff-lcs (~> 1.1.2)
20
- rspec-mocks (2.8.0)
13
+ rspec (2.14.1)
14
+ rspec-core (~> 2.14.0)
15
+ rspec-expectations (~> 2.14.0)
16
+ rspec-mocks (~> 2.14.0)
17
+ rspec-core (2.14.6)
18
+ rspec-expectations (2.14.3)
19
+ diff-lcs (>= 1.1.3, < 2.0)
20
+ rspec-mocks (2.14.4)
21
21
  yard (0.8.6.1)
22
22
 
23
23
  PLATFORMS
@@ -26,5 +26,5 @@ PLATFORMS
26
26
  DEPENDENCIES
27
27
  rake
28
28
  rautomation!
29
- rspec (~> 2.3)
29
+ rspec (~> 2.14)
30
30
  yard
@@ -1,3 +1,14 @@
1
+ == 0.14.0
2
+
3
+ === MsUia adapter
4
+
5
+ * Add SelectList#select and SelectList#clear.
6
+ * Add Table#select and Table#clear.
7
+ * Add Table#selected_rows.
8
+ * Improve performance of table Row lookups.
9
+ * SelectList#options accepts :index and :text (Regexp or String).
10
+ * Window#child in ms_uia works for popup windows as well.
11
+
1
12
  == 0.13.0
2
13
 
3
14
  === MsUia adapter
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.13.0
1
+ 0.14.0
@@ -26,6 +26,11 @@ namespace RAutomation.UIA.Controls
26
26
  set { Select(value); }
27
27
  }
28
28
 
29
+ public int[] SelectedIndexes
30
+ {
31
+ get { return DataItems.IndexesOf(x => x.AsSelectionItem().Current.IsSelected); }
32
+ }
33
+
29
34
  public bool IsRowSelected(int dataItemIndex)
30
35
  {
31
36
  return DataItems.ElementAt(dataItemIndex).AsSelectionItem().Current.IsSelected;
@@ -71,6 +76,11 @@ namespace RAutomation.UIA.Controls
71
76
  get { return TableOrListItems.Select(x => x.Current.Name).ToArray(); }
72
77
  }
73
78
 
79
+ public void SingleSelect(int value)
80
+ {
81
+ DataItems.ElementAt(value).AsSelectionItem().Select();
82
+ }
83
+
74
84
  private void Select(int value)
75
85
  {
76
86
  var selectionItem = DataItems.ElementAt(value).AsSelectionItem();
@@ -49,6 +49,19 @@ namespace RAutomation.UIA.Extensions
49
49
  return -1;
50
50
  }
51
51
 
52
+ public static int[] IndexesOf<T>(this IEnumerable<T> items, Func<T, bool> trueCondition)
53
+ {
54
+ var indexes = new List<int>();
55
+ var foundIndex = 0;
56
+ foreach (var item in items)
57
+ {
58
+ if (trueCondition(item)) indexes.Add(foundIndex);
59
+ ++foundIndex;
60
+ }
61
+
62
+ return indexes.ToArray();
63
+ }
64
+
52
65
  public static void ForEach<T>(this IEnumerable<T> items, Action<T> doIt)
53
66
  {
54
67
  foreach (var item in items)
@@ -0,0 +1,14 @@
1
+ #include "StdAfx.h"
2
+ #include "ArrayHelper.h"
3
+
4
+
5
+ int ArrayHelper::Copy(array<int, 1>^ source, int destination[])
6
+ {
7
+ if( NULL != destination ) {
8
+ auto index = 0;
9
+ for each(auto value in source) {
10
+ destination[index++] = value;
11
+ }
12
+ }
13
+ return source->Length;
14
+ }
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+ ref class ArrayHelper
3
+ {
4
+ public:
5
+ static int Copy(array<int>^ source, int destination[]);
6
+ };
7
+
@@ -1,58 +1,73 @@
1
1
  #include "stdafx.h"
2
2
  #include "Locator.h"
3
+ #include "ArrayHelper.h"
3
4
  #include "StringHelper.h"
4
5
 
5
6
  using namespace RAutomation::UIA::Controls;
6
7
 
7
8
  extern "C" {
8
9
 
9
- __declspec ( dllexport ) int Table_GetHeaders(const FindInformation& findInformation, const char* headers[]) {
10
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
11
- return StringHelper::Copy(tableControl->Headers, headers);
12
- }
10
+ __declspec ( dllexport ) int Table_GetHeaders(const FindInformation& findInformation, const char* headers[]) {
11
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
12
+ return StringHelper::Copy(tableControl->Headers, headers);
13
+ }
14
+
15
+ __declspec ( dllexport ) int Table_GetValues(const FindInformation& findInformation, const char* values[]) {
16
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
17
+ return StringHelper::Copy(tableControl->Values, values);
18
+ }
13
19
 
14
- __declspec ( dllexport ) int Table_GetValues(const FindInformation& findInformation, const char* values[]) {
15
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
16
- return StringHelper::Copy(tableControl->Values, values);
17
- }
20
+ __declspec ( dllexport ) int Table_GetSelectedIndexes(const FindInformation& findInformation, int selectedIndexes[]) {
21
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
22
+ return ArrayHelper::Copy(tableControl->SelectedIndexes, selectedIndexes);
23
+ }
18
24
 
19
- __declspec ( dllexport ) int Table_RowCount(const FindInformation& findInformation) {
20
- try {
21
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
22
- return tableControl->RowCount;
23
- } catch(Exception^ e) {
24
- Console::WriteLine(e->ToString());
25
+ __declspec ( dllexport ) int Table_RowCount(const FindInformation& findInformation) {
26
+ try {
27
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
28
+ return tableControl->RowCount;
29
+ } catch(Exception^ e) {
30
+ Console::WriteLine(e->ToString());
25
31
  return 0;
26
- }
27
- }
32
+ }
33
+ }
28
34
 
29
- __declspec ( dllexport ) bool Table_CoordinateIsValid(const FindInformation& findInformation, const int whichItemIndex, const int whichColumnIndex) {
30
- try {
31
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
32
- return tableControl->Exists(whichItemIndex, whichColumnIndex);
33
- } catch(Exception^ e) {
34
- Console::WriteLine(e->ToString());
35
- return false;
36
- }
37
- }
35
+ __declspec ( dllexport ) bool Table_CoordinateIsValid(const FindInformation& findInformation, const int whichItemIndex, const int whichColumnIndex) {
36
+ try {
37
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
38
+ return tableControl->Exists(whichItemIndex, whichColumnIndex);
39
+ } catch(Exception^ e) {
40
+ Console::WriteLine(e->ToString());
41
+ return false;
42
+ }
43
+ }
44
+
45
+ __declspec ( dllexport ) void Table_ValueAt(const FindInformation& findInformation, const int row, const int column, char *foundValue, const int foundValueLength) {
46
+ try {
47
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
48
+ StringHelper::CopyToUnmanagedString(tableControl->ValueAt(row, column), foundValue, foundValueLength);
49
+ } catch(Exception^ e) {
50
+ Console::WriteLine(e->ToString());
51
+ }
52
+ }
38
53
 
39
- __declspec ( dllexport ) void Table_ValueAt(const FindInformation& findInformation, const int row, const int column, char *foundValue, const int foundValueLength) {
40
- try {
41
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
42
- StringHelper::CopyToUnmanagedString(tableControl->ValueAt(row, column), foundValue, foundValueLength);
43
- } catch(Exception^ e) {
44
- Console::WriteLine(e->ToString());
45
- }
46
- }
54
+ __declspec ( dllexport ) void Table_SelectByIndex(const FindInformation& findInformation, const int dataItemIndex, char* errorInfo, const int errorInfoLength) {
55
+ try {
56
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
57
+ tableControl->SelectedIndex = dataItemIndex;
58
+ } catch(Exception^ e) {
59
+ StringHelper::Write(e, errorInfo, errorInfoLength);
60
+ }
61
+ }
47
62
 
48
- __declspec ( dllexport ) void Table_SelectByIndex(const FindInformation& findInformation, const int dataItemIndex, char* errorInfo, const int errorInfoLength) {
49
- try {
50
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
51
- tableControl->SelectedIndex = dataItemIndex;
52
- } catch(Exception^ e) {
63
+ __declspec ( dllexport ) void Table_SingleSelectByIndex(const FindInformation& findInformation, const int dataItemIndex, char* errorInfo, const int errorInfoLength) {
64
+ try {
65
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
66
+ tableControl->SingleSelect(dataItemIndex);
67
+ } catch(Exception^ e) {
53
68
  StringHelper::Write(e, errorInfo, errorInfoLength);
54
- }
55
- }
69
+ }
70
+ }
56
71
 
57
72
  __declspec ( dllexport ) void Table_RemoveRowByIndex(const FindInformation& findInformation, const int dataItemIndex, char* errorInfo, const int errorInfoLength) {
58
73
  try {
@@ -72,22 +87,22 @@ extern "C" {
72
87
  }
73
88
  }
74
89
 
75
- __declspec ( dllexport ) bool Table_IsSelectedByIndex(const FindInformation& findInformation, const int dataItemIndex) {
76
- try {
77
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
90
+ __declspec ( dllexport ) bool Table_IsSelectedByIndex(const FindInformation& findInformation, const int dataItemIndex) {
91
+ try {
92
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
78
93
  return tableControl->IsRowSelected(dataItemIndex);
79
- } catch(Exception^ e) {
80
- Console::WriteLine(e->ToString());
94
+ } catch(Exception^ e) {
95
+ Console::WriteLine(e->ToString());
81
96
  return false;
82
- }
83
- }
97
+ }
98
+ }
84
99
 
85
- __declspec ( dllexport ) void Table_SelectByValue(const FindInformation& findInformation, const char* dataItemValue, char* errorInfo, const int errorInfoLength) {
86
- try {
87
- auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
88
- tableControl->Value = gcnew String(dataItemValue);
89
- } catch(Exception^ e) {
100
+ __declspec ( dllexport ) void Table_SelectByValue(const FindInformation& findInformation, const char* dataItemValue, char* errorInfo, const int errorInfoLength) {
101
+ try {
102
+ auto tableControl = gcnew TableControl(Locator::FindFor(findInformation));
103
+ tableControl->Value = gcnew String(dataItemValue);
104
+ } catch(Exception^ e) {
90
105
  StringHelper::Write(e, errorInfo, errorInfoLength);
91
- }
92
- }
106
+ }
107
+ }
93
108
  }
@@ -80,6 +80,7 @@
80
80
  <Reference Include="WindowsBase" />
81
81
  </ItemGroup>
82
82
  <ItemGroup>
83
+ <ClInclude Include="ArrayHelper.h" />
83
84
  <ClInclude Include="Locator.h" />
84
85
  <ClInclude Include="DynamicAssemblyResolver.h" />
85
86
  <ClInclude Include="MenuItemSelector.h" />
@@ -90,6 +91,7 @@
90
91
  <ClInclude Include="UiaDll.h" />
91
92
  </ItemGroup>
92
93
  <ItemGroup>
94
+ <ClCompile Include="ArrayHelper.cpp" />
93
95
  <ClCompile Include="AssemblyInfo.cpp" />
94
96
  <ClCompile Include="Locator.cpp" />
95
97
  <ClCompile Include="ControlMethods.cpp" />
@@ -39,6 +39,9 @@
39
39
  <ClInclude Include="MenuItemSelector.h">
40
40
  <Filter>Header Files</Filter>
41
41
  </ClInclude>
42
+ <ClInclude Include="ArrayHelper.h">
43
+ <Filter>Header Files</Filter>
44
+ </ClInclude>
42
45
  </ItemGroup>
43
46
  <ItemGroup>
44
47
  <ClCompile Include="UiaDll.cpp">
@@ -89,6 +92,9 @@
89
92
  <ClCompile Include="SpinnerMethods.cpp">
90
93
  <Filter>Source Files</Filter>
91
94
  </ClCompile>
95
+ <ClCompile Include="ArrayHelper.cpp">
96
+ <Filter>Source Files</Filter>
97
+ </ClCompile>
92
98
  </ItemGroup>
93
99
  <ItemGroup>
94
100
  <None Include="ReadMe.txt" />
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <configuration>
3
+ <solution>
4
+ <add key="disableSourceControlIntegration" value="true" />
5
+ </solution>
6
+ </configuration>
@@ -0,0 +1,136 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <PropertyGroup>
4
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
5
+
6
+ <!-- Enable the restore command to run before builds -->
7
+ <RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
8
+
9
+ <!-- Property that enables building a package from a project -->
10
+ <BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
11
+
12
+ <!-- Determines if package restore consent is required to restore packages -->
13
+ <RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">false</RequireRestoreConsent>
14
+
15
+ <!-- Download NuGet.exe if it does not already exist -->
16
+ <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
17
+ </PropertyGroup>
18
+
19
+ <ItemGroup Condition=" '$(PackageSources)' == '' ">
20
+ <!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
21
+ <!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
22
+ <!--
23
+ <PackageSource Include="https://www.nuget.org/api/v2/" />
24
+ <PackageSource Include="https://my-nuget-source/nuget/" />
25
+ -->
26
+ </ItemGroup>
27
+
28
+ <PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
29
+ <!-- Windows specific commands -->
30
+ <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
31
+ <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
32
+ </PropertyGroup>
33
+
34
+ <PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
35
+ <!-- We need to launch nuget.exe with the mono command if we're not on windows -->
36
+ <NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
37
+ <PackagesConfig>packages.config</PackagesConfig>
38
+ </PropertyGroup>
39
+
40
+ <PropertyGroup>
41
+ <!-- NuGet command -->
42
+ <NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
43
+ <PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
44
+
45
+ <NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
46
+ <NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
47
+
48
+ <PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
49
+
50
+ <RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
51
+ <NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
52
+
53
+ <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
54
+ <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>
55
+
56
+ <!-- Commands -->
57
+ <RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>
58
+ <BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
59
+
60
+ <!-- We need to ensure packages are restored prior to assembly resolve -->
61
+ <BuildDependsOn Condition="$(RestorePackages) == 'true'">
62
+ RestorePackages;
63
+ $(BuildDependsOn);
64
+ </BuildDependsOn>
65
+
66
+ <!-- Make the build depend on restore packages -->
67
+ <BuildDependsOn Condition="$(BuildPackage) == 'true'">
68
+ $(BuildDependsOn);
69
+ BuildPackage;
70
+ </BuildDependsOn>
71
+ </PropertyGroup>
72
+
73
+ <Target Name="CheckPrerequisites">
74
+ <!-- Raise an error if we're unable to locate nuget.exe -->
75
+ <Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
76
+ <!--
77
+ Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
78
+ This effectively acts as a lock that makes sure that the download operation will only happen once and all
79
+ parallel builds will have to wait for it to complete.
80
+ -->
81
+ <MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
82
+ </Target>
83
+
84
+ <Target Name="_DownloadNuGet">
85
+ <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
86
+ </Target>
87
+
88
+ <Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
89
+ <Exec Command="$(RestoreCommand)"
90
+ Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
91
+
92
+ <Exec Command="$(RestoreCommand)"
93
+ LogStandardErrorAsError="true"
94
+ Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
95
+ </Target>
96
+
97
+ <Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
98
+ <Exec Command="$(BuildCommand)"
99
+ Condition=" '$(OS)' != 'Windows_NT' " />
100
+
101
+ <Exec Command="$(BuildCommand)"
102
+ LogStandardErrorAsError="true"
103
+ Condition=" '$(OS)' == 'Windows_NT' " />
104
+ </Target>
105
+
106
+ <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
107
+ <ParameterGroup>
108
+ <OutputFilename ParameterType="System.String" Required="true" />
109
+ </ParameterGroup>
110
+ <Task>
111
+ <Reference Include="System.Core" />
112
+ <Using Namespace="System" />
113
+ <Using Namespace="System.IO" />
114
+ <Using Namespace="System.Net" />
115
+ <Using Namespace="Microsoft.Build.Framework" />
116
+ <Using Namespace="Microsoft.Build.Utilities" />
117
+ <Code Type="Fragment" Language="cs">
118
+ <![CDATA[
119
+ try {
120
+ OutputFilename = Path.GetFullPath(OutputFilename);
121
+
122
+ Log.LogMessage("Downloading latest version of NuGet.exe...");
123
+ WebClient webClient = new WebClient();
124
+ webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
125
+
126
+ return true;
127
+ }
128
+ catch (Exception ex) {
129
+ Log.LogErrorFromException(ex);
130
+ return false;
131
+ }
132
+ ]]>
133
+ </Code>
134
+ </Task>
135
+ </UsingTask>
136
+ </Project>
@@ -1,8 +1,15 @@
1
1
  
2
- Microsoft Visual Studio Solution File, Format Version 11.00
3
- # Visual Studio 2010
2
+ Microsoft Visual Studio Solution File, Format Version 12.00
3
+ # Visual Studio 2012
4
4
  Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsForms", "WindowsForms\WindowsForms.csproj", "{79C33EDA-58C4-41EF-93DC-BA679895BD43}"
5
5
  EndProject
6
+ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C2B59FF1-0EE8-457F-A808-3B558459DA57}"
7
+ ProjectSection(SolutionItems) = preProject
8
+ .nuget\NuGet.Config = .nuget\NuGet.Config
9
+ .nuget\NuGet.exe = .nuget\NuGet.exe
10
+ .nuget\NuGet.targets = .nuget\NuGet.targets
11
+ EndProjectSection
12
+ EndProject
6
13
  Global
7
14
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
8
15
  Debug|Any CPU = Debug|Any CPU
@@ -1,7 +1,7 @@
1
1
  using System;
2
- using System.Linq;
3
2
  using System.Windows.Forms;
4
3
  using FizzWare.NBuilder;
4
+ using UIA.Extensions;
5
5
 
6
6
  namespace WindowsForms
7
7
  {
@@ -10,6 +10,7 @@ namespace WindowsForms
10
10
  public DataGridView()
11
11
  {
12
12
  InitializeComponent();
13
+ dataGridView1.AsTable();
13
14
  }
14
15
 
15
16
  public class Person
@@ -13,6 +13,8 @@
13
13
  <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
14
14
  <TargetFrameworkProfile>Client</TargetFrameworkProfile>
15
15
  <FileAlignment>512</FileAlignment>
16
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
17
+ <RestorePackages>true</RestorePackages>
16
18
  </PropertyGroup>
17
19
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
18
20
  <PlatformTarget>x86</PlatformTarget>
@@ -47,9 +49,8 @@
47
49
  <Reference Include="System.Drawing" />
48
50
  <Reference Include="System.Windows.Forms" />
49
51
  <Reference Include="System.Xml" />
50
- <Reference Include="UIA.Extensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
51
- <SpecificVersion>False</SpecificVersion>
52
- <HintPath>.\UIA.Extensions.dll</HintPath>
52
+ <Reference Include="UIA.Extensions">
53
+ <HintPath>..\packages\UIA.Extensions.1.0.5.0\lib\net35\UIA.Extensions.dll</HintPath>
53
54
  </Reference>
54
55
  <Reference Include="UIAutomationClient" />
55
56
  <Reference Include="UIAutomationProvider" />
@@ -123,6 +124,7 @@
123
124
  <AutoGen>True</AutoGen>
124
125
  <DependentUpon>Resources.resx</DependentUpon>
125
126
  </Compile>
127
+ <None Include="packages.config" />
126
128
  <None Include="Properties\Settings.settings">
127
129
  <Generator>SettingsSingleFileGenerator</Generator>
128
130
  <LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -135,6 +137,7 @@
135
137
  </ItemGroup>
136
138
  <ItemGroup />
137
139
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
140
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
138
141
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
139
142
  Other similar extension points exist, see Microsoft.Common.targets.
140
143
  <Target Name="BeforeBuild">
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <packages>
3
+ <package id="UIA.Extensions" version="1.0.5.0" targetFramework="net40-Client" />
4
+ </packages>
@@ -168,20 +168,13 @@ module RAutomation
168
168
  def control_hwnd(window_hwnd, locators)
169
169
  case
170
170
  when locators[:id]
171
- hwnd = UiaDll.cached_hwnd(UiaDll::SearchCriteria.from_locator(window_hwnd, locators))
172
- raise UnknownElementException, "#{locators[:id]} does not exist" if hwnd == 0
173
- hwnd
171
+ UiaDll.cached_hwnd(UiaDll::SearchCriteria.from_locator(window_hwnd, locators))
174
172
  when locators[:point]
175
- hwnd = UiaDll::handle_from_point(*locators[:point])
176
- raise UnknownElementException, "#{locators[:point]} does not exist" if hwnd == 0
177
- hwnd
173
+ UiaDll::handle_from_point(*locators[:point])
178
174
  else
179
- hwnd = find_hwnd(locators, window_hwnd) do |hwnd|
175
+ find_hwnd(locators, window_hwnd) do |hwnd|
180
176
  locators_match?(locators, control_properties(hwnd, locators))
181
177
  end
182
-
183
- raise UnknownElementException, "Element with #{locators.inspect} does not exist" if (hwnd == 0) or (hwnd == nil)
184
- hwnd
185
178
  end
186
179
  end
187
180
 
@@ -11,8 +11,8 @@ module RAutomation
11
11
 
12
12
  def initialize(select_list, text, index)
13
13
  @select_list = select_list
14
- @text = text
15
- @index = index
14
+ @text = text
15
+ @index = index
16
16
  end
17
17
 
18
18
  def selected?
@@ -28,22 +28,30 @@ module RAutomation
28
28
  UiaDll::remove_from_selection @select_list.search_information, @index
29
29
  end
30
30
 
31
+ def self.locators_match?(locators, item)
32
+ locators.all? do |locator, value|
33
+ return item.text =~ value if value.is_a? Regexp
34
+ return item.send(locator) == value
35
+ end
36
+ end
37
+
31
38
  alias_method :set, :select
32
39
  end
33
40
 
34
- def options(options = {})
35
- items = []
41
+ def option(locator)
42
+ options(locator).first
43
+ end
36
44
 
37
- select_options = UiaDll::select_options(search_information)
38
- select_options.each_with_index do |item, item_no|
39
- if options[:text]
40
- items.push(SelectListOption.new(self, item, item_no)) if options[:text] == item
41
- else
42
- items.push(SelectListOption.new(self, item, item_no))
43
- end
44
- end
45
+ def options(locator = {})
46
+ all_options.select { |item| SelectListOption.locators_match? locator, item }
47
+ end
48
+
49
+ def select(locator = {})
50
+ options(locator).each(&:select)
51
+ end
45
52
 
46
- items
53
+ def clear(locator = {})
54
+ options(locator).each(&:clear)
47
55
  end
48
56
 
49
57
  def value
@@ -54,14 +62,6 @@ module RAutomation
54
62
  UiaDll::selections(search_information)
55
63
  end
56
64
 
57
- def option(options)
58
- UiaDll::select_options(search_information).each_with_index do |item, item_no|
59
- return SelectListOption.new(self, item, item_no) if options[:text] == item
60
- end
61
-
62
- nil
63
- end
64
-
65
65
  def exist?
66
66
  super && matches_type?(Constants::UIA_COMBOBOX_CONTROL_TYPE)
67
67
  end
@@ -69,11 +69,16 @@ module RAutomation
69
69
  alias_method :exists?, :exist?
70
70
 
71
71
  private
72
-
73
72
  def item_count
74
73
  UiaDll::select_list_count(search_information)
75
74
  end
76
75
 
76
+ def all_options
77
+ UiaDll::select_options(search_information).each_with_index.map do |item, index|
78
+ SelectListOption.new(self, item, index)
79
+ end
80
+ end
81
+
77
82
  end
78
83
  end
79
84
  end
@@ -41,8 +41,9 @@ module RAutomation
41
41
  cells(locators).first
42
42
  end
43
43
 
44
- def initialize(window, locators)
45
- @search_information = window.search_information
44
+ def initialize(table, locators)
45
+ @table = table
46
+ @search_information = table.search_information
46
47
  @locators = extract(locators)
47
48
  end
48
49
 
@@ -67,7 +68,7 @@ module RAutomation
67
68
  end
68
69
 
69
70
  def exists?
70
- UiaDll::table_coordinate_valid?(search_information, @locators[:index])
71
+ @locators[:index].between? 0, @table.row_count - 1
71
72
  end
72
73
 
73
74
  def self.locators_match?(locators, item)
@@ -98,6 +99,18 @@ module RAutomation
98
99
  end
99
100
  end
100
101
 
102
+ def select(locators={})
103
+ rows(locators).each(&:select)
104
+ end
105
+
106
+ def clear(locators={})
107
+ rows(locators).each(&:clear)
108
+ end
109
+
110
+ def selected_rows
111
+ UiaDll.table_selected_indexes(search_information).map {|index| Row.new(self, index: index) }
112
+ end
113
+
101
114
  def strings
102
115
  headers = UiaDll.table_headers(search_information)
103
116
  values = UiaDll.table_values(search_information)
@@ -94,7 +94,7 @@ module RAutomation
94
94
  def data=(value)
95
95
  case how
96
96
  when :hwnd
97
- self[:data][:int_data] = value
97
+ self[:data][:int_data] = value || 0 # cannot accept nil
98
98
  when :id, :value
99
99
  self[:data][:string_data] = value
100
100
  when :point
@@ -302,6 +302,8 @@ module RAutomation
302
302
  [SearchCriteria.by_ref, :pointer], :int
303
303
  attach_function :Table_GetValues,
304
304
  [SearchCriteria.by_ref, :pointer], :int
305
+ attach_function :Table_GetSelectedIndexes,
306
+ [SearchCriteria.by_ref, :pointer], :int
305
307
  attach_function :table_row_count, :Table_RowCount,
306
308
  [SearchCriteria.by_ref], :int
307
309
  attach_function :Table_CoordinateIsValid,
@@ -310,6 +312,8 @@ module RAutomation
310
312
  [SearchCriteria.by_ref, :int, :int, :pointer, :int], :void
311
313
  attach_function :Table_SelectByIndex,
312
314
  [SearchCriteria.by_ref, :int, :pointer, :int], :void
315
+ attach_function :Table_SingleSelectByIndex,
316
+ [SearchCriteria.by_ref, :int, :pointer, :int], :void
313
317
  attach_function :Table_SelectByValue,
314
318
  [SearchCriteria.by_ref, :string, :pointer, :int], :void
315
319
  attach_function :table_row_is_selected, :Table_IsSelectedByIndex,
@@ -319,6 +323,10 @@ module RAutomation
319
323
  attach_function :Table_RemoveRowByValue,
320
324
  [SearchCriteria.by_ref, :string, :pointer, :int], :void
321
325
 
326
+ def self.table_selected_indexes(search_information)
327
+ integers_from(:Table_GetSelectedIndexes, search_information)
328
+ end
329
+
322
330
  def self.table_select(search_information, which_item)
323
331
  case which_item
324
332
  when Integer
@@ -328,6 +336,10 @@ module RAutomation
328
336
  end
329
337
  end
330
338
 
339
+ def self.table_single_select(search_information, which_item)
340
+ can_throw(:Table_SingleSelectByIndex, search_information, which_item)
341
+ end
342
+
331
343
  def self.table_value_at(search_information, row, column=0)
332
344
  string_from(:Table_ValueAt, search_information, row, column)
333
345
  end
@@ -381,6 +393,13 @@ module RAutomation
381
393
  end
382
394
 
383
395
  private
396
+ def self.integers_from(method, search_information)
397
+ item_count = send method, search_information, nil
398
+ pointer = FFI::MemoryPointer.new :pointer, item_count
399
+ send method, search_information, pointer
400
+ pointer.read_array_of_int(item_count)
401
+ end
402
+
384
403
  def self.strings_from(method, hwnd)
385
404
  string_count = send method, hwnd, nil
386
405
  pointer = FFI::MemoryPointer.new :pointer, string_count
@@ -27,7 +27,7 @@ RAutomation provides:
27
27
  s.require_paths = ["lib"]
28
28
 
29
29
  s.add_runtime_dependency("ffi")
30
- s.add_development_dependency("rspec", "~>2.3")
30
+ s.add_development_dependency("rspec", "~> 2.14")
31
31
  s.add_development_dependency("rake")
32
32
  s.add_development_dependency("yard")
33
33
  end
@@ -15,7 +15,7 @@ describe 'MsUia::SelectList', :if => SpecHelper.adapter == :ms_uia do
15
15
  about.select_list(:id => 'multiFruitListBox')
16
16
  end
17
17
 
18
- it '#fruits_combo' do
18
+ it '#select_list' do
19
19
  fruits_combo.should exist
20
20
 
21
21
  RAutomation::Window.wait_timeout = 0.1
@@ -29,37 +29,43 @@ describe 'MsUia::SelectList', :if => SpecHelper.adapter == :ms_uia do
29
29
  fruits_combo.should exist
30
30
  end
31
31
 
32
- it '#options' do
33
- fruits_combo.options.size.should == 5
32
+ context 'SelectListOption' do
33
+ it '#selected? & #select' do
34
+ fruits_combo.options(:text => 'Apple')[0].should_not be_selected
35
+ fruits_combo.options(:text => 'Apple')[0].select.should be_true
36
+ fruits_combo.options(:text => 'Apple')[0].should be_selected
37
+ end
34
38
 
35
- expected_options = ['Apple', 'Caimito', 'Coconut', 'Orange', 'Passion Fruit']
36
- fruits_combo.options.map {|option| option.text}.should == expected_options
37
- end
39
+ it '#value' do
38
40
 
39
- it '#selected? & #select' do
40
- fruits_combo.options(:text => 'Apple')[0].should_not be_selected
41
- fruits_combo.options(:text => 'Apple')[0].select.should be_true
42
- fruits_combo.options(:text => 'Apple')[0].should be_selected
43
- end
41
+ #default empty state
42
+ fruits_combo.value.should == ''
44
43
 
45
- it '#value' do
44
+ fruits_combo.options(:text => 'Apple')[0].select
45
+ fruits_combo.value.should == 'Apple'
46
46
 
47
- #default empty state
48
- fruits_combo.value.should == ''
47
+ fruits_combo.options(:text => 'Caimito')[0].select
48
+ fruits_combo.value.should == 'Caimito'
49
+ end
49
50
 
50
- fruits_combo.options(:text => 'Apple')[0].select
51
- fruits_combo.value.should == 'Apple'
51
+ it 'enabled/disabled' do
52
+ fruits_combo.should be_enabled
53
+ fruits_combo.should_not be_disabled
52
54
 
53
- fruits_combo.options(:text => 'Caimito')[0].select
54
- fruits_combo.value.should == 'Caimito'
55
+ disabled_combo.should_not be_enabled
56
+ disabled_combo.should be_disabled
57
+ end
55
58
  end
56
59
 
57
- it 'enabled/disabled' do
58
- fruits_combo.should be_enabled
59
- fruits_combo.should_not be_disabled
60
+ it '#select' do
61
+ multi_fruits.select text: /ng/
62
+ multi_fruits.values.should eq(['Orange', 'Mango'])
63
+ end
60
64
 
61
- disabled_combo.should_not be_enabled
62
- disabled_combo.should be_disabled
65
+ it '#clear' do
66
+ multi_fruits.select # select all
67
+ multi_fruits.clear text: 'Orange'
68
+ multi_fruits.values.should eq(['Apple', 'Mango'])
63
69
  end
64
70
 
65
71
  it '#values' do
@@ -73,10 +79,19 @@ describe 'MsUia::SelectList', :if => SpecHelper.adapter == :ms_uia do
73
79
 
74
80
  it '#option' do
75
81
  fruits_combo.option(:text => 'Apple').should_not be_selected
76
- fruits_combo.option(:text => 'Apple').set
82
+ fruits_combo.option(:index => 0).set
77
83
  fruits_combo.option(:text => 'Apple').should be_selected
78
84
  end
79
85
 
86
+ it '#options' do
87
+ fruits_combo.options.size.should == 5
88
+ fruits_combo.options.map(&:text).should eq(['Apple', 'Caimito', 'Coconut', 'Orange', 'Passion Fruit'])
89
+
90
+ fruits_combo.options(text: 'Apple').map(&:text).should eq ['Apple']
91
+ fruits_combo.options(text: /Ap{2}le/).map(&:text).should eq ['Apple']
92
+ fruits_combo.options(index: 0).map(&:text).should eq ['Apple']
93
+ end
94
+
80
95
  it 'cannot select anything on a disabled select list' do
81
96
  expect { disabled_combo.option(:text => 'Apple').set }.to raise_error
82
97
  end
@@ -1,12 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "MsUia::Table", :if => SpecHelper.adapter == :ms_uia do
3
+ describe 'MsUia::Table', :if => SpecHelper.adapter == :ms_uia do
4
+ let(:window) { RAutomation::Window.new(:title => "MainFormWindow") }
4
5
  let(:data_entry) { RAutomation::Window.new(:title => "DataEntryForm") }
6
+ let(:data_grid_view) { window.button(value: 'Data Grid View').click {true}; RAutomation::Window.new(title: /DataGridView/) }
7
+ let(:large_grid) { data_entry.close; data_grid_view.table(id: 'dataGridView1') }
5
8
  let(:table) { data_entry.table(:id => "personListView") }
6
9
  let(:toggle_multi_select) { data_entry.button(:value => 'Toggle Multi').click { true } }
7
10
 
8
11
  before :each do
9
- window = RAutomation::Window.new(:title => "MainFormWindow")
10
12
  window.button(:value => "Data Entry Form").click { RAutomation::Window.new(:title => "DataEntryForm").exists? }
11
13
  end
12
14
 
@@ -42,11 +44,42 @@ describe "MsUia::Table", :if => SpecHelper.adapter == :ms_uia do
42
44
  table.row_count.should eq(2)
43
45
  end
44
46
 
47
+ it '#select' do
48
+ large_grid.select value: /^FirstName[1-9]$/
49
+ first_nine = large_grid.rows.take(9)
50
+ expect(first_nine.count).to be 9
51
+ first_nine.should be_all(&:selected?)
52
+ end
53
+
54
+ it '#clear' do
55
+ first_three = large_grid.rows.take(3)
56
+ next_six = large_grid.rows.take_while { |r| r.index.between?(3, 9) }
57
+ large_grid.select value: /^FirstName[1-9]$/
58
+
59
+ large_grid.clear value: /^FirstName[1-3]$/
60
+
61
+ first_three.all?(&:selected?).should be_false
62
+ next_six.all?(&:selected?).should be_true
63
+ end
64
+
65
+ it '#selected_rows' do
66
+ large_grid.select value: /^FirstName[1-5]$/
67
+ large_grid.selected_rows.map(&:index).should eq([0, 1, 2, 3, 4])
68
+ end
69
+
45
70
  context "#rows" do
46
71
  it "has rows" do
47
72
  table.rows.size.should eq 2
48
73
  end
49
74
 
75
+ it 'are quick to find' do
76
+ large_grid.row_count.should eq(51)
77
+
78
+ start = Time.now
79
+ large_grid.row(index: 50).should exist
80
+ (Time.now - start).should be < 1.5
81
+ end
82
+
50
83
  it "have values" do
51
84
  table.rows.map(&:value).should eq ["John Doe", "Anna Doe"]
52
85
  end
@@ -3,8 +3,6 @@ require "spec_helper"
3
3
  describe "MsUia::Window", :if => SpecHelper.adapter == :ms_uia do
4
4
  let(:window) {RAutomation::Window.new(:title => /MainFormWindow/i)}
5
5
 
6
-
7
-
8
6
  it "move and click" do
9
7
  #window = RAutomation::Window.new(:title => /MainFormWindow/i)
10
8
  window.maximize
@@ -12,7 +10,6 @@ describe "MsUia::Window", :if => SpecHelper.adapter == :ms_uia do
12
10
  sleep 1
13
11
  window.click_mouse
14
12
  sleep 1
15
-
16
13
  end
17
14
 
18
15
  context "#send_keys" do
@@ -130,14 +130,20 @@ describe RAutomation::Window do
130
130
  to_not raise_exception
131
131
  end
132
132
 
133
- it "#child", :if => [:win_32, :ms_uia].include?(SpecHelper.adapter) do
134
- window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_full_title])
135
- window.should exist
136
-
137
- # buttons are windows too. so let's find the button for now
138
- child = window.child(:title => /About/i)
139
- child.should exist
140
- child.title.should == "&About"
141
- child.adapter.should == SpecHelper.adapter
133
+ context '#child', :if => [:win_32, :ms_uia].include?(SpecHelper.adapter) do
134
+ let(:window) { RAutomation::Window.new(:title => SpecHelper::DATA[:window1_full_title]) }
135
+
136
+ it 'immediate children' do
137
+ # buttons are windows too. so let's find the button for now
138
+ child = window.child(:title => '&About')
139
+ child.should exist
140
+ child.title.should == "&About"
141
+ child.adapter.should == SpecHelper.adapter
142
+ end
143
+
144
+ it 'popups' do
145
+ window.button(:title => '&About').click { true }
146
+ window.child(:title => 'About').should be_visible
147
+ end
142
148
  end
143
149
  end
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.13.0
4
+ version: 0.14.0
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-10-03 00:00:00.000000000 Z
11
+ date: 2014-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: '2.3'
33
+ version: '2.14'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: '2.3'
40
+ version: '2.14'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +119,8 @@ files:
119
119
  - ext/UiaDll/RAutomation.UIA/Properties/AutomationProperties.cs
120
120
  - ext/UiaDll/RAutomation.UIA/RAutomation.UIA.csproj
121
121
  - ext/UiaDll/UiaDll.sln
122
+ - ext/UiaDll/UiaDll/ArrayHelper.cpp
123
+ - ext/UiaDll/UiaDll/ArrayHelper.h
122
124
  - ext/UiaDll/UiaDll/AssemblyInfo.cpp
123
125
  - ext/UiaDll/UiaDll/ControlMethods.cpp
124
126
  - ext/UiaDll/UiaDll/DynamicAssemblyResolver.cpp
@@ -149,6 +151,9 @@ files:
149
151
  - ext/UiaDll/UiaDll/stdafx.cpp
150
152
  - ext/UiaDll/UiaDll/stdafx.h
151
153
  - ext/UiaDll/UiaDll/targetver.h
154
+ - ext/WindowsForms/.nuget/NuGet.Config
155
+ - ext/WindowsForms/.nuget/NuGet.exe
156
+ - ext/WindowsForms/.nuget/NuGet.targets
152
157
  - ext/WindowsForms/WindowsForms.sln
153
158
  - ext/WindowsForms/WindowsForms/AboutBox.Designer.cs
154
159
  - ext/WindowsForms/WindowsForms/AboutBox.cs
@@ -178,6 +183,7 @@ files:
178
183
  - ext/WindowsForms/WindowsForms/UIA.Extensions.dll
179
184
  - ext/WindowsForms/WindowsForms/ValueMonthCalendar.cs
180
185
  - ext/WindowsForms/WindowsForms/WindowsForms.csproj
186
+ - ext/WindowsForms/WindowsForms/packages.config
181
187
  - lib/rautomation.rb
182
188
  - lib/rautomation/adapter/autoit.rb
183
189
  - lib/rautomation/adapter/autoit/button.rb