# encoding: utf-8 # Copyright 2007-2014 Greg Hurrell. All rights reserved. # Licensed under the terms of the BSD 2-clause license. require 'spec_helper' describe Walrat::ParserState do before do @base_string = 'this is the string to be parsed' @state = Walrat::ParserState.new @base_string end it 'raises an ArgumentError if initialized with nil' do expect do Walrat::ParserState.new nil end.to raise_error(ArgumentError, /nil string/) end it 'before parsing has started "remainder" should equal the entire string' do @state.remainder.should == @base_string end it 'before parsing has started "remainder" should equal the entire string (when string is an empty string)' do Walrat::ParserState.new('').remainder.should == '' end it 'before parsing has started "results" should be empty' do @state.results.should be_empty end it '"parsed" should complain if passed nil' do lambda { @state.parsed(nil) }.should raise_error(ArgumentError) end it '"skipped" should complain if passed nil' do lambda { @state.skipped(nil) }.should raise_error(ArgumentError) end it '"parsed" should return the remainder of the string' do @state.parsed('this is the ').should == 'string to be parsed' @state.parsed('string ').should == 'to be parsed' @state.parsed('to be parsed').should == '' end it '"skipped" should return the remainder of the string' do @state.skipped('this is the ').should == 'string to be parsed' @state.skipped('string ').should == 'to be parsed' @state.skipped('to be parsed').should == '' end it '"results" should return an unwrapped parsed result (for single results)' do @state.parsed('this') @state.results.should == 'this' end it 'skipped substrings should not appear in "results"' do @state.skipped('this') @state.results.should be_empty end it 'should return an array of the parsed results (for multiple results)' do @state.parsed('this ') @state.parsed('is ') @state.results.should == ['this ', 'is '] end it 'should work when the entire string is consumed in a single operation (using "parsed")' do @state.parsed(@base_string).should == '' @state.results.should == @base_string end it 'should work when the entire string is consumed in a single operation (using "skipped")' do @state.skipped(@base_string).should == '' @state.results.should be_empty end it '"parsed" should complain if passed something that doesn\'t respond to the "line_end" and "column_end" messages' do # line_end my_mock = double('Mock which does not implement #line_end').as_null_object expect(my_mock).to receive(:line_end).and_raise(NoMethodError) expect { @state.parsed(my_mock) }.to raise_error(NoMethodError) # column_end my_mock = double('Mock which does not implement #column_end').as_null_object expect(my_mock).to receive(:column_end).and_raise(NoMethodError) expect { @state.parsed(my_mock) }.to raise_error(NoMethodError) end it '"skipped" should complain if passed something that doesn\'t respond to the "line_end" and "column_end" messages' do # line_end my_mock = double('Mock which does not implement #line_end').as_null_object expect(my_mock).to receive(:line_end).and_raise(NoMethodError) expect { @state.skipped(my_mock) }.to raise_error(NoMethodError) # column_end my_mock = double('Mock which does not implement #column_end').as_null_object expect(my_mock).to receive(:column_end).and_raise(NoMethodError) expect { @state.skipped(my_mock) }.to raise_error(NoMethodError) end it 'should be able to mix use of "parsed" and "skipped" methods' do # first example @state.skipped('this is the ').should == 'string to be parsed' @state.results.should be_empty @state.parsed('string ').should == 'to be parsed' @state.results.should == 'string ' @state.skipped('to be parsed').should == '' @state.results.should == 'string ' # second example (add this test to isolate a bug in another specification) state = Walrat::ParserState.new('foo1...') state.skipped('foo').should == '1...' state.remainder.should == '1...' state.results.should be_empty state.parsed('1').should == '...' state.remainder.should == '...' state.results.should == '1' end it '"parsed" and "results" methods should work with multi-byte Unicode strings' do # basic test state = Walrat::ParserState.new('400€, foo') state.remainder.should == '400€, foo' state.parsed('40').should == '0€, foo' state.results.should == '40' state.parsed('0€, ').should == 'foo' state.results.should == ['40', '0€, '] state.parsed('foo').should == '' state.results.should == ['40', '0€, ', 'foo'] # test with newlines before and after multi-byte chars state = Walrat::ParserState.new("400\n or more €...\nfoo") state.remainder.should == "400\n or more €...\nfoo" state.parsed("400\n or more").should == " €...\nfoo" state.results.should == "400\n or more" state.parsed(' €..').should == ".\nfoo" state.results.should == ["400\n or more", ' €..'] state.parsed(".\nfoo").should == '' state.results.should == ["400\n or more", ' €..', ".\nfoo"] end it '"skipped" and "results" methods should work with multi-byte Unicode strings' do state = Walrat::ParserState.new('400€, foo') state.remainder.should == '400€, foo' state.skipped('4').should == '00€, foo' state.results.should be_empty state.parsed('0').should == '0€, foo' state.results.should == '0' state.skipped('0€, ').should == 'foo' state.results.should == '0' state.parsed('foo').should == '' state.results.should == ['0', 'foo'] end end