win_gui 0.1.0
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +43 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/book_code/early_success/bundle.rb +34 -0
- data/book_code/early_success/english.txt +1 -0
- data/book_code/early_success/jruby_basics.rb +47 -0
- data/book_code/early_success/windows_basics.rb +97 -0
- data/book_code/guessing/locknote.rb +379 -0
- data/book_code/guessing/monkeyshines.rb +14 -0
- data/book_code/guessing/note.rb +120 -0
- data/book_code/guessing/note_spec.rb +175 -0
- data/book_code/guessing/replay.rb +21 -0
- data/book_code/guessing/seed.rb +9 -0
- data/book_code/guessing/spec_helper.rb +69 -0
- data/book_code/guessing/windows_gui.rb +247 -0
- data/book_code/home_stretch/junquenote.rb +151 -0
- data/book_code/home_stretch/locknote.rb +180 -0
- data/book_code/home_stretch/note.rb +144 -0
- data/book_code/home_stretch/note_spec.rb +191 -0
- data/book_code/home_stretch/spec_helper.rb +55 -0
- data/book_code/home_stretch/swing_gui.rb +50 -0
- data/book_code/home_stretch/windows_gui.rb +232 -0
- data/book_code/junquenote/exports.sh +10 -0
- data/book_code/junquenote/jruby_mac.sh +10 -0
- data/book_code/junquenote/junquenote_app.rb +262 -0
- data/book_code/novite/Rakefile +10 -0
- data/book_code/novite/app/controllers/application.rb +18 -0
- data/book_code/novite/app/controllers/guests_controller.rb +28 -0
- data/book_code/novite/app/controllers/parties_controller.rb +77 -0
- data/book_code/novite/app/helpers/application_helper.rb +11 -0
- data/book_code/novite/app/helpers/guests_helper.rb +10 -0
- data/book_code/novite/app/helpers/parties_helper.rb +10 -0
- data/book_code/novite/app/models/guest.rb +11 -0
- data/book_code/novite/app/models/party.rb +32 -0
- data/book_code/novite/app/models/party_mailer.rb +19 -0
- data/book_code/novite/app/views/layouts/application.rhtml +44 -0
- data/book_code/novite/app/views/parties/new.html.erb +42 -0
- data/book_code/novite/app/views/parties/show.html.erb +43 -0
- data/book_code/novite/app/views/party_mailer/invite.erb +17 -0
- data/book_code/novite/config/boot.rb +117 -0
- data/book_code/novite/config/database.yml +19 -0
- data/book_code/novite/config/environment.rb +67 -0
- data/book_code/novite/config/environments/development.rb +29 -0
- data/book_code/novite/config/environments/production.rb +27 -0
- data/book_code/novite/config/environments/test.rb +30 -0
- data/book_code/novite/config/initializers/inflections.rb +18 -0
- data/book_code/novite/config/initializers/mime_types.rb +13 -0
- data/book_code/novite/config/routes.rb +47 -0
- data/book_code/novite/db/migrate/001_create_parties.rb +26 -0
- data/book_code/novite/db/migrate/002_create_guests.rb +23 -0
- data/book_code/novite/db/schema.rb +41 -0
- data/book_code/novite/log/empty.txt +0 -0
- data/book_code/novite/public/.htaccess +40 -0
- data/book_code/novite/public/404.html +38 -0
- data/book_code/novite/public/422.html +38 -0
- data/book_code/novite/public/500.html +38 -0
- data/book_code/novite/public/dispatch.cgi +10 -0
- data/book_code/novite/public/dispatch.fcgi +24 -0
- data/book_code/novite/public/dispatch.rb +18 -0
- data/book_code/novite/public/favicon.ico +0 -0
- data/book_code/novite/public/images/rails.png +0 -0
- data/book_code/novite/public/index.html +285 -0
- data/book_code/novite/public/javascripts/application.js +10 -0
- data/book_code/novite/public/javascripts/controls.js +971 -0
- data/book_code/novite/public/javascripts/dragdrop.js +980 -0
- data/book_code/novite/public/javascripts/effects.js +1128 -0
- data/book_code/novite/public/javascripts/prototype.js +4233 -0
- data/book_code/novite/public/robots.txt +5 -0
- data/book_code/novite/script/about +3 -0
- data/book_code/novite/script/console +3 -0
- data/book_code/novite/script/destroy +3 -0
- data/book_code/novite/script/generate +3 -0
- data/book_code/novite/script/performance/benchmarker +3 -0
- data/book_code/novite/script/performance/profiler +3 -0
- data/book_code/novite/script/performance/request +3 -0
- data/book_code/novite/script/plugin +3 -0
- data/book_code/novite/script/process/inspector +3 -0
- data/book_code/novite/script/process/reaper +3 -0
- data/book_code/novite/script/process/spawner +3 -0
- data/book_code/novite/script/runner +3 -0
- data/book_code/novite/script/server +3 -0
- data/book_code/novite/test/test_helper.rb +46 -0
- data/book_code/one_more_thing/applescript.rb +68 -0
- data/book_code/one_more_thing/note_spec.rb +50 -0
- data/book_code/one_more_thing/spec_helper.rb +17 -0
- data/book_code/one_more_thing/textedit-pure.rb +28 -0
- data/book_code/one_more_thing/textedit.applescript +26 -0
- data/book_code/one_more_thing/textedit.rb +32 -0
- data/book_code/one_more_thing/textnote.rb +87 -0
- data/book_code/simplify/junquenote.rb +48 -0
- data/book_code/simplify/locknote.rb +46 -0
- data/book_code/simplify/note.rb +35 -0
- data/book_code/simplify/note_spec.rb +28 -0
- data/book_code/simplify/swing_gui.rb +45 -0
- data/book_code/simplify/windows_gui.rb +232 -0
- data/book_code/simplify/windows_gui_spec.rb +35 -0
- data/book_code/story/invite.story +19 -0
- data/book_code/story/journal.txt +29 -0
- data/book_code/story/novite_stories.rb +156 -0
- data/book_code/story/party.rb +149 -0
- data/book_code/story/password.rb +61 -0
- data/book_code/story/password.story +26 -0
- data/book_code/story/rsvp.story +29 -0
- data/book_code/tables/TestTime.html +93 -0
- data/book_code/tables/TestTimeSample.html +63 -0
- data/book_code/tables/calculate_time.rb +39 -0
- data/book_code/tables/calculator.rb +108 -0
- data/book_code/tables/calculator_actions.rb +27 -0
- data/book_code/tables/calculator_spec.rb +47 -0
- data/book_code/tables/fit.rb +32 -0
- data/book_code/tables/matrix.rb +109 -0
- data/book_code/tables/pseudocode.rb +17 -0
- data/book_code/tubes/book_selenium.rb +67 -0
- data/book_code/tubes/book_watir.rb +60 -0
- data/book_code/tubes/dragdrop.html +81 -0
- data/book_code/tubes/html_capture.rb +33 -0
- data/book_code/tubes/joke_list.rb +67 -0
- data/book_code/tubes/list_spec.rb +41 -0
- data/book_code/tubes/search_spec.rb +32 -0
- data/book_code/tubes/selenium_example.rb +66 -0
- data/book_code/tubes/selenium_link.rb +23 -0
- data/book_code/tubes/web_server.rb +14 -0
- data/book_code/windows/wgui.rb +29 -0
- data/book_code/windows/wobj.rb +25 -0
- data/book_code/windows/wsh.rb +25 -0
- data/book_code/with_rspec/empty_spec.rb +13 -0
- data/book_code/with_rspec/junquenote.rb +60 -0
- data/book_code/with_rspec/locknote.rb +129 -0
- data/book_code/with_rspec/note_spec.rb +32 -0
- data/book_code/with_rspec/should_examples.rb +18 -0
- data/exp/exp.rb +6 -0
- data/exp/exp_encodings.rb +40 -0
- data/exp/exp_enum_windows.rb +60 -0
- data/exp/exp_quik.rb +38 -0
- data/exp/exp_wsh.rb +115 -0
- data/exp/old/windows_basics.rb +80 -0
- data/exp/old/wnote.rb +80 -0
- data/exp/old/wnote_spec.rb +20 -0
- data/features/step_definitions/win_gui_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/features/win_gui.feature +9 -0
- data/lib/note/java/jemmy.jar +0 -0
- data/lib/note/java/jnote.rb +48 -0
- data/lib/note/java/jruby_basics.rb +37 -0
- data/lib/note/java/junquenote_app.rb +262 -0
- data/lib/note/java/note_spec.rb +20 -0
- data/lib/note/win/locknote.rb +19 -0
- data/lib/note.rb +15 -0
- data/lib/win_gui/constants.rb +66 -0
- data/lib/win_gui/string_extensions.rb +24 -0
- data/lib/win_gui/win_gui.rb +274 -0
- data/lib/win_gui/window.rb +70 -0
- data/lib/win_gui.rb +3 -0
- data/spec/note/win/locknote_spec.rb +7 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/test_apps/locknote/LockNote.exe +0 -0
- data/spec/win_gui/string_extensions_spec.rb +61 -0
- data/spec/win_gui/win_gui_spec.rb +733 -0
- data/spec/win_gui/window_spec.rb +124 -0
- metadata +251 -0
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper" )
|
|
2
|
+
|
|
3
|
+
module GuiTest
|
|
4
|
+
|
|
5
|
+
# def enum_callback
|
|
6
|
+
# @enum_callback ||= callback('LP', 'I'){|handle, message| true }
|
|
7
|
+
# end
|
|
8
|
+
|
|
9
|
+
describe WinGui, ' defines wrappers for Win32::API functions' do
|
|
10
|
+
|
|
11
|
+
context 'defining a valid API function' do
|
|
12
|
+
before(:each) { hide_method :find_window_w } # hide original method if it is defined
|
|
13
|
+
after(:each) { restore_method :find_window_w } # restore original method if it was hidden
|
|
14
|
+
|
|
15
|
+
spec{ use{ WinGui.def_api('FindWindowW', 'PP', 'L', :rename => nil, :boolean => nil, :zeronil => nil, &any_block) }}
|
|
16
|
+
|
|
17
|
+
it 'defines new instance method with appropriate name' do
|
|
18
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
|
19
|
+
respond_to?(:find_window_w).should be_true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'constructs argument prototype from uppercase string' do
|
|
23
|
+
expect { WinGui.def_api 'FindWindowW', 'PP', 'L' }.to_not raise_error
|
|
24
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
|
25
|
+
expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'constructs argument prototype from lowercase string' do
|
|
29
|
+
expect { WinGui.def_api 'FindWindowW', 'pp', 'l' }.to_not raise_error
|
|
30
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
|
31
|
+
expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'constructs argument prototype from (mixedcase) array' do
|
|
35
|
+
expect { WinGui.def_api 'FindWindowW', ['p', 'P'], 'L' }.to_not raise_error
|
|
36
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
|
37
|
+
expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it ':rename option overrides standard name for defined method' do
|
|
41
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L', :rename=> 'my_own_find'
|
|
42
|
+
expect {find_window_w(nil, nil)}.to raise_error
|
|
43
|
+
expect {my_own_find(nil, nil)}.to_not raise_error
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'defined method works properly when called with a valid args' do
|
|
47
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
|
48
|
+
expect {find_window_w(nil, nil)}.to_not raise_error
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'defined method returns expected value when called' do
|
|
52
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
|
53
|
+
test_app do |app|
|
|
54
|
+
find_window_w(nil, TEST_WIN_TITLE.to_w).should_not == 0
|
|
55
|
+
find_window_w(TEST_WIN_CLASS.to_w, nil).should_not == 0
|
|
56
|
+
end
|
|
57
|
+
find_window_w(nil, nil).should_not == 0
|
|
58
|
+
find_window_w(nil, TEST_IMPOSSIBLE).should == 0
|
|
59
|
+
find_window_w(TEST_IMPOSSIBLE, nil).should == 0
|
|
60
|
+
find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'defined method enforces the argument count when called' do
|
|
64
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
|
65
|
+
expect { find_window_w }.to raise_error 'Invalid args count'
|
|
66
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
|
67
|
+
expect { find_window_w('Str') }.to raise_error 'Invalid args count'
|
|
68
|
+
expect { find_window_w([nil, nil]) }.to raise_error 'Invalid args count'
|
|
69
|
+
expect { find_window_w('Str', 'Str', 'Str') }.to raise_error 'Invalid args count'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'defined method called with (:api) argument returns underlying Win32::API object' do
|
|
73
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
|
74
|
+
expect {@api = find_window_w(:api)}.to_not raise_error
|
|
75
|
+
@api.dll_name.should == 'user32' # The name of the DLL that exports the API function
|
|
76
|
+
@api.effective_function_name.should == 'FindWindowW' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
|
|
77
|
+
@api.function_name.should == 'FindWindowW' # The name of the function passed to the constructor
|
|
78
|
+
@api.prototype.should == ['P', 'P'] # The prototype, returned as an array of characters
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context 'auto-defining Ruby-like boolean methods if API function name starts with "Is_"' do
|
|
83
|
+
before(:each) do
|
|
84
|
+
hide_method :window?
|
|
85
|
+
WinGui.def_api 'IsWindow', 'L', 'L'
|
|
86
|
+
end
|
|
87
|
+
after(:each) { restore_method :window? }
|
|
88
|
+
|
|
89
|
+
it 'defines new instance method name dropping Is_ and adding ?' do
|
|
90
|
+
respond_to?(:window?).should be_true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'defined method returns true instead of non-zero' do
|
|
94
|
+
window?(any_handle).should == true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'defined method returns false instead of zero' do
|
|
98
|
+
window?(123).should == false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'defined method enforces the argument count' do
|
|
102
|
+
expect {window?}.to raise_error 'Invalid args count'
|
|
103
|
+
expect {window?(123, nil)}.to raise_error 'Invalid args count'
|
|
104
|
+
expect {window?(nil, nil)}.to raise_error 'Invalid args count'
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context 'defining API with :boolean option converts result to boolean' do
|
|
109
|
+
before(:each) do
|
|
110
|
+
hide_method :show_window
|
|
111
|
+
WinGui.def_api 'ShowWindow', 'LI', 'I', :boolean => true
|
|
112
|
+
end
|
|
113
|
+
after(:each) { restore_method :show_window }
|
|
114
|
+
|
|
115
|
+
it 'defines new instance method' do
|
|
116
|
+
respond_to?(:show_window).should be_true
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'defined method returns true instead of non-zero' do
|
|
120
|
+
test_app {|app| show_window(app.handle, SW_SHOWNA).should == true }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'defined method returns false instead of zero' do
|
|
124
|
+
test_app do |app|
|
|
125
|
+
show_window(app.handle, SW_HIDE)
|
|
126
|
+
show_window(app.handle, SW_HIDE).should == false
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'defined method enforces the argument count' do
|
|
131
|
+
test_app do |app|
|
|
132
|
+
expect {show_window}.to raise_error 'Invalid args count'
|
|
133
|
+
expect {show_window(app.handle, SW_HIDE, nil)}.to raise_error 'Invalid args count'
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context 'defining API with :zeronil option converts zero result to nil' do
|
|
139
|
+
before(:each) do
|
|
140
|
+
hide_method :show_window
|
|
141
|
+
WinGui.def_api 'ShowWindow', 'LI', 'I', :zeronil => true
|
|
142
|
+
end
|
|
143
|
+
after(:each) { restore_method :show_window }
|
|
144
|
+
|
|
145
|
+
it 'defines new instance method' do
|
|
146
|
+
respond_to?(:show_window).should be_true
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'defined method returns nil (but NOT false) instead of zero' do
|
|
150
|
+
test_app do |app|
|
|
151
|
+
show_window(app.handle, SW_HIDE)
|
|
152
|
+
show_window(app.handle, SW_HIDE).should == nil
|
|
153
|
+
show_window(app.handle, SW_HIDE).should_not == false
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it 'defined method does not return true when result is non-zero' do
|
|
158
|
+
test_app do |app|
|
|
159
|
+
result = show_window(app.handle, SW_SHOWNA)
|
|
160
|
+
result.should_not == 0
|
|
161
|
+
result.should_not == true
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it 'defined method enforces the argument count' do
|
|
166
|
+
test_app do |app|
|
|
167
|
+
expect {show_window}.to raise_error 'Invalid args count'
|
|
168
|
+
expect {show_window(app.handle, SW_HIDE, nil)}.to raise_error 'Invalid args count'
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context 'trying to define an invalid API function' do
|
|
174
|
+
it 'raises error when trying to define function with a wrong function name' do
|
|
175
|
+
expect { WinGui.def_api 'FindWindowImpossible', 'PP', 'L' }.
|
|
176
|
+
to raise_error( /Unable to load function 'FindWindowImpossible'/ )
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context 'defining API function using definition blocks' do
|
|
181
|
+
before(:each) { hide_method :get_window_text } # hide original method if it is defined
|
|
182
|
+
after(:each) { restore_method :get_window_text } # restore original method if it was hidden
|
|
183
|
+
|
|
184
|
+
it 'defines new instance method' do
|
|
185
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
|
186
|
+
end
|
|
187
|
+
respond_to?(:get_window_text).should be_true
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'does not enforce argument count outside of block' do
|
|
191
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
|
192
|
+
end
|
|
193
|
+
expect { get_window_text }.to_not raise_error 'Invalid args count'
|
|
194
|
+
expect { get_window_text(nil) }.to_not raise_error 'Invalid args count'
|
|
195
|
+
expect { get_window_text(nil, 'Str') }.to_not raise_error 'Invalid args count'
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'returns block return value when defined method is called' do
|
|
199
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
|
200
|
+
'Value'
|
|
201
|
+
end
|
|
202
|
+
get_window_text(nil).should == 'Value'
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it 'passes arguments and underlying Win32::API object to the block' do
|
|
206
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
|
207
|
+
@api=api; @args = args
|
|
208
|
+
end
|
|
209
|
+
get_window_text(1, 2, 3)
|
|
210
|
+
@args.should == [1, 2, 3]
|
|
211
|
+
@api.function_name.should == 'GetWindowText' # The name of the function passed to the constructor
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it ':rename option overrides standard name for defined method' do
|
|
215
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L', :rename => 'my_name' do |api, *args|
|
|
216
|
+
end
|
|
217
|
+
expect {get_window_text(nil, nil, nil)}.to raise_error
|
|
218
|
+
expect {my_name(nil, nil)}.to_not raise_error
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it 'calling defined method with (:api) argument returns underlying Win32::API object' do
|
|
222
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
|
223
|
+
end
|
|
224
|
+
expect {@api = get_window_text(:api)}.to_not raise_error
|
|
225
|
+
@api.dll_name.should == 'user32' # The name of the DLL that exports the API function
|
|
226
|
+
@api.effective_function_name.should == 'GetWindowTextA' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
|
|
227
|
+
@api.function_name.should == 'GetWindowText' # The name of the function passed to the constructor
|
|
228
|
+
@api.prototype.should == ['L', 'P', 'L'] # The prototype, returned as an array of characters
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context 'providing API function with callback' do
|
|
233
|
+
# before(:each) { hide_method :enum_windows } # hide original find_window method if it is defined
|
|
234
|
+
# after(:each) { restore_method :enum_window } # restore original find_window method if it was hidden
|
|
235
|
+
#
|
|
236
|
+
it '#callback method creates a valid callback object' do
|
|
237
|
+
pending 'callback is now a class method of WinGui, not available here (exept through module_eval)'
|
|
238
|
+
expect { @callback = callback('LP', 'I') {|handle, message| true} }.to_not raise_error
|
|
239
|
+
@callback.should be_a_kind_of(Win32::API::Callback)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'created callback object can be used as a valid arg of API function expecting callback' do
|
|
243
|
+
pending 'API changed - callback arg is no longer valid, block is used instead'
|
|
244
|
+
# WinGui.def_api 'EnumWindows', 'KP', 'L'
|
|
245
|
+
expect { enum_windows(enum_callback, 'Message') }.to_not raise_error
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'defined API functions expecting callback recognize/accept blocks' do
|
|
249
|
+
pending ' API is not exactly clear atm (what about prototype?)(.with_callback method?)'
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
describe WinGui, ' contains a set of pre-defined GUI functions' do
|
|
255
|
+
describe '#window?' do
|
|
256
|
+
spec{ use{ window?(handle = 0) }}
|
|
257
|
+
# Tests whether the specified window handle identifies an existing window.
|
|
258
|
+
# A thread should not use IsWindow for a window that it did not create because the window could be destroyed after this
|
|
259
|
+
# function was called. Further, because window handles are recycled the handle could even point to a different window.
|
|
260
|
+
|
|
261
|
+
it 'returns true if window exists' do
|
|
262
|
+
test_app do |app|
|
|
263
|
+
window?(app.handle).should == true
|
|
264
|
+
window?(app.textarea.handle).should == true
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it 'returns false if window does not exist' do
|
|
269
|
+
test_app do |app|
|
|
270
|
+
@app_handle = app.handle
|
|
271
|
+
@ta_handle = app.textarea.handle
|
|
272
|
+
end
|
|
273
|
+
window?(@app_handle).should == false
|
|
274
|
+
window?(@ta_handle).should == false
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe '#window_visible?' do
|
|
279
|
+
spec{ use{ window_visible?(handle = any_handle) }}
|
|
280
|
+
spec{ use{ visible?(handle = any_handle) }}
|
|
281
|
+
# Tests if the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style.
|
|
282
|
+
# Because the return value specifies whether the window has the WS_VISIBLE style, it may be true even if the window is totally obscured by other windows.
|
|
283
|
+
|
|
284
|
+
it 'returns true if window is visible' do
|
|
285
|
+
test_app do |app|
|
|
286
|
+
visible?(app.handle).should == true
|
|
287
|
+
window_visible?(app.handle).should == true
|
|
288
|
+
window_visible?(app.textarea.handle).should == true
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it 'returns false if window is not visible' do
|
|
293
|
+
test_app do |app|
|
|
294
|
+
hide_window(app.handle)
|
|
295
|
+
visible?(app.handle).should == false
|
|
296
|
+
window_visible?(app.handle).should == false
|
|
297
|
+
window_visible?(app.textarea.handle).should == false
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
describe '#maximized?' do
|
|
303
|
+
spec{ use{ zoomed?(handle = 0) }}
|
|
304
|
+
spec{ use{ maximized?(handle = 0) }}
|
|
305
|
+
# Tests whether the specified window is maximized.
|
|
306
|
+
|
|
307
|
+
it 'returns false if window is not maximized' do
|
|
308
|
+
test_app do |app|
|
|
309
|
+
zoomed?(app.handle).should == false
|
|
310
|
+
maximized?(app.handle).should == false
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it 'returns true if the window is maximized' do
|
|
315
|
+
test_app do |app|
|
|
316
|
+
show_window(app.handle, SW_MAXIMIZE)
|
|
317
|
+
maximized?(app.handle).should == true
|
|
318
|
+
zoomed?(app.handle).should == true
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
describe '#minimized?' do
|
|
324
|
+
spec{ use{ iconic?(handle = 0) }}
|
|
325
|
+
spec{ use{ minimized?(handle = 0) }}
|
|
326
|
+
# Tests whether the specified window is minimized.
|
|
327
|
+
|
|
328
|
+
it 'returns false if window is not minimized' do
|
|
329
|
+
test_app do |app|
|
|
330
|
+
iconic?(app.handle).should == false
|
|
331
|
+
minimized?(app.handle).should == false
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
it 'returns true if the window is minimized' do
|
|
336
|
+
test_app do |app|
|
|
337
|
+
show_window(app.handle, SW_MINIMIZE)
|
|
338
|
+
iconic?(app.handle).should == true
|
|
339
|
+
minimized?(app.handle).should == true
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
describe '#child?' do
|
|
345
|
+
spec{ use{ child?(parent_handle = any_handle, handle = any_handle) }}
|
|
346
|
+
# Tests whether a window is a child (or descendant) window of a specified parent window. A child window is the direct descendant
|
|
347
|
+
# of a specified parent window if that parent window is in the chain of parent windows; the chain of parent windows leads from
|
|
348
|
+
# the original overlapped or pop-up window to the child window.
|
|
349
|
+
|
|
350
|
+
it 'returns true if the window is a child' do
|
|
351
|
+
test_app do |app|
|
|
352
|
+
child?(app.handle, app.textarea.handle).should == true
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
it 'returns false if window is not a child' do
|
|
356
|
+
test_app do |app|
|
|
357
|
+
child?(app.handle, any_handle).should == false
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
describe '#find_window' do
|
|
363
|
+
spec{ use{ find_window(class_name = nil, win_name = nil) }}
|
|
364
|
+
|
|
365
|
+
it 'returns either Integer Window handle or nil' do
|
|
366
|
+
find_window(nil, nil).should be_a_kind_of Integer
|
|
367
|
+
nil.class.should === find_window(TEST_IMPOSSIBLE, nil)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it 'returns nil if Window is not found' do
|
|
371
|
+
find_window(TEST_IMPOSSIBLE, nil).should == nil
|
|
372
|
+
find_window(nil, TEST_IMPOSSIBLE).should == nil
|
|
373
|
+
find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
it 'finds at least one window if both args are nils' do
|
|
377
|
+
find_window(nil, nil).should_not == nil
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
it 'finds top-level window by window class' do
|
|
381
|
+
test_app {|app| find_window(TEST_WIN_CLASS, nil).should == app.handle }
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
it 'finds top-level window by title' do
|
|
385
|
+
test_app {|app| find_window(nil, TEST_WIN_TITLE).should == app.handle }
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
describe '#find_window_w' do
|
|
390
|
+
spec{ use{ find_window_w(class_name = nil, win_name = nil) }}
|
|
391
|
+
|
|
392
|
+
it 'returns zero if Window is not found' do
|
|
393
|
+
find_window_w(TEST_IMPOSSIBLE, nil).should == nil
|
|
394
|
+
find_window_w(nil, TEST_IMPOSSIBLE).should == nil
|
|
395
|
+
find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
it 'finds at least one window if given two nils' do
|
|
399
|
+
find_window_w(nil, nil).should_not == nil
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it 'finds top-level window by window class' do
|
|
403
|
+
test_app {|app| find_window_w(TEST_WIN_CLASS.to_w, nil).should == app.handle }
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
it 'finds top-level window by title' do
|
|
407
|
+
test_app {|app| find_window_w(nil, TEST_WIN_TITLE.to_w).should == app.handle }
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
describe '#find_window_ex' do
|
|
412
|
+
spec{ use{ control_handle = find_window_ex(parent = any_handle, after_child = 0, win_class = nil, win_title = nil) }}
|
|
413
|
+
|
|
414
|
+
it 'returns nil if wrong control is given' do
|
|
415
|
+
parent_handle = any_handle
|
|
416
|
+
find_window_ex(parent_handle, 0, TEST_IMPOSSIBLE, nil).should == nil
|
|
417
|
+
find_window_ex(parent_handle, 0, nil, TEST_IMPOSSIBLE).should == nil
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it 'finds child window/control by class' do
|
|
421
|
+
test_app do |app|
|
|
422
|
+
ta_handle = find_window_ex(app.handle, 0, TEST_TEXTAREA_CLASS, nil)
|
|
423
|
+
ta_handle.should_not == nil
|
|
424
|
+
ta_handle.should == app.textarea.handle
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it 'finds child window/control by text/title' do
|
|
429
|
+
pending 'Identify appropriate (short name) control'
|
|
430
|
+
test_app do |app|
|
|
431
|
+
keystroke(VK_CONTROL, 'A'.ord)
|
|
432
|
+
keystroke('1'.ord, '2'.ord)
|
|
433
|
+
ta_handle = find_window_ex(app.handle, 0, nil, '12')
|
|
434
|
+
ta_handle.should_not == 0
|
|
435
|
+
ta_handle.should == app.textarea.handle
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
describe '#get_window_thread_process_id' do
|
|
441
|
+
spec{ use{ thread, process = get_window_thread_process_id(handle = any_handle) }}
|
|
442
|
+
# Improved with block to accept window handle as a single arg and return a pair of [thread, process]
|
|
443
|
+
|
|
444
|
+
it 'returns a pair of nonzero Integer ids (window thread and process)' do
|
|
445
|
+
thread, process = get_window_thread_process_id(handle = any_handle)
|
|
446
|
+
thread.should be_a_kind_of Integer
|
|
447
|
+
thread.should be > 0
|
|
448
|
+
process.should be_a_kind_of Integer
|
|
449
|
+
process.should be > 0
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
describe '#get_window_text' do
|
|
454
|
+
spec{ use{ text = get_window_text(handle = 0)}}
|
|
455
|
+
# Improved with block to accept window handle as a single arg and return (rstripped) text string
|
|
456
|
+
|
|
457
|
+
it 'returns correct window text' do
|
|
458
|
+
test_app {|app| get_window_text(app.handle).should == TEST_WIN_TITLE }
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
describe '#get_window_text_w' do
|
|
463
|
+
spec{ use{ class_name = get_window_text_w(handle = 0)}} # result encoded as utf-8
|
|
464
|
+
# Unicode version of get_window_text (strings returned encoded as utf-8)
|
|
465
|
+
|
|
466
|
+
it 'returns correct window text' do
|
|
467
|
+
test_app {|app| get_window_text_w(app.handle).should == TEST_WIN_TITLE }
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
describe '#get_class_name' do
|
|
472
|
+
spec{ use{ class_name = get_class_name(handle = 0)}}
|
|
473
|
+
# Improved with block to accept window handle as a single arg and return class name string
|
|
474
|
+
|
|
475
|
+
it 'returns correct window class name' do
|
|
476
|
+
test_app {|app| get_class_name(app.handle).should == TEST_WIN_CLASS }
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
describe '#get_class_name_w' do
|
|
481
|
+
spec{ use{ class_name = get_class_name_w(handle = 0)}} # result encoded as utf-8
|
|
482
|
+
# Unicode version of get_class_name (strings returned encoded as utf-8)
|
|
483
|
+
|
|
484
|
+
it 'returns correct window class name' do
|
|
485
|
+
test_app {|app| get_class_name_w(app.handle).should == TEST_WIN_CLASS }
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
describe '#get_window_rect' do
|
|
490
|
+
spec{ use{ left, top, right, bottom = get_window_rect(any_handle)}}
|
|
491
|
+
|
|
492
|
+
it 'returns windows rectangle' do
|
|
493
|
+
test_app do |app|
|
|
494
|
+
get_window_rect(app.handle).should == TEST_WIN_RECT
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
describe '#show_window ', 'LI', 'I' do
|
|
500
|
+
spec{ use{ was_visible = show_window(handle = any_handle, cmd = SW_SHOWNA) }}
|
|
501
|
+
|
|
502
|
+
it 'was_visible = hide_window(handle = any_handle) # alias method (not a separate API function)' do
|
|
503
|
+
test_app do |app|
|
|
504
|
+
use{ hide_window(app.handle) }
|
|
505
|
+
visible?(app.handle).should == false
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
it 'returns true if the window was PREVIOUSLY visible' do
|
|
510
|
+
test_app {|app| show_window(app.handle, SW_HIDE).should == true }
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
it 'returns false if the window was PREVIOUSLY not visible' do
|
|
514
|
+
test_app do |app|
|
|
515
|
+
show_window(app.handle, SW_HIDE)
|
|
516
|
+
show_window(app.handle, SW_HIDE).should == false
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
it 'SW_HIDE command hides window' do
|
|
521
|
+
test_app do |app|
|
|
522
|
+
show_window(app.handle, SW_HIDE)
|
|
523
|
+
visible?(app.handle).should == false
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
it 'SW_SHOW command shows hidden window' do
|
|
528
|
+
test_app do |app|
|
|
529
|
+
show_window(app.handle, SW_HIDE)
|
|
530
|
+
show_window(app.handle, SW_SHOW)
|
|
531
|
+
visible?(app.handle).should == true
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
it 'SW_MAXIMIZE maximizes window' do
|
|
536
|
+
test_app do |app|
|
|
537
|
+
show_window(app.handle, SW_MAXIMIZE)
|
|
538
|
+
maximized?(app.handle).should == true
|
|
539
|
+
end
|
|
540
|
+
pending 'Need to make sure window is maximized but NOT activated '
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
it 'SW_MINIMIZE minimizes window and activates the next top-level window in the Z order' do
|
|
544
|
+
test_app do |app|
|
|
545
|
+
show_window(app.handle, SW_MINIMIZE)
|
|
546
|
+
minimized?(app.handle).should == true
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
it 'SW_SHOWMAXIMIZED activates the window and displays it as a maximized window' do
|
|
551
|
+
pending 'Need to make sure window is maximized AND activated '
|
|
552
|
+
test_app do |app|
|
|
553
|
+
show_window(app.handle, SW_SHOWMAXIMIZED)
|
|
554
|
+
get_window_rect(app.handle)
|
|
555
|
+
#.should == TEST_MAX_RECT
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
end
|
|
559
|
+
it 'SW_SHOWMINIMIZED activates the window and displays it as a minimized window' do
|
|
560
|
+
pending 'Need to make sure window is minimized AND activated '
|
|
561
|
+
test_app do |app|
|
|
562
|
+
show_window(app.handle, SW_SHOWMINIMIZED)
|
|
563
|
+
p get_window_rect(app.handle)
|
|
564
|
+
#.should == TEST_MAX_RECT
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
end
|
|
568
|
+
it 'SW_SHOWMINNOACTIVE displays the window as a minimized window (similar to SW_SHOWMINIMIZED, but window is not activated)'
|
|
569
|
+
it 'SW_SHOWNA displays the window in its current size and position (similar to SW_SHOW, but window is not activated)'
|
|
570
|
+
it 'SW_SHOWNOACTIVATE displays the window in its current size and position (similar to SW_SHOW, but window is not activated)'
|
|
571
|
+
it 'SW_SHOWNORMAL activates and displays a window. Restores minimized/maximized window to original size/position. Use it to show window for the first time'
|
|
572
|
+
it 'SW_RESTORE activates and displays the window. Restores minimized/maximized window to original size/position. Use it to restore minimized windows'
|
|
573
|
+
it 'SW_SHOWDEFAULT sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application'
|
|
574
|
+
it 'SW_FORCEMINIMIZE minimizes a window, even if the thread that owns the window is not responding - only Win2000/XP'
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
describe '#keydb_event' do
|
|
578
|
+
spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
|
|
579
|
+
# vkey (I) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
|
580
|
+
# bscan (I) - Specifies a hardware scan code for the key.
|
|
581
|
+
# flags (L) - Specifies various aspects of function operation. This parameter can be one or more of the following values.
|
|
582
|
+
# KEYEVENTF_EXTENDEDKEY - If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
|
|
583
|
+
# KEYEVENTF_KEYUP - If specified, the key is being released. If not specified, the key is being depressed.
|
|
584
|
+
# extra_info (L) - Specifies an additional value associated with the key stroke.
|
|
585
|
+
# no return value
|
|
586
|
+
|
|
587
|
+
it 'synthesizes a numeric keystroke, emulating keyboard driver' do
|
|
588
|
+
test_app do |app|
|
|
589
|
+
text = '123 456'
|
|
590
|
+
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
|
591
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
|
592
|
+
sleep TEST_KEY_DELAY
|
|
593
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
|
594
|
+
sleep TEST_KEY_DELAY
|
|
595
|
+
end
|
|
596
|
+
app.textarea.text.should =~ Regexp.new(text)
|
|
597
|
+
7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
it 'synthesizes a letter keystroke, emulating keyboard driver'
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
describe '#post_message' do
|
|
605
|
+
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
|
|
606
|
+
# handle (L) - Handle to the window whose window procedure will receive the message.
|
|
607
|
+
# If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
|
|
608
|
+
# invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
|
|
609
|
+
# msg (L) - Specifies the message to be posted.
|
|
610
|
+
# w_param (L) - Specifies additional message-specific information.
|
|
611
|
+
# l_param (L) - Specifies additional message-specific information.
|
|
612
|
+
# returns (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
|
|
613
|
+
|
|
614
|
+
it 'places (posts) a message in the message queue associated with the thread that created the specified window'
|
|
615
|
+
it 'returns without waiting for the thread to process the message'
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
describe '#send_message' do
|
|
619
|
+
spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
|
|
620
|
+
# handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
|
|
621
|
+
# HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
|
|
622
|
+
# overlapped windows, and pop-up windows. The message is not posted to child windows.
|
|
623
|
+
# NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
|
|
624
|
+
# msg (L) - Specifies the message to be posted.
|
|
625
|
+
# w_param (L) - Specifies additional message-specific information.
|
|
626
|
+
# l_param (L) - Specifies additional message-specific information.
|
|
627
|
+
# return (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
|
|
628
|
+
|
|
629
|
+
it 'sends the specified message to a window or windows'
|
|
630
|
+
it 'calls the window procedure and does not return until the window procedure has processed the message'
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
describe '#get_dlg_item' do
|
|
634
|
+
spec{ use{ control_handle = get_dlg_item(handle = 0, item_id = 1) }}
|
|
635
|
+
# handle (L) - Handle of the dialog box that contains the control.
|
|
636
|
+
# item_id (I) - Specifies the identifier of the control to be retrieved.
|
|
637
|
+
# Returns (L) - handle of the specified control if success or nil for invalid dialog box handle or a nonexistent control.
|
|
638
|
+
# To get extended error information, call GetLastError.
|
|
639
|
+
# You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle
|
|
640
|
+
# parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the
|
|
641
|
+
# CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.
|
|
642
|
+
|
|
643
|
+
it 'returns handle to correctly specified control'
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
describe '#enum_windows' do
|
|
647
|
+
spec{ use{ enum_windows(message = 'Message') }}
|
|
648
|
+
|
|
649
|
+
it 'return an array of top-level window handles if block is not given' do
|
|
650
|
+
enum = enum_windows(message = 'Message')
|
|
651
|
+
enum.should be_a_kind_of Array
|
|
652
|
+
enum.should_not be_empty
|
|
653
|
+
enum.should have_at_least(60).elements # typical number of top windows in WinXP system?
|
|
654
|
+
enum.compact.size.should == enum.size # should not contain nils
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
it 'iterates through all the top-level windows, passing each found window handle and message to a given block'
|
|
658
|
+
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
describe '#enum_child_windows' do
|
|
662
|
+
spec{ use{ enum_child_windows(parent = any_handle, message = 'Message') }}
|
|
663
|
+
|
|
664
|
+
it 'return an array of child window handles if block is not given' do
|
|
665
|
+
test_app do |app|
|
|
666
|
+
enum = enum_child_windows(app.handle, message = 'Message')
|
|
667
|
+
enum.should be_a_kind_of Array
|
|
668
|
+
enum.should_not be_empty
|
|
669
|
+
enum.should have(2).elements
|
|
670
|
+
p get_class_name(enum.first), get_class_name(enum.last)
|
|
671
|
+
get_class_name(enum.last).should == TEST_TEXTAREA_CLASS
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
it 'loops through all children of given window, passing each found window handle and a message to a given block'
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
it 'GetForegroundWindow ', 'V', 'L'
|
|
679
|
+
it 'GetActiveWindow ', 'V', 'L'
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
describe WinGui, ' convenience wrapper methods' do
|
|
683
|
+
describe '#keystroke' do
|
|
684
|
+
spec{ use{ keystroke( vkey = 30, vkey = 30) }}
|
|
685
|
+
# this service method emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
|
|
686
|
+
# vkey (int) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
|
687
|
+
|
|
688
|
+
it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
|
|
689
|
+
test_app do |app|
|
|
690
|
+
keystroke(VK_CONTROL, 'A'.ord)
|
|
691
|
+
keystroke(VK_SPACE)
|
|
692
|
+
app.textarea.text.should == ' '
|
|
693
|
+
2.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
describe '#type_in' do
|
|
699
|
+
spec{ use{ type_in(message = '') }}
|
|
700
|
+
# this service method types text message into window holding the focus
|
|
701
|
+
|
|
702
|
+
it 'types text message into window holding the focus' do
|
|
703
|
+
test_app do |app|
|
|
704
|
+
text = '123 456'
|
|
705
|
+
type_in(text)
|
|
706
|
+
app.textarea.text.should =~ Regexp.new(text)
|
|
707
|
+
7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
|
|
708
|
+
end
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
describe 'dialog' do
|
|
713
|
+
spec{ use{ dialog( title ='Dialog Title', timeout_sec = 0.001, &any_block) }}
|
|
714
|
+
# me od finds top-level dialog window by title and yields found dialog window to block if given
|
|
715
|
+
|
|
716
|
+
it 'finds top-level dialog window by title' do
|
|
717
|
+
pending 'Some problems (?with timeouts?) leave window open ~half of the runs'
|
|
718
|
+
test_app do |app|
|
|
719
|
+
keystroke(VK_ALT, 'F'.ord, 'A'.ord)
|
|
720
|
+
@found = false
|
|
721
|
+
dialog('Save As', 0.5) do |dialog_window|
|
|
722
|
+
@found = true
|
|
723
|
+
keystroke(VK_ESCAPE)
|
|
724
|
+
dialog_window
|
|
725
|
+
end
|
|
726
|
+
@found.should == true
|
|
727
|
+
end
|
|
728
|
+
end
|
|
729
|
+
it 'yields found dialog window to a given block'
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
end
|
|
733
|
+
end
|