0001: /*
0002: * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * o Redistributions of source code must retain the above copyright notice,
0008: * this list of conditions and the following disclaimer.
0009: *
0010: * o Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
0015: * its contributors may be used to endorse or promote products derived
0016: * from this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
0027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030:
0031: package com.jgoodies.binding.tests;
0032:
0033: import java.beans.PropertyChangeEvent;
0034: import java.beans.PropertyChangeListener;
0035: import java.beans.PropertyVetoException;
0036:
0037: import junit.framework.TestCase;
0038:
0039: import com.jgoodies.binding.beans.*;
0040: import com.jgoodies.binding.tests.beans.*;
0041: import com.jgoodies.binding.tests.event.PropertyChangeReport;
0042: import com.jgoodies.binding.tests.value.ValueHolderWithNewValueNull;
0043: import com.jgoodies.binding.tests.value.ValueHolderWithOldAndNewValueNull;
0044: import com.jgoodies.binding.tests.value.ValueHolderWithOldValueNull;
0045: import com.jgoodies.binding.value.AbstractValueModel;
0046: import com.jgoodies.binding.value.ValueHolder;
0047: import com.jgoodies.binding.value.ValueModel;
0048:
0049: /**
0050: * A test case for class {@link com.jgoodies.binding.beans.BeanAdapter}.
0051: *
0052: * @author Karsten Lentzsch
0053: * @version $Revision: 1.26 $
0054: */
0055: public final class BeanAdapterTest extends TestCase {
0056:
0057: private TestBean model1;
0058: private TestBean model2;
0059:
0060: /**
0061: * @throws Exception in case of an unexpected problem
0062: */
0063: @Override
0064: protected void setUp() throws Exception {
0065: super .setUp();
0066: model1 = new TestBean();
0067: model2 = new TestBean();
0068: }
0069:
0070: /**
0071: * @throws Exception in case of an unexpected problem
0072: */
0073: @Override
0074: protected void tearDown() throws Exception {
0075: super .tearDown();
0076: model1 = null;
0077: model2 = null;
0078: }
0079:
0080: // Constructor Tests ******************************************************
0081:
0082: /**
0083: * Verifies that we can adapt observable and non-observable objects
0084: * if we do not observe changes.
0085: */
0086: public void testConstructorsAcceptAllBeansWhenNotObserving() {
0087: for (Object bean : BeanClasses.getBeans()) {
0088: try {
0089: new BeanAdapter<Object>(bean, false);
0090: new BeanAdapter<Object>(new ValueHolder(bean, true),
0091: false);
0092: } catch (PropertyUnboundException ex) {
0093: fail("Constructor must not try to observe with observeChanges == false");
0094: }
0095: }
0096: }
0097:
0098: /**
0099: * Verifies that we can adapt and observe observables.
0100: */
0101: public void testConstructorsAcceptToObserveObservables() {
0102: for (Object bean : BeanClasses.getObservableBeans()) {
0103: try {
0104: new BeanAdapter<Object>(bean, true);
0105: new BeanAdapter<Object>(new ValueHolder(bean, true),
0106: true);
0107: } catch (PropertyUnboundException ex) {
0108: fail("Constructor failed to accept to observe an observable."
0109: + "\nbean class="
0110: + bean.getClass()
0111: + "\nexception=" + ex);
0112: }
0113: }
0114: }
0115:
0116: public void testConstructorRejectsNonIdentityCheckingBeanChannel() {
0117: try {
0118: new BeanAdapter<Object>(new ValueHolder(null));
0119: fail("Constructor must reject bean channel that has the identity check feature disabled.");
0120: } catch (IllegalArgumentException e) {
0121: // The expected behavior
0122: }
0123: }
0124:
0125: /**
0126: * Verifies that we cannot observe non-observables.
0127: */
0128: public void testConstructorsRejectToObserveObservables() {
0129: for (Object bean : BeanClasses.getUnobservableBeans()) {
0130: try {
0131: new BeanAdapter<Object>(bean, true);
0132: fail("Constructor must reject to observe non-observables.");
0133: } catch (PropertyUnboundException ex) {
0134: // The expected behavior
0135: }
0136: try {
0137: new BeanAdapter<Object>(new ValueHolder(bean, true),
0138: true);
0139: fail("Constructor must reject to observe non-observables.");
0140: } catch (PropertyUnboundException ex) {
0141: // The expected behavior
0142: }
0143: }
0144: }
0145:
0146: /**
0147: * Verifies that we cannot observe non-observables.
0148: */
0149: public void testConstructorsAcceptsToObserveObjectsThatSupportBoundProperties() {
0150: for (Object bean : BeanClasses.getBeans()) {
0151: try {
0152: boolean supportsBoundProperties = BeanUtils
0153: .supportsBoundProperties(bean.getClass());
0154: new BeanAdapter<Object>(bean, supportsBoundProperties);
0155: new BeanAdapter<Object>(new ValueHolder(bean, true),
0156: supportsBoundProperties);
0157: } catch (PropertyUnboundException ex) {
0158: fail("Constructor failed to accept to observe an observable."
0159: + "\nbean class="
0160: + bean.getClass()
0161: + "\nexception=" + ex);
0162: }
0163: }
0164: }
0165:
0166: public void testConstructorAcceptsNullBean() {
0167: try {
0168: new BeanAdapter<Object>((Object) null, true);
0169: } catch (NullPointerException ex) {
0170: ex.printStackTrace();
0171: fail("Constructor failed to accept a null bean."
0172: + "\nexception=" + ex);
0173: }
0174: }
0175:
0176: // Null As Property Name **************************************************
0177:
0178: public void testRejectNullPropertyName() {
0179: testRejectNullPropertyName(null);
0180: testRejectNullPropertyName(new TestBean());
0181: }
0182:
0183: private void testRejectNullPropertyName(Object bean) {
0184: BeanAdapter<Object> adapter = new BeanAdapter<Object>(bean);
0185: try {
0186: adapter.getValue(null);
0187: fail("#getValue(null) should throw an NPE.");
0188: } catch (NullPointerException e) {
0189: // The expected behavior
0190: }
0191: try {
0192: adapter.setValue(null, null);
0193: fail("#setValue(null, Object) should throw an NPE.");
0194: } catch (NullPointerException e) {
0195: // The expected behavior
0196: }
0197: try {
0198: adapter.setVetoableValue(null, null);
0199: fail("#setVetoableValue(null, Object) should throw an NPE.");
0200: } catch (NullPointerException e) {
0201: // The expected behavior
0202: } catch (PropertyVetoException e) {
0203: fail("An NPE should be thrown.");
0204: }
0205: try {
0206: adapter.getValueModel(null);
0207: fail("#getValueModel(null) should throw an NPE.");
0208: } catch (NullPointerException e) {
0209: // The expected behavior
0210: }
0211: try {
0212: adapter.getValueModel(null, "readA", "writeA");
0213: fail("#getValueModel(null, String, String) should throw an NPE.");
0214: } catch (NullPointerException e) {
0215: // The expected behavior
0216: }
0217: }
0218:
0219: // Testing Property Access ************************************************
0220:
0221: /**
0222: */
0223: public void testReadWriteProperties() {
0224: TestBean bean = new TestBean();
0225: bean.setReadWriteObjectProperty("initialValue");
0226: bean.setReadWriteBooleanProperty(false);
0227: bean.setReadWriteIntProperty(42);
0228: ValueModel objectAdapter = new BeanAdapter<TestBean>(bean)
0229: .getValueModel("readWriteObjectProperty");
0230: ValueModel booleanAdapter = new BeanAdapter<TestBean>(bean)
0231: .getValueModel("readWriteBooleanProperty");
0232: ValueModel intAdapter = new BeanAdapter<TestBean>(bean)
0233: .getValueModel("readWriteIntProperty");
0234: ValueModel integerAdapter = new BeanAdapter<TestBean>(bean)
0235: .getValueModel("readWriteIntegerProperty");
0236:
0237: // Adapter values equal the bean property values.
0238: assertEquals(objectAdapter.getValue(), bean
0239: .getReadWriteObjectProperty());
0240: assertEquals(booleanAdapter.getValue(), Boolean.valueOf(bean
0241: .isReadWriteBooleanProperty()));
0242: assertEquals(intAdapter.getValue(), new Integer(bean
0243: .getReadWriteIntProperty()));
0244: assertEquals(integerAdapter.getValue(), bean
0245: .getReadWriteIntegerProperty());
0246:
0247: Object objectValue = "testString";
0248: Boolean booleanValue = Boolean.TRUE;
0249: Integer integerValue = new Integer(43);
0250:
0251: objectAdapter.setValue(objectValue);
0252: booleanAdapter.setValue(booleanValue);
0253: intAdapter.setValue(integerValue);
0254: integerAdapter.setValue(integerValue);
0255: assertEquals(objectValue, bean.getReadWriteObjectProperty());
0256: assertEquals(booleanValue, Boolean.valueOf(bean
0257: .isReadWriteBooleanProperty()));
0258: assertEquals(integerValue, new Integer(bean
0259: .getReadWriteIntProperty()));
0260: assertEquals(integerValue, bean.getReadWriteIntegerProperty());
0261: }
0262:
0263: public void testReadWriteCustomProperties() {
0264: CustomAccessBean bean = new CustomAccessBean();
0265: bean.writeRWObjectProperty("initialValue");
0266: bean.writeRWBooleanProperty(false);
0267: bean.writeRWIntProperty(42);
0268: ValueModel objectAdapter = new BeanAdapter<CustomAccessBean>(
0269: bean).getValueModel("readWriteObjectProperty",
0270: "readRWObjectProperty", "writeRWObjectProperty");
0271: ValueModel booleanAdapter = new BeanAdapter<CustomAccessBean>(
0272: bean).getValueModel("readWriteBooleanProperty",
0273: "readRWBooleanProperty", "writeRWBooleanProperty");
0274: ValueModel intAdapter = new BeanAdapter<CustomAccessBean>(bean)
0275: .getValueModel("readWriteIntProperty",
0276: "readRWIntProperty", "writeRWIntProperty");
0277:
0278: // Adapter values equal the bean property values.
0279: assertEquals(objectAdapter.getValue(), bean
0280: .readRWObjectProperty());
0281: assertEquals(booleanAdapter.getValue(), Boolean.valueOf(bean
0282: .readRWBooleanProperty()));
0283: assertEquals(intAdapter.getValue(), new Integer(bean
0284: .readRWIntProperty()));
0285:
0286: Object objectValue = "testString";
0287: Boolean booleanValue = Boolean.TRUE;
0288: Integer integerValue = new Integer(43);
0289:
0290: objectAdapter.setValue(objectValue);
0291: booleanAdapter.setValue(booleanValue);
0292: intAdapter.setValue(integerValue);
0293: assertEquals(objectValue, bean.readRWObjectProperty());
0294: assertEquals(booleanValue, Boolean.valueOf(bean
0295: .readRWBooleanProperty()));
0296: assertEquals(integerValue,
0297: new Integer(bean.readRWIntProperty()));
0298: }
0299:
0300: public void testReadOnlyProperties() {
0301: TestBean bean = new TestBean();
0302: bean.readOnlyObjectProperty = "testString";
0303: bean.readOnlyBooleanProperty = true;
0304: bean.readOnlyIntProperty = 42;
0305: ValueModel objectAdapter = new BeanAdapter<TestBean>(bean)
0306: .getValueModel("readOnlyObjectProperty");
0307: ValueModel booleanAdapter = new BeanAdapter<TestBean>(bean)
0308: .getValueModel("readOnlyBooleanProperty");
0309: ValueModel intAdapter = new BeanAdapter<TestBean>(bean)
0310: .getValueModel("readOnlyIntProperty");
0311:
0312: // Adapter values equal the bean property values.
0313: assertEquals(objectAdapter.getValue(), bean
0314: .getReadOnlyObjectProperty());
0315: assertEquals(booleanAdapter.getValue(), Boolean.valueOf(bean
0316: .isReadOnlyBooleanProperty()));
0317: assertEquals(intAdapter.getValue(), new Integer(bean
0318: .getReadOnlyIntProperty()));
0319: try {
0320: objectAdapter.setValue("some");
0321: fail("Adapter must reject writing of read-only properties.");
0322: } catch (UnsupportedOperationException ex) {
0323: // The expected behavior
0324: } catch (Exception e) {
0325: fail("Unexpected exception=" + e);
0326: }
0327: }
0328:
0329: public void testReadOnlyCustomProperties() {
0330: CustomAccessBean bean = new CustomAccessBean();
0331: bean.readOnlyObjectProperty = "testString";
0332: bean.readOnlyBooleanProperty = true;
0333: bean.readOnlyIntProperty = 42;
0334: ValueModel objectAdapter = new BeanAdapter<CustomAccessBean>(
0335: bean).getValueModel("readOnlyObjectProperty",
0336: "readROObjectProperty", null);
0337: ValueModel booleanAdapter = new BeanAdapter<CustomAccessBean>(
0338: bean).getValueModel("readOnlyBooleanProperty",
0339: "readROBooleanProperty", null);
0340: ValueModel intAdapter = new BeanAdapter<CustomAccessBean>(bean)
0341: .getValueModel("readOnlyIntProperty",
0342: "readROIntProperty", null);
0343:
0344: // Adapter values equal the bean property values.
0345: assertEquals(objectAdapter.getValue(), bean
0346: .readROObjectProperty());
0347: assertEquals(booleanAdapter.getValue(), Boolean.valueOf(bean
0348: .readROBooleanProperty()));
0349: assertEquals(intAdapter.getValue(), new Integer(bean
0350: .readROIntProperty()));
0351: try {
0352: objectAdapter.setValue("some");
0353: fail("Adapter must reject writing of read-only properties.");
0354: } catch (UnsupportedOperationException ex) {
0355: // The expected behavior
0356: } catch (Exception e) {
0357: fail("Unexpected exception=" + e);
0358: }
0359: }
0360:
0361: /**
0362: */
0363: public void testWriteOnlyProperties() {
0364: TestBean bean = new TestBean();
0365: ValueModel objectAdapter = new BeanAdapter<TestBean>(bean)
0366: .getValueModel("writeOnlyObjectProperty");
0367: ValueModel booleanAdapter = new BeanAdapter<TestBean>(bean)
0368: .getValueModel("writeOnlyBooleanProperty");
0369: ValueModel intAdapter = new BeanAdapter<TestBean>(bean)
0370: .getValueModel("writeOnlyIntProperty");
0371: Object objectValue = "testString";
0372: Boolean booleanValue = Boolean.TRUE;
0373: Integer integerValue = new Integer(42);
0374: objectAdapter.setValue(objectValue);
0375: booleanAdapter.setValue(booleanValue);
0376: intAdapter.setValue(integerValue);
0377: assertEquals(objectValue, bean.writeOnlyObjectProperty);
0378: assertEquals(booleanValue, Boolean
0379: .valueOf(bean.writeOnlyBooleanProperty));
0380: assertEquals(integerValue, new Integer(
0381: bean.writeOnlyIntProperty));
0382: try {
0383: objectAdapter.getValue();
0384: fail("Adapter must reject to read a write-only property.");
0385: } catch (UnsupportedOperationException ex) {
0386: // The expected behavior
0387: } catch (Exception e) {
0388: fail("Unexpected exception=" + e);
0389: }
0390: }
0391:
0392: public void testWriteOnlyCustomProperties() {
0393: CustomAccessBean bean = new CustomAccessBean();
0394: ValueModel objectAdapter = new BeanAdapter<CustomAccessBean>(
0395: bean).getValueModel("writeOnlyObjectProperty", null,
0396: "writeWOObjectProperty");
0397: ValueModel booleanAdapter = new BeanAdapter<CustomAccessBean>(
0398: bean).getValueModel("writeOnlyBooleanProperty", null,
0399: "writeWOBooleanProperty");
0400: ValueModel intAdapter = new BeanAdapter<CustomAccessBean>(bean)
0401: .getValueModel("writeOnlyIntProperty", null,
0402: "writeWOIntProperty");
0403:
0404: Object objectValue = "testString";
0405: Boolean booleanValue = Boolean.TRUE;
0406: Integer integerValue = new Integer(42);
0407: objectAdapter.setValue(objectValue);
0408: booleanAdapter.setValue(booleanValue);
0409: intAdapter.setValue(integerValue);
0410: assertEquals(objectValue, bean.writeOnlyObjectProperty);
0411: assertEquals(booleanValue, Boolean
0412: .valueOf(bean.writeOnlyBooleanProperty));
0413: assertEquals(integerValue, new Integer(
0414: bean.writeOnlyIntProperty));
0415: try {
0416: objectAdapter.getValue();
0417: fail("Adapter must reject to read a write-only property.");
0418: } catch (UnsupportedOperationException ex) {
0419: // The expected behavior
0420: } catch (Exception e) {
0421: fail("Unexpected exception=" + e);
0422: }
0423: }
0424:
0425: /**
0426: * Checks the write access to a constrained property without veto.
0427: */
0428: public void testWriteConstrainedPropertyWithoutVeto() {
0429: TestBean bean = new TestBean();
0430: BeanAdapter<TestBean>.SimplePropertyAdapter adapter = new BeanAdapter<TestBean>(
0431: bean).getValueModel("constrainedProperty");
0432: try {
0433: bean.setConstrainedProperty("value1");
0434: } catch (PropertyVetoException e1) {
0435: fail("Unexpected veto for value1.");
0436: }
0437: assertEquals("Bean has the initial value1.", bean
0438: .getConstrainedProperty(), "value1");
0439:
0440: adapter.setValue("value2a");
0441: assertEquals("Bean now has the value2a.", bean
0442: .getConstrainedProperty(), "value2a");
0443: try {
0444: adapter.setVetoableValue("value2b");
0445: } catch (PropertyVetoException e) {
0446: fail("Unexpected veto for value2b.");
0447: }
0448: assertEquals("Bean now has the value2b.", bean
0449: .getConstrainedProperty(), "value2b");
0450: }
0451:
0452: /**
0453: * Checks the write access to a constrained property with veto.
0454: */
0455: public void testWriteConstrainedPropertyWithVeto() {
0456: TestBean bean = new TestBean();
0457: PropertyAdapter<TestBean> adapter = new PropertyAdapter<TestBean>(
0458: bean, "constrainedProperty");
0459: try {
0460: bean.setConstrainedProperty("value1");
0461: } catch (PropertyVetoException e1) {
0462: fail("Unexpected veto for value1.");
0463: }
0464: assertEquals("Bean has the initial value1.", bean
0465: .getConstrainedProperty(), "value1");
0466:
0467: // Writing with a veto
0468: bean.addVetoableChangeListener(new VetoableChangeRejector());
0469:
0470: adapter.setValue("value2a");
0471: assertEquals("Bean still has the value1.", bean
0472: .getConstrainedProperty(), "value1");
0473: try {
0474: adapter.setVetoableValue("value2b");
0475: fail("Couldn't set the valid value1");
0476: } catch (PropertyVetoException e) {
0477: PropertyChangeEvent pce = e.getPropertyChangeEvent();
0478: assertEquals("The veto's old value is value1.", pce
0479: .getOldValue(), "value1");
0480: assertEquals("The veto's new value is value2b.", pce
0481: .getNewValue(), "value2b");
0482: }
0483: assertEquals(
0484: "After setting value2b, the bean still has the value1.",
0485: bean.getConstrainedProperty(), "value1");
0486: }
0487:
0488: /**
0489: * Verifies that the reader and writer can be located in different
0490: * levels of a class hierarchy.
0491: */
0492: public void testReaderWriterSplittedInHierarchy() {
0493: ReadWriteHierarchyBean bean = new ReadWriteHierarchyBean();
0494: ValueModel adapter = new BeanAdapter<ReadWriteHierarchyBean>(
0495: bean).getValueModel("property");
0496: Object value1 = "Ewa";
0497: String value2 = "Karsten";
0498: adapter.setValue(value1);
0499: assertEquals(value1, bean.getProperty());
0500: bean.setProperty(value2);
0501: assertEquals(value2, adapter.getValue());
0502: }
0503:
0504: /**
0505: * Tests access to properties that are described by a BeanInfo class.
0506: */
0507: public void testBeanInfoProperties() {
0508: CustomBean bean = new CustomBean();
0509: ValueModel adapter = new BeanAdapter<CustomBean>(bean)
0510: .getValueModel("readWriteObjectProperty");
0511: Object value1 = "Ewa";
0512: String value2 = "Karsten";
0513: adapter.setValue(value1);
0514: assertEquals(value1, bean.getReadWriteObjectProperty());
0515: bean.setReadWriteObjectProperty(value2);
0516: assertEquals(value2, adapter.getValue());
0517:
0518: try {
0519: new BeanAdapter<CustomBean>(bean)
0520: .getValueModel("readWriteIntProperty");
0521: fail("Adapter must not find properties that "
0522: + "have been excluded by a custom BeanInfo.");
0523: } catch (PropertyNotFoundException e) {
0524: // The expected behavior
0525: }
0526: }
0527:
0528: public void testAbsentProperties() {
0529: TestBean bean = new TestBean();
0530: try {
0531: new BeanAdapter<TestBean>(bean)
0532: .getValueModel("absentObjectProperty");
0533: fail("Adapter must reject an absent object property.");
0534: } catch (PropertyNotFoundException ex) {
0535: // The expected behavior
0536: } catch (Exception e) {
0537: fail("Unexpected exception=" + e);
0538: }
0539: try {
0540: new BeanAdapter<TestBean>(bean)
0541: .getValueModel("absentBooleanProperty");
0542: fail("Adapter must reject an absent boolean property.");
0543: } catch (PropertyNotFoundException ex) {
0544: // The expected behavior
0545: } catch (Exception e) {
0546: fail("Unexpected exception=" + e);
0547: }
0548: try {
0549: new BeanAdapter<TestBean>(bean)
0550: .getValueModel("absentIntProperty");
0551: fail("Adapter must reject an absent int property.");
0552: } catch (PropertyNotFoundException ex) {
0553: // The expected behavior
0554: } catch (Exception e) {
0555: fail("Unexpected exception=" + e);
0556: }
0557: }
0558:
0559: public void testIllegalPropertyAccess() {
0560: TestBean bean = new TestBean();
0561: try {
0562: new BeanAdapter<TestBean>(bean).getValueModel("noAccess")
0563: .getValue();
0564: fail("Adapter must report read-access problems.");
0565: } catch (PropertyAccessException ex) {
0566: // The expected behavior
0567: } catch (Exception e) {
0568: fail("Unexpected exception=" + e);
0569: }
0570: try {
0571: new BeanAdapter<TestBean>(bean).getValueModel("noAccess")
0572: .setValue("Fails");
0573: fail("Adapter must report write-access problems.");
0574: } catch (PropertyAccessException ex) {
0575: // The expected behavior
0576: } catch (Exception e) {
0577: fail("Unexpected exception=" + e);
0578: }
0579: try {
0580: new BeanAdapter<TestBean>(bean).getValueModel(
0581: "readWriteIntProperty").setValue(1967L);
0582: fail("Adapter must report IllegalArgumentExceptions.");
0583: } catch (PropertyAccessException ex) {
0584: // The expected behavior
0585: } catch (Exception e) {
0586: fail("Unexpected exception=" + e);
0587: }
0588: }
0589:
0590: // Testing Update Notifications *******************************************
0591:
0592: public void testSetPropertySendsUpdates() {
0593: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0594: model1, true);
0595: String propertyName = "readWriteObjectProperty";
0596: AbstractValueModel valueModel = adapter
0597: .getValueModel(propertyName);
0598:
0599: PropertyChangeReport changeReport = new PropertyChangeReport();
0600: valueModel.addPropertyChangeListener("value", changeReport);
0601:
0602: model1.setReadWriteObjectProperty("Karsten");
0603: assertEquals("First property change.", 1, changeReport
0604: .eventCount());
0605: model1.setReadWriteObjectProperty("Ewa");
0606: assertEquals("Second property change.", 2, changeReport
0607: .eventCount());
0608: model1.setReadWriteObjectProperty(model1
0609: .getReadWriteObjectProperty());
0610: assertEquals("Property change repeated.", 2, changeReport
0611: .eventCount());
0612: }
0613:
0614: public void testSetValueModelSendsUpdates() {
0615: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0616: model1, true);
0617: String propertyName = "readWriteObjectProperty";
0618: AbstractValueModel valueModel = adapter
0619: .getValueModel(propertyName);
0620:
0621: PropertyChangeReport changeReport = new PropertyChangeReport();
0622: valueModel.addPropertyChangeListener("value", changeReport);
0623:
0624: valueModel.setValue("Johannes");
0625: assertEquals("Value change.", 1, changeReport.eventCount());
0626: valueModel.setValue(valueModel.getValue());
0627: assertEquals("Value set again.", 1, changeReport.eventCount());
0628: }
0629:
0630: public void testSetAdapterValueSendsUpdates() {
0631: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0632: model1, true);
0633: String propertyName = "readWriteObjectProperty";
0634: AbstractValueModel valueModel = adapter
0635: .getValueModel(propertyName);
0636:
0637: PropertyChangeReport changeReport = new PropertyChangeReport();
0638: valueModel.addPropertyChangeListener("value", changeReport);
0639:
0640: adapter.setValue(propertyName, "Johannes");
0641: assertEquals("Value change.", 1, changeReport.eventCount());
0642: adapter.setValue(propertyName, valueModel.getValue());
0643: assertEquals("Value set again.", 1, changeReport.eventCount());
0644: }
0645:
0646: public void testBeanChangeSendsUpdates() {
0647: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0648: model1, true);
0649: String propertyName = "readWriteObjectProperty";
0650: model1.setReadWriteObjectProperty("initialValue");
0651: AbstractValueModel valueModel = adapter
0652: .getValueModel(propertyName);
0653:
0654: PropertyChangeReport changeReport = new PropertyChangeReport();
0655: valueModel.addPropertyChangeListener("value", changeReport);
0656:
0657: adapter.setBean(model1);
0658: assertEquals("First bean set.", 0, changeReport.eventCount());
0659: adapter.setBean(new TestBean());
0660: assertEquals("Second bean set.", 1, changeReport.eventCount());
0661: }
0662:
0663: public void testMulticastAndNamedPropertyChangeEvents() {
0664: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0665: model1, true);
0666: String propertyName = "readWriteObjectProperty";
0667: AbstractValueModel valueModel = adapter
0668: .getValueModel(propertyName);
0669:
0670: PropertyChangeReport changeReport = new PropertyChangeReport();
0671: valueModel.addPropertyChangeListener("value", changeReport);
0672:
0673: model1.setReadWriteObjectProperty("Karsten");
0674: assertEquals("Adapted property changed.", 1, changeReport
0675: .eventCount());
0676: model1.setReadWriteBooleanProperty(false);
0677: assertEquals("Another property changed.", 1, changeReport
0678: .eventCount());
0679: model1.setReadWriteObjectProperties(null, false, 3);
0680: assertEquals("Multiple properties changed.", 2, changeReport
0681: .eventCount());
0682: }
0683:
0684: public void testMulticastFiresProperNewValue() {
0685: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0686: model1, true);
0687: String propertyName = "readWriteObjectProperty";
0688: AbstractValueModel valueModel = adapter
0689: .getValueModel(propertyName);
0690:
0691: PropertyChangeReport changeReport = new PropertyChangeReport();
0692: valueModel.addPropertyChangeListener("value", changeReport);
0693:
0694: Object theNewObjectValue = "The new value";
0695: model1
0696: .setReadWriteObjectProperties(theNewObjectValue, false,
0697: 3);
0698:
0699: Object eventsNewValue = changeReport.lastNewValue();
0700: assertEquals("Multicast fires proper new value .",
0701: theNewObjectValue, eventsNewValue);
0702: }
0703:
0704: // Misc *******************************************************************
0705:
0706: /**
0707: * Checks that #setBean changes the bean and moves the
0708: * PropertyChangeListeners to the new bean.
0709: */
0710: public void testSetBean() {
0711: Object value1_1 = "value1.1";
0712: Object value1_2 = "value1.2";
0713: Object value2_1 = "value2.1";
0714: Object value2_2 = "value2.2";
0715: Object value2_3 = "value2.3";
0716:
0717: model1.setReadWriteObjectProperty(value1_1);
0718: model2.setReadWriteObjectProperty(value2_1);
0719: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0720: model1, true);
0721: String propertyName = "readWriteObjectProperty";
0722: AbstractValueModel valueModel = adapter
0723: .getValueModel(propertyName);
0724: adapter.setBean(model2);
0725:
0726: assertSame("Bean has not been changed.", adapter.getBean(),
0727: model2);
0728:
0729: assertSame(
0730: "Bean change does not answer the new beans's value.",
0731: valueModel.getValue(), value2_1);
0732:
0733: valueModel.setValue(value2_2);
0734: assertSame("Bean change does not set the new bean's property.",
0735: model2.getReadWriteObjectProperty(), value2_2);
0736:
0737: model1.setReadWriteObjectProperty(value1_2);
0738: assertSame("Adapter listens to old bean after bean change.",
0739: valueModel.getValue(), value2_2);
0740:
0741: model2.setReadWriteObjectProperty(value2_3);
0742: assertSame(
0743: "Adapter does not listen to new bean after bean change.",
0744: valueModel.getValue(), value2_3);
0745: }
0746:
0747: /**
0748: * Tests that we can change the bean if we adapt a write-only property.
0749: * Changing the bean normally calls the property's getter to request
0750: * the old value that is used in the fired PropertyChangeEvent.
0751: */
0752: public void testSetBeanOnWriteOnlyProperty() {
0753: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0754: model1, true);
0755: adapter.getValueModel("writeOnlyObjectProperty");
0756: adapter.setBean(model2);
0757: }
0758:
0759: /**
0760: * Tests that we can change the read/write state of the bean.
0761: */
0762: public void testSetBeanChangesReadWriteState() {
0763: ReadWriteBean readWriteBean = new ReadWriteBean();
0764: ReadOnlyBean readOnlyBean = new ReadOnlyBean();
0765: WriteOnlyBean writeOnlyBean = new WriteOnlyBean();
0766:
0767: // From/to readWriteBean to all other read/write states
0768: BeanAdapter<Model> adapter = new BeanAdapter<Model>(
0769: readWriteBean);
0770: adapter.setBean(null);
0771: adapter.setBean(readWriteBean);
0772: adapter.setBean(readOnlyBean);
0773: adapter.setBean(readWriteBean);
0774: adapter.setBean(writeOnlyBean);
0775: adapter.setBean(readWriteBean);
0776:
0777: // From/to writeOnlyBean to all other states
0778: adapter.setBean(writeOnlyBean);
0779: adapter.setBean(null);
0780: adapter.setBean(writeOnlyBean);
0781: adapter.setBean(readOnlyBean);
0782: adapter.setBean(writeOnlyBean);
0783:
0784: // From/to readOnlyBean to all other states
0785: adapter.setBean(readOnlyBean);
0786: adapter.setBean(null);
0787: adapter.setBean(readOnlyBean);
0788: }
0789:
0790: /**
0791: * Checks that bean changes are reported.
0792: */
0793: public void testBeanIsBoundProperty() {
0794: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0795: model1);
0796: PropertyChangeReport changeReport = new PropertyChangeReport();
0797: adapter.addPropertyChangeListener("bean", changeReport);
0798:
0799: adapter.setBean(model2);
0800: assertEquals("Bean changed.", 1, changeReport.eventCount());
0801: adapter.setBean(model2);
0802: assertEquals("Bean unchanged.", 1, changeReport.eventCount());
0803: adapter.setBean(null);
0804: assertEquals("Bean set to null.", 2, changeReport.eventCount());
0805: adapter.setBean(model1);
0806: assertEquals("Bean changed from null.", 3, changeReport
0807: .eventCount());
0808: }
0809:
0810: public void testBeanChangeFiresThreeBeanEvents() {
0811: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0812: (TestBean) null, true);
0813: PropertyChangeReport changeReport = new PropertyChangeReport();
0814: adapter.addPropertyChangeListener(changeReport);
0815:
0816: adapter.setBean(model1);
0817: assertEquals(
0818: "Changing the bean fires three events: before, changing, after.",
0819: 3, changeReport.eventCount());
0820: }
0821:
0822: public void testEqualBeanChangeFiresThreeBeanEvents() {
0823: Object bean1 = new EquityTestBean("bean");
0824: Object bean2 = new EquityTestBean("bean");
0825: assertEquals("The two test beans are equal.", bean1, bean2);
0826: assertNotSame("The two test beans are not the same.", bean1,
0827: bean2);
0828:
0829: BeanAdapter<Object> adapter1 = new BeanAdapter<Object>(bean1,
0830: true);
0831: PropertyChangeReport changeReport1 = new PropertyChangeReport();
0832: adapter1.addPropertyChangeListener(changeReport1);
0833:
0834: adapter1.setBean(bean2);
0835: assertEquals(
0836: "Changing the bean fires three events: before, changing, after.",
0837: 3, changeReport1.eventCount());
0838:
0839: BeanAdapter<Object> adapter2 = new BeanAdapter<Object>(null,
0840: true);
0841: adapter2.setBean(bean1);
0842: PropertyChangeReport changeReport2 = new PropertyChangeReport();
0843: adapter2.addPropertyChangeListener(changeReport2);
0844:
0845: adapter2.setBean(bean2);
0846: assertEquals(
0847: "Changing the bean fires three events: before, changing, after.",
0848: 3, changeReport2.eventCount());
0849: }
0850:
0851: public void testBeanChangeIgnoresOldBeanNull() {
0852: testBeanChangeIgnoresMissingOldOrNullValues(new ValueHolderWithOldValueNull(
0853: null));
0854: }
0855:
0856: public void testBeanChangeIgnoresNewBeanNull() {
0857: testBeanChangeIgnoresMissingOldOrNullValues(new ValueHolderWithNewValueNull(
0858: null));
0859: }
0860:
0861: public void testBeanChangeIgnoresOldAndNewBeanNull() {
0862: testBeanChangeIgnoresMissingOldOrNullValues(new ValueHolderWithOldAndNewValueNull(
0863: null));
0864: }
0865:
0866: private void testBeanChangeIgnoresMissingOldOrNullValues(
0867: ValueModel beanChannel) {
0868: TestBean bean1 = new TestBean();
0869: TestBean bean2 = new TestBean();
0870: beanChannel.setValue(bean1);
0871: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0872: beanChannel, true);
0873: ValueModel model = adapter
0874: .getValueModel("readWriteObjectProperty");
0875: PropertyChangeReport changeReport = new PropertyChangeReport();
0876: model.addValueChangeListener(changeReport);
0877: beanChannel.setValue(bean2);
0878: bean1.setReadWriteObjectProperty("bean1value");
0879: assertEquals("No event if modifying the old bean", 0,
0880: changeReport.eventCount());
0881: bean2.setReadWriteObjectProperty("bean2value");
0882: assertEquals("Fires event if modifying the new bean", 1,
0883: changeReport.eventCount());
0884: }
0885:
0886: public void testChangedState() {
0887: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0888: model1, true);
0889:
0890: assertEquals("The initial changed state is false.", false,
0891: adapter.isChanged());
0892: model1.setReadWriteObjectProperty("aBrandNewValue");
0893: assertEquals(
0894: "Changing the bean turns the changed state to true.",
0895: true, adapter.isChanged());
0896: adapter.resetChanged();
0897: assertEquals(
0898: "Resetting changes turns the changed state to false.",
0899: false, adapter.isChanged());
0900: model1.setReadWriteObjectProperty("anotherValue");
0901: assertEquals(
0902: "Changing the bean turns the changed state to true again.",
0903: true, adapter.isChanged());
0904: adapter.setBean(model2);
0905: assertEquals("Changing the bean resets the changed state.",
0906: false, adapter.isChanged());
0907: }
0908:
0909: public void testChangedStateFiresEvents() {
0910: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0911: model1, true);
0912: PropertyChangeReport changeReport = new PropertyChangeReport();
0913: adapter.addPropertyChangeListener("changed", changeReport);
0914:
0915: model1.setReadWriteObjectProperty("aBrandNewValue");
0916: adapter.resetChanged();
0917: model1.setReadWriteObjectProperty("anotherValue");
0918: adapter.setBean(model2);
0919: assertEquals("The changed state changed four times.", 4,
0920: changeReport.eventCount());
0921: }
0922:
0923: // Testing Bean Property Changes ******************************************
0924:
0925: public void testUnnamedBeanPropertyChange() {
0926: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0927: model1, true);
0928: PropertyChangeReport changeReport = new PropertyChangeReport();
0929: adapter.addBeanPropertyChangeListener(changeReport);
0930:
0931: model1.setReadWriteObjectProperty("value1");
0932: assertEquals(
0933: "Setting a bound property forwards the PropertyChangeEvent.",
0934: 1, changeReport.eventCount());
0935: model1.setReadWriteObjectProperties("value2", false, 42);
0936: assertEquals(
0937: "Firing a multicast event forwards a PropertyChangeEvent too.",
0938: 2, changeReport.eventCount());
0939: adapter.setBean(model2);
0940: assertEquals("Changing the bean fires no bean event.", 2,
0941: changeReport.eventCount());
0942: model1.setReadWriteObjectProperty("ignoredValue1");
0943: assertEquals(
0944: "Setting a bound property in the old bean fires no event.",
0945: 2, changeReport.eventCount());
0946: model2.setReadWriteObjectProperty("value2");
0947: assertEquals(
0948: "Setting a bound property forwards another PropertyChangeEvent.",
0949: 3, changeReport.eventCount());
0950: }
0951:
0952: public void testNamedBeanPropertyChange() {
0953: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0954: model1, true);
0955: PropertyChangeReport changeReport = new PropertyChangeReport();
0956: adapter.addBeanPropertyChangeListener(
0957: "readWriteObjectProperty", changeReport);
0958:
0959: model1.setReadWriteObjectProperty("value1");
0960: assertEquals(
0961: "Setting a bound property forwards the PropertyChangeEvent.",
0962: 1, changeReport.eventCount());
0963: model1.setReadWriteObjectProperties("value2", false, 42);
0964: assertEquals(
0965: "Firing a multicast event forwards no event to named listeners.",
0966: 1, changeReport.eventCount());
0967: adapter.setBean(model2);
0968: assertEquals("Changing the bean fires no bean event.", 1,
0969: changeReport.eventCount());
0970: model1.setReadWriteObjectProperty("ignoredValue1");
0971: assertEquals(
0972: "Setting a bound property in the old bean fires no event.",
0973: 1, changeReport.eventCount());
0974: model2.setReadWriteObjectProperty("value2");
0975: assertEquals(
0976: "Setting a bound property forwards another PropertyChangeEvent.",
0977: 2, changeReport.eventCount());
0978: }
0979:
0980: // Misc *******************************************************************
0981:
0982: /**
0983: * Checks that the cached PropertyDescriptor is available when needed.
0984: */
0985: public void testPropertyDescriptorCache() {
0986: ValueModel beanChannel = new ValueHolder(null, true);
0987: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
0988: beanChannel, true);
0989: ValueModel valueModel = adapter
0990: .getValueModel("readWriteObjectProperty");
0991:
0992: beanChannel.setValue(new TestBean());
0993: valueModel.setValue("Test");
0994: }
0995:
0996: /**
0997: * Verifies that the factory method vends the same instance of the
0998: * adapting model if called multiple times.
0999: */
1000: public void testVendsSameModel() {
1001: BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
1002: model1, true);
1003: Object adapter1 = adapter
1004: .getValueModel("readWriteObjectProperty");
1005: Object adapter2 = adapter
1006: .getValueModel("readWriteObjectProperty");
1007:
1008: assertSame(
1009: "The adapter factory method vends the same instance.",
1010: adapter1, adapter2);
1011: }
1012:
1013: /**
1014: * Verifies that the BeanAdapter rejects attempts to get an adapting
1015: * ValueModel by means of <code>#getValueModel</code> with different
1016: * property accessor names. In other words, for each bean property
1017: * API users must use either {@link BeanAdapter#getValueModel(String)} or
1018: * {@link BeanAdapter#getValueModel(String, String, String)}, not both.
1019: * And all calls to the latter method must use the same getter and setter
1020: * names for the same property name.<p>
1021: *
1022: * This test invokes both methods for the same property name with different
1023: * getter and/or setter names and expects that the second call is rejected.
1024: * The BeanAdapter is created without a bean set, to avoid that the
1025: * BeanAdapter checks for a valid property.
1026: */
1027: public void testRejectsGetValueModelWithDifferentAccessors() {
1028: String failureText = "The BeanAdapter must reject attempts "
1029: + "to get a ValueModel for the same property "
1030: + "with different accessor names.";
1031: String propertyName = "property";
1032: String getterName1 = "getter1";
1033: String getterName2 = "getter2";
1034: String setterName1 = "setter1";
1035: String setterName2 = "setter2";
1036:
1037: BeanAdapter<Object> adapter1 = new BeanAdapter<Object>(null);
1038: adapter1.getValueModel(propertyName);
1039: try {
1040: adapter1.getValueModel(propertyName, getterName1,
1041: setterName1);
1042: fail(failureText);
1043: } catch (IllegalArgumentException e) {
1044: // The expected result.
1045: }
1046:
1047: BeanAdapter<Object> adapter2 = new BeanAdapter<Object>(null);
1048: adapter2.getValueModel(propertyName, getterName1, setterName1);
1049: try {
1050: adapter2.getValueModel(propertyName);
1051: fail(failureText);
1052: } catch (IllegalArgumentException e) {
1053: // The expected result.
1054: }
1055:
1056: BeanAdapter<Object> adapter3 = new BeanAdapter<Object>(null);
1057: adapter3.getValueModel(propertyName, getterName1, setterName1);
1058: try {
1059: adapter3.getValueModel(propertyName, getterName2,
1060: setterName1);
1061: fail(failureText);
1062: } catch (IllegalArgumentException e) {
1063: // The expected result.
1064: }
1065:
1066: BeanAdapter<Object> adapter4 = new BeanAdapter<Object>(null);
1067: adapter4.getValueModel(propertyName, getterName1, setterName1);
1068: try {
1069: adapter4.getValueModel(propertyName, getterName1,
1070: setterName2);
1071: fail(failureText);
1072: } catch (IllegalArgumentException e) {
1073: // The expected result.
1074: }
1075: }
1076:
1077: // Checking for ConcurrentModificationExceptions **************************
1078:
1079: /**
1080: * Sets up an environment that has thrown a ConcurrentModificationException
1081: * in older releases. Basically, in a situation where the BeanAdapter
1082: * iterates over all its internal property adapters, we add a new adapter
1083: * and check if this fails.
1084: */
1085: public void testCanGetModelWhileListeningToBeanChange() {
1086: BeanAdapter<TestBean> adapter = createConcurrentModificationEnvironment();
1087: adapter.setBean(model2);
1088: }
1089:
1090: public void testCanGetModelWhileListeningToMulticastChange() {
1091: createConcurrentModificationEnvironment();
1092: model1.setReadWriteObjectProperties("value3", true, 3);
1093: }
1094:
1095: private BeanAdapter<TestBean> createConcurrentModificationEnvironment() {
1096: model1.setReadWriteObjectProperty("value1");
1097: model2.setReadWriteObjectProperty("value2");
1098: final BeanAdapter<TestBean> adapter = new BeanAdapter<TestBean>(
1099: model1, true);
1100: ValueModel valueModel1 = adapter
1101: .getValueModel("readWriteObjectProperty");
1102: // Add a second listener so that adding a new SimplePropertyAdapter
1103: // may cause a ConcurrentModificationException while adding a new adapter.
1104: adapter.getValueModel("readWriteBooleanProperty");
1105: PropertyChangeListener listener = new PropertyChangeListener() {
1106: public void propertyChange(
1107: java.beans.PropertyChangeEvent evt) {
1108: adapter.getValueModel("readWriteIntProperty");
1109: }
1110: };
1111: valueModel1.addValueChangeListener(listener);
1112: return adapter;
1113: }
1114:
1115: }
|