001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.internal.bindings;
016:
017: import org.apache.tapestry.Binding;
018: import org.apache.tapestry.ComponentResources;
019: import org.apache.tapestry.beaneditor.Order;
020: import org.apache.tapestry.internal.test.InternalBaseTestCase;
021: import org.apache.tapestry.internal.util.IntegerRange;
022: import org.apache.tapestry.ioc.Location;
023: import org.apache.tapestry.ioc.internal.util.InternalUtils;
024: import org.apache.tapestry.ioc.internal.util.TapestryException;
025: import org.apache.tapestry.runtime.Component;
026: import org.apache.tapestry.services.BindingFactory;
027: import org.testng.annotations.AfterClass;
028: import org.testng.annotations.BeforeClass;
029: import org.testng.annotations.DataProvider;
030: import org.testng.annotations.Test;
031:
032: public class PropBindingFactoryTest extends InternalBaseTestCase {
033: private BindingFactory _factory;
034:
035: @BeforeClass
036: public void setup_factory() {
037: _factory = getService("PropBindingFactory",
038: BindingFactory.class);
039: }
040:
041: @AfterClass
042: public void cleanup_factory() {
043: _factory = null;
044: }
045:
046: private ComponentResources newComponentResources(Component component) {
047: ComponentResources resources = mockComponentResources();
048: train_getComponent(resources, component);
049:
050: train_getCompleteId(resources, "foo.Bar:baz");
051:
052: return resources;
053: }
054:
055: @Test
056: public void object_property() {
057: TargetBean bean = new TargetBean();
058: ComponentResources resources = newComponentResources(bean);
059: Location l = mockLocation();
060:
061: replay();
062:
063: Binding binding = _factory.newBinding("test binding",
064: resources, null, "objectValue", l);
065:
066: assertSame(binding.getBindingType(), String.class);
067:
068: bean.setObjectValue("first");
069:
070: assertEquals(binding.get(), "first");
071:
072: binding.set("second");
073:
074: assertEquals(bean.getObjectValue(), "second");
075: assertEquals(InternalUtils.locationOf(binding), l);
076:
077: assertEquals(binding.toString(),
078: "PropBinding[test binding foo.Bar:baz(objectValue)]");
079:
080: verify();
081: }
082:
083: @Test
084: public void annotation_from_read_only_property() {
085: TargetBean bean = new TargetBean();
086: ComponentResources resources = newComponentResources(bean);
087: Location l = mockLocation();
088:
089: replay();
090:
091: Binding binding = _factory.newBinding("test binding",
092: resources, null, "readOnly", l);
093:
094: assertEquals(binding.getAnnotation(Order.class).value(), 100);
095:
096: verify();
097: }
098:
099: @Test
100: public void annotation_from_write_only_property() {
101: TargetBean bean = new TargetBean();
102: ComponentResources resources = newComponentResources(bean);
103: Location l = mockLocation();
104:
105: replay();
106:
107: Binding binding = _factory.newBinding("test binding",
108: resources, null, "writeOnly", l);
109:
110: assertEquals(binding.getAnnotation(Order.class).value(), 200);
111:
112: verify();
113: }
114:
115: @Test
116: public void annotation_does_not_exist() {
117: TargetBean bean = new TargetBean();
118: ComponentResources resources = newComponentResources(bean);
119: Location l = mockLocation();
120:
121: replay();
122:
123: Binding binding = _factory.newBinding("test binding",
124: resources, null, "intValue", l);
125:
126: assertNull(binding.getAnnotation(Order.class));
127:
128: verify();
129: }
130:
131: @Test
132: public void annotation_on_named_method() {
133: TargetBean bean = new TargetBean();
134: ComponentResources resources = newComponentResources(bean);
135: Location l = mockLocation();
136:
137: replay();
138:
139: Binding binding = _factory.newBinding("test binding",
140: resources, null, "stringHolderMethod()", l);
141:
142: assertEquals(binding.getAnnotation(Order.class).value(), 300);
143:
144: verify();
145: }
146:
147: @Test
148: public void annnotation_on_read_method_takes_precedence_over_write_method() {
149: TargetBean bean = new TargetBean();
150: ComponentResources resources = newComponentResources(bean);
151: Location l = mockLocation();
152:
153: replay();
154:
155: Binding binding = _factory.newBinding("test binding",
156: resources, null, "objectValue", l);
157:
158: assertEquals(binding.getAnnotation(Order.class).value(), 1000);
159:
160: verify();
161: }
162:
163: @Test
164: public void property_path() {
165: TargetBean bean = new TargetBean();
166: ComponentResources resources = newComponentResources(bean);
167: Location l = mockLocation();
168:
169: replay();
170:
171: Binding binding = _factory.newBinding("test binding",
172: resources, null, "stringHolder.value", l);
173:
174: assertSame(binding.getBindingType(), String.class);
175:
176: bean.getStringHolder().setValue("first");
177:
178: assertEquals(binding.get(), "first");
179:
180: binding.set("second");
181:
182: assertEquals(bean.getStringHolder().getValue(), "second");
183:
184: assertEquals(binding.toString(),
185: "PropBinding[test binding foo.Bar:baz(stringHolder.value)]");
186:
187: verify();
188: }
189:
190: /** The "preamble" are the non-terminal property or method names. */
191: @Test
192: public void property_path_with_explicit_method_in_preamble() {
193: TargetBean bean = new TargetBean();
194: ComponentResources resources = newComponentResources(bean);
195: Location l = mockLocation();
196:
197: replay();
198:
199: Binding binding = _factory.newBinding("test binding",
200: resources, null, "stringHolderMethod().value", l);
201:
202: assertSame(binding.getBindingType(), String.class);
203:
204: bean.getStringHolder().setValue("first");
205:
206: assertEquals(binding.get(), "first");
207:
208: assertEquals(binding.toString(),
209: "PropBinding[test binding foo.Bar:baz(stringHolderMethod().value)]");
210:
211: verify();
212: }
213:
214: @Test
215: public void method_call_as_terminal() {
216: TargetBean bean = new TargetBean();
217: ComponentResources resources = newComponentResources(bean);
218: Location l = mockLocation();
219:
220: replay();
221:
222: Binding binding = _factory.newBinding("test binding",
223: resources, null, "stringHolderMethod().stringValue()",
224: l);
225:
226: assertSame(binding.getBindingType(), String.class);
227:
228: bean.getStringHolder().setValue("first");
229:
230: assertEquals(binding.get(), "first");
231:
232: try {
233: binding.set("read-only");
234: unreachable();
235: } catch (TapestryException ex) {
236: assertEquals(
237: ex.getMessage(),
238: "Expression stringHolderMethod().stringValue() for class org.apache.tapestry.internal.bindings.TargetBean is read-only.");
239: assertSame(ex.getLocation(), l);
240: }
241:
242: verify();
243:
244: }
245:
246: @Test
247: public void method_not_found_in_preamble() {
248: TargetBean bean = new TargetBean();
249: ComponentResources resources = mockComponentResources();
250: Location l = mockLocation();
251:
252: train_getComponent(resources, bean);
253:
254: replay();
255:
256: try {
257: _factory.newBinding("test binding", resources, null,
258: "isThatRealBlood().value", l);
259: unreachable();
260: } catch (RuntimeException ex) {
261: assertEquals(
262: ex.getMessage(),
263: "No public method \'isThatRealBlood()\' in class org.apache.tapestry.internal.bindings.TargetBean (within property expression \'isThatRealBlood().value\').");
264: }
265:
266: verify();
267: }
268:
269: @Test
270: public void method_not_found_in_terminal() {
271: TargetBean bean = new TargetBean();
272: ComponentResources resources = mockComponentResources();
273: Location l = mockLocation();
274:
275: train_getComponent(resources, bean);
276:
277: replay();
278:
279: try {
280: _factory.newBinding("test binding", resources, null,
281: "stringHolder.isThatRealBlood()", l);
282: unreachable();
283: } catch (RuntimeException ex) {
284: assertEquals(
285: ex.getMessage(),
286: "No public method \'isThatRealBlood()\' in class org.apache.tapestry.internal.bindings.StringHolder (within property expression \'stringHolder.isThatRealBlood()\').");
287: }
288:
289: verify();
290: }
291:
292: @Test
293: public void void_method_in_preamble() {
294: TargetBean bean = new TargetBean();
295: ComponentResources resources = mockComponentResources();
296: Location l = mockLocation();
297:
298: train_getComponent(resources, bean);
299:
300: replay();
301:
302: try {
303: _factory.newBinding("test binding", resources, null,
304: "voidMethod().value", l);
305: unreachable();
306: } catch (RuntimeException ex) {
307: assertEquals(
308: ex.getMessage(),
309: "Method \'voidMethod()\' returns void (in class org.apache.tapestry.internal.bindings.TargetBean, within property expression \'voidMethod().value\').");
310: }
311:
312: verify();
313: }
314:
315: @Test
316: public void void_method_as_terminal() {
317: TargetBean bean = new TargetBean();
318: ComponentResources resources = mockComponentResources();
319: Location l = mockLocation();
320:
321: train_getComponent(resources, bean);
322:
323: replay();
324:
325: try {
326: _factory.newBinding("test binding", resources, null,
327: "stringHolder.voidMethod()", l);
328: unreachable();
329: } catch (RuntimeException ex) {
330: assertEquals(
331: ex.getMessage(),
332: "Method \'voidMethod()\' returns void (in class org.apache.tapestry.internal.bindings.StringHolder, within property expression \'stringHolder.voidMethod()\').");
333: }
334:
335: verify();
336: }
337:
338: @Test
339: public void property_path_through_missing_property() {
340: TargetBean bean = new TargetBean();
341: ComponentResources resources = mockComponentResources();
342: Location l = mockLocation();
343:
344: train_getComponent(resources, bean);
345:
346: replay();
347:
348: String propertyPath = "stringHolder.missingProperty.terminalProperty";
349:
350: try {
351: _factory.newBinding("test binding", resources, null,
352: propertyPath, l);
353: unreachable();
354: } catch (TapestryException ex) {
355: assertEquals(
356: ex.getMessage(),
357: "Class org.apache.tapestry.internal.bindings.StringHolder does not contain a property named \'missingProperty\' (within property expression \'stringHolder.missingProperty.terminalProperty\').");
358: assertSame(ex.getLocation(), l);
359: }
360:
361: verify();
362: }
363:
364: @Test
365: public void property_path_through_write_only_property() {
366: TargetBean bean = new TargetBean();
367: ComponentResources resources = mockComponentResources();
368: Location l = mockLocation();
369:
370: train_getComponent(resources, bean);
371:
372: replay();
373:
374: String propertyPath = "writeOnly.terminalProperty";
375:
376: try {
377: _factory.newBinding("test binding", resources, null,
378: propertyPath, l);
379: unreachable();
380: } catch (TapestryException ex) {
381: assertEquals(
382: ex.getMessage(),
383: "Property \'writeOnly\' of class org.apache.tapestry.internal.bindings.TargetBean (within property expression \'writeOnly.terminalProperty\') is not readable (it has no read accessor method).");
384: assertSame(ex.getLocation(), l);
385: }
386:
387: verify();
388:
389: }
390:
391: @Test
392: public void primitive_property() {
393: TargetBean bean = new TargetBean();
394: ComponentResources resources = newComponentResources(bean);
395: Location l = mockLocation();
396:
397: replay();
398:
399: Binding binding = _factory.newBinding("test binding",
400: resources, null, "intValue", l);
401:
402: assertSame(binding.getBindingType(), int.class);
403:
404: bean.setIntValue(1);
405:
406: assertEquals(binding.get(), 1);
407:
408: binding.set(2);
409:
410: assertEquals(bean.getIntValue(), 2);
411:
412: verify();
413: }
414:
415: @Test
416: public void read_only_property() {
417: TargetBean bean = new TargetBean();
418: ComponentResources resources = newComponentResources(bean);
419: Location l = mockLocation();
420:
421: replay();
422:
423: Binding binding = _factory.newBinding("test binding",
424: resources, null, "readOnly", l);
425:
426: assertEquals(binding.get(), "ReadOnly");
427:
428: try {
429: binding.set("fail");
430: unreachable();
431: } catch (TapestryException ex) {
432: assertEquals(
433: ex.getMessage(),
434: "Expression readOnly for class org.apache.tapestry.internal.bindings.TargetBean is read-only.");
435: assertEquals(ex.getLocation(), l);
436: }
437:
438: verify();
439: }
440:
441: @Test
442: public void write_only_property() {
443: TargetBean bean = new TargetBean();
444: ComponentResources resources = newComponentResources(bean);
445: Location l = mockLocation();
446:
447: replay();
448:
449: Binding binding = _factory.newBinding("test binding",
450: resources, null, "writeOnly", l);
451:
452: binding.set("updated");
453:
454: assertEquals(bean._writeOnly, "updated");
455:
456: try {
457: assertEquals(binding.get(), "ReadOnly");
458: unreachable();
459: } catch (TapestryException ex) {
460: assertEquals(
461: ex.getMessage(),
462: "Expression writeOnly for class org.apache.tapestry.internal.bindings.TargetBean is write-only.");
463: assertEquals(ex.getLocation(), l);
464: }
465:
466: verify();
467: }
468:
469: @Test
470: public void unknown_property() {
471: TargetBean bean = new TargetBean();
472: ComponentResources resources = mockComponentResources();
473: Location l = mockLocation();
474:
475: train_getComponent(resources, bean);
476:
477: replay();
478:
479: try {
480: _factory.newBinding("test binding", resources, null,
481: "missingProperty", l);
482: unreachable();
483: } catch (TapestryException ex) {
484: assertEquals(
485: ex.getMessage(),
486: "Class org.apache.tapestry.internal.bindings.TargetBean does not contain a property named \'missingProperty\' (within property expression \'missingProperty\').");
487: assertSame(ex.getLocation(), l);
488: }
489:
490: verify();
491: }
492:
493: @Test
494: public void special_prop_binding_value_null() {
495: Location l = mockLocation();
496: String description = "my description";
497: ComponentResources resources = mockComponentResources();
498: Component component = mockComponent();
499:
500: train_getComponent(resources, component);
501:
502: replay();
503:
504: Binding binding = _factory.newBinding(description, resources,
505: null, "this", l);
506:
507: assertSame(binding.get(), component);
508:
509: verify();
510: }
511:
512: @Test(dataProvider="values")
513: public void special_prop_binding_values(String expression,
514: Object expected) {
515: Location l = mockLocation();
516: String description = "my description";
517: ComponentResources resources = mockComponentResources();
518:
519: replay();
520:
521: Binding binding = _factory.newBinding(description, resources,
522: null, expression, l);
523:
524: assertEquals(binding.get(), expected);
525:
526: verify();
527: }
528:
529: @DataProvider(name="values")
530: public Object[][] values() {
531: return new Object[][] {
532: { "true", true, },
533: { "True", true, },
534: { " true ", true, },
535: { "false", false },
536: { "null", null },
537: { "3", 3l },
538: { " 37 ", 37l },
539: { " -227", -227l },
540: { " 5.", 5d },
541: { " -100.", -100d },
542: { " -0.0 ", -0d },
543: { "1..10", new IntegerRange(1, 10) },
544: { " -20 .. -30 ", new IntegerRange(-20, -30) },
545: { "0.", 0d },
546: { " 227.75", 227.75d },
547: { " -10123.67", -10123.67d },
548: { "'Hello World'", "Hello World" },
549: { " 'Whitespace Ignored' ", "Whitespace Ignored" },
550: { " ' Inside ' ", " Inside " },
551: { " 'Nested ' Quotes ' Inside'",
552: "Nested ' Quotes ' Inside" }, { "'''", "'" } };
553: }
554: }
|