diff --git a/CHANGELOG.md b/CHANGELOG.md index e8930f1..1ded7bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). -## Unreleased +## [0.109] - 2024-09-05 ### Changed +- templates: fixed bug in templates for map-based classes - `CodeGenerator`: added explicit types to public APIs ## [0.108] - 2024-08-07 diff --git a/README.md b/README.md index d703a95..3d04aa0 100644 --- a/README.md +++ b/README.md @@ -334,25 +334,25 @@ operation: ## Dependency Specification -The latest version of the library is 0.108, and it may be obtained from the Maven Central repository. +The latest version of the library is 0.109, and it may be obtained from the Maven Central repository. ### Maven ```xml net.pwall.json json-kotlin-schema-codegen - 0.108 + 0.109 ``` ### Gradle ```groovy - implementation 'net.pwall.json:json-kotlin-schema-codegen:0.108' + implementation 'net.pwall.json:json-kotlin-schema-codegen:0.109' ``` ### Gradle (kts) ```kotlin - implementation("net.pwall.json:json-kotlin-schema-codegen:0.108") + implementation("net.pwall.json:json-kotlin-schema-codegen:0.109") ``` Peter Wall -2024-08-07 +2024-09-05 diff --git a/pom.xml b/pom.xml index 02dc74e..28951e3 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 net.pwall.json json-kotlin-schema-codegen - 0.108 + 0.109 JSON Schema Code Generation Code generation from JSON Schema to Kotlin or Java jar diff --git a/src/main/resources/kotlin/class_map_property.mustache b/src/main/resources/kotlin/class_map_property.mustache index 880e7c2..f387b3d 100644 --- a/src/main/resources/kotlin/class_map_property.mustache +++ b/src/main/resources/kotlin/class_map_property.mustache @@ -1,7 +1,6 @@ -{{&indent}} require(cg_map["{{&name}}"] is {{#isArray}}{{>list_or_set}}<*>{{/isArray}}{{! -}}{{^isArray}}{{>type_ex_nullable}}{{/isArray}}) { "{{&name}} is not the correct type, expecting {{>type}}" } +{{&indent}} require(cg_map["{{&name}}"] is {{>type_or_list_or_set}}) { "{{&name}} is not the correct type, expecting {{>type}}" } {{#isArray}}{{&indent}} (cg_map["{{&name}}"] as {{>list_or_set}}<*>).forEach { {{#indent.increment}}{{#arrayItems}}{{&kotlinName}} -> {{>class_map_property_item}}{{/arrayItems}}{{/indent.increment}}{{&indent}} } -{{/isArray}}{{^isArray}}{{#validations}}{{#first}}{{&indent}} (cg_map["{{&name}}"] as {{>type_ex_nullable}}).let { {{&kotlinName}} -> +{{/isArray}}{{^isArray}}{{#validations}}{{#first}}{{&indent}} (cg_map["{{&name}}"] as {{>type}}){{#nullable}}?{{/nullable}}.let { {{&kotlinName}} -> {{/first}}{{#indent.increment}}{{>validations_2}}{{/indent.increment}}{{#last}}{{&indent}} } {{/last}}{{/validations}}{{/isArray}} \ No newline at end of file diff --git a/src/main/resources/kotlin/nested_class_map.mustache b/src/main/resources/kotlin/nested_class_map.mustache index 70292e6..d3a1e75 100644 --- a/src/main/resources/kotlin/nested_class_map.mustache +++ b/src/main/resources/kotlin/nested_class_map.mustache @@ -6,9 +6,12 @@ {{#properties}}{{#defaultValue}}{{&indent}} if (cg_map.containsKey("{{&name}}")){{#validations}}{{#first}} {{&openBrace}}{{/first}}{{/validations}} {{#indent.increment}}{{>class_map_property}}{{/indent.increment}}{{#validations}}{{#first}}{{&indent}} } {{/first}}{{/validations}}{{/defaultValue}}{{^defaultValue}}{{! -}}{{#nullable}}{{&indent}} if (cg_map.containsKey("{{&name}}")){{#validations}}{{#first}} {{&openBrace}}{{/first}}{{/validations}} -{{#indent.increment}}{{>class_map_property}}{{/indent.increment}}{{#validations}}{{#first}}{{&indent}} } -{{/first}}{{/validations}}{{/nullable}}{{^nullable}}{{&indent}} require(cg_map.containsKey("{{&name}}")) { "required property missing - {{&name}}" } +}}{{#nullable}}{{&indent}} if (cg_map.containsKey("{{&name}}")){{! +}}{{#isArray}} {{&openBrace}}{{/isArray}}{{^isArray}}{{#validations}}{{#first}} {{&openBrace}}{{/first}}{{/validations}}{{/isArray}} +{{#indent.increment}}{{>class_map_property}}{{/indent.increment}}{{! +}}{{#isArray}}{{&indent}} } +{{/isArray}}{{^isArray}}{{#validations}}{{#first}}{{&indent}} } +{{/first}}{{/validations}}{{/isArray}}{{/nullable}}{{^nullable}}{{&indent}} require(cg_map.containsKey("{{&name}}")) { "required property missing - {{&name}}" } {{>class_map_property}}{{/nullable}}{{/defaultValue}}{{/properties}}{{! }}{{^properties}}{{#additionalProperties}}{{#validations}}{{#first}}{{&indent}} cg_map.entries.forEach { (key, value) -> {{/first}}{{#indent.increment}}{{#mapEntryContext}}{{>validations_2}}{{/mapEntryContext}}{{/indent.increment}}{{#last}}{{&indent}} } @@ -16,9 +19,11 @@ {{#properties}} {{#schema}}{{#description}}{{&indent}} /** {{&safeDescription}} */ {{/description}}{{/schema}}{{&indent}} val {{&kotlinName}}: {{>type}}{{#defaultValue}} -{{&indent}} get() = if (cg_map.containsKey("{{&name}}")) cg_map["{{&name}}"] as {{>type}} else {{>default_value}} +{{#isArray}}{{&indent}} @Suppress("unchecked_cast") +{{/isArray}}{{&indent}} get() = if (cg_map.containsKey("{{&name}}")) cg_map["{{&name}}"] as {{>type}} else {{>default_value}} {{/defaultValue}}{{^defaultValue}}{{#nullable}} -{{&indent}} get() = cg_map["{{&name}}"] as {{>type}} +{{#isArray}}{{&indent}} @Suppress("unchecked_cast") +{{/isArray}}{{&indent}} get() = cg_map["{{&name}}"] as {{>type}} {{/nullable}}{{^nullable}} by cg_map {{/nullable}}{{/defaultValue}}{{/properties}} {{&indent}} override fun toString(): String = "{{&className}}(${cg_map.entries.joinToString { "${it.key}=${it.value}" }})" diff --git a/src/main/resources/kotlin/type_or_list_or_set.mustache b/src/main/resources/kotlin/type_or_list_or_set.mustache new file mode 100644 index 0000000..460954d --- /dev/null +++ b/src/main/resources/kotlin/type_or_list_or_set.mustache @@ -0,0 +1 @@ +{{#isArray}}{{>list_or_set}}<*>{{/isArray}}{{^isArray}}{{>type}}{{/isArray}} \ No newline at end of file diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/CodeGeneratorAdditionalPropertiesTest.kt b/src/test/kotlin/net/pwall/json/schema/codegen/CodeGeneratorAdditionalPropertiesTest.kt index 5a960e9..ca19e95 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/CodeGeneratorAdditionalPropertiesTest.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/CodeGeneratorAdditionalPropertiesTest.kt @@ -123,6 +123,42 @@ class CodeGeneratorAdditionalPropertiesTest { expect(resultFile("TestApTrueExtra")) { outputDetails.output() } } + @Test fun `should generate code for aP true with optional extra`() { + val input = File("src/test/resources/test-ap-true-extra-optional.schema.json") + val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraOptional", "kt", packageDirs)) + CodeGenerator().apply { + additionalPropertiesOption = CodeGenerator.AdditionalPropertiesOption.STRICT + basePackageName = packageName + outputResolver = outputCapture(outputDetails) + generate(input) + } + expect(resultFile("TestApTrueExtraOptional")) { outputDetails.output() } + } + + @Test fun `should generate code for aP true with extra with validation`() { + val input = File("src/test/resources/test-ap-true-extra-valid.schema.json") + val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraValid", "kt", packageDirs)) + CodeGenerator().apply { + additionalPropertiesOption = CodeGenerator.AdditionalPropertiesOption.STRICT + basePackageName = packageName + outputResolver = outputCapture(outputDetails) + generate(input) + } + expect(resultFile("TestApTrueExtraValid")) { outputDetails.output() } + } + + @Test fun `should generate code for aP true with optional extra with validation`() { + val input = File("src/test/resources/test-ap-true-extra-opt-valid.schema.json") + val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraOptValid", "kt", packageDirs)) + CodeGenerator().apply { + additionalPropertiesOption = CodeGenerator.AdditionalPropertiesOption.STRICT + basePackageName = packageName + outputResolver = outputCapture(outputDetails) + generate(input) + } + expect(resultFile("TestApTrueExtraOptValid")) { outputDetails.output() } + } + @Test fun `should generate code for aP true with extra array`() { val input = File("src/test/resources/test-ap-true-extra-array.schema.json") val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraArray", "kt", packageDirs)) @@ -135,6 +171,30 @@ class CodeGeneratorAdditionalPropertiesTest { expect(resultFile("TestApTrueExtraArray")) { outputDetails.output() } } + @Test fun `should generate code for aP true with optional extra array`() { + val input = File("src/test/resources/test-ap-true-extra-array-opt.schema.json") + val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraArrayOpt", "kt", packageDirs)) + CodeGenerator().apply { + additionalPropertiesOption = CodeGenerator.AdditionalPropertiesOption.STRICT + basePackageName = packageName + outputResolver = outputCapture(outputDetails) + generate(input) + } + expect(resultFile("TestApTrueExtraArrayOpt")) { outputDetails.output() } + } + + @Test fun `should generate code for aP true with optional extra array with validation`() { + val input = File("src/test/resources/test-ap-true-extra-array-opt-valid.schema.json") + val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraArrayOptValid", "kt", packageDirs)) + CodeGenerator().apply { + additionalPropertiesOption = CodeGenerator.AdditionalPropertiesOption.STRICT + basePackageName = packageName + outputResolver = outputCapture(outputDetails) + generate(input) + } + expect(resultFile("TestApTrueExtraArrayOptValid")) { outputDetails.output() } + } + @Test fun `should generate code for aP true with extra with default value`() { val input = File("src/test/resources/test-ap-true-extra-default.schema.json") val outputDetails = OutputDetails(TargetFileName("TestApTrueExtraDefault", "kt", packageDirs)) diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesDeserializationTest.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesDeserializationTest.kt index 18aaa53..ff3c805 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesDeserializationTest.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesDeserializationTest.kt @@ -94,31 +94,31 @@ class AdditionalPropertiesDeserializationTest { @Test fun `should deserialize TestApTrueExtra`() { val json1 = """{"extra":"content"}""" - val result1 = json1.parseJSON() + val result1 = json1.parseJSON() expect("content") { result1.extra } assertNull(result1["whatever"]) val json2 = """{"extra":"content","anything":"another"}""" - val result2 = json2.parseJSON() + val result2 = json2.parseJSON() expect("content") { result2.extra } expect("another") { result2["anything"] } assertNull(result2["whatever"]) assertFailsWith { - """{"anything":"another"}""".parseJSON() + """{"anything":"another"}""".parseJSON() }.cause.let { assertIs(it) expect("required property missing - extra") { it.message } } assertFailsWith { - """{"extra":123}""".parseJSON() + """{"extra":123}""".parseJSON() }.let { expect("Can't deserialize 123 as String at /extra") { it.message } } assertFailsWith { - """{"extra":""}""".parseJSON() + """{"extra":""}""".parseJSON() }.cause.let { assertIs(it) expect("extra length < minimum 1 - 0") { it.message } @@ -150,7 +150,7 @@ class AdditionalPropertiesDeserializationTest { } assertFailsWith { - """{"extra":""}""".parseJSON() + """{"extra":""}""".parseJSON() }.cause.let { assertIs(it) expect("extra length < minimum 1 - 0") { it.message } diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesFunctionalityTest.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesFunctionalityTest.kt index 2700a74..1aedebd 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesFunctionalityTest.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/AdditionalPropertiesFunctionalityTest.kt @@ -27,6 +27,7 @@ package net.pwall.json.schema.codegen.test.kotlin import kotlin.test.Test import kotlin.test.assertFailsWith +import kotlin.test.assertIs import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.test.expect @@ -130,9 +131,143 @@ class AdditionalPropertiesFunctionalityTest { }.let { expect("extra is not the correct type, expecting String") { it.message } } + } + + @Test fun `should generate functional TestApTrueExtraOptional`() { + val testClass1 = TestApTrueExtraOptional(mapOf( + "extra" to "content", + )) + expect("content") { testClass1.extra } + assertNull(testClass1["whatever"]) + expect("TestApTrueExtraOptional(extra=content)") { testClass1.toString() } + + val testClass2 = TestApTrueExtraOptional(mapOf( + "extra" to "content", + "anything" to "another", + )) + expect("content") { testClass2.extra } + expect("another") { testClass2["anything"] } + assertNull(testClass2["whatever"]) + expect("TestApTrueExtraOptional(extra=content, anything=another)") { testClass2.toString() } + + val testClass3 = TestApTrueExtraOptional(mapOf( + "extra" to null, + )) + assertNull(testClass3.extra) + assertNull(testClass3["whatever"]) + expect("TestApTrueExtraOptional(extra=null)") { testClass3.toString() } + + val testClass4 = TestApTrueExtraOptional(emptyMap()) + assertNull(testClass4.extra) + assertNull(testClass4["whatever"]) + expect("TestApTrueExtraOptional()") { testClass4.toString() } + + val testClass5 = TestApTrueExtraOptional(mapOf( + "anything" to "another", + )) + assertNull(testClass5.extra) + expect("another") { testClass5["anything"] } + assertNull(testClass5["whatever"]) + expect("TestApTrueExtraOptional(anything=another)") { testClass5.toString() } assertFailsWith { - TestApTrueExtra(mapOf( + TestApTrueExtraOptional(mapOf( + "extra" to 123, + )) + }.let { + expect("extra is not the correct type, expecting String?") { it.message } + } + } + + @Test fun `should generate functional TestApTrueExtraValid`() { + val testClass1 = TestApTrueExtraValid(mapOf( + "extra" to "content", + )) + expect("content") { testClass1.extra } + assertNull(testClass1["whatever"]) + expect("TestApTrueExtraValid(extra=content)") { testClass1.toString() } + + val testClass2 = TestApTrueExtraValid(mapOf( + "extra" to "content", + "anything" to "another", + )) + expect("content") { testClass2.extra } + expect("another") { testClass2["anything"] } + assertNull(testClass2["whatever"]) + expect("TestApTrueExtraValid(extra=content, anything=another)") { testClass2.toString() } + + assertFailsWith { + TestApTrueExtraValid(mapOf( + "anything" to "another", + )) + }.let { + expect("required property missing - extra") { it.message } + } + + assertFailsWith { + TestApTrueExtraValid(mapOf( + "extra" to 123, + )) + }.let { + expect("extra is not the correct type, expecting String") { it.message } + } + + assertFailsWith { + TestApTrueExtraValid(mapOf( + "extra" to "", + )) + }.let { + expect("extra length < minimum 1 - 0") { it.message } + } + } + + @Test fun `should generate functional TestApTrueExtraOptValid`() { + val testClass1 = TestApTrueExtraOptValid(mapOf( + "extra" to "content", + )) + expect("content") { testClass1.extra } + assertNull(testClass1["whatever"]) + expect("TestApTrueExtraOptValid(extra=content)") { testClass1.toString() } + + val testClass2 = TestApTrueExtraOptValid(mapOf( + "extra" to "content", + "anything" to "another", + )) + expect("content") { testClass2.extra } + expect("another") { testClass2["anything"] } + assertNull(testClass2["whatever"]) + expect("TestApTrueExtraOptValid(extra=content, anything=another)") { testClass2.toString() } + + val testClass3 = TestApTrueExtraOptValid(mapOf( + "extra" to null, + )) + assertNull(testClass3.extra) + assertNull(testClass3["whatever"]) + expect("TestApTrueExtraOptValid(extra=null)") { testClass3.toString() } + + val testClass4 = TestApTrueExtraOptValid(emptyMap()) + assertNull(testClass4.extra) + assertNull(testClass4["whatever"]) + expect("TestApTrueExtraOptValid()") { testClass4.toString() } + + val testClass5 = TestApTrueExtraOptValid(mapOf( + "anything" to "another", + )) + assertNull(testClass5.extra) + expect("another") { testClass5["anything"] } + assertNull(testClass5["whatever"]) + expect("TestApTrueExtraOptValid(anything=another)") { testClass5.toString() } + + assertFailsWith { + TestApTrueExtraOptValid(mapOf( + "extra" to 123, + )) + }.let { + expect("extra is not the correct type, expecting String?") { it.message } + } + + assertFailsWith { + TestApTrueExtraOptValid(mapOf( "extra" to "", )) }.let { @@ -182,6 +317,170 @@ class AdditionalPropertiesFunctionalityTest { } } + @Test fun `should generate functional TestApTrueExtraArray`() { + with(TestApTrueExtraArray(mapOf( + "extra" to listOf("alpha", "beta"), + ))) { + with(extra) { + assertIs>(this) + expect(2) { size } + expect("alpha") { this[0] } + expect("beta") { this[1] } + } + assertNull(this["whatever"]) + expect("TestApTrueExtraArray(extra=[alpha, beta])") { toString() } + } + + with(TestApTrueExtraArray(mapOf( + "extra" to listOf("alpha", "beta"), + "anything" to "another", + ))) { + with(extra) { + assertIs>(this) + expect(2) { size } + expect("alpha") { this[0] } + expect("beta") { this[1] } + } + expect("another") { this["anything"] } + assertNull(this["whatever"]) + expect("TestApTrueExtraArray(extra=[alpha, beta], anything=another)") { toString() } + } + + assertFailsWith { + TestApTrueExtraArray(emptyMap()) + }.let { + expect("required property missing - extra") { it.message } + } + + assertFailsWith { + TestApTrueExtraArray(mapOf( + "extra" to "wrong", + )) + }.let { + expect("extra is not the correct type, expecting List") { it.message } + } + + assertFailsWith { + TestApTrueExtraArray(mapOf( + "extra" to listOf(123, 456), + )) + }.let { + expect("extra item is not the correct type, expecting String") { it.message } + } + } + + @Test fun `should generate functional TestApTrueExtraArrayOpt`() { + with(TestApTrueExtraArrayOpt(mapOf( + "extra" to listOf("alpha", "beta"), + ))) { + with(extra) { + assertIs>(this) + expect(2) { size } + expect("alpha") { this[0] } + expect("beta") { this[1] } + } + assertNull(this["whatever"]) + expect("TestApTrueExtraArrayOpt(extra=[alpha, beta])") { toString() } + } + + with(TestApTrueExtraArrayOpt(mapOf( + "extra" to listOf("alpha", "beta"), + "anything" to "another", + ))) { + with(extra) { + assertIs>(this) + expect(2) { size } + expect("alpha") { this[0] } + expect("beta") { this[1] } + } + expect("another") { this["anything"] } + assertNull(this["whatever"]) + expect("TestApTrueExtraArrayOpt(extra=[alpha, beta], anything=another)") { toString() } + } + + with(TestApTrueExtraArrayOpt(emptyMap())) { + assertNull(this["extra"]) + assertNull(this["whatever"]) + expect("TestApTrueExtraArrayOpt()") { toString() } + } + + assertFailsWith { + TestApTrueExtraArrayOpt(mapOf( + "extra" to "wrong", + )) + }.let { + expect("extra is not the correct type, expecting List?") { it.message } + } + + assertFailsWith { + TestApTrueExtraArrayOpt(mapOf( + "extra" to listOf(123, 456), + )) + }.let { + expect("extra item is not the correct type, expecting String") { it.message } + } + } + + @Test fun `should generate functional TestApTrueExtraArrayOptValid`() { + with(TestApTrueExtraArrayOptValid(mapOf( + "extra" to listOf("alpha", "beta"), + ))) { + with(extra) { + assertIs>(this) + expect(2) { size } + expect("alpha") { this[0] } + expect("beta") { this[1] } + } + assertNull(this["whatever"]) + expect("TestApTrueExtraArrayOptValid(extra=[alpha, beta])") { toString() } + } + + with(TestApTrueExtraArrayOptValid(mapOf( + "extra" to listOf("alpha", "beta"), + "anything" to "another", + ))) { + with(extra) { + assertIs>(this) + expect(2) { size } + expect("alpha") { this[0] } + expect("beta") { this[1] } + } + expect("another") { this["anything"] } + assertNull(this["whatever"]) + expect("TestApTrueExtraArrayOptValid(extra=[alpha, beta], anything=another)") { toString() } + } + + with(TestApTrueExtraArrayOptValid(emptyMap())) { + assertNull(this["extra"]) + assertNull(this["whatever"]) + expect("TestApTrueExtraArrayOptValid()") { toString() } + } + + assertFailsWith { + TestApTrueExtraArrayOptValid(mapOf( + "extra" to "wrong", + )) + }.let { + expect("extra is not the correct type, expecting List?") { it.message } + } + + assertFailsWith { + TestApTrueExtraArrayOptValid(mapOf( + "extra" to listOf(123, 456), + )) + }.let { + expect("extra item is not the correct type, expecting String") { it.message } + } + + assertFailsWith { + TestApTrueExtraArrayOptValid(mapOf( + "extra" to listOf("alpha", ""), + )) + }.let { + expect("extra item length < minimum 1 - 0") { it.message } + } + } + @Test fun `should generate functional TestAdditionalPropertiesSchemaExtra`() { val testClass1 = TestAdditionalPropertiesSchemaExtra(mapOf( "extra" to "content", diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestAdditionalPropertiesSchemaExtra3.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestAdditionalPropertiesSchemaExtra3.kt index 03f9245..780584b 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestAdditionalPropertiesSchemaExtra3.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestAdditionalPropertiesSchemaExtra3.kt @@ -23,8 +23,8 @@ class TestAdditionalPropertiesSchemaExtra3( require(extra.isNotEmpty()) { "extra length < minimum 1 - ${extra.length}" } } if (cg_map.containsKey("extra2")) { - require(cg_map["extra2"] is Int) { "extra2 is not the correct type, expecting Int?" } - (cg_map["extra2"] as Int).let { extra2 -> + require(cg_map["extra2"] is Int?) { "extra2 is not the correct type, expecting Int?" } + (cg_map["extra2"] as Int?)?.let { extra2 -> require(extra2 in 0..99) { "extra2 not in range 0..99 - $extra2" } } } diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApFalsePatternExtraOpt.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApFalsePatternExtraOpt.kt index a0e1ff4..c41b3b2 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApFalsePatternExtraOpt.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApFalsePatternExtraOpt.kt @@ -18,8 +18,8 @@ class TestApFalsePatternExtraOpt( init { if (cg_map.containsKey("extra")) { - require(cg_map["extra"] is String) { "extra is not the correct type, expecting String?" } - (cg_map["extra"] as String).let { extra -> + require(cg_map["extra"] is String?) { "extra is not the correct type, expecting String?" } + (cg_map["extra"] as String?)?.let { extra -> require(extra.isNotEmpty()) { "extra length < minimum 1 - ${extra.length}" } } } diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtra.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtra.kt index 72a2d98..11c9b10 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtra.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtra.kt @@ -19,9 +19,6 @@ class TestApTrueExtra( init { require(cg_map.containsKey("extra")) { "required property missing - extra" } require(cg_map["extra"] is String) { "extra is not the correct type, expecting String" } - (cg_map["extra"] as String).let { extra -> - require(extra.isNotEmpty()) { "extra length < minimum 1 - ${extra.length}" } - } } val extra: String by cg_map diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraArrayOpt.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraArrayOpt.kt new file mode 100644 index 0000000..45aca42 --- /dev/null +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraArrayOpt.kt @@ -0,0 +1,38 @@ +/* + * TestApTrueExtraArrayOpt.kt + * + * This code was generated by json-kotlin-schema-codegen - JSON Schema Code Generator + * See https://github.com/pwall567/json-kotlin-schema-codegen + * + * It is not advisable to modify generated code as any modifications will be lost + * when the generation process is re-run. + */ +package net.pwall.json.schema.codegen.test.kotlin + +/** + * Test use of additionalProperties true with optional extra list field. + */ +class TestApTrueExtraArrayOpt( + private val cg_map: Map +) : Map by cg_map { + + init { + if (cg_map.containsKey("extra")) { + require(cg_map["extra"] is List<*>) { "extra is not the correct type, expecting List?" } + (cg_map["extra"] as List<*>).forEach { cg_0 -> + require(cg_0 is String) { "extra item is not the correct type, expecting String" } + } + } + } + + val extra: List? + @Suppress("unchecked_cast") + get() = cg_map["extra"] as List? + + override fun toString(): String = "TestApTrueExtraArrayOpt(${cg_map.entries.joinToString { "${it.key}=${it.value}" }})" + + override fun equals(other: Any?): Boolean = this === other || other is TestApTrueExtraArrayOpt && cg_map == other.cg_map + + override fun hashCode(): Int = cg_map.hashCode() + +} diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraArrayOptValid.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraArrayOptValid.kt new file mode 100644 index 0000000..cacda17 --- /dev/null +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraArrayOptValid.kt @@ -0,0 +1,39 @@ +/* + * TestApTrueExtraArrayOptValid.kt + * + * This code was generated by json-kotlin-schema-codegen - JSON Schema Code Generator + * See https://github.com/pwall567/json-kotlin-schema-codegen + * + * It is not advisable to modify generated code as any modifications will be lost + * when the generation process is re-run. + */ +package net.pwall.json.schema.codegen.test.kotlin + +/** + * Test use of additionalProperties true with optional extra list field with item validation. + */ +class TestApTrueExtraArrayOptValid( + private val cg_map: Map +) : Map by cg_map { + + init { + if (cg_map.containsKey("extra")) { + require(cg_map["extra"] is List<*>) { "extra is not the correct type, expecting List?" } + (cg_map["extra"] as List<*>).forEach { cg_0 -> + require(cg_0 is String) { "extra item is not the correct type, expecting String" } + require(cg_0.isNotEmpty()) { "extra item length < minimum 1 - ${cg_0.length}" } + } + } + } + + val extra: List? + @Suppress("unchecked_cast") + get() = cg_map["extra"] as List? + + override fun toString(): String = "TestApTrueExtraArrayOptValid(${cg_map.entries.joinToString { "${it.key}=${it.value}" }})" + + override fun equals(other: Any?): Boolean = this === other || other is TestApTrueExtraArrayOptValid && cg_map == other.cg_map + + override fun hashCode(): Int = cg_map.hashCode() + +} diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraNested.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraNested.kt index 9c3b711..26783bd 100644 --- a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraNested.kt +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraNested.kt @@ -22,7 +22,7 @@ class TestApTrueExtraNested( require(cg_map.containsKey("codes")) { "required property missing - codes" } require(cg_map["codes"] is Codes) { "codes is not the correct type, expecting Codes" } if (cg_map.containsKey("empty")) - require(cg_map["empty"] is Empty) { "empty is not the correct type, expecting Empty?" } + require(cg_map["empty"] is Empty?) { "empty is not the correct type, expecting Empty?" } } /** Extra data. */ diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraOptValid.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraOptValid.kt new file mode 100644 index 0000000..6b9dd72 --- /dev/null +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraOptValid.kt @@ -0,0 +1,37 @@ +/* + * TestApTrueExtraOptValid.kt + * + * This code was generated by json-kotlin-schema-codegen - JSON Schema Code Generator + * See https://github.com/pwall567/json-kotlin-schema-codegen + * + * It is not advisable to modify generated code as any modifications will be lost + * when the generation process is re-run. + */ +package net.pwall.json.schema.codegen.test.kotlin + +/** + * Test use of additionalProperties true with optional extra fields with validation. + */ +class TestApTrueExtraOptValid( + private val cg_map: Map +) : Map by cg_map { + + init { + if (cg_map.containsKey("extra")) { + require(cg_map["extra"] is String?) { "extra is not the correct type, expecting String?" } + (cg_map["extra"] as String?)?.let { extra -> + require(extra.isNotEmpty()) { "extra length < minimum 1 - ${extra.length}" } + } + } + } + + val extra: String? + get() = cg_map["extra"] as String? + + override fun toString(): String = "TestApTrueExtraOptValid(${cg_map.entries.joinToString { "${it.key}=${it.value}" }})" + + override fun equals(other: Any?): Boolean = this === other || other is TestApTrueExtraOptValid && cg_map == other.cg_map + + override fun hashCode(): Int = cg_map.hashCode() + +} diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraOptional.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraOptional.kt new file mode 100644 index 0000000..c7af994 --- /dev/null +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraOptional.kt @@ -0,0 +1,33 @@ +/* + * TestApTrueExtraOptional.kt + * + * This code was generated by json-kotlin-schema-codegen - JSON Schema Code Generator + * See https://github.com/pwall567/json-kotlin-schema-codegen + * + * It is not advisable to modify generated code as any modifications will be lost + * when the generation process is re-run. + */ +package net.pwall.json.schema.codegen.test.kotlin + +/** + * Test use of additionalProperties true with optional extra fields. + */ +class TestApTrueExtraOptional( + private val cg_map: Map +) : Map by cg_map { + + init { + if (cg_map.containsKey("extra")) + require(cg_map["extra"] is String?) { "extra is not the correct type, expecting String?" } + } + + val extra: String? + get() = cg_map["extra"] as String? + + override fun toString(): String = "TestApTrueExtraOptional(${cg_map.entries.joinToString { "${it.key}=${it.value}" }})" + + override fun equals(other: Any?): Boolean = this === other || other is TestApTrueExtraOptional && cg_map == other.cg_map + + override fun hashCode(): Int = cg_map.hashCode() + +} diff --git a/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraValid.kt b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraValid.kt new file mode 100644 index 0000000..85597b9 --- /dev/null +++ b/src/test/kotlin/net/pwall/json/schema/codegen/test/kotlin/TestApTrueExtraValid.kt @@ -0,0 +1,35 @@ +/* + * TestApTrueExtraValid.kt + * + * This code was generated by json-kotlin-schema-codegen - JSON Schema Code Generator + * See https://github.com/pwall567/json-kotlin-schema-codegen + * + * It is not advisable to modify generated code as any modifications will be lost + * when the generation process is re-run. + */ +package net.pwall.json.schema.codegen.test.kotlin + +/** + * Test use of additionalProperties true with extra fields with validation. + */ +class TestApTrueExtraValid( + private val cg_map: Map +) : Map by cg_map { + + init { + require(cg_map.containsKey("extra")) { "required property missing - extra" } + require(cg_map["extra"] is String) { "extra is not the correct type, expecting String" } + (cg_map["extra"] as String).let { extra -> + require(extra.isNotEmpty()) { "extra length < minimum 1 - ${extra.length}" } + } + } + + val extra: String by cg_map + + override fun toString(): String = "TestApTrueExtraValid(${cg_map.entries.joinToString { "${it.key}=${it.value}" }})" + + override fun equals(other: Any?): Boolean = this === other || other is TestApTrueExtraValid && cg_map == other.cg_map + + override fun hashCode(): Int = cg_map.hashCode() + +} diff --git a/src/test/resources/test-ap-true-extra-array-opt-valid.schema.json b/src/test/resources/test-ap-true-extra-array-opt-valid.schema.json new file mode 100644 index 0000000..46ac0f2 --- /dev/null +++ b/src/test/resources/test-ap-true-extra-array-opt-valid.schema.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft/2019-09/schema", + "$id": "http://pwall.net/test-ap-true-extra-array-opt-valid", + "description": "Test use of additionalProperties true with optional extra list field with item validation.", + "type": "object", + "properties": { + "extra": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "additionalProperties": true +} diff --git a/src/test/resources/test-ap-true-extra-array-opt.schema.json b/src/test/resources/test-ap-true-extra-array-opt.schema.json new file mode 100644 index 0000000..8410720 --- /dev/null +++ b/src/test/resources/test-ap-true-extra-array-opt.schema.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft/2019-09/schema", + "$id": "http://pwall.net/test-ap-true-extra-array-opt", + "description": "Test use of additionalProperties true with optional extra list field.", + "type": "object", + "properties": { + "extra": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true +} diff --git a/src/test/resources/test-ap-true-extra-opt-valid.schema.json b/src/test/resources/test-ap-true-extra-opt-valid.schema.json new file mode 100644 index 0000000..e74bd4a --- /dev/null +++ b/src/test/resources/test-ap-true-extra-opt-valid.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft/2019-09/schema", + "$id": "http://pwall.net/test-ap-true-extra-opt-valid", + "description": "Test use of additionalProperties true with optional extra fields with validation.", + "type": "object", + "properties": { + "extra": { + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": true +} diff --git a/src/test/resources/test-ap-true-extra-optional.schema.json b/src/test/resources/test-ap-true-extra-optional.schema.json new file mode 100644 index 0000000..06f502b --- /dev/null +++ b/src/test/resources/test-ap-true-extra-optional.schema.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft/2019-09/schema", + "$id": "http://pwall.net/test-ap-true-extra-optional", + "description": "Test use of additionalProperties true with optional extra fields.", + "type": "object", + "properties": { + "extra": { + "type": "string" + } + }, + "additionalProperties": true +} diff --git a/src/test/resources/test-ap-true-extra-valid.schema.json b/src/test/resources/test-ap-true-extra-valid.schema.json new file mode 100644 index 0000000..c4f85b0 --- /dev/null +++ b/src/test/resources/test-ap-true-extra-valid.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft/2019-09/schema", + "$id": "http://pwall.net/test-ap-true-extra-valid", + "description": "Test use of additionalProperties true with extra fields with validation.", + "type": "object", + "properties": { + "extra": { + "type": "string", + "minLength": 1 + } + }, + "required": [ "extra" ], + "additionalProperties": true +} diff --git a/src/test/resources/test-ap-true-extra.schema.json b/src/test/resources/test-ap-true-extra.schema.json index 4b68d5e..6b0767b 100644 --- a/src/test/resources/test-ap-true-extra.schema.json +++ b/src/test/resources/test-ap-true-extra.schema.json @@ -5,8 +5,7 @@ "type": "object", "properties": { "extra": { - "type": "string", - "minLength": 1 + "type": "string" } }, "required": [ "extra" ],