docs: Guides für Farben, Variablen, Theme-Optionen, Schriften, Snapshots und Schleifen-Inhalte

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 23:21:09 +02:00
co-authored by Claude Sonnet 5.5
parent cfc46e1c5e
commit fc35cbe9dd
7 changed files with 387 additions and 20 deletions
+77
View File
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Guides;
use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
/**
* The loop part of the guides (Etappe 4e) says what the tools say: the refusal phrases come from the code, and every
* {{loop:<name>}} example names an option Divi 5.15.1 really registers (research 4e, table of the loop_* options).
*/
final class LoopGuideTest extends TestCase
{
/** Divi 5.15.1 option keys (without WooCommerce and ACF repeater options). */
private const DIVI_LOOP_OPTIONS = [
'loop_post_title', 'loop_post_excerpt', 'loop_post_date', 'loop_post_modified_date', 'loop_post_author',
'loop_post_author_bio', 'loop_post_author_profile_picture', 'loop_post_comment_count',
'loop_post_featured_image', 'loop_post_id', 'loop_post_link', 'loop_post_terms',
'loop_term_name', 'loop_term_description', 'loop_term_count', 'loop_term_permalink', 'loop_term_taxonomy',
'loop_term_featured_image', 'loop_user_name', 'loop_user_username', 'loop_user_email', 'loop_user_avatar',
'loop_user_description', 'loop_user_url', 'loop_menu_text', 'loop_menu_link', 'loop_menu_menu_order',
'loop_menu_attr_title', 'loop_menu_classes', 'loop_menu_xfn', 'loop_menu_description',
];
private const PHRASES = ['braucht eine Divi-Schleife', 'passt nicht zur Schleife', 'kein Schleifen-Kontext'];
private static function root(): string
{
return dirname(__DIR__, 3);
}
/** @return string Content of all guides. */
private static function guides(): string
{
$text = '';
foreach (glob(self::root() . '/docs/guides/*.md') ?: [] as $file) {
$text .= (string) file_get_contents($file) . "\n";
}
return $text;
}
public function testGuidesExplainTheLoopRefusals(): void
{
$guides = self::guides();
foreach (self::PHRASES as $phrase) {
self::assertStringContainsString($phrase, $guides, 'guides lack "' . $phrase . '"');
}
}
public function testRefusalPhrasesAreTheOnesTheCodeSays(): void
{
$code = '';
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(self::root() . '/src'));
foreach ($files as $file) {
if (str_ends_with((string) $file, '.php')) {
$code .= (string) file_get_contents((string) $file);
}
}
foreach (self::PHRASES as $phrase) {
self::assertNotFalse(mb_stripos($code, $phrase), 'no source says "' . $phrase . '"');
}
}
public function testLoopShortFormExamplesNameRealDiviOptions(): void
{
preg_match_all('/\{\{loop:([a-z0-9_]+)\}\}/', self::guides(), $examples);
self::assertNotEmpty($examples[1], 'the guides show no {{loop:…}} example');
foreach (array_unique($examples[1]) as $name) {
self::assertContains('loop_' . $name, self::DIVI_LOOP_OPTIONS, '{{loop:' . $name . '}} is no Divi option');
}
}
}
+11
View File
@@ -130,6 +130,17 @@ final class ToolNamingTest extends TestCase
self::assertSame($files, $listedTopics);
}
/** Every indirect tool is named in the overview (the only place a client learns which `lit/` tools exist). */
public function testOverviewNamesEveryIndirectTool(): void
{
$overview = (string) file_get_contents(dirname(__DIR__, 3) . '/docs/guides/overview.md');
preg_match_all('#`lit/([a-z]+(?:-[a-z]+)*)`#', $overview, $named);
$indirect = array_keys(array_filter(self::abilities(), static fn (bool $direct): bool => ! $direct));
self::assertNotEmpty($indirect);
self::assertSame([], array_values(array_diff($indirect, $named[1])), 'indirect tools missing in overview.md');
}
public function testOverviewListsExactlyTheDirectTools(): void
{
$overview = (string) file_get_contents(dirname(__DIR__, 3) . '/docs/guides/overview.md');