summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/scala/com/google/gimd/text/Parser.scala26
-rw-r--r--src/test/scala/com/google/gimd/text/ParserTestCase.scala40
2 files changed, 64 insertions, 2 deletions
diff --git a/src/main/scala/com/google/gimd/text/Parser.scala b/src/main/scala/com/google/gimd/text/Parser.scala
index 8767281..0a0c33d 100644
--- a/src/main/scala/com/google/gimd/text/Parser.scala
+++ b/src/main/scala/com/google/gimd/text/Parser.scala
@@ -41,9 +41,31 @@ class Parser extends RegexParsers {
def message: Parser[Message] = message(0)
def field: Parser[Field] = field(0)
- private def message(level: Int): Parser[Message] = (field(level) *) ^^ {
- case fieldList => Message(fieldList)
+ private def checkSorting(fields: List[Field]): Option[String] = fields match {
+ case x :: y :: tail => if (x < y)
+ checkSorting(y :: tail)
+ else
+ Some("""|Fields X, Y do not satisfy condition X < Y where
+ |X:
+ |%1s
+ |Y:
+ |%2s""".format(x, y))
+ case x :: Nil => None
+ case Nil => None
}
+
+ private def message(level: Int): Parser[Message] = (field(level) *) into {
+ case fieldList => checkSorting(fieldList) match {
+ case None => success(Message(fieldList))
+ //TODO Right now message for failure can be very big depending on contents
+ //TODO of fields that are in wrong order.
+ //TODO It would be much better to rewrite Message parser from scratch and
+ //TODO fail as soon as field that is out of order is parsed. Then it would
+ //TODO be enough just to report the line number where parsing really failed.
+ case Some(errorMsg) => failure(errorMsg)
+ }
+ }
+
private def field(level: Int): Parser[Field] =
indent(level) ~> ident <~ ' ' into {
case name => value(level, name) <~ '\n'
diff --git a/src/test/scala/com/google/gimd/text/ParserTestCase.scala b/src/test/scala/com/google/gimd/text/ParserTestCase.scala
index d960c17..b1566ae 100644
--- a/src/test/scala/com/google/gimd/text/ParserTestCase.scala
+++ b/src/test/scala/com/google/gimd/text/ParserTestCase.scala
@@ -197,6 +197,46 @@ final class ParserTestCase {
assertEquals(Message(Field("field", "-0")), msg)
}
+ @Test
+ def wrongOrderOfTwoFields {
+ val input = """|b 2
+ |a 1
+ |""".stripMargin
+ assertInvalidFieldOrder(input)
+ }
+
+ @Test
+ def wrongOrderOfFourFields {
+ val input = """|b 1
+ |c 1
+ |a 1
+ |d 1
+ |""".stripMargin
+ assertInvalidFieldOrder(input)
+ }
+
+ @Test
+ def duplicatedFields {
+ val input = """|a 1
+ |b 2
+ |b 2
+ |c 3
+ |""".stripMargin
+ assertInvalidFieldOrder(input)
+ }
+
+ private def assertInvalidFieldOrder(input: String) {
+ val expectedMsg = "Fields X, Y do not satisfy condition X < Y where"
+ try {
+ parse(input)
+ } catch {
+ //TODO this is a quick hack to make sure that exception we catch is carrying information about
+ //TODO the error we are expecting. In a future it should be Parser that is changed to make
+ //TODO such testing easier
+ case e: ParserException => if (!e.getMessage.contains(expectedMsg)) throw e
+ }
+ }
+
//TODO (1) Add tests for Int and Long specifically
//TODO (2) Add tests for timestamps