Skip to content

Commit 6ea3df4

Browse files
committed
move stack validation logic to test
1 parent f0efa62 commit 6ea3df4

File tree

4 files changed

+55
-49
lines changed

4 files changed

+55
-49
lines changed

core/src/main/kotlin/com/fractalwrench/json2kotlin/ClassTypeHolder.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@ internal class ClassTypeHolder(val delegate: SourceBuildDelegate) : TraversalDel
1010
private val jsonProcessor = JsonProcessor()
1111
private val jsonFieldGrouper = JsonFieldGrouper()
1212

13+
14+
/**
15+
* Processes JSON nodes in a reverse level order traversal,
16+
* by building class types for each level of the tree.
17+
*/
18+
fun processQueue(bfsStack: Stack<TypedJsonElement>) { // TODO split into two separate classes, as separate responsibilities.
19+
var level = -1
20+
val levelQueue = LinkedList<TypedJsonElement>()
21+
22+
while (bfsStack.isNotEmpty()) {
23+
val pop = bfsStack.pop()
24+
25+
if (level != -1 && pop.level != level) {
26+
handleLevel(level, levelQueue)
27+
}
28+
levelQueue.add(pop)
29+
level = pop.level
30+
}
31+
handleLevel(level, levelQueue)
32+
}
33+
private fun handleLevel(level: Int, levelQueue: LinkedList<TypedJsonElement>) {
34+
processTreeLevel(levelQueue)
35+
}
36+
37+
1338
/**
1439
* Processes a single level in the tree
1540
*/

core/src/main/kotlin/com/fractalwrench/json2kotlin/Kotlin2JsonConverter.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ import java.io.OutputStream
66
/**
77
* Converts JSON to Kotlin
88
*/
9-
class Kotlin2JsonConverter(buildDelegate: SourceBuildDelegate = GsonBuildDelegate()) {
9+
class Kotlin2JsonConverter(val buildDelegate: SourceBuildDelegate = GsonBuildDelegate()) {
1010

1111
// TODO (general: update KDocs!)
1212

1313
// TODO expose grouping class as a parameter, add to config
1414

1515
private val jsonReader = JsonReader(JsonParser())
1616
private val sourceFileWriter = SourceFileWriter()
17-
private val typeHolder = ClassTypeHolder(buildDelegate)
18-
private val traverser = ReverseJsonTreeTraverser(typeHolder)
17+
private val traverser = ReverseJsonTreeTraverser()
1918

2019
/**
2120
* Converts a JSON string to Kotlin, writing it to the OutputStream.
@@ -27,7 +26,10 @@ class Kotlin2JsonConverter(buildDelegate: SourceBuildDelegate = GsonBuildDelegat
2726
}
2827

2928
val jsonRoot = jsonReader.readJsonTree(input, args)
30-
traverser.traverse(jsonRoot, args.rootClassName)
29+
val stack = traverser.traverse(jsonRoot, args.rootClassName)
30+
val typeHolder = ClassTypeHolder(buildDelegate)
31+
typeHolder.processQueue(stack)
32+
3133
sourceFileWriter.writeSourceFile(typeHolder.stack, args, output)
3234
} catch (e: JsonSyntaxException) {
3335
throw IllegalArgumentException("Invalid JSON supplied", e)

core/src/main/kotlin/com/fractalwrench/json2kotlin/ReverseJsonTreeTraverser.kt

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,19 @@ import java.util.*
99
/**
1010
* Traverses a JSON tree from the bottom up in level order.
1111
*/
12-
internal class ReverseJsonTreeTraverser(delegate: TraversalDelegate) : TraversalDelegate by delegate {
12+
internal class ReverseJsonTreeTraverser {
1313

14-
private val bfsStack: Stack<TypedJsonElement> = Stack()
15-
16-
fun traverse(element: JsonElement, rootName: String) { // TODO should return a stack instead and not use a delegate
17-
buildStack(element, rootName)
18-
validateStackOrder()
19-
processQueue()
20-
}
21-
22-
private fun validateStackOrder() { // TODO add to a test instead (perf)
23-
var maxLevel = 0
24-
bfsStack.forEach {
25-
if (maxLevel > it.level) {
26-
throw IllegalStateException("Stack is not in correct order: $it")
27-
}
28-
maxLevel = it.level
29-
}
14+
fun traverse(element: JsonElement, rootName: String): Stack<TypedJsonElement> {
15+
val bfsStack: Stack<TypedJsonElement> = Stack()
16+
buildStack(bfsStack, element, rootName)
17+
return bfsStack
3018
}
3119

3220
/**
3321
* Adds the JSON nodes to a stack using BFS. This permits a reverse level order traversal, which is used to build
3422
* class types from the bottom up.
3523
*/
36-
private fun buildStack(parent: JsonElement, key: String?) {
24+
private fun buildStack(bfsStack: Stack<TypedJsonElement>, parent: JsonElement, key: String?) {
3725
val queue = LinkedList<TypedJsonElement>()
3826
queue.add(TypedJsonElement(parent, key!!, 0))
3927

@@ -52,26 +40,6 @@ internal class ReverseJsonTreeTraverser(delegate: TraversalDelegate) : Traversal
5240
}
5341
}
5442

55-
/**
56-
* Processes JSON nodes in a reverse level order traversal,
57-
* by building class types for each level of the tree.
58-
*/
59-
private fun processQueue() { // TODO split into two separate classes, as separate responsibilities.
60-
var level = -1
61-
val levelQueue = LinkedList<TypedJsonElement>()
62-
63-
while (bfsStack.isNotEmpty()) {
64-
val pop = bfsStack.pop()
65-
66-
if (level != -1 && pop.level != level) {
67-
handleLevel(level, levelQueue)
68-
}
69-
levelQueue.add(pop)
70-
level = pop.level
71-
}
72-
handleLevel(level, levelQueue)
73-
}
74-
7543
private fun convertParent(jsonArray: JsonArray, key: String?, depth: Int): List<TypedJsonElement> {
7644
val identifier = key ?:
7745
throw IllegalStateException("Expected generated identifier for array element")
@@ -93,8 +61,5 @@ internal class ReverseJsonTreeTraverser(delegate: TraversalDelegate) : Traversal
9361

9462
private fun shouldAddToStack(element: JsonElement) = element.isJsonArray || element.isJsonObject
9563

96-
private fun handleLevel(level: Int, levelQueue: LinkedList<TypedJsonElement>) {
97-
processTreeLevel(levelQueue)
98-
}
9964

10065
}

core/src/test/kotlin/com/fractalwrench/json2kotlin/JsonConverterTest.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.fractalwrench.json2kotlin
22

3+
import com.google.gson.JsonParser
34
import org.junit.Assert
45
import org.junit.Before
56
import org.junit.Test
67
import org.junit.runner.RunWith
78
import org.junit.runners.Parameterized
89
import java.io.ByteArrayOutputStream
910
import java.io.File
11+
import java.util.*
1012

1113
@RunWith(Parameterized::class)
1214
open class JsonConverterTest(val expectedFilename: String, val jsonFilename: String) {
@@ -17,7 +19,7 @@ open class JsonConverterTest(val expectedFilename: String, val jsonFilename: Str
1719

1820
@Before
1921
fun setUp() {
20-
json = ""
22+
json = fileReader.readContents(jsonFilename)
2123
}
2224

2325
companion object {
@@ -58,8 +60,7 @@ open class JsonConverterTest(val expectedFilename: String, val jsonFilename: Str
5860
* Takes a JSON file and converts it into the equivalent Kotlin class, then compares to expected output.
5961
*/
6062
@Test
61-
open fun testJsonToKotlinConversion() {
62-
json = fileReader.readContents(jsonFilename)
63+
fun testJsonToKotlinConversion() {
6364
val outputStream = ByteArrayOutputStream()
6465
val rootClassName = classNameForFile(expectedFilename)
6566
jsonConverter.convert(json, outputStream, ConversionArgs(rootClassName))
@@ -70,6 +71,19 @@ open class JsonConverterTest(val expectedFilename: String, val jsonFilename: Str
7071
Assert.assertEquals(msg, expectedContents, generatedSource)
7172
}
7273

73-
internal fun classNameForFile(filename: String): String
74+
@Test
75+
fun testStackOrder() {
76+
val readJsonTree = JsonReader(JsonParser()).readJsonTree(json, ConversionArgs())
77+
val stack = ReverseJsonTreeTraverser().traverse(readJsonTree, "Foo")
78+
var maxLevel = 0
79+
stack.forEach {
80+
if (maxLevel > it.level) {
81+
Assert.fail("Stack is not in correct order: $it")
82+
}
83+
maxLevel = it.level
84+
}
85+
}
86+
87+
private fun classNameForFile(filename: String): String
7488
= filename.replace(".kt", "").substringAfterLast(File.separator)
7589
}

0 commit comments

Comments
 (0)