fit 1.1
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/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
|