| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /* |
| ******************************************************************************* |
| * Copyright (C) 1996-2016, International Business Machines Corporation and |
| * others. All Rights Reserved. |
| ******************************************************************************* |
| * |
| */ |
| |
| package com.ibm.icu.dev.test.serializable; |
| |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.net.JarURLConnection; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.List; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import com.ibm.icu.dev.test.TestFmwk; |
| import com.ibm.icu.dev.test.serializable.SerializableTestUtility.Handler; |
| |
| import junitparams.JUnitParamsRunner; |
| import junitparams.Parameters; |
| |
| /** |
| * @author sgill |
| * @author emader |
| */ |
| @RunWith(JUnitParamsRunner.class) |
| public class CompatibilityTest extends TestFmwk |
| { |
| private static final class FileHolder { |
| String className; |
| String icuVersion; |
| byte[] b; |
| boolean skip; |
| |
| FileHolder(String fileName, byte[] b) { |
| this.b = b; |
| |
| // Replace '\' with '/' to normalize fileName before extracting |
| // substrings. This is required if serialization test data is |
| // loaded from Windows file system. |
| String tmpPath = fileName.replaceAll("\\\\", "/"); |
| |
| int fileBreak = tmpPath.lastIndexOf('/'); |
| this.className = fileName.substring(fileBreak + 1, tmpPath.lastIndexOf('.')); |
| int finalDirBreak = tmpPath.lastIndexOf("/ICU"); |
| this.icuVersion = tmpPath.substring(finalDirBreak + 1, fileBreak); |
| className = className.substring(className.lastIndexOf('/') + 1); |
| |
| this.skip = skipFile(this.icuVersion, this.className); |
| } |
| |
| private static boolean skipFile(String icuVersion, String className) { |
| for (int skip = 0; skip < SKIP_CASES.length; skip++) { |
| if (icuVersion.equals(SKIP_CASES[skip][0]) && className.equals(SKIP_CASES[skip][1])) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return icuVersion + "[" + className + "]"; |
| } |
| } |
| |
| @Test |
| @Parameters(method="generateClassList") |
| public void testCompatibility(FileHolder holder) throws ClassNotFoundException, IOException { |
| if (holder.skip) { |
| logln("Skipping File = " + holder); |
| return; |
| } |
| |
| Object[] oldObjects = SerializableTestUtility.getSerializedObjects(holder.b); |
| Handler classHandler = SerializableTestUtility.getHandler(holder.className); |
| |
| Object[] testObjects = classHandler.getTestObjects(); |
| for (int i = 0; i < testObjects.length; i++) { |
| if (!classHandler.hasSameBehavior(oldObjects[i], testObjects[i])) { |
| errln("Input object " + i + ", className " + holder.className + ": failed behavior test."); |
| } |
| } |
| } |
| |
| /** |
| * The path to an actual data resource file in the JAR. This is needed because when the |
| * code is packaged for Android the resulting archive does not have entries for directories |
| * and so only actual resources can be found. |
| */ |
| private static final String ACTUAL_RESOURCE = "/ICU_3.6/com.ibm.icu.impl.OlsonTimeZone.dat"; |
| |
| @SuppressWarnings("unused") |
| private List<FileHolder> generateClassList() throws IOException { |
| // Get the URL to an actual resource and then compute the URL to the directory just in |
| // case the resources are in a JAR file that doesn't have entries for directories. |
| URL dataURL = getClass().getResource("data" + ACTUAL_RESOURCE); |
| try { |
| dataURL = new URL(dataURL.toExternalForm().replace(ACTUAL_RESOURCE, "")); |
| } catch (MalformedURLException e) { |
| throw new RuntimeException(e); |
| } |
| String protocol = dataURL.getProtocol(); |
| |
| if (protocol.equals("jar")) { |
| return getJarList(dataURL); |
| } else if (protocol.equals("file")) { |
| return getFileList(dataURL); |
| } else { |
| errln("Don't know how to test " + dataURL); |
| return null; |
| } |
| } |
| |
| private List<FileHolder> getFileList(URL dataURL) throws IOException { |
| List<FileHolder> classList = new ArrayList(); |
| |
| File topDir = new File(dataURL.getPath()); |
| File dataDirs[] = topDir.listFiles(new FileFilter() { |
| @Override |
| public boolean accept(File pathname) { |
| return pathname.isDirectory(); |
| }}); |
| |
| for (File dataDir : dataDirs) { |
| File files[] = dataDir.listFiles(new FileFilter() { |
| @Override |
| public boolean accept(File pathname) { |
| return pathname.isFile() && pathname.getName().endsWith(".dat"); |
| }}); |
| |
| for (File file : files) { |
| FileInputStream fis = new FileInputStream(file); |
| byte[] fileBytes; |
| try { |
| fileBytes = SerializableTestUtility.copyStreamBytes(fis); |
| } finally { |
| fis.close(); |
| } |
| classList.add(new FileHolder(file.getAbsolutePath(), fileBytes)); |
| } |
| } |
| return classList; |
| } |
| |
| private List<FileHolder> getJarList(URL jarURL) throws IOException { |
| List<FileHolder> classList = new ArrayList(); |
| |
| String prefix = jarURL.getPath(); |
| int ix = prefix.indexOf("!/"); |
| if (ix >= 0) { |
| prefix = prefix.substring(ix + 2); |
| } |
| |
| JarFile jarFile = null; |
| try { |
| // Need to trim the directory off the JAR entry before opening the connection otherwise |
| // it could fail as it will try and find the entry within the JAR which may not exist. |
| String urlAsString = jarURL.toExternalForm(); |
| ix = urlAsString.indexOf("!/"); |
| jarURL = new URL(urlAsString.substring(0, ix + 2)); |
| |
| JarURLConnection conn = (JarURLConnection) jarURL.openConnection(); |
| jarFile = conn.getJarFile(); |
| Enumeration entries = jarFile.entries(); |
| while (entries.hasMoreElements()) { |
| JarEntry entry = (JarEntry) entries.nextElement(); |
| if (!entry.isDirectory()) { |
| String entryName = entry.getName(); |
| |
| if (entryName.startsWith(prefix) && entryName.endsWith(".dat")) { |
| FileHolder holder = new FileHolder(entryName, |
| SerializableTestUtility.copyStreamBytes(jarFile.getInputStream(entry))); |
| classList.add(holder); |
| |
| } |
| } |
| } |
| } finally { |
| if (jarFile != null) { |
| jarFile.close(); |
| } |
| } |
| return classList; |
| } |
| |
| private static final String[][] SKIP_CASES = { |
| // ICU 52+ PluralRules/PluralFormat/CurrencyPluralInfo are not |
| // serialization-compatible with previous versions. |
| {"ICU_50.1", "com.ibm.icu.text.CurrencyPluralInfo"}, |
| {"ICU_51.1", "com.ibm.icu.text.CurrencyPluralInfo"}, |
| |
| {"ICU_50.1", "com.ibm.icu.text.PluralFormat"}, |
| {"ICU_51.1", "com.ibm.icu.text.PluralFormat"}, |
| |
| {"ICU_50.1", "com.ibm.icu.text.PluralRules"}, |
| {"ICU_51.1", "com.ibm.icu.text.PluralRules"}, |
| |
| // GeneralMeasureFormat was in technical preview, but is going away after ICU 52.1. |
| {"ICU_52.1", "com.ibm.icu.text.GeneralMeasureFormat"}, |
| |
| // RuleBasedNumberFormat |
| {"ICU_3.6", "com.ibm.icu.text.RuleBasedNumberFormat"}, |
| |
| // ICU 4.8+ MessageFormat is not serialization-compatible with previous versions. |
| {"ICU_3.6", "com.ibm.icu.text.MessageFormat"}, |
| }; |
| } |