rubydoctest 0.2.1 → 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/History.txt +10 -0
- data/License.txt +16 -17
- data/Manifest.txt +13 -5
- data/PostInstall.txt +2 -3
- data/README.txt +48 -57
- data/Ruby DocTest.tmproj +197 -0
- data/bin/rubydoctest +41 -25
- data/config/hoe.rb +3 -5
- data/lib/code_block.rb +68 -0
- data/lib/doctest_require.rb +3 -0
- data/lib/lines.rb +143 -0
- data/lib/result.rb +63 -0
- data/lib/rubydoctest.rb +13 -255
- data/lib/rubydoctest/version.rb +3 -3
- data/lib/runner.rb +370 -0
- data/lib/special_directive.rb +44 -0
- data/lib/statement.rb +75 -0
- data/lib/test.rb +29 -0
- data/rubydoctest.gemspec +6 -6
- data/script/console +0 -0
- data/script/destroy +0 -0
- data/script/generate +0 -0
- data/script/rstakeout +92 -0
- data/script/txt2html +0 -0
- data/tasks/doctests.rake +2 -1
- data/textmate/DocTest (Markdown).textmate +7 -0
- data/textmate/DocTest (Ruby).textmate +55 -0
- data/textmate/DocTest (Text).textmate +66 -0
- data/website/index.html +141 -11
- data/website/template.html.erb +1 -1
- metadata +22 -15
- data/test/doctest/file_relative.doctest +0 -5
- data/test/doctest/runner.doctest +0 -58
- data/test/doctest/simple.doctest +0 -30
- data/test/test_helper.rb +0 -2
- data/test/test_rubydoctest.rb +0 -11
data/config/hoe.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
require 'rubydoctest/version'
|
2
2
|
|
3
|
-
AUTHOR = ['Tom Locke', 'Dr Nic Williams'] # can also be an array of Authors
|
4
|
-
EMAIL = "
|
3
|
+
AUTHOR = ['Duane Johnson', 'Tom Locke', 'Dr Nic Williams'] # can also be an array of Authors
|
4
|
+
EMAIL = "duane.johnson@gmail.com"
|
5
5
|
DESCRIPTION = "Ruby version of Python's doctest tool, but a bit different."
|
6
6
|
GEM_NAME = 'rubydoctest' # what ppl will type to install your gem
|
7
7
|
RUBYFORGE_PROJECT = 'rubydoctest' # The unix name for your project
|
8
8
|
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
9
|
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
-
EXTRA_DEPENDENCIES = [
|
11
|
-
# ['activesupport', '>= 1.3.1']
|
12
|
-
] # An array of rubygem dependencies [name, version]
|
10
|
+
EXTRA_DEPENDENCIES = []
|
13
11
|
|
14
12
|
@config_file = "~/.rubyforge/user-config.yml"
|
15
13
|
@config = nil
|
data/lib/code_block.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'statement'
|
5
|
+
require 'result'
|
6
|
+
|
7
|
+
module RubyDocTest
|
8
|
+
# A +CodeBlock+ is a group of one or more ruby statements, followed by an optional result.
|
9
|
+
# For example:
|
10
|
+
# >> a = 1 + 1
|
11
|
+
# >> a - 3
|
12
|
+
# => -1
|
13
|
+
class CodeBlock
|
14
|
+
attr_reader :statements, :result, :passed
|
15
|
+
|
16
|
+
def initialize(statements = [], result = nil)
|
17
|
+
@statements = statements
|
18
|
+
@result = result
|
19
|
+
end
|
20
|
+
|
21
|
+
# === Tests
|
22
|
+
# doctest: Single statement with result should pass
|
23
|
+
# >> ss = [RubyDocTest::Statement.new([">> a = 1"])]
|
24
|
+
# >> r = RubyDocTest::Result.new(["=> 1"])
|
25
|
+
# >> cb = RubyDocTest::CodeBlock.new(ss, r)
|
26
|
+
# >> cb.pass?
|
27
|
+
# => true
|
28
|
+
#
|
29
|
+
# doctest: Single statement without result should pass by default
|
30
|
+
# >> ss = [RubyDocTest::Statement.new([">> a = 1"])]
|
31
|
+
# >> cb = RubyDocTest::CodeBlock.new(ss)
|
32
|
+
# >> cb.pass?
|
33
|
+
# => true
|
34
|
+
#
|
35
|
+
# doctest: Multi-line statement with result should pass
|
36
|
+
# >> ss = [RubyDocTest::Statement.new([">> a = 1"]),
|
37
|
+
# RubyDocTest::Statement.new([">> 'a' + a.to_s"])]
|
38
|
+
# >> r = RubyDocTest::Result.new(["=> 'a1'"])
|
39
|
+
# >> cb = RubyDocTest::CodeBlock.new(ss, r)
|
40
|
+
# >> cb.pass?
|
41
|
+
# => true
|
42
|
+
def pass?
|
43
|
+
if @computed
|
44
|
+
@passed
|
45
|
+
else
|
46
|
+
@computed = true
|
47
|
+
@passed =
|
48
|
+
begin
|
49
|
+
actual_results = @statements.map{ |s| s.evaluate }
|
50
|
+
@result ? @result.matches?(actual_results.last) : true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def actual_result
|
56
|
+
@statements.last.actual_result
|
57
|
+
end
|
58
|
+
|
59
|
+
def expected_result
|
60
|
+
@result.expected_result
|
61
|
+
end
|
62
|
+
|
63
|
+
def lines
|
64
|
+
@statements.map{ |s| s.lines }.flatten +
|
65
|
+
@result.lines
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/lines.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
module RubyDocTest
|
2
|
+
# === Description
|
3
|
+
# Keeps track of which lines within a document belong to a group. Line groups are
|
4
|
+
# determined by their indentation level, as in the Python programming language.
|
5
|
+
#
|
6
|
+
# === Example
|
7
|
+
# This line and the next one
|
8
|
+
# are part of the same group
|
9
|
+
#
|
10
|
+
# But this line is separate from
|
11
|
+
# this line.
|
12
|
+
#
|
13
|
+
# === Note
|
14
|
+
# This class also considers one '#' character (comment) as an indentation character,
|
15
|
+
# i.e. similar to how whitespace is treated.
|
16
|
+
class Lines
|
17
|
+
def initialize(doc_lines, line_index = 0)
|
18
|
+
@doc_lines, @line_index = doc_lines, line_index
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def line_number
|
23
|
+
@line_index + 1
|
24
|
+
end
|
25
|
+
|
26
|
+
# === Tests
|
27
|
+
# doctest: Return an array of 1 line if there is only one line
|
28
|
+
# >> l = RubyDocTest::Lines.new(["line 1"])
|
29
|
+
# >> l.lines
|
30
|
+
# => ["line 1"]
|
31
|
+
#
|
32
|
+
# doctest: Remove indentation from lines 2 to the end of this Lines group.
|
33
|
+
# >> l = RubyDocTest::Lines.new(["line 1", " line 2", " line 3", " line 4"])
|
34
|
+
# >> l.lines
|
35
|
+
# => ["line 1", "line 2", "line 3", " line 4"]
|
36
|
+
def lines
|
37
|
+
r = range
|
38
|
+
size = r.last - r.first + 1
|
39
|
+
if size > 1
|
40
|
+
# Remove indentation from all lines after the first,
|
41
|
+
# as measured from the 2nd line's indentation level
|
42
|
+
idt2 = indentation(@doc_lines, @line_index + 1)
|
43
|
+
[@doc_lines[range.first]] +
|
44
|
+
@doc_lines[(range.first + 1)..(range.last)].
|
45
|
+
map{ |l| $1 if l =~ /^#{Regexp.escape(idt2)}(.*)/ }
|
46
|
+
else
|
47
|
+
@doc_lines[range]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# === Description
|
53
|
+
# Calculate the range of python-like indentation within this Lines group
|
54
|
+
#
|
55
|
+
# === Tests
|
56
|
+
# >> l = RubyDocTest::Lines.new([])
|
57
|
+
#
|
58
|
+
# doctest: Return a range of one line when there is only one line to begin with
|
59
|
+
# >> l.range %w(a), 0
|
60
|
+
# => 0..0
|
61
|
+
#
|
62
|
+
# doctest: Return a range of one line when there are two lines, side by side
|
63
|
+
# >> l.range %w(a b), 0
|
64
|
+
# => 0..0
|
65
|
+
# >> l.range %w(a b), 1
|
66
|
+
# => 1..1
|
67
|
+
#
|
68
|
+
# doctest: Return a range of two lines when there are two lines, the second blank
|
69
|
+
# >> l.range ["a", ""], 0
|
70
|
+
# => 0..1
|
71
|
+
#
|
72
|
+
# doctest: Return a range of two lines when the second is indented
|
73
|
+
# >> l.range ["a", " b"], 0
|
74
|
+
# => 0..1
|
75
|
+
#
|
76
|
+
# doctest: Indentation can also include the ?> marker
|
77
|
+
# >> l.range [">> 1 +", "?> 2"], 0
|
78
|
+
# => 0..1
|
79
|
+
def range(doc_lines = @doc_lines, start_index = @line_index)
|
80
|
+
end_index = start_index
|
81
|
+
idt = indentation(doc_lines, start_index)
|
82
|
+
# Find next lines that are blank, or have indentation more than the first line
|
83
|
+
remaining_lines(doc_lines, start_index + 1).each do |current_line|
|
84
|
+
if current_line =~ /^(#{Regexp.escape(idt)}(\s+|\?>\s)|\s*$)/
|
85
|
+
end_index += 1
|
86
|
+
else
|
87
|
+
break
|
88
|
+
end
|
89
|
+
end
|
90
|
+
# Compute the range from what we found
|
91
|
+
start_index..end_index
|
92
|
+
end
|
93
|
+
|
94
|
+
def inspect
|
95
|
+
"#<#{self.class} lines=#{lines.inspect}>"
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
# === Tests
|
101
|
+
# >> l = RubyDocTest::Lines.new([])
|
102
|
+
#
|
103
|
+
# doctest: Get a whitespace indent from a line with whitespace
|
104
|
+
# >> l.send :indentation, [" a"], 0
|
105
|
+
# => " "
|
106
|
+
#
|
107
|
+
# doctest: Get a whitespace and '#' indent from a comment line
|
108
|
+
# >> l.send :indentation, [" # a"], 0
|
109
|
+
# => " # "
|
110
|
+
def indentation(doc_lines = @doc_lines, line_index = @line_index)
|
111
|
+
if doc_lines[line_index]
|
112
|
+
doc_lines[line_index][/^(\s*#\s*|\s*)(\?>\s)?/]
|
113
|
+
else
|
114
|
+
""
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# === Description
|
120
|
+
# Get lines from +start_index+ up to the end of the document.
|
121
|
+
#
|
122
|
+
# === Tests
|
123
|
+
# >> l = RubyDocTest::Lines.new([])
|
124
|
+
#
|
125
|
+
# doctest: Return an empty array if start_index is out of bounds
|
126
|
+
# >> l.send :remaining_lines, [], 1
|
127
|
+
# => []
|
128
|
+
# >> l.send :remaining_lines, [], -1
|
129
|
+
# => []
|
130
|
+
#
|
131
|
+
# doctest: Return the specified line at start_index, up to and including the
|
132
|
+
# last line of +doc_lines+.
|
133
|
+
# >> l.send :remaining_lines, %w(a b c), 1
|
134
|
+
# => %w(b c)
|
135
|
+
# >> l.send :remaining_lines, %w(a b c), 2
|
136
|
+
# => %w(c)
|
137
|
+
#
|
138
|
+
def remaining_lines(doc_lines = @doc_lines, start_index = @line_index)
|
139
|
+
return [] if start_index < 0 or start_index >= doc_lines.size
|
140
|
+
doc_lines[start_index..-1]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
data/lib/result.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'lines'
|
5
|
+
|
6
|
+
module RubyDocTest
|
7
|
+
class Result < Lines
|
8
|
+
|
9
|
+
def normalize_result(s)
|
10
|
+
s.gsub(/:0x[a-f0-9]{8}>/, ':0xXXXXXXXX>').strip
|
11
|
+
end
|
12
|
+
|
13
|
+
def expected_result
|
14
|
+
@expected_result ||=
|
15
|
+
begin
|
16
|
+
lines.first =~ /^#{Regexp.escape(indentation)}=>\s(.*)$/
|
17
|
+
([$1] + (lines[1..-1] || [])).join("\n")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# === Tests
|
22
|
+
# doctest: Strings should match
|
23
|
+
# >> r = RubyDocTest::Result.new(["=> 'hi'"])
|
24
|
+
# >> r.matches? 'hi'
|
25
|
+
# => true
|
26
|
+
#
|
27
|
+
# >> r = RubyDocTest::Result.new(["=> \"hi\""])
|
28
|
+
# >> r.matches? "hi"
|
29
|
+
# => true
|
30
|
+
#
|
31
|
+
# doctest: Regexps should match
|
32
|
+
# >> r = RubyDocTest::Result.new(["=> /^reg.../"])
|
33
|
+
# >> r.matches? /^reg.../
|
34
|
+
# => true
|
35
|
+
#
|
36
|
+
# >> r = RubyDocTest::Result.new(["=> /^reg.../"])
|
37
|
+
# >> r.matches? /^regexp/
|
38
|
+
# => false
|
39
|
+
#
|
40
|
+
# doctest: Arrays should match
|
41
|
+
# >> r = RubyDocTest::Result.new(["=> [1, 2, 3]"])
|
42
|
+
# >> r.matches? [1, 2, 3]
|
43
|
+
# => true
|
44
|
+
#
|
45
|
+
# doctest: Arrays of arrays should match
|
46
|
+
# >> r = RubyDocTest::Result.new(["=> [[1, 2], [3, 4]]"])
|
47
|
+
# >> r.matches? [[1, 2], [3, 4]]
|
48
|
+
# => true
|
49
|
+
#
|
50
|
+
# doctest: Hashes should match
|
51
|
+
# >> r = RubyDocTest::Result.new(["=> {:one => 1, :two => 2}"])
|
52
|
+
# >> r.matches?({:two => 2, :one => 1})
|
53
|
+
# => true
|
54
|
+
def matches?(actual_result)
|
55
|
+
normalize_result(actual_result.inspect) ==
|
56
|
+
normalize_result(expected_result) \
|
57
|
+
or
|
58
|
+
actual_result == eval(expected_result, TOPLEVEL_BINDING)
|
59
|
+
rescue Exception
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/rubydoctest.rb
CHANGED
@@ -2,270 +2,28 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
2
2
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
3
|
|
4
4
|
require 'irb'
|
5
|
+
require "runner"
|
5
6
|
|
6
|
-
|
7
|
+
module RubyDocTest
|
7
8
|
|
8
9
|
class << self
|
9
|
-
attr_accessor :trace
|
10
|
-
|
11
|
-
|
12
|
-
PROMPT_RX = /^[>?]>( |\s*$)/
|
13
|
-
|
14
|
-
RESULT_RX = /^=> /
|
15
|
-
|
16
|
-
CODE_LINE_RX = /^( |\t)/
|
17
|
-
|
18
|
-
def initialize(src, file_name)
|
19
|
-
@passed = 0
|
20
|
-
@block_count = 0
|
21
|
-
@failures = []
|
22
|
-
@src_lines = src.split("\n")
|
23
|
-
@line_num = 0
|
24
|
-
@file_name = file_name
|
10
|
+
attr_accessor :trace, :ignore_interactive
|
11
|
+
attr_writer :output_format
|
25
12
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
print_report
|
32
|
-
end
|
33
|
-
|
34
|
-
attr_accessor :passed, :failures, :current_line, :src_lines, :line_num, :block_count
|
35
|
-
|
36
|
-
def environment
|
37
|
-
TOPLEVEL_BINDING
|
38
|
-
end
|
39
|
-
|
40
|
-
def next_line
|
41
|
-
@line_num += 1
|
42
|
-
@current_line = src_lines.shift
|
43
|
-
end
|
44
|
-
|
45
|
-
def next_line?
|
46
|
-
src_lines.any?
|
47
|
-
end
|
48
|
-
|
49
|
-
def strip_prompt(s)
|
50
|
-
s.sub(PROMPT_RX, "")
|
51
|
-
end
|
52
|
-
|
53
|
-
def result_start?(s=current_line)
|
54
|
-
s =~ RESULT_RX
|
55
|
-
end
|
56
|
-
|
57
|
-
def string_result_start?(s=current_line)
|
58
|
-
s =~ /^=>""/
|
59
|
-
end
|
60
|
-
|
61
|
-
def statement_start?(s=current_line)
|
62
|
-
s =~ PROMPT_RX
|
63
|
-
end
|
64
|
-
|
65
|
-
def strip_result_marker(s=current_line)
|
66
|
-
s.sub(RESULT_RX, "")
|
67
|
-
end
|
68
|
-
|
69
|
-
def normalize_result(s)
|
70
|
-
s.gsub(/:0x[a-f0-9]{8}>/, ':0xXXXXXXXX>').strip
|
71
|
-
end
|
72
|
-
|
73
|
-
def code_line?(s=current_line)
|
74
|
-
s =~ CODE_LINE_RX
|
75
|
-
end
|
76
|
-
|
77
|
-
def code_block_start?(s=current_line)
|
78
|
-
l = unindent_code_line
|
79
|
-
code_line? && (statement_start?(l) || irb_interrupt?(l))
|
80
|
-
end
|
81
|
-
|
82
|
-
def blank_line?(s=current_line)
|
83
|
-
s =~ /^\s*$/
|
84
|
-
end
|
85
|
-
|
86
|
-
def irb_interrupt?(line)
|
87
|
-
line =~ /!!!/
|
88
|
-
end
|
89
|
-
|
90
|
-
def run_file
|
91
|
-
# run_code_block if code_block_start?
|
92
|
-
while next_line
|
93
|
-
run_code_block if code_block_start?
|
94
|
-
end
|
95
|
-
failures.length == 0
|
96
|
-
end
|
97
|
-
|
98
|
-
def unindent_code_line(s=current_line)
|
99
|
-
s.sub(CODE_LINE_RX, "")
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
def get_code_lines
|
104
|
-
lines = []
|
105
|
-
while blank_line? || code_line?
|
106
|
-
lines << [unindent_code_line, line_num]
|
107
|
-
next_line
|
108
|
-
end
|
109
|
-
lines.pop while blank_line?(lines.last)
|
110
|
-
lines
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
def run_code_block
|
115
|
-
self.block_count += 1
|
116
|
-
|
117
|
-
lines = get_code_lines
|
118
|
-
|
119
|
-
reading = :statement
|
120
|
-
|
121
|
-
result = nil
|
122
|
-
statement = ""
|
123
|
-
statement_line = lines.first.last
|
124
|
-
lines.each do |line, line_num|
|
125
|
-
|
126
|
-
if irb_interrupt?(line)
|
127
|
-
evaluate(statement, statement_line) unless statement == ""
|
128
|
-
|
129
|
-
puts statement unless statement.blank?
|
130
|
-
puts "=> #{result}" unless result.blank?
|
131
|
-
puts
|
132
|
-
|
133
|
-
start_irb
|
134
|
-
line = nil
|
135
|
-
|
136
|
-
elsif string_result_start?(line)
|
137
|
-
reading = :string_result
|
138
|
-
line = nil
|
139
|
-
result = ""
|
140
|
-
|
141
|
-
elsif result_start?(line)
|
142
|
-
reading = :ruby_result
|
143
|
-
line = strip_result_marker(line)
|
144
|
-
result = ""
|
145
|
-
|
146
|
-
elsif statement_start?(line)
|
147
|
-
if result
|
148
|
-
# start of a new statement
|
149
|
-
if reading == :string_result
|
150
|
-
# end of a string result statement
|
151
|
-
result.chomp!
|
152
|
-
run_statement(statement, result, statement_line, true)
|
153
|
-
else
|
154
|
-
run_statement(statement, result, statement_line)
|
155
|
-
end
|
156
|
-
statement_line = line_num
|
157
|
-
statement = ""
|
158
|
-
result = nil
|
159
|
-
end
|
160
|
-
reading = :statement
|
161
|
-
end
|
162
|
-
|
163
|
-
if reading == :statement
|
164
|
-
# The statement has a prompt on every line
|
165
|
-
if line
|
166
|
-
line = strip_prompt(line)
|
167
|
-
statement << line + "\n"
|
168
|
-
end
|
13
|
+
def output_format
|
14
|
+
if @output_format == :ansi or (@output_format.nil? and STDOUT.tty?)
|
15
|
+
:ansi
|
16
|
+
elsif @output_format == :html
|
17
|
+
:html
|
169
18
|
else
|
170
|
-
|
171
|
-
result << line + "\n" if line
|
19
|
+
:plain
|
172
20
|
end
|
173
|
-
|
174
|
-
end
|
175
|
-
|
176
|
-
if result.nil?
|
177
|
-
# The block ends with a statement - just evaluate it
|
178
|
-
evaluate(statement, statement_line)
|
179
|
-
else
|
180
|
-
run_statement(statement, result, statement_line)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
|
185
|
-
def start_irb
|
186
|
-
IRB.init_config(nil)
|
187
|
-
IRB.conf[:PROMPT_MODE] = :SIMPLE
|
188
|
-
irb = IRB::Irb.new(IRB::WorkSpace.new(environment))
|
189
|
-
IRB.conf[:MAIN_CONTEXT] = irb.context
|
190
|
-
irb.eval_input
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
def run_statement(statement, expected_result, statement_line, string_comparison=false)
|
195
|
-
actual_result = evaluate(statement, statement_line)
|
196
|
-
|
197
|
-
if result_matches?(expected_result, actual_result, string_comparison)
|
198
|
-
self.passed += 1
|
199
|
-
else
|
200
|
-
actual_result = actual_result.inspect unless string_comparison
|
201
|
-
failures << [statement, actual_result, expected_result, statement_line]
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
|
206
|
-
def result_matches?(expected_result, actual_result, string_comparison)
|
207
|
-
if string_comparison
|
208
|
-
actual_result == expected_result
|
209
|
-
else
|
210
|
-
actual_result = actual_result.inspect
|
211
|
-
normalize_result(expected_result) == normalize_result(actual_result) or
|
212
|
-
# If the expected result looks like a literal, see if they eval to equal objects - this will often fail
|
213
|
-
if expected_result =~ /^[:\[{A-Z'"%\/]/
|
214
|
-
begin
|
215
|
-
eval(expected_result) == eval(actual_result)
|
216
|
-
rescue Exception
|
217
|
-
false
|
218
|
-
end
|
219
|
-
end
|
220
21
|
end
|
221
|
-
end
|
222
|
-
|
223
|
-
|
224
|
-
def evaluate(statement, line_num)
|
225
|
-
statement.gsub!("__FILE__", @file_name.inspect)
|
226
|
-
eval(statement, environment, __FILE__, __LINE__)
|
227
|
-
rescue SyntaxError => e
|
228
|
-
puts "Syntax error in statement on line #{line_num}:"
|
229
|
-
puts indent(statement)
|
230
|
-
puts e.to_s
|
231
|
-
puts
|
232
|
-
exit 1
|
233
|
-
rescue Exception => e
|
234
|
-
puts "Exception in statement on line #{line_num}:"
|
235
|
-
puts indent(statement)
|
236
|
-
puts e.backtrace
|
237
22
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
puts e.to_s
|
242
|
-
puts
|
243
|
-
exit 1
|
23
|
+
def indent(s, level=4)
|
24
|
+
spaces = " " * level
|
25
|
+
spaces + s.split("\n").join("\n#{spaces}")
|
244
26
|
end
|
245
27
|
end
|
246
28
|
|
247
|
-
|
248
|
-
def number_run
|
249
|
-
passed + failures.length
|
250
|
-
end
|
251
|
-
|
252
|
-
def indent(s, level=4)
|
253
|
-
spaces = " " * level
|
254
|
-
spaces + s.split("\n").join("\n#{spaces}")
|
255
|
-
end
|
256
|
-
|
257
|
-
def print_report
|
258
|
-
statements_per_block = number_run.to_f / block_count
|
259
|
-
puts("%d blocks, %d tests (avg. %.1f/block), %d failures\n\n" %
|
260
|
-
[block_count, number_run, statements_per_block, failures.length])
|
261
|
-
|
262
|
-
failures.each do |statement, actual, expected, lnum|
|
263
|
-
puts "Failure line #{lnum}"
|
264
|
-
puts " Statement:", indent(statement)
|
265
|
-
puts " Expected:", indent(expected)
|
266
|
-
puts " Got:\n", indent(actual)
|
267
|
-
puts
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
29
|
end
|