win32-autogui 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitattributes +1 -0
- data/.gitignore +10 -0
- data/.yardopts +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +60 -0
- data/HISTORY.markdown +11 -0
- data/LICENSE +20 -0
- data/README.markdown +265 -0
- data/Rakefile +55 -0
- data/TODO.markdown +9 -0
- data/VERSION +1 -0
- data/config/cucumber.yml +7 -0
- data/examples/quicknote/.gitignore +8 -0
- data/examples/quicknote/FormAboutU.dfm +44 -0
- data/examples/quicknote/FormAboutU.pas +36 -0
- data/examples/quicknote/FormMainU.dfm +110 -0
- data/examples/quicknote/FormMainU.pas +268 -0
- data/examples/quicknote/FormSplashU.dfm +32 -0
- data/examples/quicknote/FormSplashU.pas +52 -0
- data/examples/quicknote/LICENSE +20 -0
- data/examples/quicknote/README.markdown +28 -0
- data/examples/quicknote/Rakefile +12 -0
- data/examples/quicknote/TODO.markdown +15 -0
- data/examples/quicknote/dcu/.gitignore +1 -0
- data/examples/quicknote/exe/.gitignore +0 -0
- data/examples/quicknote/exe/quicknote.exe +0 -0
- data/examples/quicknote/lib/quicknote.rb +140 -0
- data/examples/quicknote/quicknote.cfg +37 -0
- data/examples/quicknote/quicknote.dof +158 -0
- data/examples/quicknote/quicknote.dpr +16 -0
- data/examples/quicknote/quicknote.res +0 -0
- data/examples/quicknote/spec/quicknote/form_about_spec.rb +50 -0
- data/examples/quicknote/spec/quicknote/form_main_spec.rb +274 -0
- data/examples/quicknote/spec/quicknote/form_splash_spec.rb +44 -0
- data/examples/quicknote/spec/spec.opts +2 -0
- data/examples/quicknote/spec/spec_helper.rb +34 -0
- data/examples/quicknote/spec/watchr.rb +143 -0
- data/examples/skeleton/.gitignore +8 -0
- data/examples/skeleton/LICENSE +20 -0
- data/examples/skeleton/README.markdown +62 -0
- data/examples/skeleton/Rakefile +21 -0
- data/examples/skeleton/TODO.markdown +9 -0
- data/examples/skeleton/config/cucumber.yml +7 -0
- data/examples/skeleton/dcu/.gitignore +1 -0
- data/examples/skeleton/exe/.gitignore +1 -0
- data/examples/skeleton/features/basic.feature +6 -0
- data/examples/skeleton/features/step_definitions/.gitignore +0 -0
- data/examples/skeleton/features/step_definitions/application_steps.rb +43 -0
- data/examples/skeleton/features/support/env.rb +5 -0
- data/examples/skeleton/lib/myapp.rb +73 -0
- data/examples/skeleton/spec/myapp/form_about_spec.rb +50 -0
- data/examples/skeleton/spec/myapp/form_main_spec.rb +60 -0
- data/examples/skeleton/spec/spec.opts +2 -0
- data/examples/skeleton/spec/spec_helper.rb +29 -0
- data/examples/skeleton/spec/watchr.rb +143 -0
- data/features/automating_an_application.feature +11 -0
- data/features/step_definitions/.gitignore +0 -0
- data/features/step_definitions/calculator_steps.rb +37 -0
- data/features/support/env.rb +4 -0
- data/lib/win32/autogui.rb +27 -0
- data/lib/win32/autogui/application.rb +249 -0
- data/lib/win32/autogui/input.rb +238 -0
- data/lib/win32/autogui/window.rb +191 -0
- data/lib/win32/autogui/windows/window.rb +22 -0
- data/spec/applications/calculator.rb +34 -0
- data/spec/auto_gui/application_spec.rb +132 -0
- data/spec/basic_gem/basic_gem_spec.rb +13 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/watchr.rb +144 -0
- data/win32-autogui.gemspec +43 -0
- metadata +329 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'windows/window'
|
2
|
+
require 'windows/window/message'
|
3
|
+
require 'win32/autogui/windows/window'
|
4
|
+
|
5
|
+
module Autogui
|
6
|
+
|
7
|
+
# Enumerate desktop child windows
|
8
|
+
#
|
9
|
+
# Start at the desktop and work down through all the child windows
|
10
|
+
#
|
11
|
+
class EnumerateDesktopWindows
|
12
|
+
include Enumerable
|
13
|
+
include Windows::Window
|
14
|
+
|
15
|
+
def each
|
16
|
+
child_after = 0
|
17
|
+
while (child_after = FindWindowEx(nil, child_after, nil, nil)) > 0 do
|
18
|
+
yield Window.new child_after
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Enumerate just the child windows one level down from the parent window
|
24
|
+
#
|
25
|
+
class Children
|
26
|
+
include Enumerable
|
27
|
+
include Windows::Window
|
28
|
+
|
29
|
+
# @param [Number] parent window handle
|
30
|
+
#
|
31
|
+
def initialize(parent)
|
32
|
+
@parent = parent
|
33
|
+
end
|
34
|
+
|
35
|
+
# @yield [Window]
|
36
|
+
#
|
37
|
+
def each
|
38
|
+
child_after = 0
|
39
|
+
while (child_after = FindWindowEx(@parent.handle, child_after, nil, nil)) > 0 do
|
40
|
+
window = Window.new child_after
|
41
|
+
# immediate children only
|
42
|
+
yield window if (window.parent.handle == @parent.handle)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Wrapper for window
|
48
|
+
#
|
49
|
+
class Window
|
50
|
+
include Windows::Window # instance methods from windows-pr gem
|
51
|
+
include Windows::Window::Message # PostMessage and constants
|
52
|
+
|
53
|
+
attr_reader :handle
|
54
|
+
|
55
|
+
def initialize(handle)
|
56
|
+
@handle = handle
|
57
|
+
end
|
58
|
+
|
59
|
+
# enumerable immeadiate child windows
|
60
|
+
#
|
61
|
+
# @see Children
|
62
|
+
#
|
63
|
+
def children
|
64
|
+
Children.new(self)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Object] Window or nil
|
68
|
+
#
|
69
|
+
def parent
|
70
|
+
h = GetParent(handle)
|
71
|
+
Window.new h if h > 0
|
72
|
+
end
|
73
|
+
|
74
|
+
# PostMessage SC_CLOSE and optionally wait for the window to close
|
75
|
+
#
|
76
|
+
# @param [Hash] options
|
77
|
+
# @option options [Boolean] :wait_for_close (true) sleep while waiting for timeout or close
|
78
|
+
# @option options [Boolean] :timeout (5) wait_for_close timeout in seconds
|
79
|
+
#
|
80
|
+
def close(options={})
|
81
|
+
PostMessage(handle, WM_SYSCOMMAND, SC_CLOSE, 0)
|
82
|
+
wait_for_close(options) if (options[:wait_for_close] == true)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Wait for the window to close
|
86
|
+
#
|
87
|
+
# @param [Hash] options
|
88
|
+
# @option options [Boolean] :timeout (5) timeout in seconds
|
89
|
+
#
|
90
|
+
def wait_for_close(options={})
|
91
|
+
seconds = options[:timeout] || 5
|
92
|
+
timeout(seconds) do
|
93
|
+
sleep 0.05 until 0 == IsWindow(handle)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [String] the ANSI Windows ClassName
|
98
|
+
#
|
99
|
+
def window_class
|
100
|
+
buffer = "\0" * 255
|
101
|
+
length = GetClassNameA(handle, buffer, buffer.length)
|
102
|
+
length == 0 ? '' : buffer[0..length - 1]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Window text (WM_GETTEXT)
|
106
|
+
#
|
107
|
+
# @param [Number] max_length (2048)
|
108
|
+
#
|
109
|
+
# @return [String] of max_length (2048)
|
110
|
+
#
|
111
|
+
def text(max_length = 2048)
|
112
|
+
buffer = "\0" * max_length
|
113
|
+
length = SendMessageA(handle, WM_GETTEXT, buffer.length, buffer)
|
114
|
+
length == 0 ? '' : buffer[0..length - 1]
|
115
|
+
end
|
116
|
+
alias :title :text
|
117
|
+
|
118
|
+
# Determines whether the specified window handle identifies an existing window
|
119
|
+
#
|
120
|
+
# @return [Boolean]
|
121
|
+
#
|
122
|
+
def is_window?
|
123
|
+
(handle != 0) && (IsWindow(handle) != 0)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Brings the window into the foreground and activates it.
|
127
|
+
# Keyboard input is directed to the window, and various visual cues
|
128
|
+
# are changed for the user.
|
129
|
+
#
|
130
|
+
# @return [Number] nonzero number if sucessful, nil or zero if failed
|
131
|
+
#
|
132
|
+
def set_focus
|
133
|
+
SetForegroundWindow(handle) if is_window?
|
134
|
+
end
|
135
|
+
|
136
|
+
# The identifier (pid) of the process that created the window
|
137
|
+
#
|
138
|
+
# @return [Integer] process id if the window exists, otherwise nil
|
139
|
+
#
|
140
|
+
def pid
|
141
|
+
return nil unless is_window?
|
142
|
+
process_id = 0.chr * 4
|
143
|
+
GetWindowThreadProcessId(handle, process_id)
|
144
|
+
process_id = process_id.unpack('L').first
|
145
|
+
end
|
146
|
+
|
147
|
+
# The identifier of the thread that created the window
|
148
|
+
#
|
149
|
+
# @return [Integer] thread id if the window exists, otherwise nil
|
150
|
+
#
|
151
|
+
def thread_id
|
152
|
+
return nil unless is_window?
|
153
|
+
GetWindowThreadProcessId(handle, nil)
|
154
|
+
end
|
155
|
+
|
156
|
+
# The window text including all child windows
|
157
|
+
# joined together with newlines. Faciliates matching text.
|
158
|
+
# Text from any given window is limited to 2048 characters
|
159
|
+
#
|
160
|
+
# @example partial match of the Window's calulator's about dialog copywrite text
|
161
|
+
#
|
162
|
+
# dialog_about = @calculator.dialog_about
|
163
|
+
# dialog_about.title.should == "About Calculator"
|
164
|
+
# dialog_about.combined_text.should match(/Microsoft . Calculator/)
|
165
|
+
#
|
166
|
+
# @return [String] with newlines
|
167
|
+
#
|
168
|
+
def combined_text
|
169
|
+
return unless is_window?
|
170
|
+
t = []
|
171
|
+
t << text unless text == ''
|
172
|
+
children.each do |w|
|
173
|
+
t << w.combined_text unless w.combined_text == ''
|
174
|
+
end
|
175
|
+
t.join("\n")
|
176
|
+
end
|
177
|
+
|
178
|
+
# Debugging information
|
179
|
+
#
|
180
|
+
# @return [String] with child window information
|
181
|
+
def inspect
|
182
|
+
c = []
|
183
|
+
children.each do |w|
|
184
|
+
c << w.inspect
|
185
|
+
end
|
186
|
+
s = super + " #{self.class}=<window_class:#{window_class} pid:#{pid} thread_id:#{thread_id} title:\"#{title}\" children=<" + c.join("\n") + ">>"
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Reopen module and supply missing constants and
|
2
|
+
# functions from windows-pr gem
|
3
|
+
#
|
4
|
+
# TODO: Fork and send pull request for Windows::Window module, be sure to lock bundle before sending request
|
5
|
+
#
|
6
|
+
module Windows
|
7
|
+
module Window
|
8
|
+
|
9
|
+
SC_CLOSE = 0xF060
|
10
|
+
|
11
|
+
API.auto_namespace = 'Windows::Window'
|
12
|
+
API.auto_constant = true
|
13
|
+
API.auto_method = true
|
14
|
+
API.auto_unicode = false
|
15
|
+
|
16
|
+
API.new('IsWindow', 'L', 'I', 'user32')
|
17
|
+
API.new('SetForegroundWindow', 'L', 'I', 'user32')
|
18
|
+
API.new('SendMessageA', 'LIIP', 'I', 'user32')
|
19
|
+
API.new('GetClassNameA', 'LPI', 'I', 'user32')
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class Calculator < Autogui::Application
|
4
|
+
|
5
|
+
# initialize with the binary name 'calc' and the window title
|
6
|
+
# 'Calculator' used along with the application pid to find the
|
7
|
+
# main application window
|
8
|
+
def initialize(options = {})
|
9
|
+
defaults = {
|
10
|
+
:name => "calc",
|
11
|
+
:title => "Calculator"
|
12
|
+
}
|
13
|
+
super defaults.merge(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
# the calculator's results window
|
17
|
+
def edit_window
|
18
|
+
main_window.children.find {|w| w.window_class == 'Edit'}
|
19
|
+
end
|
20
|
+
|
21
|
+
# About dialog, hotkey (VK_MENU, VK_H, VK_A)
|
22
|
+
def dialog_about
|
23
|
+
Autogui::EnumerateDesktopWindows.new.find do |w|
|
24
|
+
w.title.match(/About Calculator/) && (w.pid == pid)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# the 'CE' button
|
29
|
+
def clear_entry
|
30
|
+
set_focus
|
31
|
+
keystroke(VK_DELETE)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
include Autogui::Input
|
4
|
+
|
5
|
+
describe Autogui::Application do
|
6
|
+
|
7
|
+
describe "driving calc.exe" do
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
@calculator = Calculator.new
|
11
|
+
@calculator.set_focus
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:all) do
|
15
|
+
@calculator.close(:wait_for_close => true) if @calculator.running?
|
16
|
+
@calculator.should_not be_running
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should start when initialized" do
|
20
|
+
@calculator.should be_running
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should die when sending the kill signal" do
|
24
|
+
killme = Calculator.new
|
25
|
+
killme.should be_running
|
26
|
+
killme.kill
|
27
|
+
killme.should_not be_running
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have the title 'Calculator' that matches the main_window title" do
|
31
|
+
@calculator.main_window.title.should == 'Calculator'
|
32
|
+
@calculator.main_window.title.should == @calculator.title
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should have an inspect method showing child window information" do
|
36
|
+
@calculator.inspect.should match(/children=</)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an error if setting focus and the application title is incorrect" do
|
40
|
+
goodcalc = Calculator.new :title => "Calculator"
|
41
|
+
lambda { goodcalc.set_focus }.should_not raise_error
|
42
|
+
goodcalc.close
|
43
|
+
|
44
|
+
badcalc = Calculator.new :title => "BaDTitle"
|
45
|
+
lambda {
|
46
|
+
begin
|
47
|
+
badcalc.setfocus
|
48
|
+
ensure
|
49
|
+
badcalc.kill
|
50
|
+
end
|
51
|
+
}.should raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should control the focus with 'set_focus'" do
|
55
|
+
@calculator.set_focus
|
56
|
+
keystroke(VK_9)
|
57
|
+
@calculator.edit_window.text.strip.should == "9."
|
58
|
+
|
59
|
+
calculator2 = Calculator.new
|
60
|
+
calculator2.pid.should_not == @calculator.pid
|
61
|
+
calculator2.set_focus
|
62
|
+
keystroke(VK_1, VK_0)
|
63
|
+
calculator2.edit_window.text.strip.should == "10."
|
64
|
+
|
65
|
+
@calculator.set_focus
|
66
|
+
@calculator.edit_window.text.strip.should == "9."
|
67
|
+
|
68
|
+
calculator2.close(:wait_for_close => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should open and close the 'About Calculator' dialog via (VK_MENU, VK_H, VK_A)" do
|
72
|
+
@calculator.set_focus
|
73
|
+
dialog_about = @calculator.dialog_about
|
74
|
+
dialog_about.should be_nil
|
75
|
+
keystroke(VK_MENU, VK_H, VK_A)
|
76
|
+
dialog_about = @calculator.dialog_about
|
77
|
+
dialog_about.title.should == "About Calculator"
|
78
|
+
dialog_about.combined_text.should match(/Microsoft . Calculator/)
|
79
|
+
dialog_about.close
|
80
|
+
@calculator.dialog_about.should be_nil
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "calculations" do
|
84
|
+
before(:each) do
|
85
|
+
@calculator.clear_entry
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should calculate '2+2=4' using the keystroke method" do
|
89
|
+
@calculator.set_focus
|
90
|
+
keystroke(VK_2, VK_ADD, VK_2, VK_RETURN)
|
91
|
+
@calculator.edit_window.text.strip.should == "4."
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should calculate '2+12=14' using the type_in method" do
|
95
|
+
@calculator.set_focus
|
96
|
+
type_in("2+12=")
|
97
|
+
@calculator.edit_window.text.strip.should == "14."
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "clipboard" do
|
102
|
+
before(:each) do
|
103
|
+
@calculator.clear_entry
|
104
|
+
@calculator.clipboard.text = ""
|
105
|
+
@calculator.clipboard.text.should == ""
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "copy (VK_CONTROL, VK_C)" do
|
109
|
+
it "should copy the edit window" do
|
110
|
+
@calculator.set_focus
|
111
|
+
type_in("3002")
|
112
|
+
@calculator.edit_window.text.strip.should == "3,002."
|
113
|
+
@calculator.edit_window.set_focus
|
114
|
+
keystroke(VK_CONTROL, VK_C)
|
115
|
+
@calculator.clipboard.text.should == "3002"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "paste (VK_CONTROL, VK_V)" do
|
120
|
+
it "should paste into the edit window" do
|
121
|
+
@calculator.edit_window.set_focus
|
122
|
+
@calculator.clipboard.text = "12345"
|
123
|
+
@calculator.edit_window.text.strip.should == "0."
|
124
|
+
keystroke(VK_CONTROL, VK_V)
|
125
|
+
@calculator.edit_window.text.strip.should == "12,345."
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Autogui do
|
4
|
+
|
5
|
+
describe 'version' do
|
6
|
+
|
7
|
+
it "should return a string formatted '#.#.#'" do
|
8
|
+
Autogui::version.should match(/(^[\d]+\.[\d]+\.[\d]+$)/)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('..', __FILE__) unless
|
2
|
+
$LOAD_PATH.include? File.expand_path('..', __FILE__)
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) unless
|
4
|
+
$LOAD_PATH.include? File.expand_path('../../lib', __FILE__)
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'win32/autogui'
|
8
|
+
require 'spec'
|
9
|
+
require 'spec/autorun'
|
10
|
+
require 'aruba/api'
|
11
|
+
|
12
|
+
# applications
|
13
|
+
require File.expand_path(File.dirname(__FILE__) + '/applications/calculator')
|
14
|
+
|
15
|
+
# aruba helper, returns full path to files in the aruba tmp folder
|
16
|
+
def fullpath(filename)
|
17
|
+
path = File.expand_path(File.join(current_dir, filename))
|
18
|
+
path = `cygpath -w #{path}`.chomp if path.match(/^\/cygdrive/) # cygwin?
|
19
|
+
path
|
20
|
+
end
|
21
|
+
|
22
|
+
# return the contents of "filename" in the aruba tmp folder
|
23
|
+
def get_file_content(filename)
|
24
|
+
in_current_dir do
|
25
|
+
IO.read(filename)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Spec::Runner.configure do |config|
|
30
|
+
config.include Aruba::Api
|
31
|
+
end
|
data/spec/watchr.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# Watchr: Autotest like functionality
|
2
|
+
#
|
3
|
+
# gem install watchr
|
4
|
+
#
|
5
|
+
# Run me with:
|
6
|
+
#
|
7
|
+
# $ watchr spec/watchr.rb
|
8
|
+
|
9
|
+
require 'term/ansicolor'
|
10
|
+
|
11
|
+
$c = Term::ANSIColor
|
12
|
+
|
13
|
+
def getch
|
14
|
+
state = `stty -g`
|
15
|
+
begin
|
16
|
+
`stty raw -echo cbreak`
|
17
|
+
$stdin.getc
|
18
|
+
ensure
|
19
|
+
`stty #{state}`
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# --------------------------------------------------
|
24
|
+
# Convenience Methods
|
25
|
+
# --------------------------------------------------
|
26
|
+
def all_feature_files
|
27
|
+
Dir['features/*.feature']
|
28
|
+
end
|
29
|
+
|
30
|
+
def all_spec_files
|
31
|
+
files = Dir['spec/**/*_spec\.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
def run(cmd)
|
35
|
+
|
36
|
+
pid = fork do
|
37
|
+
puts "\n"
|
38
|
+
print $c.cyan, cmd, $c.clear, "\n"
|
39
|
+
exec(cmd)
|
40
|
+
end
|
41
|
+
Signal.trap('INT') do
|
42
|
+
puts "sending KILL to pid: #{pid}"
|
43
|
+
Process.kill("KILL", pid)
|
44
|
+
end
|
45
|
+
Process.waitpid(pid)
|
46
|
+
|
47
|
+
prompt
|
48
|
+
end
|
49
|
+
|
50
|
+
def run_all
|
51
|
+
run_all_specs
|
52
|
+
run_default_cucumber
|
53
|
+
end
|
54
|
+
|
55
|
+
# allow cucumber rerun.txt smarts
|
56
|
+
def run_default_cucumber
|
57
|
+
cmd = "cucumber"
|
58
|
+
run(cmd)
|
59
|
+
end
|
60
|
+
|
61
|
+
def run_all_features
|
62
|
+
cmd = "cucumber #{all_feature_files.join(' ')}"
|
63
|
+
run(cmd)
|
64
|
+
end
|
65
|
+
|
66
|
+
def run_feature(feature)
|
67
|
+
cmd = "cucumber #{feature}"
|
68
|
+
$last_feature = feature
|
69
|
+
run(cmd)
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_last_feature
|
73
|
+
run_feature($last_feature) if $last_feature
|
74
|
+
end
|
75
|
+
|
76
|
+
def run_default_spec
|
77
|
+
cmd = "spec _1.3.1_ --color --format s ./spec"
|
78
|
+
run(cmd)
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_all_specs
|
82
|
+
cmd = "spec _1.3.1_ --color --format s #{all_spec_files.join(' ')}"
|
83
|
+
p cmd
|
84
|
+
run(cmd)
|
85
|
+
end
|
86
|
+
|
87
|
+
def run_spec(spec)
|
88
|
+
cmd = "spec _1.3.1_ --color --format s #{spec}"
|
89
|
+
$last_spec = spec
|
90
|
+
run(cmd)
|
91
|
+
end
|
92
|
+
|
93
|
+
def run_last_spec
|
94
|
+
run_spec($last_spec) if $last_spec
|
95
|
+
end
|
96
|
+
|
97
|
+
def prompt
|
98
|
+
puts "Ctrl-\\ for menu, Ctrl-C to quit"
|
99
|
+
end
|
100
|
+
|
101
|
+
# init
|
102
|
+
$last_feature = nil
|
103
|
+
prompt
|
104
|
+
|
105
|
+
# --------------------------------------------------
|
106
|
+
# Watchr Rules
|
107
|
+
# --------------------------------------------------
|
108
|
+
watch( '^features/(.*)\.feature' ) { run_default_cucumber }
|
109
|
+
|
110
|
+
watch( '^bin/(.*)' ) { run_default_cucumber }
|
111
|
+
watch( '^lib/(.*)' ) { run_default_cucumber }
|
112
|
+
|
113
|
+
watch( '^features/step_definitions/(.*)\.rb' ) { run_default_cucumber }
|
114
|
+
watch( '^features/support/(.*)\.rb' ) { run_default_cucumber }
|
115
|
+
|
116
|
+
watch( '^spec/(.*)_spec\.rb' ) { |m| run_spec(m[0]) }
|
117
|
+
# specify just the lib files that have specs
|
118
|
+
# TODO: This can be determined automatically from the spec file naming convention
|
119
|
+
watch( '^lib/(.*)' ) { run_default_spec }
|
120
|
+
watch( '^spec/applications/(.*)' ) { run_default_spec }
|
121
|
+
|
122
|
+
# --------------------------------------------------
|
123
|
+
# Signal Handling
|
124
|
+
# --------------------------------------------------
|
125
|
+
|
126
|
+
# Ctrl-\
|
127
|
+
Signal.trap('QUIT') do
|
128
|
+
|
129
|
+
puts "\n\nMENU: a = all , f = features s = specs, l = last feature (#{$last_feature ? $last_feature : 'none'}), q = quit\n\n"
|
130
|
+
c = getch
|
131
|
+
puts c.chr
|
132
|
+
if c.chr == "a"
|
133
|
+
run_all
|
134
|
+
elsif c.chr == "f"
|
135
|
+
run_default_cucumber
|
136
|
+
elsif c.chr == "s"
|
137
|
+
run_all_specs
|
138
|
+
elsif c.chr == "q"
|
139
|
+
abort("exiting\n")
|
140
|
+
elsif c.chr == "l"
|
141
|
+
run_last_feature
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|