gotime-slither 1.0.2

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