1414use Tests \Utils \ModelsSecondary \OnlyHere ;
1515
1616/**
17- * This class does test the internal behaviour of the BaseDirective class.
17+ * This class does test the internal behavior of the BaseDirective class.
1818 *
1919 * While typically considered an anti-pattern, the BaseDirective is meant
2020 * to be extended by other directives and offers basic utilities that
2121 * are commonly used in directives. As users may also extend it to create
22- * custom directives, its behaviour should be stable and well-defined.
22+ * custom directives, its behavior should be stable and well-defined.
2323 */
2424final class BaseDirectiveTest extends TestCase
2525{
2626 public function testGetsModelClassFromDirective (): void
2727 {
28- $ this ->schema .= /** @lang GraphQL */ '
29- type User @model(class: "Team") {
30- id: ID
31- }
32- ' ;
28+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
29+ type User @model(class: "Team") {
30+ id: ID
31+ }
32+ GRAPHQL ;
3333
3434 $ directive = $ this ->constructFieldDirective ('foo: User @dummy ' );
3535
@@ -39,13 +39,13 @@ public function testGetsModelClassFromDirective(): void
3939 );
4040 }
4141
42- public function testDefaultsToFieldTypeForTheModelClass (): void
42+ public function testDefaultsToFieldTypeForTheModelClassIfObject (): void
4343 {
44- $ this ->schema .= /** @lang GraphQL */ '
45- type User {
46- id: ID
47- }
48- ' ;
44+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
45+ type User {
46+ id: ID
47+ }
48+ GRAPHQL ;
4949
5050 $ directive = $ this ->constructFieldDirective ('foo: User @dummy ' );
5151
@@ -55,6 +55,56 @@ public function testDefaultsToFieldTypeForTheModelClass(): void
5555 );
5656 }
5757
58+ public function testDefaultsToFieldTypeForTheModelClassIfInterface (): void
59+ {
60+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL'
61+ interface User {
62+ id: ID
63+ }
64+ GRAPHQL;
65+
66+ $ directive = $ this ->constructFieldDirective ('foo: User @dummy ' );
67+
68+ $ this ->assertSame (
69+ User::class,
70+ $ directive ->getModelClass (),
71+ );
72+ }
73+
74+ public function testDefaultsToFieldTypeForTheModelClassIfUnion (): void
75+ {
76+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL'
77+ union User = Admin | Member
78+
79+ type Admin {
80+ id: ID
81+ }
82+
83+ type Member {
84+ id: ID
85+ }
86+ GRAPHQL;
87+
88+ $ directive = $ this ->constructFieldDirective ('foo: User @dummy ' );
89+
90+ $ this ->assertSame (
91+ User::class,
92+ $ directive ->getModelClass (),
93+ );
94+ }
95+
96+ public function testDoesntDefaultToFieldTypeForTheModelClassIfScalar (): void
97+ {
98+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL'
99+ scalar User
100+ GRAPHQL;
101+
102+ $ directive = $ this ->constructFieldDirective ('foo: User @dummy ' );
103+
104+ $ this ->expectException (DefinitionException::class);
105+ $ directive ->getModelClass ();
106+ }
107+
58108 public function testThrowsIfTheClassIsNotInTheSchema (): void
59109 {
60110 $ directive = $ this ->constructFieldDirective ('foo: UnknownType @dummy ' );
@@ -75,11 +125,11 @@ public function testBuiltInTypeTolerated(): void
75125
76126 public function testThrowsIfTheClassIsNotAModel (): void
77127 {
78- $ this ->schema .= /** @lang GraphQL */ '
79- type Exception {
80- id: ID
81- }
82- ' ;
128+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
129+ type Exception {
130+ id: ID
131+ }
132+ GRAPHQL ;
83133
84134 $ directive = $ this ->constructFieldDirective ('foo: Exception @dummy ' );
85135
@@ -89,11 +139,11 @@ public function testThrowsIfTheClassIsNotAModel(): void
89139
90140 public function testResolvesAModelThatIsNamedLikeABaseClass (): void
91141 {
92- $ this ->schema .= /** @lang GraphQL */ '
93- type Closure {
94- id: ID
95- }
96- ' ;
142+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
143+ type Closure {
144+ id: ID
145+ }
146+ GRAPHQL ;
97147
98148 $ directive = $ this ->constructFieldDirective ('foo: Closure @dummy ' );
99149
@@ -105,11 +155,11 @@ public function testResolvesAModelThatIsNamedLikeABaseClass(): void
105155
106156 public function testPrefersThePrimaryModelNamespace (): void
107157 {
108- $ this ->schema .= /** @lang GraphQL */ '
109- type Category {
110- id: ID
111- }
112- ' ;
158+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
159+ type Category {
160+ id: ID
161+ }
162+ GRAPHQL ;
113163
114164 $ directive = $ this ->constructFieldDirective ('foo: Category @dummy ' );
115165
@@ -121,11 +171,11 @@ public function testPrefersThePrimaryModelNamespace(): void
121171
122172 public function testAllowsOverwritingTheDefaultModel (): void
123173 {
124- $ this ->schema .= /** @lang GraphQL */ '
125- type OnlyHere {
126- id: ID
127- }
128- ' ;
174+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
175+ type OnlyHere {
176+ id: ID
177+ }
178+ GRAPHQL ;
129179
130180 $ directive = $ this ->constructFieldDirective ('foo: OnlyHere @dummy(model: "Tests \\\Utils \\\ModelsSecondary \\\Category") ' );
131181
@@ -137,11 +187,11 @@ public function testAllowsOverwritingTheDefaultModel(): void
137187
138188 public function testResolvesFromTheSecondaryModelNamespace (): void
139189 {
140- $ this ->schema .= /** @lang GraphQL */ '
141- type OnlyHere {
142- id: ID
143- }
144- ' ;
190+ $ this ->schema .= /** @lang GraphQL */ <<<'GRAPHQL '
191+ type OnlyHere {
192+ id: ID
193+ }
194+ GRAPHQL ;
145195
146196 $ directive = $ this ->constructFieldDirective ('foo: OnlyHere @dummy ' );
147197
@@ -188,24 +238,48 @@ public function testMutuallyExclusive(): void
188238 $ directive ->validateMutuallyExclusiveArguments (['bar ' , 'baz ' , 'qux ' ]);
189239 }
190240
191- protected function constructFieldDirective (string $ definition ): BaseDirective
241+ public function testHydrateShouldResetCachedArgs (): void
242+ {
243+ $ directive = $ this ->constructFieldDirective ('foo: ID @dummy(arg: "value") ' );
244+
245+ $ this ->assertSame (
246+ 'value ' ,
247+ // @phpstan-ignore-next-line protected method is called via wrapper below
248+ $ directive ->directiveArgValue ('arg ' ),
249+ );
250+
251+ $ field = Parser::fieldDefinition ('foo: ID @dummy(arg: "new value") ' );
252+
253+ $ directive ->hydrate (
254+ $ field ->directives ->get (0 ),
255+ $ field ,
256+ );
257+
258+ $ this ->assertSame (
259+ 'new value ' ,
260+ // @phpstan-ignore-next-line protected method is called via wrapper below
261+ $ directive ->directiveArgValue ('arg ' ),
262+ );
263+ }
264+
265+ private function constructFieldDirective (string $ definition ): BaseDirective
192266 {
193267 $ fieldDefinition = Parser::fieldDefinition ($ definition );
194268
195269 $ directive = new class () extends BaseDirective {
196270 public static function definition (): string
197271 {
198- return /** @lang GraphQL */ 'directive @base on FIELD_DEFINITION ' ;
272+ return /** @lang GraphQL */ <<<'GRAPHQL'
273+ directive @base on FIELD_DEFINITION
274+ GRAPHQL;
199275 }
200276
201277 /**
202278 * Allows calling protected methods from the test.
203279 *
204280 * @param array<mixed> $args
205- *
206- * @return mixed whatever the method returns
207281 */
208- public function __call (string $ method , array $ args )
282+ public function __call (string $ method , array $ args ): mixed
209283 {
210284 return $ this ->{$ method }(...$ args );
211285 }
0 commit comments