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.ioc.internal.services;
016:
017: import java.awt.Image;
018: import java.beans.BeanDescriptor;
019: import java.beans.BeanInfo;
020: import java.beans.EventSetDescriptor;
021: import java.beans.MethodDescriptor;
022: import java.beans.PropertyDescriptor;
023: import java.util.Arrays;
024: import java.util.Random;
025:
026: import org.apache.tapestry.ioc.Registry;
027: import org.apache.tapestry.ioc.annotations.Scope;
028: import org.apache.tapestry.ioc.internal.IOCInternalTestCase;
029: import org.apache.tapestry.ioc.services.ClassPropertyAdapter;
030: import org.apache.tapestry.ioc.services.PropertyAccess;
031: import org.apache.tapestry.ioc.services.PropertyAdapter;
032: import org.testng.annotations.Test;
033:
034: public class PropertyAccessImplTest extends IOCInternalTestCase {
035: private static final String CLASS_NAME = PropertyAccessImplTest.class
036: .getName();
037:
038: private PropertyAccess _access = new PropertyAccessImpl();
039:
040: private Random _random = new Random();
041:
042: public static class Bean {
043: private int _value;
044:
045: public int getValue() {
046: return _value;
047: }
048:
049: public void setValue(int value) {
050: _value = value;
051: }
052:
053: @Override
054: public String toString() {
055: return "PropertyUtilsTestBean";
056: }
057:
058: public void setWriteOnly(boolean b) {
059: }
060:
061: public String getReadOnly() {
062: return null;
063: }
064: }
065:
066: public static class ExceptionBean {
067: public boolean getFailure() {
068: throw new RuntimeException("getFailure");
069: }
070:
071: public void setFailure(boolean b) {
072: throw new RuntimeException("setFailure");
073: }
074:
075: @Override
076: public String toString() {
077: return "PropertyUtilsExceptionBean";
078: }
079: }
080:
081: public static class UglyBean {
082: }
083:
084: public static class UglyBeanBeanInfo implements BeanInfo {
085:
086: public BeanInfo[] getAdditionalBeanInfo() {
087: return new BeanInfo[0];
088: }
089:
090: public BeanDescriptor getBeanDescriptor() {
091: return null;
092: }
093:
094: public int getDefaultEventIndex() {
095: return 0;
096: }
097:
098: public int getDefaultPropertyIndex() {
099: return 0;
100: }
101:
102: public EventSetDescriptor[] getEventSetDescriptors() {
103: return new EventSetDescriptor[0];
104: }
105:
106: public Image getIcon(int iconKind) {
107: return null;
108: }
109:
110: public MethodDescriptor[] getMethodDescriptors() {
111: return new MethodDescriptor[0];
112: }
113:
114: public PropertyDescriptor[] getPropertyDescriptors() {
115: throw new RuntimeException("This is the UglyBean.");
116: }
117:
118: }
119:
120: public static class BooleanHolder {
121: private boolean _flag;
122:
123: public boolean isFlag() {
124: return _flag;
125: }
126:
127: public void setFlag(boolean flag) {
128: _flag = flag;
129: }
130: }
131:
132: @Test
133: public void simple_read_access() {
134: Bean b = new Bean();
135:
136: int value = _random.nextInt();
137:
138: b.setValue(value);
139:
140: assertEquals(_access.get(b, "value"), value);
141: }
142:
143: @Test
144: public void property_name_case_is_ignored_on_read() {
145: Bean b = new Bean();
146:
147: int value = _random.nextInt();
148:
149: b.setValue(value);
150:
151: assertEquals(_access.get(b, "VALUE"), value);
152: }
153:
154: @Test
155: public void simple_write_access() {
156: Bean b = new Bean();
157:
158: int value = _random.nextInt();
159:
160: _access.set(b, "value", value);
161:
162: assertEquals(b.getValue(), value);
163: }
164:
165: @Test
166: public void property_name_case_is_ignored_on_write() {
167: Bean b = new Bean();
168:
169: int value = _random.nextInt();
170:
171: _access.set(b, "VALUE", value);
172:
173: assertEquals(b.getValue(), value);
174: }
175:
176: @Test
177: public void missing_property() {
178: Bean b = new Bean();
179:
180: try {
181: _access.get(b, "zaphod");
182:
183: unreachable();
184: } catch (IllegalArgumentException ex) {
185: assertEquals(ex.getMessage(), "Class " + CLASS_NAME
186: + "$Bean does not "
187: + "contain a property named 'zaphod'.");
188: }
189: }
190:
191: @Test
192: public void attempt_to_update_read_only_property() {
193: Bean b = new Bean();
194:
195: try {
196: _access.set(b, "class", null);
197: unreachable();
198: } catch (UnsupportedOperationException ex) {
199: assertEquals(
200: ex.getMessage(),
201: "Class "
202: + CLASS_NAME
203: + "$Bean does not provide an mutator ('setter') method for property 'class'.");
204: }
205: }
206:
207: @Test
208: public void attempt_to_read_from_write_only_property() {
209: Bean b = new Bean();
210:
211: try {
212: _access.get(b, "writeOnly");
213: unreachable();
214: } catch (UnsupportedOperationException ex) {
215: assertEquals(
216: ex.getMessage(),
217: "Class "
218: + CLASS_NAME
219: + "$Bean does not provide an accessor ('getter') method for property 'writeOnly'.");
220: }
221: }
222:
223: @Test
224: public void exception_thrown_inside_getter() {
225: ExceptionBean b = new ExceptionBean();
226:
227: try {
228: _access.get(b, "failure");
229: unreachable();
230: } catch (RuntimeException ex) {
231: assertEquals(ex.getMessage(),
232: "Error reading property 'failure' of PropertyUtilsExceptionBean: getFailure");
233: }
234: }
235:
236: @Test
237: public void exception_thrown_inside_setter() {
238: ExceptionBean b = new ExceptionBean();
239:
240: try {
241: _access.set(b, "failure", false);
242: unreachable();
243: } catch (RuntimeException ex) {
244: assertEquals(ex.getMessage(),
245: "Error updating property 'failure' of PropertyUtilsExceptionBean: setFailure");
246: }
247: }
248:
249: @Test
250: public void failure_when_introspecting_class() {
251: UglyBean b = new UglyBean();
252:
253: try {
254: _access.get(b, "google");
255: unreachable();
256: } catch (RuntimeException ex) {
257: assertEquals(ex.getMessage(),
258: "java.lang.RuntimeException: This is the UglyBean.");
259: }
260: }
261:
262: @Test
263: public void clear_wipes_internal_cache() {
264: ClassPropertyAdapter cpa1 = _access.getAdapter(Bean.class);
265:
266: assertSame(cpa1.getBeanType(), Bean.class);
267:
268: ClassPropertyAdapter cpa2 = _access.getAdapter(Bean.class);
269:
270: assertSame(cpa2, cpa1);
271:
272: _access.clearCache();
273:
274: ClassPropertyAdapter cpa3 = _access.getAdapter(Bean.class);
275:
276: assertNotSame(cpa3, cpa1);
277: }
278:
279: @Test
280: public void class_property_adapter_toString() {
281: ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
282:
283: assertEquals(cpa.toString(), "<ClassPropertyAdaptor "
284: + CLASS_NAME
285: + "$Bean : class, readOnly, value, writeOnly>");
286: }
287:
288: @Test
289: public void property_adapter_read_only_property() {
290: ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
291: PropertyAdapter pa = cpa.getPropertyAdapter("readOnly");
292:
293: assertTrue(pa.isRead());
294: assertFalse(pa.isUpdate());
295:
296: assertNull(pa.getWriteMethod());
297: assertEquals(pa.getReadMethod(), findMethod(Bean.class,
298: "getReadOnly"));
299: }
300:
301: @Test
302: public void property_adapter_write_only_property() {
303: ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
304: PropertyAdapter pa = cpa.getPropertyAdapter("writeOnly");
305:
306: assertFalse(pa.isRead());
307: assertTrue(pa.isUpdate());
308:
309: assertEquals(pa.getWriteMethod(), findMethod(Bean.class,
310: "setWriteOnly"));
311: assertNull(pa.getReadMethod());
312: }
313:
314: @Test
315: public void class_property_adapter_returns_null_for_unknown_property() {
316: ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
317:
318: assertNull(cpa.getPropertyAdapter("google"));
319: }
320:
321: @Test
322: public void access_to_property_type() {
323: ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
324:
325: assertEquals(cpa.getPropertyAdapter("value").getType(),
326: int.class);
327: assertEquals(cpa.getPropertyAdapter("readOnly").getType(),
328: String.class);
329: assertEquals(cpa.getPropertyAdapter("writeOnly").getType(),
330: boolean.class);
331: }
332:
333: @Test
334: public void property_names() {
335: ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
336:
337: assertEquals(cpa.getPropertyNames(), Arrays.asList("class",
338: "readOnly", "value", "writeOnly"));
339: }
340:
341: @Test
342: public void integration() {
343: Registry registry = buildRegistry();
344:
345: PropertyAccess pa = registry.getService("PropertyAccess",
346: PropertyAccess.class);
347:
348: Bean b = new Bean();
349:
350: int value = _random.nextInt();
351:
352: pa.set(b, "value", value);
353:
354: assertEquals(b.getValue(), value);
355: }
356:
357: @Test
358: public void super _interface_methods_inherited_by_sub_interface() {
359: ClassPropertyAdapter cpa = _access
360: .getAdapter(SubInterface.class);
361:
362: assertEquals(cpa.getPropertyNames(), Arrays.asList(
363: "grandParentProperty", "parentProperty", "subProperty"));
364: }
365:
366: @Test
367: public void indexed_properties_are_ignored() {
368: ClassPropertyAdapter cpa = _access
369: .getAdapter(BeanWithIndexedProperty.class);
370:
371: assertEquals(cpa.getPropertyNames(), Arrays.asList("class",
372: "primitiveProperty"));
373: }
374:
375: @Test
376: public void get_annotation_when_annotation_not_present() {
377: PropertyAdapter pa = _access.getAdapter(AnnotatedBean.class)
378: .getPropertyAdapter("readWrite");
379:
380: assertNull(pa.getAnnotation(Scope.class));
381: }
382:
383: @Test
384: public void get_annotation_with_annotation_on_write_method() {
385: PropertyAdapter pa = _access.getAdapter(AnnotatedBean.class)
386: .getPropertyAdapter("annotationOnWrite");
387:
388: Scope annotation = pa.getAnnotation(Scope.class);
389: assertNotNull(annotation);
390:
391: assertEquals(annotation.value(), "onwrite");
392: }
393:
394: @Test
395: public void read_method_annotation_overrides_write_method_annotation() {
396: PropertyAdapter pa = _access.getAdapter(AnnotatedBean.class)
397: .getPropertyAdapter("annotationOnRead");
398:
399: Scope annotation = pa.getAnnotation(Scope.class);
400: assertNotNull(annotation);
401:
402: assertEquals(annotation.value(), "onread");
403: }
404:
405: @Test
406: public void no_write_method_reading_missing_annotation() {
407: PropertyAdapter pa = _access.getAdapter(AnnotatedBean.class)
408: .getPropertyAdapter("readOnly");
409:
410: assertNull(pa.getAnnotation(Scope.class));
411: }
412: }
|