crosstab 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +23 -0
- data/README.txt +133 -0
- data/Rakefile +17 -0
- data/lib/crosstab.rb +25 -0
- data/lib/crosstab/banner.rb +90 -0
- data/lib/crosstab/cell.rb +162 -0
- data/lib/crosstab/column.rb +64 -0
- data/lib/crosstab/crosstab.rb +243 -0
- data/lib/crosstab/extensions.rb +26 -0
- data/lib/crosstab/generic.rb +83 -0
- data/lib/crosstab/group.rb +28 -0
- data/lib/crosstab/row.rb +65 -0
- data/lib/crosstab/table.rb +85 -0
- data/test/test_banner.rb +81 -0
- data/test/test_cell.rb +95 -0
- data/test/test_column.rb +60 -0
- data/test/test_crosstab.rb +214 -0
- data/test/test_extensions.rb +12 -0
- data/test/test_group.rb +67 -0
- data/test/test_missing.rb +75 -0
- data/test/test_row.rb +60 -0
- data/test/test_table.rb +67 -0
- metadata +87 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
class Crosstab::Table < Crosstab::Generic
|
2
|
+
# Pass in a block and we'll execute it within the context of this class.
|
3
|
+
#
|
4
|
+
# Example:
|
5
|
+
#
|
6
|
+
# my_crosstab = Crosstab.new do
|
7
|
+
# table do
|
8
|
+
# row "Male", :a => 1
|
9
|
+
# row "Female", :a => 2
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
def initialize(&block)
|
14
|
+
instance_eval(&block) if block
|
15
|
+
end
|
16
|
+
|
17
|
+
# attr_reader for the rows attribute which should contain an empty array, or a list of rows
|
18
|
+
#
|
19
|
+
# Example:
|
20
|
+
#
|
21
|
+
# rows
|
22
|
+
# #=> []
|
23
|
+
#
|
24
|
+
# row "Male", :a => 1
|
25
|
+
#
|
26
|
+
# rows
|
27
|
+
# #=> [Crosstab::Row...]
|
28
|
+
#
|
29
|
+
def rows
|
30
|
+
@rows ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
# Creates a new Crosstab::Row and appends it to the rows array.
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
#
|
37
|
+
# rows
|
38
|
+
# #=> []
|
39
|
+
#
|
40
|
+
# row "Male", :a => 1
|
41
|
+
#
|
42
|
+
# rows
|
43
|
+
# #=> [Crosstab::Row...]
|
44
|
+
#
|
45
|
+
def row(name,qualification)
|
46
|
+
rows << Crosstab::Row.new(name, qualification)
|
47
|
+
end
|
48
|
+
|
49
|
+
# DSL child setter, creates a new Group, and rows created within its block will be assigned to that group.
|
50
|
+
#
|
51
|
+
# Example:
|
52
|
+
#
|
53
|
+
# rows
|
54
|
+
# #=> []
|
55
|
+
#
|
56
|
+
# group "Gender" do
|
57
|
+
# row "Male", :a => 1
|
58
|
+
# row "Female", :a => 2
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# rows
|
62
|
+
# #=> [Crosstab::Row..., Crosstab::Row...]
|
63
|
+
#
|
64
|
+
# rows[0].group.title
|
65
|
+
# # => "Gender"
|
66
|
+
#
|
67
|
+
# rows[1].group.title
|
68
|
+
# # => "Gender"
|
69
|
+
|
70
|
+
def group(name=nil, &block)
|
71
|
+
if block
|
72
|
+
old_rows = rows.dup # Save current state
|
73
|
+
|
74
|
+
instance_eval(&block) # Execute block within current scope
|
75
|
+
|
76
|
+
g = Crosstab::Group.new(name) # Create new group
|
77
|
+
|
78
|
+
# Set group for all of the new rows
|
79
|
+
(rows - old_rows).each do |row|
|
80
|
+
row.group g
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/test/test_banner.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
$LOAD_PATH.unshift "../lib" if __FILE__ == $0
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'crosstab'
|
5
|
+
|
6
|
+
class BannerTests < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@banner = Crosstab::Banner.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Responds to these public methods
|
12
|
+
def test_respond_methods
|
13
|
+
[:title, :qualification, :qualifies?, :columns, :column, :group].each do |method|
|
14
|
+
assert_respond_to @banner, method, "Hey, an instantiated banner should have a `#{method}` method."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Test defaults for reader methods
|
19
|
+
def test_default_columns
|
20
|
+
assert_kind_of Array, @banner.columns
|
21
|
+
|
22
|
+
# Should have a total column by default
|
23
|
+
assert_equal 1, @banner.columns.length
|
24
|
+
assert_kind_of Crosstab::Column, @banner.columns.first
|
25
|
+
assert_equal "Total", @banner.columns.first.title
|
26
|
+
assert_equal true, @banner.columns.first.qualifies?(Hash.new)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_default_title
|
30
|
+
assert_nil @banner.title
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_default_qualifies?
|
34
|
+
assert_equal true, @banner.qualifies?(Hash.new)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Test behavior of setter methods
|
38
|
+
def test_set_title
|
39
|
+
@banner.title "Test Title"
|
40
|
+
assert_equal "Test Title", @banner.title
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_set_qualification
|
44
|
+
@banner.qualification :a => 1
|
45
|
+
|
46
|
+
assert_equal true, @banner.qualifies?(:a => 1, :b => 1)
|
47
|
+
assert_equal false, @banner.qualifies?(:a => 2, :b => 1)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_set_column
|
51
|
+
# erase the default column
|
52
|
+
@banner.columns.pop
|
53
|
+
|
54
|
+
@banner.column "New Column", :a => 2
|
55
|
+
|
56
|
+
assert_equal 1, @banner.columns.length
|
57
|
+
assert_kind_of Crosstab::Column, @banner.columns.first
|
58
|
+
assert_equal "New Column", @banner.columns.first.title
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_set_group
|
62
|
+
# erase the default column
|
63
|
+
@banner.columns.pop
|
64
|
+
|
65
|
+
@banner.group "Gender" do
|
66
|
+
column "Male", :a => 1
|
67
|
+
column "Female", :a => 2
|
68
|
+
end
|
69
|
+
|
70
|
+
assert_equal 2, @banner.columns.length
|
71
|
+
assert_kind_of Crosstab::Column, @banner.columns.first
|
72
|
+
assert_kind_of Crosstab::Column, @banner.columns.last
|
73
|
+
|
74
|
+
assert_equal "Male", @banner.columns.first.title
|
75
|
+
assert_equal "Female", @banner.columns.last.title
|
76
|
+
|
77
|
+
assert_equal "Gender", @banner.columns.first.group.title
|
78
|
+
assert_equal "Gender", @banner.columns.last.group.title
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/test/test_cell.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
$LOAD_PATH.unshift "../lib" if __FILE__ == $0
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class TestCrosstabCell < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@cell = Crosstab::Cell.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# Responds to these public methods
|
11
|
+
def test_respond_methods
|
12
|
+
[:base, :frequency, :percentage, :result, :significant_against?, :column].each do |method|
|
13
|
+
assert_respond_to @cell, method, "Hey, an instantiated cell should have a `#{method}` method."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Test defaults for reader methods
|
18
|
+
def test_default_base
|
19
|
+
assert_equal 0, @cell.base
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_default_frequency
|
23
|
+
assert_equal 0, @cell.frequency
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_default_percentage
|
27
|
+
assert_equal 0, @cell.percentage
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_default_result
|
31
|
+
assert_equal ["--"], @cell.result
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_normal_result
|
35
|
+
@cell.base 100
|
36
|
+
@cell.frequency 75
|
37
|
+
|
38
|
+
assert_equal [75, "75%"], @cell.result
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_zero_frequency_result
|
42
|
+
@cell.base 100
|
43
|
+
@cell.frequency 0
|
44
|
+
|
45
|
+
assert_equal ["--"], @cell.result
|
46
|
+
end
|
47
|
+
|
48
|
+
# Test behavior of setter methods
|
49
|
+
def test_set_base
|
50
|
+
@cell.base 999
|
51
|
+
assert_equal 999, @cell.base
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_set_frequency
|
55
|
+
@cell.frequency 999
|
56
|
+
assert_equal 999, @cell.frequency
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_default_column
|
60
|
+
assert_equal nil, @cell.column
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_set_column
|
64
|
+
column = Crosstab::Column.new
|
65
|
+
@cell.column column
|
66
|
+
assert_equal column, @cell.column
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_alternate_initialization
|
70
|
+
cell = Crosstab::Cell.new :frequency => 2, :base => 4
|
71
|
+
|
72
|
+
assert_equal 2, cell.frequency
|
73
|
+
assert_equal 4, cell.base
|
74
|
+
end
|
75
|
+
|
76
|
+
# Test behavior of complex methods
|
77
|
+
def test_percentage
|
78
|
+
@cell.base 100
|
79
|
+
@cell.frequency 75
|
80
|
+
|
81
|
+
assert_equal 0.75, @cell.percentage
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_significant_against
|
85
|
+
@cell.base 100
|
86
|
+
@cell.frequency 50
|
87
|
+
|
88
|
+
@test_cell_a = Crosstab::Cell.new :base => 100, :frequency => 63
|
89
|
+
@test_cell_b = Crosstab::Cell.new :base => 100, :frequency => 64
|
90
|
+
|
91
|
+
assert_equal false, @test_cell_a.significant_against?(@cell) #63/100 against 50/100 is not significant at a 95% confidence level
|
92
|
+
assert_equal true, @test_cell_b.significant_against?(@cell) #64/100 against 50/100, however, is.
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
data/test/test_column.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
$LOAD_PATH.unshift "../lib" if __FILE__ == $0
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
|
6
|
+
class ColumnTests < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@column = Crosstab::Column.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Responds to these public methods
|
12
|
+
def test_respond_method
|
13
|
+
[:title, :qualification, :qualifies?, :records, :group].each do |method|
|
14
|
+
assert_respond_to @column, method, "Hey, an instantiated column should have a `#{method}` method."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Test defaults for reader methods
|
19
|
+
def test_default_title
|
20
|
+
assert_nil @column.title
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_default_qualifies?
|
24
|
+
assert_equal true, @column.qualifies?(Hash.new)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_default_records
|
28
|
+
assert_equal [], @column.records
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_default_group
|
32
|
+
assert_equal nil, @column.group
|
33
|
+
end
|
34
|
+
|
35
|
+
# Test behavior of setter methods
|
36
|
+
def test_set_title
|
37
|
+
@column.title "Test Title"
|
38
|
+
assert_equal "Test Title", @column.title
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_set_qualification
|
42
|
+
@column.qualification :a => 1
|
43
|
+
|
44
|
+
assert_equal true, @column.qualifies?(:a => 1, :b => 1)
|
45
|
+
assert_equal false, @column.qualifies?(:a => 2, :b => 1)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_set_records
|
49
|
+
record = {:a => 1}
|
50
|
+
|
51
|
+
@column.records [record]
|
52
|
+
assert_equal [record], @column.records
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_set_group
|
56
|
+
@column.group Crosstab::Group.new("Group Title")
|
57
|
+
assert_equal "Group Title", @column.group.title
|
58
|
+
assert_equal [ @column ], @column.group.children
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
$LOAD_PATH.unshift "../lib" if __FILE__ == $0
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'crosstab'
|
5
|
+
|
6
|
+
class CrosstabTests < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
# Minimal crosstab for most tests
|
9
|
+
@crosstab = Crosstab::Crosstab.new
|
10
|
+
|
11
|
+
# Complex crosstab for calculation tests
|
12
|
+
@calculated_crosstab = Crosstab::Crosstab.new do
|
13
|
+
data_source [{:a => 1, :b => 1, :c => 1},
|
14
|
+
{:a => 1, :b => 2, :c => 2},
|
15
|
+
{:a => 1, :b => 2, :c => 4}]
|
16
|
+
|
17
|
+
banner do
|
18
|
+
column "Total"
|
19
|
+
group "Gender" do
|
20
|
+
column "Male", :a => 1
|
21
|
+
column "Female", :a => 2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
table do
|
26
|
+
title "Q.A Gender"
|
27
|
+
row "Male", :a => 1
|
28
|
+
row "Female", :a => 2
|
29
|
+
end
|
30
|
+
|
31
|
+
table do
|
32
|
+
title "Q.B Age"
|
33
|
+
row "18-34", :b => 1
|
34
|
+
row "35-54", :b => 2
|
35
|
+
end
|
36
|
+
|
37
|
+
table do
|
38
|
+
title "Q.C Likelihood of purchasing"
|
39
|
+
|
40
|
+
group "Very/somewhat likely (Net)" do
|
41
|
+
row "Very likely", :c => 1
|
42
|
+
row "Somewhat likely", :c => 2
|
43
|
+
end
|
44
|
+
|
45
|
+
group "Very/somewhat unlikely (Net)" do
|
46
|
+
row "Somewhat unlikely", :c => 3
|
47
|
+
row "Very unlikely", :c => 4
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
@calculated_crosstab.calculate
|
52
|
+
end
|
53
|
+
|
54
|
+
# Responds to these public methods
|
55
|
+
def test_respond_methods
|
56
|
+
[:data_source, :calculate, :title, :qualification,
|
57
|
+
:qualifies?, :banner, :table, :tables, :printed?].each do |method|
|
58
|
+
assert_respond_to @crosstab, method, "Hey an instantiated crosstab should have a `#{method}` method."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Test defaults for reader methods
|
63
|
+
def test_default_data_source
|
64
|
+
assert_equal [], @crosstab.data_source, "By default, `data_source` is supposed to respond with an empty array."
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_default_title
|
68
|
+
assert_nil @crosstab.title, "By default, `title` is supposed to be nil"
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_default_qualifies?
|
72
|
+
record = Hash.new
|
73
|
+
|
74
|
+
assert(@crosstab.qualifies?(record), "By default, `qualifies?` is supposed to respond with true.")
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_default_banner
|
78
|
+
assert_kind_of Crosstab::Banner, @crosstab.banner, "By default, `banner` is supposed to respond with a Crosstab::Banner kind of object. The user shouldn't have to define their own unless they want more than a total column."
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_default_tables
|
82
|
+
assert_equal [], @crosstab.tables, "By default, `tables` is supposed to respond with an empty array."
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_default_printed?
|
86
|
+
assert_equal false, @crosstab.printed?
|
87
|
+
end
|
88
|
+
|
89
|
+
# Test behavior of setter methods
|
90
|
+
def test_set_data_source
|
91
|
+
test_data = [{:a => 1}, {:a => 2}]
|
92
|
+
|
93
|
+
@crosstab.data_source test_data
|
94
|
+
assert_equal test_data, @crosstab.data_source, "`data_source [{:a => 1}, {:a => 2}]` is supposed to respond with the same thing it was set with."
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_set_title
|
98
|
+
@crosstab.title "Test Title"
|
99
|
+
assert_equal "Test Title", @crosstab.title
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_set_qualification
|
103
|
+
@crosstab.qualification :a => true
|
104
|
+
|
105
|
+
assert_equal true, @crosstab.qualifies?({:a => true}), "`qualification :a => true` should redefine `qualifies?` so that it returns true on `qualifies? {:a => true}`"
|
106
|
+
assert_equal false, @crosstab.qualifies?({:a => false}), "`qualification :a => true` should redefine `qualifies?` so that it returns false on `qualifies? {:a => false}`"
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_set_banner
|
110
|
+
old_banner = @crosstab.banner
|
111
|
+
@crosstab.banner do
|
112
|
+
# empty on purpose
|
113
|
+
end
|
114
|
+
|
115
|
+
assert_not_same old_banner, @crosstab.banner, "`banner` should create a new banner. It didn't. It still has the same ID."
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_set_table
|
119
|
+
@crosstab.table do
|
120
|
+
# empty on purpose
|
121
|
+
end
|
122
|
+
|
123
|
+
assert_equal 1, @crosstab.tables.length, "`table {}` should push a new table onto `tables`. `tables` should now have a length of 1."
|
124
|
+
assert_kind_of Crosstab::Table, @crosstab.tables.first, "`table {}` should push a new Crosstab::Table object onto `tables`. It didn't."
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_set_printed?
|
128
|
+
@crosstab.printed? true
|
129
|
+
assert_equal true, @crosstab.printed?
|
130
|
+
end
|
131
|
+
|
132
|
+
# Test the post-calculation methods
|
133
|
+
def test_calculate_adds_cells
|
134
|
+
columns = @calculated_crosstab.banner.columns
|
135
|
+
rows = @calculated_crosstab.tables[0].rows
|
136
|
+
|
137
|
+
assert_equal true, rows.all? { |row| row.cells.length == columns.length }, "Each row should have a number of cells equal to the number of columns in the banner."
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_calculate_cells_make_sense
|
141
|
+
|
142
|
+
tables = []
|
143
|
+
|
144
|
+
tables << []
|
145
|
+
tables.last << [{:frequency => 3, :base => 3},
|
146
|
+
{:frequency => 3, :base => 3},
|
147
|
+
{:frequency => 0, :base => 0}] # Male
|
148
|
+
|
149
|
+
tables.last << [{:frequency => 0, :base => 3},
|
150
|
+
{:frequency => 0, :base => 3},
|
151
|
+
{:frequency => 0, :base => 0}] # Female
|
152
|
+
|
153
|
+
tables << []
|
154
|
+
tables.last << [{:frequency => 1, :base => 3},
|
155
|
+
{:frequency => 1, :base => 3},
|
156
|
+
{:frequency => 0, :base => 0}] # 18-34
|
157
|
+
tables.last << [{:frequency => 2, :base => 3},
|
158
|
+
{:frequency => 2, :base => 3},
|
159
|
+
{:frequency => 0, :base => 0}] # 35+
|
160
|
+
|
161
|
+
tables << []
|
162
|
+
tables.last << [{:frequency => 1, :base => 3},
|
163
|
+
{:frequency => 1, :base => 3},
|
164
|
+
{:frequency => 0, :base => 0}] # Very likely
|
165
|
+
tables.last << [{:frequency => 1, :base => 3},
|
166
|
+
{:frequency => 1, :base => 3},
|
167
|
+
{:frequency => 0, :base => 0}] # Somewhat likely
|
168
|
+
tables.last << [{:frequency => 0, :base => 3},
|
169
|
+
{:frequency => 0, :base => 3},
|
170
|
+
{:frequency => 0, :base => 0}] # Somewhat unlikely
|
171
|
+
tables.last << [{:frequency => 1, :base => 3},
|
172
|
+
{:frequency => 1, :base => 3},
|
173
|
+
{:frequency => 0, :base => 0}] # Very unlikely
|
174
|
+
|
175
|
+
tables.each_with_index do |table, table_index|
|
176
|
+
table.each_with_index do |row, row_index|
|
177
|
+
row.each_with_index do |cell, cell_index|
|
178
|
+
cell.each do |method,value|
|
179
|
+
assert_equal value, @calculated_crosstab.
|
180
|
+
tables[table_index].
|
181
|
+
rows[row_index].
|
182
|
+
cells[cell_index].
|
183
|
+
send(method), "for @calculated_crosstab.tables[#{table_index}].rows[#{row_index}].cells[#{cell_index}].send(#{method.inspect})"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_calculate_groups
|
191
|
+
groups = []
|
192
|
+
groups << [{:frequency => 2, :base => 3},
|
193
|
+
{:frequency => 2, :base => 3},
|
194
|
+
{:frequency => 0, :base => 0}] # Very//somewhat likely
|
195
|
+
groups << [{:frequency => 1, :base => 3},
|
196
|
+
{:frequency => 1, :base => 3},
|
197
|
+
{:frequency => 0, :base => 0}] # Somewhat unlikely
|
198
|
+
|
199
|
+
groups.each_with_index do |row, index|
|
200
|
+
row.each_with_index do |cell, cell_index|
|
201
|
+
cell.each do |method, value|
|
202
|
+
# index + 1 is a cheat for referencing rows 1 & 2 which both have two different groups.
|
203
|
+
assert_equal value,
|
204
|
+
@calculated_crosstab.tables[2].rows[index + 1].group.cells[cell_index].send(method)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_add_tests_for_to_s
|
211
|
+
assert false
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|