View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.html;
18  
19  import static org.apache.juneau.commons.utils.CollectionUtils.*;
20  import static org.apache.juneau.commons.utils.Utils.*;
21  import static org.apache.juneau.junit.bct.BctAssertions.*;
22  import static org.junit.jupiter.api.Assertions.*;
23  
24  import java.util.*;
25  import java.util.function.*;
26  import java.util.stream.*;
27  
28  import org.apache.juneau.*;
29  import org.apache.juneau.commons.reflect.*;
30  import org.apache.juneau.html.annotation.*;
31  import org.apache.juneau.svl.*;
32  import org.junit.jupiter.api.*;
33  
34  /**
35   * Tests the @HtmlDocConfig annotation.
36   */
37  class HtmlDocConfigAnnotation_Test extends TestBase {
38  
39  	private static void check(String expected, Object o) {
40  		assertEquals(expected, TO_STRING.apply(o));
41  	}
42  
43  	private static final Function<Object,String> TO_STRING = t -> {
44  		if (isArray(t))
45  			return HtmlDocConfigAnnotation_Test.TO_STRING.apply(toList(t, Object.class));
46  		if (t instanceof Collection)
47  			return ((Collection<?>)t)
48  				.stream()
49  				.map(HtmlDocConfigAnnotation_Test.TO_STRING)
50  				.collect(Collectors.joining(","));
51  		if (t instanceof HtmlDocTemplate)
52  			return t.getClass().getSimpleName();
53  		return t.toString();
54  	};
55  
56  	static VarResolverSession sr = VarResolver.create().vars(XVar.class).build().createSession();
57  
58  	//-----------------------------------------------------------------------------------------------------------------
59  	// Basic tests
60  	//-----------------------------------------------------------------------------------------------------------------
61  
62  	@HtmlDocConfig(
63  		aside="$X{foo}",
64  		footer="$X{foo}",
65  		head="$X{foo}",
66  		header="$X{foo}",
67  		nav="$X{foo}",
68  		navlinks="$X{foo1}",
69  		noResultsMessage="$X{foo}",
70  		nowrap="$X{true}",
71  		script="$X{foo1}",
72  		style="$X{foo1}",
73  		stylesheet="$X{foo1}",
74  		template=BasicHtmlDocTemplate.class
75  	)
76  	static class A {}
77  	static ClassInfo a = ClassInfo.of(A.class);
78  
79  	@Test void basic() {
80  		var al = AnnotationWorkList.of(sr, rstream(a.getAnnotations()));
81  		var x = HtmlDocSerializer.create().apply(al).build().getSession();
82  		check("foo", x.getAside());
83  		check("foo", x.getFooter());
84  		check("foo", x.getHead());
85  		check("foo", x.getHeader());
86  		check("foo", x.getNav());
87  		check("foo1", x.getNavlinks());
88  		check("foo", x.getNoResultsMessage());
89  		check("true", x.isNowrap());
90  		check("foo1", x.getScript());
91  		check("foo1", x.getStyle());
92  		check("foo1", x.getStylesheet());
93  		check("BasicHtmlDocTemplate", x.getTemplate());
94  	}
95  
96  	//-----------------------------------------------------------------------------------------------------------------
97  	// Annotation with no values.
98  	//-----------------------------------------------------------------------------------------------------------------
99  
100 	@HtmlDocConfig()
101 	static class B {}
102 	static ClassInfo b = ClassInfo.of(B.class);
103 
104 	@Test void defaults() {
105 		var al = AnnotationWorkList.of(sr, rstream(b.getAnnotations()));
106 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
107 		check("", x.getAside());
108 		check("", x.getFooter());
109 		check("", x.getHead());
110 		check("", x.getHeader());
111 		check("", x.getNav());
112 		check("", x.getNavlinks());
113 		check("<p>no results</p>", x.getNoResultsMessage());
114 		check("false", x.isNowrap());
115 		check("", x.getScript());
116 		check("", x.getStyle());
117 		check("", x.getStylesheet());
118 		check("BasicHtmlDocTemplate", x.getTemplate());
119 	}
120 
121 	//-----------------------------------------------------------------------------------------------------------------
122 	// No annotation.
123 	//-----------------------------------------------------------------------------------------------------------------
124 
125 	static class C {}
126 	static ClassInfo c = ClassInfo.of(C.class);
127 
128 	@Test void noAnnotation() {
129 		var al = AnnotationWorkList.of(sr, rstream(c.getAnnotations()));
130 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
131 		check("", x.getAside());
132 		check("", x.getFooter());
133 		check("", x.getHead());
134 		check("", x.getHeader());
135 		check("", x.getNav());
136 		check("", x.getNavlinks());
137 		check("<p>no results</p>", x.getNoResultsMessage());
138 		check("false", x.isNowrap());
139 		check("", x.getScript());
140 		check("", x.getStyle());
141 		check("", x.getStylesheet());
142 		check("BasicHtmlDocTemplate", x.getTemplate());
143 	}
144 
145 	//-----------------------------------------------------------------------------------------------------------------
146 	// Inheritance tests
147 	//-----------------------------------------------------------------------------------------------------------------
148 
149 	@HtmlDocConfig(
150 		aside={"$X{foo2}","$X{INHERIT}"},
151 		footer={"$X{foo2}","$X{INHERIT}"},
152 		head={"$X{foo2}","$X{INHERIT}"},
153 		header={"$X{foo2}","$X{INHERIT}"},
154 		nav={"$X{foo2}","$X{INHERIT}"},
155 		navlinks={"$X{foo2}","$X{INHERIT}"},
156 		script={"$X{foo2}","$X{INHERIT}"},
157 		style={"$X{foo2}","$X{INHERIT}"},
158 		stylesheet={"$X{foo2}","$X{INHERIT}"}
159 	)
160 	static class D1 extends A {}
161 	static ClassInfo d1 = ClassInfo.of(D1.class);
162 
163 	@Test void inheritance1() {
164 		var al = AnnotationWorkList.of(sr, rstream(d1.getAnnotations()));
165 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
166 		check("foo2,foo", x.getAside());
167 		check("foo2,foo", x.getFooter());
168 		check("foo2,foo", x.getHead());
169 		check("foo2,foo", x.getHeader());
170 		check("foo2,foo", x.getNav());
171 		check("foo2,foo1", x.getNavlinks());
172 		check("foo2,foo1", x.getScript());
173 		check("foo2,foo1", x.getStyle());
174 		check("foo2,foo1", x.getStylesheet());
175 	}
176 
177 	@HtmlDocConfig(
178 		aside={"$X{INHERIT}","$X{foo2}"},
179 		footer={"$X{INHERIT}","$X{foo2}"},
180 		head={"$X{INHERIT}","$X{foo2}"},
181 		header={"$X{INHERIT}","$X{foo2}"},
182 		nav={"$X{INHERIT}","$X{foo2}"},
183 		navlinks={"$X{INHERIT}","$X{foo2}"},
184 		script={"$X{INHERIT}","$X{foo2}"},
185 		style={"$X{INHERIT}","$X{foo2}"},
186 		stylesheet={"$X{INHERIT}","$X{foo2}"}
187 	)
188 	static class D2 extends A {}
189 	static ClassInfo d2 = ClassInfo.of(D2.class);
190 
191 	@Test void inheritance2() {
192 		var al = AnnotationWorkList.of(sr, rstream(d2.getAnnotations()));
193 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
194 		check("foo,foo2", x.getAside());
195 		check("foo,foo2", x.getFooter());
196 		check("foo,foo2", x.getHead());
197 		check("foo,foo2", x.getHeader());
198 		check("foo,foo2", x.getNav());
199 		check("foo1,foo2", x.getNavlinks());
200 		check("foo1,foo2", x.getScript());
201 		check("foo1,foo2", x.getStyle());
202 		check("foo1,foo2", x.getStylesheet());
203 	}
204 
205 	@HtmlDocConfig(
206 		aside={"$X{foo2}"},
207 		footer={"$X{foo2}"},
208 		head={"$X{foo2}"},
209 		header={"$X{foo2}"},
210 		nav={"$X{foo2}"},
211 		navlinks={"$X{foo2}"},
212 		script={"$X{foo2}"},
213 		style={"$X{foo2}"},
214 		stylesheet={"$X{foo2}"}
215 	)
216 	static class D3 extends A {}
217 	static ClassInfo d3 = ClassInfo.of(D3.class);
218 
219 	@Test void inheritance3() {
220 		var al = AnnotationWorkList.of(sr, rstream(d3.getAnnotations()));
221 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
222 		check("foo2", x.getAside());
223 		check("foo2", x.getFooter());
224 		check("foo2", x.getHead());
225 		check("foo2", x.getHeader());
226 		check("foo2", x.getNav());
227 		check("foo2", x.getNavlinks());
228 		check("foo2", x.getScript());
229 		check("foo2", x.getStyle());
230 		check("foo2", x.getStylesheet());
231 	}
232 
233 	@HtmlDocConfig(
234 		aside={"NONE"},
235 		footer={"NONE"},
236 		head={"NONE"},
237 		header={"NONE"},
238 		nav={"NONE"},
239 		navlinks={"NONE"},
240 		script={"NONE"},
241 		style={"NONE"},
242 		stylesheet={"NONE"}
243 	)
244 	static class D4 extends A {}
245 	static ClassInfo d4 = ClassInfo.of(D4.class);
246 
247 	@Test void inheritance4() {
248 		var al = AnnotationWorkList.of(sr, rstream(d4.getAnnotations()));
249 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
250 		check("", x.getAside());
251 		check("", x.getFooter());
252 		check("", x.getHead());
253 		check("", x.getHeader());
254 		check("", x.getNav());
255 		check("", x.getNavlinks());
256 		check("", x.getScript());
257 		check("", x.getStyle());
258 		check("", x.getStylesheet());
259 	}
260 
261 	//-----------------------------------------------------------------------------------------------------------------
262 	// Widgets
263 	//-----------------------------------------------------------------------------------------------------------------
264 
265 	@HtmlDocConfig(
266 		aside="$W{E}",
267 		footer="$W{E}",
268 		head="$W{E}",
269 		header="$W{E}",
270 		nav="$W{E}",
271 		navlinks="$W{E}",
272 		noResultsMessage="$W{E}",
273 		nowrap="$W{E}",
274 		script="$W{E}",
275 		style="$W{E}",
276 		stylesheet="$W{E}",
277 		widgets=EWidget.class
278 	)
279 	static class E {}
280 	static ClassInfo e = ClassInfo.of(E.class);
281 
282 	public static class EWidget implements HtmlWidget {
283 		@Override
284 		public String getName() {
285 			return "E";
286 		}
287 		@Override
288 		public String getHtml(VarResolverSession session) {
289 			return "xxx";
290 		}
291 		@Override
292 		public String getScript(VarResolverSession session) {
293 			return "yyy";
294 		}
295 		@Override
296 		public String getStyle(VarResolverSession session) {
297 			return "zzz";
298 		}
299 	}
300 
301 	@Test void widgets_basic() {
302 		var al = AnnotationWorkList.of(sr, rstream(e.getAnnotations()));
303 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
304 		check("$W{E}", x.getAside());
305 		check("$W{E}", x.getFooter());
306 		check("$W{E}", x.getHead());
307 		check("$W{E}", x.getHeader());
308 		check("$W{E}", x.getNav());
309 		check("$W{E}", x.getNavlinks());
310 		check("$W{E}", x.getNoResultsMessage());
311 		check("false", x.isNowrap());
312 		check("$W{E}", x.getScript());
313 		check("$W{E}", x.getStyle());
314 		check("$W{E}", x.getStylesheet());
315 		check("BasicHtmlDocTemplate", x.getTemplate());
316 	}
317 
318 	@Test void widgets_resolution() throws Exception {
319 		var al = AnnotationWorkList.of(sr, rstream(e.getAnnotations()));
320 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
321 		var r = x.serialize(null).replaceAll("[\r\n]+", "|");
322 		assertContainsAll(r, "<aside>xxx</aside>","<footer>xxx</footer>","<head>xxx","<style>@import \"xxx\"; xxx zzz</style>","<nav><ol><li>xxx</li></ol>xxx</nav>","<script>xxx| yyy|</script>");
323 	}
324 
325 	//-----------------------------------------------------------------------------------------------------------------
326 	// Rank sorting
327 	//-----------------------------------------------------------------------------------------------------------------
328 
329 	@HtmlDocConfig(
330 		rank=1,
331 		aside="f1"
332 	)
333 	static class F1 {}
334 
335 	@HtmlDocConfig(
336 		aside="f2"
337 	)
338 	static class F2 extends F1 {}
339 
340 	@HtmlDocConfig(
341 		rank=3,
342 		aside="f3"
343 	)
344 	static class F3 extends F2 {}
345 
346 	@HtmlDocConfig(
347 		rank=2,
348 		aside="f4"
349 	)
350 	static class F4 extends F3 {}
351 
352 	@HtmlDocConfig(
353 		rank=3,
354 		aside="f5"
355 	)
356 	static class F5 extends F4 {}
357 
358 	static ClassInfo f1 = ClassInfo.of(F1.class);
359 	static ClassInfo f2 = ClassInfo.of(F2.class);
360 	static ClassInfo f3 = ClassInfo.of(F3.class);
361 	static ClassInfo f4 = ClassInfo.of(F4.class);
362 	static ClassInfo f5 = ClassInfo.of(F5.class);
363 
364 	@Test void e01_rankedAnnotations_f1() {
365 		var al = AnnotationWorkList.of(sr, rstream(f1.getAnnotations()));
366 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
367 		check("f1", x.getAside());
368 	}
369 
370 	@Test void e02_rankedAnnotations_f2() {
371 		var al = AnnotationWorkList.of(sr, rstream(f2.getAnnotations()));
372 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
373 		check("f1", x.getAside());
374 	}
375 
376 	@Test void e03_rankedAnnotations_f3() {
377 		var al = AnnotationWorkList.of(sr, rstream(f3.getAnnotations()));
378 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
379 		check("f3", x.getAside());
380 	}
381 
382 	@Test void e04_rankedAnnotations_f4() {
383 		var al = AnnotationWorkList.of(sr, rstream(f4.getAnnotations()));
384 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
385 		check("f3", x.getAside());
386 	}
387 
388 	@Test void e05_rankedAnnotations_f5() {
389 		var al = AnnotationWorkList.of(sr, rstream(f5.getAnnotations()));
390 		var x = HtmlDocSerializer.create().apply(al).build().getSession();
391 		check("f5", x.getAside());
392 	}
393 }