blackstart 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/LICENSE.txt +19 -0
- data/README.txt +152 -0
- data/blackstart.gemspec +11 -0
- data/lib/blackstart.rb +92 -0
- data/test/blackstart_test.rb +404 -0
- metadata +73 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2024 Aaron Beckerman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.txt
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
Blackstart
|
2
|
+
|
3
|
+
Blackstart is a small, subdued library for automated testing in Ruby. It
|
4
|
+
doesn't depend on anything beyond the Ruby platform and doesn't modify the
|
5
|
+
environment outside its conventional namespace. It's tested with a primitive
|
6
|
+
program, not via an automated-testing library.
|
7
|
+
|
8
|
+
The blackstart is a small, subdued bird that eats bugs. A black start is when a
|
9
|
+
power plant starts up without relying on the electrical grid.
|
10
|
+
|
11
|
+
Here's an example of a test program that uses Blackstart:
|
12
|
+
|
13
|
+
require "blackstart"
|
14
|
+
|
15
|
+
exit Blackstart.run Blackstart.add { |adder|
|
16
|
+
adder.call do
|
17
|
+
unless "Hello, World!" == ["He", "", "o, Wor", "d!"].join("l")
|
18
|
+
raise "join did not work as expected"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
adder.call do
|
23
|
+
unless "sample" == "simple".gsub(/i/, "a")
|
24
|
+
raise "gsub did not work as expected"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
Blackstart.add adds procs to a collection and returns that collection. In the
|
30
|
+
example, each proc is designed to run a test and, if it fails, raise an error
|
31
|
+
to signal this.
|
32
|
+
|
33
|
+
Blackstart.run runs a sequence of tests and reports information about any that
|
34
|
+
fail -- that is, any that raise an error. In the example, failure information
|
35
|
+
would be written to the standard output stream. It returns false if there were
|
36
|
+
failures; otherwise, it returns true.
|
37
|
+
|
38
|
+
The library provides little beyond this, but it's easy to do relatively
|
39
|
+
sophisticated things with it. Some examples follow.
|
40
|
+
|
41
|
+
|
42
|
+
- Exiting with the appropriate status
|
43
|
+
|
44
|
+
Blackstart.run returns false if there were any failures; otherwise, it returns
|
45
|
+
true. If you use this as the argument to Kernel#exit, your test program will
|
46
|
+
exit with a successful status only if there were no failures.
|
47
|
+
|
48
|
+
|
49
|
+
- Defining helpers
|
50
|
+
|
51
|
+
You may want all your tests to be able to assert something, generate test data,
|
52
|
+
or perform some other task by sending a message. You could implement this
|
53
|
+
statelessly in a singleton object or all instances of Object, for example, but
|
54
|
+
there's another option that may be more convenient. Blackstart.run calls each
|
55
|
+
test proc in the context of a new Blackstart::Context instance. You can define
|
56
|
+
instance methods in that class like this:
|
57
|
+
|
58
|
+
class Blackstart::Context
|
59
|
+
def assert boolean
|
60
|
+
raise "assertion failed" unless boolean
|
61
|
+
end
|
62
|
+
|
63
|
+
def make_products
|
64
|
+
@cabbage = { :description => "head of cabbage", :price => 125 }
|
65
|
+
@orange = { :description => "Cara cara navel orange", :price => 100 }
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
All of your tests will be able to use them by sending messages to self. These
|
71
|
+
methods can see and modify the test's state, which is disposable: it will be
|
72
|
+
discarded after the test is complete and so will not affect later tests.
|
73
|
+
|
74
|
+
|
75
|
+
- Running code before and after each test
|
76
|
+
|
77
|
+
You can run code before and after each test by defining a custom
|
78
|
+
Blackstart::Context#instance_exec. For example:
|
79
|
+
|
80
|
+
class Blackstart::Context
|
81
|
+
def instance_exec(*)
|
82
|
+
puts "doing setup"
|
83
|
+
@variable = "example"
|
84
|
+
super
|
85
|
+
ensure
|
86
|
+
puts "doing teardown"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
- Building a test collection in stages
|
92
|
+
|
93
|
+
You can build your collection of test objects in stages and run it at the end.
|
94
|
+
For example:
|
95
|
+
|
96
|
+
require "blackstart"
|
97
|
+
|
98
|
+
TEST_OBJECTS = []
|
99
|
+
|
100
|
+
Blackstart.add TEST_OBJECTS do |adder|
|
101
|
+
adder.call do
|
102
|
+
unless "Hello, World!" == ["He", "", "o, Wor", "d!"].join("l")
|
103
|
+
raise "join did not work as expected"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
Blackstart.add TEST_OBJECTS do |adder|
|
109
|
+
adder.call do
|
110
|
+
unless "sample" == "simple".gsub(/i/, "a")
|
111
|
+
raise "gsub did not work as expected"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
exit Blackstart.run TEST_OBJECTS
|
117
|
+
|
118
|
+
This makes it straightforward to define your tests in multiple files that you
|
119
|
+
load in your test program.
|
120
|
+
|
121
|
+
|
122
|
+
- Running tests in random order
|
123
|
+
|
124
|
+
Blackstart.run runs a sequence of tests in order, but you can pass it a
|
125
|
+
randomly-ordered sequence. Array#shuffle may be helpful for this. If you do
|
126
|
+
this, you may also want to print the random seed at the start of your program
|
127
|
+
so you can re-run your tests in the same order.
|
128
|
+
|
129
|
+
|
130
|
+
- Reporting detailed test descriptions
|
131
|
+
|
132
|
+
After a test fails, Blackstart.run writes a description of the test to the
|
133
|
+
output stream. It gets this description by converting the test object to a
|
134
|
+
string. When the test object is an instance of Proc, which is what
|
135
|
+
Blackstart.add produces when used as expected, this string typically includes
|
136
|
+
the file path and line number where it was defined: helpful, but it won't be
|
137
|
+
immediately clear what was being tested.
|
138
|
+
|
139
|
+
You can improve this by making your own test objects instead of using
|
140
|
+
Blackstart.add. Blackstart.run does not strictly need a sequence of Proc
|
141
|
+
instances; it only needs a sequence of objects that convert to Proc instances
|
142
|
+
in response to to_proc messages. Your custom test objects can respond to to_s
|
143
|
+
with detailed descriptions instead of mere file paths and line numbers.
|
144
|
+
|
145
|
+
|
146
|
+
- Handling failures differently
|
147
|
+
|
148
|
+
Blackstart.run handles each failure by sending a puts message to the output
|
149
|
+
stream, one of its parameters. By default, this is $stdout, so the default
|
150
|
+
behavior is to print unadorned failure information to standard output. But you
|
151
|
+
can specify any object as the output stream -- even if it's not really a stream
|
152
|
+
-- allowing you to handle failure information however you want.
|
data/blackstart.gemspec
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "blackstart"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.authors = ["Aaron Beckerman"]
|
5
|
+
s.summary = "A small, subdued library for automated testing."
|
6
|
+
s.licenses = ["MIT"]
|
7
|
+
s.required_ruby_version = ">= 1.8.7"
|
8
|
+
s.files = ["LICENSE.txt", "README.txt", "blackstart.gemspec",
|
9
|
+
"lib/blackstart.rb", "test/blackstart_test.rb"]
|
10
|
+
s.test_files = ["test/blackstart_test.rb"]
|
11
|
+
end
|
data/lib/blackstart.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
##
|
2
|
+
# This module provides facilities for defining and running automated tests.
|
3
|
+
|
4
|
+
module Blackstart
|
5
|
+
|
6
|
+
##
|
7
|
+
# Calls the block and returns a string describing the error raised, if any.
|
8
|
+
#
|
9
|
+
# In detail: This method sends call with no arguments to the object
|
10
|
+
# representing the block. If that raises an error -- that is, an exception
|
11
|
+
# whose class is StandardError or a descendent of StandardError -- this
|
12
|
+
# method creates a string describing that error and returns it; the
|
13
|
+
# description includes the error's class, message, and backtrace (if any). If
|
14
|
+
# sending the message raises any other exception, this method raises that
|
15
|
+
# exception. If sending the message does not raise an exception, this method
|
16
|
+
# returns nil.
|
17
|
+
|
18
|
+
def self.vet &prc
|
19
|
+
prc.call
|
20
|
+
nil
|
21
|
+
rescue ::StandardError
|
22
|
+
# Like IO#puts, separate lines with a line feed character rather than $\.
|
23
|
+
["#{$!.class}: #{$!.message}"].concat($!.backtrace || []).join "\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Allows the block to add procs to a collection, which it returns.
|
28
|
+
#
|
29
|
+
# In detail: This method sends call with one positional argument, an adder
|
30
|
+
# object, to the object representing the block, director. This block can send
|
31
|
+
# call messages to the adder to add objects representing the respective
|
32
|
+
# blocks to the collection, sink. With each sending of call, the object to be
|
33
|
+
# added will be either a proc (if call is sent with a block) or nil (if call
|
34
|
+
# is sent without a block). If any non-block arguments are sent with the call
|
35
|
+
# message, an exception is raised. To add the object, the adder sends a <<
|
36
|
+
# message to sink with the object as the positional argument and no other
|
37
|
+
# arguments. The adder returns nil in response to a call message if it
|
38
|
+
# returns at all. This method returns sink.
|
39
|
+
#
|
40
|
+
# By default, sink is a new empty array.
|
41
|
+
|
42
|
+
def self.add sink = [], &director
|
43
|
+
director.call ::Kernel.lambda { |&prc|
|
44
|
+
sink << prc
|
45
|
+
nil
|
46
|
+
}
|
47
|
+
sink
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# A class for the contexts (the self objects) of tests.
|
52
|
+
|
53
|
+
class Context
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Runs the tests, writes any failure information to the output stream, and
|
58
|
+
# returns a boolean indicating whether there were no failures.
|
59
|
+
#
|
60
|
+
# In detail: This method expects the sequence of test objects, source, to
|
61
|
+
# respond to an each message by yielding successive test objects to its
|
62
|
+
# block. Each test is run by converting the test object to a proc and calling
|
63
|
+
# it in the context of a new instance of Blackstart::Context. A failure is
|
64
|
+
# when the test raises an error (that is, an exception whose class is
|
65
|
+
# StandardError or a descendent of StandardError). After a failure, this
|
66
|
+
# method sends a puts message to the output stream, ostream, with these
|
67
|
+
# arguments (positional, in order): a string "FAILED TEST:", the test object
|
68
|
+
# converted to a string via to_s, a string "...ERROR:", a string describing
|
69
|
+
# the error, and an empty string. If a test raises any other exception, this
|
70
|
+
# method immediately raises that exception. After it has run all the tests
|
71
|
+
# and handled any failures, this method returns false if there were failures
|
72
|
+
# or true otherwise.
|
73
|
+
#
|
74
|
+
# By default, ostream is $stdout.
|
75
|
+
|
76
|
+
def self.run source, ostream = $stdout
|
77
|
+
success = true
|
78
|
+
for tst in source
|
79
|
+
# Convert to a proc and create a context outside the vet block so that
|
80
|
+
# this method will raise any exception that results instead of
|
81
|
+
# potentially treating it as a test failure.
|
82
|
+
prc = ::Proc.new(&tst)
|
83
|
+
context = Context.new
|
84
|
+
if err_desc = vet { context.instance_exec(&prc) }
|
85
|
+
success = false
|
86
|
+
ostream.puts "FAILED TEST:", tst.to_s, "...ERROR:", err_desc.to_s, ""
|
87
|
+
end
|
88
|
+
end
|
89
|
+
success
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,404 @@
|
|
1
|
+
# Sections that create local variables are in class definitions so that later
|
2
|
+
# sections cannot accidentally reference those local variables.
|
3
|
+
|
4
|
+
require "blackstart"
|
5
|
+
|
6
|
+
# Blackstart should be a module.
|
7
|
+
fail "" unless Module.equal? Blackstart.class
|
8
|
+
|
9
|
+
# Blackstart should say it responds to vet, add, and run.
|
10
|
+
fail "" unless Blackstart.respond_to? :vet
|
11
|
+
fail "" unless Blackstart.respond_to? :add
|
12
|
+
fail "" unless Blackstart.respond_to? :run
|
13
|
+
|
14
|
+
# Test Blackstart.vet:
|
15
|
+
|
16
|
+
# Blackstart.vet should raise an exception if any non-block arguments are sent.
|
17
|
+
begin
|
18
|
+
Blackstart.vet nil
|
19
|
+
rescue ArgumentError
|
20
|
+
else
|
21
|
+
fail ""
|
22
|
+
end
|
23
|
+
begin
|
24
|
+
Blackstart.vet(nil) {}
|
25
|
+
rescue ArgumentError
|
26
|
+
else
|
27
|
+
fail ""
|
28
|
+
end
|
29
|
+
|
30
|
+
# If sending call with no arguments to the block raises an error,
|
31
|
+
# Blackstart.vet should return a new descriptive string.
|
32
|
+
class ::Object
|
33
|
+
fail "" unless /\ANoMethodError: / =~ Blackstart.vet
|
34
|
+
|
35
|
+
e_class = Class.new StandardError
|
36
|
+
def e_class.to_s
|
37
|
+
"FakeError".freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
e_nil = e_class.new "a".freeze
|
41
|
+
def e_nil.backtrace
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
fail "" unless "FakeError: a" == Blackstart.vet { ::Kernel.raise e_nil }
|
45
|
+
|
46
|
+
e_empty = e_class.new "b".freeze
|
47
|
+
def e_empty.backtrace
|
48
|
+
[].freeze
|
49
|
+
end
|
50
|
+
fail "" unless "FakeError: b" == Blackstart.vet { ::Kernel.raise e_empty }
|
51
|
+
|
52
|
+
e_full = e_class.new "c".freeze
|
53
|
+
def e_full.backtrace
|
54
|
+
["d".freeze, "e".freeze].freeze
|
55
|
+
end
|
56
|
+
fail "" unless "FakeError: c\nd\ne" ==
|
57
|
+
Blackstart.vet { ::Kernel.raise e_full }
|
58
|
+
end
|
59
|
+
|
60
|
+
# If sending call with no arguments to the block raises a non-StandardError
|
61
|
+
# exception, Blackstart.vet should not rescue it.
|
62
|
+
class ::Object
|
63
|
+
non_standard_error = Class.new Exception
|
64
|
+
begin
|
65
|
+
Blackstart.vet { ::Kernel.raise non_standard_error }
|
66
|
+
rescue non_standard_error
|
67
|
+
else
|
68
|
+
fail ""
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# If sending call with no arguments to the block does not raise an exception,
|
73
|
+
# Blackstart.vet should return nil.
|
74
|
+
fail "" unless nil.equal? Blackstart.vet { nil }
|
75
|
+
fail "" unless nil.equal? Blackstart.vet { true }
|
76
|
+
|
77
|
+
# Test Blackstart.add:
|
78
|
+
|
79
|
+
# When there is no block, Blackstart.add should raise an exception.
|
80
|
+
begin
|
81
|
+
Blackstart.add
|
82
|
+
rescue NoMethodError
|
83
|
+
else
|
84
|
+
fail ""
|
85
|
+
end
|
86
|
+
begin
|
87
|
+
Blackstart.add []
|
88
|
+
rescue NoMethodError
|
89
|
+
else
|
90
|
+
fail ""
|
91
|
+
end
|
92
|
+
|
93
|
+
# Blackstart.add should raise an exception if superfluous arguments are sent.
|
94
|
+
begin
|
95
|
+
Blackstart.add [], "invalid"
|
96
|
+
rescue ArgumentError
|
97
|
+
else
|
98
|
+
fail ""
|
99
|
+
end
|
100
|
+
begin
|
101
|
+
Blackstart.add([], "invalid") {}
|
102
|
+
rescue ArgumentError
|
103
|
+
else
|
104
|
+
fail ""
|
105
|
+
end
|
106
|
+
|
107
|
+
# When no collection is specified and the block does nothing, Blackstart.add
|
108
|
+
# should return an empty array.
|
109
|
+
fail "" unless [] == Blackstart.add {}
|
110
|
+
|
111
|
+
# When a collection is specified and the block tries to add to the collection,
|
112
|
+
# Blackstart.add should add corresponding procs or nil to the collection by
|
113
|
+
# sending <<.
|
114
|
+
class ::Object
|
115
|
+
sink = [42]
|
116
|
+
prc1 = proc {}
|
117
|
+
prc2 = proc {}
|
118
|
+
retval = Blackstart.add sink do |adder|
|
119
|
+
adder.call(&prc1)
|
120
|
+
adder.call(&prc2)
|
121
|
+
adder.call
|
122
|
+
end
|
123
|
+
fail "" unless sink.equal? retval
|
124
|
+
fail "" unless [42, prc1, prc2, nil] == sink
|
125
|
+
end
|
126
|
+
|
127
|
+
# When the block sends call to the adder with arguments other than a block, it
|
128
|
+
# should raise an exception and not add anything to the collection.
|
129
|
+
class ::Object
|
130
|
+
sink = []
|
131
|
+
begin
|
132
|
+
Blackstart.add(sink) { |adder| adder.call("invalid") {} }
|
133
|
+
rescue ArgumentError
|
134
|
+
else
|
135
|
+
fail ""
|
136
|
+
end
|
137
|
+
begin
|
138
|
+
Blackstart.add(sink) { |adder| adder.call "invalid" }
|
139
|
+
rescue ArgumentError
|
140
|
+
else
|
141
|
+
fail ""
|
142
|
+
end
|
143
|
+
fail "" unless 0 == sink.length
|
144
|
+
end
|
145
|
+
|
146
|
+
# When Blackstart.add's block sends call to the adder and it returns, nil
|
147
|
+
# should be the object it returns.
|
148
|
+
class ::Object
|
149
|
+
retval_block = retval_no_block = true
|
150
|
+
Blackstart.add do |adder|
|
151
|
+
retval_block = adder.call {}
|
152
|
+
retval_no_block = adder.call
|
153
|
+
end
|
154
|
+
fail "" unless nil.equal? retval_block
|
155
|
+
fail "" unless nil.equal? retval_no_block
|
156
|
+
end
|
157
|
+
|
158
|
+
# In general, when there is a block that raises an exception, Blackstart.add
|
159
|
+
# should not rescue it.
|
160
|
+
class ::Object
|
161
|
+
e = StandardError.new
|
162
|
+
begin
|
163
|
+
Blackstart.add { ::Kernel.raise e }
|
164
|
+
rescue
|
165
|
+
fail "" unless e.equal? $!
|
166
|
+
else
|
167
|
+
fail ""
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# When there is a block that tries to add to the collection and the collection
|
172
|
+
# responds to the << message by raising an exception, Blackstart.add should not
|
173
|
+
# rescue it.
|
174
|
+
begin
|
175
|
+
Blackstart.add(nil) { |adder| adder.call {} }
|
176
|
+
rescue NoMethodError
|
177
|
+
else
|
178
|
+
fail ""
|
179
|
+
end
|
180
|
+
|
181
|
+
# When no collection is specified and the block tries to add to the collection,
|
182
|
+
# Blackstart.add should append to a new array that gets returned.
|
183
|
+
class ::Object
|
184
|
+
prc = proc {}
|
185
|
+
fail "" unless [prc] == Blackstart.add { |adder| adder.call(&prc) }
|
186
|
+
end
|
187
|
+
|
188
|
+
# Test Blackstart::Context:
|
189
|
+
|
190
|
+
# Blackstart::Context.new should return an instance of Blackstart::Context,
|
191
|
+
# which implies that Blackstart::Context should be a class.
|
192
|
+
fail "" unless Blackstart::Context.equal? Blackstart::Context.new.class
|
193
|
+
|
194
|
+
# Blackstart::Context.new should raise an exception if any non-block arguments
|
195
|
+
# are sent.
|
196
|
+
begin
|
197
|
+
Blackstart::Context.new nil
|
198
|
+
rescue ArgumentError
|
199
|
+
else
|
200
|
+
fail ""
|
201
|
+
end
|
202
|
+
|
203
|
+
# Test Blackstart.run:
|
204
|
+
|
205
|
+
# Blackstart.run should send appropriate messages to the output stream and
|
206
|
+
# return the appropriate object based on the behavior of the tests.
|
207
|
+
class ::Object
|
208
|
+
begin
|
209
|
+
# Set $stdout to a test spy and set it back in the ensure clause.
|
210
|
+
original_stdout = $stdout
|
211
|
+
spy_stdout = $stdout.clone
|
212
|
+
spy_stdout.instance_variable_set :@_test_calls, stdout_calls = []
|
213
|
+
def spy_stdout.puts *args
|
214
|
+
@_test_calls << args
|
215
|
+
nil
|
216
|
+
end
|
217
|
+
$stdout = spy_stdout
|
218
|
+
|
219
|
+
# No tests.
|
220
|
+
source = [].freeze
|
221
|
+
fail "" unless true.equal? Blackstart.run(source, Object.new)
|
222
|
+
fail "" unless true.equal? Blackstart.run(source, spy_stdout)
|
223
|
+
fail "" unless true.equal? Blackstart.run(source)
|
224
|
+
fail "" unless 0 == stdout_calls.length
|
225
|
+
|
226
|
+
# Tests that do not raise exceptions.
|
227
|
+
source = [proc {}, proc { 42 }].freeze
|
228
|
+
fail "" unless true.equal? Blackstart.run(source, Object.new)
|
229
|
+
fail "" unless true.equal? Blackstart.run(source, spy_stdout)
|
230
|
+
fail "" unless true.equal? Blackstart.run(source)
|
231
|
+
fail "" unless 0 == stdout_calls.length
|
232
|
+
|
233
|
+
# Define some example test objects.
|
234
|
+
e_class = Class.new StandardError
|
235
|
+
def e_class.to_s
|
236
|
+
"FakeError"
|
237
|
+
end
|
238
|
+
fail_prc1 = proc { ::Kernel.raise e_class, "fake message 1" }
|
239
|
+
def fail_prc1.to_s
|
240
|
+
"to_s 1"
|
241
|
+
end
|
242
|
+
fail_prc2 = Object.new # Not a Proc instance, but converts to one.
|
243
|
+
fail_prc2.instance_variable_set :@_test_e_class, e_class
|
244
|
+
def fail_prc2.to_proc
|
245
|
+
e_class = @_test_e_class
|
246
|
+
::Proc.new { ::Kernel.raise e_class, "fake message 2" }
|
247
|
+
end
|
248
|
+
def fail_prc2.to_s
|
249
|
+
"to_s 2"
|
250
|
+
end
|
251
|
+
pass_prc = proc {}
|
252
|
+
|
253
|
+
# A mix of tests that raise errors and tests that return.
|
254
|
+
source = [fail_prc1, fail_prc2, pass_prc].freeze
|
255
|
+
|
256
|
+
# Output stream that does not conform to the expected interface. (And in
|
257
|
+
# general, the only exceptions Blackstart.run should rescue are
|
258
|
+
# StandardError exceptions raised by tests.)
|
259
|
+
begin
|
260
|
+
Blackstart.run source, Object.new
|
261
|
+
rescue NoMethodError
|
262
|
+
else
|
263
|
+
fail ""
|
264
|
+
end
|
265
|
+
fail "" unless 0 == stdout_calls.length
|
266
|
+
|
267
|
+
# Output stream that conforms to the expected interface.
|
268
|
+
spy_ostream = Object.new
|
269
|
+
spy_ostream.instance_variable_set :@_test_calls, calls = []
|
270
|
+
def spy_ostream.puts *args
|
271
|
+
@_test_calls << args
|
272
|
+
nil
|
273
|
+
end
|
274
|
+
fail "" unless false.equal? Blackstart.run(source, spy_ostream)
|
275
|
+
fail "" unless 0 == stdout_calls.length
|
276
|
+
fail "" unless 2 == calls.length
|
277
|
+
fail "" unless 5 == calls[0].length
|
278
|
+
fail "" unless "FAILED TEST:" == calls[0][0]
|
279
|
+
fail "" unless "to_s 1" == calls[0][1]
|
280
|
+
fail "" unless "...ERROR:" == calls[0][2]
|
281
|
+
fail "" unless /\AFakeError: fake message 1$/ =~ calls[0][3]
|
282
|
+
fail "" unless "" == calls[0][4]
|
283
|
+
fail "" unless 5 == calls[1].length
|
284
|
+
fail "" unless "FAILED TEST:" == calls[1][0]
|
285
|
+
fail "" unless "to_s 2" == calls[1][1]
|
286
|
+
fail "" unless "...ERROR:" == calls[1][2]
|
287
|
+
fail "" unless /\AFakeError: fake message 2$/ =~ calls[1][3]
|
288
|
+
fail "" unless "" == calls[1][4]
|
289
|
+
spy_ostream = calls = nil
|
290
|
+
|
291
|
+
# Default output stream.
|
292
|
+
stdout_calls.clear
|
293
|
+
fail "" unless false.equal? Blackstart.run(source)
|
294
|
+
fail "" unless 2 == stdout_calls.length
|
295
|
+
fail "" unless 5 == stdout_calls[0].length
|
296
|
+
fail "" unless "FAILED TEST:" == stdout_calls[0][0]
|
297
|
+
fail "" unless "to_s 1" == stdout_calls[0][1]
|
298
|
+
fail "" unless "...ERROR:" == stdout_calls[0][2]
|
299
|
+
fail "" unless /\AFakeError: fake message 1$/ =~ stdout_calls[0][3]
|
300
|
+
fail "" unless "" == stdout_calls[0][4]
|
301
|
+
fail "" unless 5 == stdout_calls[1].length
|
302
|
+
fail "" unless "FAILED TEST:" == stdout_calls[1][0]
|
303
|
+
fail "" unless "to_s 2" == stdout_calls[1][1]
|
304
|
+
fail "" unless "...ERROR:" == stdout_calls[1][2]
|
305
|
+
fail "" unless /\AFakeError: fake message 2$/ =~ stdout_calls[1][3]
|
306
|
+
fail "" unless "" == stdout_calls[1][4]
|
307
|
+
stdout_calls.clear
|
308
|
+
|
309
|
+
# Test that raises a non-StandardError exception. (And in general, the only
|
310
|
+
# exceptions Blackstart.run should rescue are StandardError exceptions
|
311
|
+
# raised by tests.)
|
312
|
+
non_standard_error = Class.new Exception
|
313
|
+
source = [proc { ::Kernel.raise non_standard_error }]
|
314
|
+
begin
|
315
|
+
Blackstart.run source, spy_stdout
|
316
|
+
rescue non_standard_error
|
317
|
+
else
|
318
|
+
fail ""
|
319
|
+
end
|
320
|
+
fail "" unless 0 == stdout_calls.length
|
321
|
+
|
322
|
+
# Test sequence that does not conform to the interface. (And in general,
|
323
|
+
# the only exceptions Blackstart.run should rescue are StandardError
|
324
|
+
# exceptions raised by tests.)
|
325
|
+
begin
|
326
|
+
Blackstart.run nil, spy_stdout
|
327
|
+
rescue NoMethodError
|
328
|
+
else
|
329
|
+
fail ""
|
330
|
+
end
|
331
|
+
fail "" unless 0 == stdout_calls.length
|
332
|
+
|
333
|
+
# Test sequences containing objects that do not convert to procs (and do
|
334
|
+
# not pretend to) and objects that pretend to convert to procs but do not.
|
335
|
+
# (And in general, the only exceptions Blackstart.run should rescue are
|
336
|
+
# StandardError exceptions raised by tests.)
|
337
|
+
source = [nil]
|
338
|
+
begin
|
339
|
+
Blackstart.run source, spy_stdout
|
340
|
+
rescue ArgumentError
|
341
|
+
else
|
342
|
+
fail ""
|
343
|
+
end
|
344
|
+
source = [0]
|
345
|
+
begin
|
346
|
+
Blackstart.run source, spy_stdout
|
347
|
+
rescue TypeError
|
348
|
+
else
|
349
|
+
fail ""
|
350
|
+
end
|
351
|
+
bad_to_proc = Object.new
|
352
|
+
def bad_to_proc.to_proc
|
353
|
+
nil
|
354
|
+
end
|
355
|
+
source = [bad_to_proc]
|
356
|
+
begin
|
357
|
+
Blackstart.run source, spy_stdout
|
358
|
+
rescue TypeError
|
359
|
+
else
|
360
|
+
fail ""
|
361
|
+
end
|
362
|
+
fail "" unless 0 == stdout_calls.length
|
363
|
+
ensure
|
364
|
+
$stdout = original_stdout
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# Blackstart.run should call each test proc with no arguments.
|
369
|
+
class ::Object
|
370
|
+
args = nil
|
371
|
+
tst = proc do |*a|
|
372
|
+
args = a
|
373
|
+
end
|
374
|
+
Blackstart.run [tst], nil
|
375
|
+
fail "" unless [] == args
|
376
|
+
end
|
377
|
+
|
378
|
+
# Blackstart.run should call each test proc in the context of a unique instance
|
379
|
+
# of Blackstart::Context.
|
380
|
+
class ::Object
|
381
|
+
context1 = context2 = nil
|
382
|
+
Blackstart.run [proc { context1 = self }, proc { context2 = self }], nil
|
383
|
+
fail "" unless Blackstart::Context.equal? context1.class
|
384
|
+
fail "" unless Blackstart::Context.equal? context2.class
|
385
|
+
fail "" if context1.equal? context2
|
386
|
+
end
|
387
|
+
|
388
|
+
# Blackstart.run should raise an exception if too few or too many non-block
|
389
|
+
# arguments are sent.
|
390
|
+
begin
|
391
|
+
Blackstart.run
|
392
|
+
rescue ArgumentError
|
393
|
+
else
|
394
|
+
fail ""
|
395
|
+
end
|
396
|
+
begin
|
397
|
+
Blackstart.run [], nil, "invalid"
|
398
|
+
rescue ArgumentError
|
399
|
+
else
|
400
|
+
fail ""
|
401
|
+
end
|
402
|
+
|
403
|
+
# If this message doesn't get written, there was a problem.
|
404
|
+
puts "Test finished: #{__FILE__}"
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: blackstart
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Aaron Beckerman
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2024-03-19 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email:
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- LICENSE.txt
|
32
|
+
- README.txt
|
33
|
+
- blackstart.gemspec
|
34
|
+
- lib/blackstart.rb
|
35
|
+
- test/blackstart_test.rb
|
36
|
+
has_rdoc: true
|
37
|
+
homepage:
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
hash: 57
|
51
|
+
segments:
|
52
|
+
- 1
|
53
|
+
- 8
|
54
|
+
- 7
|
55
|
+
version: 1.8.7
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.6.2
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A small, subdued library for automated testing.
|
72
|
+
test_files:
|
73
|
+
- test/blackstart_test.rb
|