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.
Files changed (164) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +43 -0
  5. data/Rakefile +58 -0
  6. data/VERSION +1 -0
  7. data/book_code/early_success/bundle.rb +34 -0
  8. data/book_code/early_success/english.txt +1 -0
  9. data/book_code/early_success/jruby_basics.rb +47 -0
  10. data/book_code/early_success/windows_basics.rb +97 -0
  11. data/book_code/guessing/locknote.rb +379 -0
  12. data/book_code/guessing/monkeyshines.rb +14 -0
  13. data/book_code/guessing/note.rb +120 -0
  14. data/book_code/guessing/note_spec.rb +175 -0
  15. data/book_code/guessing/replay.rb +21 -0
  16. data/book_code/guessing/seed.rb +9 -0
  17. data/book_code/guessing/spec_helper.rb +69 -0
  18. data/book_code/guessing/windows_gui.rb +247 -0
  19. data/book_code/home_stretch/junquenote.rb +151 -0
  20. data/book_code/home_stretch/locknote.rb +180 -0
  21. data/book_code/home_stretch/note.rb +144 -0
  22. data/book_code/home_stretch/note_spec.rb +191 -0
  23. data/book_code/home_stretch/spec_helper.rb +55 -0
  24. data/book_code/home_stretch/swing_gui.rb +50 -0
  25. data/book_code/home_stretch/windows_gui.rb +232 -0
  26. data/book_code/junquenote/exports.sh +10 -0
  27. data/book_code/junquenote/jruby_mac.sh +10 -0
  28. data/book_code/junquenote/junquenote_app.rb +262 -0
  29. data/book_code/novite/Rakefile +10 -0
  30. data/book_code/novite/app/controllers/application.rb +18 -0
  31. data/book_code/novite/app/controllers/guests_controller.rb +28 -0
  32. data/book_code/novite/app/controllers/parties_controller.rb +77 -0
  33. data/book_code/novite/app/helpers/application_helper.rb +11 -0
  34. data/book_code/novite/app/helpers/guests_helper.rb +10 -0
  35. data/book_code/novite/app/helpers/parties_helper.rb +10 -0
  36. data/book_code/novite/app/models/guest.rb +11 -0
  37. data/book_code/novite/app/models/party.rb +32 -0
  38. data/book_code/novite/app/models/party_mailer.rb +19 -0
  39. data/book_code/novite/app/views/layouts/application.rhtml +44 -0
  40. data/book_code/novite/app/views/parties/new.html.erb +42 -0
  41. data/book_code/novite/app/views/parties/show.html.erb +43 -0
  42. data/book_code/novite/app/views/party_mailer/invite.erb +17 -0
  43. data/book_code/novite/config/boot.rb +117 -0
  44. data/book_code/novite/config/database.yml +19 -0
  45. data/book_code/novite/config/environment.rb +67 -0
  46. data/book_code/novite/config/environments/development.rb +29 -0
  47. data/book_code/novite/config/environments/production.rb +27 -0
  48. data/book_code/novite/config/environments/test.rb +30 -0
  49. data/book_code/novite/config/initializers/inflections.rb +18 -0
  50. data/book_code/novite/config/initializers/mime_types.rb +13 -0
  51. data/book_code/novite/config/routes.rb +47 -0
  52. data/book_code/novite/db/migrate/001_create_parties.rb +26 -0
  53. data/book_code/novite/db/migrate/002_create_guests.rb +23 -0
  54. data/book_code/novite/db/schema.rb +41 -0
  55. data/book_code/novite/log/empty.txt +0 -0
  56. data/book_code/novite/public/.htaccess +40 -0
  57. data/book_code/novite/public/404.html +38 -0
  58. data/book_code/novite/public/422.html +38 -0
  59. data/book_code/novite/public/500.html +38 -0
  60. data/book_code/novite/public/dispatch.cgi +10 -0
  61. data/book_code/novite/public/dispatch.fcgi +24 -0
  62. data/book_code/novite/public/dispatch.rb +18 -0
  63. data/book_code/novite/public/favicon.ico +0 -0
  64. data/book_code/novite/public/images/rails.png +0 -0
  65. data/book_code/novite/public/index.html +285 -0
  66. data/book_code/novite/public/javascripts/application.js +10 -0
  67. data/book_code/novite/public/javascripts/controls.js +971 -0
  68. data/book_code/novite/public/javascripts/dragdrop.js +980 -0
  69. data/book_code/novite/public/javascripts/effects.js +1128 -0
  70. data/book_code/novite/public/javascripts/prototype.js +4233 -0
  71. data/book_code/novite/public/robots.txt +5 -0
  72. data/book_code/novite/script/about +3 -0
  73. data/book_code/novite/script/console +3 -0
  74. data/book_code/novite/script/destroy +3 -0
  75. data/book_code/novite/script/generate +3 -0
  76. data/book_code/novite/script/performance/benchmarker +3 -0
  77. data/book_code/novite/script/performance/profiler +3 -0
  78. data/book_code/novite/script/performance/request +3 -0
  79. data/book_code/novite/script/plugin +3 -0
  80. data/book_code/novite/script/process/inspector +3 -0
  81. data/book_code/novite/script/process/reaper +3 -0
  82. data/book_code/novite/script/process/spawner +3 -0
  83. data/book_code/novite/script/runner +3 -0
  84. data/book_code/novite/script/server +3 -0
  85. data/book_code/novite/test/test_helper.rb +46 -0
  86. data/book_code/one_more_thing/applescript.rb +68 -0
  87. data/book_code/one_more_thing/note_spec.rb +50 -0
  88. data/book_code/one_more_thing/spec_helper.rb +17 -0
  89. data/book_code/one_more_thing/textedit-pure.rb +28 -0
  90. data/book_code/one_more_thing/textedit.applescript +26 -0
  91. data/book_code/one_more_thing/textedit.rb +32 -0
  92. data/book_code/one_more_thing/textnote.rb +87 -0
  93. data/book_code/simplify/junquenote.rb +48 -0
  94. data/book_code/simplify/locknote.rb +46 -0
  95. data/book_code/simplify/note.rb +35 -0
  96. data/book_code/simplify/note_spec.rb +28 -0
  97. data/book_code/simplify/swing_gui.rb +45 -0
  98. data/book_code/simplify/windows_gui.rb +232 -0
  99. data/book_code/simplify/windows_gui_spec.rb +35 -0
  100. data/book_code/story/invite.story +19 -0
  101. data/book_code/story/journal.txt +29 -0
  102. data/book_code/story/novite_stories.rb +156 -0
  103. data/book_code/story/party.rb +149 -0
  104. data/book_code/story/password.rb +61 -0
  105. data/book_code/story/password.story +26 -0
  106. data/book_code/story/rsvp.story +29 -0
  107. data/book_code/tables/TestTime.html +93 -0
  108. data/book_code/tables/TestTimeSample.html +63 -0
  109. data/book_code/tables/calculate_time.rb +39 -0
  110. data/book_code/tables/calculator.rb +108 -0
  111. data/book_code/tables/calculator_actions.rb +27 -0
  112. data/book_code/tables/calculator_spec.rb +47 -0
  113. data/book_code/tables/fit.rb +32 -0
  114. data/book_code/tables/matrix.rb +109 -0
  115. data/book_code/tables/pseudocode.rb +17 -0
  116. data/book_code/tubes/book_selenium.rb +67 -0
  117. data/book_code/tubes/book_watir.rb +60 -0
  118. data/book_code/tubes/dragdrop.html +81 -0
  119. data/book_code/tubes/html_capture.rb +33 -0
  120. data/book_code/tubes/joke_list.rb +67 -0
  121. data/book_code/tubes/list_spec.rb +41 -0
  122. data/book_code/tubes/search_spec.rb +32 -0
  123. data/book_code/tubes/selenium_example.rb +66 -0
  124. data/book_code/tubes/selenium_link.rb +23 -0
  125. data/book_code/tubes/web_server.rb +14 -0
  126. data/book_code/windows/wgui.rb +29 -0
  127. data/book_code/windows/wobj.rb +25 -0
  128. data/book_code/windows/wsh.rb +25 -0
  129. data/book_code/with_rspec/empty_spec.rb +13 -0
  130. data/book_code/with_rspec/junquenote.rb +60 -0
  131. data/book_code/with_rspec/locknote.rb +129 -0
  132. data/book_code/with_rspec/note_spec.rb +32 -0
  133. data/book_code/with_rspec/should_examples.rb +18 -0
  134. data/exp/exp.rb +6 -0
  135. data/exp/exp_encodings.rb +40 -0
  136. data/exp/exp_enum_windows.rb +60 -0
  137. data/exp/exp_quik.rb +38 -0
  138. data/exp/exp_wsh.rb +115 -0
  139. data/exp/old/windows_basics.rb +80 -0
  140. data/exp/old/wnote.rb +80 -0
  141. data/exp/old/wnote_spec.rb +20 -0
  142. data/features/step_definitions/win_gui_steps.rb +0 -0
  143. data/features/support/env.rb +4 -0
  144. data/features/win_gui.feature +9 -0
  145. data/lib/note/java/jemmy.jar +0 -0
  146. data/lib/note/java/jnote.rb +48 -0
  147. data/lib/note/java/jruby_basics.rb +37 -0
  148. data/lib/note/java/junquenote_app.rb +262 -0
  149. data/lib/note/java/note_spec.rb +20 -0
  150. data/lib/note/win/locknote.rb +19 -0
  151. data/lib/note.rb +15 -0
  152. data/lib/win_gui/constants.rb +66 -0
  153. data/lib/win_gui/string_extensions.rb +24 -0
  154. data/lib/win_gui/win_gui.rb +274 -0
  155. data/lib/win_gui/window.rb +70 -0
  156. data/lib/win_gui.rb +3 -0
  157. data/spec/note/win/locknote_spec.rb +7 -0
  158. data/spec/spec.opts +2 -0
  159. data/spec/spec_helper.rb +100 -0
  160. data/spec/test_apps/locknote/LockNote.exe +0 -0
  161. data/spec/win_gui/string_extensions_spec.rb +61 -0
  162. data/spec/win_gui/win_gui_spec.rb +733 -0
  163. data/spec/win_gui/window_spec.rb +124 -0
  164. metadata +251 -0
@@ -0,0 +1,379 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ require 'windows_gui'
10
+ require 'note'
11
+ require 'ftools'
12
+ require 'set'
13
+
14
+
15
+ class LockNote < Note
16
+ include WindowsGui
17
+
18
+ @@app = LockNote
19
+ @@titles =
20
+ {
21
+ :file => 'Save As',
22
+ :exit => 'Steganos LockNote',
23
+ :about => 'About Steganos LockNote...',
24
+ :about_menu => 'About',
25
+ :dialog => 'Steganos LockNote'
26
+ }
27
+
28
+ BasePath = "C:\\LockNote"
29
+ WindowsGui.load_symbols "#{BasePath}\\src\\resource.h"
30
+ WindowsGui.load_symbols "#{BasePath}\\src\\atlres.h"
31
+ ID_HELP_ABOUT = ID_APP_ABOUT
32
+
33
+ DefaultOptions = {
34
+ :password => 'password',
35
+ :confirmation => 'password'
36
+ }
37
+
38
+ EditControl = 'ATL:00434310'
39
+
40
+ def initialize(name = 'LockNote', with_options = {})
41
+ options = DefaultOptions.merge(with_options)
42
+
43
+ @prompted = {}
44
+ @path = LockNote.path_to name
45
+
46
+ system 'start "" "' + @path + '"'
47
+ unlock_password options
48
+
49
+ if @prompted[:with_error] || options[:cancel_password]
50
+ @main_window = Window.new 0
51
+ sleep 1.0
52
+ else
53
+ @main_window = Window.top_level "#{name} - Steganos LockNote"
54
+ @edit_window = @main_window.child EditControl
55
+
56
+ set_foreground_window @main_window.handle
57
+ end
58
+ end
59
+
60
+
61
+ def select_all
62
+ keystroke VK_CONTROL, ?A
63
+ end
64
+
65
+ def text
66
+ @edit_window.text
67
+ end
68
+
69
+ def text=(new_text)
70
+ select_all
71
+ delete
72
+ type_in new_text
73
+ end
74
+
75
+ def selection
76
+ result = send_message @edit_window.handle, EM_GETSEL, 0, 0
77
+ bounds = [result].pack('L').unpack('SS')
78
+ bounds[0]...bounds[1]
79
+ end
80
+
81
+ def go_to(where)
82
+ case where
83
+ when :beginning
84
+ keystroke VK_CONTROL, VK_HOME
85
+ when :end
86
+ keystroke VK_CONTROL, VK_END
87
+ end
88
+ end
89
+
90
+ WholeWord = 0x0410
91
+ ExactCase = 0x0411
92
+ SearchUp = 0x0420
93
+
94
+ def find(term, with_options={})
95
+ menu 'Edit', 'Find...'
96
+
97
+ appeared = dialog('Find') do |d|
98
+ type_in term
99
+
100
+ d.click WholeWord if with_options[:whole_word]
101
+ d.click ExactCase if with_options[:exact_case]
102
+ d.click SearchUp if :back == with_options[:direction]
103
+
104
+ d.click IDOK
105
+ d.click IDCANCEL
106
+ end
107
+
108
+ raise 'Find dialog did not appear' unless appeared
109
+ end
110
+
111
+ def running?
112
+ @main_window.handle != 0 && is_window(@main_window.handle) != 0
113
+ end
114
+
115
+ def menu(name, item, wait = false)
116
+ multiple_words = /[.]/
117
+ single_word = /[ .]/
118
+
119
+ [multiple_words, single_word].each do |pattern|
120
+ words = item.gsub(pattern, '').split
121
+ const_name = ['ID', name, *words].join('_').upcase
122
+
123
+ begin
124
+ id = LockNote.const_get const_name
125
+ action = wait ? :send_message : :post_message
126
+
127
+ return send(action, @main_window.handle, WM_COMMAND, id, 0)
128
+ rescue NameError
129
+ end
130
+ end
131
+ end
132
+
133
+ def self.path_to(name)
134
+ "#{BasePath}\\#{name}.exe"
135
+ end
136
+
137
+ private
138
+
139
+ def enter_password(with_options = {})
140
+ options = DefaultOptions.merge with_options
141
+
142
+ @prompted[:for_password] = dialog(@@titles[:dialog]) do |d|
143
+ type_in options[:password]
144
+
145
+ if options[:confirmation]
146
+ keystroke VK_TAB
147
+ type_in options[:confirmation]
148
+ end
149
+
150
+ d.click options[:cancel_password] ? IDCANCEL : IDOK
151
+ end
152
+ end
153
+
154
+ ErrorIcon = 0x0014
155
+
156
+ def watch_for_error
157
+ if @prompted[:for_password]
158
+ @prompted[:with_error] = dialog(@@titles[:dialog]) do |d|
159
+ d.click IDCANCEL if get_dlg_item(d.handle, ErrorIcon) > 0
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+
166
+
167
+ srand
168
+ $seed ||= srand #(1)
169
+ srand $seed
170
+ puts "Using random seed #{$seed}"
171
+
172
+ class LockNote
173
+ def paste
174
+ case rand(3)
175
+ when 0
176
+ menu 'Edit', 'Paste'
177
+ puts 'Pasting from the menu'
178
+ when 1
179
+ keystroke VK_CONTROL, ?V
180
+ puts 'Pasting from a keyboard shortcut'
181
+ when 2
182
+ @main_window.click EditControl, :right #(2)
183
+ type_in 'P'
184
+ puts 'Pasting from a context menu'
185
+ end
186
+ end
187
+ end
188
+
189
+
190
+
191
+ class LockNote
192
+ @@default_way = :random
193
+
194
+ def self.def_action(name, options, way = nil)
195
+ define_method name do
196
+ keys = options.keys.sort {|k| k.to_s}
197
+
198
+ way ||= @@default_way #(3)
199
+ key = case way
200
+ when nil; keys.last
201
+ when :random; keys[rand(keys.size)]
202
+ else way
203
+ end
204
+
205
+ action = options[key]
206
+
207
+ case key
208
+ when :menu
209
+ menu *action
210
+
211
+ puts "Performing #{name} from the menu bar"
212
+
213
+
214
+ when :keyboard
215
+ keystroke *action
216
+ sleep 0.5
217
+ puts "Performing #{name} from a keyboard shortcut"
218
+
219
+ when :context
220
+ @main_window.click LockNote::EditControl, :right
221
+ sleep 0.5
222
+ type_in action
223
+ sleep 0.5
224
+ puts "Performing #{name} from a context menu"
225
+
226
+ else
227
+ raise "Don't know how to use #{key}"
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+
234
+
235
+ require 'logger'
236
+
237
+ class SimpleFormatter < Logger::Formatter #(4)
238
+ def call(severity, time, progname, msg)
239
+ msg2str(msg) + "\n"
240
+ end
241
+ end
242
+
243
+ $logger = Logger.new STDERR
244
+ $logger.formatter = SimpleFormatter.new #(5)
245
+
246
+
247
+ class LockNote
248
+ @@actions = Set.new
249
+
250
+ def self.def_action(name, options, way = nil)
251
+ @@actions << name
252
+
253
+ define_method name do
254
+ way ||= @@default_way
255
+
256
+ keys = options.keys.sort_by {|k| k.to_s}
257
+ key = case way
258
+ when nil; keys.last
259
+ when :random; keys[rand(keys.size)]
260
+ else way
261
+ end
262
+
263
+ action = options[key]
264
+
265
+ case key
266
+ when :menu
267
+ menu *action
268
+ $logger.info "menu '#{action[0]}', '#{action[1]}'"
269
+
270
+ when :keyboard
271
+ keystroke *action
272
+ sleep 0.5
273
+ $logger.info "keystroke " + action.join(', ')
274
+
275
+ when :context
276
+ @main_window.click LockNote::EditControl, :right
277
+ sleep 0.5
278
+ type_in action
279
+ sleep 0.5
280
+ $logger.info "@main_window.click EditControl, :right"
281
+ $logger.info "type_in '#{action}'"
282
+
283
+ else
284
+ raise "Don't know how to use #{key}"
285
+ end
286
+ end
287
+ end
288
+ end
289
+
290
+ class LockNote
291
+
292
+ def_action :paste,
293
+ :menu => ['Edit', 'Paste', :wait],
294
+ :keyboard => [VK_CONTROL, ?V],
295
+ :context => 'p'
296
+
297
+ end
298
+
299
+ class LockNote
300
+
301
+ def_action :undo,
302
+ :menu => ['Edit', 'Undo', :wait],
303
+ :keyboard => [VK_CONTROL, ?Z]
304
+
305
+ def_action :cut,
306
+ :menu => ['Edit', 'Cut', :wait],
307
+ :keyboard => [VK_CONTROL, ?X],
308
+ :context => 't'
309
+
310
+ def_action :copy,
311
+ :menu => ['Edit', 'Copy', :wait],
312
+ :keyboard => [VK_CONTROL, ?C],
313
+ :context => 'c'
314
+
315
+ def_action :delete,
316
+ :keyboard => [VK_BACK],
317
+ :context => 'd'
318
+
319
+ def_action :select_all,
320
+ :menu => ['Edit', 'Select All', :wait],
321
+ :keyboard => [VK_CONTROL, ?A],
322
+ :context => 'a'
323
+
324
+ end
325
+
326
+ class LockNote
327
+ def_action :find_next,
328
+ :menu => ['Edit', 'Find Next', :wait],
329
+ :keyboard => [VK_F3]
330
+ end
331
+
332
+ class LockNote
333
+ def random_action
334
+ raise "LockNote is not running" unless running?
335
+ choices = @@actions.to_a
336
+ action = choices[rand(choices.size)]
337
+ send action
338
+ end
339
+
340
+
341
+ def random_typing
342
+ num = 1 + rand(50)
343
+ random_text = (1..num).collect {rand(26) + ?a}.pack 'c*'
344
+ type_in random_text
345
+ $logger.info "Typing #{random_text}"
346
+ end
347
+
348
+ def random_clicking
349
+ num = 1 + rand(10)
350
+ num.times do
351
+ point = nil
352
+ (rand(2) + 1).times do
353
+ point = @main_window.click(EditControl, :left, point || :random)
354
+ $logger.info "Clicking #{point.inspect}"
355
+ end
356
+ end
357
+ end
358
+
359
+ @@actions << :random_typing << :random_clicking
360
+
361
+
362
+ def random_typing
363
+ num = 1 + rand(50)
364
+ random_text = (1..num).collect {rand(26) + ?a}.pack 'c*'
365
+ type_in random_text
366
+ $logger.info "type_in '#{random_text}'"
367
+ end
368
+
369
+ def random_clicking
370
+ num = 1 + rand(10)
371
+ num.times do
372
+ point = nil
373
+ (rand(2) + 1).times do
374
+ point = @main_window.click(EditControl, :left, point || :random)
375
+ $logger.info "@main_window.click EditControl, :left, " + point.inspect
376
+ end
377
+ end
378
+ end
379
+ end
@@ -0,0 +1,14 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ require 'locknote'
10
+
11
+
12
+ note = Note.open
13
+ 100.times {note.random_action}
14
+
@@ -0,0 +1,120 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ class Note
10
+ attr_reader :path
11
+
12
+ @@app = nil
13
+ @@titles = {}
14
+
15
+ def self.open(*args)
16
+ @@app.new *args
17
+ end
18
+
19
+ DefaultOptions = {
20
+ :password => 'password',
21
+ :confirmation => 'password'
22
+ }
23
+
24
+ def exit!(with_options = {})
25
+ options = DefaultOptions.merge with_options
26
+
27
+ @main_window.close
28
+
29
+ @prompted[:to_confirm_exit] = dialog(@@titles[:exit]) do |d|
30
+ d.click(options[:save_as] ? '_Yes' : '_No')
31
+ end
32
+
33
+ if options[:save_as]
34
+ path = @@app.path_to options[:save_as]
35
+ enter_filename path
36
+ assign_password options
37
+ end
38
+ end
39
+
40
+ def change_password(with_options = {})
41
+ old_options = {
42
+ :password => with_options[:old_password]} #(1)
43
+
44
+ new_options = {
45
+ :password => with_options[:password],
46
+ :confirmation =>
47
+ with_options[:confirmation] ||
48
+ with_options[:password]} #(2)
49
+
50
+ menu 'File', 'Change Password...'
51
+
52
+ unlock_password old_options
53
+ assign_password new_options
54
+ end
55
+
56
+ def save_as(name, with_options = {})
57
+ options = DefaultOptions.merge with_options #(3)
58
+
59
+ @path = @@app.path_to(name) #(4)
60
+ File.delete @path if File.exists? @path
61
+
62
+ menu 'File', 'Save As...' #(5)
63
+
64
+ enter_filename @path #(6)
65
+ assign_password options
66
+ end
67
+
68
+ def about
69
+ menu 'Help', @@titles[:about_menu]
70
+
71
+ @prompted[:with_help_text] = dialog(@@titles[:about]) do |d|
72
+ d.click '_OK'
73
+ end
74
+ end
75
+
76
+ # [:undo, :cut, :copy, :paste, :find_next].each do |method|
77
+ # item = method.to_s.split('_').collect {|m| m.capitalize}.join(' ')
78
+ # define_method(method) {menu 'Edit', item, :wait} #(7)
79
+ # end
80
+
81
+ def has_prompted?(kind)
82
+ @prompted[kind]
83
+ end
84
+
85
+ def self.fixture(name)
86
+ source = @@app.path_to(name + 'Fixture')
87
+ target = @@app.path_to(name)
88
+
89
+ File.delete target if File.exists? target
90
+ File.copy source, target
91
+ end
92
+
93
+ private
94
+
95
+ def enter_filename(path)
96
+ dialog(@@titles[:file]) do |d| #(8)
97
+ d.type_in path
98
+ d.click '_Save'
99
+ end
100
+ end
101
+
102
+ def unlock_password(with_options = {})
103
+ options = DefaultOptions.merge with_options
104
+ options[:confirmation] = false #(9)
105
+
106
+ enter_password options
107
+ watch_for_error
108
+ end
109
+
110
+ def assign_password(with_options = {})
111
+ options = DefaultOptions.merge with_options
112
+
113
+ enter_password options
114
+ watch_for_error
115
+
116
+ if @prompted[:with_error]
117
+ enter_password :cancel_password => true #(10)
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,175 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ require 'spec_helper'
10
+
11
+ describe 'The main window' do
12
+ it_should_behave_like 'a new document'
13
+
14
+ it 'launches with a welcome message' do
15
+ @note.text.should include('Welcome')
16
+ end
17
+
18
+ it 'exits without a prompt if nothing has changed' do
19
+ @note.exit!
20
+ @note.should_not have_prompted(:to_confirm_exit)
21
+ end
22
+
23
+ it 'prompts before exiting if the document has changed' do
24
+ @note.text = 'changed'
25
+ @note.exit!
26
+ @note.should have_prompted(:to_confirm_exit)
27
+ end
28
+
29
+ it 'offers information about the program' do
30
+ @note.about
31
+ @note.should have_prompted(:with_help_text)
32
+ end
33
+ end
34
+
35
+ describe 'Saving a document for the first time' do
36
+ it_should_behave_like 'a new document'
37
+
38
+ it 'requires a password' do
39
+ @note.save_as 'MyNote'
40
+ @note.should have_prompted(:for_password)
41
+ end
42
+ end
43
+
44
+ describe 'The password assignment prompt' do
45
+ it_should_behave_like 'a new document'
46
+
47
+ it 'ignores the new password if cancelled' do
48
+ @note.text = 'changed'
49
+ @note.save_as 'MyNote', :cancel_password => true
50
+ @note.exit!
51
+ @note.should have_prompted(:to_confirm_exit)
52
+ end
53
+
54
+ it 'ignores an unconfirmed password' do
55
+ @note.text = 'changed'
56
+ @note.save_as 'SavedNote', :confirmation => 'mismatch'
57
+ @note.should have_prompted(:with_error)
58
+ @note.exit!
59
+ @note.should have_prompted(:to_confirm_exit)
60
+ end
61
+ end
62
+
63
+ describe 'The password entry prompt' do
64
+ it_should_behave_like 'a saved document'
65
+
66
+ it 'ignores the password if cancelled' do
67
+ note = Note.open 'SavedNote', :cancel_password => true
68
+ note.should_not be_running
69
+ end
70
+
71
+ it 'exits with an error message for an invalid password' do
72
+ note = Note.open 'SavedNote', :password => 'invalid'
73
+ note.should_not be_running
74
+ note.should have_prompted(:with_error)
75
+ end
76
+ end
77
+
78
+ describe 'A previously saved document' do
79
+ it_should_behave_like 'a saved document'
80
+ it_should_behave_like 'a reopened document'
81
+
82
+ it 'preserves and encrypts the contents of the file' do
83
+ @note.text.should include('Welcome')
84
+ IO.read(@note.path).should_not include('Welcome')
85
+ end
86
+
87
+ it 'does not require a password on subsequent saves' do
88
+ @note.text = 'changed'
89
+ @note.exit! :save_as => 'MyNote'
90
+ @note.should_not have_prompted(:for_password)
91
+ end
92
+
93
+ it 'supports changing the password' do
94
+ @note.change_password \
95
+ :old_password => 'password',
96
+ :password => 'new'
97
+ @note.exit!
98
+
99
+ @note = Note.open 'SavedNote', :password => 'new'
100
+ @note.should_not have_prompted(:with_error)
101
+ @note.should be_running
102
+ end
103
+ end
104
+
105
+ describe 'The editor' do
106
+ it_should_behave_like 'a new document'
107
+
108
+ it 'supports multiple levels of undo' do
109
+ @note.text = 'abc'
110
+
111
+ @note.undo
112
+ @note.text.should == 'ab'
113
+
114
+ @note.undo
115
+ @note.text.should == 'a'
116
+ end
117
+
118
+ it 'supports copying and pasting text' do
119
+ @note.text = 'itchy'
120
+ @note.select_all
121
+ @note.copy
122
+ @note.text.should == 'itchy'
123
+
124
+ @note.text = 'scratchy'
125
+ @note.select_all
126
+ @note.paste
127
+ @note.text.should == 'itchy'
128
+ end
129
+
130
+ it 'supports cutting and pasting text' do
131
+ @note.text = 'pineapple'
132
+ @note.select_all
133
+ @note.cut
134
+ @note.text.should be_empty
135
+
136
+ @note.text = 'mango'
137
+ @note.select_all
138
+ @note.paste
139
+ @note.text.should == 'pineapple'
140
+ end
141
+ end
142
+
143
+ describe 'The Find window' do
144
+ it_should_behave_like 'a new document'
145
+ it_should_behave_like 'a searchable document'
146
+
147
+ it 'supports searching forward' do
148
+ @note.go_to :beginning
149
+ @note.find @term
150
+ @note.selection.begin.should == @first_match
151
+
152
+ @note.find_next
153
+ @note.selection.begin.should == @second_match
154
+ end
155
+
156
+ it 'supports searching backward' do
157
+ @note.go_to :end
158
+ @note.find @term, :direction => :back
159
+ @note.selection.begin.should == @reverse_match
160
+ end
161
+
162
+ it 'can restrict its search to whole words' do
163
+ pending 'on hold' do
164
+ @note.go_to :beginning
165
+ @note.find @term, :whole_word => true
166
+ @note.selection.begin.should == @word_match
167
+ end
168
+ end
169
+
170
+ it 'can restrict its search to exact case matches' do
171
+ @note.go_to :beginning
172
+ @note.find @term, :exact_case => true
173
+ @note.selection.begin.should == @case_match
174
+ end
175
+ end
@@ -0,0 +1,21 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ require 'LockNote'
10
+
11
+ EditControl = LockNote::EditControl
12
+
13
+ Note.open.instance_eval do
14
+ menu 'Edit', 'Select All'
15
+ type_in 'asggzwhcbgk'
16
+ keystroke 17, 90; sleep 0.5
17
+ @main_window.click EditControl, :left, [370, 253]
18
+ @main_window.click EditControl, :left, [370, 253]
19
+ @main_window.click EditControl, :left, [644, 255]
20
+ # ...
21
+ end
@@ -0,0 +1,9 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ $seed = 12345