@@ -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