gotime-slither 1.0.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.
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Slither::Generator do
4
+ before(:each) do
5
+ @definition = Slither.define :test do |d|
6
+ d.header do |h|
7
+ h.trap { |line| line[0,4] == 'HEAD' }
8
+ h.column :type, 4
9
+ h.column :file_id, 10
10
+ end
11
+ d.body do |b|
12
+ b.trap { |line| line[0,4] =~ /[^(HEAD|FOOT)]/ }
13
+ b.column :first, 10
14
+ b.column :last, 10
15
+ end
16
+ d.footer do |f|
17
+ f.trap { |line| line[0,4] == 'FOOT' }
18
+ f.column :type, 4
19
+ f.column :file_id, 10
20
+ end
21
+ end
22
+ @data = {
23
+ :header => [ {:type => "HEAD", :file_id => "1" }],
24
+ :body => [
25
+ {:first => "Paul", :last => "Hewson" },
26
+ {:first => "Dave", :last => "Evans" }
27
+ ],
28
+ :footer => [ {:type => "FOOT", :file_id => "1" }]
29
+ }
30
+ @generator = Slither::Generator.new(@definition)
31
+ end
32
+
33
+ it "should raise an error if there is no data for a required section" do
34
+ @data.delete :header
35
+ lambda { @generator.generate(@data) }.should raise_error(Slither::RequiredSectionEmptyError, "Required section 'header' was empty.")
36
+ end
37
+
38
+ it "should generate a string with default newline options" do
39
+ expected = "HEAD 1\n Paul Hewson\n Dave Evans\nFOOT 1"
40
+ @generator.generate(@data).should == expected
41
+ end
42
+
43
+ it "should generate a string with the specified newline options" do
44
+ @definition.options.merge!({:newline_style => :dos, :terminal_newline => true})
45
+ expected = "HEAD 1\r\n Paul Hewson\r\n Dave Evans\r\nFOOT 1\r\n"
46
+ @generator.generate(@data).should == expected
47
+ end
48
+ end
@@ -0,0 +1,297 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Slither::Parser do
4
+
5
+ describe "when parsing sections" do
6
+ before(:each) do
7
+ @definition = Slither.define :test, :by_bytes => false do |d|
8
+ d.header do |h|
9
+ h.trap { |line| line[0,4] == 'HEAD' }
10
+ h.column :type, 4
11
+ h.column :file_id, 10
12
+ end
13
+ d.body do |b|
14
+ b.trap { |line| line[0,4] != 'HEAD' && line[0,4] != 'FOOT'}
15
+ b.column :first, 10
16
+ b.column :last, 10
17
+ end
18
+ d.footer do |f|
19
+ f.trap { |line| line[0,4] == 'FOOT' }
20
+ f.column :type, 4
21
+ f.column :file_id, 10
22
+ end
23
+ end
24
+
25
+ @io = StringIO.new
26
+ @parser = Slither::Parser.new(@definition, @io)
27
+ end
28
+
29
+ it "should add lines to the proper sections" do
30
+ @io.string = "HEAD 1\n Paul Hewson\n Dave Evans\nFOOT 1"
31
+
32
+ expected = {
33
+ :header => [ {:type => "HEAD", :file_id => "1" }],
34
+ :body => [
35
+ {:first => "Paul", :last => "Hewson" },
36
+ {:first => "Dave", :last => "Evans" }
37
+ ],
38
+ :footer => [ {:type => "FOOT", :file_id => "1" }]
39
+ }
40
+ result = @parser.parse
41
+ result.should == expected
42
+ end
43
+
44
+ it "should allow optional sections to be skipped" do
45
+ @definition.sections[0].optional = true
46
+ @definition.sections[2].optional = true
47
+ @io.string = ' Paul Hewson'
48
+
49
+ expected = { :body => [ {:first => "Paul", :last => "Hewson" } ] }
50
+ @parser.parse.should == expected
51
+ end
52
+
53
+ it "should raise an error if a required section is not found" do
54
+ @io.string = ' Ryan Wood'
55
+
56
+ lambda { @parser.parse }.should raise_error(Slither::RequiredSectionNotFoundError, "Required section 'header' was not found.")
57
+ end
58
+
59
+ it "should raise an error if the line is too long" do
60
+ @definition.sections[0].optional = true
61
+ @definition.sections[2].optional = true
62
+ @io.string = 'abc'*20
63
+
64
+ lambda { @parser.parse }.should raise_error(Slither::LineWrongSizeError)
65
+ end
66
+
67
+ it "should raise an error if the line is too short" do
68
+ @definition.sections[0].optional = true
69
+ @definition.sections[2].optional = true
70
+ @io.string = 'abc'
71
+
72
+ lambda { @parser.parse }.should raise_error(Slither::LineWrongSizeError)
73
+ end
74
+
75
+ it "shouldn't raise an error if validate is turned off and too short" do
76
+ @definition.options[:validate_length] = false
77
+ @definition.sections[0].optional = true
78
+ @definition.sections[2].optional = true
79
+ @io.string = "abcdefghijk\nabc"
80
+
81
+ expected = { :body => [ {:first => "abcdefghij", :last => "k" },
82
+ {:first => "abc", :last => "" } ] }
83
+ @parser.parse.should == expected
84
+ end
85
+
86
+ it "shouldn't raise an error if validate is turned off and too long" do
87
+ @definition.options[:validate_length] = false
88
+ @definition.sections[0].optional = true
89
+ @definition.sections[2].optional = true
90
+ @io.string = 'abcdefghijklmnopqrstuvwxyz'
91
+
92
+ expected = { :body => [ {:first => "abcdefghij", :last => "klmnopqrst" } ] }
93
+ @parser.parse.should == expected
94
+ end
95
+
96
+ it 'should handle utf characters with force_character_offset = true' do
97
+ @definition.sections[0].optional = true
98
+ @definition.sections[2].optional = true
99
+ @definition.options[:force_character_offset] = true
100
+ utf_str1 = "12\xE5\x9B\xBD4567890".force_encoding('utf-8')
101
+ utf_str2 = "ab\xE5\x9B\xBDdefghij".force_encoding('utf-8')
102
+ @io.string = (utf_str1 + utf_str2)
103
+
104
+ (utf_str1 + utf_str2).size.should eq(20)
105
+
106
+ expected = {
107
+ :body => [ {:first => utf_str1, :last => utf_str2} ]
108
+ }
109
+
110
+ Slither.parseIo(@io, :test).should eq(expected)
111
+ end
112
+
113
+ end
114
+
115
+ describe "when parsing by bytes" do
116
+ before(:each) do
117
+ @definition = Slither.define :test do |d|
118
+ d.body do |b|
119
+ b.trap { true }
120
+ b.column :first, 5
121
+ b.column :last, 5
122
+ end
123
+ end
124
+
125
+ @io = StringIO.new
126
+ @parser = Slither::Parser.new(@definition, @io)
127
+ end
128
+
129
+ it 'should raise error for data with line length too long' do
130
+ @io.string = "abcdefghijklmnop"
131
+
132
+ lambda { @parser.parse_by_bytes }.should raise_error(Slither::LineWrongSizeError)
133
+ end
134
+
135
+ it 'should raise error for data with line length too short' do
136
+ @io.string = "abc"
137
+
138
+ lambda { @parser.parse_by_bytes }.should raise_error(Slither::LineWrongSizeError)
139
+ end
140
+
141
+ it 'should raise error for data with empty lines' do
142
+ @io.string = "abcdefghij\r\n\n\n\n" # 10 then 3
143
+
144
+ lambda { @parser.parse_by_bytes }.should raise_error(Slither::LineWrongSizeError)
145
+ end
146
+
147
+ it 'should handle utf characters' do
148
+ utf_str1 = "\xE5\x9B\xBD45"
149
+ utf_str2 = "ab\xE5\x9B\xBD"
150
+ @io.string = (utf_str1 + utf_str2)
151
+
152
+ expected = {
153
+ :body => [ {:first => utf_str1, :last => utf_str2} ]
154
+ }
155
+
156
+ Slither.parseIo(@io, :test).should eq(expected)
157
+ end
158
+
159
+ it 'should handle mid-line newline chars' do
160
+ str1 = "12\n45"
161
+ str2 = "a\n\r\nb"
162
+ @io.string = (str1 + str2 + "\n" + str1 + str2)
163
+
164
+ expected = {
165
+ :body => [ {:first => str1, :last => str2}, {:first => str1, :last => str2} ]
166
+ }
167
+
168
+ Slither.parseIo(@io, :test).should eq(expected)
169
+ end
170
+
171
+ it 'should throw exception if section lengths are different' do
172
+ definition = Slither.define :test, :by_bytes => true do |d|
173
+ d.body do |b|
174
+ b.column :one, 5
175
+ end
176
+ d.foot do |f|
177
+ f.column :only, 2
178
+ end
179
+ end
180
+
181
+ parser = Slither::Parser.new(definition, @io)
182
+
183
+ lambda { parser.parse_by_bytes }.should raise_error(Slither::SectionsNotSameLengthError)
184
+ end
185
+ end
186
+
187
+ describe 'when parsing binary data' do
188
+ before(:each) do
189
+ @definition = Slither.define :test do |d|
190
+ d.body do |b|
191
+ b.trap { true }
192
+ b.column :first, 3
193
+ b.column :dat, 2, type: :binary
194
+ b.column :last, 3
195
+ end
196
+ end
197
+
198
+ @io = StringIO.new
199
+ @parser = Slither::Parser.new(@definition, @io)
200
+ end
201
+
202
+ it 'should work basic case' do
203
+ @io.string = "abc\x00\x18end\n"
204
+
205
+ expected = {
206
+ :body => [ {:first => 'abc', :dat => [0x00, 0x18], :last => 'end'} ]
207
+ }
208
+
209
+ Slither.parseIo(@io, :test).should eq(expected)
210
+ end
211
+
212
+ it 'should handle spaces' do
213
+ @io.string = "abc \x18end\n"
214
+
215
+ expected = {
216
+ :body => [ {:first => 'abc', :dat => [0x20, 0x18], :last => 'end'} ]
217
+ }
218
+
219
+ Slither.parseIo(@io, :test).should eq(expected)
220
+ end
221
+ end
222
+
223
+ describe 'when calling the helper method' do
224
+
225
+ it 'remove_newlines returns true for file starting in newlines or EOF' do
226
+ @io = StringIO.new
227
+ @parser = Slither::Parser.new(@definition, @io)
228
+
229
+ @parser.send(:remove_newlines!).should eq(true)
230
+
231
+ @io.string = "\nXYZ"
232
+ @parser.send(:remove_newlines!).should eq(true)
233
+ @io.string = "\r\n"
234
+ @parser.send(:remove_newlines!).should eq(true)
235
+ @io.string = "\n\n\n\nXYZ\n"
236
+ @parser.send(:remove_newlines!).should eq(true)
237
+ @io.string = ""
238
+ @parser.send(:remove_newlines!).should eq(true)
239
+
240
+ end
241
+
242
+ it 'remove_newlines returns false for any other first characters' do
243
+ @io = StringIO.new
244
+ @parser = Slither::Parser.new(@definition, @io)
245
+
246
+ @io.string = "XYZ\nxyz"
247
+ @parser.send(:remove_newlines!).should eq(false)
248
+ @io.string = " \nxyz"
249
+ @parser.send(:remove_newlines!).should eq(false)
250
+ @io.string = "!YZxyz\n"
251
+ @parser.send(:remove_newlines!).should eq(false)
252
+
253
+ end
254
+
255
+ it 'remove_newlines leaves first non-newline char in place' do
256
+ @io = StringIO.new
257
+ @parser = Slither::Parser.new(@definition, @io)
258
+
259
+ @io.string = "\nXYZ"
260
+ @parser.send(:remove_newlines!).should eq(true)
261
+ @io.getc.should eq("X")
262
+ @parser.send(:remove_newlines!).should eq(false)
263
+ end
264
+
265
+ it 'newline? it is true for \n or \r and false otherwise' do
266
+ @parser = Slither::Parser.new(nil,nil)
267
+
268
+ [["\n",true],["\r",true],["n",false]].each do |el|
269
+ @parser.send(:newline?,el[0].ord).should eq(el[1])
270
+ end
271
+ @parser.send(:newline?,nil).should eq(false)
272
+ @parser.send(:newline?,"").should eq(false)
273
+ end
274
+ end
275
+
276
+ describe "when using error handler" do
277
+
278
+ it "calls the error_handler lambda" do
279
+ error_handler = lambda {|line| raise "error handler exception for #{line}"}
280
+
281
+ @definition = Slither.define :test, error_handler: error_handler do |d|
282
+ d.body do |b|
283
+ b.trap { true }
284
+ b.column :first, 5
285
+ b.column :last, 5
286
+ end
287
+ end
288
+
289
+ @io = StringIO.new 'abc'
290
+ @parser = Slither::Parser.new(@definition, @io)
291
+
292
+ lambda { @parser.parse(error_handler) }.should raise_error(RuntimeError, "error handler exception for abc")
293
+ end
294
+
295
+ end
296
+
297
+ end
@@ -0,0 +1,156 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Slither::Section do
4
+ before(:each) do
5
+ @section = Slither::Section.new(:body)
6
+ end
7
+
8
+ it "should have no columns after creation" do
9
+ @section.columns.should be_empty
10
+ end
11
+
12
+ it "should know it's reserved names" do
13
+ Slither::Section::RESERVED_NAMES.should == [:spacer]
14
+ end
15
+
16
+ describe "when adding columns" do
17
+ it "should build an ordered column list" do
18
+ @section.should have(0).columns
19
+
20
+ col1 = @section.column :id, 10
21
+ col2 = @section.column :name, 30
22
+ col3 = @section.column :state, 2
23
+
24
+ @section.should have(3).columns
25
+ @section.columns[0].should be(col1)
26
+ @section.columns[1].should be(col2)
27
+ @section.columns[2].should be(col3)
28
+ end
29
+
30
+ it "should create spacer columns" do
31
+ @section.should have(0).columns
32
+ @section.spacer(5)
33
+ @section.should have(1).columns
34
+ end
35
+
36
+ it "can should override the alignment of the definition" do
37
+ section = Slither::Section.new('name', :align => :left)
38
+ section.options[:align].should == :left
39
+ end
40
+
41
+ it "should use a missing method to create a column" do
42
+ @section.should have(0).columns
43
+ @section.first_name 5
44
+ @section.should have(1).columns
45
+ end
46
+
47
+ it "should prevent duplicate column names" do
48
+ @section.column :id, 10
49
+ lambda { @section.column(:id, 30) }.should raise_error(Slither::DuplicateColumnNameError, "You have already defined a column named 'id'.")
50
+ end
51
+
52
+ it "should allow duplicate column names that are reserved (i.e. spacer)" do
53
+ @section.spacer 10
54
+ lambda { @section.spacer 10 }.should_not raise_error(Slither::DuplicateColumnNameError)
55
+ end
56
+ end
57
+
58
+ it "should accept and store the trap as a block" do
59
+ @section.trap { |v| v == 4 }
60
+ trap = @section.instance_variable_get(:@trap)
61
+ trap.should be_a(Proc)
62
+ trap.call(4).should == true
63
+ end
64
+
65
+ describe "when adding a template" do
66
+ before(:each) do
67
+ @template = mock('templated section', :columns => [1,2,3], :options => {})
68
+ @definition = mock("definition", :templates => { :test => @template } )
69
+ @section.definition = @definition
70
+ end
71
+
72
+ it "should ensure the template exists" do
73
+ @definition.stub! :templates => {}
74
+ lambda { @section.template(:none) }.should raise_error(ArgumentError)
75
+ end
76
+
77
+ it "should add the template columns to the current column list" do
78
+ @template.should_receive(:length).and_return(0)
79
+ @section.template :test
80
+ @section.should have(3).columns
81
+ end
82
+
83
+ it "should merge the template option" do
84
+ @section = Slither::Section.new(:body, :align => :left)
85
+ @section.definition = @definition
86
+ @template.should_receive(:length).and_return(0)
87
+ @template.stub! :options => {:align => :right}
88
+ @section.template :test
89
+ @section.options.should == {:align => :left}
90
+ end
91
+ end
92
+
93
+ describe "when formatting a row" do
94
+ before(:each) do
95
+ @data = { :id => 3, :name => "Ryan" }
96
+ end
97
+
98
+ it "should default to string data aligned right" do
99
+ @section.column(:id, 5)
100
+ @section.column(:name, 10)
101
+ @section.format( @data ).should == " 3 Ryan"
102
+ end
103
+
104
+ it "should left align if asked" do
105
+ @section.column(:id, 5)
106
+ @section.column(:name, 10, :align => :left)
107
+ @section.format(@data).should == " 3Ryan "
108
+ end
109
+
110
+ # it "should raise an error if the data and column definitions aren't the same size" do
111
+ # @section.column(:id, 5)
112
+ # lambda { @section.format(@data) }.should raise_error(
113
+ # Slither::ColumnMismatchError,
114
+ # "The 'body' section has 1 column(s) defined, but there are 2 column(s) provided in the data."
115
+ # )
116
+ # end
117
+ end
118
+
119
+ describe "when parsing a file" do
120
+ before(:each) do
121
+ @line = ' 45 Ryan WoodSC '
122
+ @section = Slither::Section.new(:body)
123
+ definition = Slither::Definition.new()
124
+ @section.definition = definition
125
+ @column_content = { :id => 5, :first => 10, :last => 10, :state => 2 }
126
+ end
127
+
128
+ it "should return a key for key column" do
129
+ @column_content.each { |k,v| @section.column(k, v) }
130
+ parsed = @section.parse(@line)
131
+ @column_content.each_key { |name| parsed.should have_key(name) }
132
+ end
133
+
134
+ it "should not return a key for reserved names" do
135
+ @column_content.each { |k,v| @section.column(k, v) }
136
+ @section.spacer 5
137
+ @section.should have(5).columns
138
+ parsed = @section.parse(@line)
139
+ parsed.should have(4).keys
140
+ end
141
+
142
+ it "should retain encoding of source" do
143
+ @column_content.each { |k,v| @section.column(k, v) }
144
+ parsed = @section.parse(@line)
145
+ parsed[:id].encoding.should eq(@line.encoding)
146
+ end
147
+ end
148
+
149
+ it "should try to match a line using the trap" do
150
+ @section.trap do |line|
151
+ line == 'hello'
152
+ end
153
+ @section.match('hello').should be_true
154
+ @section.match('goodbye').should be_false
155
+ end
156
+ end