Skip to content

Commit 6ac4a87

Browse files
authored
Implement new Javascript test case sync mechanism (#328)
This adds a new 3 way sync mechanism, where the test definitions (Asciidoc), that are generated from neo4j-graphql (Javascript) are stored separately as `*.js.adoc`. The new tool JsTestCaseSync.kt now compares the Javascript version with the previous Javascript version and only take over test that were changed. Additionally, the reformatting feature is extracted from the TestSuites into a new tool AsciidocReformater.kt. This removes code that is not test relevant out of the test factories. As a refactoring, utility functions were also removed from the test factories into own *Utils classes.
1 parent cf743db commit 6ac4a87

File tree

492 files changed

+77118
-8962
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

492 files changed

+77118
-8962
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ ij_asciidoc_blank_lines_after_header = 1
411411
ij_asciidoc_blank_lines_keep_after_header = 1
412412
ij_asciidoc_formatting_enabled = true
413413
ij_asciidoc_one_sentence_per_line = true
414+
trim_trailing_whitespace = false
414415

415416
[{*.ant,*.fo,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.qrc,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
416417
ij_xml_align_attributes = true

.run/AsciidocReformater.run.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="org.neo4j.graphql.tools.AsciidocReformater" type="JetRunConfigurationType" nameIsGenerated="true">
3+
<option name="MAIN_CLASS_NAME" value="org.neo4j.graphql.tools.AsciidocReformater" />
4+
<module name="neo4j-graphql-java" />
5+
<shortenClasspath name="NONE" />
6+
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
7+
<method v="2">
8+
<option name="Make" enabled="true" />
9+
</method>
10+
</configuration>
11+
</component>

.run/JsTestCaseSync.run.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="org.neo4j.graphql.tools.JsTestCaseSync" type="JetRunConfigurationType" nameIsGenerated="true">
3+
<option name="MAIN_CLASS_NAME" value="org.neo4j.graphql.tools.JsTestCaseSync" />
4+
<module name="neo4j-graphql-java" />
5+
<shortenClasspath name="NONE" />
6+
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
7+
<method v="2">
8+
<option name="Make" enabled="true" />
9+
</method>
10+
</configuration>
11+
</component>

.run/Reformat Tests.run.xml

Lines changed: 0 additions & 13 deletions
This file was deleted.

core/src/test/kotlin/org/neo4j/graphql/asciidoc/AsciiDocParser.kt

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
package org.neo4j.graphql.asciidoc
22

3-
import org.neo4j.graphql.asciidoc.ast.*
43
import org.apache.commons.csv.CSVFormat
5-
import java.io.File
4+
import org.neo4j.graphql.asciidoc.ast.*
65
import java.net.URI
6+
import java.nio.file.Path
77
import java.util.regex.Pattern
88
import javax.ws.rs.core.UriBuilder
9+
import kotlin.io.path.readLines
910

1011
class AsciiDocParser(
11-
fileName: String
12+
private val file: Path
1213
) {
1314

14-
private val file = File(AsciiDocParser::class.java.getResource("/$fileName")?.toURI()!!)
15-
private val srcLocation = File("src/test/resources/", fileName).toURI()
16-
17-
private var root = Document(srcLocation)
15+
private var root = Document(file.toUri())
1816
private var currentSection: Section = root
1917
private var currentDepth: Int = 0
2018

21-
2219
fun parse(): Document {
23-
val lines = file.readLines()
20+
return parseLines(file.readLines())
21+
}
22+
23+
fun parseContent(content: String): Document {
24+
return parseLines(content.lines())
25+
}
26+
27+
private fun parseLines(lines: List<String>): Document {
2428
var title: String?
2529

2630
var insideCodeblock = false
@@ -29,7 +33,7 @@ class AsciiDocParser(
2933

3034
val fileContent = StringBuilder()
3135

32-
root = Document(srcLocation)
36+
root = Document(file.toUri())
3337
currentSection = root
3438
currentDepth = 0
3539
var caption: String? = null
@@ -42,11 +46,6 @@ class AsciiDocParser(
4246
loop@ for ((lineNr, line) in lines.withIndex()) {
4347
fileContent.append(line).append('\n')
4448

45-
if (line.startsWith("#") || line.startsWith("//")) {
46-
offset += line.length + 1
47-
continue
48-
}
49-
5049
val headlineMatcher = HEADLINE_PATTERN.matcher(line)
5150

5251
when {
@@ -55,7 +54,7 @@ class AsciiDocParser(
5554
addBlock(content)
5655
val depth = headlineMatcher.group(1).length
5756
title = headlineMatcher.group(2)
58-
val uri = UriBuilder.fromUri(srcLocation).queryParam("line", lineNr + 1).build()
57+
val uri = uriWithLineNr(lineNr)
5958
startSection(title, uri, depth)
6059
}
6160

@@ -65,10 +64,10 @@ class AsciiDocParser(
6564

6665
line.startsWith("[%header,format=csv") -> {
6766
addBlock(content)
68-
val uri = UriBuilder.fromUri(srcLocation).queryParam("line", lineNr + 1).build()
67+
val uri = uriWithLineNr(lineNr)
6968

70-
val parts = line.substring(19, line.indexOf("]")).trim().split(",")
71-
val attributes = parts.slice(0..<parts.size).map {
69+
val parts = line.substring(19, line.indexOf("]")).trim().split(",").filter { it.isNotBlank() }
70+
val attributes = parts.slice(parts.indices).map {
7271
val attributeParts = it.split("=")
7372
attributeParts[0] to attributeParts.getOrNull(1)
7473
}.toMap()
@@ -82,7 +81,7 @@ class AsciiDocParser(
8281

8382
line.startsWith("[source,") -> {
8483
addBlock(content)
85-
val uri = UriBuilder.fromUri(srcLocation).queryParam("line", lineNr + 1).build()
84+
val uri = uriWithLineNr(lineNr)
8685

8786
val parts = line.substring(8, line.indexOf("]")).trim().split(",")
8887
val language = parts[0]
@@ -93,8 +92,6 @@ class AsciiDocParser(
9392

9493
currentCodeBlock = CodeBlock(uri, language, currentSection, attributes).also {
9594
it.caption = caption
96-
it.markerStart = offset
97-
it.markerEnd = offset + line.length
9895
currentSection.blocks.add(it)
9996
}
10097
caption = null
@@ -124,10 +121,8 @@ class AsciiDocParser(
124121
line == "----" -> {
125122
insideCodeblock = !insideCodeblock
126123
if (insideCodeblock) {
127-
currentCodeBlock?.start = offset + line.length + 1
128124
content = StringBuilder()
129125
} else if (currentCodeBlock != null) {
130-
currentCodeBlock.end = offset
131126
currentCodeBlock.content = content.toString().trim()
132127
currentCodeBlock = null
133128
content = StringBuilder()
@@ -145,10 +140,13 @@ class AsciiDocParser(
145140
return root
146141
}
147142

143+
private fun uriWithLineNr(lineNr: Int): URI =
144+
UriBuilder.fromUri(file.toUri()).queryParam("line", lineNr + 1).build()
145+
148146
private fun addBlock(content: StringBuilder) {
149147
val str = content.toString()
150-
if (str.trim().isNotEmpty()) {
151-
currentSection.let { it.blocks.add(Block(it, str)) }
148+
if (str.isNotBlank()) {
149+
currentSection.let { it.blocks.add(Block(it, str.trimEnd())) }
152150
}
153151
content.clear()
154152
}

core/src/test/kotlin/org/neo4j/graphql/asciidoc/ast/Block.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ package org.neo4j.graphql.asciidoc.ast
22

33
class Block(
44
parent: StructuralNode,
5-
val content: String
5+
var content: String
66
) : StructuralNode(parent) {
77

88
override fun toString(): String {
99
return "Block(content='$content')"
1010
}
11+
12+
override fun buildContent(contentExtractor: (CodeBlock) -> String): String {
13+
return content + "\n"
14+
}
1115
}

core/src/test/kotlin/org/neo4j/graphql/asciidoc/ast/CodeBlock.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ class CodeBlock(
1111

1212
var caption: String? = null
1313

14-
var markerStart: Int? = null
15-
var markerEnd: Int? = null
16-
var start: Int? = null
17-
var end: Int? = null
18-
1914
lateinit var content: String
2015

2116
/**
@@ -49,4 +44,15 @@ class CodeBlock(
4944
fun matches(language: String, filter: Map<String, String?> = emptyMap(), exactly: Boolean = false) =
5045
this.language == language && filter.all { (k, v) -> attributes[k] == v } && (!exactly || attributes.size == filter.size)
5146

47+
override fun buildContent(contentExtractor: (CodeBlock) -> String): String {
48+
val builder = StringBuilder()
49+
caption?.let {
50+
builder.append("\n.${it}\n")
51+
}
52+
builder.append(adjustedMarker)
53+
builder.append("\n----\n")
54+
builder.append(contentExtractor(this))
55+
builder.append("\n----\n")
56+
return builder.toString()
57+
}
5258
}

core/src/test/kotlin/org/neo4j/graphql/asciidoc/ast/Document.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@ class Document(
88

99
lateinit var content: String
1010

11+
override fun buildContent(contentExtractor: (CodeBlock) -> String): String {
12+
val builder = StringBuilder()
13+
blocks.forEach {
14+
builder.append(it.buildContent(contentExtractor))
15+
}
16+
return builder.toString()
17+
}
18+
1119
}

core/src/test/kotlin/org/neo4j/graphql/asciidoc/ast/Section.kt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.neo4j.graphql.asciidoc.ast
22

3+
import org.neo4j.graphql.domain.CodeBlockPredicate
34
import java.net.URI
45

56
open class Section(
@@ -11,4 +12,75 @@ open class Section(
1112
override fun toString(): String {
1213
return "Section(title='$title')"
1314
}
15+
16+
override fun buildContent(contentExtractor: (CodeBlock) -> String): String {
17+
18+
val builder = StringBuilder("\n")
19+
var current: Section? = this
20+
do {
21+
builder.append("=")
22+
current = current?.parent
23+
if (current is Document && current.blocks.filterIsInstance<Section>().size > 1) {
24+
// we are in a document with multiple sections, so we need to add another level to the title
25+
builder.append("=")
26+
}
27+
} while (current != null && current !is Document)
28+
builder.append(" ${title}\n")
29+
blocks.forEach {
30+
builder.append(it.buildContent(contentExtractor))
31+
}
32+
return builder.toString()
33+
}
34+
35+
/**
36+
* Find all directly nested code blocks of a given section matching the language and filter
37+
*/
38+
fun findCodeBlocks(
39+
predicate: CodeBlockPredicate,
40+
): List<CodeBlock> =
41+
blocks
42+
.filterIsInstance<CodeBlock>()
43+
.filter { predicate.matches(it) }
44+
45+
/**
46+
* Find a single code block of a given section matching the language and filter
47+
*/
48+
fun findSingleOrNullCodeBlock(
49+
predicate: CodeBlockPredicate,
50+
): CodeBlock? =
51+
findCodeBlocks(predicate)
52+
.also { require(it.size <= 1) { "Found more than one code block matching the predicate" } }
53+
.singleOrNull()
54+
55+
/**
56+
* Find all setup blocks for a given section, including the setup blocks of the parent sections
57+
*/
58+
fun findSetupCodeBlocks(
59+
predicate: CodeBlockPredicate,
60+
): List<CodeBlock> {
61+
val result = mutableListOf<CodeBlock>()
62+
var currentSection: Section? = this
63+
while (currentSection != null) {
64+
result.addAll(currentSection.findCodeBlocks(predicate))
65+
currentSection.blocks
66+
.filterIsInstance<Section>()
67+
.filter { it.title == "Setup" }
68+
.forEach { result.addAll(it.findCodeBlocks(predicate)) }
69+
currentSection = currentSection.parent
70+
}
71+
return result
72+
}
73+
74+
fun addAfter(insertPoint: StructuralNode?, node: StructuralNode) {
75+
if (insertPoint == null) {
76+
blocks.add(node)
77+
} else {
78+
val index = blocks.indexOf(insertPoint)
79+
if (index == -1) {
80+
blocks.add(node)
81+
} else {
82+
blocks.add(index + 1, node)
83+
}
84+
}
85+
}
1486
}

core/src/test/kotlin/org/neo4j/graphql/asciidoc/ast/StructuralNode.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ sealed class StructuralNode(
44
open val parent: StructuralNode?
55
) {
66
val blocks = mutableListOf<StructuralNode>()
7+
8+
abstract fun buildContent(contentExtractor: (CodeBlock) -> String): String
79
}

0 commit comments

Comments
 (0)