diff --git a/src/Integrations/Divi/Design/ThemeOptionDiff.php b/src/Integrations/Divi/Design/ThemeOptionDiff.php new file mode 100644 index 0000000..10164f7 --- /dev/null +++ b/src/Integrations/Divi/Design/ThemeOptionDiff.php @@ -0,0 +1,62 @@ + + * action: added|changed|reset + */ + public static function between(ThemeOptionBook $before, ThemeOptionBook $after): array + { + $rows = []; + foreach (ThemeOptionSpec::KEYS as $key) { + $action = match (true) { + ! $before->has($key) && $after->has($key) => 'added', + $before->has($key) && ! $after->has($key) => 'reset', + $before->get($key) !== $after->get($key) => 'changed', + default => null, + }; + if ($action !== null) { + $rows[] = [ + 'key' => $key, + 'label' => ThemeOptionSpec::definition($key)['label'], + 'action' => $action, + 'before' => $before->get($key), + 'after' => $after->get($key), + ]; + } + } + + return $rows; + } + + /** + * One German sentence for the dry run and the change log (spec §4 step 6). + * + * @param list> $diff + */ + public static function summary(array $diff): string + { + $count = array_count_values(array_map(static fn (array $row): string => (string) $row['action'], $diff)); + $parts = []; + foreach (['added' => 'gesetzt', 'changed' => 'geändert', 'reset' => 'zurückgesetzt'] as $action => $word) { + if (isset($count[$action])) { + $parts[] = $count[$action] . ' ' . $word; + } + } + + return 'Theme-Optionen: ' . ($parts === [] ? 'keine Änderung' : implode(', ', $parts)) . '.'; + } +} diff --git a/tests/Unit/Integrations/Divi/Design/ThemeOptionDiffTest.php b/tests/Unit/Integrations/Divi/Design/ThemeOptionDiffTest.php new file mode 100644 index 0000000..f517c0f --- /dev/null +++ b/tests/Unit/Integrations/Divi/Design/ThemeOptionDiffTest.php @@ -0,0 +1,101 @@ +with('content_width', 1200) + ->with('body_font_size', 18) + ->with('body_font', 'Roboto') + ->without('body_header_style'); + + self::assertSame([ + ['key' => 'body_font', 'label' => 'Fließtext-Schrift', 'action' => 'changed', + 'before' => 'Lato', 'after' => 'Roboto'], + ['key' => 'body_font_size', 'label' => 'Fließtext-Schriftgröße', 'action' => 'changed', + 'before' => 16, 'after' => 18], + ['key' => 'body_header_style', 'label' => 'Überschrift-Schriftstil', 'action' => 'reset', + 'before' => 'uppercase', 'after' => null], + ['key' => 'content_width', 'label' => 'Inhaltsbreite', 'action' => 'added', + 'before' => null, 'after' => 1200], + ], ThemeOptionDiff::between($before, $after)); + } + + public function testFalseIsAValueOfItsOwn(): void + { + $unset = ThemeOptionBook::fromDivi([]); + $default = ThemeOptionBook::fromDivi(['heading_font' => false]); + $font = ThemeOptionBook::fromDivi(['heading_font' => 'Lato']); + + self::assertSame( + [['key' => 'heading_font', 'label' => 'Überschrift-Schrift', 'action' => 'added', + 'before' => null, 'after' => false]], + ThemeOptionDiff::between($unset, $default) + ); + self::assertSame( + [['key' => 'heading_font', 'label' => 'Überschrift-Schrift', 'action' => 'changed', + 'before' => false, 'after' => 'Lato']], + ThemeOptionDiff::between($default, $font) + ); + self::assertSame( + [['key' => 'heading_font', 'label' => 'Überschrift-Schrift', 'action' => 'reset', + 'before' => false, 'after' => null]], + ThemeOptionDiff::between($default, $unset) + ); + } + + public function testATypeChangeCountsAsAChange(): void + { + $int = ThemeOptionBook::fromDivi(['gutter_width' => 1, 'body_header_height' => 1]); + $text = ThemeOptionBook::fromDivi(['gutter_width' => '1', 'body_header_height' => 1.0]); + + self::assertSame( + [ + ['key' => 'body_header_height', 'label' => 'Überschrift-Zeilenhöhe', 'action' => 'changed', + 'before' => 1, 'after' => 1.0], + ['key' => 'gutter_width', 'label' => 'Spaltenabstand', 'action' => 'changed', + 'before' => 1, 'after' => '1'], + ], + ThemeOptionDiff::between($int, $text) + ); + } + + public function testSummaryCountsPerAction(): void + { + $before = ThemeOptionBook::fromDivi(ThemeOptionBookTest::stored()); + $after = $before->with('content_width', 1200)->with('body_font_size', 18)->with('body_font', 'Roboto') + ->without('body_header_style'); + + self::assertSame( + 'Theme-Optionen: 1 gesetzt, 2 geändert, 1 zurückgesetzt.', + ThemeOptionDiff::summary(ThemeOptionDiff::between($before, $after)) + ); + self::assertSame( + 'Theme-Optionen: 1 gesetzt.', + ThemeOptionDiff::summary(ThemeOptionDiff::between( + ThemeOptionBook::fromDivi([]), + ThemeOptionBook::fromDivi(['content_width' => 1200]) + )) + ); + self::assertSame('Theme-Optionen: keine Änderung.', ThemeOptionDiff::summary([])); + } +}