001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.util.test;
023:
024: import java.beans.PropertyEditor;
025: import java.beans.PropertyEditorManager;
026: import java.io.File;
027: import java.net.InetAddress;
028: import java.net.URL;
029: import java.text.DateFormat;
030: import java.text.SimpleDateFormat;
031: import java.util.Calendar;
032: import java.util.Comparator;
033: import java.util.Date;
034: import java.util.Locale;
035: import java.util.Properties;
036: import java.util.TimeZone;
037:
038: import javax.management.ObjectName;
039:
040: import junit.framework.Test;
041: import junit.framework.TestSuite;
042:
043: import org.jboss.test.JBossTestCase;
044: import org.jboss.util.propertyeditor.DateEditor;
045: import org.jboss.util.propertyeditor.DocumentEditor;
046: import org.jboss.util.propertyeditor.ElementEditor;
047: import org.w3c.dom.Node;
048: import org.w3c.dom.NodeList;
049:
050: /**
051: * Unit tests for the custom JBoss property editors
052: *
053: * @see org.jboss.util.propertyeditor.PropertyEditors
054: *
055: * @author Scott.Stark@jboss.org
056: * @author Dimitris.Andreadis@jboss.org
057: * @version $Revision: 59596 $
058: */
059: public class PropertyEditorsUnitTestCase extends JBossTestCase {
060: Calendar calendar = Calendar.getInstance();
061:
062: /** Augment the PropertyEditorManager search path to incorporate the JBoss
063: specific editors. This simply references the PropertyEditors.class to
064: invoke its static initialization block.
065: */
066: static {
067: // Class c = org.jboss.util.propertyeditor.PropertyEditors.class;
068: // JBAS-3617 - on linux the above initializer doesn't work!
069: org.jboss.util.propertyeditor.PropertyEditors.init();
070: }
071:
072: static class StringArrayComparator implements Comparator {
073: public int compare(Object o1, Object o2) {
074: String[] a1 = (String[]) o1;
075: String[] a2 = (String[]) o2;
076: int compare = a1.length - a2.length;
077: for (int n = 0; n < a1.length; n++)
078: compare += a1[n].compareTo(a2[n]);
079: return compare;
080: }
081: }
082:
083: static class ClassArrayComparator implements Comparator {
084: public int compare(Object o1, Object o2) {
085: Class[] a1 = (Class[]) o1;
086: Class[] a2 = (Class[]) o2;
087: int compare = a1.length - a2.length;
088: for (int n = 0; n < a1.length; n++) {
089: int hash1 = a1[n].hashCode();
090: int hash2 = a2[n].hashCode();
091: compare += hash1 - hash2;
092: }
093: return compare;
094: }
095: }
096:
097: static class IntArrayComparator implements Comparator {
098: public int compare(Object o1, Object o2) {
099: int[] a1 = (int[]) o1;
100: int[] a2 = (int[]) o2;
101: int compare = a1.length - a2.length;
102: for (int n = 0; n < a1.length; n++)
103: compare += a1[n] - a2[n];
104: return compare;
105: }
106: }
107:
108: public static Test suite() throws Exception {
109: // JBAS-3617 - the execution order of tests in this test case is important
110: // so it must be defined explicitly when running under some JVMs
111: TestSuite suite = new TestSuite();
112: suite.addTest(new PropertyEditorsUnitTestCase(
113: "testEditorSearchPath"));
114: suite.addTest(new PropertyEditorsUnitTestCase(
115: "testJavaLangEditors"));
116: suite.addTest(new PropertyEditorsUnitTestCase(
117: "testJBossEditors"));
118: suite
119: .addTest(new PropertyEditorsUnitTestCase(
120: "testDateEditor"));
121: suite.addTest(new PropertyEditorsUnitTestCase(
122: "testDocumentElementEditors"));
123:
124: return suite;
125: }
126:
127: public PropertyEditorsUnitTestCase(String name) {
128: super (name);
129: }
130:
131: public void testEditorSearchPath() throws Exception {
132: getLog().debug("+++ testEditorSearchPath");
133: String[] searchPath = PropertyEditorManager
134: .getEditorSearchPath();
135: boolean foundJBossPath = false;
136: for (int p = 0; p < searchPath.length; p++) {
137: String path = searchPath[p];
138: getLog().debug("path[" + p + "]=" + path);
139: foundJBossPath |= path
140: .equals("org.jboss.util.propertyeditor");
141: }
142: assertTrue(
143: "Found org.jboss.util.propertyeditor in search path",
144: foundJBossPath);
145: }
146:
147: /** The mechanism for mapping java.lang.* variants of the primative types
148: misses editors for java.lang.Boolean and java.lang.Integer. Here we test
149: the java.lang.* variants we expect editors for.
150: **/
151: public void testJavaLangEditors() throws Exception {
152: getLog().debug("+++ testJavaLangEditors");
153: // The supported java.lang.* types
154: Class[] types = { Boolean.class, Byte.class, Short.class,
155: Integer.class, Long.class, Float.class, Double.class,
156: Byte.class, Character.class, };
157: // The input string data for each type
158: String[][] inputData = {
159: { "true", "false", "TRUE", "FALSE", "tRuE", "FaLsE",
160: null }, { "1", "-1", "0", "0x1A" },
161: { "1", "-1", "0", "0xA0" }, { "1", "-1", "0", "0xA0" },
162: { "1", "-1", "0", "1000" },
163: { "1", "-1", "0", "1000.1" },
164: { "1", "-1", "0", "1000.1" }, { "0x1", "-#1", "0" },
165: { "A", "a", "Z", "z" }, };
166: // The expected java.lang.* instance for each inputData value
167: Object[][] expectedData = {
168: { Boolean.TRUE, Boolean.FALSE, Boolean.TRUE,
169: Boolean.FALSE, Boolean.TRUE, Boolean.FALSE,
170: null },
171: { Byte.valueOf("1"), Byte.valueOf("-1"),
172: Byte.valueOf("0"), Byte.decode("0x1A") },
173: { Short.valueOf("1"), Short.valueOf("-1"),
174: Short.valueOf("0"), Short.decode("0xA0") },
175: { Integer.valueOf("1"), Integer.valueOf("-1"),
176: Integer.valueOf("0"), Integer.decode("0xA0") },
177: { Long.valueOf("1"), Long.valueOf("-1"),
178: Long.valueOf("0"), Long.valueOf("1000") },
179: { Float.valueOf("1"), Float.valueOf("-1"),
180: Float.valueOf("0"), Float.valueOf("1000.1") },
181: { Double.valueOf("1"), Double.valueOf("-1"),
182: Double.valueOf("0"), Double.valueOf("1000.1") },
183: { Byte.valueOf("1"), Byte.valueOf("-1"),
184: Byte.valueOf("0") },
185: { new Character('A'), new Character('a'),
186: new Character('Z'), new Character('z') }, };
187: // The expected string output from getAsText()
188: String[][] expectedStringData = {
189: { "true", "false", "true", "false", "true", "false",
190: "null" }, { "1", "-1", "0", "26" },
191: { "1", "-1", "0", "160" }, { "1", "-1", "0", "160" },
192: { "1", "-1", "0", "1000" },
193: { "1.0", "-1.0", "0.0", "1000.1" },
194: { "1.0", "-1.0", "0.0", "1000.1" }, { "1", "-1", "0" },
195: { "A", "a", "Z", "z" }, };
196: Comparator[] comparators = new Comparator[types.length];
197:
198: doTests(types, inputData, expectedData, expectedStringData,
199: comparators);
200: }
201:
202: /** Test custom JBoss property editors.
203: **/
204: public void testJBossEditors() throws Exception {
205: getLog().debug("+++ testJBossEditors");
206: Class[] types = { javax.management.ObjectName.class,
207: java.util.Properties.class, java.io.File.class,
208: java.net.URL.class, java.lang.String.class,
209: java.lang.Class.class, InetAddress.class,
210: String[].class, Class[].class, int[].class, Date.class };
211: // The input string data for each type
212: String[][] inputData = {
213: // javax.management.ObjectName.class
214: { "jboss.test:test=1" },
215: // java.util.Properties.class
216: { "prop1=value1\nprop2=value2\nprop3=value3\nprop32=${prop3}\nprop4=${user.home}\nprop5=${some.win32.path}" },
217: // java.io.File.class
218: { "/tmp/test1", "/tmp/subdir/../test2" },
219: // java.net.URL.class
220: { "http://www.jboss.org" },
221: // java.lang.String.class
222: { "JBoss, Home of Professional Open Source" },
223: // java.lang.Class.class
224: { "java.util.Arrays" },
225: // InetAddress.class, localhost must be defined for this to work
226: { "127.0.0.1", "localhost" },
227: // String[].class
228: { "1,2,3", "a,b,c", "", "#,%,\\,,.,_$,\\,v" },
229: // Class[].class
230: { "java.lang.Integer,java.lang.Float" },
231: // int[].class
232: { "0,#123,-123" },
233: // Date.class
234: { "Jan 4, 2005", "Tue Jan 4 23:38:21 PST 2005",
235: "Tue, 04 Jan 2005 23:38:48 -0800" } };
236: // The expected instance for each inputData value
237: calendar.set(2005, 0, 4, 0, 0, 0);
238: calendar.set(Calendar.MILLISECOND, 0);
239: Date date1 = calendar.getTime();
240: calendar.setTimeZone(TimeZone.getTimeZone("PST"));
241: calendar.set(2005, 0, 4, 23, 38, 21);
242: Date date2 = calendar.getTime();
243: calendar.set(2005, 0, 4, 23, 38, 48);
244: Date date3 = calendar.getTime();
245: Properties props = new Properties();
246: props.setProperty("prop1", "value1");
247: props.setProperty("prop2", "value2");
248: props.setProperty("prop3", "value3");
249: props.setProperty("prop32", "value3");
250: props.setProperty("prop4", System.getProperty("user.home"));
251: System.setProperty("some.win32.path", "C:\\disk1\\root\\");
252: props.setProperty("prop5", "C:\\disk1\\root\\");
253: Object[][] expectedData = {
254: { new ObjectName("jboss.test:test=1") },
255: { props },
256: { new File("/tmp/test1").getCanonicalFile(),
257: new File("/tmp/test2").getCanonicalFile() },
258: { new URL("http://www.jboss.org") },
259: { new String("JBoss, Home of Professional Open Source") },
260: { java.util.Arrays.class },
261: { InetAddress.getByName("127.0.0.1"),
262: InetAddress.getByName("localhost") },
263: { new String[] { "1", "2", "3" },
264: new String[] { "a", "b", "c" },
265: new String[] {},
266: new String[] { "#", "%", ",", ".", "_$", ",v" } },
267: { new Class[] { Integer.class, Float.class } },
268: { new int[] { 0, 0x123, -123 } },
269: { date1, date2, date3 } };
270: // The expected string output from getAsText()
271: String[][] expectedStringData = {
272: // javax.management.ObjectName.class
273: { "jboss.test:test=1" },
274: // java.util.Properties.class
275: { "prop1=value1\nprop2=value2\nprop3=value3\nprop32=${prop3}\nprop4=${user.home}\nprop5=${some.win32.path}" },
276: // java.io.File.class
277: { "/tmp/test1", "/tmp/subdir/../test2" },
278: // java.net.URL.class
279: { "http://www.jboss.org" },
280: // java.lang.String.class
281: { "JBoss, Home of Professional Open Source" },
282: // java.lang.Class.class
283: { "java.util.Arrays" },
284: // InetAddress.class, localhost must be defined for this to work
285: { "127.0.0.1", "localhost" },
286: // String[].class
287: { "1,2,3", "a,b,c", "", "#,%,\\,,.,_$,,v" },
288: // Class[].class
289: { "java.lang.Integer,java.lang.Float" },
290: // int[].class
291: { "0,291,-123" },
292: // Date.class
293: { "Jan 4, 2005", "Tue Jan 4 23:38:21 PST 2005",
294: "Tue, 04 Jan 2005 23:38:48 -0800" } };
295: // The Comparator for non-trival types
296: Comparator[] comparators = { null, // ObjectName
297: null, // Properties
298: null, // File
299: null, // URL
300: null, // String
301: null, // Class
302: null, // InetAddress
303: new StringArrayComparator(), // String[]
304: new ClassArrayComparator(), // Class[]
305: new IntArrayComparator(), // int[]
306: null // Date
307: };
308:
309: doTests(types, inputData, expectedData, expectedStringData,
310: comparators);
311: }
312:
313: public void testDateEditor() throws Exception {
314: getLog().debug("+++ testDateEditor");
315:
316: Locale locale = Locale.getDefault();
317:
318: try {
319: // Use the default locale
320: getLog().debug("Current Locale: " + Locale.getDefault());
321:
322: // An important date
323: String text = "Fri, 25 Jun 1971 00:30:00 +0200";
324: DateFormat format = new SimpleDateFormat(
325: "EEE, d MMM yyyy HH:mm:ss Z");
326: Date date = format.parse(text);
327:
328: PropertyEditor editor = new DateEditor();
329: editor.setAsText(text);
330: getLog().debug(
331: "setAsText('" + text + "') --> getValue() = '"
332: + editor.getValue() + "'");
333: assertTrue("Compare date1: " + date + ", date2: "
334: + editor.getValue(), date.compareTo((Date) editor
335: .getValue()) == 0);
336:
337: editor.setValue(date);
338: getLog().debug(
339: "setValue('" + date + "') --> getAsText() - '"
340: + editor.getAsText() + "'");
341: Date date2 = format.parse(editor.getAsText());
342: assertTrue("Compare date1: " + date + ", date2: " + date2,
343: date.compareTo(date2) == 0);
344:
345: // Try in French
346: Locale.setDefault(Locale.FRENCH);
347: getLog().debug("Current Locale: " + Locale.getDefault());
348: DateEditor.initialize();
349:
350: // An important date
351: text = "ven., 25 juin 1971 00:30:00 +0200";
352: format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
353: date = format.parse(text);
354:
355: editor = new DateEditor();
356: editor.setAsText(text);
357: getLog().debug(
358: "setAsText('" + text + "') --> getValue() = '"
359: + editor.getValue() + "'");
360: assertTrue("Compare date1: " + date + ", date2: "
361: + editor.getValue(), date.compareTo((Date) editor
362: .getValue()) == 0);
363:
364: editor.setValue(date);
365: getLog().debug(
366: "setValue('" + date + "') --> getAsText() = '"
367: + editor.getAsText() + "'");
368: date2 = format.parse(editor.getAsText());
369: assertTrue("Compare date1: " + date + ", date2: " + date2,
370: date.compareTo(date2) == 0);
371: } finally {
372: // reset locale
373: Locale.setDefault(locale);
374: DateEditor.initialize();
375: }
376: }
377:
378: /**
379: * Tests the DOM Document and Element editors.
380: */
381: public void testDocumentElementEditors() {
382: getLog().debug("+++ testDocumentElementEditors");
383: DocumentEditor de = new DocumentEditor();
384: // Comments can appear outside of a document
385: String s = "<!-- header comment --><doc name='whatever'/><!-- footer comment -->";
386: getLog().debug("setAsText '" + s + "'");
387: de.setAsText(s);
388: getLog().debug("Parsed XML document:");
389: log((Node) de.getValue(), " ");
390: getLog().debug("getAsText '" + de.getAsText() + "'");
391: assertTrue("Document :\n" + de.getAsText(), de.getAsText()
392: .trim().endsWith(s));
393: assertTrue(de.getValue() instanceof org.w3c.dom.Document);
394: // Test whitespace preservation
395: s = "<element>\n\n<e2/> testing\n\n</element>";
396: de.setAsText(s);
397: assertTrue("Document :\n" + de.getAsText() + "\nvs\n" + s, de
398: .getAsText().trim().endsWith(s));
399:
400: ElementEditor ee = new ElementEditor();
401: s = "<element>text</element>";
402: ee.setAsText(s);
403: assertEquals(s, ee.getAsText());
404: assertTrue(ee.getValue() instanceof org.w3c.dom.Element);
405: }
406:
407: private void doTests(Class[] types, String[][] inputData,
408: Object[][] expectedData, String[][] expectedStringData,
409: Comparator[] comparators) {
410: for (int t = 0; t < types.length; t++) {
411: Class type = types[t];
412: getLog().debug("Checking property editor for: " + type);
413: PropertyEditor editor = PropertyEditorManager
414: .findEditor(type);
415: assertTrue("Found property editor for: " + type,
416: editor != null);
417: getLog().debug(
418: "Found property editor for: " + type + ", editor="
419: + editor.getClass().getName());
420: assertTrue("inputData.length == expectedData.length",
421: inputData[t].length == expectedData[t].length);
422: for (int i = 0; i < inputData[t].length; i++) {
423: String input = inputData[t][i];
424: editor.setAsText(input);
425: Object expected = expectedData[t][i];
426: Object output = editor.getValue();
427: Comparator c = comparators[t];
428: boolean equals = false;
429: if (c == null) {
430: equals = output != null ? output.equals(expected)
431: : expected == null;
432: } else {
433: equals = c.compare(output, expected) == 0;
434: }
435: assertTrue("Transform of " + input + " equals "
436: + expected + ", output=" + output, equals);
437:
438: String expectedStringOutput = expectedStringData[t][i];
439: String stringOutput = editor.getAsText();
440: getLog().debug("setAsText '" + logString(input) + "'");
441: getLog().debug(
442: "getAsText '" + logString(stringOutput) + "'");
443:
444: boolean stringOutputEquals = stringOutput != null ? stringOutput
445: .equals(expectedStringOutput)
446: : expectedStringOutput == null;
447: assertTrue("PropertyEditor: "
448: + editor.getClass().getName()
449: + ", getAsText() == expectedStringOutput '"
450: + logString(expectedStringOutput) + "'",
451: stringOutputEquals);
452: }
453: }
454: }
455:
456: /**
457: * Log a Node hierarchy
458: */
459: private void log(Node node, String indent) {
460: String name = node.getNodeName();
461: String value = node.getNodeValue();
462: getLog().debug(indent + "Name=" + name + ", Value=" + value);
463: NodeList list = node.getChildNodes();
464: for (int i = 0; i < list.getLength(); i++)
465: log(list.item(i), indent + indent);
466: }
467:
468: private static String logString(String s) {
469: return s != null ? s : "<null>";
470: }
471: }
|