justReturn(true); } private static function ability(): DiviThemeOptionsGetAbility { $stored = ThemeOptionsAreaTest::stored(); $writes = []; return new DiviThemeOptionsGetAbility(ThemeOptionsAreaTest::adapter($stored, $writes)); } /** * @param array $result * @return array> key => row */ private static function byKey(array $result): array { return array_column($result['options'], null, 'key'); } public function testSchemaAndMeta(): void { $ability = self::ability(); $schema = $ability->inputSchema(); self::assertSame('lit/divi-theme-options-get', $ability->name()); self::assertFalse($ability->isDirect()); self::assertSame(Annotations::read(), $ability->annotations()); self::assertSame([DiviFeature::ThemeOptionRead], $ability->diviFeatures([])); self::assertSame(ThemeOptionSpec::KEYS, $schema['properties']['keys']['items']['enum']); self::assertFalse($schema['additionalProperties']); self::assertSame(['options', 'design_rev', 'notes'], $ability->outputSchema()['required']); self::assertStringContainsString('lit/divi-theme-options-update', $ability->description()); } /** Reading needs what lit/divi-design-system needs (edit_posts) – checked before Divi is asked. */ public function testNeedsEditPosts(): void { Functions\when('current_user_can')->justReturn(false); $options = Mockery::mock(ThemeOptionsAdapter::class); $options->shouldNotReceive('read'); $ability = new DiviThemeOptionsGetAbility($options); self::assertToolError($ability->permission([]), 'forbidden'); self::assertToolError($ability->execute([]), 'forbidden'); } public function testListsEveryOptionWithValueEffectiveValueAndDefault(): void { $result = self::ability()->execute([]); self::assertSame(ThemeOptionSpec::KEYS, array_column($result['options'], 'key')); self::assertSame(ThemeOptionBook::fromDivi(ThemeOptionsAreaTest::stored())->rev(), $result['design_rev']); $rows = self::byKey($result); $size = ThemeOptionSpec::definition('body_font_size'); $expected = ['key' => 'body_font_size', 'label' => $size['label'], 'type' => 'int', 'value' => 16, 'effective' => 16, 'default' => ThemeOptionSpec::effective('body_font_size', []), 'is_default' => false, 'min' => $size['min'], 'max' => $size['max'], 'step' => $size['step']]; $actual = $rows['body_font_size']; ksort($expected); ksort($actual); self::assertSame($expected, $actual); self::assertSame('Open Sans', $rows['body_font']['value']); } /** Ruling W3: an unset tablet size inherits the desktop size – as effective value and as its default. */ public function testUnsetSizesInheritTheLargerSize(): void { $tablet = self::byKey(self::ability()->execute([]))['tablet_body_font_size']; self::assertNull($tablet['value']); self::assertTrue($tablet['is_default']); self::assertSame(16, $tablet['effective']); self::assertSame(16, $tablet['default']); self::assertSame('body_font_size', $tablet['inherits']); } public function testChoicesAreListed(): void { $rows = self::byKey(self::ability()->execute([])); self::assertSame( ThemeOptionSpec::definition('body_header_style')['choices'], $rows['body_header_style']['choices'] ); self::assertArrayNotHasKey('choices', $rows['body_font']); } public function testKeysNarrowTheAnswerInTheFixedOrder(): void { $result = self::ability()->execute(['keys' => ['row_padding', 'body_font']]); self::assertSame(['body_font', 'row_padding'], array_column($result['options'], 'key')); } public function testUnknownKeysAreRefused(): void { $error = self::ability()->execute(['keys' => ['accent_color', 'body_font', 5]]); self::assertToolError($error, 'validation_failed'); self::assertSame(['keys[0]', 'keys[2]'], array_keys(self::errorFields($error))); self::assertToolError(self::ability()->execute(['keys' => 'body_font']), 'validation_failed'); } /** G3, A8: the main colors are not theme options here; the notes point to lit/divi-colors-set. */ public function testNotesPointToTheColorTool(): void { $notes = implode(' ', self::ability()->execute([])['notes']); self::assertStringContainsString('lit/divi-colors-set', $notes); self::assertStringContainsString('null', $notes); } }