001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * If you wish your version of this file to be governed by only the CDDL
025: * or only the GPL Version 2, indicate your decision by adding
026: * "[Contributor] elects to include this software in this distribution
027: * under the [CDDL or GPL Version 2] license." If you do not indicate a
028: * single choice of license, a recipient has the option to distribute
029: * your version of this file under either the CDDL, the GPL Version 2 or
030: * to extend the choice of license to its licensees as provided above.
031: * However, if you add GPL Version 2 code and therefore, elected the GPL
032: * Version 2 license, then the option applies only if the new code is
033: * made subject to such option by the copyright holder.
034: *
035: * Contributor(s):
036: *
037: * Portions Copyrighted 2007 Sun Microsystems, Inc.
038: */
039:
040: package org.netbeans.modules.visualweb.dataprovider;
041:
042: import com.sun.data.provider.FieldKey;
043: import com.sun.data.provider.DataProvider;
044: import com.sun.data.provider.DataListener;
045: import com.sun.data.provider.impl.ObjectDataProvider;
046: import java.io.ByteArrayInputStream;
047: import java.io.ByteArrayOutputStream;
048: import java.io.ObjectInputStream;
049: import java.io.ObjectOutputStream;
050: import java.util.List;
051: import java.util.Map;
052: import org.netbeans.junit.NbTestCase;
053:
054: /**
055: * <p>Unit tests for {@link ObjectDataProvider}.</p>
056: */
057: public class ObjectDataProviderTest extends NbTestCase {
058:
059: // ------------------------------------------------------ Instance Variables
060:
061: /**
062: * <p>The bean being wrapped by the {@link DataProvider} under test.
063: */
064: private TestBean bean = null;
065:
066: /**
067: * <p>The {@link DataProvider} instance under test.
068: */
069: private ObjectDataProvider dp = null;
070:
071: /**
072: * <p>Event listener for event testing.</p>
073: */
074: private Listener listener = null;
075:
076: // -------------------------------------------------------- Static Variables
077:
078: // Dummy variables just to provide access to type information
079: private static int intArray[] = new int[0];
080: private static TestBean nestedArray[] = new TestBean[0];
081:
082: /**
083: * <p>Descriptors for the set of fieldKeys we expect to be known.</p>
084: */
085: private static Descriptor[] fieldKeys = {
086: // Specific fieldKeys of this class
087: new Descriptor("public1", String.class, false,
088: "This is public1"),
089: new Descriptor("public2", Integer.class, false,
090: new Integer(8888)), };
091:
092: /**
093: * <p>Descriptors for the set of properties we expect to be known.</p>
094: */
095: private static Descriptor[] properties = {
096: // Specific properties of this class
097: new Descriptor("booleanProperty", Boolean.class, false,
098: Boolean.TRUE),
099: new Descriptor("byteProperty", Byte.class, false, new Byte(
100: (byte) 123)),
101: new Descriptor("doubleProperty", Double.class, false,
102: new Double(654.321)),
103: new Descriptor("floatProperty", Float.class, false,
104: new Float((float) 123.45)),
105: new Descriptor("id", String.class, false, null),
106: new Descriptor("intArray", intArray.getClass(), false, null),
107: new Descriptor("intList", List.class, false, null),
108: new Descriptor("intProperty", Integer.class, false,
109: new Integer(1234)),
110: new Descriptor("longProperty", Long.class, false, new Long(
111: 54321)),
112: new Descriptor("nestedArray", nestedArray.getClass(),
113: false, null),
114: new Descriptor("nestedList", List.class, false, null),
115: new Descriptor("nestedMap", Map.class, false, null),
116: new Descriptor("nestedProperty", TestBean.class, false,
117: null),
118: new Descriptor("readOnly", String.class, true, null),
119: new Descriptor("shortProperty", Short.class, false,
120: new Short((short) 321)),
121: new Descriptor("stringProperty", String.class, false,
122: "This is a String"),
123: new Descriptor("nullString", String.class, true, null),
124: // Inherited from java.lang.Object
125: new Descriptor("class", Class.class, true, null), };
126:
127: /**
128: * <p>Descriptors for updates that should be applied and tested.</p>
129: */
130: private static Update[] updates = {
131: // Updates to read-write properties
132: new Update("booleanProperty", Boolean.FALSE),
133: new Update("byteProperty", new Byte((byte) 213)),
134: new Update("doubleProperty", new Double(123.456)),
135: new Update("floatProperty", new Float((float) 111.22)),
136: new Update("intProperty", new Integer(23432)),
137: new Update("longProperty", new Long((long) 55555)),
138: new Update("shortProperty", new Short((short) 123)),
139: new Update("stringProperty", "Updated string value"),
140: // Public fieldKeys are read-write as well
141: new Update("public1", "revised String1 value"),
142: new Update("public2", new Integer(55555)), };
143:
144: // ------------------------------------------------------------ Constructors
145:
146: /**
147: * <p>Construct a new test case instance.</p>
148: */
149: public ObjectDataProviderTest(String name) {
150: super (name);
151: }
152:
153: // ---------------------------------------------------- Overall Test Methods
154:
155: /**
156: * <p>Set up the instance to be tested.</p>
157: */
158: @Override
159: public void setUp() {
160: bean = new TestBean("test");
161: dp = new ObjectDataProvider(bean, true);
162: }
163:
164: /**
165: * <p>Tear down the instance from the previous test.</p>
166: */
167: @Override
168: public void tearDown() {
169: dp = null;
170: bean = null;
171: }
172:
173: // ------------------------------------------------- Individual Test Methods
174:
175: /**
176: * <p>Check convenience methods on abstract base class that
177: * should still show through the concrete implementation.</p>
178: */
179: public void testBaseClassMethods() {
180:
181: // Operate on FieldKey or field identifier
182: for (int i = 0; i < properties.length; i++) {
183: String fieldId = properties[i].name;
184: FieldKey fieldKey = dp.getFieldKey(fieldId);
185: assertEquals("type(" + fieldId + ")", dp.getType(fieldKey),
186: dp.getType(fieldId));
187: assertEquals("value(" + fieldId + ")", dp
188: .getValue(fieldKey), dp.getValue(fieldId));
189: assertEquals("readOnly(" + fieldId + ")", dp
190: .isReadOnly(fieldKey), dp.isReadOnly(fieldId));
191: }
192:
193: }
194:
195: /**
196: * <p>Check for event propogation.</p>
197: */
198: public void testEvents() {
199:
200: assertNotNull(dp.getFieldKey("intProperty"));
201: assertNotNull(dp.getFieldKey("public1"));
202:
203: // Register a new listener and verify that it worked
204: listener = new Listener();
205: dp.addDataListener(listener);
206: DataListener listeners[] = dp.getDataListeners();
207: assertEquals(1, listeners.length);
208: assertTrue(listener == listeners[0]);
209:
210: // Make sure we log the update events correctly
211: dp.setValue(dp.getFieldKey("intProperty"), new Integer(23432));
212: dp.setValue(dp.getFieldKey("public1"), "new public1");
213: assertEquals(
214: "intProperty/1234/23432//public1/This is public1/new public1//",
215: listener.getLog());
216:
217: // Deregister the old listener and verify that it worked
218: dp.removeDataListener(listener);
219: listeners = dp.getDataListeners();
220: assertEquals(0, listeners.length);
221:
222: }
223:
224: /**
225: * <p>Check some things that should <strong>not</strong> work.</p>
226: */
227: public void testNegative() {
228:
229: // Access to unknown fieldKey/property
230: try {
231: dp.getFieldKey("unknown id value");
232: fail("Should have thrown IllegalArgumentException");
233: } catch (IllegalArgumentException e) {
234: ; // Expected result
235: }
236:
237: // Attempt to update a read only value
238: try {
239: dp.setValue(dp.getFieldKey("readOnly"), "xyz");
240: fail("Should have thrown IllegalStateException");
241: } catch (IllegalStateException e) {
242: ; // Expected result
243: }
244:
245: // Attempt to set value with an incorrect data type
246: try {
247: dp.setValue(dp.getFieldKey("intProperty"), "string value");
248: fail("Should have thrown IllegalArgumentException");
249: } catch (IllegalArgumentException e) {
250: ; // Expected result
251: }
252:
253: }
254:
255: /**
256: * <p>Ensure that access to public fields can be turned off.</p>
257: */
258: public void testNoFields() {
259:
260: dp = new ObjectDataProvider(bean, false);
261: try {
262: dp.getFieldKey("public1");
263: fail("Should have thrown IllegalArgumentException");
264: } catch (IllegalArgumentException e) {
265: ; // Expected result
266: }
267: try {
268: dp.getFieldKey("public2");
269: fail("Should have thrown IllegalArgumentException");
270: } catch (IllegalArgumentException e) {
271: ; // Expected result
272: }
273:
274: // Check the available properties for expected characteristics
275: checkProperties();
276: checkExtras();
277:
278: }
279:
280: /**
281: * <p>Test a pristine instance.</p>
282: */
283: public void testPristine() {
284:
285: assertEquals("test", ((TestBean) dp.getObject()).getId());
286:
287: // Check the available fieldKeys and properties for expected characteristics
288: checkFields();
289: checkProperties();
290: checkExtras();
291:
292: }
293:
294: /**
295: * <p>Test updates to updateable fieldKeys and properties.</p>
296: */
297: public void testUpdates() {
298:
299: // Do the easy cases
300: checkUpdates();
301:
302: }
303:
304: /**
305: * <p>Test serializability of this data provider.</p>
306: */
307: public void testSerializable() throws Exception {
308:
309: ByteArrayOutputStream baos = new ByteArrayOutputStream();
310: ObjectOutputStream oos = new ObjectOutputStream(baos);
311: oos.writeObject(dp);
312: oos.close();
313: ByteArrayInputStream bais = new ByteArrayInputStream(baos
314: .toByteArray());
315: ObjectInputStream ois = new ObjectInputStream(bais);
316: dp = (ObjectDataProvider) ois.readObject();
317: ois.close();
318:
319: testPristine();
320:
321: }
322:
323: // --------------------------------------------------------- Support Methods
324:
325: /**
326: * <p>Ensure that the array returned by <code>getFieldKeys()</code>
327: * does not include any keys that should not be there.</p>
328: */
329: private void checkExtras() {
330:
331: FieldKey keys[] = dp.getFieldKeys();
332: assertNotNull(keys);
333: for (int i = 0; i < keys.length; i++) {
334: String name = keys[i].getFieldId();
335: boolean found = false;
336: for (int j = 0; j < properties.length; j++) {
337: if (name.equals(properties[j].name)) {
338: found = true;
339: break;
340: }
341: }
342: if (!found && dp.isIncludeFields()) {
343: for (int j = 0; j < fieldKeys.length; j++) {
344: if (name.equals(fieldKeys[j].name)) {
345: found = true;
346: break;
347: }
348: }
349: }
350: assertTrue("Id '" + name + "' is valid", found);
351: }
352:
353: }
354:
355: /**
356: * <p>Ensure that all the expected fieldKeys are present and have
357: * the specified default values (where possible).</p>
358: */
359: private void checkFields() {
360:
361: FieldKey dk = null;
362: String name = null;
363: for (int i = 0; i < fieldKeys.length; i++) {
364: name = fieldKeys[i].name;
365: dk = dp.getFieldKey(name);
366: assertNotNull("FieldKey for '" + name + "'", dk);
367: assertTrue("Type for '" + name + "'", isAssignableFrom(dp
368: .getType(dk), fieldKeys[i].type));
369: assertEquals("ReadOnly for '" + name + "'",
370: fieldKeys[i].canSetValue, dp.isReadOnly(dk));
371: if (fieldKeys[i].defaultValue != null) {
372: assertEquals("Value for '" + name + "'",
373: fieldKeys[i].defaultValue, dp.getValue(dk));
374: }
375: }
376:
377: }
378:
379: /**
380: * <p>Ensure that all the expected properties are present and have
381: * the specified default values (where possible).</p>
382: */
383: private void checkProperties() {
384:
385: FieldKey dk = null;
386: String name = null;
387: for (int i = 0; i < properties.length; i++) {
388: name = properties[i].name;
389: dk = dp.getFieldKey(name);
390: assertNotNull("FieldKey for '" + name + "'", dk);
391: assertTrue("Type for '" + name + "'", isAssignableFrom(dp
392: .getType(dk), properties[i].type));
393: assertEquals("ReadOnly for '" + name + "'",
394: properties[i].canSetValue, dp.isReadOnly(dk));
395: if (properties[i].defaultValue != null) {
396: assertEquals("Value for '" + name + "'",
397: properties[i].defaultValue, dp.getValue(dk));
398: }
399: }
400:
401: }
402:
403: private boolean isAssignableFrom(Class to, Class from) {
404: if (to.isPrimitive()) {
405: if (to == Boolean.TYPE)
406: to = Boolean.class;
407: else if (to == Character.TYPE)
408: to = Character.class;
409: else if (to == Byte.TYPE)
410: to = Byte.class;
411: else if (to == Short.TYPE)
412: to = Short.class;
413: else if (to == Integer.TYPE)
414: to = Integer.class;
415: else if (to == Long.TYPE)
416: to = Long.class;
417: else if (to == Float.TYPE)
418: to = Float.class;
419: else if (to == Double.TYPE)
420: to = Double.class;
421: }
422: return to.isAssignableFrom(from);
423: }
424:
425: /**
426: * <p>Ensure that we can update all the simple fieldKeys and properties
427: * that should be updatable by default.</p>
428: */
429: private void checkUpdates() {
430:
431: FieldKey dk = null;
432: String name = null;
433: for (int i = 0; i < updates.length; i++) {
434: name = updates[i].name;
435: try {
436: dp.setValue(dp.getFieldKey(name), updates[i].value);
437: } catch (Exception e) {
438: fail("Cannot set value for '" + name + "':" + e);
439: }
440: assertEquals("Updated value for '" + name + "'",
441: updates[i].value, dp.getValue(dp.getFieldKey(name)));
442: }
443:
444: }
445:
446: // Private class to describe the expected properties
447: static class Descriptor {
448: public Descriptor(String name, Class type, boolean canSetValue,
449: Object defaultValue) {
450: this .name = name;
451: this .type = type;
452: this .canSetValue = canSetValue;
453: this .defaultValue = defaultValue;
454: }
455:
456: public String name;
457: public Class type;
458: public boolean canSetValue;
459: public Object defaultValue;
460: }
461:
462: // Private class to represent an event listener
463: static class Listener implements DataListener {
464: String log = "";
465:
466: public String getLog() {
467: return this .log;
468: }
469:
470: public void clear() {
471: this .log = "";
472: }
473:
474: public void valueChanged(DataProvider dp, FieldKey dk,
475: Object oldValue, Object newValue) {
476: log += dk.getFieldId() + "/" + oldValue + "/" + newValue
477: + "//";
478: }
479:
480: public void providerChanged(DataProvider dp) {
481: log += "providerChanged//";
482: }
483: }
484:
485: // Private class to describe updates to be performed and checked
486: static class Update {
487: public Update(String name, Object value) {
488: this .name = name;
489: this .value = value;
490: }
491:
492: public String name;
493: public Object value;
494: }
495:
496: }
|