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