Skip to content

Commit a17ea11

Browse files
committed
Add comprehensive tests for oneOf discriminator-first decoding
- Add 5 unit and integration tests for Swift5 generator - Add 5 unit and integration tests for Swift6 generator - Tests validate CodegenModel discriminator properties - Tests validate generated Swift code contains discriminator-first decoding - Tests verify fallback to sequential try? when no discriminator - Tests use existing oneOfDiscriminator.yaml spec Tests cover: - Discriminator property extraction - Enum discriminator mapping - Generated code patterns (switch on discriminator value) - Backward compatibility (sequential try? without discriminator)
1 parent 4165a5d commit a17ea11

File tree

2 files changed

+376
-0
lines changed

2 files changed

+376
-0
lines changed

modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,192 @@ public void oneOfFormParameterTest() {
317317

318318
}
319319

320+
@Test(description = "test oneOf model with discriminator properties", enabled = true)
321+
public void oneOfWithDiscriminatorModelTest() {
322+
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/oneOfDiscriminator.yaml");
323+
final DefaultCodegen codegen = new Swift5ClientCodegen();
324+
codegen.setOpenAPI(openAPI);
325+
326+
final Schema schema = openAPI.getComponents().getSchemas().get("FruitReqDisc");
327+
final CodegenModel cm = codegen.fromModel("FruitReqDisc", schema);
328+
329+
Assert.assertNotNull(cm.discriminator, "Discriminator should not be null");
330+
Assert.assertEquals(cm.discriminator.getPropertyName(), "fruitType");
331+
Assert.assertEquals(cm.discriminator.getPropertyBaseName(), "fruitType");
332+
Assert.assertTrue(cm.getHasDiscriminatorWithNonEmptyMapping(),
333+
"Should have discriminator with non-empty mapping");
334+
335+
java.util.Set<org.openapitools.codegen.CodegenDiscriminator.MappedModel> mappedModels =
336+
cm.discriminator.getMappedModels();
337+
Assert.assertEquals(mappedModels.size(), 2, "Should have 2 mapped models");
338+
339+
java.util.Set<String> modelNames = new java.util.HashSet<>();
340+
for (org.openapitools.codegen.CodegenDiscriminator.MappedModel mm : mappedModels) {
341+
modelNames.add(mm.getModelName());
342+
}
343+
Assert.assertTrue(modelNames.contains("AppleReqDisc"), "Should contain AppleReqDisc");
344+
Assert.assertTrue(modelNames.contains("BananaReqDisc"), "Should contain BananaReqDisc");
345+
}
346+
347+
@Test(description = "test oneOf model with enum discriminator mapping", enabled = true)
348+
public void oneOfWithEnumDiscriminatorMappingModelTest() {
349+
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/oneOfDiscriminator.yaml");
350+
final DefaultCodegen codegen = new Swift5ClientCodegen();
351+
codegen.setOpenAPI(openAPI);
352+
353+
final Schema schema = openAPI.getComponents().getSchemas().get("FruitOneOfEnumMappingDisc");
354+
final CodegenModel cm = codegen.fromModel("FruitOneOfEnumMappingDisc", schema);
355+
356+
Assert.assertNotNull(cm.discriminator, "Discriminator should not be null");
357+
Assert.assertEquals(cm.discriminator.getPropertyName(), "fruitType");
358+
Assert.assertTrue(cm.getHasDiscriminatorWithNonEmptyMapping(),
359+
"Should have discriminator with non-empty mapping");
360+
361+
java.util.Set<org.openapitools.codegen.CodegenDiscriminator.MappedModel> mappedModels =
362+
cm.discriminator.getMappedModels();
363+
Assert.assertEquals(mappedModels.size(), 2, "Should have 2 mapped models");
364+
365+
java.util.Map<String, String> mappings = new java.util.HashMap<>();
366+
for (org.openapitools.codegen.CodegenDiscriminator.MappedModel mm : mappedModels) {
367+
mappings.put(mm.getMappingName(), mm.getModelName());
368+
}
369+
Assert.assertTrue(mappings.containsKey("APPLE"), "Should have APPLE mapping");
370+
Assert.assertTrue(mappings.containsKey("BANANA"), "Should have BANANA mapping");
371+
Assert.assertEquals(mappings.get("APPLE"), "AppleOneOfEnumMappingDisc");
372+
Assert.assertEquals(mappings.get("BANANA"), "BananaOneOfEnumMappingDisc");
373+
}
374+
375+
@Test(description = "test oneOf generates discriminator-first decoding", enabled = true)
376+
public void oneOfDiscriminatorFirstDecodingTest() throws IOException {
377+
Path target = Files.createTempDirectory("test");
378+
File output = target.toFile();
379+
try {
380+
final CodegenConfigurator configurator = new CodegenConfigurator()
381+
.setGeneratorName("swift5")
382+
.setInputSpec("src/test/resources/3_0/oneOfDiscriminator.yaml")
383+
.setOutputDir(target.toAbsolutePath().toString());
384+
385+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
386+
DefaultGenerator generator = new DefaultGenerator(false);
387+
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
388+
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
389+
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
390+
391+
List<File> files = generator.opts(clientOptInput).generate();
392+
393+
File modelFile = files.stream()
394+
.filter(f -> f.getName().equals("FruitReqDisc.swift"))
395+
.findFirst()
396+
.orElseThrow(() -> new RuntimeException("FruitReqDisc.swift not found"));
397+
398+
String content = Files.readString(modelFile.toPath());
399+
400+
Assert.assertTrue(content.contains("private enum DiscriminatorCodingKey: String, CodingKey"),
401+
"Missing DiscriminatorCodingKey enum");
402+
Assert.assertTrue(content.contains("case fruitType ="),
403+
"Missing fruitType discriminator key");
404+
Assert.assertTrue(content.contains("let keyedContainer = try decoder.container(keyedBy: DiscriminatorCodingKey.self)"),
405+
"Missing keyedContainer for discriminator");
406+
Assert.assertTrue(content.contains("let discriminatorValue = try keyedContainer.decode(String.self, forKey: .fruitType)"),
407+
"Missing discriminator value extraction");
408+
Assert.assertTrue(content.contains("switch discriminatorValue"),
409+
"Missing switch on discriminator value");
410+
Assert.assertTrue(content.contains("case \"AppleReqDisc\":"),
411+
"Missing AppleReqDisc case");
412+
Assert.assertTrue(content.contains("self = .typeAppleReqDisc(try AppleReqDisc(from: decoder))"),
413+
"Missing AppleReqDisc initialization");
414+
Assert.assertTrue(content.contains("case \"BananaReqDisc\":"),
415+
"Missing BananaReqDisc case");
416+
Assert.assertTrue(content.contains("self = .typeBananaReqDisc(try BananaReqDisc(from: decoder))"),
417+
"Missing BananaReqDisc initialization");
418+
Assert.assertFalse(content.contains("if let value = try? container.decode(AppleReqDisc.self)"),
419+
"Should NOT have sequential try? decoding when discriminator exists");
420+
421+
} finally {
422+
output.deleteOnExit();
423+
}
424+
}
425+
426+
@Test(description = "test oneOf with enum mapping generates correct discriminator cases", enabled = true)
427+
public void oneOfEnumMappingDiscriminatorDecodingTest() throws IOException {
428+
Path target = Files.createTempDirectory("test");
429+
File output = target.toFile();
430+
try {
431+
final CodegenConfigurator configurator = new CodegenConfigurator()
432+
.setGeneratorName("swift5")
433+
.setInputSpec("src/test/resources/3_0/oneOfDiscriminator.yaml")
434+
.setOutputDir(target.toAbsolutePath().toString());
435+
436+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
437+
DefaultGenerator generator = new DefaultGenerator(false);
438+
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
439+
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
440+
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
441+
442+
List<File> files = generator.opts(clientOptInput).generate();
443+
444+
File modelFile = files.stream()
445+
.filter(f -> f.getName().equals("FruitOneOfEnumMappingDisc.swift"))
446+
.findFirst()
447+
.orElseThrow(() -> new RuntimeException("FruitOneOfEnumMappingDisc.swift not found"));
448+
449+
String content = Files.readString(modelFile.toPath());
450+
451+
Assert.assertTrue(content.contains("case \"APPLE\":"),
452+
"Missing APPLE enum mapping case");
453+
Assert.assertTrue(content.contains("self = .typeAppleOneOfEnumMappingDisc(try AppleOneOfEnumMappingDisc(from: decoder))"),
454+
"Missing AppleOneOfEnumMappingDisc initialization with APPLE mapping");
455+
Assert.assertTrue(content.contains("case \"BANANA\":"),
456+
"Missing BANANA enum mapping case");
457+
Assert.assertTrue(content.contains("self = .typeBananaOneOfEnumMappingDisc(try BananaOneOfEnumMappingDisc(from: decoder))"),
458+
"Missing BananaOneOfEnumMappingDisc initialization with BANANA mapping");
459+
460+
} finally {
461+
output.deleteOnExit();
462+
}
463+
}
464+
465+
@Test(description = "test oneOf without discriminator uses sequential try decoding", enabled = true)
466+
public void oneOfWithoutDiscriminatorFallbackTest() throws IOException {
467+
Path target = Files.createTempDirectory("test");
468+
File output = target.toFile();
469+
try {
470+
final CodegenConfigurator configurator = new CodegenConfigurator()
471+
.setGeneratorName("swift5")
472+
.setInputSpec("src/test/resources/3_0/oneOf.yaml")
473+
.setOutputDir(target.toAbsolutePath().toString());
474+
475+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
476+
DefaultGenerator generator = new DefaultGenerator(false);
477+
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
478+
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
479+
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
480+
481+
List<File> files = generator.opts(clientOptInput).generate();
482+
483+
File modelFile = files.stream()
484+
.filter(f -> f.getName().equals("Fruit.swift"))
485+
.findFirst()
486+
.orElseThrow(() -> new RuntimeException("Fruit.swift not found"));
487+
488+
String content = Files.readString(modelFile.toPath());
489+
490+
Assert.assertTrue(content.contains("let container = try decoder.singleValueContainer()"),
491+
"Missing singleValueContainer for fallback");
492+
Assert.assertTrue(content.contains("if let value = try? container.decode("),
493+
"Missing sequential try? decoding pattern");
494+
Assert.assertTrue(content.contains("} else if let value = try? container.decode("),
495+
"Missing else if try? decoding pattern");
496+
Assert.assertFalse(content.contains("private enum DiscriminatorCodingKey"),
497+
"Should NOT have DiscriminatorCodingKey when no discriminator");
498+
Assert.assertFalse(content.contains("keyedContainer"),
499+
"Should NOT have keyedContainer when no discriminator");
500+
Assert.assertFalse(content.contains("discriminatorValue"),
501+
"Should NOT have discriminatorValue when no discriminator");
502+
503+
} finally {
504+
output.deleteOnExit();
505+
}
506+
}
507+
320508
}

0 commit comments

Comments
 (0)