1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 1996-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 * 10 */ 11 12 package android.icu.dev.test.serializable; 13 14 import java.io.File; 15 import java.io.FileFilter; 16 import java.io.FileInputStream; 17 import java.io.IOException; 18 import java.net.JarURLConnection; 19 import java.net.MalformedURLException; 20 import java.net.URL; 21 import java.util.ArrayList; 22 import java.util.Enumeration; 23 import java.util.List; 24 import java.util.jar.JarEntry; 25 import java.util.jar.JarFile; 26 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 30 import android.icu.dev.test.TestFmwk; 31 import android.icu.dev.test.serializable.SerializableTestUtility.Handler; 32 33 import junitparams.JUnitParamsRunner; 34 import junitparams.Parameters; 35 36 /** 37 * @author sgill 38 * @author emader 39 */ 40 @RunWith(JUnitParamsRunner.class) 41 public class CompatibilityTest extends TestFmwk 42 { 43 private static final class FileHolder { 44 String className; 45 String icuVersion; 46 byte[] b; 47 boolean skip; 48 49 FileHolder(String fileName, byte[] b) { 50 this.b = b; 51 52 // Replace '\' with '/' to normalize fileName before extracting 53 // substrings. This is required if serialization test data is 54 // loaded from Windows file system. 55 String tmpPath = fileName.replaceAll("\\\\", "/"); 56 57 int fileBreak = tmpPath.lastIndexOf('/'); 58 this.className = fileName.substring(fileBreak + 1, tmpPath.lastIndexOf('.')); 59 int finalDirBreak = tmpPath.lastIndexOf("/ICU"); 60 this.icuVersion = tmpPath.substring(finalDirBreak + 1, fileBreak); 61 className = className.substring(className.lastIndexOf('/') + 1); 62 63 this.skip = skipFile(this.icuVersion, this.className); 64 } 65 66 private static boolean skipFile(String icuVersion, String className) { 67 for (int skip = 0; skip < SKIP_CASES.length; skip++) { 68 if (icuVersion.equals(SKIP_CASES[skip][0]) && className.equals(SKIP_CASES[skip][1])) { 69 return true; 70 } 71 } 72 return false; 73 } 74 75 @Override 76 public String toString() { 77 return icuVersion + "[" + className + "]"; 78 } 79 } 80 81 @Test 82 @Parameters(method="generateClassList") 83 public void testCompatibility(FileHolder holder) throws ClassNotFoundException, IOException { 84 if (holder.skip) { 85 logln("Skipping File = " + holder); 86 return; 87 } 88 89 Object[] oldObjects = SerializableTestUtility.getSerializedObjects(holder.b); 90 Handler classHandler = SerializableTestUtility.getHandler(holder.className); 91 92 Object[] testObjects = classHandler.getTestObjects(); 93 for (int i = 0; i < testObjects.length; i++) { 94 if (!classHandler.hasSameBehavior(oldObjects[i], testObjects[i])) { 95 errln("Input object " + i + " failed behavior test."); 96 } 97 } 98 } 99 100 /** 101 * The path to an actual data resource file in the JAR. This is needed because when the 102 * code is packaged for Android the resulting archive does not have entries for directories 103 * and so only actual resources can be found. 104 */ 105 private static final String ACTUAL_RESOURCE = "/ICU_3.6/android.icu.impl.OlsonTimeZone.dat"; 106 107 @SuppressWarnings("unused") 108 private List<FileHolder> generateClassList() throws IOException { 109 // Get the URL to an actual resource and then compute the URL to the directory just in 110 // case the resources are in a JAR file that doesn't have entries for directories. 111 URL dataURL = getClass().getResource("data" + ACTUAL_RESOURCE); 112 try { 113 dataURL = new URL(dataURL.toExternalForm().replace(ACTUAL_RESOURCE, "")); 114 } catch (MalformedURLException e) { 115 throw new RuntimeException(e); 116 } 117 String protocol = dataURL.getProtocol(); 118 119 if (protocol.equals("jar")) { 120 return getJarList(dataURL); 121 } else if (protocol.equals("file")) { 122 return getFileList(dataURL); 123 } else { 124 errln("Don't know how to test " + dataURL); 125 return null; 126 } 127 } 128 129 private List<FileHolder> getFileList(URL dataURL) throws IOException { 130 List<FileHolder> classList = new ArrayList(); 131 132 File topDir = new File(dataURL.getPath()); 133 File dataDirs[] = topDir.listFiles(new FileFilter() { 134 @Override 135 public boolean accept(File pathname) { 136 return pathname.isDirectory(); 137 }}); 138 139 for (File dataDir : dataDirs) { 140 File files[] = dataDir.listFiles(new FileFilter() { 141 @Override 142 public boolean accept(File pathname) { 143 return pathname.isFile() && pathname.getName().endsWith(".dat"); 144 }}); 145 146 for (File file : files) { 147 FileInputStream fis = new FileInputStream(file); 148 byte[] fileBytes; 149 try { 150 fileBytes = SerializableTestUtility.copyStreamBytes(fis); 151 } finally { 152 fis.close(); 153 } 154 classList.add(new FileHolder(file.getAbsolutePath(), fileBytes)); 155 } 156 } 157 return classList; 158 } 159 160 private List<FileHolder> getJarList(URL jarURL) throws IOException { 161 List<FileHolder> classList = new ArrayList(); 162 163 String prefix = jarURL.getPath(); 164 int ix = prefix.indexOf("!/"); 165 if (ix >= 0) { 166 prefix = prefix.substring(ix + 2); 167 } 168 169 JarFile jarFile = null; 170 try { 171 // Need to trim the directory off the JAR entry before opening the connection otherwise 172 // it could fail as it will try and find the entry within the JAR which may not exist. 173 String urlAsString = jarURL.toExternalForm(); 174 ix = urlAsString.indexOf("!/"); 175 jarURL = new URL(urlAsString.substring(0, ix + 2)); 176 177 JarURLConnection conn = (JarURLConnection) jarURL.openConnection(); 178 jarFile = conn.getJarFile(); 179 Enumeration entries = jarFile.entries(); 180 while (entries.hasMoreElements()) { 181 JarEntry entry = (JarEntry) entries.nextElement(); 182 if (!entry.isDirectory()) { 183 String entryName = entry.getName(); 184 185 if (entryName.startsWith(prefix) && entryName.endsWith(".dat")) { 186 FileHolder holder = new FileHolder(entryName, 187 SerializableTestUtility.copyStreamBytes(jarFile.getInputStream(entry))); 188 classList.add(holder); 189 190 } 191 } 192 } 193 } finally { 194 if (jarFile != null) { 195 jarFile.close(); 196 } 197 } 198 return classList; 199 } 200 201 private static final String[][] SKIP_CASES = { 202 // ICU 52+ PluralRules/PluralFormat/CurrencyPluralInfo are not 203 // serialization-compatible with previous versions. 204 {"ICU_50.1", "android.icu.text.CurrencyPluralInfo"}, 205 {"ICU_51.1", "android.icu.text.CurrencyPluralInfo"}, 206 207 {"ICU_50.1", "android.icu.text.PluralFormat"}, 208 {"ICU_51.1", "android.icu.text.PluralFormat"}, 209 210 {"ICU_50.1", "android.icu.text.PluralRules"}, 211 {"ICU_51.1", "android.icu.text.PluralRules"}, 212 213 // GeneralMeasureFormat was in technical preview, but is going away after ICU 52.1. 214 {"ICU_52.1", "android.icu.text.GeneralMeasureFormat"}, 215 216 // RuleBasedNumberFormat 217 {"ICU_3.6", "android.icu.text.RuleBasedNumberFormat"}, 218 219 // ICU 4.8+ MessageFormat is not serialization-compatible with previous versions. 220 {"ICU_3.6", "android.icu.text.MessageFormat"}, 221 }; 222 } 223