2 # Copyright 2007-2010 Wincent Colaiuta. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are met:
6 # 1. Redistributions of source code must retain the above copyright notice,
7 # this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright notice,
9 # this list of conditions and the following disclaimer in the documentation
10 # and/or other materials provided with the distribution.
12 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22 # POSSIBILITY OF SUCH DAMAGE.
24 require File.expand_path('../spec_helper', File.dirname(__FILE__))
26 describe Walrat::ParserState do
28 @base_string = 'this is the string to be parsed'
29 @state = Walrat::ParserState.new @base_string
32 it 'raises an ArgumentError if initialized with nil' do
34 Walrat::ParserState.new nil
35 end.to raise_error(ArgumentError, /nil string/)
38 it 'before parsing has started "remainder" should equal the entire string' do
39 @state.remainder.should == @base_string
42 it 'before parsing has started "remainder" should equal the entire string (when string is an empty string)' do
43 Walrat::ParserState.new('').remainder.should == ''
46 it 'before parsing has started "results" should be empty' do
47 @state.results.should be_empty
50 it '"parsed" should complain if passed nil' do
51 lambda { @state.parsed(nil) }.should raise_error(ArgumentError)
54 it '"skipped" should complain if passed nil' do
55 lambda { @state.skipped(nil) }.should raise_error(ArgumentError)
58 it '"parsed" should return the remainder of the string' do
59 @state.parsed('this is the ').should == 'string to be parsed'
60 @state.parsed('string ').should == 'to be parsed'
61 @state.parsed('to be parsed').should == ''
64 it '"skipped" should return the remainder of the string' do
65 @state.skipped('this is the ').should == 'string to be parsed'
66 @state.skipped('string ').should == 'to be parsed'
67 @state.skipped('to be parsed').should == ''
70 it '"results" should return an unwrapped parsed result (for single results)' do
72 @state.results.should == 'this'
75 it 'skipped substrings should not appear in "results"' do
76 @state.skipped('this')
77 @state.results.should be_empty
80 it 'should return an array of the parsed results (for multiple results)' do
81 @state.parsed('this ')
83 @state.results.should == ['this ', 'is ']
86 it 'should work when the entire string is consumed in a single operation (using "parsed")' do
87 @state.parsed(@base_string).should == ''
88 @state.results.should == @base_string
91 it 'should work when the entire string is consumed in a single operation (using "skipped")' do
92 @state.skipped(@base_string).should == ''
93 @state.results.should be_empty
96 it '"parsed" should complain if passed something that doesn\'t respond to the "line_end" and "column_end" messages' do
98 my_mock = mock('mock_which_does_not_implement_line_end', :null_object => true)
99 my_mock.should_receive(:line_end).and_raise(NoMethodError)
100 lambda { @state.parsed(my_mock) }.should raise_error(NoMethodError)
103 my_mock = mock('mock_which_does_not_implement_column_end', :null_object => true)
104 my_mock.should_receive(:column_end).and_raise(NoMethodError)
105 lambda { @state.parsed(my_mock) }.should raise_error(NoMethodError)
108 it '"skipped" should complain if passed something that doesn\'t respond to the "line_end" and "column_end" messages' do
110 my_mock = mock('mock_which_does_not_implement_line_end', :null_object => true)
111 my_mock.should_receive(:line_end).and_raise(NoMethodError)
112 lambda { @state.skipped(my_mock) }.should raise_error(NoMethodError)
115 my_mock = mock('mock_which_does_not_implement_column_end', :null_object => true)
116 my_mock.should_receive(:column_end).and_raise(NoMethodError)
117 lambda { @state.skipped(my_mock) }.should raise_error(NoMethodError)
120 it 'should be able to mix use of "parsed" and "skipped" methods' do
122 @state.skipped('this is the ').should == 'string to be parsed'
123 @state.results.should be_empty
124 @state.parsed('string ').should == 'to be parsed'
125 @state.results.should == 'string '
126 @state.skipped('to be parsed').should == ''
127 @state.results.should == 'string '
129 # second example (add this test to isolate a bug in another specification)
130 state = Walrat::ParserState.new('foo1...')
131 state.skipped('foo').should == '1...'
132 state.remainder.should == '1...'
133 state.results.should be_empty
134 state.parsed('1').should == '...'
135 state.remainder.should == '...'
136 state.results.should == '1'
139 it '"parsed" and "results" methods should work with multi-byte Unicode strings' do
141 state = Walrat::ParserState.new('400€, foo')
142 state.remainder.should == '400€, foo'
143 state.parsed('40').should == '0€, foo'
144 state.results.should == '40'
145 state.parsed('0€, ').should == 'foo'
146 state.results.should == ['40', '0€, ']
147 state.parsed('foo').should == ''
148 state.results.should == ['40', '0€, ', 'foo']
150 # test with newlines before and after multi-byte chars
151 state = Walrat::ParserState.new("400\n or more €...\nfoo")
152 state.remainder.should == "400\n or more €...\nfoo"
153 state.parsed("400\n or more").should == " €...\nfoo"
154 state.results.should == "400\n or more"
155 state.parsed(' €..').should == ".\nfoo"
156 state.results.should == ["400\n or more", ' €..']
157 state.parsed(".\nfoo").should == ''
158 state.results.should == ["400\n or more", ' €..', ".\nfoo"]
161 it '"skipped" and "results" methods should work with multi-byte Unicode strings' do
162 state = Walrat::ParserState.new('400€, foo')
163 state.remainder.should == '400€, foo'
164 state.skipped('4').should == '00€, foo'
165 state.results.should be_empty
166 state.parsed('0').should == '0€, foo'
167 state.results.should == '0'
168 state.skipped('0€, ').should == 'foo'
169 state.results.should == '0'
170 state.parsed('foo').should == ''
171 state.results.should == ['0', 'foo']