001: /*
002: * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.binding.tests;
032:
033: import junit.framework.TestCase;
034:
035: import com.jgoodies.binding.beans.PropertyConnector;
036: import com.jgoodies.binding.tests.beans.TestBean;
037: import com.jgoodies.binding.tests.event.PropertyChangeReport;
038: import com.jgoodies.binding.tests.value.ToUpperCaseStringHolder;
039: import com.jgoodies.binding.value.ValueHolder;
040: import com.jgoodies.binding.value.ValueModel;
041:
042: /**
043: * A test case for class {@link PropertyConnector}.
044: *
045: * @author Karsten Lentzsch
046: * @version $Revision: 1.15 $
047: */
048: public final class PropertyConnectorTest extends TestCase {
049:
050: private PropertyConnector createDefaultConnector(TestBean bean1,
051: TestBean bean2) {
052: return PropertyConnector.connect(bean1,
053: "readWriteObjectProperty", bean2,
054: "readWriteObjectProperty");
055: }
056:
057: private PropertyConnector createDefaultConnector(TestBean bean1,
058: Object initialValue1, TestBean bean2, Object initialValue2) {
059: bean1.setReadWriteObjectProperty(initialValue1);
060: bean2.setReadWriteObjectProperty(initialValue2);
061: return createDefaultConnector(bean1, bean2);
062: }
063:
064: // Constructor Tests ******************************************************
065:
066: public void testConstructorRejectsNullParameters() {
067: TestBean bean1;
068: TestBean bean2;
069: bean1 = new TestBean();
070: bean2 = new TestBean();
071: try {
072: PropertyConnector.connect(null, "readWriteObjectProperty",
073: bean2, "readWriteObjectProperty");
074: fail("Constructor failed to reject bean1==null.");
075: } catch (NullPointerException ex) {
076: // The expected behavior
077: }
078: bean1 = new TestBean();
079: bean2 = new TestBean();
080: try {
081: PropertyConnector.connect(bean1, null, bean2,
082: "readWriteObjectProperty");
083: fail("Constructor failed to reject property1Name==null.");
084: } catch (NullPointerException ex) {
085: // The expected behavior
086: }
087: bean1 = new TestBean();
088: bean2 = new TestBean();
089: try {
090: PropertyConnector.connect(bean1, "readWriteObjectProperty",
091: null, "readWriteObjectProperty");
092: fail("Constructor failed to reject bean2==null.");
093: } catch (NullPointerException ex) {
094: // The expected behavior
095: }
096: bean1 = new TestBean();
097: bean2 = new TestBean();
098: try {
099: PropertyConnector.connect(bean1, "readWriteObjectProperty",
100: bean2, null);
101: fail("Constructor failed to reject property2Name==null.");
102: } catch (NullPointerException ex) {
103: // The expected behavior
104: }
105: }
106:
107: public void testConstructorRejectsToConnectTheSameProperty() {
108: TestBean bean = new TestBean();
109: try {
110: PropertyConnector.connect(bean, "readWriteObjectProperty",
111: bean, "readWriteObjectProperty");
112: fail("Constructor failed to reject bean1==bean2 && property1Name.equals(property2Name).");
113: } catch (IllegalArgumentException ex) {
114: // The expected behavior
115: }
116: }
117:
118: public void testConstructorRejectsWriteOnlyProperty1() {
119: TestBean bean = new TestBean();
120: try {
121: PropertyConnector.connect(bean, "writeOnlyObjectProperty",
122: bean, "readWriteObjectProperty");
123: fail("Constructor failed to reject the write only property1.");
124: } catch (IllegalArgumentException ex) {
125: // The expected behavior
126: }
127: }
128:
129: public void testConstructorRejectsWriteOnlyProperty2() {
130: TestBean bean = new TestBean();
131: try {
132: PropertyConnector.connect(bean, "readWriteObjectProperty",
133: bean, "writeOnlyObjectProperty");
134: fail("Constructor failed to reject the write only property2.");
135: } catch (IllegalArgumentException ex) {
136: // The expected behavior
137: }
138: }
139:
140: public void testConstructorRejectsReadOnlyBeans() {
141: TestBean bean1 = new TestBean();
142: TestBean bean2 = new TestBean();
143: try {
144: PropertyConnector.connect(bean1, "readOnlyObjectProperty",
145: bean2, "readOnlyObjectProperty");
146: fail("Constructor failed to reject read-only bean properties.");
147: } catch (IllegalArgumentException ex) {
148: // The expected behavior
149: }
150: }
151:
152: public void testConstructorLeavesValuesUnchanged() {
153: TestBean bean1 = new TestBean();
154: TestBean bean2 = new TestBean();
155: Object initialValue1 = "initialValue1";
156: Object initialValue2 = "initialValue2";
157: createDefaultConnector(bean1, initialValue1, bean2,
158: initialValue2);
159: assertEquals("The constructor must not change the property1.",
160: initialValue1, bean1.getReadWriteObjectProperty());
161: assertEquals("The constructor must not change the property2.",
162: initialValue2, bean2.getReadWriteObjectProperty());
163: }
164:
165: // Synchronization ********************************************************
166:
167: public void testUpdateProperty1() {
168: TestBean bean1 = new TestBean();
169: TestBean bean2 = new TestBean();
170: Object initialValue2 = "newValue2";
171: PropertyConnector connector = createDefaultConnector(bean1,
172: "value1", bean2, initialValue2);
173: connector.updateProperty1();
174: assertEquals("#updateProperty1 failed to update property1.",
175: bean1.getReadWriteObjectProperty(), bean2
176: .getReadWriteObjectProperty());
177: }
178:
179: public void testUpdateProperty2() {
180: TestBean bean1 = new TestBean();
181: TestBean bean2 = new TestBean();
182: Object initialValue1 = "newValue1";
183: PropertyConnector connector = createDefaultConnector(bean1,
184: initialValue1, bean2, "value2");
185: connector.updateProperty2();
186: assertEquals("#updateProperty2 failed to update property2.",
187: bean1.getReadWriteObjectProperty(), bean2
188: .getReadWriteObjectProperty());
189: }
190:
191: public void testProperty1ChangeUpdatesProperty2() {
192: TestBean bean1 = new TestBean();
193: TestBean bean2 = new TestBean();
194: createDefaultConnector(bean1, "value1", bean2, "value2");
195: bean1.setReadWriteObjectProperty("newValue1");
196: assertEquals(
197: "Failed to update property2 after a named change.",
198: bean1.getReadWriteObjectProperty(), bean2
199: .getReadWriteObjectProperty());
200: }
201:
202: public void testProperty2ChangeUpdatesProperty1() {
203: TestBean bean1 = new TestBean();
204: TestBean bean2 = new TestBean();
205: createDefaultConnector(bean1, "value1", bean2, "value2");
206: bean2.setReadWriteObjectProperty("newValue1");
207: assertEquals(
208: "Failed to update property1 after a named change.",
209: bean1.getReadWriteObjectProperty(), bean2
210: .getReadWriteObjectProperty());
211: }
212:
213: public void testProperty1AnonymousChangeUpdatesProperty2() {
214: TestBean bean1 = new TestBean();
215: TestBean bean2 = new TestBean();
216: createDefaultConnector(bean1, "value1", bean2, "value2");
217: bean1.setReadWriteObjectProperties("newValue1", true, 42);
218: assertEquals(
219: "Failed to update property2 after an unnamed change.",
220: bean1.getReadWriteObjectProperty(), bean2
221: .getReadWriteObjectProperty());
222: }
223:
224: public void testProperty2AnonymousChangeUpdatesProperty1() {
225: TestBean bean1 = new TestBean();
226: TestBean bean2 = new TestBean();
227: createDefaultConnector(bean1, "value1", bean2, "value2");
228: bean2.setReadWriteObjectProperties("newValue1", true, 42);
229: assertEquals(
230: "Failed to update property1 after an unnamed change.",
231: bean1.getReadWriteObjectProperty(), bean2
232: .getReadWriteObjectProperty());
233: }
234:
235: // Avoid Unnecessary Events ***********************************************
236:
237: public void testAvoidUnnecessaryChangeEvents() {
238: TestBean bean1 = new TestBean();
239: TestBean bean2 = new TestBean();
240: createDefaultConnector(bean1, "value1", bean2, null);
241: PropertyChangeReport report = new PropertyChangeReport();
242: bean2.addPropertyChangeListener("readWriteObjectProperty",
243: report);
244: assertEquals("No changes.", 0, report.eventCount());
245: bean1.setReadWriteObjectProperty(null);
246: assertEquals("bean2 remains the same", 0, report.eventCount());
247: bean1.setReadWriteObjectProperty("newValue1");
248: assertEquals("bean2 updated", 1, report.eventCount());
249: }
250:
251: // Events that lack the new value *****************************************
252:
253: public void testProperty1ChangeWithNullEventNewValueUpdatesProperty2() {
254: TestBean bean1 = new TestBean();
255: TestBean bean2 = new TestBean();
256: PropertyConnector.connect(bean1, "nullNewValueProperty", bean2,
257: "readWriteObjectProperty");
258: bean1.setNullNewValueProperty("newValue1");
259: assertEquals(
260: "Failed to update property2 after a change with event that has a null new value.",
261: bean1.getNullNewValueProperty(), bean2
262: .getReadWriteObjectProperty());
263: }
264:
265: public void testProperty2ChangeWithNullEventNewValueUpdatesProperty1() {
266: TestBean bean1 = new TestBean();
267: TestBean bean2 = new TestBean();
268: PropertyConnector.connect(bean1, "readWriteObjectProperty",
269: bean2, "nullNewValueProperty");
270: bean2.setNullNewValueProperty("newValue1");
271: assertEquals(
272: "Failed to update property1 after a change with event that has a null new value.",
273: bean1.getReadWriteObjectProperty(), bean2
274: .getNullNewValueProperty());
275: }
276:
277: // One-Way Synchronization ************************************************
278:
279: public void testConnectReadWriteProperty1WithReadOnlyProperty2() {
280: TestBean bean1 = new TestBean();
281: TestBean bean2 = new TestBean();
282: bean1.setReadWriteObjectProperty("initalValue1");
283: PropertyConnector.connect(bean1, "readWriteObjectProperty",
284: bean2, "readOnlyObjectProperty");
285: testConnectReadWriteWithReadOnlyProperty(bean1, bean2);
286: }
287:
288: public void testConnectReadOnlyProperty1WithReadWriteProperty2() {
289: TestBean bean1 = new TestBean();
290: TestBean bean2 = new TestBean();
291: bean1.setReadWriteObjectProperty("initalValue1");
292: PropertyConnector.connect(bean1, "readOnlyObjectProperty",
293: bean2, "readWriteObjectProperty");
294: testConnectReadWriteWithReadOnlyProperty(bean2, bean1);
295: }
296:
297: public void testUpdateHonorsTargetModifications() {
298: ValueModel bean1 = new ValueHolder("initalValue");
299: ValueModel bean2 = new ToUpperCaseStringHolder();
300: PropertyConnector.connect(bean1, "value", bean2, "value");
301: String newValue = "newValue";
302: String newValueUpperCase = newValue.toUpperCase();
303: bean1.setValue("newValue");
304: assertEquals("Target value is uppercase", newValueUpperCase,
305: bean2.getValue());
306: assertEquals("Source value is uppercase too",
307: newValueUpperCase, bean1.getValue());
308: }
309:
310: public void testConnectReadOnlyWithModifyingTarget() {
311: TestBean bean1 = new TestBean();
312: ValueModel bean2 = new ToUpperCaseStringHolder();
313: bean1.readOnlyObjectProperty = "initialValue";
314: PropertyConnector.connect(bean1, "readOnlyObjectProperty",
315: bean2, "value");
316: // Update property1 if the read-only property2 changes.
317: String newValue = "newValue";
318: bean1.fireChangeOnReadOnlyObjectProperty(newValue);
319: assertEquals("Bean2 has the read-only in upper case.", newValue
320: .toUpperCase(), bean2.getValue());
321: }
322:
323: // Helper Code ************************************************************
324:
325: private void testConnectReadWriteWithReadOnlyProperty(
326: TestBean beanWithReadWriteProperty,
327: TestBean beanWithReadOnlyProperty) {
328: Object initialValue2 = "initialValue2";
329: beanWithReadOnlyProperty.readOnlyObjectProperty = initialValue2;
330:
331: // Ignore updates of property1.
332: beanWithReadWriteProperty
333: .setReadWriteObjectProperty("newValue1");
334: assertEquals("The connector must not update property2.",
335: initialValue2, beanWithReadOnlyProperty
336: .getReadOnlyObjectProperty());
337:
338: // Update property1 if the read-only property2 changes.
339: Object newValue2 = "newValue2";
340: beanWithReadOnlyProperty
341: .fireChangeOnReadOnlyObjectProperty(newValue2);
342: assertEquals(
343: "Bean2 has a new value for the read-only property2.",
344: newValue2, beanWithReadOnlyProperty
345: .getReadOnlyObjectProperty());
346: assertEquals("The connector must update property1.", newValue2,
347: beanWithReadWriteProperty.getReadWriteObjectProperty());
348:
349: // Ignore subsequent updates of property1.
350: beanWithReadWriteProperty
351: .setReadWriteObjectProperty("newValue1b");
352: assertEquals("The connector must not update property2.",
353: newValue2, beanWithReadOnlyProperty
354: .getReadOnlyObjectProperty());
355: }
356:
357: }
|