Skip to content

Commit

Permalink
Implement run paths (#936)
Browse files Browse the repository at this point in the history
  • Loading branch information
raniejade authored Nov 7, 2020
1 parent 4e1e6d9 commit ae4278f
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
56 changes: 56 additions & 0 deletions design-docs/run-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Run paths

A run path represents which tests are run by Spek. The most basic run path is `/` which means to run every test.

To run tests under a specific package, say `com.example`, use the run path `/com/example` - basically replace all occurrences of `.` to a `/`. The same can be applied to running tests for a specific class. For the class `com.example.FooSpec` , use the run path `/com/example/FooSpec`.

Given the example below, to run the test `it("do this")` use the run path `com/example/FooSpec/Some foo/do this`.

```kotlin
package com.example

object FooSpec: Spek({
describe("Some foo") {
it("do this") { ... }
it("do that") { ... }
}
})
```

## Relationships

Given the following structure:

```
com/
example/
FooSpec
BarSpec
sample/
FooBarSpec
```

If Spek is run with the run path `/com/example`, the test classes `FooSpec` and `BarSpec` will be executed but not `FooBarSpec` as it is not a child of `/com/example`. If the run path used was `/com` or `/`, then all test classes will be executed.

The same rules above can be applied to scopes within a test class.

```kotlin
object FooSpec: Spek({
describe("Some foo") {
it("do this") { ... }
it("do that") { ... }
}

describe("Another foo") {
it("should do this") { ... }
}
})
```

Running Spek with the run path `/com/example/FooSpec/Some foo`, will only execute the test scopes `it("do this")` and `it("do that")`. To run all test scopes under `FooSpec`, use the run path `/com/example/FooSpec`.

## Future enhancements

- Support ANT-like path wildcards (`**` and `*`) in the future when there is a need for it.
- `/` is a reserved character, escaping it can be supported later on.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.spekframework.spek2

import org.spekframework.spek2.runtime.scope.RunPath
import org.spekframework.spek2.style.specification.describe
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue

object RunPathTest: Spek({
describe("RunPath") {
it("should parse root") {
RunPath("/")
}

it("should parse valid paths") {
RunPath("/com/example/FooSpec/Some foo/do this")
}

it("should throw exception when parsing invalid paths") {
assertFailsWith<IllegalArgumentException> {
RunPath("com/example/FooSpec")
}
}

it("should check for ancestry") {
listOf(
"/",
"/com",
"/com/example",
"/com/example/FooSpec",
"/com/example/FooSpec/Some foo",
).map(::RunPath).forEach { path ->
assertTrue {
path.isParentOf(RunPath("/com/example/FooSpec/Some foo/do this"))
}
}
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.spekframework.spek2.runtime.scope

/**
* Specifies which tests are run by Spek.
*/
class RunPath (val path: String) {
init {
if (!RUN_PATH_REGEX.matches(path)) {
throw IllegalArgumentException("Invalid run path: '$path'")
}
}

/**
* Check if this run path is a parent of the given [path].
*/
fun isParentOf(path: RunPath): Boolean {
return path.path.startsWith(this.path)
}

class Builder(packageName: String, className: String) {
private val scopes = mutableListOf<String>()

init {
scopes.addAll(packageName.split("."))
scopes.add(className);
}

fun addScope(scope: String): Builder {
scopes.add(scope)
return this
}

fun build(): RunPath {
val builder = StringBuilder()
builder.append(SEPARATOR)

return RunPath(
StringBuilder()
.append(SEPARATOR)
.append(scopes.joinToString(SEPARATOR))
.toString()
)
}
}

companion object {
private const val SEPARATOR = "/"
private val RUN_PATH_REGEX = Regex("(^\\/\$)|(\\/[^\\/]+)+?")

fun builder(packageName: String, className: String): Builder {
return Builder(packageName, className)
}

fun builder(className: String) = builder("", className)
}
}

0 comments on commit ae4278f

Please sign in to comment.