diff options
-rw-r--r-- | src/main/scala/com/google/gimd/text/Parser.scala | 26 | ||||
-rw-r--r-- | src/test/scala/com/google/gimd/text/ParserTestCase.scala | 40 |
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 |