@@ -58,6 +58,9 @@ TEST_CASE("SchemaNode")
5858 ],
5959 "type_module:anydataWithMandatoryChild": {"content": "test-string"},
6060 "type_module:anyxmlWithMandatoryChild": {"content": "test-string"},
61+ "type_module:choiceWithMandatoryContainer": {
62+ "l4": "test-string"
63+ },
6164 "type_module:containerWithMandatoryChild": {
6265 "leafWithMandatoryTrue": "test-string"
6366 },
@@ -180,6 +183,10 @@ TEST_CASE("SchemaNode")
180183 " /type_module:anydataWithMandatoryChild" ,
181184 " /type_module:anyxmlBasic" ,
182185 " /type_module:anyxmlWithMandatoryChild" ,
186+ " /type_module:choiceBasicContainer" ,
187+ " /type_module:choiceWithMandatoryContainer" ,
188+ " /type_module:choiceWithDefaultContainer" ,
189+ " /type_module:implicitCaseContainer" ,
183190 " /type_module:leafBinary" ,
184191 " /type_module:leafBits" ,
185192 " /type_module:leafEnum" ,
@@ -417,6 +424,71 @@ TEST_CASE("SchemaNode")
417424 REQUIRE (!ctx->findPath (" /type_module:anyxmlBasic" ).asAnyDataAnyXML ().isMandatory ());
418425 }
419426
427+ DOCTEST_SUBCASE (" Choice and Case" )
428+ {
429+ std::string xpath;
430+ bool isMandatory = false ;
431+ std::optional<std::string> defaultCase;
432+ std::vector<std::string> caseNames;
433+ std::optional<libyang::SchemaNode> root;
434+
435+ DOCTEST_SUBCASE (" two cases with nothing fancy" )
436+ {
437+ root = ctx->findPath (" /type_module:choiceBasicContainer" );
438+ caseNames = {" case1" , " case2" };
439+ }
440+
441+ DOCTEST_SUBCASE (" mandatory choice" ) {
442+ root = ctx->findPath (" /type_module:choiceWithMandatoryContainer" );
443+ isMandatory = true ;
444+ caseNames = {" case3" , " case4" };
445+ }
446+
447+ DOCTEST_SUBCASE (" default choice" ) {
448+ root = ctx->findPath (" /type_module:choiceWithDefaultContainer" );
449+ defaultCase = " case5" ;
450+ caseNames = {" case5" , " case6" };
451+ }
452+
453+ DOCTEST_SUBCASE (" implicit case" ) {
454+ root = ctx->findPath (" /type_module:implicitCaseContainer" );
455+ caseNames = {" implicitLeaf" };
456+ }
457+
458+ // For testing purposes, we have each choice in its own container. As choice and case are not directly instantiable,
459+ // we wrap them in a container to simplify the testing process. It allows us to simply address the choice by its
460+ // container and then get the choice from it. It also prevents polluting the test schema with unnecessary nodes
461+ // and isolates the choice from other nodes.
462+ auto container = root->asContainer ();
463+ auto choice = container.immediateChildren ().begin ()->asChoice ();
464+ REQUIRE (choice.isMandatory () == isMandatory);
465+ REQUIRE (!!choice.defaultCase () == !!defaultCase);
466+ if (defaultCase) {
467+ REQUIRE (choice.defaultCase ()->name () == *defaultCase);
468+ }
469+ std::vector<std::string> actualCaseNames;
470+ for (const auto & case_ : choice.cases ()) {
471+ actualCaseNames.push_back (case_.name ());
472+ }
473+ REQUIRE (actualCaseNames == caseNames);
474+
475+ // Also test child node access for one arbitrary choice/case combination
476+ if (root->path () == " /type_module:choiceBasicContainer" ) {
477+ REQUIRE (choice.cases ().size () == 2 );
478+ auto case1 = choice.cases ()[0 ];
479+ auto children = case1.immediateChildren ();
480+ auto it = children.begin ();
481+ REQUIRE (it->asLeaf ().name () == " l" );
482+ ++it;
483+ REQUIRE (it->asLeafList ().name () == " ll" );
484+
485+ auto case2 = choice.cases ()[1 ];
486+ children = case2.immediateChildren ();
487+ it = children.begin ();
488+ REQUIRE (it->asLeaf ().name () == " l2" );
489+ }
490+ }
491+
420492 DOCTEST_SUBCASE (" Container::isMandatory" )
421493 {
422494 REQUIRE (ctx->findPath (" /type_module:containerWithMandatoryChild" ).asContainer ().isMandatory ());
0 commit comments