blob: 5ad0224f0560a528f40e89e1613baaa51c712120 [file] [log] [blame]
package org.jetbrains.kmark.test
import org.junit.runner.*
import org.junit.runner.notification.*
import java.io.File
import org.junit.runners.ParentRunner
import java.io.Serializable
import kotlin.properties.Delegates
import org.junit.ComparisonFailure
data class MarkdownTestUniqueId(val id: Int) : Serializable {
companion object {
var id = 0
fun next() = MarkdownTestUniqueId(id++)
}
}
public open class MarkdownSpecification(val path: String, val processor: (String) -> String)
interface MarkdownTest {
fun description(): Description
}
public open class MarkdownTestCase(val spec: MarkdownSpecification, val input: String, val expected: String) : MarkdownTest, Runner() {
val _description by lazy {
Description.createSuiteDescription(input, MarkdownTestUniqueId.next())!!
}
override fun description(): Description = _description
override fun getDescription(): Description? = description()
override fun run(notifier: RunNotifier?) {
notifier!!
notifier.fireTestStarted(_description)
val result = spec.processor(input)
when (result) {
expected -> notifier.fireTestFinished(_description)
else -> notifier.fireTestFailure(Failure(_description, ComparisonFailure("Output mismatch", expected, result)))
}
}
}
public open class MarkdownTestSection(val spec: MarkdownSpecification, val title: String) : MarkdownTest, ParentRunner<MarkdownTest>(spec.javaClass) {
val children = arrayListOf<MarkdownTest>();
val _description by lazy {
val desc = Description.createSuiteDescription(title, MarkdownTestUniqueId.next())!!
for (item in getChildren()!!) {
desc.addChild(describeChild(item))
}
desc
}
override fun description(): Description = _description
override fun getChildren(): MutableList<MarkdownTest>? = children
override fun describeChild(child: MarkdownTest?): Description? = child!!.description()
override fun runChild(child: MarkdownTest?, notifier: RunNotifier?) {
notifier!!
when (child) {
is MarkdownTestCase -> child.run(notifier)
is MarkdownTestSection -> {
if (child.children.size() == 0) {
notifier.fireTestStarted(child.description())
notifier.fireTestFinished(child.description())
} else {
child.run(notifier)
}
}
}
}
}
public class MarkdownTestRunner(specificationClass: Class<MarkdownSpecification>) : MarkdownTestSection(specificationClass.newInstance(), "Tests") {
init {
val lines = File(spec.path).readLines()
createSections(this, lines, 1)
}
private fun createTests(parent: MarkdownTestSection, lines: List<String>): Int {
val testMark = lines.takeWhile { it.trim() != "." }
val testHtml = lines.drop(testMark.size()).drop(1).takeWhile { it.trim() != "." }
val markdown = testMark.join("\n", postfix = "\n", prefix = "\n")
val html = testHtml.join("\n", postfix = "\n")
val markdownTestCase = MarkdownTestCase(spec, markdown, html)
parent.children.add(markdownTestCase)
return testMark.size() + testHtml.size() + 3
}
private fun createSections(parent: MarkdownTestSection, lines: List<String>, level: Int): Int {
var sectionNumber = 1
var index = 0
while (index < lines.size()) {
val line = lines[index]
if (line.trim() == ".") {
index = createTests(parent, lines.subList(index + 1, lines.lastIndex)) + index + 1
continue
}
val head = line.takeWhile { it == '#' }.length()
if (head == 0) {
index++
continue
}
if (head < level) {
return index
}
if (head == level) {
val title = lines[index].dropWhile { it == '#' }.dropWhile { it.isWhitespace() }
sectionNumber++
val section = MarkdownTestSection(spec, title)
val lastIndex = createSections(section, lines.subList(index + 1, lines.lastIndex), level + 1) + index + 1
if (section.children.size() > 0)
parent.children.add(section)
val nextHead = lines[lastIndex].takeWhile { it == '#' }.length()
if (nextHead < level) {
return lastIndex
}
index = lastIndex
continue
}
index++
}
return lines.size()
}
}