/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.util.test;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.File;
import java.net.InetAddress;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import javax.management.ObjectName;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jboss.test.JBossTestCase;
import org.jboss.util.propertyeditor.DateEditor;
import org.jboss.util.propertyeditor.DocumentEditor;
import org.jboss.util.propertyeditor.ElementEditor;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Unit tests for the custom JBoss property editors
*
* @see org.jboss.util.propertyeditor.PropertyEditors
*
* @author Scott.Stark@jboss.org
* @author Dimitris.Andreadis@jboss.org
* @version $Revision: 59598 $
*/
public class PropertyEditorsUnitTestCase extends JBossTestCase
{
Calendar calendar = Calendar.getInstance();
/** Augment the PropertyEditorManager search path to incorporate the JBoss
specific editors. This simply references the PropertyEditors.class to
invoke its static initialization block.
*/
static
{
// Class c = org.jboss.util.propertyeditor.PropertyEditors.class;
// JBAS-3617 - on linux the above initializer doesn't work!
org.jboss.util.propertyeditor.PropertyEditors.init();
}
static class StringArrayComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
String[] a1 = (String[]) o1;
String[] a2 = (String[]) o2;
int compare = a1.length - a2.length;
for(int n = 0; n < a1.length; n ++)
compare += a1[n].compareTo(a2[n]);
return compare;
}
}
static class ClassArrayComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
Class[] a1 = (Class[]) o1;
Class[] a2 = (Class[]) o2;
int compare = a1.length - a2.length;
for(int n = 0; n < a1.length; n ++)
{
int hash1 = a1[n].hashCode();
int hash2 = a2[n].hashCode();
compare += hash1 - hash2;
}
return compare;
}
}
static class IntArrayComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
int[] a1 = (int[]) o1;
int[] a2 = (int[]) o2;
int compare = a1.length - a2.length;
for(int n = 0; n < a1.length; n ++)
compare += a1[n] - a2[n];
return compare;
}
}
public static Test suite() throws Exception
{
// JBAS-3617 - the execution order of tests in this test case is important
// so it must be defined explicitly when running under some JVMs
TestSuite suite = new TestSuite();
suite.addTest(new PropertyEditorsUnitTestCase("testEditorSearchPath"));
suite.addTest(new PropertyEditorsUnitTestCase("testJavaLangEditors"));
suite.addTest(new PropertyEditorsUnitTestCase("testJBossEditors"));
suite.addTest(new PropertyEditorsUnitTestCase("testDateEditor"));
suite.addTest(new PropertyEditorsUnitTestCase("testDocumentElementEditors"));
return suite;
}
public PropertyEditorsUnitTestCase(String name)
{
super(name);
}
public void testEditorSearchPath()
throws Exception
{
getLog().debug("+++ testEditorSearchPath");
String[] searchPath = PropertyEditorManager.getEditorSearchPath();
boolean foundJBossPath = false;
for(int p = 0; p < searchPath.length; p ++)
{
String path = searchPath[p];
getLog().debug("path["+p+"]="+path);
foundJBossPath |= path.equals("org.jboss.util.propertyeditor");
}
assertTrue("Found org.jboss.util.propertyeditor in search path", foundJBossPath);
}
/** The mechanism for mapping java.lang.* variants of the primative types
misses editors for java.lang.Boolean and java.lang.Integer. Here we test
the java.lang.* variants we expect editors for.
**/
public void testJavaLangEditors()
throws Exception
{
getLog().debug("+++ testJavaLangEditors");
// The supported java.lang.* types
Class[] types = {
Boolean.class,
Byte.class,
Short.class,
Integer.class,
Long.class,
Float.class,
Double.class,
Byte.class,
Character.class,
};
// The input string data for each type
String[][] inputData = {
{"true", "false", "TRUE", "FALSE", "tRuE", "FaLsE", null},
{"1", "-1", "0", "0x1A"},
{"1", "-1", "0", "0xA0"},
{"1", "-1", "0", "0xA0"},
{"1", "-1", "0", "1000"},
{"1", "-1", "0", "1000.1"},
{"1", "-1", "0", "1000.1"},
{"0x1", "-#1", "0"},
{"A", "a", "Z", "z"},
};
// The expected java.lang.* instance for each inputData value
Object[][] expectedData = {
{Boolean.TRUE, Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, null},
{Byte.valueOf("1"), Byte.valueOf("-1"), Byte.valueOf("0"), Byte.decode("0x1A")},
{Short.valueOf("1"), Short.valueOf("-1"), Short.valueOf("0"), Short.decode("0xA0")},
{Integer.valueOf("1"), Integer.valueOf("-1"), Integer.valueOf("0"), Integer.decode("0xA0")},
{Long.valueOf("1"), Long.valueOf("-1"), Long.valueOf("0"), Long.valueOf("1000")},
{Float.valueOf("1"), Float.valueOf("-1"), Float.valueOf("0"), Float.valueOf("1000.1")},
{Double.valueOf("1"), Double.valueOf("-1"), Double.valueOf("0"), Double.valueOf("1000.1")},
{Byte.valueOf("1"), Byte.valueOf("-1"), Byte.valueOf("0")},
{new Character('A'), new Character('a'), new Character('Z'), new Character('z')},
};
// The expected string output from getAsText()
String[][] expectedStringData = {
{"true", "false", "true", "false", "true", "false", "null"},
{"1", "-1", "0", "26"},
{"1", "-1", "0", "160"},
{"1", "-1", "0", "160"},
{"1", "-1", "0", "1000"},
{"1.0", "-1.0", "0.0", "1000.1"},
{"1.0", "-1.0", "0.0", "1000.1"},
{"1", "-1", "0"},
{"A", "a", "Z", "z"},
};
Comparator[] comparators = new Comparator[types.length];
doTests(types, inputData, expectedData, expectedStringData, comparators);
}
/** Test custom JBoss property editors.
**/
public void testJBossEditors()
throws Exception
{
getLog().debug("+++ testJBossEditors");
Class[] types = {
javax.management.ObjectName.class,
java.util.Properties.class,
java.io.File.class,
java.net.URL.class,
java.lang.String.class,
java.lang.Class.class,
InetAddress.class,
String[].class,
Class[].class,
int[].class,
Date.class
};
// The input string data for each type
String[][] inputData = {
// javax.management.ObjectName.class
{"jboss.test:test=1"},
// java.util.Properties.class
{"prop1=value1\nprop2=value2\nprop3=value3\nprop32=${prop3}\nprop4=${user.home}\nprop5=${some.win32.path}"},
// java.io.File.class
{"/tmp/test1", "/tmp/subdir/../test2"},
// java.net.URL.class
{"http://www.jboss.org"},
// java.lang.String.class
{"JBoss, Home of Professional Open Source"},
// java.lang.Class.class
{"java.util.Arrays"},
// InetAddress.class, localhost must be defined for this to work
{"127.0.0.1", "localhost"},
// String[].class
{"1,2,3", "a,b,c", "", "#,%,\\,,.,_$,\\,v"},
// Class[].class
{"java.lang.Integer,java.lang.Float"},
// int[].class
{"0,#123,-123"},
// Date.class
{"Jan 4, 2005", "Tue Jan 4 23:38:21 PST 2005", "Tue, 04 Jan 2005 23:38:48 -0800"}
};
// The expected instance for each inputData value
calendar.set(2005, 0, 4, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date date1 = calendar.getTime();
calendar.setTimeZone(TimeZone.getTimeZone("PST"));
calendar.set(2005, 0, 4, 23, 38, 21);
Date date2 = calendar.getTime();
calendar.set(2005, 0, 4, 23, 38, 48);
Date date3 = calendar.getTime();
Properties props = new Properties();
props.setProperty("prop1", "value1");
props.setProperty("prop2", "value2");
props.setProperty("prop3", "value3");
props.setProperty("prop32", "value3");
props.setProperty("prop4", System.getProperty("user.home"));
System.setProperty("some.win32.path", "C:\\disk1\\root\\");
props.setProperty("prop5", "C:\\disk1\\root\\");
Object[][] expectedData = {
{new ObjectName("jboss.test:test=1")},
{props},
{new File("/tmp/test1").getCanonicalFile(), new File("/tmp/test2").getCanonicalFile()},
{new URL("http://www.jboss.org")},
{new String("JBoss, Home of Professional Open Source")},
{java.util.Arrays.class},
{InetAddress.getByName("127.0.0.1"), InetAddress.getByName("localhost")},
{new String[]{"1", "2", "3"}, new String[] {"a", "b", "c"},
new String[]{}, new String[]{"#","%",",",".","_$", ",v"}},
{new Class[]{Integer.class, Float.class}},
{new int[]{0, 0x123, -123}},
{date1, date2, date3}
};
// The expected string output from getAsText()
String[][] expectedStringData = {
// javax.management.ObjectName.class
{"jboss.test:test=1"},
// java.util.Properties.class
{"prop1=value1\nprop2=value2\nprop3=value3\nprop32=${prop3}\nprop4=${user.home}\nprop5=${some.win32.path}"},
// java.io.File.class
{"/tmp/test1", "/tmp/subdir/../test2"},
// java.net.URL.class
{"http://www.jboss.org"},
// java.lang.String.class
{"JBoss, Home of Professional Open Source"},
// java.lang.Class.class
{"java.util.Arrays"},
// InetAddress.class, localhost must be defined for this to work
{"127.0.0.1", "localhost"},
// String[].class
{"1,2,3", "a,b,c", "", "#,%,\\,,.,_$,,v"},
// Class[].class
{"java.lang.Integer,java.lang.Float"},
// int[].class
{"0,291,-123"},
// Date.class
{"Jan 4, 2005", "Tue Jan 4 23:38:21 PST 2005", "Tue, 04 Jan 2005 23:38:48 -0800"}
};
// The Comparator for non-trival types
Comparator[] comparators = {
null, // ObjectName
null, // Properties
null, // File
null, // URL
null, // String
null, // Class
null, // InetAddress
new StringArrayComparator(), // String[]
new ClassArrayComparator(), // Class[]
new IntArrayComparator(), // int[]
null // Date
};
doTests(types, inputData, expectedData, expectedStringData, comparators);
}
public void testDateEditor() throws Exception
{
getLog().debug("+++ testDateEditor");
Locale locale = Locale.getDefault();
try
{
// Use the default locale
getLog().debug("Current Locale: " + Locale.getDefault());
// An important date
String text = "Fri, 25 Jun 1971 00:30:00 +0200";
DateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
Date date = format.parse(text);
PropertyEditor editor = new DateEditor();
editor.setAsText(text);
getLog().debug("setAsText('" + text + "') --> getValue() = '" + editor.getValue() + "'");
assertTrue("Compare date1: " + date + ", date2: " + editor.getValue(),
date.compareTo((Date)editor.getValue()) == 0);
editor.setValue(date);
getLog().debug("setValue('" + date + "') --> getAsText() - '" + editor.getAsText() + "'");
Date date2 = format.parse(editor.getAsText());
assertTrue("Compare date1: " + date + ", date2: " + date2,
date.compareTo(date2) == 0);
// Try in French
Locale.setDefault(Locale.FRENCH);
getLog().debug("Current Locale: " + Locale.getDefault());
DateEditor.initialize();
// An important date
text = "ven., 25 juin 1971 00:30:00 +0200";
format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
date = format.parse(text);
editor = new DateEditor();
editor.setAsText(text);
getLog().debug("setAsText('" + text + "') --> getValue() = '" + editor.getValue() + "'");
assertTrue("Compare date1: " + date + ", date2: " + editor.getValue(),
date.compareTo((Date)editor.getValue()) == 0);
editor.setValue(date);
getLog().debug("setValue('" + date + "') --> getAsText() = '" + editor.getAsText() + "'");
date2 = format.parse(editor.getAsText());
assertTrue("Compare date1: " + date + ", date2: " + date2,
date.compareTo(date2) == 0);
}
finally
{
// reset locale
Locale.setDefault(locale);
DateEditor.initialize();
}
}
/**
* Tests the DOM Document and Element editors.
*/
public void testDocumentElementEditors()
{
getLog().debug("+++ testDocumentElementEditors");
DocumentEditor de = new DocumentEditor();
// Comments can appear outside of a document
String s = "<!-- header comment --><doc name='whatever'/><!-- footer comment -->";
getLog().debug("setAsText '" + s + "'");
de.setAsText(s);
getLog().debug("Parsed XML document:");
log((Node)de.getValue(), " ");
getLog().debug("getAsText '" + de.getAsText() + "'");
assertTrue("Document :\n" + de.getAsText(), de.getAsText().trim().endsWith(s));
assertTrue(de.getValue() instanceof org.w3c.dom.Document);
// Test whitespace preservation
s = "<element>\n\n<e2/> testing\n\n</element>";
de.setAsText(s);
assertTrue("Document :\n" + de.getAsText() + "\nvs\n" + s, de.getAsText().trim().endsWith(s));
ElementEditor ee = new ElementEditor();
s = "<element>text</element>";
ee.setAsText(s);
assertEquals(s, ee.getAsText());
assertTrue(ee.getValue() instanceof org.w3c.dom.Element);
}
private void doTests(Class[] types, String[][] inputData, Object[][] expectedData,
String[][] expectedStringData, Comparator[] comparators)
{
for(int t = 0; t < types.length; t ++)
{
Class type = types[t];
getLog().debug("Checking property editor for: "+type);
PropertyEditor editor = PropertyEditorManager.findEditor(type);
assertTrue("Found property editor for: "+type, editor != null);
getLog().debug("Found property editor for: "+type+", editor="+editor.getClass().getName());
assertTrue("inputData.length == expectedData.length", inputData[t].length == expectedData[t].length);
for(int i = 0; i < inputData[t].length; i ++)
{
String input = inputData[t][i];
editor.setAsText(input);
Object expected = expectedData[t][i];
Object output = editor.getValue();
Comparator c = comparators[t];
boolean equals = false;
if (c == null)
{
equals = output != null ? output.equals(expected) : expected == null;
}
else
{
equals = c.compare(output, expected) == 0;
}
assertTrue("Transform of "+input+" equals "+expected+", output="+output, equals);
String expectedStringOutput = expectedStringData[t][i];
String stringOutput = editor.getAsText();
getLog().debug("setAsText '" + logString(input) + "'");
getLog().debug("getAsText '" + logString(stringOutput) + "'");
boolean stringOutputEquals = stringOutput != null ?
stringOutput.equals(expectedStringOutput) : expectedStringOutput == null;
assertTrue("PropertyEditor: " + editor.getClass().getName() + ", getAsText() == expectedStringOutput '" +
logString(expectedStringOutput) + "'", stringOutputEquals);
}
}
}
/**
* Log a Node hierarchy
*/
private void log(Node node, String indent)
{
String name = node.getNodeName();
String value = node.getNodeValue();
getLog().debug(indent + "Name=" + name + ", Value=" + value);
NodeList list = node.getChildNodes();
for (int i = 0; i < list.getLength(); i++)
log(list.item(i), indent + indent);
}
private static String logString(String s)
{
return s != null ? s : "<null>";
}
}