fit 1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +203 -0
- data/Rakefile +111 -0
- data/bin/FitServer.rb +6 -0
- data/bin/fit +10 -0
- data/bin/fit.cgi +36 -0
- data/doc/examples/AllCombinations.html +55 -0
- data/doc/examples/AllFiles.html +60 -0
- data/doc/examples/AllPairs/function/cosine.html +57 -0
- data/doc/examples/AllPairs/function/sine.html +57 -0
- data/doc/examples/AllPairs/magnitude/180+30.html +45 -0
- data/doc/examples/AllPairs/magnitude/30.html +33 -0
- data/doc/examples/AllPairs/magnitude/360+30.html +45 -0
- data/doc/examples/AllPairs/magnitude/90-30.html +45 -0
- data/doc/examples/AllPairs/sign/change-sign.html +27 -0
- data/doc/examples/AllPairs/sign/multiply.html +31 -0
- data/doc/examples/AllPairs/sign/no-change.html +23 -0
- data/doc/examples/AllPairs.html +51 -0
- data/doc/examples/BinaryChop.html +89 -0
- data/doc/examples/CalculatorExample.html +108 -0
- data/doc/examples/ColumnIndex.html +43 -0
- data/doc/examples/ExampleTests.html +43 -0
- data/doc/examples/FitAcceptanceTests.html +53 -0
- data/doc/examples/GeoCoordinate.html +87 -0
- data/doc/examples/MusicExample.html +143 -0
- data/doc/examples/MusicExampleWithErrors.html +128 -0
- data/doc/examples/NetworkExample.html +47 -0
- data/doc/examples/WebPageExample.html +92 -0
- data/doc/examples/arithmetic.html +211 -0
- data/doc/examples/files/hp35bk.jpg +0 -0
- data/doc/examples/logo.gif +0 -0
- data/doc/fitnesse/FitNesse.RubY.AcceptanceTests.FixtureParameters.html +81 -0
- data/doc/fitnesse/FitNesse.RubY.AcceptanceTests.GracefulFixtureNames.html +87 -0
- data/doc/fitnesse/FitNesse.RubY.AcceptanceTests.GracefulMemberNames.html +73 -0
- data/doc/fitnesse/FitNesse.RubY.AcceptanceTests.ImportFixture.html +61 -0
- data/doc/fitnesse/FitNesse.RubY.AcceptanceTests.WaysToSpecifyaFixtureNamespace.html +81 -0
- data/doc/spec/annotation.html +3833 -0
- data/doc/spec/extensions.html +302 -0
- data/doc/spec/fixtures.html +5181 -0
- data/doc/spec/index.html +947 -0
- data/doc/spec/parse.html +3094 -0
- data/lib/eg/all_combinations.rb +44 -0
- data/lib/eg/all_files.rb +94 -0
- data/lib/eg/all_pairs.rb +172 -0
- data/lib/eg/arithmetic_column_fixture.rb +35 -0
- data/lib/eg/arithmetic_fixture.rb +29 -0
- data/lib/eg/binary_chop.rb +100 -0
- data/lib/eg/calculator.rb +69 -0
- data/lib/eg/column_index.rb +85 -0
- data/lib/eg/division.rb +13 -0
- data/lib/eg/echo_args_fixture.rb +9 -0
- data/lib/eg/example_tests.rb +84 -0
- data/lib/eg/music/Music.txt +38 -0
- data/lib/eg/music/browser.rb +60 -0
- data/lib/eg/music/display.rb +24 -0
- data/lib/eg/music/music.rb +67 -0
- data/lib/eg/music/music_library.rb +70 -0
- data/lib/eg/music/music_player.rb +77 -0
- data/lib/eg/music/realtime.rb +39 -0
- data/lib/eg/music/simulator.rb +81 -0
- data/lib/eg/nested/bob.rb +12 -0
- data/lib/eg/nested/bob_the_builder_fixture.rb +11 -0
- data/lib/eg/net/simulator.rb +69 -0
- data/lib/eg/page.rb +91 -0
- data/lib/eg/sqrt.rb +19 -0
- data/lib/fat/annotation_fixture.rb +83 -0
- data/lib/fat/color.rb +45 -0
- data/lib/fat/divide.rb +13 -0
- data/lib/fat/document_parse_fixture.rb +67 -0
- data/lib/fat/equals.rb +59 -0
- data/lib/fat/fixture_name_fixture.rb +67 -0
- data/lib/fat/html_to_text_fixture.rb +20 -0
- data/lib/fat/money.rb +18 -0
- data/lib/fat/output_fixture.rb +32 -0
- data/lib/fat/parse_fixture.rb +92 -0
- data/lib/fat/reference_fixture.rb +31 -0
- data/lib/fat/standard_annotation_fixture.rb +58 -0
- data/lib/fat/string_writer.rb +12 -0
- data/lib/fat/table.rb +23 -0
- data/lib/fat/table_parse_fixture.rb +33 -0
- data/lib/fat/text_to_html_fixture.rb +21 -0
- data/lib/fit/action_fixture.rb +65 -0
- data/lib/fit/column_fixture.rb +104 -0
- data/lib/fit/file_runner.rb +80 -0
- data/lib/fit/fit_protocol.rb +62 -0
- data/lib/fit/fit_server.rb +173 -0
- data/lib/fit/fixture.rb +309 -0
- data/lib/fit/fixture_loader.rb +75 -0
- data/lib/fit/import_fixture.rb +9 -0
- data/lib/fit/parse.rb +206 -0
- data/lib/fit/primitive_fixture.rb +52 -0
- data/lib/fit/row_fixture.rb +188 -0
- data/lib/fit/scientific_double.rb +70 -0
- data/lib/fit/summary.rb +46 -0
- data/lib/fit/timed_action_fixture.rb +35 -0
- data/lib/fit/type_adapter.rb +95 -0
- data/lib/fit/wiki_runner.rb +15 -0
- data/lib/fittask.rb +184 -0
- data/test/all_tests.rb +13 -0
- data/test/file_runner_test.rb +52 -0
- data/test/fit_server_test.rb +214 -0
- data/test/fixture_loader_test.rb +71 -0
- data/test/fixture_test.rb +41 -0
- data/test/fixtures/fail_fixture.rb +9 -0
- data/test/fixtures/pass_fixture.rb +9 -0
- data/test/framework_test.rb +51 -0
- data/test/parse_test.rb +101 -0
- data/test/row_fixture_test.rb +44 -0
- data/test/scientific_double_test.rb +35 -0
- data/test/type_adapter_test.rb +120 -0
- metadata +165 -0
@@ -0,0 +1,188 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/column_fixture'
|
5
|
+
require 'fit/parse'
|
6
|
+
require 'fit/type_adapter'
|
7
|
+
|
8
|
+
module Fit
|
9
|
+
|
10
|
+
class RowFixture < ColumnFixture
|
11
|
+
|
12
|
+
attr_accessor :results
|
13
|
+
attr_accessor :missing, :surplus
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@missing = []
|
18
|
+
@surplus = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def do_rows rows
|
22
|
+
begin
|
23
|
+
bind rows.parts
|
24
|
+
@results = query
|
25
|
+
match list(rows.more), @results, 0
|
26
|
+
last = rows.last
|
27
|
+
last.more = build_rows @surplus
|
28
|
+
mark_parse last.more, 'surplus'
|
29
|
+
mark_list @missing, 'missing'
|
30
|
+
rescue Exception => e
|
31
|
+
exception rows.leaf, e
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Gets rows to be compared
|
36
|
+
def query; end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def match expected, computed, column_index
|
41
|
+
if column_index >= @column_bindings.size
|
42
|
+
check_list expected, computed
|
43
|
+
elsif @column_bindings[column_index].nil?
|
44
|
+
match(expected, computed, column_index + 1)
|
45
|
+
else
|
46
|
+
e_map = e_sort(expected, column_index)
|
47
|
+
c_map = c_sort(computed, column_index)
|
48
|
+
keys = e_map.keys | c_map.keys
|
49
|
+
keys.each do |key|
|
50
|
+
e_list = e_map[key]
|
51
|
+
c_list = c_map[key]
|
52
|
+
if e_list.nil?
|
53
|
+
@surplus += c_list
|
54
|
+
elsif c_list.nil?
|
55
|
+
@missing += e_list
|
56
|
+
elsif e_list.size == 1 and c_list.size == 1
|
57
|
+
check_list e_list, c_list
|
58
|
+
else
|
59
|
+
match(e_list, c_list, column_index + 1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def list rows
|
66
|
+
result = []
|
67
|
+
until rows.nil?
|
68
|
+
result << rows
|
69
|
+
rows = rows.more
|
70
|
+
end
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
def e_sort list, column_index
|
75
|
+
adapter = @column_bindings[column_index]
|
76
|
+
result = {}
|
77
|
+
list.each do |row|
|
78
|
+
cell = row.parts.at(column_index)
|
79
|
+
begin
|
80
|
+
key = adapter.parse(cell.text)
|
81
|
+
bin(result, key, row)
|
82
|
+
rescue Exception => e
|
83
|
+
exception cell, e
|
84
|
+
rest = cell.more
|
85
|
+
until rest.nil?
|
86
|
+
ignore rest
|
87
|
+
rest = rest.more
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
result
|
92
|
+
end
|
93
|
+
|
94
|
+
def c_sort list, column_index
|
95
|
+
adapter = @column_bindings[column_index]
|
96
|
+
result = {}
|
97
|
+
list.each do |row|
|
98
|
+
begin
|
99
|
+
adapter.target = row
|
100
|
+
key = adapter.get
|
101
|
+
bin(result, key, row)
|
102
|
+
rescue Exception => e
|
103
|
+
@surplus << row # surplus anything with bad keys, including nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
def bin map, key, row
|
110
|
+
if map.include? key
|
111
|
+
map[key] <<= row
|
112
|
+
else
|
113
|
+
map[key] = [row]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def check_list e_list, c_list
|
118
|
+
if e_list.empty?
|
119
|
+
@surplus += c_list
|
120
|
+
return
|
121
|
+
end
|
122
|
+
if c_list.empty?
|
123
|
+
@missing += e_list
|
124
|
+
return
|
125
|
+
end
|
126
|
+
row = e_list.shift
|
127
|
+
cell = row.parts
|
128
|
+
obj = c_list.shift
|
129
|
+
@column_bindings.each do |adapter|
|
130
|
+
adapter.target = obj unless adapter.nil?
|
131
|
+
check cell, adapter
|
132
|
+
cell = cell.more
|
133
|
+
break if cell.nil?
|
134
|
+
end
|
135
|
+
check_list e_list, c_list
|
136
|
+
end
|
137
|
+
|
138
|
+
def mark_parse rows, message
|
139
|
+
annotation = Fixture.label message
|
140
|
+
until rows.nil?
|
141
|
+
wrong rows.parts
|
142
|
+
rows.parts.add_to_body annotation
|
143
|
+
rows = rows.more
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def mark_list rows, message
|
148
|
+
annotation = Fixture.label message
|
149
|
+
rows.each do |row|
|
150
|
+
wrong row.parts
|
151
|
+
row.parts.add_to_body annotation
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def build_rows rows
|
156
|
+
root_parse = ParseHolder.create nil, nil, nil, nil
|
157
|
+
next_parse = root_parse
|
158
|
+
rows.each {|row| next_parse = next_parse.more = ParseHolder.create('tr', nil, build_cells(row), nil)}
|
159
|
+
root_parse.more
|
160
|
+
end
|
161
|
+
|
162
|
+
def build_cells row
|
163
|
+
if row.nil?
|
164
|
+
nihil = ParseHolder.create 'td', 'nil', nil, nil
|
165
|
+
nihil.add_to_tag('colspan="' + @column_bindings.size.to_s + '"')
|
166
|
+
return nihil
|
167
|
+
end
|
168
|
+
root_parse = ParseHolder.create nil, nil, nil, nil
|
169
|
+
next_parse = root_parse
|
170
|
+
@column_bindings.each do |adapter|
|
171
|
+
next_parse = next_parse.more = ParseHolder.create('td', ' ', nil, nil)
|
172
|
+
if adapter.nil?
|
173
|
+
ignore next_parse
|
174
|
+
else
|
175
|
+
begin
|
176
|
+
adapter.target = row
|
177
|
+
next_parse.body = Fixture.gray(Fixture.escape(adapter.to_s(adapter.get)))
|
178
|
+
rescue Exception => e
|
179
|
+
exception next_parse, e
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
root_parse.more
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
module Fit
|
5
|
+
|
6
|
+
# Warning: not (yet) a general number usable in all calculations
|
7
|
+
class ScientificDouble
|
8
|
+
|
9
|
+
attr_accessor :precision
|
10
|
+
|
11
|
+
def initialize value
|
12
|
+
@value = Float(value)
|
13
|
+
@precision = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def ScientificDouble.value_of s
|
17
|
+
if s.downcase.index('infinity')
|
18
|
+
new (1.0/0.0) # Infinity
|
19
|
+
else
|
20
|
+
result = new s.to_f
|
21
|
+
result.precision = precision s
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def ScientificDouble.precision s
|
27
|
+
value = s.to_f
|
28
|
+
bound = tweak(s.strip).to_f
|
29
|
+
(bound - value).abs
|
30
|
+
end
|
31
|
+
|
32
|
+
def ScientificDouble.tweak s
|
33
|
+
pos = s.downcase.index('e')
|
34
|
+
unless pos.nil?
|
35
|
+
return tweak(s[0..(pos - 1)]) + s[pos..-1]
|
36
|
+
end
|
37
|
+
unless s.index('.').nil?
|
38
|
+
return s + "5"
|
39
|
+
end
|
40
|
+
return s + ".5"
|
41
|
+
end
|
42
|
+
|
43
|
+
def == obj
|
44
|
+
sd = ScientificDouble.value_of obj.to_s
|
45
|
+
self.<=>(sd) == 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def <=> obj
|
49
|
+
other = obj.to_f
|
50
|
+
diff = @value - other
|
51
|
+
|
52
|
+
# workaround the much more precise way of Ruby doing floats than Java
|
53
|
+
return 0 if @precision.zero? and diff.abs < 1.0e-5
|
54
|
+
|
55
|
+
precision = @precision > obj.precision ? @precision : obj.precision
|
56
|
+
return -1 if diff < -precision
|
57
|
+
return 1 if diff > precision
|
58
|
+
return 0 if @value.nan? and other.nan?
|
59
|
+
return 1 if @value.nan?
|
60
|
+
return -1 if other.nan?
|
61
|
+
0
|
62
|
+
end
|
63
|
+
|
64
|
+
def nan?; @value.nan?; end # unused?
|
65
|
+
def to_f; @value; end
|
66
|
+
def to_s; @value.to_s; end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/fit/summary.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
module Fit
|
5
|
+
|
6
|
+
class Summary < Fixture
|
7
|
+
@@counts_key = 'counts'
|
8
|
+
|
9
|
+
def do_table table
|
10
|
+
@summary[@@counts_key] = totals
|
11
|
+
table.parts.more = rows @summary.keys.sort
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def rows keys
|
17
|
+
return nil if keys.empty?
|
18
|
+
key = keys.shift
|
19
|
+
result = tr(td(key, td(summary[key].to_s, nil)), rows(keys))
|
20
|
+
mark(result) if key == @@counts_key
|
21
|
+
result
|
22
|
+
end
|
23
|
+
|
24
|
+
def tr parts, more
|
25
|
+
ParseHolder.create('tr', nil, parts, more)
|
26
|
+
end
|
27
|
+
|
28
|
+
def td body, more
|
29
|
+
ParseHolder.create('td', Fixture.gray(body), nil, more)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Mark summary good or bad without counting
|
33
|
+
def mark row
|
34
|
+
official = @counts
|
35
|
+
@counts = Counts.new # use a fake results holder to avoid counting
|
36
|
+
cell = row.parts.more
|
37
|
+
if official.total_errors > 0
|
38
|
+
wrong cell
|
39
|
+
else
|
40
|
+
right cell
|
41
|
+
end
|
42
|
+
@counts = official
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/action_fixture'
|
5
|
+
|
6
|
+
module Fit
|
7
|
+
|
8
|
+
class TimedActionFixture < ActionFixture
|
9
|
+
attr_accessor :format
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
@format = '%H:%M:%S'
|
13
|
+
end
|
14
|
+
def do_table table
|
15
|
+
super
|
16
|
+
table.parts.parts.last.more = td('time')
|
17
|
+
table.parts.parts.last.more = td('split')
|
18
|
+
end
|
19
|
+
def do_cells cells
|
20
|
+
start = time
|
21
|
+
super
|
22
|
+
split = time - start
|
23
|
+
cells.last.more = td(start.strftime(@format))
|
24
|
+
cells.last.more = td(split < 1 ? ' ' : sprintf("%1.1f", split))
|
25
|
+
end
|
26
|
+
# Utility
|
27
|
+
def td body
|
28
|
+
ParseHolder.create('td', Fixture.gray(body), nil, nil)
|
29
|
+
end
|
30
|
+
def time
|
31
|
+
Time.now
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/scientific_double'
|
5
|
+
|
6
|
+
module Fit
|
7
|
+
|
8
|
+
class TypeAdapter
|
9
|
+
|
10
|
+
attr_accessor :target, :type, :fixture
|
11
|
+
|
12
|
+
def initialize target, name = '', is_output = false
|
13
|
+
@is_output = is_output
|
14
|
+
@target = @fixture = target
|
15
|
+
|
16
|
+
@name=name
|
17
|
+
ends_in_qm = is_output && name=~/\?$/
|
18
|
+
if @name.index(/[A-Z]/)
|
19
|
+
@name = @name.split(/([A-Z][^A-Z]+)/).delete_if {|e| e.empty?}.collect {|e| e.downcase}.join('_')
|
20
|
+
end
|
21
|
+
@name = @name.gsub(/[^0-9a-zA-Z_]+$/,'').gsub(/[^0-9a-zA-Z_]+/,'_').gsub(/_+/,'_')
|
22
|
+
@name << '?' if ends_in_qm
|
23
|
+
end
|
24
|
+
|
25
|
+
# Factories
|
26
|
+
|
27
|
+
def TypeAdapter.for fixture, name, is_output=(name=~/(\(\))|(\?)$/)
|
28
|
+
GenericAdapter.new fixture, name, is_output
|
29
|
+
end
|
30
|
+
|
31
|
+
def TypeAdapter.on fixture, type
|
32
|
+
adapter = GenericAdapter.new fixture
|
33
|
+
adapter.type = type
|
34
|
+
adapter
|
35
|
+
end
|
36
|
+
|
37
|
+
def get
|
38
|
+
return nil if @name.nil?
|
39
|
+
getter = @name
|
40
|
+
getter.chop! if getter =~ /\?$/ && ! @target.respond_to?(getter.to_sym)
|
41
|
+
@target.send(getter)
|
42
|
+
end
|
43
|
+
|
44
|
+
def set value
|
45
|
+
raise 'Output fields cannot be set' if @is_output
|
46
|
+
@target.send("#{@name}=", value)
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_output?
|
50
|
+
@is_output
|
51
|
+
end
|
52
|
+
|
53
|
+
def equals a, b
|
54
|
+
if ((a.kind_of? Float) and (b.kind_of? Numeric)) or ((a.kind_of? Numeric) and (b.kind_of? Float))
|
55
|
+
(a - b).abs < 1.0e-5 # use a delta to test equality between a float and a number
|
56
|
+
else
|
57
|
+
a == b
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s target
|
62
|
+
target.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# A generic adapter uses the appartent type of its input to store
|
68
|
+
# appropriate values. For example, if a cell contains <td>1</td>,
|
69
|
+
# a Fixnum is generated; if a cell contains <td>0.5</td>, a Float
|
70
|
+
# is generated. Note that this process might not feasible for every
|
71
|
+
# type of primitive data.
|
72
|
+
class GenericAdapter < TypeAdapter
|
73
|
+
def parse value
|
74
|
+
return true if value.downcase == 'true'
|
75
|
+
return false if value.downcase == 'false'
|
76
|
+
unless @type.nil?
|
77
|
+
result = @fixture.parse value, @type
|
78
|
+
return result unless result.nil?
|
79
|
+
end
|
80
|
+
return Integer(value) if value =~ /^-?\d+$/
|
81
|
+
return Float(value) if (value =~ /^-?\d*\.\d*$/ || value =~ /^-?\d*\.\d*[e|E]\d+$/)
|
82
|
+
elements = value.split(',')
|
83
|
+
unless elements.size == 1
|
84
|
+
array = []
|
85
|
+
element_adapter = TypeAdapter.for @target, @name, @is_output
|
86
|
+
elements.each do |e|
|
87
|
+
array << element_adapter.parse(e.strip)
|
88
|
+
end
|
89
|
+
return array
|
90
|
+
end
|
91
|
+
return value
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/file_runner'
|
5
|
+
|
6
|
+
$stderr.puts 'WikiRunner is deprecated: use FileRunner'
|
7
|
+
|
8
|
+
if __FILE__ == $0
|
9
|
+
begin
|
10
|
+
Fit::FileRunner.new.run ARGV
|
11
|
+
rescue Exception => e
|
12
|
+
$stderr.puts e.message
|
13
|
+
exit -1
|
14
|
+
end
|
15
|
+
end
|
data/lib/fittask.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
require 'fit/file_runner'
|
5
|
+
require 'fit/parse'
|
6
|
+
|
7
|
+
module Rake
|
8
|
+
|
9
|
+
class FitReportRunner < Fit::FileRunner
|
10
|
+
def run args
|
11
|
+
process_args args
|
12
|
+
process
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class FitRunner < Fit::FileRunner
|
17
|
+
def run args
|
18
|
+
process_args args
|
19
|
+
process
|
20
|
+
end
|
21
|
+
def process_args args
|
22
|
+
input_name = File.expand_path args[0]
|
23
|
+
input_file = File.open input_name
|
24
|
+
@input = input_file.read
|
25
|
+
input_file.close
|
26
|
+
@output = OutputStream.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# A dummy output stream to avoid creating output files
|
31
|
+
class OutputStream < String
|
32
|
+
def print text; end
|
33
|
+
def close; end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a task that runs a set of FIT tests.
|
37
|
+
#
|
38
|
+
# If rake is invoked with a ATEST command line option, then the list of
|
39
|
+
# test files will be overridden to include only the filename specified on
|
40
|
+
# the command line. This provides an easy way to run just one test.
|
41
|
+
# The exact syntax of the ATEST option is as follows:
|
42
|
+
# ATEST=/path/to/FileHtml:Right:Wrong:Ignores:Exceptions
|
43
|
+
# where you can include a path to the HTML file, which must be specified
|
44
|
+
# without the .html extension; and where Rights, Wrong, Ignores and
|
45
|
+
# Exceptions are the numbers of the expected results from the test run.
|
46
|
+
# Note that the report path will be the same as the test path.
|
47
|
+
#
|
48
|
+
class FitTask < TaskLib
|
49
|
+
|
50
|
+
attr_accessor :name, :libs, :pattern, :fail_on_failed_test
|
51
|
+
|
52
|
+
def test_suites=(list)
|
53
|
+
@test_suites = list
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_suites
|
57
|
+
if ENV['ATEST']
|
58
|
+
atest = ENV['ATEST'].split ':'
|
59
|
+
filename = atest[0]
|
60
|
+
test_name = File.basename(filename)
|
61
|
+
test = { :name => test_name,
|
62
|
+
:right => atest[1].to_i, :wrong => atest[2].to_i,
|
63
|
+
:ignores => atest[3].to_i, :exceptions => atest[4].to_i }
|
64
|
+
suite = AcceptanceTestSuite.new
|
65
|
+
suite << test
|
66
|
+
suite.test_path = suite.report_path = File.dirname(filename) + File::SEPARATOR
|
67
|
+
[suite]
|
68
|
+
else
|
69
|
+
@test_suites
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize(name=:fittest)
|
74
|
+
@name = name
|
75
|
+
@libs = ["lib"]
|
76
|
+
@pattern = nil
|
77
|
+
@test_files = []
|
78
|
+
@test_suites = []
|
79
|
+
@fail_on_failed_test=false
|
80
|
+
@tests_failed=false
|
81
|
+
yield self if block_given?
|
82
|
+
define name
|
83
|
+
end
|
84
|
+
|
85
|
+
def define task_name
|
86
|
+
# describe the fit task
|
87
|
+
desc "Run FIT acceptance tests"
|
88
|
+
task task_name
|
89
|
+
# silence footnote creation since we don't want HTML reports
|
90
|
+
task task_name do
|
91
|
+
Fit::Parse.send(:define_method, 'footnote', lambda {''})
|
92
|
+
end
|
93
|
+
# define a fit task for each test suite
|
94
|
+
test_suites.each do |suite|
|
95
|
+
task task_name do
|
96
|
+
@tests_failed = true unless suite.run_tests
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
task task_name do
|
101
|
+
raise 'Tests failed.' if @fail_on_failed_test && @tests_failed
|
102
|
+
end
|
103
|
+
|
104
|
+
# describe the fit_report task
|
105
|
+
desc "Run FIT acceptance tests with HTML reports"
|
106
|
+
task_report_name = (task_name.to_s + '_report').to_sym
|
107
|
+
task task_report_name
|
108
|
+
# define a fit_report task for each test suite
|
109
|
+
test_suites.each do |suite|
|
110
|
+
task task_report_name do
|
111
|
+
# set footnote path to an appropriate location
|
112
|
+
Fit::Parse.footnote_path = suite.report_path
|
113
|
+
# run tests
|
114
|
+
@tests_failed = true unless suite.run_tests_with_reports
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
task task_report_name do
|
119
|
+
raise 'Tests failed.' if @fail_on_failed_test && @tests_failed
|
120
|
+
end
|
121
|
+
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
def create_test_suite &block
|
126
|
+
suite = AcceptanceTestSuite.new
|
127
|
+
block.call suite
|
128
|
+
@test_suites << suite
|
129
|
+
end
|
130
|
+
|
131
|
+
class AcceptanceTestSuite
|
132
|
+
attr_accessor :test_path, :report_path, :tests
|
133
|
+
def initialize
|
134
|
+
@tests = []
|
135
|
+
@test_path = @report_path = ''
|
136
|
+
end
|
137
|
+
def << test
|
138
|
+
@tests << test
|
139
|
+
end
|
140
|
+
|
141
|
+
def run_tests_with_reports; run_tests true; end;
|
142
|
+
|
143
|
+
def run_tests with_report=false
|
144
|
+
all_passed = true
|
145
|
+
@tests.each do |test|
|
146
|
+
begin
|
147
|
+
runner_args = [@test_path + "#{test[:name]}.html"]
|
148
|
+
puts "Running #{test[:name]}.html"
|
149
|
+
|
150
|
+
if with_report
|
151
|
+
report_file=@report_path + "Report_#{test[:name]}.html"
|
152
|
+
puts " (Writing report to #{report_file})"
|
153
|
+
runner_args << report_file
|
154
|
+
runner = Rake::FitReportRunner.new
|
155
|
+
else
|
156
|
+
runner = Rake::FitRunner.new
|
157
|
+
end
|
158
|
+
|
159
|
+
runner.run runner_args
|
160
|
+
result = runner.fixture.counts
|
161
|
+
verify test, result
|
162
|
+
rescue Exception => e
|
163
|
+
puts " #{test[:name]} failed: #{e}"
|
164
|
+
all_passed = false
|
165
|
+
end
|
166
|
+
end
|
167
|
+
all_passed
|
168
|
+
end
|
169
|
+
|
170
|
+
def verify test, result
|
171
|
+
[:exceptions,:wrong].each { |symbol| test[symbol] = 0 if test[symbol].nil? }
|
172
|
+
[:right, :wrong, :ignores, :exceptions].each do |symbol|
|
173
|
+
count = result.method(symbol).call
|
174
|
+
expected = test[symbol]
|
175
|
+
unless expected.nil? || count == expected
|
176
|
+
raise Exception.new("#{expected} #{symbol} expected, found #{count} instead.")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
data/test/all_tests.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
require 'test/file_runner_test'
|
7
|
+
require 'test/fit_server_test'
|
8
|
+
require 'test/fixture_test'
|
9
|
+
#require 'test/framework_test'
|
10
|
+
require 'test/parse_test'
|
11
|
+
require 'test/scientific_double_test'
|
12
|
+
require 'test/type_adapter_test'
|
13
|
+
require 'test/fixture_loader_test'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright (c) 2002 Cunningham & Cunningham, Inc.
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
# Make the test run location independent
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
require 'fit/file_runner'
|
8
|
+
|
9
|
+
module Fit
|
10
|
+
|
11
|
+
class FileRunnerTest < Test::Unit::TestCase
|
12
|
+
def test_simple_html
|
13
|
+
simple_html = "<table>" +
|
14
|
+
" <tr><td>fit.Fixture</td></tr>" +
|
15
|
+
"</table>"
|
16
|
+
do_html simple_html
|
17
|
+
end
|
18
|
+
def test_wiki_html
|
19
|
+
wiki_html = "<table><tr><td>extra formatting" +
|
20
|
+
" <wiki>" +
|
21
|
+
" <table>" +
|
22
|
+
" <tr><td>fit.Fixture</td></tr>" +
|
23
|
+
" </table>" +
|
24
|
+
" </wiki>" +
|
25
|
+
"</td></tr></table>"
|
26
|
+
do_html wiki_html
|
27
|
+
end
|
28
|
+
def do_html text
|
29
|
+
runner = FileRunner.new
|
30
|
+
runner.fixture = TempFixture.new
|
31
|
+
runner.input = text
|
32
|
+
runner.output = OutputStream.new
|
33
|
+
runner.process
|
34
|
+
|
35
|
+
assert_equal 'fit.Fixture', $tempParse.leaf.text
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# What's the Ruby equivalent of Java anonymous classes?
|
40
|
+
class TempFixture < Fixture
|
41
|
+
def do_tables tables
|
42
|
+
$tempParse = tables
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# A dummy output stream
|
47
|
+
class OutputStream < String
|
48
|
+
def print text; end
|
49
|
+
def close; end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|