Skip to content

Commit aa0e902

Browse files
committed
Add targeted mutation-killing tests for GenerateFixturesCommand to restore MSI above 85%
Adds tests that cover: continue-vs-break in top-level iteration, stripUiPrefix edge cases (null, non-prefixed values, CwaPage-prefixed pages), child pages/pageData linked via parentPage appearing in nested closures (previously only parentPageData path was tested), page title triggering configure closure, route+uiClassNames both emitted in page args, two-position groups emitting both positions, and full component assignment format asserting class instantiation plus uiComponent/uiClassNames/own-property all appear.
1 parent aaa3937 commit aa0e902

1 file changed

Lines changed: 241 additions & 2 deletions

File tree

tests/Command/GenerateFixturesCommandTest.php

Lines changed: 241 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ public function test_page_data_var_name_has_pd_prefix_and_slugified_title(): voi
900900
$this->assertStringContainsString('$pd_My_Great_Article', $content);
901901
}
902902

903-
public function test_page_data_with_null_title_uses_pageData_fallback_var_name(): void
903+
public function test_page_data_with_null_title_uses_page_data_fallback_var_name(): void
904904
{
905905
$pd = new _TestArticleData();
906906
$pd->setTitle(null); // explicitly null — triggers the ?? 'pageData' fallback
@@ -1153,7 +1153,7 @@ public function test_export_array_format_multiple_items_comma_separated(): void
11531153
public function test_success_message_written_to_output(): void
11541154
{
11551155
$command = $this->makeCommand($this->emptyRegistry());
1156-
$tester = new \Symfony\Component\Console\Tester\CommandTester($command);
1156+
$tester = new CommandTester($command);
11571157
$tester->execute(['--output' => $this->outputFile]);
11581158

11591159
$display = $tester->getDisplay();
@@ -1249,4 +1249,243 @@ public function test_page_with_title_and_children_emits_both_title_and_nested_in
12491249
$this->assertStringContainsString("\$page->title('Parent Title')", $content);
12501250
$this->assertStringContainsString('->nested(', $content);
12511251
}
1252+
1253+
// --- Coalesce mutant killers: child indexed via getParentPage() fallback ---
1254+
1255+
public function test_child_page_linked_via_parent_page_appears_in_nested_closure(): void
1256+
{
1257+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1258+
$parent = $this->makePage('parent', 'CwaPageParent', $layout, $this->makeRoute('/parent'));
1259+
$child = $this->makePage('child', 'CwaPageChild', $layout, $this->makeRoute('/parent/child'));
1260+
$child->setParentPage($parent);
1261+
1262+
$this->runCommand(
1263+
$this->registryWith(layouts: [$layout], pages: [$parent, $child]),
1264+
$this->outputFile,
1265+
);
1266+
1267+
$content = file_get_contents($this->outputFile);
1268+
$this->assertStringContainsString('->nested(', $content);
1269+
$this->assertStringContainsString("'child'", $content);
1270+
}
1271+
1272+
public function test_child_page_data_linked_via_parent_page_appears_in_nested_closure(): void
1273+
{
1274+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1275+
$templatePage = $this->makePage('tmpl', 'CwaPageTmpl', $layout, null, true);
1276+
$parent = $this->makePage('parent', 'CwaPageParent', $layout, $this->makeRoute('/parent'));
1277+
1278+
$childPd = new _TestArticleData();
1279+
$childPd->setTitle('Child Article');
1280+
$childPd->setParentPage($parent);
1281+
$childPd->setRoute($this->makeRoute('/parent/child'));
1282+
$childPd->page = $templatePage;
1283+
1284+
$this->runCommand(
1285+
$this->registryWith(layouts: [$layout], pages: [$parent, $templatePage], pageData: [$childPd]),
1286+
$this->outputFile,
1287+
);
1288+
1289+
$content = file_get_contents($this->outputFile);
1290+
$this->assertStringContainsString('->nested(', $content);
1291+
$this->assertStringContainsString('Child Article', $content);
1292+
}
1293+
1294+
// --- stripUiPrefix edge cases ---
1295+
1296+
public function test_layout_with_null_ui_component_emits_null(): void
1297+
{
1298+
$layout = $this->makeLayout('main', '');
1299+
$layout->uiComponent = null;
1300+
1301+
$this->runCommand($this->registryWith(layouts: [$layout]), $this->outputFile);
1302+
1303+
$content = file_get_contents($this->outputFile);
1304+
$this->assertStringContainsString('->layout(', $content);
1305+
$this->assertStringContainsString('NULL', $content);
1306+
}
1307+
1308+
public function test_layout_with_non_cwa_prefixed_ui_component_emits_as_is(): void
1309+
{
1310+
$layout = $this->makeLayout('main', 'MyCustomLayout');
1311+
1312+
$this->runCommand($this->registryWith(layouts: [$layout]), $this->outputFile);
1313+
1314+
$content = file_get_contents($this->outputFile);
1315+
$this->assertStringContainsString("'MyCustomLayout'", $content);
1316+
}
1317+
1318+
public function test_page_with_cwa_page_prefixed_ui_component_strips_prefix(): void
1319+
{
1320+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1321+
$route = $this->makeRoute('/blog');
1322+
$page = $this->makePage('blog', 'CwaPageBlog', $layout, $route);
1323+
1324+
$this->runCommand($this->registryWith(layouts: [$layout], pages: [$page]), $this->outputFile);
1325+
1326+
$content = file_get_contents($this->outputFile);
1327+
$this->assertStringContainsString("'Blog'", $content);
1328+
$this->assertStringNotContainsString("'CwaPageBlog'", $content);
1329+
}
1330+
1331+
public function test_page_with_non_cwa_prefixed_ui_component_emits_as_is(): void
1332+
{
1333+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1334+
$route = $this->makeRoute('/home');
1335+
$page = $this->makePage('home', 'CustomPageTemplate', $layout, $route);
1336+
1337+
$this->runCommand($this->registryWith(layouts: [$layout], pages: [$page]), $this->outputFile);
1338+
1339+
$content = file_get_contents($this->outputFile);
1340+
$this->assertStringContainsString("'CustomPageTemplate'", $content);
1341+
}
1342+
1343+
// --- continue vs break in top-level iteration ---
1344+
1345+
public function test_second_top_level_page_is_emitted_when_first_page_in_array_is_a_child(): void
1346+
{
1347+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1348+
$parent = $this->makePage('parent', 'CwaPageParent', $layout, $this->makeRoute('/parent'));
1349+
$child = $this->makePage('child', 'CwaPageChild', $layout, $this->makeRoute('/parent/child'));
1350+
$child->setParentPage($parent);
1351+
$other = $this->makePage('other', 'CwaPageOther', $layout, $this->makeRoute('/other'));
1352+
1353+
// child is first in array — break mutant would stop after skipping it, losing 'other'
1354+
$this->runCommand(
1355+
$this->registryWith(layouts: [$layout], pages: [$child, $parent, $other]),
1356+
$this->outputFile,
1357+
);
1358+
1359+
$content = file_get_contents($this->outputFile);
1360+
$this->assertStringContainsString("'other'", $content);
1361+
$this->assertStringContainsString("'parent'", $content);
1362+
}
1363+
1364+
public function test_second_top_level_page_data_is_emitted_when_first_is_a_child(): void
1365+
{
1366+
$parentPd = new _TestArticleData();
1367+
$parentPd->setTitle('Parent');
1368+
$parentPd->setRoute($this->makeRoute('/parent'));
1369+
1370+
$childPd = new _TestArticleData();
1371+
$childPd->setTitle('Child');
1372+
$childPd->setParentPageData($parentPd);
1373+
$childPd->setRoute($this->makeRoute('/parent/child'));
1374+
1375+
$otherPd = new _TestArticleData();
1376+
$otherPd->setTitle('Other');
1377+
$otherPd->setRoute($this->makeRoute('/other'));
1378+
1379+
// child first — break mutant stops after skipping, losing 'other'
1380+
$this->runCommand(
1381+
$this->registryWith(pageData: [$childPd, $parentPd, $otherPd]),
1382+
$this->outputFile,
1383+
);
1384+
1385+
$content = file_get_contents($this->outputFile);
1386+
$this->assertStringContainsString("'Other'", $content);
1387+
$this->assertStringContainsString("'Parent'", $content);
1388+
}
1389+
1390+
// --- page configure closure triggered by title alone ---
1391+
1392+
public function test_page_with_title_only_emits_configure_closure_with_title(): void
1393+
{
1394+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1395+
$page = $this->makePage('home', 'CwaPageHome', $layout, $this->makeRoute('/'));
1396+
$page->setTitle('Welcome');
1397+
1398+
$this->runCommand($this->registryWith(layouts: [$layout], pages: [$page]), $this->outputFile);
1399+
1400+
$content = file_get_contents($this->outputFile);
1401+
$this->assertStringContainsString('configure:', $content);
1402+
$this->assertStringContainsString("->title('Welcome')", $content);
1403+
}
1404+
1405+
// --- route + uiClassNames both appear in page args (kills Assignment .= → = mutant) ---
1406+
1407+
public function test_page_ui_class_names_appended_alongside_route_in_args(): void
1408+
{
1409+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1410+
$route = $this->makeRoute('/home', 'home-page');
1411+
$page = $this->makePage('home', 'CwaPageHome', $layout, $route);
1412+
$page->uiClassNames = ['hero'];
1413+
1414+
$this->runCommand($this->registryWith(layouts: [$layout], pages: [$page]), $this->outputFile);
1415+
1416+
$content = file_get_contents($this->outputFile);
1417+
$this->assertStringContainsString("'/home'", $content);
1418+
$this->assertStringContainsString('uiClassNames', $content);
1419+
$this->assertStringContainsString("'hero'", $content);
1420+
}
1421+
1422+
// --- group with two positions emits both (kills posCode concat mutants) ---
1423+
1424+
public function test_group_with_two_components_emits_both_in_closure(): void
1425+
{
1426+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1427+
$route = $this->makeRoute('/home');
1428+
$page = $this->makePage('home', 'CwaPageHome', $layout, $route);
1429+
1430+
$comp1 = new _TestHtmlComponent();
1431+
$comp1->html = 'first';
1432+
$comp2 = new _TestHtmlComponent();
1433+
$comp2->html = 'second';
1434+
1435+
$pos1 = new ComponentPosition();
1436+
$pos1->setComponent($comp1);
1437+
$pos1->setSortValue(10);
1438+
$pos2 = new ComponentPosition();
1439+
$pos2->setComponent($comp2);
1440+
$pos2->setSortValue(20);
1441+
1442+
$group = new ComponentGroup();
1443+
$group->reference = 'page-home-primary';
1444+
$group->location = '/_/pages/some-uuid';
1445+
$group->componentPositions->add($pos1);
1446+
$group->componentPositions->add($pos2);
1447+
$page->getComponentGroups()->add($group);
1448+
1449+
$this->runCommand($this->registryWith(layouts: [$layout], pages: [$page]), $this->outputFile);
1450+
1451+
$content = file_get_contents($this->outputFile);
1452+
$this->assertStringContainsString('first', $content);
1453+
$this->assertStringContainsString('second', $content);
1454+
}
1455+
1456+
// --- component uiComponent and own-property both emitted (kills code .= Assignment/Concat mutants) ---
1457+
1458+
public function test_component_class_instantiation_uicomponent_and_property_all_appear(): void
1459+
{
1460+
$layout = $this->makeLayout('main', 'CwaLayoutPrimary');
1461+
$route = $this->makeRoute('/home');
1462+
$page = $this->makePage('home', 'CwaPageHome', $layout, $route);
1463+
1464+
$comp = new _TestHtmlComponent();
1465+
$comp->uiComponent = 'FancyRenderer';
1466+
$comp->uiClassNames = ['bold', 'dark'];
1467+
$comp->html = 'body text';
1468+
1469+
$pos = new ComponentPosition();
1470+
$pos->setComponent($comp);
1471+
$pos->setSortValue(10);
1472+
1473+
$group = new ComponentGroup();
1474+
$group->reference = 'page-home-primary';
1475+
$group->location = '/_/pages/some-uuid';
1476+
$group->componentPositions->add($pos);
1477+
$page->getComponentGroups()->add($group);
1478+
1479+
$this->runCommand($this->registryWith(layouts: [$layout], pages: [$page]), $this->outputFile);
1480+
1481+
$content = file_get_contents($this->outputFile);
1482+
// class instantiation must appear (kills Assignment line 174/177 that resets $code)
1483+
$this->assertStringContainsString('new _TestHtmlComponent()', $content);
1484+
// full uiComponent assignment (kills Concat/ConcatOperandRemoval on line ~174)
1485+
$this->assertStringContainsString("->uiComponent = 'FancyRenderer';", $content);
1486+
// full uiClassNames assignment (kills Concat/ConcatOperandRemoval/Assignment on line ~177)
1487+
$this->assertStringContainsString("->uiClassNames = ['bold', 'dark'];", $content);
1488+
// full own-property assignment including value (kills ConcatOperandRemoval on line ~189)
1489+
$this->assertStringContainsString("->html = 'body text';", $content);
1490+
}
12521491
}

0 commit comments

Comments
 (0)