11<?php namespace lang \ast \unittest \emit ;
22
3- use lang \IllegalArgumentException ;
3+ use lang \{ Reflection , IllegalArgumentException } ;
44use test \{Assert , Expect , Test , Values };
55
66/**
1111 */
1212abstract class AnnotationSupport extends EmittingTest {
1313
14+ /**
15+ * Declares annotations, optionally including a type
16+ *
17+ * @param string $declaration
18+ * @return lang.reflection.Type
19+ */
20+ private function declare ($ declaration ) {
21+ return Reflection::type ($ this ->type (
22+ $ declaration .(strstr ($ declaration , '<T> ' ) ? '' : ' class <T> { } ' )
23+ ));
24+ }
25+
26+ /**
27+ * Returns annotations present in the given type
28+ *
29+ * @param lang.reflection.Annotated $annotated
30+ * @return [:var[]]
31+ */
32+ private function annotations ($ annotated ) {
33+ $ r = [];
34+ foreach ($ annotated ->annotations () as $ name => $ annotation ) {
35+ $ r [$ name ]= $ annotation ->arguments ();
36+ }
37+ return $ r ;
38+ }
39+
1440 #[Test]
1541 public function without_value () {
16- $ t = $ this ->type ('#[Test] class <T> { } ' );
17- Assert::equals (['test ' => null ], $ t ->getAnnotations ());
42+ Assert::equals (
43+ ['Test ' => []],
44+ $ this ->annotations ($ this ->declare ('#[Test] ' ))
45+ );
1846 }
1947
2048 #[Test]
2149 public function within_namespace () {
22- $ t = $ this ->type ('namespace tests; #[Test] class <T> { } ' );
23- Assert::equals (['test ' => null ], $ t ->getAnnotations ());
50+ Assert::equals (
51+ ['tests \\Test ' => []],
52+ $ this ->annotations ($ this ->declare ('namespace tests; #[Test] ' ))
53+ );
2454 }
2555
2656 #[Test]
2757 public function resolved_against_import () {
28- $ t = $ this ->type ('use unittest\Test; #[Test] class <T> { } ' );
29- Assert::equals (['test ' => null ], $ t ->getAnnotations ());
58+ Assert::equals (
59+ ['unittest \\Test ' => []],
60+ $ this ->annotations ($ this ->declare ('use unittest\Test; #[Test] ' ))
61+ );
3062 }
3163
3264 #[Test]
3365 public function primitive_value () {
34- $ t = $ this ->type ('#[Author("Timm")] class <T> { } ' );
35- Assert::equals (['author ' => 'Timm ' ], $ t ->getAnnotations ());
66+ Assert::equals (
67+ ['Author ' => ['Timm ' ]],
68+ $ this ->annotations ($ this ->declare ('#[Author("Timm")] ' ))
69+ );
3670 }
3771
3872 #[Test]
3973 public function array_value () {
40- $ t = $ this ->type ('#[Authors(["Timm", "Alex"])] class <T> { } ' );
41- Assert::equals (['authors ' => ['Timm ' , 'Alex ' ]], $ t ->getAnnotations ());
74+ Assert::equals (
75+ ['Authors ' => [['Timm ' , 'Alex ' ]]],
76+ $ this ->annotations ($ this ->declare ('#[Authors(["Timm", "Alex"])] ' ))
77+ );
4278 }
4379
4480 #[Test]
4581 public function map_value () {
46- $ t = $ this ->type ('#[Expect(["class" => \lang\IllegalArgumentException::class])] class <T> { } ' );
47- Assert::equals (['expect ' => ['class ' => IllegalArgumentException::class]], $ t ->getAnnotations ());
82+ Assert::equals (
83+ ['Expect ' => [['class ' => IllegalArgumentException::class]]],
84+ $ this ->annotations ($ this ->declare ('#[Expect(["class" => \lang\IllegalArgumentException::class])] ' ))
85+ );
4886 }
4987
5088 #[Test]
5189 public function named_argument () {
52- $ t = $ this ->type ('#[Expect(class: \lang\IllegalArgumentException::class)] class <T> { } ' );
53- Assert::equals (['expect ' => ['class ' => IllegalArgumentException::class]], $ t ->getAnnotations ());
90+ Assert::equals (
91+ ['Expect ' => ['class ' => IllegalArgumentException::class]],
92+ $ this ->annotations ($ this ->declare ('#[Expect(class: \lang\IllegalArgumentException::class)] ' ))
93+ );
5494 }
5595
5696 #[Test]
5797 public function closure_value () {
58- $ t = $ this ->type ('#[Verify(function($arg) { return $arg; })] class <T> { } ' );
59- $ f = $ t ->getAnnotation ('verify ' );
60- Assert::equals ('test ' , $ f ('test ' ));
98+ $ verify = $ this ->annotations ($ this ->declare ('#[Verify(function($arg) { return $arg; })] ' ))['Verify ' ];
99+ Assert::equals ('test ' , $ verify [0 ]('test ' ));
61100 }
62101
63102 #[Test]
64103 public function arrow_function_value () {
65- $ t = $ this ->type ('#[Verify(fn($arg) => $arg)] class <T> { } ' );
66- $ f = $ t ->getAnnotation ('verify ' );
67- Assert::equals ('test ' , $ f ('test ' ));
104+ $ verify = $ this ->annotations ($ this ->declare ('#[Verify(fn($arg) => $arg)] ' ))['Verify ' ];
105+ Assert::equals ('test ' , $ verify [0 ]('test ' ));
68106 }
69107
70108 #[Test]
71109 public function array_of_arrow_function_value () {
72- $ t = $ this ->type ('#[Verify([fn($arg) => $arg])] class <T> { } ' );
73- $ f = $ t ->getAnnotation ('verify ' );
74- Assert::equals ('test ' , $ f [0 ]('test ' ));
110+ $ verify = $ this ->annotations ($ this ->declare ('#[Verify([fn($arg) => $arg])] ' ))['Verify ' ];
111+ Assert::equals ('test ' , $ verify [0 ][0 ]('test ' ));
75112 }
76113
77114 #[Test]
78115 public function named_arrow_function_value () {
79- $ t = $ this ->type ('#[Verify(func: fn($arg) => $arg)] class <T> { } ' );
80- $ f = $ t ->getAnnotation ('verify ' );
81- Assert::equals ('test ' , $ f ['func ' ]('test ' ));
116+ $ verify = $ this ->annotations ($ this ->declare ('#[Verify(func: fn($arg) => $arg)] ' ))['Verify ' ];
117+ Assert::equals ('test ' , $ verify ['func ' ]('test ' ));
82118 }
83119
84120 #[Test]
85121 public function single_quoted_string_inside_non_constant_expression () {
86- $ t = $ this ->type ('#[Verify(fn($arg) => \'php \\\\\'.$arg)] class <T> { } ' );
87- $ f = $ t ->getAnnotation ('verify ' );
88- Assert::equals ('php \\test ' , $ f ('test ' ));
122+ $ verify = $ this ->annotations ($ this ->declare ('#[Verify(fn($arg) => \'php \\\\\'.$arg)] ' ))['Verify ' ];
123+ Assert::equals ('php \\test ' , $ verify [0 ]('test ' ));
89124 }
90125
91126 #[Test]
92127 public function has_access_to_class () {
93- $ t = $ this ->type ('#[Expect(self::SUCCESS)] class <T> { const SUCCESS = true; } ' );
94- Assert::equals (['expect ' => true ], $ t ->getAnnotations ());
128+ Assert::equals (
129+ ['Expect ' => [true ]],
130+ $ this ->annotations ($ this ->declare ('#[Expect(self::SUCCESS)] class <T> { const SUCCESS = true; } ' ))
131+ );
95132 }
96133
97134 #[Test]
98135 public function method () {
99- $ t = $ this ->type ('class <T> { #[Test] public function fixture() { } } ' );
100- Assert::equals (['test ' => null ], $ t ->getMethod ('fixture ' )->getAnnotations ());
136+ $ t = $ this ->declare ('class <T> { #[Test] public function fixture() { } } ' );
137+ Assert::equals (
138+ ['Test ' => []],
139+ $ this ->annotations ($ t ->method ('fixture ' ))
140+ );
101141 }
102142
103143 #[Test]
104144 public function field () {
105- $ t = $ this ->type ('class <T> { #[Test] public $fixture; } ' );
106- Assert::equals (['test ' => null ], $ t ->getField ('fixture ' )->getAnnotations ());
145+ $ t = $ this ->declare ('class <T> { #[Test] public $fixture; } ' );
146+ Assert::equals (
147+ ['Test ' => []],
148+ $ this ->annotations ($ t ->property ('fixture ' ))
149+ );
107150 }
108151
109152 #[Test]
110153 public function param () {
111- $ t = $ this ->type ('class <T> { public function fixture(#[Test] $param) { } } ' );
112- Assert::equals (['test ' => null ], $ t ->getMethod ('fixture ' )->getParameter (0 )->getAnnotations ());
154+ $ t = $ this ->declare ('class <T> { public function fixture(#[Test] $param) { } } ' );
155+ Assert::equals (
156+ ['Test ' => []],
157+ $ this ->annotations ($ t ->method ('fixture ' )->parameter (0 ))
158+ );
113159 }
114160
115161 #[Test]
116162 public function params () {
117- $ t = $ this ->type ('class <T> { public function fixture(#[Inject(["name" => "a"])] $a, #[Inject] $b) { } } ' );
118- $ m = $ t ->getMethod ('fixture ' );
163+ $ t = $ this ->declare ('class <T> { public function fixture(#[Inject(["name" => "a"])] $a, #[Inject] $b) { } } ' );
119164 Assert::equals (
120- [['inject ' => ['name ' => 'a ' ]], ['inject ' => null ]],
121- [$ m ->getParameter (0 )->getAnnotations (), $ m ->getParameter (1 )->getAnnotations ()]
165+ ['Inject ' => [['name ' => 'a ' ]]],
166+ $ this ->annotations ($ t ->method ('fixture ' )->parameter (0 ))
167+ );
168+ Assert::equals (
169+ ['Inject ' => []],
170+ $ this ->annotations ($ t ->method ('fixture ' )->parameter (1 ))
122171 );
123172 }
124173
125174 #[Test]
126175 public function multiple_class_annotations () {
127- $ t = $ this ->type ('#[Resource("/"), Authenticated] class <T> { } ' );
128- Assert::equals (['resource ' => '/ ' , 'authenticated ' => null ], $ t ->getAnnotations ());
176+ Assert::equals (
177+ ['Resource ' => ['/ ' ], 'Authenticated ' => []],
178+ $ this ->annotations ($ this ->declare ('#[Resource("/"), Authenticated] ' ))
179+ );
129180 }
130181
131182 #[Test]
132183 public function multiple_member_annotations () {
133- $ t = $ this ->type ('class <T> { #[Test, Values([1, 2, 3])] public function fixture() { } } ' );
134- Assert::equals (['test ' => null , 'values ' => [1 , 2 , 3 ]], $ t ->getMethod ('fixture ' )->getAnnotations ());
184+ $ t = $ this ->declare ('class <T> { #[Test, Values([1, 2, 3])] public function fixture() { } } ' );
185+ Assert::equals (
186+ ['Test ' => [], 'Values ' => [[1 , 2 , 3 ]]],
187+ $ this ->annotations ($ t ->method ('fixture ' ))
188+ );
135189 }
136190
137191 #[Test]
138192 public function multiline_annotations () {
139- $ t = $ this ->type ('
193+ $ annotations = $ this ->annotations ( $ this -> declare ('
140194 #[Authors([
141195 "Timm",
142196 "Mr. Midori",
143197 ])]
144198 class <T> { } '
145- );
146- Assert::equals (['authors ' => ['Timm ' , 'Mr. Midori ' ]], $ t -> getAnnotations () );
199+ )) ;
200+ Assert::equals (['Authors ' => [[ 'Timm ' , 'Mr. Midori ' ]]] , $ annotations );
147201 }
148202}
0 commit comments