blackstart 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -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