Skip to content

Commit b1965e9

Browse files
committed
Add GenerateFixturesCommand mutation tests to restore MSI above 85%
Seven new PHPUnit tests target the surviving mutants: - emitPage simple-form condition (LogicalAnd, LogicalAndSingleSubExprNegation, LogicalNot, LogicalOrAllSubExprNegation) — all require setTitle(null) to isolate the condition being tested from the default 'Unnamed Page' title - emitPageData title and pdArgs Assignment (.= → =) mutants - emitPosition Continue_ → break mutant on null-value skip Also tightens test_page_with_title_only to assert configure: but not ->nested(.
1 parent aa0e902 commit b1965e9

1 file changed

Lines changed: 161 additions & 0 deletions

File tree

tests/Command/GenerateFixturesCommandTest.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)