fit 1.1 → 1.2
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/CHANGELOG +27 -0
- data/{README.txt → README.rdoc} +28 -9
- data/Rakefile +44 -4
- data/bin/fit +29 -3
- data/doc/book/TestChatServer.html +207 -0
- data/doc/book/TestDiscount.html +178 -0
- data/doc/book/TestDiscountGroup.html +223 -0
- data/doc/book/TestDiscountMoney.html +179 -0
- data/doc/book/TestLateHours.html +245 -0
- data/doc/bugs/ColumnFixtureFollowedByActionFixture.html +316 -0
- data/doc/examples/MusicExampleWithErrors.html +1 -1
- data/doc/spec/annotation.html +3634 -3833
- data/doc/spec/index.html +1043 -947
- data/doc/spec/parse-windows-1252.html +3806 -0
- data/doc/spec/parse.html +3806 -3094
- data/doc/spec/ui.html +1537 -0
- data/lib/eg/all_files.rb +1 -1
- data/lib/eg/book/calculate_discount.rb +25 -0
- data/lib/eg/book/calculate_discount_money.rb +60 -0
- data/lib/eg/book/chat_server_actions.rb +85 -0
- data/lib/eg/book/discount_group_ordered_list.rb +59 -0
- data/lib/eg/book/rent/calculate_late_hours.rb +35 -0
- data/lib/eg/column_index.rb +4 -3
- data/lib/eg/music/display.rb +4 -2
- data/lib/eg/music/music.rb +4 -2
- data/lib/fat/command_line_fixture.rb +33 -0
- data/lib/fat/html_to_text_fixture.rb +3 -3
- data/lib/fit/column_fixture.rb +11 -7
- data/lib/fit/file_runner.rb +65 -10
- data/lib/fit/fixture.rb +10 -4
- data/lib/fit/fixture_loader.rb +29 -19
- data/lib/fit/parse.rb +46 -12
- data/lib/fit/type_adapter.rb +8 -3
- data/lib/fit/version.rb +26 -0
- data/lib/fitlibrary/comment_fixture.rb +12 -0
- data/lib/fitlibrary/spec/specify_fixture.rb +154 -0
- data/lib/fitlibrary/specify/column_fixture_under_test.rb +17 -0
- data/lib/fitlibrary/specify/column_fixture_under_test_with_args.rb +17 -0
- data/lib/fittask.rb +43 -47
- data/test/all_tests.rb +2 -1
- data/test/column_fixture_test.rb +26 -0
- data/test/file_runner_test.rb +2 -7
- data/test/fixture_loader_test.rb +16 -3
- data/test/parse_test.rb +18 -3
- data/test/type_adapter_test.rb +58 -44
- metadata +180 -156
data/lib/fit/fixture.rb
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
# Released under the terms of the GNU General Public License version 2 or later.
|
3
3
|
|
4
4
|
require 'fit/scientific_double'
|
5
|
-
require 'parsedate'
|
6
5
|
require 'fit/fixture_loader'
|
7
6
|
|
7
|
+
require 'date'
|
8
|
+
|
8
9
|
module Fit
|
9
10
|
|
10
11
|
class RunTime
|
@@ -60,13 +61,14 @@ module Fit
|
|
60
61
|
@@metadata = {}
|
61
62
|
def Fixture.metadata; @@metadata; end
|
62
63
|
|
64
|
+
@@loader = FixtureLoader.new
|
65
|
+
|
63
66
|
attr_accessor :summary, :counts, :listener, :args
|
64
67
|
|
65
68
|
def initialize
|
66
69
|
@summary = {}
|
67
70
|
@counts = Counts.new
|
68
71
|
@listener = FixtureListener.new
|
69
|
-
@loader = FixtureLoader.new
|
70
72
|
@args = []
|
71
73
|
end
|
72
74
|
|
@@ -77,7 +79,7 @@ module Fit
|
|
77
79
|
# Traversal
|
78
80
|
|
79
81
|
def find_class class_name
|
80
|
-
|
82
|
+
@@loader.find_fixture_class class_name
|
81
83
|
end
|
82
84
|
|
83
85
|
def do_tables tables
|
@@ -91,6 +93,7 @@ module Fit
|
|
91
93
|
fixture.interpret_tables tables
|
92
94
|
rescue Exception => e
|
93
95
|
exception fixture_name, e
|
96
|
+
@listener.table_finished(tables)
|
94
97
|
interpret_following_tables tables
|
95
98
|
end
|
96
99
|
end
|
@@ -267,7 +270,10 @@ module Fit
|
|
267
270
|
end
|
268
271
|
|
269
272
|
def parse string, klass
|
270
|
-
|
273
|
+
if klass == Date
|
274
|
+
d = Date._parse string
|
275
|
+
return [d[:year], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:zone], d[:wday]]
|
276
|
+
end
|
271
277
|
return ScientificDouble.value_of(string) if klass == ScientificDouble
|
272
278
|
return string if klass == String
|
273
279
|
nil
|
data/lib/fit/fixture_loader.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Fit
|
2
4
|
|
3
5
|
class FixtureLoader
|
@@ -9,9 +11,10 @@ module Fit
|
|
9
11
|
|
10
12
|
def find_fixture_class name
|
11
13
|
camelizedName = (name.split(/[^a-zA-Z0-9.:$]/).collect { |word| first = word.slice!(0,1).upcase; first + word }).join.chomp('.')
|
12
|
-
|
13
|
-
raise "Fixture #{name} not found."
|
14
|
-
|
14
|
+
klasses = ([camelizedName, camelizedName + 'Fixture'].collect { |n| find_class(n) }).compact
|
15
|
+
raise "Fixture #{name} not found." if klasses.length == 0
|
16
|
+
klass = klasses.find { |k| k < Fixture }
|
17
|
+
raise "#{name} is not a fixture." unless klass
|
15
18
|
klass
|
16
19
|
end
|
17
20
|
|
@@ -23,7 +26,7 @@ module Fit
|
|
23
26
|
def find_class name
|
24
27
|
klass = find_constant name
|
25
28
|
unless klass
|
26
|
-
([''] + @@fixture_packages).detect do |prefix|
|
29
|
+
([''] + @@fixture_packages.to_a).detect do |prefix|
|
27
30
|
file_path = (prefix + name).gsub(/::/, '/').gsub(/\./, '/')
|
28
31
|
classname = basename = File::basename(file_path)
|
29
32
|
if basename.index('$')
|
@@ -34,19 +37,13 @@ module Fit
|
|
34
37
|
file_basename = basename.split(/([A-Z][^A-Z]+)/).delete_if {|e| e.empty?}.collect {|e| e.downcase!}.join('_')
|
35
38
|
file_dirname = File::dirname(file_path)
|
36
39
|
file_name = (file_dirname == '.' ? '' : file_dirname + '/') + file_basename
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
rescue LoadError
|
41
|
-
require file_name.downcase
|
42
|
-
end
|
43
|
-
rescue LoadError
|
44
|
-
#raise "Couldn't load file #{file_name} or file #{file_name.downcase}"
|
45
|
-
end
|
40
|
+
|
41
|
+
require_file file_name
|
42
|
+
|
46
43
|
if file_dirname == '.'
|
47
44
|
klass_name = classname
|
48
45
|
else
|
49
|
-
klass_name =
|
46
|
+
klass_name = File::dirname(file_path).split(%r{/}).collect { |e|
|
50
47
|
e.index(/[A-Z]/).nil? ? e.capitalize : e
|
51
48
|
}.join('::') + "::#{classname}"
|
52
49
|
end
|
@@ -58,18 +55,31 @@ module Fit
|
|
58
55
|
|
59
56
|
def find_constant name
|
60
57
|
class_name = name.gsub '.', '::'
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
return class_name.split('::').inject(Object) { |par, const| par.const_get(const) }
|
59
|
+
rescue NameError
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def require_file file_name
|
64
|
+
begin
|
65
|
+
require file_name.downcase
|
66
|
+
rescue LoadError
|
67
|
+
require file_name
|
68
|
+
end
|
69
|
+
rescue LoadError
|
70
|
+
#raise "Couldn't load file #{file_name} or file #{file_name.downcase}"
|
64
71
|
end
|
65
72
|
|
66
|
-
@@fixture_packages=['Fit::']
|
73
|
+
@@fixture_packages = Set.new(['Fit::'])
|
67
74
|
# This method adds the name of a module as a 'package' we should search for fixtures.
|
68
75
|
# Supports import_fixture
|
69
76
|
def FixtureLoader.add_fixture_package module_name
|
70
77
|
@@fixture_packages << module_name + '::'
|
71
78
|
end
|
79
|
+
def FixtureLoader.fixture_packages
|
80
|
+
@@fixture_packages
|
81
|
+
end
|
72
82
|
|
73
83
|
end
|
74
84
|
|
75
|
-
end
|
85
|
+
end
|
data/lib/fit/parse.rb
CHANGED
@@ -68,19 +68,19 @@ module Fit
|
|
68
68
|
@more.nil? ? 1 : @more.size + 1
|
69
69
|
end
|
70
70
|
|
71
|
-
def print out
|
72
|
-
out.print @leader
|
73
|
-
out.print @tag
|
71
|
+
def print out, conv=nil
|
72
|
+
out.print conv.nil? ? @leader : conv.iconv(@leader)
|
73
|
+
out.print conv.nil? ? @tag : conv.iconv(@tag)
|
74
74
|
if @parts
|
75
|
-
@parts.print out
|
75
|
+
@parts.print out, conv
|
76
76
|
else
|
77
|
-
out.print @body
|
77
|
+
out.print conv.nil? ? @body : conv.iconv(@body)
|
78
78
|
end
|
79
|
-
out.print @end
|
79
|
+
out.print conv.nil? ? @end : conv.iconv(@end)
|
80
80
|
if @more
|
81
|
-
@more.print out
|
81
|
+
@more.print out, conv
|
82
82
|
else
|
83
|
-
out.print @trailer
|
83
|
+
out.print conv.nil? ? @trailer : conv.iconv(@end)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -165,16 +165,50 @@ module Fit
|
|
165
165
|
end
|
166
166
|
|
167
167
|
def Parse.unescape s
|
168
|
-
str =
|
168
|
+
str = Parse.unescape_numeric_entities s
|
169
|
+
str = str.gsub %r{<br />}, "\n"
|
169
170
|
# unescape HTML entities
|
170
171
|
str = str.gsub(%r{<}, '<').gsub(%r{>}, '>').gsub(%r{ }, ' ').gsub(%r{"}, '"').gsub(%r{&}, '&')
|
171
172
|
# unescape smart quotes
|
172
|
-
|
173
|
+
left_double_quotes = [0x201c].pack('U')
|
174
|
+
right_double_quotes = [0x201d].pack('U')
|
175
|
+
left_single_quotes = [0x2018].pack('U')
|
176
|
+
right_single_quotes = [0x2019].pack('U')
|
177
|
+
str.gsub(left_double_quotes, '"').gsub(right_double_quotes, '"').gsub(left_single_quotes, "'").gsub(right_single_quotes, "'")
|
178
|
+
end
|
179
|
+
|
180
|
+
def Parse.unescape_numeric_entities s
|
181
|
+
result = ''
|
182
|
+
last_start = 0
|
183
|
+
starts_at = s.index '&#'
|
184
|
+
while not starts_at.nil?
|
185
|
+
ends_at = s.index ';', starts_at
|
186
|
+
if ends_at.nil?
|
187
|
+
starts_at = s.index('&#', starts_at + 1)
|
188
|
+
next
|
189
|
+
end
|
190
|
+
begin
|
191
|
+
entity = s[(starts_at + 2)...ends_at]
|
192
|
+
entity = '0x' + entity[1..-1] if (entity =~ /^x/ or entity =~ /^X/)
|
193
|
+
char = Integer(entity)
|
194
|
+
if char <= 0xFFFF
|
195
|
+
result += s[last_start...starts_at] + [char].pack('U')
|
196
|
+
last_start = ends_at + 1
|
197
|
+
end
|
198
|
+
rescue ArgumentError
|
199
|
+
# just loop around again
|
200
|
+
ensure
|
201
|
+
starts_at = s.index '&#', ends_at
|
202
|
+
end
|
203
|
+
end
|
204
|
+
result += s[last_start..-1]
|
173
205
|
end
|
174
206
|
|
175
207
|
def Parse.condense_whitespace s
|
176
|
-
|
177
|
-
|
208
|
+
not_breaking_space = [0x00a0].pack('U')
|
209
|
+
# Hack to work around not_breaking_space being considered
|
210
|
+
# a normal whitespace in Ruby 1.9, thus matching %r{\s+}
|
211
|
+
s.gsub(not_breaking_space, ' ').gsub(%r{\s+}, ' ').gsub(%r{ }, ' ').strip
|
178
212
|
end
|
179
213
|
|
180
214
|
# The original implementation of footnote hardcodes the creation path,
|
data/lib/fit/type_adapter.rb
CHANGED
@@ -59,7 +59,12 @@ module Fit
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def to_s target
|
62
|
-
target
|
62
|
+
case target
|
63
|
+
when Array
|
64
|
+
target.join(", ")
|
65
|
+
else
|
66
|
+
target.to_s
|
67
|
+
end
|
63
68
|
end
|
64
69
|
|
65
70
|
end
|
@@ -77,8 +82,8 @@ module Fit
|
|
77
82
|
result = @fixture.parse value, @type
|
78
83
|
return result unless result.nil?
|
79
84
|
end
|
80
|
-
return Integer(value) if value =~
|
81
|
-
return Float(value) if
|
85
|
+
return Integer(value) if value =~ /\A-?\d+\Z/
|
86
|
+
return Float(value) if value =~ /\A[+-]?\d*\.\d+([eE][+-]?\d+)?\Z/
|
82
87
|
elements = value.split(',')
|
83
88
|
unless elements.size == 1
|
84
89
|
array = []
|
data/lib/fit/version.rb
ADDED
@@ -0,0 +1,26 @@
|
|
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
|
+
VERSION = '1.2'
|
6
|
+
|
7
|
+
VERSION_BLURB = <<EOF_VERSION_BLURB
|
8
|
+
RubyFIT v#{Fit::VERSION}
|
9
|
+
Conforms to Fit Specification v1.2
|
10
|
+
Copyright (C) 2006-9 Giulio Piancastelli
|
11
|
+
License GPLv2+: GNU GPL version 2 or later
|
12
|
+
This is free software: you are free to change and redistribute it.
|
13
|
+
There is NO WARRANTY, to the extent permitted by law.
|
14
|
+
EOF_VERSION_BLURB
|
15
|
+
|
16
|
+
HELP_BLURB = <<EOF_HELP_BLURB
|
17
|
+
usage: #{File.basename($0)} [options] infile outfile
|
18
|
+
|
19
|
+
Options:
|
20
|
+
--encoding=CHARENC read and write files using specified character encoding
|
21
|
+
--version print version number
|
22
|
+
--help show this help screen
|
23
|
+
|
24
|
+
See http://fit.rubyforge.org for further information and to report bugs
|
25
|
+
EOF_HELP_BLURB
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Copyright (c) 2005 Rick Mugridge, University of Auckland, NZ
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/fixture'
|
5
|
+
|
6
|
+
module Fitlibrary
|
7
|
+
|
8
|
+
class CommentFixture < Fit::Fixture
|
9
|
+
def do_table table; end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# Copyright (c) 2005 Rick Mugridge, University of Auckland, NZ
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/fixture'
|
5
|
+
|
6
|
+
module Fitlibrary
|
7
|
+
module Spec
|
8
|
+
|
9
|
+
# Uses embedded tables to specify how fixtures work, based on simple
|
10
|
+
# subclasses of those fixtures.
|
11
|
+
# The test and the report can be in two separate rows, or in a single row.
|
12
|
+
class SpecifyFixture < Fit::Fixture
|
13
|
+
|
14
|
+
def do_table table
|
15
|
+
first_row = table.parts.more
|
16
|
+
actual = first_row.parts.parts
|
17
|
+
second_row = first_row.more
|
18
|
+
expected_cell = second_row.nil? ? first_row.parts.more : second_row.parts
|
19
|
+
expected = expected_cell.parts
|
20
|
+
Fit::Fixture.new.do_tables(actual)
|
21
|
+
if reports_equal(actual, expected)
|
22
|
+
right expected_cell
|
23
|
+
else
|
24
|
+
wrong expected_cell
|
25
|
+
print_parse actual, 'actual'
|
26
|
+
add_table_to_better_show_differences table, actual, expected
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_table_to_better_show_differences table, actual, expected
|
31
|
+
parse_end = table.last
|
32
|
+
cells1 = Fit::ParseHolder.create('td', 'fitlibrary.CommentFixture', nil, nil)
|
33
|
+
cells2 = Fit::ParseHolder.create('td', 'actual', nil, Fit::ParseHolder.create('td', 'expected', nil, nil))
|
34
|
+
cells3 = Fit::ParseHolder.create('td', show(actual), nil, Fit::ParseHolder.create('td', show(expected), nil, nil))
|
35
|
+
rows = Fit::ParseHolder.create('tr', '', cells1, Fit::ParseHolder.create('tr', '', cells2, Fit::ParseHolder.create('tr', '', cells3, nil)))
|
36
|
+
parse_end.more = Fit::ParseHolder.create('table', '', rows, nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def show parse
|
40
|
+
return 'nil' if parse.nil?
|
41
|
+
result = "<#{parse.tag[0..-2]}><ul>"
|
42
|
+
result += show_field('leader', parse.leader)
|
43
|
+
result += parse.parts.nil? ? show_field('body', parse.body) : show(parse.parts)
|
44
|
+
result += show_field('trailer', parse.trailer)
|
45
|
+
result += '</ul>'
|
46
|
+
result += show(parse.more) unless parse.more.nil?
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def show_field field, value
|
51
|
+
if (not value.nil?) and (not value.strip.empty?)
|
52
|
+
"<li>#{field}: '#{no_tags(value)}'"
|
53
|
+
else
|
54
|
+
""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def no_tags value
|
59
|
+
while true
|
60
|
+
index = value.index '<'
|
61
|
+
break if index < 0
|
62
|
+
value = value[0..index] + '<' + value[index + 1..-1]
|
63
|
+
end
|
64
|
+
value
|
65
|
+
end
|
66
|
+
|
67
|
+
def reports_equal actual, expected
|
68
|
+
return expected.nil? if actual.nil?
|
69
|
+
return false if expected.nil?
|
70
|
+
massage_body_to_table actual
|
71
|
+
result = equal_tags(actual, expected) and
|
72
|
+
equal_strings(actual.leader, expected.leader) and
|
73
|
+
equal_bodies(actual, expected) and
|
74
|
+
equal_strings(actual.trailer, expected.trailer) and
|
75
|
+
reports_equal(actual.more, expected.more) and
|
76
|
+
reports_equal(actual.parts, expected.parts)
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
def massage_body_to_table actual
|
81
|
+
if (not actual.body.nil?) and (not actual.body.index('<table').nil?)
|
82
|
+
if actual.parts.nil?
|
83
|
+
begin
|
84
|
+
actual.parts = Fit::Parse.new actual.body
|
85
|
+
rescue Exception => e # FIXME FitParseException
|
86
|
+
# do nothing
|
87
|
+
end
|
88
|
+
end
|
89
|
+
actual.body = ''
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def equal_bodies actual, expected
|
94
|
+
result = equal_bodies_22 actual, expected
|
95
|
+
puts "!SpecifyFixture#equal_bodies(\"#{actual.body}\",\"#{expected.body}\")" unless result
|
96
|
+
result
|
97
|
+
end
|
98
|
+
|
99
|
+
def equal_bodies_22 actual, expected
|
100
|
+
expected_body = canonical_string expected.body
|
101
|
+
actual_body = canonical_string actual.body
|
102
|
+
return true if expected_body == 'IGNORE'
|
103
|
+
return true if actual_body == expected_body
|
104
|
+
stack_trace = 'class="fit_stacktrace">'
|
105
|
+
start = expected_body.index stack_trace
|
106
|
+
unless start.nil?
|
107
|
+
pattern = expected_body[0, start + stack_trace.size]
|
108
|
+
return actual.body =~ pattern
|
109
|
+
end
|
110
|
+
error_message = '<span class="fit_label">'
|
111
|
+
start = expected_body.index error_message
|
112
|
+
unless start.nil?
|
113
|
+
end_span = expected_body.index '</span>', start
|
114
|
+
unless end_span.nil?
|
115
|
+
pattern = expected_body[0, end_span - 1]
|
116
|
+
return actual.body =~ pattern
|
117
|
+
end
|
118
|
+
end
|
119
|
+
false
|
120
|
+
end
|
121
|
+
|
122
|
+
def canonical_string body
|
123
|
+
s = body.nil? ? '' : body.strip
|
124
|
+
s
|
125
|
+
end
|
126
|
+
|
127
|
+
def equal_tags p1, p2
|
128
|
+
p1.tag == p2.tag
|
129
|
+
end
|
130
|
+
|
131
|
+
def equal_strings actual, expected
|
132
|
+
result = equal_strings_22 actual, expected
|
133
|
+
puts "!SpecifyFixture#equal_strings(\"#{actual}\",\"#{expected}\")" unless result
|
134
|
+
result
|
135
|
+
end
|
136
|
+
|
137
|
+
def equal_strings_22 actual, expected
|
138
|
+
return (expected.nil? or expected.strip.empty? or expected == "\n") if actual.nil?
|
139
|
+
return (actual.strip.empty? or actual == "\n") if expected.nil?
|
140
|
+
return true if expected == 'IGNORE'
|
141
|
+
actual.strip == expected.strip
|
142
|
+
end
|
143
|
+
|
144
|
+
# FIXME This should go in Fitlibrary::ParseUtility
|
145
|
+
def print_parse tables, title
|
146
|
+
puts "---------Parse tables for #{title}:----------"
|
147
|
+
tables.print(STDOUT) unless tables.nil?
|
148
|
+
puts "-------------------"
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright (c) 2003 Rick Mugridge, University of Auckland, NZ
|
2
|
+
# Released under the terms of the GNU General Public License version 2 or later.
|
3
|
+
|
4
|
+
require 'fit/column_fixture'
|
5
|
+
|
6
|
+
module Fitlibrary
|
7
|
+
module Specify
|
8
|
+
|
9
|
+
class ColumnFixtureUnderTest < Fit::ColumnFixture
|
10
|
+
attr_accessor :camel_field_name
|
11
|
+
def get_camel_field_name
|
12
|
+
@camel_field_name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|