aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/scala/org/perl8/test/tap/Consumer.scala
blob: 8c55e1771214bff663a450f5c97dae274ec9d8fe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package org.perl8.test.tap

import org.perl8.test.{Plan,NumericPlan,SkipAll}

object Consumer {
  def parseLine (line: String): Line = {
    commentRx.findFirstMatchIn(line).map { m =>
      m.subgroups match {
        case Seq(indent, text) => new CommentLine(text, indent)
      }
    }.getOrElse {
      planRx.findFirstMatchIn(line).map { m =>
        m.subgroups match {
          case Seq(indent, p, null) =>
            new PlanLine(NumericPlan(p.toInt), indent)
          case Seq(indent, _, skip) =>
            new PlanLine(SkipAll(skip), indent)
        }
      }.getOrElse {
        resultRx.findFirstMatchIn(line).map { m =>
          val indent = m.group(1)
          val passed = m.group(2) == null
          val number = m.group(3).toInt
          val description = m.group(4) match {
            case null => ""
            case s    => s.trim
          }
          val directive = (m.group(5), m.group(6)) match {
            case (null, null) => None
            case (d, r)       => {
              val reason = if (r == null) "" else r
              """(?i:skip)""".r.findFirstIn(d) match {
                case Some(_) => Some(new SkipDirective(Some(reason)))
                case None    => Some(new TodoDirective(Some(reason)))
              }
            }
          }
          val result = new TestResult(
            passed,
            number,
            description,
            directive,
            None
          )
          new ResultLine(result, indent)
        }.getOrElse {
          throw ParseException("Couldn't parse line: " + line)
        }
      }
    }
  }

  sealed trait Line {
    def contents: String
    def indent:   String

    override def toString: String =
      indent + contents
  }

  case class CommentLine (text: String, indent: String) extends Line {
    def contents = "# " + text
  }

  case class PlanLine (plan: Plan, indent: String) extends Line {
    def contents = {
      val count = plan.plan
      val comment = plan match {
        case SkipAll(m) => " # SKIP " + m
        case _          => ""
      }
      indent + "1.." + count + comment
    }
  }

  case class ResultLine (result: TestResult, indent: String) extends Line {
    def contents = {
      val success = (if (result.passed) "ok" else "not ok") + " "
      val number = result.number + " "
      val description = result.description match {
        case "" => ""
        case s  => s + " "
      }
      val directive = result.directive.map { d =>
        d match {
          case TodoDirective(m) => "# TODO " + m
          case SkipDirective(m) => "# skip " + m
        }
      }.getOrElse("")
      indent + success + number + description + directive
    }
  }

  private val commentRx = """^(\s*)#\s*(.*)""".r
  private val planRx    = """^(\s*)1..(\d+)\s*(?:# SKIP (.*))?""".r
  private val resultRx  =
    """^(\s*)(not )?ok (\d+)\s*([^#]+)?(?:#\s*(?i:(skip|todo))\s+(.*))?""".r
}