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