@@ -1400,6 +1400,167 @@ public function test_page_with_title_only_emits_configure_closure_with_title():
14001400 $ content = file_get_contents ($ this ->outputFile );
14011401 $ this ->assertStringContainsString ('configure: ' , $ content );
14021402 $ this ->assertStringContainsString ("->title('Welcome') " , $ content );
1403+ // no children — nested closure must NOT appear (kills LogicalOrAllSubExprNegation on $hasChildren)
1404+ $ this ->assertStringNotContainsString ('->nested( ' , $ content );
1405+ }
1406+
1407+ // --- explicit cases for the $groups->isEmpty() && !$hasChildren && null===$title condition ---
1408+
1409+ public function test_page_with_no_title_no_groups_no_children_emits_simple_one_liner (): void
1410+ {
1411+ // All three condition parts true → simple one-liner returned
1412+ // Kills LogicalAndSingleSubExprNegation (negates isEmpty → condition fails → empty configure closure emitted)
1413+ $ layout = $ this ->makeLayout ('main ' , 'CwaLayoutPrimary ' );
1414+ $ page = $ this ->makePage ('empty ' , 'CwaPageEmpty ' , $ layout , $ this ->makeRoute ('/empty ' ));
1415+ $ page ->setTitle (null ); // AbstractPage defaults to 'Unnamed Page'; clear it for true no-title case
1416+
1417+ $ this ->runCommand ($ this ->registryWith (layouts: [$ layout ], pages: [$ page ]), $ this ->outputFile );
1418+
1419+ $ content = file_get_contents ($ this ->outputFile );
1420+ $ this ->assertStringContainsString ("'empty' " , $ content );
1421+ // simple form: no configure closure
1422+ $ this ->assertStringNotContainsString ('configure: ' , $ content );
1423+ $ this ->assertStringNotContainsString ('->nested( ' , $ content );
1424+ }
1425+
1426+ public function test_page_with_groups_no_title_no_children_uses_configure_closure (): void
1427+ {
1428+ // groups → condition false → configure closure used (not simple form)
1429+ // Kills LogicalAnd (changes to OR logic), LogicalAndSingleSubExprNegation
1430+ $ layout = $ this ->makeLayout ('main ' , 'CwaLayoutPrimary ' );
1431+ $ page = $ this ->makePage ('main ' , 'CwaPageMain ' , $ layout , $ this ->makeRoute ('/main ' ));
1432+ $ page ->setTitle (null ); // clear default 'Unnamed Page' so groups alone trigger configure closure
1433+
1434+ $ comp = new _TestHtmlComponent ();
1435+ $ comp ->html = 'content ' ;
1436+ $ pos = new ComponentPosition ();
1437+ $ pos ->setComponent ($ comp );
1438+ $ pos ->setSortValue (10 );
1439+ $ group = new ComponentGroup ();
1440+ $ group ->reference = 'page-main-primary ' ;
1441+ $ group ->location = '/_/pages/some-uuid ' ;
1442+ $ group ->componentPositions ->add ($ pos );
1443+ $ page ->getComponentGroups ()->add ($ group );
1444+
1445+ $ this ->runCommand ($ this ->registryWith (layouts: [$ layout ], pages: [$ page ]), $ this ->outputFile );
1446+
1447+ $ content = file_get_contents ($ this ->outputFile );
1448+ $ this ->assertStringContainsString ('configure: ' , $ content );
1449+ $ this ->assertStringContainsString ('content ' , $ content );
1450+ }
1451+
1452+ public function test_page_with_children_only_uses_configure_closure_with_nested (): void
1453+ {
1454+ // !$hasChildren=false → condition false → configure closure with nested block
1455+ // Kills LogicalNot (changes !$hasChildren to $hasChildren → condition true → simple form, no nested)
1456+ $ layout = $ this ->makeLayout ('main ' , 'CwaLayoutPrimary ' );
1457+ $ parent = $ this ->makePage ('hub ' , 'CwaPageHub ' , $ layout , $ this ->makeRoute ('/hub ' ));
1458+ $ parent ->setTitle (null ); // clear default so children alone trigger configure closure
1459+ $ child = $ this ->makePage ('sub ' , 'CwaPageSub ' , $ layout , $ this ->makeRoute ('/hub/sub ' ));
1460+ $ child ->setParentPage ($ parent );
1461+
1462+ $ this ->runCommand (
1463+ $ this ->registryWith (layouts: [$ layout ], pages: [$ parent , $ child ]),
1464+ $ this ->outputFile ,
1465+ );
1466+
1467+ $ content = file_get_contents ($ this ->outputFile );
1468+ $ this ->assertStringContainsString ('configure: ' , $ content );
1469+ $ this ->assertStringContainsString ('->nested( ' , $ content );
1470+ }
1471+
1472+ public function test_page_with_both_child_pages_and_child_page_data_emits_nested (): void
1473+ {
1474+ // $hasChildren = !empty(childPages) || !empty(childPd)
1475+ // Kills LogicalOrAllSubExprNegation: empty(childPages)||empty(childPd) = false||false = false
1476+ // → hasChildren=false → no children path → nested lost
1477+ $ layout = $ this ->makeLayout ('main ' , 'CwaLayoutPrimary ' );
1478+ $ templatePage = $ this ->makePage ('tmpl ' , 'CwaPageTmpl ' , $ layout , null , true );
1479+ $ parent = $ this ->makePage ('hub2 ' , 'CwaPageHub2 ' , $ layout , $ this ->makeRoute ('/hub2 ' ));
1480+ $ parent ->setTitle (null ); // clear default so both childPages and childPd together trigger $hasChildren
1481+
1482+ $ childPage = $ this ->makePage ('sub2 ' , 'CwaPageSub2 ' , $ layout , $ this ->makeRoute ('/hub2/sub2 ' ));
1483+ $ childPage ->setParentPage ($ parent );
1484+
1485+ $ childPd = new _TestArticleData ();
1486+ $ childPd ->setTitle ('Hub Article ' );
1487+ $ childPd ->setParentPage ($ parent );
1488+ $ childPd ->setRoute ($ this ->makeRoute ('/hub2/article ' ));
1489+ $ childPd ->page = $ templatePage ;
1490+
1491+ $ this ->runCommand (
1492+ $ this ->registryWith (layouts: [$ layout ], pages: [$ parent , $ childPage , $ templatePage ], pageData: [$ childPd ]),
1493+ $ this ->outputFile ,
1494+ );
1495+
1496+ $ content = file_get_contents ($ this ->outputFile );
1497+ $ this ->assertStringContainsString ('->nested( ' , $ content );
1498+ $ this ->assertStringContainsString ("'sub2' " , $ content );
1499+ $ this ->assertStringContainsString ('Hub Article ' , $ content );
1500+ }
1501+
1502+ public function test_page_data_with_title_emits_class_instantiation_and_set_title (): void
1503+ {
1504+ // Assignment mutant on setTitle line ($code = '...' instead of $code .= '...') resets $code,
1505+ // losing the class instantiation line.
1506+ $ pd = new _TestArticleData ();
1507+ $ pd ->setTitle ('My Article ' );
1508+
1509+ $ this ->runCommand ($ this ->registryWith (pageData: [$ pd ]), $ this ->outputFile );
1510+
1511+ $ content = file_get_contents ($ this ->outputFile );
1512+ $ this ->assertStringContainsString ('new _TestArticleData() ' , $ content );
1513+ $ this ->assertStringContainsString ("->setTitle('My Article') " , $ content );
1514+ }
1515+
1516+ public function test_page_data_with_template_and_route_both_appear_in_pagedata_call (): void
1517+ {
1518+ // Assignment mutant on $pdArgs .= ', template: ...' resets $pdArgs, losing the $varName prefix
1519+ $ layout = $ this ->makeLayout ('main ' , 'CwaLayoutPrimary ' );
1520+ $ templatePage = $ this ->makePage ('tmpl ' , 'CwaPageTmpl ' , $ layout , null , true );
1521+ $ templatePage ->reference = 'blog-tmpl ' ;
1522+
1523+ $ pd = new _TestArticleData ();
1524+ $ pd ->setTitle ('Article ' );
1525+ $ pd ->page = $ templatePage ;
1526+ $ pd ->setRoute ($ this ->makeRoute ('/articles/first ' ));
1527+
1528+ $ this ->runCommand (
1529+ $ this ->registryWith (layouts: [$ layout ], pages: [$ templatePage ], pageData: [$ pd ]),
1530+ $ this ->outputFile ,
1531+ );
1532+
1533+ $ content = file_get_contents ($ this ->outputFile );
1534+ // $varName (derived from title) AND template both must appear in the ->pageData(...) call
1535+ $ this ->assertStringContainsString ('$pd_Article ' , $ content );
1536+ $ this ->assertStringContainsString ("template: 'blog-tmpl' " , $ content );
1537+ }
1538+
1539+ public function test_component_with_null_first_property_still_emits_second_non_null_property (): void
1540+ {
1541+ // Continue_ → break mutant on the null-value check: stops at the FIRST null property
1542+ // and never reaches subsequent non-null properties.
1543+ // _TestHtmlComponent: html (null here), cssClass (non-null here)
1544+ $ layout = $ this ->makeLayout ('main ' , 'CwaLayoutPrimary ' );
1545+ $ page = $ this ->makePage ('home ' , 'CwaPageHome ' , $ layout , $ this ->makeRoute ('/ ' ));
1546+
1547+ $ comp = new _TestHtmlComponent ();
1548+ // html = null (not set), cssClass = 'my-class' (set second)
1549+ $ comp ->cssClass = 'my-class ' ;
1550+
1551+ $ pos = new ComponentPosition ();
1552+ $ pos ->setComponent ($ comp );
1553+ $ pos ->setSortValue (10 );
1554+ $ group = new ComponentGroup ();
1555+ $ group ->reference = 'page-home-primary ' ;
1556+ $ group ->location = '/_/pages/test ' ;
1557+ $ group ->componentPositions ->add ($ pos );
1558+ $ page ->getComponentGroups ()->add ($ group );
1559+
1560+ $ this ->runCommand ($ this ->registryWith (layouts: [$ layout ], pages: [$ page ]), $ this ->outputFile );
1561+
1562+ $ content = file_get_contents ($ this ->outputFile );
1563+ $ this ->assertStringContainsString ("->cssClass = 'my-class'; " , $ content );
14031564 }
14041565
14051566 // --- route + uiClassNames both appear in page args (kills Assignment .= → = mutant) ---
0 commit comments