33use App \Exceptions \BadRequestException ;
44use App \Exceptions \InternalServerException ;
55use App \Exceptions \InvalidApiArgumentException ;
6+ use App \Helpers \MetaFormats \Attributes \Format ;
67use App \Helpers \MetaFormats \Attributes \FPath ;
78use App \Helpers \MetaFormats \Attributes \FPost ;
89use App \Helpers \MetaFormats \Attributes \FQuery ;
@@ -61,6 +62,33 @@ class ValidationTestFormat extends MetaFormat
6162 }
6263}
6364
65+ #[Format(ParentFormat::class)]
66+ class ParentFormat extends MetaFormat
67+ {
68+ #[FQuery(new VInt (), required: true , nullable: false )]
69+ public ?int $ field ;
70+
71+ #[FPost(new VObject (NestedFormat::class), required: true , nullable: false )]
72+ public NestedFormat $ nested ;
73+
74+ public function validateStructure ()
75+ {
76+ return $ this ->field == 1 ;
77+ }
78+ }
79+
80+ #[Format(NestedFormat::class)]
81+ class NestedFormat extends MetaFormat
82+ {
83+ #[FQuery(new VInt (), required: true , nullable: false )]
84+ public ?int $ field ;
85+
86+ public function validateStructure ()
87+ {
88+ return $ this ->field == 2 ;
89+ }
90+ }
91+
6492/**
6593 * @testCase
6694 */
@@ -75,7 +103,7 @@ class TestFormats extends Tester\TestCase
75103 $ this ->container = $ container ;
76104 }
77105
78- private function injectFormat (string $ format )
106+ private static function injectFormat (string $ format )
79107 {
80108 // initialize the cache
81109 FormatCache::getFormatToFieldDefinitionsMap ();
@@ -227,6 +255,7 @@ class TestFormats extends Tester\TestCase
227255 // assign valid values to all fields, but fail the structural constraint of $query == 1
228256 $ format ->checkedAssign ("path " , 1 );
229257 $ format ->checkedAssign ("query " , 2 );
258+ Assert::false ($ format ->validateStructure ());
230259 Assert::throws (
231260 function () use ($ format ) {
232261 try {
@@ -240,7 +269,47 @@ class TestFormats extends Tester\TestCase
240269 );
241270 }
242271
243- ///TODO: nested formats, loose format
272+ public function testNestedFormat ()
273+ {
274+ self ::injectFormat (NestedFormat::class);
275+ self ::injectFormat (ParentFormat::class);
276+ $ nested = new NestedFormat ();
277+ $ parent = new ParentFormat ();
278+
279+ // assign valid values that do not pass structural validation
280+ // (both fields need to be 1 to pass)
281+ $ nested ->checkedAssign ("field " , 0 );
282+ $ parent ->checkedAssign ("field " , 0 );
283+ $ parent ->checkedAssign ("nested " , $ nested );
284+
285+ Assert::false ($ nested ->validateStructure ());
286+ Assert::false ($ parent ->validateStructure ());
287+
288+ Assert::throws (
289+ function () use ($ nested ) {
290+ $ nested ->validate ();
291+ },
292+ BadRequestException::class
293+ );
294+ Assert::throws (
295+ function () use ($ parent ) {
296+ $ parent ->validate ();
297+ },
298+ BadRequestException::class
299+ );
300+
301+ // fix the structural constain in the parent
302+ $ parent ->checkedAssign ("field " , 1 );
303+ Assert::true ($ parent ->validateStructure ());
304+
305+ // make sure that the structural error in the nested format propagates to the parent
306+ Assert::throws (
307+ function () use ($ parent ) {
308+ $ parent ->validate ();
309+ },
310+ BadRequestException::class
311+ );
312+ }
244313}
245314
246315(new TestFormats ())->run ();
0 commit comments