cutest 1.0.0.beta → 1.0.0.beta1
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/README.markdown +25 -30
- data/bin/cutest +20 -8
- data/cutest.gemspec +2 -2
- data/lib/cutest.rb +69 -71
- data/test/assert_equal.rb +9 -0
- data/test/setup.rb +1 -1
- metadata +4 -3
data/README.markdown
CHANGED
@@ -6,12 +6,9 @@ Forking tests.
|
|
6
6
|
Description
|
7
7
|
-----------
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
file, you get a debugger and the ability to fix the error in place. If you
|
13
|
-
choose to quit the debugger, the rest of the file is skipped. This way, doing
|
14
|
-
TDD is easier and running your test suite feels faster.
|
9
|
+
Each test file is run in a forked process to avoid shared state. Once a failure
|
10
|
+
is found, you get a report detailing what failed and how to locate the error
|
11
|
+
and the rest of the file is skipped.
|
15
12
|
|
16
13
|
You can use the `scope` command around tests: it guarantees that no instance
|
17
14
|
variables are shared between tests.
|
@@ -35,12 +32,11 @@ block as a parameter to the `test` blocks.
|
|
35
32
|
The `test` method executes the passed block after running `prepare` and
|
36
33
|
`setup`. This is where assertions must be declared.
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
the
|
42
|
-
exception is raised
|
43
|
-
match the expectation.
|
35
|
+
Three assertions are available: `assert`, that accepts a value and raises
|
36
|
+
if it's false or nil; `assert_equal`, that raises if its arguments are not
|
37
|
+
equal; and `assert_raise`, that executes a passed block and compares the raised
|
38
|
+
exception to the expected one. In all cases, if the expectation is no met, an
|
39
|
+
`AssertionFailed` exception is raised.
|
44
40
|
|
45
41
|
Usage
|
46
42
|
-----
|
@@ -115,24 +111,23 @@ running them.
|
|
115
111
|
Handling errors
|
116
112
|
---------------
|
117
113
|
|
118
|
-
If you get an error when running the tests, you will see
|
119
|
-
|
120
|
-
Exception:
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
you fix the code and save it, the debugger will reload it and retry.
|
114
|
+
If you get an error when running the tests, this is what you will see:
|
115
|
+
|
116
|
+
Exception: assert_equal 24, params[:a] # 24 != 23
|
117
|
+
test/setup.rb +14
|
118
|
+
|
119
|
+
Command Line Interface
|
120
|
+
----------------------
|
121
|
+
|
122
|
+
The tool `cutest` accepts a list of files and sends them to `Cutest.run`. If
|
123
|
+
you need to require a file or library before running the tests, as is the case
|
124
|
+
with test helpers, use the `-r` flag:
|
125
|
+
|
126
|
+
$ cutest -r test/helper.rb test/*_test.rb
|
127
|
+
|
128
|
+
If you want to check which version you are running, try the `-v` flag.
|
129
|
+
|
130
|
+
If you want to require ruby-debug, use the `--debug` flag.
|
136
131
|
|
137
132
|
Installation
|
138
133
|
------------
|
data/bin/cutest
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require File.expand_path("../lib/cutest", File.dirname(__FILE__))
|
4
4
|
|
5
5
|
if ARGV.empty?
|
6
|
-
puts "usage: cutest [-r lib] [-v] file ..."
|
6
|
+
puts "usage: cutest [-r lib] [-v] [--debug] file ..."
|
7
7
|
exit
|
8
8
|
end
|
9
9
|
|
@@ -13,7 +13,7 @@ class Cutest
|
|
13
13
|
# http://github.com/soveran/clap
|
14
14
|
# http://rubygems.org/gems/clap
|
15
15
|
class Clap
|
16
|
-
VERSION = "0.0.
|
16
|
+
VERSION = "0.0.2"
|
17
17
|
|
18
18
|
attr :argv
|
19
19
|
attr :opts
|
@@ -23,7 +23,7 @@ class Cutest
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def initialize(argv, opts)
|
26
|
-
@argv = argv.
|
26
|
+
@argv = argv.dup
|
27
27
|
@opts = opts
|
28
28
|
end
|
29
29
|
|
@@ -31,13 +31,24 @@ class Cutest
|
|
31
31
|
args = []
|
32
32
|
|
33
33
|
while argv.any?
|
34
|
-
item = argv.pop
|
35
34
|
|
36
|
-
|
35
|
+
item = argv.shift
|
36
|
+
flag = opts[item]
|
37
|
+
|
38
|
+
if flag
|
39
|
+
|
40
|
+
# Work around lambda semantics in 1.8.7.
|
41
|
+
arity = [flag.arity, 0].max
|
42
|
+
|
43
|
+
# Raise if there are not enough parameters
|
44
|
+
# available for the flag.
|
45
|
+
if argv.size < arity
|
46
|
+
raise ArgumentError
|
47
|
+
end
|
37
48
|
|
38
49
|
# Call the lambda with N items from argv,
|
39
50
|
# where N is the lambda's arity.
|
40
|
-
|
51
|
+
flag.call(*argv.shift(arity))
|
41
52
|
else
|
42
53
|
|
43
54
|
# Collect the items that don't correspond to
|
@@ -52,7 +63,8 @@ class Cutest
|
|
52
63
|
end
|
53
64
|
|
54
65
|
files = Cutest::Clap.run ARGV,
|
55
|
-
"-r"
|
56
|
-
"-v"
|
66
|
+
"-r" => lambda { |file| require file },
|
67
|
+
"-v" => lambda { puts Cutest::VERSION },
|
68
|
+
"--debug" => lambda { ENV["DEBUG"] = true }
|
57
69
|
|
58
70
|
Cutest.run(Dir[*files]) if files.any?
|
data/cutest.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "cutest"
|
3
|
-
s.version = "1.0.0.
|
3
|
+
s.version = "1.0.0.beta1"
|
4
4
|
s.summary = "Forking tests."
|
5
5
|
s.description = "Run tests in separate processes to avoid shared state."
|
6
6
|
s.authors = ["Damian Janowski", "Michel Martens"]
|
7
7
|
s.email = ["djanowski@dimaion.com", "michel@soveran.com"]
|
8
8
|
s.homepage = "http://github.com/djanowski/cutest"
|
9
|
-
s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/cutest.rb", "cutest.gemspec", "test/assert.rb", "test/assert_raise.rb", "test/prepare.rb", "test/run.rb", "test/scopes.rb", "test/setup.rb"]
|
9
|
+
s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/cutest.rb", "cutest.gemspec", "test/assert.rb", "test/assert_equal.rb", "test/assert_raise.rb", "test/prepare.rb", "test/run.rb", "test/scopes.rb", "test/setup.rb"]
|
10
10
|
s.executables.push "cutest"
|
11
11
|
end
|
data/lib/cutest.rb
CHANGED
@@ -1,59 +1,56 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
rescue LoadError
|
4
|
-
puts "Cutest needs ruby-debug, but it couldn't be required."
|
5
|
-
puts "Please install ruby-debug or ruby-debug19 and try again."
|
6
|
-
exit
|
7
|
-
end
|
1
|
+
class Cutest
|
2
|
+
VERSION = "1.0.0.beta1"
|
8
3
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
if ENV["DEBUG"]
|
5
|
+
begin
|
6
|
+
require "ruby-debug"
|
7
|
+
rescue LoadError
|
8
|
+
puts "Cutest needs ruby-debug, but it couldn't be required."
|
9
|
+
puts "Please install ruby-debug or ruby-debug19 and try again."
|
10
|
+
exit
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
|
13
|
+
Debugger.settings[:autoeval] = 1
|
14
|
+
Debugger.settings[:autolist] = 1
|
15
|
+
Debugger.settings[:listsize] = 5
|
16
|
+
Debugger.settings[:reload_source_on_change] = 1
|
17
|
+
end
|
16
18
|
|
17
19
|
def self.run(files)
|
18
|
-
trap("INT") { exit }
|
19
|
-
trap("TERM") { exit }
|
20
|
-
|
21
20
|
files.each do |file|
|
22
|
-
|
21
|
+
stdin, stdout = IO.pipe
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
fork do
|
24
|
+
stdin.close
|
26
25
|
|
27
|
-
|
28
|
-
|
26
|
+
begin
|
27
|
+
load(file)
|
29
28
|
|
30
|
-
|
31
|
-
|
29
|
+
rescue LoadError, SyntaxError
|
30
|
+
puts ["\n", error([file, $!.message])]
|
31
|
+
exit
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
rescue Exception
|
34
|
+
fn, ln = $!.backtrace.first.split(":")
|
35
|
+
message = File.readlines(fn)[ln.to_i - 1]
|
36
|
+
stdout.write("#{fn}\n#{ln}\n#{error(message.strip)} # #{$!.message}")
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
stdout.write("#{fn}\n#{ln}\n#{error($!)}\n#{hint}")
|
40
|
-
end
|
41
|
-
end
|
39
|
+
stdout.close
|
40
|
+
end
|
42
41
|
|
43
|
-
|
42
|
+
stdout.close
|
44
43
|
|
45
|
-
|
44
|
+
Process.wait
|
46
45
|
|
47
|
-
|
46
|
+
output = stdin.read
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
48
|
+
stdin.close
|
49
|
+
|
50
|
+
unless output.empty?
|
51
|
+
fn, ln, error = output.split("\n")
|
52
|
+
|
53
|
+
puts "\n#{error}\n#{fn} +#{ln}"
|
57
54
|
end
|
58
55
|
end
|
59
56
|
|
@@ -64,11 +61,6 @@ class Cutest
|
|
64
61
|
"\033[01;36mException: \033[01;33m#{e}\033[00m"
|
65
62
|
end
|
66
63
|
|
67
|
-
def self.hint
|
68
|
-
"\033[01;36mType \033[0;33mcontinue\033[0;36m to retry " +
|
69
|
-
"or \033[0;33medit\033[0;36m to modify the source\033[00m"
|
70
|
-
end
|
71
|
-
|
72
64
|
class AssertionFailed < StandardError
|
73
65
|
end
|
74
66
|
|
@@ -86,8 +78,8 @@ end
|
|
86
78
|
module Kernel
|
87
79
|
private
|
88
80
|
|
89
|
-
# Use Thread.current[:cutest] to store information about test preparation
|
90
|
-
# setup.
|
81
|
+
# Use Thread.current[:cutest] to store information about test preparation
|
82
|
+
# and setup.
|
91
83
|
Thread.current[:cutest] ||= { :prepare => [] }
|
92
84
|
|
93
85
|
# Shortcut to access Thread.current[:cutest].
|
@@ -101,31 +93,31 @@ private
|
|
101
93
|
Cutest::Scope.new(&block).call
|
102
94
|
end
|
103
95
|
|
104
|
-
# Prepare the environment in order to run the tests. This method can be
|
105
|
-
# many times, and each new block is appended to a list of
|
106
|
-
# When a test is executed, all the preparation blocks
|
107
|
-
# were declared. If called without a block, it
|
108
|
-
# blocks.
|
96
|
+
# Prepare the environment in order to run the tests. This method can be
|
97
|
+
# called many times, and each new block is appended to a list of
|
98
|
+
# preparation blocks. When a test is executed, all the preparation blocks
|
99
|
+
# are ran in the order they were declared. If called without a block, it
|
100
|
+
# returns the array of preparation blocks.
|
109
101
|
def prepare(&block)
|
110
102
|
cutest[:prepare] << block if block_given?
|
111
103
|
cutest[:prepare]
|
112
104
|
end
|
113
105
|
|
114
|
-
# Setup parameters for the tests. The block passed to setup is evaluated
|
115
|
-
# running each test, and the result of the setup block is passed to
|
116
|
-
# a parameter. If the setup and the tests are declared at the
|
117
|
-
# the global scope or in a sub scope), it is possible to use
|
118
|
-
# variables, but the parameter passing pattern is recommended to
|
119
|
-
# are no side effects.
|
106
|
+
# Setup parameters for the tests. The block passed to setup is evaluated
|
107
|
+
# before running each test, and the result of the setup block is passed to
|
108
|
+
# the test as a parameter. If the setup and the tests are declared at the
|
109
|
+
# same level (in the global scope or in a sub scope), it is possible to use
|
110
|
+
# instance variables, but the parameter passing pattern is recommended to
|
111
|
+
# ensure there are no side effects.
|
120
112
|
#
|
121
113
|
# If the setup blocks are declared in the global scope and the tests are
|
122
114
|
# declared in sub scopes, the parameter passing usage is required.
|
123
115
|
#
|
124
|
-
# Setup blocks can be defined many times, but each new definition overrides
|
125
|
-
# previous one. It is recommended to split the tests in many different
|
126
|
-
# (the report is per file, not per assertion). Usually one setup
|
127
|
-
# is enough, but nothing forbids having different scopes
|
128
|
-
# blocks.
|
116
|
+
# Setup blocks can be defined many times, but each new definition overrides
|
117
|
+
# the previous one. It is recommended to split the tests in many different
|
118
|
+
# files (the report is per file, not per assertion). Usually one setup
|
119
|
+
# block per file is enough, but nothing forbids having different scopes
|
120
|
+
# with different setup blocks.
|
129
121
|
def setup(&block)
|
130
122
|
cutest[:setup] = block if block_given?
|
131
123
|
cutest[:setup]
|
@@ -136,8 +128,8 @@ private
|
|
136
128
|
|
137
129
|
# Call the prepare and setup blocks before executing the test. Even
|
138
130
|
# though the assertions can live anywhere (it's not mandatory to put them
|
139
|
-
# inside test blocks), it is necessary to wrap them in test blocks in order
|
140
|
-
# execute preparation and setup blocks.
|
131
|
+
# inside test blocks), it is necessary to wrap them in test blocks in order
|
132
|
+
# to execute preparation and setup blocks.
|
141
133
|
def test(name = nil, &block)
|
142
134
|
cutest[:test] = name
|
143
135
|
|
@@ -147,7 +139,13 @@ private
|
|
147
139
|
|
148
140
|
# Assert that value is not nil or false.
|
149
141
|
def assert(value)
|
150
|
-
flunk unless value
|
142
|
+
flunk("assertion failed") unless value
|
143
|
+
print "."
|
144
|
+
end
|
145
|
+
|
146
|
+
# Assert that two values are equal.
|
147
|
+
def assert_equal(value, other)
|
148
|
+
flunk("#{value} != #{other}") unless value == other
|
151
149
|
print "."
|
152
150
|
end
|
153
151
|
|
@@ -157,15 +155,15 @@ private
|
|
157
155
|
yield
|
158
156
|
rescue => exception
|
159
157
|
ensure
|
160
|
-
flunk unless exception.kind_of?(expected)
|
158
|
+
flunk("got #{exception} instead") unless exception.kind_of?(expected)
|
161
159
|
print "."
|
162
160
|
end
|
163
161
|
end
|
164
162
|
|
165
163
|
# Stop the tests and raise an error where the message is the last line
|
166
164
|
# executed before flunking.
|
167
|
-
def flunk
|
168
|
-
exception = Cutest::AssertionFailed.new
|
165
|
+
def flunk(message = nil)
|
166
|
+
exception = Cutest::AssertionFailed.new(message)
|
169
167
|
exception.set_backtrace([caller[1]])
|
170
168
|
|
171
169
|
raise exception
|
data/test/setup.rb
CHANGED
metadata
CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
- 1
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.0.
|
9
|
+
- beta1
|
10
|
+
version: 1.0.0.beta1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Damian Janowski
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-30 00:00:00 -03:00
|
20
20
|
default_executable:
|
21
21
|
dependencies: []
|
22
22
|
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- lib/cutest.rb
|
38
38
|
- cutest.gemspec
|
39
39
|
- test/assert.rb
|
40
|
+
- test/assert_equal.rb
|
40
41
|
- test/assert_raise.rb
|
41
42
|
- test/prepare.rb
|
42
43
|
- test/run.rb
|