@@ 157,6 157,10 @@ func (p *Parser) next() (rune, error) {
// Used by NextRecord to advance to the start of the next line, or EOF. Non-EOF
// errors are propagated.
func (p *Parser) readUntilNewLine() error {
+ if p.iseof {
+ return nil
+ }
+
for p.current != '\n' {
_, err := p.next()
if err == io.EOF {
@@ 61,6 61,53 @@ func Test_MultiLineString(t *testing.T) {
assert.True(t, IsSyntaxError(err))
}
+func Test_MixedQuotes(t *testing.T) {
+ // Strings with another quoted string inside should be OK, as long as
+ // the outer string is property terminated.
+
+ p, err := NewParserFromString("key=\"abc 'xyz'\"")
+ assert.Nil(t, err)
+
+ rec, err := p.NextRecord()
+ assert.Nil(t, err)
+
+ expect := map[string]interface{}{
+ "key": "abc 'xyz'",
+ }
+ assert.Equal(t, expect, rec)
+
+ p, err = NewParserFromString("key='abc \"xyz\"'")
+ assert.Nil(t, err)
+
+ rec, err = p.NextRecord()
+ assert.Nil(t, err)
+
+ expect = map[string]interface{}{
+ "key": "abc \"xyz\"",
+ }
+ assert.Equal(t, expect, rec)
+
+ // It's OK if the inner string isn't quoted propertly
+ p, err = NewParserFromString("key=\"abc 'xyz 123\"")
+ assert.Nil(t, err)
+
+ rec, err = p.NextRecord()
+ assert.Nil(t, err)
+
+ expect = map[string]interface{}{
+ "key": "abc 'xyz 123",
+ }
+ assert.Equal(t, expect, rec)
+
+ // We can't mix the outer quotes though.
+ p, err = NewParserFromString("key=\"abc'")
+ assert.Nil(t, err)
+
+ rec, err = p.NextRecord()
+ assert.NotNil(t, err)
+ assert.True(t, IsSyntaxError(err))
+}
+
func Test_IllegalKeys(t *testing.T) {
// A string with an un-escaped newline in it should be a syntax error.
p, err := NewParserFromString("'=foo'\n';foo'\n'\"foo'\n\"'\"foo\nfoo")