whitestone 1.0.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/.gitignore +1 -0
- data/Gemfile +4 -0
- data/LICENSE +16 -0
- data/README.txt +78 -0
- data/Rakefile +1 -0
- data/bin/whitestone +263 -0
- data/doc/README-snippets.rdoc +58 -0
- data/doc/whitestone.markdown +806 -0
- data/etc/aliases +5 -0
- data/etc/examples/example_1.rb +51 -0
- data/etc/examples/example_2.rb +51 -0
- data/etc/extra_tests/basic.rb +56 -0
- data/etc/extra_tests/error_should_not_also_fail.rb +17 -0
- data/etc/extra_tests/output_examples.rb +108 -0
- data/etc/extra_tests/output_examples_code.rb +38 -0
- data/etc/extra_tests/raise.rb +4 -0
- data/etc/extra_tests/realistic_example.rb +94 -0
- data/etc/extra_tests/specification_error.rb +8 -0
- data/etc/extra_tests/stop.rb +16 -0
- data/etc/extra_tests/terminate_suite.rb +56 -0
- data/etc/run-output-examples +1 -0
- data/etc/run-unit-tests +1 -0
- data/etc/ws +1 -0
- data/lib/whitestone.rb +710 -0
- data/lib/whitestone/assertion_classes.rb +418 -0
- data/lib/whitestone/auto.rb +20 -0
- data/lib/whitestone/custom_assertions.rb +252 -0
- data/lib/whitestone/include.rb +14 -0
- data/lib/whitestone/output.rb +335 -0
- data/lib/whitestone/support.rb +29 -0
- data/lib/whitestone/version.rb +3 -0
- data/test/_setup.rb +5 -0
- data/test/custom_assertions.rb +120 -0
- data/test/insulation.rb +202 -0
- data/test/whitestone_test.rb +616 -0
- data/whitestone.gemspec +31 -0
- metadata +125 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
# A convenient way to include the Whitestone methods like T, Eq, etc. in the top
|
3
|
+
# level.
|
4
|
+
#
|
5
|
+
# Long way:
|
6
|
+
# require 'whitestone'
|
7
|
+
# include Whitestone
|
8
|
+
#
|
9
|
+
# Short way:
|
10
|
+
# require 'whitestone/include'
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'whitestone'
|
14
|
+
include Whitestone
|
@@ -0,0 +1,335 @@
|
|
1
|
+
|
2
|
+
require 'stringio'
|
3
|
+
require 'col'
|
4
|
+
|
5
|
+
module Whitestone
|
6
|
+
|
7
|
+
# --------------------------------------------------------------section---- #
|
8
|
+
# #
|
9
|
+
# Whitestone::Output #
|
10
|
+
# #
|
11
|
+
# Contains all code that writes to the console #
|
12
|
+
# #
|
13
|
+
# ------------------------------------------------------------------------- #
|
14
|
+
|
15
|
+
class Output
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
# @buf is the buffer into which we write details of errors and failures so
|
19
|
+
# that they can be emitted to the console all together.
|
20
|
+
@buf = StringIO.new
|
21
|
+
# @@files is a means of printing lines of code in failure and error
|
22
|
+
# details.
|
23
|
+
@@files ||= Hash.new { |h,k| h[k] = File.readlines(k) rescue nil }
|
24
|
+
@filter_backtrace_yn = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_full_backtrace
|
28
|
+
@filter_backtrace_yn = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def Output.relative_path(path)
|
32
|
+
@current_dir ||= Dir.pwd
|
33
|
+
path.sub(@current_dir, '.')
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
##
|
39
|
+
# Print the name and result of each test, using indentation.
|
40
|
+
# This must be done after execution is finished in order to get the tree
|
41
|
+
# structure right.
|
42
|
+
def display_test_by_test_result(top_level)
|
43
|
+
pipe = "|"
|
44
|
+
space = " "
|
45
|
+
#empty_line = space + pipe + (space * 76) + pipe
|
46
|
+
header = Col[" +----- Report " + "-" * (77-14) + "+"].cb
|
47
|
+
empty_line = Col[space, pipe, space * 76, pipe].fmt(:_, :cb, :_, :cb)
|
48
|
+
line = lambda { |desc,c1,s1,result,c2,s2|
|
49
|
+
padding = space * ( 77 - (1 + desc.size + result.size ) )
|
50
|
+
Col.inline( space, :_, pipe, :cb, desc, [c1,s1], \
|
51
|
+
result, [c2,s2], padding, :_, pipe, :cb)
|
52
|
+
}
|
53
|
+
footer = Col[" +#{'-'*76}+"].cb
|
54
|
+
|
55
|
+
puts
|
56
|
+
puts header
|
57
|
+
|
58
|
+
tree_walk(top_level.tests) do |test, level|
|
59
|
+
description = (space + space + " " * level + test.description).ljust(67)
|
60
|
+
description = description[0...67]
|
61
|
+
colour1, style1 =
|
62
|
+
case test.result
|
63
|
+
when :pass then [:_, :_]
|
64
|
+
when :fail then [:red, :bold]
|
65
|
+
when :error then [:magenta, :bold]
|
66
|
+
when :blank then [:_, :_]
|
67
|
+
end
|
68
|
+
result, colour2, style2 =
|
69
|
+
case test.result
|
70
|
+
when :pass then ['PASS', :green, :bold]
|
71
|
+
when :fail then ['FAIL', :red, :bold]
|
72
|
+
when :error then ['ERROR', :magenta, :bold]
|
73
|
+
when :blank then ['-', :green, :bold]
|
74
|
+
end
|
75
|
+
result = " " + result
|
76
|
+
if level == 0
|
77
|
+
puts empty_line
|
78
|
+
colour1 = (test.passed? or test.blank?) ? :yellow : colour2
|
79
|
+
style1 = :bold
|
80
|
+
end
|
81
|
+
puts line[description, colour1, style1, result, colour2, style2]
|
82
|
+
end
|
83
|
+
|
84
|
+
puts empty_line
|
85
|
+
puts footer
|
86
|
+
end
|
87
|
+
|
88
|
+
# Yield each test and its children (along with the current level 0,1,2,...)
|
89
|
+
# in depth-first order.
|
90
|
+
def tree_walk(tests, level=0, &block)
|
91
|
+
tests.each do |test|
|
92
|
+
block.call(test, level)
|
93
|
+
unless test.children.empty?
|
94
|
+
tree_walk( test.children, level+1, &block )
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
private :tree_walk
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
def display_details_of_failures_and_errors
|
103
|
+
unless @buf.string.strip.empty?
|
104
|
+
puts
|
105
|
+
puts @buf.string
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
# Prepares and displays a colourful summary message saying how many tests
|
112
|
+
# have passed, failed and errored.
|
113
|
+
def display_results_npass_nfail_nerror_etc(stats)
|
114
|
+
npass = stats[:pass] || 0
|
115
|
+
nfail = stats[:fail] || 0
|
116
|
+
nerror = stats[:error] || 0
|
117
|
+
overall = (nfail + nerror > 0) ? :FAIL : :PASS
|
118
|
+
time = stats[:time]
|
119
|
+
assertions = stats[:assertions]
|
120
|
+
|
121
|
+
overall_str = overall.to_s.ljust(9)
|
122
|
+
npass_str = sprintf "#pass: %-6d", npass
|
123
|
+
nfail_str = sprintf "#fail: %-6d", nfail
|
124
|
+
nerror_str = sprintf "#error: %-6d", nerror
|
125
|
+
assertions_str = sprintf "assertions: %-6d", assertions
|
126
|
+
time_str = sprintf "time: %3.3f", time
|
127
|
+
|
128
|
+
overall_col = (overall == :PASS) ? :green : :red
|
129
|
+
npass_col = :green
|
130
|
+
nfail_col = (nfail > 0) ? :red : :green
|
131
|
+
nerror_col = (nerror > 0) ? :magenta : :green
|
132
|
+
assertions_col = :white
|
133
|
+
time_col = :white
|
134
|
+
|
135
|
+
coloured_info = Col.inline(
|
136
|
+
overall_str, [overall_col, :bold],
|
137
|
+
npass_str, [npass_col, :bold],
|
138
|
+
nfail_str, [nfail_col, :bold],
|
139
|
+
nerror_str, [nerror_col, :bold],
|
140
|
+
assertions_str, [assertions_col, :bold],
|
141
|
+
time_str, [time_col, :bold]
|
142
|
+
)
|
143
|
+
|
144
|
+
equals = Col["=" * 80].fmt [overall_col, :bold]
|
145
|
+
nl = "\n"
|
146
|
+
|
147
|
+
output = String.new.tap { |str|
|
148
|
+
str << equals << nl
|
149
|
+
str << " " << coloured_info << nl
|
150
|
+
str << equals << nl
|
151
|
+
}
|
152
|
+
|
153
|
+
puts
|
154
|
+
puts output
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
def report_failure(description, message, backtrace)
|
160
|
+
message ||= "No message! #{__FILE__}:#{__LINE__}"
|
161
|
+
bp = BacktraceProcessor.new(backtrace, @filter_backtrace_yn)
|
162
|
+
|
163
|
+
# Determine the file and line number of the failed assertion, and extract
|
164
|
+
# the code surrounding that line.
|
165
|
+
file, line = bp.determine_file_and_lineno()
|
166
|
+
code = extract_code(file, line)
|
167
|
+
|
168
|
+
# Emit the failure report.
|
169
|
+
@buf.puts
|
170
|
+
@buf.puts Col["FAIL: #{description}"].rb
|
171
|
+
@buf.puts code.___indent(4) if code
|
172
|
+
@buf.puts message.___indent(2)
|
173
|
+
@buf.puts " Backtrace\n" + bp.backtrace.join("\n").___indent(4)
|
174
|
+
end # report_failure
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
def report_uncaught_exception(description, exception, _calls, force_filter_bt=false)
|
179
|
+
filter_yn = @filter_backtrace_yn || force_filter_bt
|
180
|
+
bp = BacktraceProcessor.new(exception.backtrace, filter_yn)
|
181
|
+
|
182
|
+
# Determine the current test file, the line number that triggered the
|
183
|
+
# error, and extract the code surrounding that line.
|
184
|
+
file, line = bp.determine_file_and_lineno(_calls)
|
185
|
+
code = extract_code(file, line)
|
186
|
+
|
187
|
+
# Emit the error report.
|
188
|
+
@buf.puts
|
189
|
+
@buf.puts Col("ERROR: #{description}").fmt(:mb)
|
190
|
+
@buf.puts code.___indent(4) if code
|
191
|
+
@buf.puts Col.inline(" Class: ", :mb, exception.class, :yb)
|
192
|
+
@buf.puts Col.inline(" Message: ", :mb, exception.message, :yb)
|
193
|
+
@buf.puts " Backtrace\n" + bp.backtrace.join("\n").___indent(4)
|
194
|
+
end # report_uncaught_exception
|
195
|
+
|
196
|
+
|
197
|
+
|
198
|
+
def report_specification_error(e)
|
199
|
+
puts
|
200
|
+
puts "You have made an error in specifying one of your assertions."
|
201
|
+
puts "Details below; can't continue; exiting."
|
202
|
+
puts
|
203
|
+
puts Col.inline("Message: ", :_, e.message, :yb)
|
204
|
+
puts
|
205
|
+
puts "Filtered backtrace:"
|
206
|
+
filtered = BacktraceProcessor.new(e.backtrace, true).backtrace
|
207
|
+
puts filtered.join("\n").___indent(2)
|
208
|
+
puts
|
209
|
+
puts "Full backtrace:"
|
210
|
+
puts e.backtrace.join("\n").___indent(2)
|
211
|
+
puts
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
|
216
|
+
def extract_code(file, line)
|
217
|
+
return nil if file.nil? or line.nil? or file == "(eval)"
|
218
|
+
if source = @@files[file]
|
219
|
+
line = line.to_i
|
220
|
+
radius = 2 # number of surrounding lines to show
|
221
|
+
region1 = [line - radius, 1].max .. [line - 1, 1].max
|
222
|
+
region2 = [line]
|
223
|
+
region3 = [line + 1, source.length].min .. [line + radius, source.length].min
|
224
|
+
|
225
|
+
# ensure proper alignment by zero-padding line numbers
|
226
|
+
format = "%2s %0#{region3.last.to_s.length}d %s"
|
227
|
+
|
228
|
+
pretty1 = region1.map { |n|
|
229
|
+
format % [nil, n, source[n-1].chomp.___truncate(60)]
|
230
|
+
}
|
231
|
+
pretty2 = region2.map { |n|
|
232
|
+
string = format % ['=>', n, source[n-1].chomp.___truncate(60)]
|
233
|
+
Col[string].fmt(:yb)
|
234
|
+
}
|
235
|
+
pretty3 = region3.map { |n|
|
236
|
+
format % [nil, n, source[n-1].chomp.___truncate(60)]
|
237
|
+
}
|
238
|
+
pretty = pretty1 + pretty2 + pretty3
|
239
|
+
|
240
|
+
pretty.unshift Col[Output.relative_path(file)].y
|
241
|
+
|
242
|
+
pretty.join("\n")
|
243
|
+
end
|
244
|
+
end # extract_code
|
245
|
+
private :extract_code
|
246
|
+
|
247
|
+
end # module Output
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
# --------------------------------------------------------------section---- #
|
252
|
+
# #
|
253
|
+
# Output::BacktraceProcessor #
|
254
|
+
# #
|
255
|
+
# ------------------------------------------------------------------------- #
|
256
|
+
|
257
|
+
class Output
|
258
|
+
class BacktraceProcessor
|
259
|
+
INTERNALS_RE = (
|
260
|
+
libdir = File.dirname(__FILE__)
|
261
|
+
bindir = "bin/whitestone"
|
262
|
+
Regexp.union(libdir, bindir)
|
263
|
+
)
|
264
|
+
|
265
|
+
def initialize(backtrace, filter_yn)
|
266
|
+
@backtrace = filter(backtrace, filter_yn)
|
267
|
+
end
|
268
|
+
|
269
|
+
# +calls+ is an array of proc objects (scopes of the tests run so far,
|
270
|
+
# from top level to current nesting). The last of them is the context for
|
271
|
+
# the current test, like
|
272
|
+
#
|
273
|
+
# #<Proc:0x10b7b1b8@./test/shape/triangle/construct/various.rb:52>
|
274
|
+
#
|
275
|
+
# From this, we determine the current test file. _Then_ we look in the
|
276
|
+
# backtrace for the last mention of that test file. That stack frame,
|
277
|
+
# from the backtrace, tells us what line of code in the test file caused
|
278
|
+
# the failure/error.
|
279
|
+
#
|
280
|
+
# If _calls_ is not provided, we simply take the first frame of the
|
281
|
+
# backtrace. That will happen when reporting a _failure_. A failure is
|
282
|
+
# simply a false assertion, so no stack unwinding is necessary.
|
283
|
+
#
|
284
|
+
# If no appropriate frame is found (not sure why that would be), then the
|
285
|
+
# return values will be nil.
|
286
|
+
#
|
287
|
+
# Return:: file (String) and line number (Integer)
|
288
|
+
def determine_file_and_lineno(calls=nil)
|
289
|
+
frame =
|
290
|
+
if calls
|
291
|
+
current_test_file = calls.last.to_s.scan(/@(.+?):/).flatten.first
|
292
|
+
@backtrace.find { |str| str.index(current_test_file) }
|
293
|
+
else
|
294
|
+
@backtrace.first
|
295
|
+
end
|
296
|
+
file, line =
|
297
|
+
if frame
|
298
|
+
file, line = frame.scan(/(.+?):(\d+(?=:|\z))/).first
|
299
|
+
[file, line.to_i]
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
# Returns the backtrace (array of strings) with all paths converted to
|
304
|
+
# relative paths (where possible).
|
305
|
+
def backtrace
|
306
|
+
make_relative(@backtrace)
|
307
|
+
end
|
308
|
+
|
309
|
+
def filter(backtrace, filter_yn)
|
310
|
+
# TODO: remove (or update and move) following comment.
|
311
|
+
#
|
312
|
+
# It's up to the user whether we filter backtraces. That's set in
|
313
|
+
# @filter_backtrace_yn. However, there are times when it makes sense to
|
314
|
+
# _force_ a filter (if an AssertionSpecificationError is raised). That's
|
315
|
+
# what the parameter force_filter is for; it can override
|
316
|
+
# @filter_backtrace_yn.
|
317
|
+
if filter_yn
|
318
|
+
backtrace.reject { |str| str =~ INTERNALS_RE }.uniq
|
319
|
+
else
|
320
|
+
backtrace.dup
|
321
|
+
end
|
322
|
+
end
|
323
|
+
private :filter
|
324
|
+
|
325
|
+
# Turn absolute paths into relative paths if possible, to save space and
|
326
|
+
# ease reading.
|
327
|
+
def make_relative(backtrace)
|
328
|
+
backtrace.map { |path| Output.relative_path(path) }
|
329
|
+
end
|
330
|
+
private :make_relative
|
331
|
+
|
332
|
+
end # class BacktraceProcessor
|
333
|
+
end # module Output
|
334
|
+
end # module Whitestone
|
335
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
class String
|
3
|
+
|
4
|
+
def ___indent(n)
|
5
|
+
if n >= 0
|
6
|
+
gsub(/^/, ' ' * n)
|
7
|
+
else
|
8
|
+
gsub(/^ {0,#{-n}}/, "")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def ___truncate(n)
|
13
|
+
str = self
|
14
|
+
if str.length > n
|
15
|
+
str[0...n] + "..."
|
16
|
+
else
|
17
|
+
str
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def ___margin # adapted from 'facets' project
|
22
|
+
d = ((/\A.*\n\s*(.)/.match(self)) ||
|
23
|
+
(/\A\s*(.)/.match(self)))[1]
|
24
|
+
return '' unless d
|
25
|
+
gsub(/\n\s*\Z/,'').gsub(/^\s*[#{d}]/, '')
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
data/test/_setup.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
# In this test file, we create a simple Person class so that we have something
|
4
|
+
# to test custom assertions on.
|
5
|
+
#
|
6
|
+
# We implement CSV parsing to give a little realism to the scenario:
|
7
|
+
# * we have a domain object (Person)
|
8
|
+
# * we expect to create a lot of these in some way (CSV) and that these
|
9
|
+
# objects will play a large part in our system
|
10
|
+
# * we will therefore need to check the correctness of lots of these objects
|
11
|
+
# * therefore, a custom assertion is handy
|
12
|
+
|
13
|
+
# Person consists of name (first, middle, last) and date of birth.
|
14
|
+
# Create them directly via Person.new(...) or indirectly by Person.from_csv "..."
|
15
|
+
class Person
|
16
|
+
attr_accessor :first, :middle, :last
|
17
|
+
attr_accessor :dob
|
18
|
+
def initialize(f, m, l, dob)
|
19
|
+
@first, @middle, @last, @dob = f, m, l, dob
|
20
|
+
end
|
21
|
+
# Reads multiple lines of CSV and returns an array of Person objects.
|
22
|
+
def Person.from_csv(text)
|
23
|
+
text.strip.split("\n").map { |line|
|
24
|
+
f, m, l, dob = line.strip.split(",")
|
25
|
+
m = nil if m.empty?
|
26
|
+
dob = Date.parse(dob)
|
27
|
+
Person.new(f,m,l,dob)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
D "Custom assertions" do
|
33
|
+
D "Create :person custom assertion" do
|
34
|
+
E! do
|
35
|
+
Whitestone.custom :person, {
|
36
|
+
:description => "Person equality",
|
37
|
+
:parameters => [ [:person, Person], [:string, String] ],
|
38
|
+
:run => proc {
|
39
|
+
f, m, l, dob = string.split
|
40
|
+
m = nil if m == '-'
|
41
|
+
dob = Date.parse(dob)
|
42
|
+
test('first') { Eq person.first, f }
|
43
|
+
test('middle') { Eq person.middle, m }
|
44
|
+
test('last') { Eq person.last, l }
|
45
|
+
test('dob') { Eq person.dob, dob }
|
46
|
+
}
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
D "Use :person custom assertion" do
|
52
|
+
D.< do
|
53
|
+
@people = Person.from_csv %{
|
54
|
+
John,William,Smith,1974-03-19
|
55
|
+
Jane,,Galois,1941-12-23
|
56
|
+
Hans,Dieter,Flich,1963-11-01,
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
D "manual check that people were created properly" do
|
61
|
+
person = @people[1]
|
62
|
+
Eq person.first, "Jane"
|
63
|
+
N person.middle
|
64
|
+
Eq person.last, "Galois"
|
65
|
+
Eq person.dob, Date.new(1941,12,23)
|
66
|
+
end
|
67
|
+
|
68
|
+
D "check all three people using :person custom assertion" do
|
69
|
+
T :person, @people[0], 'John William Smith 1974-03-19'
|
70
|
+
T :person, @people[1], 'Jane - Galois 1941-12-23'
|
71
|
+
T :person, @people[2], 'Hans Dieter Flich 1963-11-01'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
D "correct message when a failure occurs" do
|
76
|
+
@c = Term::ANSIColor
|
77
|
+
D.< do
|
78
|
+
@person = Person.new("Terrence", "James", "Hu", Date.new(1981,10,27))
|
79
|
+
end
|
80
|
+
D "in 'first' field" do
|
81
|
+
# In testing this person object, we'll accidentally mispell the first name,
|
82
|
+
# expect an error, and check that the message identifies the field ("first").
|
83
|
+
E { T :person, @person, "Terence James Hu 1981-10-27" }
|
84
|
+
Ko Whitestone.exception, Whitestone::FailureOccurred
|
85
|
+
message = @c.uncolored(Whitestone.exception.message)
|
86
|
+
Mt message, /Person equality test failed: first \(details below\)/
|
87
|
+
end
|
88
|
+
D "in 'middle' field" do
|
89
|
+
E { T :person, @person, "Terrence Janes Hu 1981-10-27" }
|
90
|
+
Ko Whitestone.exception, Whitestone::FailureOccurred
|
91
|
+
message = @c.uncolored(Whitestone.exception.message)
|
92
|
+
Mt message, /Person equality test failed: middle \(details below\)/
|
93
|
+
end
|
94
|
+
D "in 'last' field" do
|
95
|
+
E { T :person, @person, "Terrence James Hux 1981-10-27" }
|
96
|
+
Ko Whitestone.exception, Whitestone::FailureOccurred
|
97
|
+
message = @c.uncolored(Whitestone.exception.message)
|
98
|
+
Mt message, /Person equality test failed: last \(details below\)/
|
99
|
+
end
|
100
|
+
D "in 'dob' field" do
|
101
|
+
E { T :person, @person, "Terrence James Hu 1993-02-28" }
|
102
|
+
Ko Whitestone.exception, Whitestone::FailureOccurred
|
103
|
+
message = @c.uncolored(Whitestone.exception.message)
|
104
|
+
Mt message, /Person equality test failed: dob \(details below\)/
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
D "check correct number of assertions" do
|
109
|
+
# We are checking that the three 'T :person' assertions above only count as
|
110
|
+
# three assertions, that their consituent primitive assertions are not added
|
111
|
+
# to the total.
|
112
|
+
person = Person.new("Henrietta", nil, "Evangalier", Date.parse('2002-04-09'))
|
113
|
+
assertions = Whitestone.stats[:assertions]
|
114
|
+
T :person, person, "Henrietta - Evangalier 2002-04-09"
|
115
|
+
T :person, person, "Henrietta - Evangalier 2002-04-09"
|
116
|
+
T :person, person, "Henrietta - Evangalier 2002-04-09"
|
117
|
+
assertions = Whitestone.stats[:assertions] - assertions
|
118
|
+
Eq assertions, 3
|
119
|
+
end
|
120
|
+
end
|