/** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tuscany.sdo.test; import junit.framework.TestCase; import java.io.InputStream; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Comparator; import java.util.Date; import java.util.TimeZone; import org.apache.tuscany.sdo.util.DataObjectUtil; import commonj.sdo.DataObject; import commonj.sdo.Property; import commonj.sdo.Type; import commonj.sdo.helper.DataFactory; import commonj.sdo.helper.TypeHelper; import commonj.sdo.helper.XSDHelper; public class TypeConversionTestCase extends TestCase { // The following constants are used to get Types from XSDs private static final String TEST_MODEL = "/api_test.xsd"; private static final String TEST_NAMESPACE = "http://www.example.com/api_test"; // The following constants describe the index for the fields in api_test.xsd. private static final int STRING_VAL_INDEX = 0; private static final int BOOLEAN_VAL_INDEX = 1; private static final int BYTE_VAL_INDEX = 3; private static final int DECIMAL_VAL_INDEX = 5; private static final int INT_VAL_INDEX = 7; private static final int FLOAT_VAL_INDEX = 8; private static final int DOUBLE_VAL_INDEX = 9; private static final int DATE_VAL_INDEX = 10; private static final int SHORT_VAL_INDEX = 11; private static final int LONG_VAL_INDEX = 12; private static final int BYTES_VAL_INDEX = 14; private static final int INTEGER_VAL_INDEX = 15; private static final int CHAR_VAL_INDEX = 16; // The following variables are Method arrays. Each array refers to a specific get, but within // the array exist the get(index), get(property), and get(path). Rather than // referring to each of the three in every circumstance, the more compact array appears. private static ConversionType TO_BOOLEAN = new ConversionType("Boolean", boolean.class ); private static ConversionType TO_BYTE = new ConversionType("Byte", byte.class ); private static ConversionType TO_CHAR = new ConversionType("Char", char.class ); private static ConversionType TO_DOUBLE = new ConversionType("Double", double.class ); private static ConversionType TO_FLOAT = new ConversionType("Float", float.class ); private static ConversionType TO_INT = new ConversionType("Int", int.class ); private static ConversionType TO_LONG = new ConversionType("Long", long.class ); private static ConversionType TO_SHORT = new ConversionType("Short", short.class ); private static ConversionType TO_BYTES = new ConversionType("Bytes", byte[].class ); private static ConversionType TO_BIGDECIMAL = new ConversionType("BigDecimal", java.math.BigDecimal.class ); private static ConversionType TO_BIGINTEGER = new ConversionType("BigInteger", java.math.BigInteger.class ); private static ConversionType TO_DATAOBJECT = new ConversionType("DataObject", commonj.sdo.DataObject.class ); private static ConversionType TO_DATE = new ConversionType("Date", java.util.Date.class ); private static ConversionType TO_STRING = new ConversionType("String", java.lang.String.class ); private static ConversionType TO_LIST = new ConversionType("List", java.util.List.class ); // There is no setXXXX methods for sequence... private static ConversionType TO_SEQUENCE = new ConversionType("Sequence", null ); private static GeneralComparator COMPARE_ANY; // There will be several instances where a Property must be passed as a parameter. Have available the Type // to call getProperty() as needed. private static Type API_TEST_TYPE; // The default constructor establishes each of the Method and Method[] variables. public TypeConversionTestCase() throws Exception { COMPARE_ANY = new GeneralComparator(); // Populate the meta data for the test model URL url = getClass().getResource(TEST_MODEL); InputStream inputStream = url.openStream(); XSDHelper.INSTANCE.define(inputStream, url.toString()); inputStream.close(); API_TEST_TYPE = TypeHelper.INSTANCE.getType(TEST_NAMESPACE, "APITest"); } private static class ConversionType { // The following constants are used because the getMethod function requires an Class // array describing the parameters to the functions. private static final Class[] GET_INT_CLASS_ARRAY = {int.class}; private static final Class[] GET_PROPERTY_CLASS_ARRAY = {Property.class}; private static final Class[] GET_STRING_CLASS_ARRAY = {String.class}; private static final Class[] SET_INT_CLASS_ARRAY = {int.class, Class.class}; private static final Class[] SET_PROPERTY_CLASS_ARRAY = {Property.class, Class.class}; private static final Class[] SET_STRING_CLASS_ARRAY = {String.class, Class.class}; Method get_index_method; Method get_property_method; Method get_path_method; Method set_index_method; Method set_property_method; Method set_path_method; public ConversionType (String method_name, Class type ) { try { this.get_index_method = DataObject.class.getMethod("get"+method_name, GET_INT_CLASS_ARRAY); this.get_property_method = DataObject.class.getMethod("get"+method_name, GET_PROPERTY_CLASS_ARRAY); this.get_path_method = DataObject.class.getMethod("get"+method_name, GET_STRING_CLASS_ARRAY); if( type != null ) { SET_INT_CLASS_ARRAY[1] = type; this.set_index_method = DataObject.class.getMethod("set"+method_name, SET_INT_CLASS_ARRAY); SET_PROPERTY_CLASS_ARRAY[1] = type; this.set_property_method = DataObject.class.getMethod("set"+method_name, SET_PROPERTY_CLASS_ARRAY); SET_STRING_CLASS_ARRAY[1] = type; this.set_path_method = DataObject.class.getMethod("set"+method_name, SET_STRING_CLASS_ARRAY); } else { this.set_index_method = null; this.set_property_method = null; this.set_path_method = null; } } catch (NoSuchMethodException e) { this.get_index_method = null; this.get_property_method = null; this.get_path_method = null; this.set_index_method = null; this.set_property_method = null; this.set_path_method = null; } } public Method getIndexGetMethod() { return this.get_index_method; } public Method getPropertyGetMethod() { return this.get_property_method; } public Method getPathGetMethod() { return this.get_path_method; } public Method getIndexSetMethod() { return this.set_index_method; } public Method getPropertySetMethod() { return this.set_property_method; } public Method getPathSetMethod() { return this.set_path_method; } } // Each instance of Test describes a convert-from type. The index, property and path parms // will refer to the same field, which is a field of the convert-from type. private static class Test { DataObject test_obj; Object[] get_index_parm; Object[] get_property_parm; Object[] get_path_parm; Object[] set_index_parm; Object[] set_property_parm; Object[] set_path_parm; Object expected_value; String from_type; Class from_type_class; // The constructor prepares a test DataObject and determines how to access the field // in three different ways - index, property, and path. Test(String path, int index) { this.test_obj = DataFactory.INSTANCE.create(API_TEST_TYPE); this.get_index_parm = new Object[] {new Integer(index)}; this.get_property_parm = new Object[] {API_TEST_TYPE.getProperty(path)}; this.get_path_parm = new Object[] {path}; this.set_index_parm = new Object[] {new Integer(index), null}; this.set_property_parm = new Object[] {API_TEST_TYPE.getProperty(path), null}; this.set_path_parm = new Object[] {path, null}; this.expected_value = null; } // The initialize() function establishes the initial value of the test field. public void initialize(Class type, String type_name, Object initial_value) throws Exception { this.expected_value = initial_value; this.from_type = type_name; this.from_type_class = type; setDefaultValue(); } private void setDefaultValue() throws Exception { Class[] classArray = {int.class, from_type_class}; Object[] initValueArray = new Object[] {this.get_index_parm[0], expected_value}; Method setter = DataObject.class.getMethod("set" + from_type, classArray); setter.invoke(test_obj, initValueArray); } // Attempts the conversion to the specified type, using DataObject.get____(). // The get___() function can be called with an index, path, and property. attemptConversion() // calls each of those three. public void attemptConversion(ConversionType to_type) throws Exception { performConversion(to_type.getIndexGetMethod(), this.get_index_parm, to_type.getIndexSetMethod(), this.set_index_parm); performConversion(to_type.getPathGetMethod(), this.get_path_parm, to_type.getPathSetMethod(), this.set_path_parm ); performConversion(to_type.getPropertyGetMethod(), this.get_property_parm, to_type.getPropertySetMethod(), this.set_property_parm ); } public void checkConversionException(ConversionType to_type, Class expected_exception) throws Exception { boolean index_err, path_err, property_err, consistency_err = false; index_err = executeExceptionCase(to_type.getIndexGetMethod(), this.get_index_parm, expected_exception); path_err = executeExceptionCase(to_type.getPathGetMethod(), this.get_path_parm, expected_exception); property_err = executeExceptionCase(to_type.getPropertyGetMethod(), this.get_property_parm, expected_exception); if (index_err != path_err || path_err != property_err) consistency_err = true; else if (index_err == false) attemptConversion(to_type); assertFalse("An exception inconsistency exists for " + to_type.getPathGetMethod().getName() + " when called " + "for a " + this.from_type + " property.", consistency_err); } private void performConversion (Method getMeth, Object[] getParm, Method setMeth, Object[] setParm ) throws Exception { // First use the set try { // get the set value setParm[1] = getMeth.invoke(test_obj, getParm);; // now set it... setMeth.invoke(test_obj, setParm); } catch (Exception e) { Throwable cause = e.getCause(); if (cause == null) { System.err.println("An exception of type " + e.getClass() + " occurred while performing " + setMeth.getName() + " on a " + this.from_type + " property."); } else { System.err.println("An exception of type " + cause.getClass() + " occurred while performing " + setMeth.getName() + " on a " + this.from_type + " property."); } throw e; } try { assertTrue("Conversion did not yield expected value for get" + getMeth.getName() + " on a " + this.from_type + " property.", COMPARE_ANY.compare(getMeth.invoke(test_obj, getParm), this.expected_value) == 0); } catch (Exception e) { Throwable cause = e.getCause(); if (cause == null) { System.err.println("An exception of type " + e.getClass() + " occurred while performing " + getMeth.getName() + " on a " + this.from_type + " property."); } else { System.err.println("An exception of type " + cause.getClass() + " occurred while performing " + getMeth.getName() + " on a " + this.from_type + " property."); } throw e; } // reset to default setDefaultValue(); } private boolean executeExceptionCase (Method convert, Object[] parm, Class expected_exception) throws Exception { boolean exception_thrown = false; try { convert.invoke(test_obj, parm); } catch (Exception e) { exception_thrown = true; Throwable cause = e.getCause(); if (cause == null) { assertEquals("An unexpected exception occurred while performing " + convert.getName() + " on a " + this.from_type + " property.", expected_exception, e.getClass()); } else { assertEquals("An unexpected exception occurred while performing " + convert.getName() + " on a " + this.from_type + " property.", expected_exception, cause.getClass()); } } return exception_thrown; } } private static class GeneralComparator implements Comparator { public int compare(Object obj1, Object obj2) { if (obj1.getClass() == obj2.getClass()) { if (obj1.equals(obj2)) return 0; else return 1; } else if ( (obj1.getClass() == byte[].class && obj2.getClass() == String.class) || (obj2.getClass() == byte[].class && obj1.getClass() == String.class) ) { String strVal; byte [] byteVal; if( obj1.getClass() == String.class ) { strVal = (String)obj1; byteVal = (byte [])obj2; } else { strVal = (String)obj2; byteVal = (byte [])obj1; } if( strVal.length()/2 != byteVal.length ) return -1; for( int i=0; i