86 lines
1.5 KiB
Crystal
86 lines
1.5 KiB
Crystal
|
|
class Tap::ParserError < Exception
|
|
end
|
|
|
|
class Tap::Entry
|
|
enum Status
|
|
Ok
|
|
NotOk
|
|
|
|
def self.new(s : String)
|
|
if s == "ok"
|
|
Ok
|
|
elsif s == "not ok"
|
|
NotOk
|
|
else
|
|
raise ParserError.new "Invalid TAP status: '#{s}'"
|
|
end
|
|
end
|
|
end
|
|
|
|
getter id : Int32
|
|
getter status : Status
|
|
getter title : String
|
|
getter comment : String?
|
|
|
|
def initialize(@status, @id, @title, @comment = nil)
|
|
end
|
|
end
|
|
|
|
class Tap::Summary
|
|
property tests_passed = [] of Tap::Entry
|
|
property tests_failed = [] of Tap::Entry
|
|
def initialize(@tests_passed, @tests_failed)
|
|
end
|
|
end
|
|
|
|
class Tap::Suite < Array(Tap::Entry)
|
|
def summary
|
|
tests_passed = self.select(&.status.ok?)
|
|
tests_failed = self.select(&.status.not_ok?)
|
|
|
|
Summary.new tests_passed, tests_failed
|
|
end
|
|
end
|
|
|
|
module Tap
|
|
def self.parse(text : String)
|
|
tap : Tap::Suite? = nil
|
|
|
|
text.lines.each do |line|
|
|
if md = line.match /^[ \t]*#.*$/
|
|
# Comments, currently ignored.
|
|
next
|
|
end
|
|
|
|
if md = line.match(/^([0-9]+)\.\.([0-9]+)$/)
|
|
unless tap
|
|
tap = Tap::Suite.new md[2].to_i
|
|
else
|
|
if tap.size != md[2].to_i
|
|
raise ParserError.new "Number of tests parsed does not match number of tests written in suite."
|
|
end
|
|
end
|
|
|
|
next
|
|
end
|
|
|
|
if md = line.match(/^(not ok|ok) ([0-9]+) *- *([^#]*)(#.*)?$/)
|
|
unless tap
|
|
tap = Tap::Suite.new
|
|
end
|
|
|
|
tap << Tap::Entry.new Entry::Status.new(md[1]), md[2].to_i, md[3], md[4]?.try(&.gsub /^# */, "")
|
|
|
|
next
|
|
end
|
|
|
|
# Line could not be read.
|
|
raise "syntax error: line did not match known pattern"
|
|
end
|
|
|
|
tap
|
|
end
|
|
end
|
|
|