Merge pull request #40 from pelletier/pelletier/space-in-keys

Accept spaces in keys
diff --git a/.travis.yml b/.travis.yml
index cdd30d2..83e84ad 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,3 +7,9 @@
     - 1.3
     - 1.4.1
     - tip
+before_install:
+  - go get github.com/axw/gocov/gocov
+  - go get github.com/mattn/goveralls
+  - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
+after_success:
+    - $HOME/gopath/bin/goveralls -service=travis-ci
diff --git a/README.md b/README.md
index db73b4b..d154726 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@
 
 [![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml)
 [![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml)
+[![Coverage Status](https://coveralls.io/repos/pelletier/go-toml/badge.svg?branch=master&service=github)](https://coveralls.io/github/pelletier/go-toml?branch=master)
 
 ## Features
 
diff --git a/lexer.go b/lexer.go
index 7cb789b..13fd84f 100644
--- a/lexer.go
+++ b/lexer.go
@@ -423,7 +423,11 @@
 				return l.errorf("invalid escape sequence: \\" + string(l.peek()))
 			}
 		} else {
-			growingString += string(l.peek())
+			r := l.peek()
+			if 0x00 <= r && r <= 0x1F {
+				return l.errorf("unescaped control character %U", r)
+			}
+			growingString += string(r)
 		}
 
 		if l.next() == eof {
diff --git a/lexer_test.go b/lexer_test.go
index 05958fc..de539c1 100644
--- a/lexer_test.go
+++ b/lexer_test.go
@@ -472,6 +472,19 @@
 	})
 }
 
+func TestKeyEqualStringNoEscape(t *testing.T) {
+	testFlow(t, "foo = \"hello \u0002\"", []token{
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenError, "unescaped control character U+0002"},
+	})
+	testFlow(t, "foo = \"hello \u001F\"", []token{
+		token{Position{1, 1}, tokenKey, "foo"},
+		token{Position{1, 5}, tokenEqual, "="},
+		token{Position{1, 8}, tokenError, "unescaped control character U+001F"},
+	})
+}
+
 func TestLiteralString(t *testing.T) {
 	testFlow(t, `foo = 'C:\Users\nodejs\templates'`, []token{
 		token{Position{1, 1}, tokenKey, "foo"},
@@ -523,19 +536,33 @@
 		token{Position{1, 34}, tokenEOF, ""},
 	})
 
-	testFlow(t, "foo = \"\"\"\nhello\n\"literal\"\nworld\"\"\"", []token{
+	testFlow(t, "foo = \"\"\"\nhello\\\n\"literal\"\\\nworld\"\"\"", []token{
 		token{Position{1, 1}, tokenKey, "foo"},
 		token{Position{1, 5}, tokenEqual, "="},
-		token{Position{2, 1}, tokenString, "hello\n\"literal\"\nworld"},
+		token{Position{2, 1}, tokenString, "hello\"literal\"world"},
 		token{Position{4, 9}, tokenEOF, ""},
 	})
 
-	testFlow(t, "foo = \"\"\"\\\n    \\\n    \\\n    hello\nmultiline\nworld\"\"\"", []token{
+	testFlow(t, "foo = \"\"\"\\\n    \\\n    \\\n    hello\\\nmultiline\\\nworld\"\"\"", []token{
 		token{Position{1, 1}, tokenKey, "foo"},
 		token{Position{1, 5}, tokenEqual, "="},
-		token{Position{1, 10}, tokenString, "hello\nmultiline\nworld"},
+		token{Position{1, 10}, tokenString, "hellomultilineworld"},
 		token{Position{6, 9}, tokenEOF, ""},
 	})
+
+	testFlow(t, "key2 = \"\"\"\nThe quick brown \\\n\n\n  fox jumps over \\\n    the lazy dog.\"\"\"", []token{
+		token{Position{1, 1}, tokenKey, "key2"},
+		token{Position{1, 6}, tokenEqual, "="},
+		token{Position{2, 1}, tokenString, "The quick brown fox jumps over the lazy dog."},
+		token{Position{6, 21}, tokenEOF, ""},
+	})
+
+	testFlow(t, "key2 = \"\"\"\\\n       The quick brown \\\n       fox jumps over \\\n       the lazy dog.\\\n       \"\"\"", []token{
+		token{Position{1, 1}, tokenKey, "key2"},
+		token{Position{1, 6}, tokenEqual, "="},
+		token{Position{1, 11}, tokenString, "The quick brown fox jumps over the lazy dog."},
+		token{Position{5, 11}, tokenEOF, ""},
+	})
 }
 
 func TestUnicodeString(t *testing.T) {