blackstart 0.2.0 → 0.8.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.
@@ -1,14 +1,29 @@
1
1
  # Sections that create local variables are in class definitions so that later
2
2
  # sections cannot accidentally reference those local variables.
3
3
 
4
+ # Kernel#fail is an alias of Kernel#raise, so they do the same thing. However,
5
+ # they are used differently in this file: Kernel#fail is used only for
6
+ # assertions and Kernel#raise is used otherwise. Assertions always pass a
7
+ # string argument so that a new RuntimeError is raised. Kernel#fail with no
8
+ # arguments re-raises the current exception ($!) or, if there is none, raises a
9
+ # new RuntimeError. This would be fine (that is, it would raise a new
10
+ # RuntimeError) sometimes, but not always (not in a rescue clause, for
11
+ # example). Always using Kernel#fail with a string argument makes assertions
12
+ # consistent and avoids this subtle error.
13
+
14
+ # Constant references in blocks are fully qualified because this program must
15
+ # run correctly on a wide range of Ruby versions, including those in the 1.9.1
16
+ # and 1.9.2 branches. Ruby 1.9.1 and 1.9.2 used constant-lookup rules in
17
+ # certain situations that differed from those of earlier and later branches of
18
+ # Ruby.
19
+
4
20
  require "blackstart"
5
21
 
6
22
  # Blackstart should be a module.
7
23
  fail "" unless Module.equal? Blackstart.class
8
24
 
9
- # Blackstart should say it responds to vet, add, and run.
25
+ # Blackstart should say it responds to vet and run.
10
26
  fail "" unless Blackstart.respond_to? :vet
11
- fail "" unless Blackstart.respond_to? :add
12
27
  fail "" unless Blackstart.respond_to? :run
13
28
 
14
29
  # Test Blackstart.vet:
@@ -27,10 +42,14 @@ else
27
42
  fail ""
28
43
  end
29
44
 
30
- # If sending call with no arguments to the block raises an error,
31
- # Blackstart.vet should return a new descriptive string.
45
+ # If yielding to the block raises an error, Blackstart.vet should return a
46
+ # string describing that error.
32
47
  class ::Object
33
- fail "" unless /\ANoMethodError: / =~ Blackstart.vet
48
+ # Should return an error description when no block is given.
49
+ fail "" unless String.equal? Blackstart.vet.class
50
+
51
+ # Use frozen strings and backtrace arrays so that an exception will be raised
52
+ # if they're modified.
34
53
 
35
54
  e_class = Class.new StandardError
36
55
  def e_class.to_s
@@ -41,158 +60,73 @@ class ::Object
41
60
  def e_nil.backtrace
42
61
  nil
43
62
  end
44
- fail "" unless "FakeError: a" == Blackstart.vet { ::Kernel.raise e_nil }
63
+ error = Blackstart.vet { ::Kernel.raise e_nil }
64
+ fail "" unless String.equal? error.class
65
+ fail "" unless "FakeError: a" == error
45
66
 
46
67
  e_empty = e_class.new "b".freeze
47
68
  def e_empty.backtrace
48
69
  [].freeze
49
70
  end
50
- fail "" unless "FakeError: b" == Blackstart.vet { ::Kernel.raise e_empty }
71
+ error = Blackstart.vet { ::Kernel.raise e_empty }
72
+ fail "" unless String.equal? error.class
73
+ fail "" unless "FakeError: b" == error
51
74
 
52
75
  e_full = e_class.new "c".freeze
53
76
  def e_full.backtrace
54
77
  ["d".freeze, "e".freeze].freeze
55
78
  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
79
+ error = Blackstart.vet { ::Kernel.raise e_full }
80
+ fail "" unless String.equal? error.class
81
+ fail "" unless "FakeError: c\nd\ne" == error
125
82
  end
126
83
 
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.
84
+ # If yielding to the block raises an error and that error raises an exception
85
+ # when queried, Blackstart.vet should raise that second exception.
129
86
  class ::Object
130
- sink = []
131
- begin
132
- Blackstart.add(sink) { |adder| adder.call("invalid") {} }
133
- rescue ArgumentError
134
- else
135
- fail ""
87
+ e1 = StandardError.new
88
+ e2_class = Class.new StandardError
89
+ e1.instance_variable_set :@next_exception_class, e2_class
90
+ def e1.to_s
91
+ ::Kernel.raise @next_exception_class
136
92
  end
137
93
  begin
138
- Blackstart.add(sink) { |adder| adder.call "invalid" }
139
- rescue ArgumentError
94
+ Blackstart.vet { ::Kernel.raise e1 }
95
+ rescue e2_class
140
96
  else
141
97
  fail ""
142
98
  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
99
  end
157
100
 
158
- # In general, when there is a block that raises an exception, Blackstart.add
159
- # should not rescue it.
101
+ # If yielding to the block raises a non-StandardError exception, Blackstart.vet
102
+ # should raise it.
160
103
  class ::Object
161
- e = StandardError.new
104
+ non_standard_error = Class.new Exception
162
105
  begin
163
- Blackstart.add { ::Kernel.raise e }
164
- rescue
165
- fail "" unless e.equal? $!
106
+ Blackstart.vet { ::Kernel.raise non_standard_error }
107
+ rescue non_standard_error
166
108
  else
167
109
  fail ""
168
110
  end
169
111
  end
170
112
 
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
113
+ # If yielding to the block does not raise an exception, Blackstart.vet should
114
+ # return nil. The object returned by the block shouldn't matter.
115
+ fail "" unless nil.equal? Blackstart.vet { nil }
116
+ fail "" unless nil.equal? Blackstart.vet { true }
180
117
 
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
118
+ # Test Blackstart::Scratchpad:
187
119
 
188
- # Test Blackstart::Context:
120
+ # Blackstart::Scratchpad.new should return an instance of
121
+ # Blackstart::Scratchpad, which implies that Blackstart::Scratchpad should be a
122
+ # class.
123
+ fail "" unless Blackstart::Scratchpad.equal? Blackstart::Scratchpad.new.class
189
124
 
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
125
+ # Blackstart::Scratchpad should not be frozen.
126
+ fail "" if Blackstart::Scratchpad.frozen?
193
127
 
194
- # A new context should have no instance variables.
195
- fail "" unless 0 == Blackstart::Context.new.instance_variables.length
128
+ # A new scratchpad should have no instance variables.
129
+ fail "" unless 0 == Blackstart::Scratchpad.new.instance_variables.length
196
130
 
197
131
  # Test Blackstart.run:
198
132
 
@@ -200,7 +134,7 @@ fail "" unless 0 == Blackstart::Context.new.instance_variables.length
200
134
  # return the appropriate object based on the behavior of the tests.
201
135
  class ::Object
202
136
  begin
203
- # Set $stdout to a test spy and set it back in the ensure clause.
137
+ # Set $stdout to a test spy and restore it in the ensure clause.
204
138
  original_stdout = $stdout
205
139
  spy_stdout = $stdout.clone
206
140
  spy_stdout.instance_variable_set :@_test_calls, stdout_calls = []
@@ -210,155 +144,237 @@ class ::Object
210
144
  end
211
145
  $stdout = spy_stdout
212
146
 
213
- # No tests.
214
- source = [].freeze
215
- fail "" unless true.equal? Blackstart.run(source, Object.new)
147
+ invalid_ostream = Object.new
148
+ def invalid_ostream.puts(*)
149
+ ::Kernel.raise ::NoMethodError
150
+ end
151
+
152
+ # When there are no tests, Blackstart.run should not notify the output
153
+ # stream of any failures.
154
+ source = []
155
+ fail "" unless true.equal? Blackstart.run(source, invalid_ostream)
216
156
  fail "" unless true.equal? Blackstart.run(source, spy_stdout)
217
157
  fail "" unless true.equal? Blackstart.run(source)
218
158
  fail "" unless 0 == stdout_calls.length
219
159
 
220
- # Tests that do not raise exceptions.
221
- source = [proc {}, proc { 42 }].freeze
222
- fail "" unless true.equal? Blackstart.run(source, Object.new)
160
+ # When there are tests but none raise exceptions, Blackstart.run should not
161
+ # notify the output stream of any failures. The objects returned by the
162
+ # test procs shouldn't affect Blackstart.run's behavior.
163
+ source = [lambda {}, lambda { 42 }]
164
+ fail "" unless true.equal? Blackstart.run(source, invalid_ostream)
223
165
  fail "" unless true.equal? Blackstart.run(source, spy_stdout)
224
166
  fail "" unless true.equal? Blackstart.run(source)
225
167
  fail "" unless 0 == stdout_calls.length
226
168
 
227
- # Define some example test objects.
228
- e_class = Class.new StandardError
169
+ # Define some test objects. Freeze them, the strings to which they convert,
170
+ # some exception details, and the strings to which the exception classes
171
+ # convert to check that they don't get modified.
172
+ e_class = Class.new StandardError do
173
+ def backtrace
174
+ ["line1".freeze, "line2".freeze].freeze
175
+ end
176
+ end
229
177
  def e_class.to_s
230
- "FakeError"
178
+ "FakeError".freeze
231
179
  end
232
- fail_prc1 = proc { ::Kernel.raise e_class, "fake message 1" }
180
+ fail_prc1 = lambda { ::Kernel.raise e_class, "fake message 1".freeze }
233
181
  def fail_prc1.to_s
234
- "to_s 1"
182
+ "to_s 1".freeze
235
183
  end
184
+ fail_prc1.freeze
185
+ pass_prc = lambda {}.freeze
236
186
  fail_prc2 = Object.new # Not a Proc instance, but converts to one.
237
187
  fail_prc2.instance_variable_set :@_test_e_class, e_class
238
188
  def fail_prc2.to_proc
239
189
  e_class = @_test_e_class
240
- ::Proc.new { ::Kernel.raise e_class, "fake message 2" }
190
+ ::Kernel.lambda do
191
+ ::Kernel.raise e_class, "fake message 2".freeze
192
+ end.freeze
241
193
  end
242
194
  def fail_prc2.to_s
243
- "to_s 2"
195
+ "to_s 2".freeze
244
196
  end
245
- pass_prc = proc {}
246
-
247
- # A mix of tests that raise errors and tests that return.
248
- source = [fail_prc1, fail_prc2, pass_prc].freeze
249
-
250
- # Output stream that does not conform to the expected interface. (And in
251
- # general, the only exceptions Blackstart.run should rescue are
252
- # StandardError exceptions raised by tests.)
253
- begin
254
- Blackstart.run source, Object.new
255
- rescue NoMethodError
256
- else
257
- fail ""
197
+ fail_prc2.freeze
198
+ non_prc = Object.new # Does not convert to a proc.
199
+ def non_prc.to_proc
200
+ ::Kernel.raise ::NoMethodError
258
201
  end
259
- fail "" unless 0 == stdout_calls.length
202
+ def non_prc.to_s
203
+ "to_s 3".freeze
204
+ end
205
+ non_prc.freeze
206
+ bad_prc = Object.new # Pretends to convert to a proc but doesn't.
207
+ def bad_prc.to_proc
208
+ 0
209
+ end
210
+ def bad_prc.to_s
211
+ "to_s 4".freeze
212
+ end
213
+ bad_prc.freeze
260
214
 
261
- # Output stream that conforms to the expected interface.
215
+ # A mix of tests that raise errors and tests that return. Freeze the array
216
+ # to check that it's not being modified.
217
+ source = [fail_prc1, pass_prc, fail_prc2, non_prc, bad_prc].freeze
218
+
219
+ # An output stream that conforms to the expected interface and does not
220
+ # raise an exception should receive all failure information.
262
221
  spy_ostream = Object.new
263
222
  spy_ostream.instance_variable_set :@_test_calls, calls = []
264
223
  def spy_ostream.puts *args
265
224
  @_test_calls << args
266
- nil
225
+ # A real standard output stream would return nil here (and spy_stdout
226
+ # does that), but Blackstart.run's behavior should not be affected by the
227
+ # returned object. Returning this unusual object tests that.
228
+ ::Object.new
267
229
  end
230
+ # Freeze the output stream to check that it's not being modified.
231
+ spy_ostream.freeze
268
232
  fail "" unless false.equal? Blackstart.run(source, spy_ostream)
269
233
  fail "" unless 0 == stdout_calls.length
270
- fail "" unless 2 == calls.length
234
+ fail "" unless 4 == calls.length
271
235
  fail "" unless 5 == calls[0].length
236
+ fail "" unless calls[0].all? { |o| ::String.equal? o.class }
272
237
  fail "" unless "FAILED TEST:" == calls[0][0]
273
238
  fail "" unless "to_s 1" == calls[0][1]
274
239
  fail "" unless "...ERROR:" == calls[0][2]
275
- fail "" unless /\AFakeError: fake message 1$/ =~ calls[0][3]
240
+ fail "" unless "FakeError: fake message 1\nline1\nline2" == calls[0][3]
276
241
  fail "" unless "" == calls[0][4]
277
242
  fail "" unless 5 == calls[1].length
243
+ fail "" unless calls[1].all? { |o| ::String.equal? o.class }
278
244
  fail "" unless "FAILED TEST:" == calls[1][0]
279
245
  fail "" unless "to_s 2" == calls[1][1]
280
246
  fail "" unless "...ERROR:" == calls[1][2]
281
- fail "" unless /\AFakeError: fake message 2$/ =~ calls[1][3]
247
+ fail "" unless "FakeError: fake message 2\nline1\nline2" == calls[1][3]
282
248
  fail "" unless "" == calls[1][4]
283
- spy_ostream = calls = nil
284
-
285
- # Default output stream.
249
+ fail "" unless 5 == calls[2].length
250
+ fail "" unless calls[2].all? { |o| ::String.equal? o.class }
251
+ fail "" unless "FAILED TEST:" == calls[2][0]
252
+ fail "" unless "to_s 3" == calls[2][1]
253
+ fail "" unless "...ERROR:" == calls[2][2]
254
+ # (No need to check the error description.)
255
+ fail "" unless "" == calls[2][4]
256
+ fail "" unless 5 == calls[3].length
257
+ fail "" unless calls[3].all? { |o| ::String.equal? o.class }
258
+ fail "" unless "FAILED TEST:" == calls[3][0]
259
+ fail "" unless "to_s 4" == calls[3][1]
260
+ fail "" unless "...ERROR:" == calls[3][2]
261
+ # (No need to check the error description.)
262
+ fail "" unless "" == calls[3][4]
263
+
264
+ # The faked standard output stream.
286
265
  stdout_calls.clear
287
266
  fail "" unless false.equal? Blackstart.run(source)
288
- fail "" unless 2 == stdout_calls.length
267
+ fail "" unless 4 == stdout_calls.length
289
268
  fail "" unless 5 == stdout_calls[0].length
269
+ fail "" unless stdout_calls[0].all? { |o| ::String.equal? o.class }
290
270
  fail "" unless "FAILED TEST:" == stdout_calls[0][0]
291
271
  fail "" unless "to_s 1" == stdout_calls[0][1]
292
272
  fail "" unless "...ERROR:" == stdout_calls[0][2]
293
- fail "" unless /\AFakeError: fake message 1$/ =~ stdout_calls[0][3]
273
+ fail "" unless "FakeError: fake message 1\nline1\nline2" ==
274
+ stdout_calls[0][3]
294
275
  fail "" unless "" == stdout_calls[0][4]
295
276
  fail "" unless 5 == stdout_calls[1].length
277
+ fail "" unless stdout_calls[1].all? { |o| ::String.equal? o.class }
296
278
  fail "" unless "FAILED TEST:" == stdout_calls[1][0]
297
279
  fail "" unless "to_s 2" == stdout_calls[1][1]
298
280
  fail "" unless "...ERROR:" == stdout_calls[1][2]
299
- fail "" unless /\AFakeError: fake message 2$/ =~ stdout_calls[1][3]
281
+ fail "" unless "FakeError: fake message 2\nline1\nline2" ==
282
+ stdout_calls[1][3]
300
283
  fail "" unless "" == stdout_calls[1][4]
284
+ fail "" unless 5 == stdout_calls[2].length
285
+ fail "" unless stdout_calls[2].all? { |o| ::String.equal? o.class }
286
+ fail "" unless "FAILED TEST:" == stdout_calls[2][0]
287
+ fail "" unless "to_s 3" == stdout_calls[2][1]
288
+ fail "" unless "...ERROR:" == stdout_calls[2][2]
289
+ # (No need to check the error description.)
290
+ fail "" unless "" == stdout_calls[2][4]
291
+ fail "" unless 5 == stdout_calls[3].length
292
+ fail "" unless stdout_calls[3].all? { |o| ::String.equal? o.class }
293
+ fail "" unless "FAILED TEST:" == stdout_calls[3][0]
294
+ fail "" unless "to_s 4" == stdout_calls[3][1]
295
+ fail "" unless "...ERROR:" == stdout_calls[3][2]
296
+ # (No need to check the error description.)
297
+ fail "" unless "" == stdout_calls[3][4]
301
298
  stdout_calls.clear
302
299
 
303
- # Test that raises a non-StandardError exception. (And in general, the only
304
- # exceptions Blackstart.run should rescue are StandardError exceptions
305
- # raised by tests.)
306
- non_standard_error = Class.new Exception
307
- source = [proc { ::Kernel.raise non_standard_error }]
300
+ # An output stream that raises an exception when notified of a failure
301
+ # should cause Blackstart.run to raise that exception and stop processing
302
+ # tests. (In general, the only exceptions Blackstart.run should rescue are
303
+ # StandardError exceptions raised by tests.)
304
+ second_test_run = false
305
+ source = [lambda { ::Kernel.raise "" }, lambda { second_test_run = true }]
308
306
  begin
309
- Blackstart.run source, spy_stdout
310
- rescue non_standard_error
307
+ Blackstart.run source, invalid_ostream
308
+ rescue NoMethodError
311
309
  else
312
310
  fail ""
313
311
  end
312
+ fail "" if second_test_run
314
313
  fail "" unless 0 == stdout_calls.length
315
314
 
316
- # Test sequence that does not conform to the interface. (And in general,
317
- # the only exceptions Blackstart.run should rescue are StandardError
318
- # exceptions raised by tests.)
315
+ # When a test raises a non-StandardError exception, Blackstart.run should
316
+ # raise that exception and stop processing tests. (In general, the only
317
+ # exceptions Blackstart.run should rescue are StandardError exceptions
318
+ # raised by tests.)
319
+ second_test_run = false
320
+ non_standard_error = Class.new Exception
321
+ source = [lambda { ::Kernel.raise non_standard_error },
322
+ lambda { second_test_run = true }]
319
323
  begin
320
- Blackstart.run nil, spy_stdout
321
- rescue NoMethodError
324
+ Blackstart.run source, spy_stdout
325
+ rescue non_standard_error
322
326
  else
323
327
  fail ""
324
328
  end
329
+ fail "" if second_test_run
325
330
  fail "" unless 0 == stdout_calls.length
326
331
 
327
- # Test sequences containing objects that do not convert to procs (and do
328
- # not pretend to) and objects that pretend to convert to procs but do not.
329
- # (And in general, the only exceptions Blackstart.run should rescue are
332
+ # When the test sequence does not conform to the interface and raises an
333
+ # exception during iteration, Blackstart.run should raise that exception.
334
+ # (In general, the only exceptions Blackstart.run should rescue are
330
335
  # StandardError exceptions raised by tests.)
331
- source = [nil]
332
- begin
333
- Blackstart.run source, spy_stdout
334
- rescue ArgumentError
335
- else
336
- fail ""
336
+ source = Object.new
337
+ def source.each(*)
338
+ ::Kernel.raise ::NoMethodError
337
339
  end
338
- source = [0]
339
340
  begin
340
341
  Blackstart.run source, spy_stdout
341
- rescue TypeError
342
+ rescue NoMethodError
342
343
  else
343
344
  fail ""
344
345
  end
345
- bad_to_proc = Object.new
346
- def bad_to_proc.to_proc
347
- nil
346
+ fail "" unless 0 == stdout_calls.length
347
+
348
+ # When a test fails and converting the test object to a string raises an
349
+ # exception, Blackstart.run should raise that exception and stop processing
350
+ # tests. (In general, the only exceptions Blackstart.run should rescue are
351
+ # StandardError exceptions raised by tests.)
352
+ second_test_run = false
353
+ no_desc = lambda { ::Kernel.raise "" }
354
+ def no_desc.to_s
355
+ ::Kernel.raise ::NoMethodError
348
356
  end
349
- source = [bad_to_proc]
357
+ source = [no_desc, lambda { second_test_run = true }]
350
358
  begin
351
359
  Blackstart.run source, spy_stdout
352
- rescue TypeError
360
+ rescue NoMethodError
353
361
  else
354
362
  fail ""
355
363
  end
364
+ fail "" if second_test_run
356
365
  fail "" unless 0 == stdout_calls.length
357
366
  ensure
358
367
  $stdout = original_stdout
359
368
  end
360
369
  end
361
370
 
371
+ # Blackstart.run should run tests in order.
372
+ class ::Object
373
+ data = []
374
+ Blackstart.run [lambda { data << 1 }, lambda { data << 2 }], nil
375
+ fail "" unless [1, 2] == data
376
+ end
377
+
362
378
  # Blackstart.run should call each test proc with no arguments.
363
379
  class ::Object
364
380
  args = nil
@@ -369,14 +385,55 @@ class ::Object
369
385
  fail "" unless [] == args
370
386
  end
371
387
 
372
- # Blackstart.run should call each test proc in the context of a unique instance
373
- # of Blackstart::Context.
388
+ # Blackstart.run should work with any source that responds to each. The object
389
+ # returned in response to the each message should not affect Blackstart.run's
390
+ # behavior.
374
391
  class ::Object
375
- context1 = context2 = nil
376
- Blackstart.run [proc { context1 = self }, proc { context2 = self }], nil
377
- fail "" unless Blackstart::Context.equal? context1.class
378
- fail "" unless Blackstart::Context.equal? context2.class
379
- fail "" if context1.equal? context2
392
+ source = Object.new
393
+ def source.each
394
+ ran = false
395
+ yield lambda { ran = true }
396
+ @ran = ran
397
+ self
398
+ end
399
+ fail "" unless true.equal? Blackstart.run(source, nil)
400
+ fail "" unless source.instance_variable_get :@ran
401
+
402
+ source = Object.new
403
+ def source.each
404
+ yield lambda {}
405
+ nil
406
+ end
407
+ fail "" unless true.equal? Blackstart.run(source, nil)
408
+ end
409
+
410
+ # Blackstart.run should send exactly one each message to the source.
411
+ class ::Object
412
+ source = Object.new
413
+ source.instance_variable_set :@count, 0
414
+ def source.each
415
+ @count += 1
416
+ self
417
+ end
418
+ Blackstart.run source, nil
419
+ fail "" unless 1 == source.instance_variable_get(:@count)
420
+ end
421
+
422
+ # When Blackstart.run calls a test proc, the self object should be a unique
423
+ # instance of Blackstart::Scratchpad.
424
+ class ::Object
425
+ sp1 = sp2 = nil
426
+ Blackstart.run [lambda { sp1 = self }, lambda { sp2 = self }], nil
427
+ fail "" unless Blackstart::Scratchpad.equal? sp1.class
428
+ fail "" unless Blackstart::Scratchpad.equal? sp2.class
429
+ fail "" if sp1.equal? sp2
430
+ end
431
+
432
+ # When Blackstart.run runs a test, the scratchpad should not be frozen.
433
+ class ::Object
434
+ frozen = true
435
+ Blackstart.run [lambda { frozen = frozen? }], nil
436
+ fail "" if frozen
380
437
  end
381
438
 
382
439
  # Blackstart.run should raise an exception if too few or too many non-block
@@ -387,11 +444,34 @@ rescue ArgumentError
387
444
  else
388
445
  fail ""
389
446
  end
390
- begin
391
- Blackstart.run [], nil, "invalid"
392
- rescue ArgumentError
393
- else
394
- fail ""
447
+ class ::Object
448
+ source = []
449
+ begin
450
+ Blackstart.run source, nil, nil
451
+ rescue ArgumentError
452
+ else
453
+ fail ""
454
+ end
455
+ end
456
+
457
+ # The following section modifies the state of the library, so it must be run
458
+ # after all the ordinary tests.
459
+
460
+ # Blackstart.run should run each test by sending instance_exec to a scratchpad.
461
+ class Blackstart::Scratchpad
462
+ def foo
463
+ 2
464
+ end
465
+
466
+ def instance_exec(*)
467
+ @ivar = 1
468
+ super
469
+ end
470
+ end
471
+ class ::Object
472
+ result = nil
473
+ Blackstart.run [lambda { result = [@ivar, foo()] }], nil
474
+ fail "" unless [1, 2] == result
395
475
  end
396
476
 
397
477
  # If this message doesn't get written, there was a problem.