package jp.terasoluna.fw.file.ut; import java.io.File; import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * ◎ JUnitでの単体テストをサポートするユーティリティクラス。 * @version 2003.08.29 */ public class UTUtil { /** * 日付のフォーマット文字列 */ private static final String DATE_FORMAT = "yyyy-MM-dd"; /** * 日付を比較するためのassertユーティリティメソッド。 <BR> * <BR> * selectRows()はDATE型の値を"yyyy-MM-dd HH:mm:ss.fffffffff"フォーマットで 返却するようになっているため、そのままでは値の比較がしづらい。<BR> * そのため、日付用のassertユーティリティメソッドを用意している。 <BR> * <BR> * * <pre> * [使用例] * List list = UTUtil.selectRows("CUSTOMER", "C_ID=1"); * Map map = (Map) list.get(0); * UTUtil.assertEqualsDate("2003-01-01", map.get("C_REGIST_DATE")); * </pre> * * @param expected 期待値 * @param actual 実際の値 */ public static void assertEqualsDate(Object expected, Object actual) { // パラメータがString型でなければ例外を返す。 if ((expected != null) && (!(expected instanceof String))) { throw new IllegalArgumentException(); } if ((actual != null) && (!(actual instanceof String))) { throw new IllegalArgumentException(); } // "yyyy-MM-dd HH:mm:ss.fffffffff"の"yyyy-MM-dd"だけ取り出す。 String actualDate = (actual != null) ? ((String) actual).substring(0, 10) : null; // Stringにキャストした上でassertEqualsする。 String expectedDate = (String) expected; assertEquals(expectedDate, actualDate); } /** * 時刻を比較するためのassertユーティリティメソッド。 <BR> * <BR> * selectRows()はDATE型の値を"yyyy-MM-dd HH:mm:ss.fffffffff"フォーマットで 返却するようになっているため、そのままでは値の比較がしづらい。<BR> * そのため、時刻用のassertユーティリティメソッドを用意している。 <BR> * <BR> * * <pre> * [使用例] * List list = UTUtil.selectRows("CUSTOMER", "C_ID=1"); * Map map = (Map) list.get(0); * UTUtil.assertEqualsDate("12:34:56", map.get("C_UPDATE_TIME")); * </pre> * * @param expected 期待値 * @param actual 実際の値 */ public static void assertEqualsTime(Object expected, Object actual) { // パラメータがString型でなければ例外を返す。 if ((expected != null) && (!(expected instanceof String))) { throw new IllegalArgumentException(); } if ((actual != null) && (!(actual instanceof String))) { throw new IllegalArgumentException(); } // "yyyy-MM-dd HH:mm:ss.fffffffff"の"HH:mm:ss"だけ取り出す。 String actualTime = (actual != null) ? ((String) actual).substring(11, 19) : null; // Stringにキャストした上でassertEqualsする。 String expectedTime = (String) expected; assertEquals(expectedTime, actualTime); } /** * 日付+時刻を比較するためのassertユーティリティメソッド。 <BR> * <BR> * selectRows()はDATE型の値を"yyyy-MM-dd HH:mm:ss.fffffffff"フォーマットで 返却するようになっているため、そのままでは値の比較がしづらい。<BR> * そのため、日付+時刻用のassertユーティリティメソッドを用意している。 <BR> * <BR> * * <pre> * [使用例] * List list = UTUtil.selectRows("CUSTOMER", "C_ID=1"); * Map map = (Map) list.get(0); * UTUtil.assertEqualsDateTime("2003-01-01 12:00:05", * map.get("C_UPDATE_DATE")); * </pre> * * @param expected 期待値 * @param actual 実際の値 */ public static void assertEqualsDateTime(Object expected, Object actual) { // パラメータがString型でなければ例外を返す。 if ((expected != null) && (!(expected instanceof String))) { throw new IllegalArgumentException(); } if ((actual != null) && (!(actual instanceof String))) { throw new IllegalArgumentException(); } // "yyyy-MM-dd HH:mm:ss.fffffffff"の"yyyy-MM-dd HH:mm:ss"だけ取り出す。 String actualDateTime = (actual != null) ? ((String) actual).substring( 0, 19) : null; // Stringにキャストした上でassertEqualsする。 String expectedDateTime = (String) expected; assertEquals(expectedDateTime, actualDateTime); } /** * 現在日付と比較するためのassertユーティリティメソッド。 <BR> * <BR> * selectRows()はDATE型の値を"yyyy-MM-dd HH:mm:ss.fffffffff"フォーマットで 返却するようになっているため、そのままでは値の比較がしづらい。<BR> * そのため、現在日付と比較するassertユーティリティメソッドを用意している。 * * <pre> * [使用例] * List list = UTUtil.selectRows("CUSTOMER", "C_ID=1"); * Map map = (Map) list.get(0); * UTUtil.assertEqualsToday(map.get("C_UPDATE_DATE")); * </pre> * * @param actual 実際の値 */ public static void assertEqualsToday(Object actual) { // パラメータがString型でなければ例外を返す。 if ((actual != null) && (!(actual instanceof String))) { throw new IllegalArgumentException(); } // 現在日付の文字列を取得する。 Date d = new Date(); SimpleDateFormat f = new SimpleDateFormat(DATE_FORMAT); String currentDate = f.format(d); // 日付の文字列をassertEqualsする。 assertEqualsDate(currentDate, actual); } /** * ファイルの中身をバイナリ比較する。 * * <pre> * [使用例] * class SampleTest extends TestCase { * @SuppressWarnings("unchecked") public void testDoSomething() throws Excepton { * // なんらかの処理を実行し結果のファイルが戻される。 * File actual = Sample.doSomething(); * * // 比較するための期待値データのファイルを取得する。 * // ファイルはSampleTestクラスと同じフォルダに置いてある。 * File expected = UTUtil.getFile(this, "expected.txt"); * * // ファイルの比較をする。 * UTUtil.assertEqualsFile(expected, actual); * * } * } * </pre> * * @param expected 期待値のファイル * @param actual 実際の値のファイル */ public static void assertEqualsFile(File expected, File actual) { // パラメータがnullの場合は例外を返す。 if ((expected == null) || (actual == null)) { throw new IllegalArgumentException(); } // 中身を比較するためのラッパーオブジェクト(FileContent)を生成 FileContent expectedContent = new FileContent(expected); FileContent actualContent = new FileContent(actual); // assertにかける。 assertTrue(expectedContent.equals(actualContent)); } /** * テストクラスと同じフォルダに置いてあるテスト用ファイルの Fileオブジェクトを取得する。 * * <pre> * [使用例] * class SampleTest extends TestCase { * @SuppressWarnings("unchecked") public void testDoSomething() throws Excepton { * // なんらかの処理を実行し結果のファイルが戻される。 * File actual = Sample.doSomething(); * * // 比較するための期待値データのファイルを取得する。 * // ファイルはSampleTestクラスと同じフォルダに置いてある。 * File expected = UTUtil.getFile(SampleTest.class, "expected.txt"); * * // ファイルの比較をする。 * UTUtil.assertEqualsFile(expected, actual); * * } * } * </pre> * * @param cls テストクラスのClassオブジェクト * @param filename ファイル名 * @return 指定されたファイル名のFileオブジェクト。 ファイルが存在しない場合はnullを返す。 */ public static File getFile(Class<?> cls, String filename) { // ファイル名がヌル、空文字列の場合はヌルを返す。 if ((filename == null) || ("".equals(filename))) { return null; } // 指定されたファイル名のURLを取得する。 // "file://c:/folder/filename"のようなURLが得られる。 URL url = cls.getResource(filename); // URLがヌルならばヌルを返す。 if (url == null) { return null; } // URLからURIを生成する。 // URISyntaxExceptionが発生することは事実上あり得ないので、catch以下の // コードはヌルを返すだけにしている。 URI uri = null; try { uri = new URI(url.toString()); } catch (URISyntaxException e) { return null; } // Fileオブジェクトを生成して返す。 return new File(uri); } /** * テストクラスと同じフォルダに置いてあるテスト用ファイルの Fileオブジェクトを取得する。 * * <pre> * [使用例] * class SampleTest extends TestCase { * @SuppressWarnings("unchecked") public void testDoSomething() throws Excepton { * // なんらかの処理を実行し結果のファイルが戻される。 * File actual = Sample.doSomething(); * * // 比較するための期待値データのファイルを取得する。 * // ファイルはSampleTestクラスと同じフォルダに置いてある。 * File expected = UTUtil.getFile(this, "expected.txt"); * * // ファイルの比較をする。 * UTUtil.assertEqualsFile(expected, actual); * * } * } * </pre> * * @param instance テストクラスのインスタンス * @param filename ファイル名 * @return 指定されたファイル名のFileオブジェクト。 ファイルが存在しない場合はnullを返す。 */ public static File getFile(Object instance, String filename) { return getFile(instance.getClass(), filename); } /** * privateメソッド(staticでないもの)を呼び出す。<BR> * パラメータ0個~2個のメソッドには専用のメソッドが用意されているので、 そちらを利用した方がシンプルに記述できる。 * * <pre> * [使用例] * class Sample { * private int calcAdd(int val1, int val2, int val3) { * return val1 + val2 + val3; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Sample sample = new Sample(); * Integer result = (Integer) UTUtil.invokePrivate( * sample, * "calcAdd", * new Class[] { int.class, int.class, int.class }, * new Object[] { new Integer(1), new Integer(2), * new Integer(3) } * ); * assertEquals(6, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @param argTypes 引数の型の配列 * @param args 引数の値の配列。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName, @SuppressWarnings("rawtypes") Class[] argTypes, Object[] args) throws Exception { return PrivateAccessUtil.invokePrivate(target, methodName, argTypes, args); } /** * privateメソッド(staticでないもの)を呼び出す(パラメータ0個用)。 * * <pre> * [使用例] * class Sample { * private int getString() { * return "success"; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testGetString() { * Sample sample = new Sample(); * String result = * (String) UTUtil.invokePrivate(sample, "getString"): * assertEquals("success", result); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName) throws Exception { return invokePrivate(target, methodName, new Class[] {}, new Object[] {}); } /** * privateメソッド(staticでないもの)を呼び出す(パラメータ1個用)。 * * <pre> * [使用例] * class Sample { * private long square(long val) { * return val ˆ 2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testSquare() { * Sample sample = new Sample(); * Long result = (Long) UTUtil.invokePrivate( * sample, "square", long.class, new Long(2L)): * assertEquals(4, result.longValue()); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @param argType 引数の型 * @param arg 引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName, Class<?> argType, Object arg) throws Exception { return invokePrivate(target, methodName, new Class[] { argType }, new Object[] { arg }); } /** * privateメソッド(staticでないもの)を呼び出す(パラメータ2個用)。 * * <pre> * [使用例] * class Sample { * private static int calcAdd(int val1, int val2) { * return val1 + val2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Sample sample = new Sample(); * Integer result = (Integer) UTUtil.invokePrivate( * sample, * "calcAdd", * int.class, * int.class, * new Integer(1), * new Integer(2) * ); * assertEquals(3, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @param argType1 第一引数の型 * @param argType2 第二引数の型 * @param arg1 第一引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @param arg2 第二引数の値。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName, Class<?> argType1, Class<?> argType2, Object arg1, Object arg2) throws Exception { return invokePrivate(target, methodName, new Class[] { argType1, argType2 }, new Object[] { arg1, arg2 }); } /** * staticなprivateメソッドを呼び出す。 <BR> * <BR> * パラメータ0個~2個のメソッドには専用のメソッドが用意されているので、 そちらを利用した方がシンプルに記述できる。 * * <pre> * [使用例] * class Sample { * private static int calcAdd(int val1, int val2, int val3) { * return val1 + val2 + val3; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Integer result = (Integer) UTUtil.invokePrivate( * Sample.class, * "calcAdd", * new Class[] { int.class, int.class, int.class }, * new Object[] { new Integer(1), new Integer(2), * new Integer(3) } * ); * assertEquals(6, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argTypes 引数の型の配列 * @param args 引数の値の配列。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName, @SuppressWarnings("rawtypes") Class[] argTypes, Object[] args) throws Exception { return PrivateAccessUtil.invokePrivate(target, methodName, argTypes, args); } /** * staticなprivateメソッドを呼び出す(パラメータ0個用)。 * * <pre> * [使用例] * class Sample { * private static int getString() { * return "success"; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testGetString() { * String result = (String) UTUtil.invokePrivate( * Sample.class, "getString"): * assertEquals("success", result); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName) throws Exception { return invokePrivate(target, methodName, new Class[] {}, new Object[] {}); } /** * staticなprivateメソッドを呼び出す(パラメータ1個用)。 * * <pre> * [使用例] * class Sample { * private static long square(long val) { * return val ˆ 2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testSquare() { * Long result = (Long) UTUtil.invokePrivate( * Sample.class, "square", long.class, new Long(2L)): * assertEquals(4, result.longValue()); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argType 引数の型 * @param arg 引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName, Class<?> argType, Object arg) throws Exception { return invokePrivate(target, methodName, new Class[] { argType }, new Object[] { arg }); } /** * staticなprivateメソッドを呼び出す(パラメータ2個用)。 * * <pre> * [使用例] * class Sample { * private static int calcAdd(int val1, int val2) { * return val1 + val2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Integer result = (Integer) UTUtil.invokePrivate( * Sample.class, * "calcAdd", * int.class, * int.class, * new Integer(1), * new Integer(2) * ); * assertEquals(3, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argType1 第一引数の型 * @param argType2 第二引数の型 * @param arg1 第一引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @param arg2 第二引数の値。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName, Class<?> argType1, Class<?> argType2, Object arg1, Object arg2) throws Exception { return invokePrivate(target, methodName, new Class[] { argType1, argType2 }, new Object[] { arg1, arg2 }); } /** * 指定したオブジェクトのprivateフィールドの値を返す。 * @param target 対象のオブジェクト * @param fieldName 値を取得するprivateフィールドの名前 * @return privateフィールドの値 * @exception NoSuchFieldException */ public static Object getField(Object target, String fieldName) throws NoSuchFieldException { // パラメータ値のチェック if (target == null) { throw new IllegalArgumentException(); } if (fieldName == null || fieldName.equals("")) { throw new IllegalArgumentException(); } // privateフィールド取得処理。 // スーパークラス全てについて呼び出しをトライする。 for (Class<?> c = target.getClass(); c != null; c = c.getSuperclass()) { try { Field field = c.getDeclaredField(fieldName); field.setAccessible(true); return field.get(target); } catch (Exception e) { // 取得しようとしたフィールドが存在しなかった場合、何もしない。 // (親クラスで同じトライを繰り返す) } } // 取得しようとしたフィールドが存在しなかった場合 throw new NoSuchFieldException("Could get value for field " + target .getClass().getName() + "." + fieldName); } /** * 指定したクラスのstaticなprivateフィールドの値を返す。 * @param target 対象のクラス * @param fieldName 値を取得するprivateフィールドの名前 * @return privateフィールドの値 * @exception NoSuchFieldException */ public static Object getField(Class<?> target, String fieldName) throws NoSuchFieldException { // パラメータ値のチェック if (target == null) { throw new IllegalArgumentException(); } if (fieldName == null || fieldName.equals("")) { throw new IllegalArgumentException(); } // privateフィールド取得処理。 // スーパークラス全てについて呼び出しをトライする。 Class<?> c = target; while (c != null) { try { Field field = c.getDeclaredField(fieldName); field.setAccessible(true); return field.get(c); } catch (Exception e) { // 取得しようとしたフィールドが存在しなかった場合、何もしない。 // (親クラスで同じトライを繰り返す) } c = c.getSuperclass(); } // 取得しようとしたフィールドが存在しなかった場合 throw new NoSuchFieldException("Could get value for field " + target .getName() + "." + fieldName); } /** * 指定したオブジェクトのprivateフィールドに値を設定する。 * @param target 対象のオブジェクト * @param fieldName 値を設定するprivateフィールドの名前 * @param value 設定する値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @exception NoSuchFieldException */ public static void setField(Object target, String fieldName, Object value) throws NoSuchFieldException { // パラメータ値のチェック if (target == null) { throw new IllegalArgumentException(); } if (fieldName == null || fieldName.equals("")) { throw new IllegalArgumentException(); } // privateフィールド設定処理。 // スーパークラス全てについて呼び出しをトライする。 for (Class<?> c = target.getClass(); c != null; c = c.getSuperclass()) { try { Field field = c.getDeclaredField(fieldName); field.setAccessible(true); field.set(target, value); return; } catch (Exception e) { // 設定しようとしたフィールドが存在しなかった場合、何もしない。 // (親クラスで同じトライを繰り返す) } } // 設定しようとしたフィールドが存在しなかった場合 throw new NoSuchFieldException("Could set value for field " + target .getClass().getName() + "." + fieldName); } /** * 指定したクラスのstaticなprivateフィールドに値を設定する。 * @param target 対象のクラス * @param fieldName 値を設定するprivateフィールドの名前 * @param value 設定する値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @exception NoSuchFieldException */ public static void setField(Class<?> target, String fieldName, Object value) throws NoSuchFieldException { // パラメータ値のチェック if (target == null) { throw new IllegalArgumentException(); } if (fieldName == null || fieldName.equals("")) { throw new IllegalArgumentException(); } Class<?> c = target; while (c != null) { try { Field field = c.getDeclaredField(fieldName); field.setAccessible(true); field.set(c, value); return; } catch (Exception ex) { // 設定しようとしたフィールドが存在しなかった場合、何もしない。 // (親クラスで同じトライを繰り返す) } c = c.getSuperclass(); } // 設定しようとしたフィールドが存在しなかった場合 throw new NoSuchFieldException("Could set value for static field " + target.getName() + "." + fieldName); } }