whitestone 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/etc/aliases
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
# This example runs some tests against the Date class. All of them pass.
|
3
|
+
# The Date class is large and complex; this barely scratches the surface.
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
D "Date" do
|
8
|
+
|
9
|
+
D.< { # setup for each block
|
10
|
+
@d = Date.new(1972, 5, 13)
|
11
|
+
}
|
12
|
+
|
13
|
+
D "#to_s" do
|
14
|
+
Eq @d.to_s, "1972-05-13"
|
15
|
+
end
|
16
|
+
|
17
|
+
D "#next" do
|
18
|
+
end_of_april = Date.new(2010, 4, 30)
|
19
|
+
start_of_may = Date.new(2010, 5, 1)
|
20
|
+
T { end_of_april.next == start_of_may }
|
21
|
+
end
|
22
|
+
|
23
|
+
D "day, month, year, week, day-of-year, etc." do
|
24
|
+
|
25
|
+
D.< { :extra_setup_for_these_three_blocks_if_required }
|
26
|
+
|
27
|
+
D "civil" do
|
28
|
+
Eq @d.year, 1972
|
29
|
+
Eq @d.month, 5
|
30
|
+
Eq @d.day, 13
|
31
|
+
end
|
32
|
+
D "commercial" do
|
33
|
+
Eq @d.cwyear, 1972
|
34
|
+
Eq @d.cweek, 19 # Commercial week-of-year
|
35
|
+
Eq @d.cwday, 6 # Commercial day-of-week (6 = Sat)
|
36
|
+
end
|
37
|
+
D "ordinal" do
|
38
|
+
Eq @d.yday, 134 # 134th day of the year
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
D "#leap?" do
|
43
|
+
[1984, 2000, 2400].each do |year|
|
44
|
+
T { Date.new(year, 6, 27).leap? }
|
45
|
+
end
|
46
|
+
[1900, 2007, 2100, 2401].each do |year|
|
47
|
+
F { Date.new(year, 12, 3).leap? }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
# This example is the same as Example 1, except that some bugs have
|
3
|
+
# been introduced into the test code so that some assertions will fail.
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
D "Date" do
|
8
|
+
|
9
|
+
D.< { # setup for each block
|
10
|
+
@d = Date.new(1972, 5, 13)
|
11
|
+
}
|
12
|
+
|
13
|
+
D "#to_s" do
|
14
|
+
Eq @d.to_s, "1972-5-13"
|
15
|
+
end
|
16
|
+
|
17
|
+
D "#next" do
|
18
|
+
end_of_april = Date.new(2010, 4, 30)
|
19
|
+
start_of_may = Date.new(2010, 6, 1)
|
20
|
+
T { end_of_april.next == start_of_may }
|
21
|
+
end
|
22
|
+
|
23
|
+
D "day, month, year, week, day-of-year, etc." do
|
24
|
+
|
25
|
+
D.< { :extra_setup_for_these_three_blocks_if_required }
|
26
|
+
|
27
|
+
D "civil" do
|
28
|
+
Eq @d.year, 1972
|
29
|
+
Eq @d.month, 5
|
30
|
+
Eq @d.day, 13
|
31
|
+
end
|
32
|
+
D "commercial" do
|
33
|
+
Eq @d.cwyear, 1972
|
34
|
+
Eq @d.cweek, 13 # Commercial week-of-year
|
35
|
+
Eq @d.cwday, 6 # Commercial day-of-week (6 = Sat)
|
36
|
+
end
|
37
|
+
D "ordinal" do
|
38
|
+
Eq @d.day_of_year, 134 # 134th day of the year
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
D "#leap?" do
|
43
|
+
[1984, 2000, 2400].each do |year|
|
44
|
+
T { Date.new(year, 6, 27).leap? }
|
45
|
+
end
|
46
|
+
[1900, 2007, 2100, 2401].each do |year|
|
47
|
+
F { Date.new(year, 12, 3).leap? }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
D "Whitestone.action" do
|
3
|
+
T { Whitestone.action :Eq, :query, 4, 4 }
|
4
|
+
T { Whitestone.action :T, :query, :foo }
|
5
|
+
T { Whitestone.action(:T, :query) { :foo } }
|
6
|
+
end
|
7
|
+
|
8
|
+
def this_method_will_raise_an_error
|
9
|
+
raise StandardError, "Sample error"
|
10
|
+
end
|
11
|
+
|
12
|
+
def this_one_wont
|
13
|
+
:foo
|
14
|
+
end
|
15
|
+
|
16
|
+
def throws_foo
|
17
|
+
throw :foo
|
18
|
+
end
|
19
|
+
|
20
|
+
def doesnt_throw_foo
|
21
|
+
:noop
|
22
|
+
end
|
23
|
+
|
24
|
+
def specific_error(sym)
|
25
|
+
case sym
|
26
|
+
when :type then raise TypeError
|
27
|
+
when :run then raise RuntimeError
|
28
|
+
when :range then raise RangeError
|
29
|
+
when :io then raise IOError
|
30
|
+
else raise ArgumentError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
D "Basic tests" do
|
35
|
+
x = 2 + 2
|
36
|
+
T { x == 4 }
|
37
|
+
T! { x == 5 }
|
38
|
+
F { x == 5 }
|
39
|
+
F! { x == 4 }
|
40
|
+
N { "foo".index("z") }
|
41
|
+
N! { "foo".index("o") }
|
42
|
+
Eq x, 4
|
43
|
+
Eq! x, 5
|
44
|
+
Mt /(an){2}/, "banana"
|
45
|
+
Mt! /(an){3}/, "banana"
|
46
|
+
E { this_method_will_raise_an_error }
|
47
|
+
E! { this_one_wont }
|
48
|
+
E!(RangeError) { this_one_wont }
|
49
|
+
E() { specific_error(:run) }
|
50
|
+
E(RuntimeError) { specific_error(:run) }
|
51
|
+
E(RuntimeError, IOError) { specific_error(:run) }
|
52
|
+
C(:foo) { throws_foo }
|
53
|
+
C!(:foo) { doesnt_throw_foo }
|
54
|
+
|
55
|
+
E!() { specific_error(:io) }
|
56
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
def some_method(n)
|
3
|
+
raise ArgumentError unless n > 0
|
4
|
+
n
|
5
|
+
end
|
6
|
+
|
7
|
+
D "An error should not also fail" do
|
8
|
+
## The following call should result in ERROR and not an additional FAIL.
|
9
|
+
## (This is therefore not a unit test, really; it's designed to error out...)
|
10
|
+
T { this_method_does_not_exist(:foo) }
|
11
|
+
|
12
|
+
## This test works
|
13
|
+
Eq some_method(5), 5
|
14
|
+
|
15
|
+
## This test errors out
|
16
|
+
Eq some_method(-5), -5
|
17
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
# The examples here are designed to demonstrate that all the different ways of
|
3
|
+
# failing (T, F, N, Eq, Mt, E, C) produce good output.
|
4
|
+
#
|
5
|
+
# Some of the tests will pass; some will fail; some will raise an error.
|
6
|
+
#
|
7
|
+
# The output doesn't make pretty reading, but it's a way to look for poor
|
8
|
+
# formatting or inconsistent colour or less-than-helpful error messages.
|
9
|
+
|
10
|
+
load "#{Dir.pwd}/etc/extra_tests/output_examples_code.rb"
|
11
|
+
|
12
|
+
D 'Vanilla assertion failure' do
|
13
|
+
T { prime? 64 }
|
14
|
+
end
|
15
|
+
|
16
|
+
D "Attempt to open file that doesn't exist" do
|
17
|
+
T { count_lines_in_file("fdsjhfaksljdfhakljshdf.txt") == 492 }
|
18
|
+
end
|
19
|
+
|
20
|
+
D 'Expected error to be raised but it didn\'t happen (default: StandardError)' do
|
21
|
+
E { prime? 13 }
|
22
|
+
end
|
23
|
+
|
24
|
+
D "Expected error to be raised but it didn't happen (specify errors)" do
|
25
|
+
E(ArgumentError, NameError) { prime? 99 }
|
26
|
+
end
|
27
|
+
|
28
|
+
D "Expect NameError to be raised but it's not NameError; it's Errno::ENOENT" do
|
29
|
+
E(NameError) { count_lines_in_file("fdsjhfakslljshdf.txt") }
|
30
|
+
end
|
31
|
+
|
32
|
+
D 'Expect no error to occur, but one does' do
|
33
|
+
E! { count_lines_in_file("fdsjhfaksljdfhakljshdf.txt") }
|
34
|
+
end
|
35
|
+
|
36
|
+
D 'Failure to catch appropriate symbol' do
|
37
|
+
C(:something) { Dir.entries('.') }
|
38
|
+
end
|
39
|
+
|
40
|
+
D 'Expected :even not to be thrown but it was' do
|
41
|
+
C!(:even) { even_or_odd(12) }
|
42
|
+
end
|
43
|
+
|
44
|
+
D 'Error raised while trying to catch a symbol' do
|
45
|
+
C(:foo) { count_lines_in_file("fdsjhfakshakljshdf.txt") }
|
46
|
+
end
|
47
|
+
|
48
|
+
D 'Test prime?' do
|
49
|
+
T { prime? 43 }
|
50
|
+
F { prime? 1 }
|
51
|
+
E { prime? 450 }
|
52
|
+
E { prime? 41.9 }
|
53
|
+
E!{ prime? 35 }
|
54
|
+
end
|
55
|
+
|
56
|
+
D 'Test even_or_odd' do
|
57
|
+
C(:even) { even_or_odd(148) }
|
58
|
+
C(:odd) { even_or_odd(9313) }
|
59
|
+
end
|
60
|
+
|
61
|
+
D 'Straightforward equality failure (positive)' do
|
62
|
+
array = (1...10).to_a
|
63
|
+
Eq array.size, 10
|
64
|
+
end
|
65
|
+
|
66
|
+
D 'Straightforward equality failure (negative)' do
|
67
|
+
Eq! "\n\t text \r \n".strip, "text"
|
68
|
+
end
|
69
|
+
|
70
|
+
D 'Test simple_html; demonstrates string difference' do
|
71
|
+
text = "I _must_ go down to the *seas* again\nTo the @lonely@ sea and the sky"
|
72
|
+
Eq simple_html(text),
|
73
|
+
"<p>I <em>must</em> go down to <strong>seas</strong> again\nTo the " +
|
74
|
+
"<code>lonely</code> sea and the skies</p>"
|
75
|
+
end
|
76
|
+
|
77
|
+
D 'Regular expression matching (positive)' do
|
78
|
+
Mt "Smith, John: (02) 9481 1111", /^[A-z0-9]+$/
|
79
|
+
end
|
80
|
+
|
81
|
+
D 'Regular expression matching (negative)' do
|
82
|
+
Mt! "Doe, Jane: (07) 131 008", /Jane/
|
83
|
+
end
|
84
|
+
|
85
|
+
D 'Expecting something to be nil' do
|
86
|
+
N [25, 32, 7, 51].find { |n| prime? n }
|
87
|
+
end
|
88
|
+
|
89
|
+
D 'Expecting something not to be nil' do
|
90
|
+
N! { "foo".index('t') }
|
91
|
+
end
|
92
|
+
|
93
|
+
D 'Identity (positive)' do
|
94
|
+
Id "foo", "foo"
|
95
|
+
end
|
96
|
+
|
97
|
+
D 'Identity (negative)' do
|
98
|
+
array = (1..10).to_a
|
99
|
+
Id! array, array
|
100
|
+
end
|
101
|
+
|
102
|
+
D 'Float equality (positive)' do
|
103
|
+
Ft 3.14, Math::PI
|
104
|
+
end
|
105
|
+
|
106
|
+
D 'Float equality (negative)' do
|
107
|
+
Ft! 3.141592654, Math::PI
|
108
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
# Used to test 'catch'
|
3
|
+
def even_or_odd(n)
|
4
|
+
if n % 2 == 1
|
5
|
+
throw :odd
|
6
|
+
else
|
7
|
+
throw :even
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Used to generate errors (file not found).
|
12
|
+
def count_lines_in_file(path)
|
13
|
+
File.readlines(path).size
|
14
|
+
end
|
15
|
+
|
16
|
+
# Used for assertions and error raising.
|
17
|
+
def prime?(n)
|
18
|
+
unless (1..100).include? n
|
19
|
+
raise ArgumentError, "Argument to prime? must be in range (1..100): #{n}"
|
20
|
+
end
|
21
|
+
unless Integer === n
|
22
|
+
raise ArgumentError, "Argument to prime? must be an integer: #{n}"
|
23
|
+
end
|
24
|
+
return false if n == 1
|
25
|
+
(2..Math.sqrt(n).to_i).map { |i| n % i }.all? { |rem| rem != 0 }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Used to test string equality and demonstrate string difference.
|
29
|
+
# Surround with <p>, implement _word_, *word* and @word@. Remove newlines.
|
30
|
+
def simple_html(string)
|
31
|
+
tag = lambda { |str, t| "<#{t}>#{str}</#{t}>" }
|
32
|
+
html = string.
|
33
|
+
gsub(/_(\w+)_/) { tag[$1, :em] }.
|
34
|
+
gsub(/\*(\w+)\*/) { tag[$1, :strong] }.
|
35
|
+
gsub(/@(\w+)@/) { tag[$1, :code] }.
|
36
|
+
gsub(/\r?\n/, ' ')
|
37
|
+
tag[html, :p]
|
38
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
|
2
|
+
# This file contains a realistic example of unit testing using whitestone.
|
3
|
+
# The code contains bugs which the tests reveal.
|
4
|
+
|
5
|
+
# - something with a complex #inspect and/or #to_s (or perhaps #html)
|
6
|
+
# - something that takes direct input and gives direct output
|
7
|
+
# (i.e. no need for reading file or interacting with other objects)
|
8
|
+
# - something involving some parsing, like RGeom's types
|
9
|
+
# - something involving a data store (index), especially if it means
|
10
|
+
# that setup is required before the tests
|
11
|
+
# - add_xxx(...)
|
12
|
+
# - maybe take a test from an existing project (RubyGems?) and convert
|
13
|
+
# it to whitestone
|
14
|
+
# - RGeom::Label ?
|
15
|
+
# - RGeom::Point, modified to store points like :A itself ?
|
16
|
+
# - and RGeom::Vertex to boot?
|
17
|
+
# - something that takes a nested data structure (arrays inside hashes
|
18
|
+
# inside...) and generates meaningful summary data
|
19
|
+
# - look at existing unit testing tutorials on the net
|
20
|
+
# - found nothing
|
21
|
+
# - something in standard library ?
|
22
|
+
# - extend Date with some Duration-type methods ?
|
23
|
+
# - some extensions to core classes, taken from 'extensions' ?
|
24
|
+
|
25
|
+
# p1 = Point.new(5, -2)
|
26
|
+
# p2 = Point.polar(11, 30)
|
27
|
+
# Point[:A] = p1
|
28
|
+
# Point[:B] = p2
|
29
|
+
# Point[:A] # -> p1
|
30
|
+
class Point
|
31
|
+
@@index = Hash.new
|
32
|
+
def initialize(x, y)
|
33
|
+
@x, @y = x, y
|
34
|
+
end
|
35
|
+
def Point.cartesian(x, y)
|
36
|
+
Point.new(x, y)
|
37
|
+
end
|
38
|
+
def Point.polar(r, th)
|
39
|
+
Point.new(r * Math.cos(th), r * Math.sin(th))
|
40
|
+
end
|
41
|
+
def Point.[](symbol)
|
42
|
+
@@index[symbol]
|
43
|
+
end
|
44
|
+
def Point.[]=(symbol, point)
|
45
|
+
@@index[symbol] = point
|
46
|
+
end
|
47
|
+
def polar
|
48
|
+
r = Math.sqrt(x**2 + y**2)
|
49
|
+
th = Math.atan2(y, x)
|
50
|
+
[r, th]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#
|
56
|
+
# Simple markup function to turn formatted text into HTML:
|
57
|
+
# * Implement _word_, *word* and @word@ (em, strong and code, respectively);
|
58
|
+
# * Surround paragraphs with <p> tags;
|
59
|
+
# * Turn single newlines into spaces.
|
60
|
+
#
|
61
|
+
def simple_markup(string)
|
62
|
+
tag = lambda { |str, t| "<#{t}>#{str}</#{t}>" }
|
63
|
+
html = string.
|
64
|
+
gsub(/_(\w+)_/) { tag[$1, :em] }.
|
65
|
+
gsub(/\*(\W+)\*/) { tag[$1, :strong] }.
|
66
|
+
gsub(/@(\w+)@/) { tag[$1, :code] }.
|
67
|
+
gsub(/(.+?)\n{2,}/) { tag[$1, :p] }.
|
68
|
+
gsub(/\n/, ' ')
|
69
|
+
end
|
70
|
+
|
71
|
+
D "simple_markup" do
|
72
|
+
D "breaks text into paragraphs" do
|
73
|
+
Eq simple_markup("abc"), "<p>abc</p>"
|
74
|
+
Eq simple_markup("abc\n\ndef"), "<p>abc</p><p>def</p>"
|
75
|
+
Eq simple_markup("abc\n\ndef\n\n\n\nghi\n"), "<p>abc</p><p>def</p><p>ghi</p>"
|
76
|
+
end
|
77
|
+
D "replaces single newlines with a space" do
|
78
|
+
Eq simple_markup("abc\ndef"), "<p>abc xyz</p>"
|
79
|
+
Eq simple_markup("abc\ndef\nghi"), "<p>abc xyz ghi</p>"
|
80
|
+
end
|
81
|
+
D "handles mixed paragraphs and single newlines correctly" do
|
82
|
+
text = "Once upon a time\nIn a land far away\n\n" \
|
83
|
+
+ "A frog named Kermit\n\nDecared he was here to stay"
|
84
|
+
html = "<p>Once upon a time In a land far away</p>" \
|
85
|
+
+ "<p>A frog named Kermit Decared he was here to stay</p>"
|
86
|
+
Eq simple_markup(text), html
|
87
|
+
end
|
88
|
+
D "handles _words_" do
|
89
|
+
Eq simple_markup("One _two_ _three_"), "<p>One <em>two</em> <em>three</em></p>"
|
90
|
+
end
|
91
|
+
D "handles *words*" do
|
92
|
+
Eq simple_markup("One *fine* day"), "<p>One <strong>fine</strong> day</p>"
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
D "Whitestone.stop" do
|
2
|
+
D "Benign first test" do
|
3
|
+
T { 1 + 1 == 2 }
|
4
|
+
end
|
5
|
+
D "Here we go" do
|
6
|
+
if defined? Whitestone
|
7
|
+
Whitestone.stop
|
8
|
+
elsif defined? Dfect
|
9
|
+
Dfect.stop
|
10
|
+
end
|
11
|
+
raise "Must not get here"
|
12
|
+
end
|
13
|
+
D "Must not get here" do
|
14
|
+
raise "Must not get here"
|
15
|
+
end
|
16
|
+
end
|