From 42af181065e99775ed94698e8fa8d8ffea2ddade Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 18 Nov 2018 00:01:40 +0000 Subject: [PATCH] #62921 - Provide OOXMLLite alternative for Java 12+ git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1846809 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 147 ++++--- .../org/apache/poi/ooxml/util/OOXMLLite.java | 375 ------------------ .../apache/poi/ooxml/util/OOXMLLiteAgent.java | 78 ++++ .../poi/ss/format/TestCellFormatPart.java | 2 +- .../org/apache/poi/hmef/TestAttachments.java | 5 +- .../hmef/attribute/TestMAPIAttributes.java | 5 +- .../hmef/attribute/TestTNEFAttributes.java | 5 +- .../TestExcelStyleDateFormatter.java | 159 ++++---- 8 files changed, 223 insertions(+), 553 deletions(-) delete mode 100644 src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLite.java create mode 100644 src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java diff --git a/build.xml b/build.xml index d15b45b74b..89f0423e78 100644 --- a/build.xml +++ b/build.xml @@ -130,8 +130,12 @@ under the License. - - + + + + + + @@ -397,7 +401,8 @@ under the License. - + + @@ -1015,8 +1020,6 @@ under the License. compile-scratchpad, compile-examples, compile-excelant" description="Compiles the POI main classes, scratchpad and examples"/> - - - @@ -1385,9 +1388,7 @@ under the License. - + @@ -1564,6 +1565,7 @@ under the License. + @@ -1598,6 +1600,7 @@ under the License. + @@ -1620,7 +1623,7 @@ under the License. - @@ -1638,7 +1641,7 @@ under the License. - @@ -1650,6 +1653,7 @@ under the License. + @@ -1677,57 +1681,28 @@ under the License. - - - - - - - - - + + + + - - - + + - - + + + + + - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1736,6 +1711,15 @@ under the License. + + + + + + + + + @@ -1953,11 +1937,11 @@ under the License. - + - + @@ -1971,33 +1955,39 @@ under the License. + + + + + - + + - - - - - - - + + + + + + + - - - - - - + + + + + + - + @@ -2112,6 +2102,7 @@ under the License. lib/**, bin/**, out/**, + tmp/**, sonar/**/target/**, sonar/*/src/**, compile-lib/**, @@ -2167,14 +2158,12 @@ under the License. - - - diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLite.java b/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLite.java deleted file mode 100644 index 450f958ae6..0000000000 --- a/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLite.java +++ /dev/null @@ -1,375 +0,0 @@ -/* ==================================================================== - 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.poi.ooxml.util; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.URL; -import java.security.AccessController; -import java.security.CodeSource; -import java.security.PrivilegedAction; -import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Vector; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.regex.Pattern; - -import org.apache.poi.util.IOUtils; -import org.apache.poi.util.StringUtil; -import org.apache.poi.util.SuppressForbidden; -import org.apache.xmlbeans.StringEnumAbstractBase; -import org.junit.Test; -import org.junit.internal.TextListener; -import org.junit.runner.Description; -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; -import org.reflections.Reflections; - -import junit.framework.TestCase; - -/** - * Build a 'lite' version of the ooxml-schemas.jar - * - * @author Yegor Kozlov - */ -public final class OOXMLLite { - private static final Pattern SCHEMA_PATTERN = Pattern.compile("schemaorg_apache_xmlbeans/(system|element)/.*\\.xsb"); - - /** - * Destination directory to copy filtered classes - */ - private File _destDest; - - /** - * Directory with the compiled ooxml tests - */ - private File _testDir; - - /** - * Reference to the ooxml-schemas.jar - */ - private File _ooxmlJar; - - - OOXMLLite(String dest, String test, String ooxmlJar) { - _destDest = new File(dest); - _testDir = new File(test); - _ooxmlJar = new File(ooxmlJar); - } - - public static void main(String[] args) throws IOException { - System.out.println("Free memory (bytes): " + - Runtime.getRuntime().freeMemory()); - long maxMemory = Runtime.getRuntime().maxMemory(); - System.out.println("Maximum memory (bytes): " + - (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory)); - System.out.println("Total memory (bytes): " + - Runtime.getRuntime().totalMemory()); - - String dest = null, test = null, ooxml = null; - - for (int i = 0; i < args.length; i++) { - switch (args[i]) { - case "-dest": - dest = args[++i]; // lgtm[java/index-out-of-bounds] - break; - case "-test": - test = args[++i]; // lgtm[java/index-out-of-bounds] - break; - case "-ooxml": - ooxml = args[++i]; // lgtm[java/index-out-of-bounds] - break; - } - } - OOXMLLite builder = new OOXMLLite(dest, test, ooxml); - builder.build(); - } - - void build() throws IOException { - List> lst = new ArrayList<>(); - //collect unit tests - String exclude = StringUtil.join("|", - "BaseTestXWorkbook", - "BaseTestXSheet", - "BaseTestXRow", - "BaseTestXCell", - "BaseTestXSSFPivotTable", - "TestSXSSFWorkbook\\$\\d", - "TestUnfixedBugs", - "MemoryUsage", - "TestDataProvider", - "TestDataSamples", - "All.+Tests", - "ZipFileAssert", - "AesZipFileZipEntrySource", - "TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource", - "PkiTestUtils", - "TestCellFormatPart\\$\\d", - "TestSignatureInfo\\$\\d", - "TestCertificateEncryption\\$CertData", - "TestPOIXMLDocument\\$OPCParser", - "TestPOIXMLDocument\\$TestFactory", - "TestXSLFTextParagraph\\$DrawTextParagraphProxy", - "TestXSSFExportToXML\\$\\d", - "TestXSSFExportToXML\\$DummyEntityResolver", - "TestFormulaEvaluatorOnXSSF\\$Result", - "TestFormulaEvaluatorOnXSSF\\$SS", - "TestMultiSheetFormulaEvaluatorOnXSSF\\$Result", - "TestMultiSheetFormulaEvaluatorOnXSSF\\$SS", - "TestXSSFBugs\\$\\d", - "AddImageBench", - "AddImageBench_jmhType_B\\d", - "AddImageBench_benchCreatePicture_jmhTest", - "TestEvilUnclosedBRFixingInputStream\\$EvilUnclosedBRFixingInputStream", - "TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource\\$TempFileRecordingSheetDataWriterWithDecorator", - "TestXSSFBReader\\$1", - "TestXSSFBReader\\$TestSheetHandler", - "TestFormulaEvaluatorOnXSSF\\$1", - "TestMultiSheetFormulaEvaluatorOnXSSF\\$1", - "TestZipPackagePropertiesMarshaller\\$1", - "SLCommonUtils", - "TestPPTX2PNG\\$1", - "TestMatrixFormulasFromXMLSpreadsheet\\$1", - "TestMatrixFormulasFromXMLSpreadsheet\\$Navigator", - "TestPOIXMLDocument\\$UncaughtHandler", - "TestOleShape\\$Api", - "TestOleShape\\$1", - "TestPOIXMLDocument\\$1", - "TestXMLSlideShow\\$1", - "TestXMLSlideShow\\$BufAccessBAOS", - "TestXDDFChart\\$1", - "TestOOXMLLister\\$1", - "TestOOXMLPrettyPrint\\$1" - ); - System.out.println("Collecting unit tests from " + _testDir); - collectTests(_testDir, _testDir, lst, ".+.class$", ".+(" + exclude + ").class"); - System.out.println("Found " + lst.size() + " classes"); - - //run tests - JUnitCore jUnitCore = new JUnitCore(); - jUnitCore.addListener(new TextListener(System.out) { - private final Set classes = new HashSet<>(); - private int count; - - @Override - public void testStarted(Description description) { - // count how many test-classes we already saw - classes.add(description.getClassName()); - count++; - if(count % 100 == 0) { - System.out.println(); - System.out.println(classes.size() + "/" + lst.size() + ": " + description.getDisplayName()); - } - - super.testStarted(description); - } - }); - Result result = jUnitCore.run(lst.toArray(new Class[0])); - if (!result.wasSuccessful()) { - throw new RuntimeException("Tests did not succeed, cannot build ooxml-lite jar"); - } - - //see what classes from the ooxml-schemas.jar are loaded - System.out.println("Copying classes to " + _destDest); - Set> classes = getLoadedClasses(_ooxmlJar.getName()); - Set packages = new HashSet<>(); - for (Class cls : classes) { - copyFile(cls); - packages.add(cls.getPackage().getName()); - - if (cls.isInterface()) { - /// Copy classes and interfaces declared as members of this class - for (Class fc : cls.getDeclaredClasses()) { - copyFile(fc); - } - } - } - for (String pkg : packages) { - Reflections reflections = new Reflections(pkg); - Set> listClasses = reflections.getSubTypesOf(List.class); - listClasses.removeAll(classes); - for (Class listClass : listClasses) { - for (Class compare : classes) { - if (listClass.getName().startsWith(compare.getName())) { - copyFile(listClass); - } - } - } - Set> enumClasses = reflections.getSubTypesOf(StringEnumAbstractBase.class); - listClasses.removeAll(classes); - for (Class enumClass : enumClasses) { - for (Class compare : classes) { - if (enumClass.getName().startsWith(compare.getName())) { - copyFile(enumClass); - } - } - } - } - - //finally copy the compiled .xsb files - System.out.println("Copying .xsb resources"); - try (JarFile jar = new JarFile(_ooxmlJar)) { - for (Enumeration e = jar.entries(); e.hasMoreElements(); ) { - JarEntry je = e.nextElement(); - if (SCHEMA_PATTERN.matcher(je.getName()).matches()) { - File destFile = new File(_destDest, je.getName()); - IOUtils.copy(jar.getInputStream(je), destFile); - } - } - } - } - - private void copyFile(Class cls) throws IOException { - String className = cls.getName(); - String classRef = className.replace('.', '/') + ".class"; - File destFile = new File(_destDest, classRef); - IOUtils.copy(cls.getResourceAsStream('/' + classRef), destFile); - } - - private static boolean checkForTestAnnotation(Class testclass) { - for (Method m : testclass.getDeclaredMethods()) { - if(m.isAnnotationPresent(Test.class)) { - return true; - } - } - - // also check super classes - if(testclass.getSuperclass() != null) { - for (Method m : testclass.getSuperclass().getDeclaredMethods()) { - if(m.isAnnotationPresent(Test.class)) { - return true; - } - } - } - - System.out.println("Class " + testclass.getName() + " does not derive from TestCase and does not have a @Test annotation"); - - // Should we also look at superclasses to find cases - // where we have abstract base classes with derived tests? - // if(checkForTestAnnotation(testclass.getSuperclass())) return true; - - return false; - } - - /** - * Recursively collect classes from the supplied directory - * - * @param arg the directory to search in - * @param out output - * @param ptrn the pattern (regexp) to filter found files - */ - private static void collectTests(File root, File arg, List> out, String ptrn, String exclude) { - if (arg.isDirectory()) { - File files[] = arg.listFiles(); - if (files != null) { - for (File f : files) { - collectTests(root, f, out, ptrn, exclude); - } - } - } else { - String path = arg.getAbsolutePath(); - String prefix = root.getAbsolutePath(); - String cls = path.substring(prefix.length() + 1).replace(File.separator, "."); - if(!cls.matches(ptrn)) { - return; - } - if (cls.matches(exclude)) { - return; - } - //ignore inner classes defined in tests - if (cls.indexOf('$') != -1) { - System.out.println("Inner class " + cls + " not included"); - return; - } - - cls = cls.replace(".class", ""); - - try { - Class testclass = Class.forName(cls); - if (TestCase.class.isAssignableFrom(testclass) - || checkForTestAnnotation(testclass)) { - out.add(testclass); - } - } catch (Throwable e) { // NOSONAR - System.out.println("Class " + cls + " is not in classpath"); - } - } - } - - /** - * - * @param ptrn the pattern to filter output - * @return the classes loaded by the system class loader - */ - @SuppressWarnings("unchecked") - private static Set> getLoadedClasses(String ptrn) { - // make the field accessible, we defer this from static initialization to here to - // allow JDKs which do not have this field (e.g. IBM JDK) to at least load the class - // without failing, see https://issues.apache.org/bugzilla/show_bug.cgi?id=56550 - final Field _classes = AccessController.doPrivileged(new PrivilegedAction() { - @Override - @SuppressForbidden("TODO: Reflection works until Java 8 on Oracle/Sun JDKs, but breaks afterwards (different classloader types, access checks)") - public Field run() { - try { - Field fld = ClassLoader.class.getDeclaredField("classes"); - fld.setAccessible(true); - return fld; - } catch (Exception e) { - throw new RuntimeException(e); - } - - } - }); - - ClassLoader appLoader = ClassLoader.getSystemClassLoader(); - try { - Vector> classes = (Vector>) _classes.get(appLoader); - Set> set = new HashSet<>(); - for (Class cls : classes) { - // e.g. proxy-classes, ... - ProtectionDomain pd = cls.getProtectionDomain(); - if (pd == null) { - continue; - } - CodeSource cs = pd.getCodeSource(); - if (cs == null) { - continue; - } - URL loc = cs.getLocation(); - if (loc == null) { - continue; - } - - String jar = loc.toString(); - if (jar.contains(ptrn)) { - set.add(cls); - } - } - return set; - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java b/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java new file mode 100644 index 0000000000..48c9240e98 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java @@ -0,0 +1,78 @@ +/* ==================================================================== + 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.poi.ooxml.util; + +import java.io.IOException; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.security.ProtectionDomain; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +/** + * OOXMLLiteAgent is the replacement for the former OOXMLLite, because in Java 12 + * it isn't possible to access the privates :) of the ClassLoader + */ +public class OOXMLLiteAgent { + + static class LoggingTransformer implements ClassFileTransformer { + final Path path; + final Pattern includes; + final Set fileHashes = new HashSet<>(); + + public LoggingTransformer(String agentArgs) { + String args[] = (agentArgs == null ? "" : agentArgs).split("\\|",2); + path = Paths.get(args.length >= 1 ? args[0] : "ooxml-lite.out"); + includes = Pattern.compile(args.length >= 2 ? args[1] : ".*/schemas/.*"); + + try { + if (Files.exists(path)) { + try (Stream stream = Files.lines(path)) { + stream.forEach((s) -> fileHashes.add(s.hashCode())); + } + } else { + Files.createFile(path); + } + } catch (IOException ignored) { + } + } + + public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) { + if (path != null && className != null && !fileHashes.contains(className.hashCode()) && includes.matcher(className).find()) { + try { + // TODO: check if this is atomic ... as transform() is probably called synchronized, it doesn't matter anyway + Files.write(path, (className+"\n").getBytes(StandardCharsets.ISO_8859_1), StandardOpenOption.APPEND); + fileHashes.add(className.hashCode()); + } catch (IOException ignroed) { + } + } + return bytes; + } + } + + public static void premain(String agentArgs, Instrumentation inst) { + inst.addTransformer(new LoggingTransformer(agentArgs)); + } +} diff --git a/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java b/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java index 583fa8b851..fd1c8d8a10 100644 --- a/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java +++ b/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java @@ -41,7 +41,7 @@ public class TestCellFormatPart extends CellFormatTestBase { @BeforeClass public static void setLocale() { userLocale = LocaleUtil.getUserLocale(); - LocaleUtil.setUserLocale(Locale.ROOT); + LocaleUtil.setUserLocale(Locale.UK); } @AfterClass diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java index 18f59725bb..87655cb3ae 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java @@ -18,6 +18,7 @@ package org.apache.poi.hmef; import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.List; import java.util.Locale; @@ -83,9 +84,7 @@ public final class TestAttachments extends HMEFTest { List attachments = quick.getAttachments(); // Pick a predictable date format + timezone - DateFormat fmt = DateFormat.getDateTimeInstance( - DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.UK - ); + DateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss", Locale.UK); fmt.setTimeZone(LocaleUtil.TIMEZONE_UTC); // They should all have the same date on them diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java index f854394816..7fcad02042 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java @@ -20,6 +20,7 @@ package org.apache.poi.hmef.attribute; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Locale; import org.apache.poi.POIDataSamples; @@ -159,9 +160,7 @@ protected void tearDown() throws Exception { assertEquals(MAPIDateAttribute.class, attr.getClass()); MAPIDateAttribute date = (MAPIDateAttribute)attr; - DateFormat fmt = DateFormat.getDateTimeInstance( - DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.UK - ); + DateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss", Locale.UK); fmt.setTimeZone(LocaleUtil.TIMEZONE_UTC); assertEquals("15-Dec-2010 14:46:31", fmt.format(date.getDate())); diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java index cd13b94b39..04004fae23 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java @@ -19,6 +19,7 @@ package org.apache.poi.hmef.attribute; import java.io.ByteArrayInputStream; import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Locale; import org.apache.poi.POIDataSamples; @@ -159,9 +160,7 @@ public final class TestTNEFAttributes extends TestCase { // Ask for it as a Java date, and have it converted // Pick a predictable format + location + timezone TNEFDateAttribute date = (TNEFDateAttribute)attr; - DateFormat fmt = DateFormat.getDateTimeInstance( - DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.UK - ); + DateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss", Locale.UK); fmt.setTimeZone(LocaleUtil.TIMEZONE_UTC); assertEquals("28-Apr-2010 12:40:56", fmt.format(date.getDate())); } diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestExcelStyleDateFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestExcelStyleDateFormatter.java index f4e61801a5..9d64f3a8a0 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/TestExcelStyleDateFormatter.java +++ b/src/testcases/org/apache/poi/ss/usermodel/TestExcelStyleDateFormatter.java @@ -23,119 +23,100 @@ import java.text.DateFormatSymbols; import java.text.FieldPosition; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.poi.util.LocaleUtil; import org.junit.Test; public class TestExcelStyleDateFormatter { private static final String EXCEL_DATE_FORMAT = "MMMMM"; + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT); + private final int jreVersion; + + public TestExcelStyleDateFormatter() { + jreVersion = Integer.parseInt(System.getProperty("java.version") + .replace("1.8", "8").replaceAll("(\\d+).*", "$1")); + } /** * [Bug 60369] Month format 'MMMMM' issue with TEXT-formula and Java 8 */ @Test - public void test60369() throws ParseException { - Map> testMap = initializeLocales(); + public void test60369() { + Map testMap = initializeLocales(); // We have to set up dates as well. - SimpleDateFormat testDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - List testDates = Arrays.asList( - testDateFormat.parse("12.01.1980"), - testDateFormat.parse("11.02.1995"), - testDateFormat.parse("10.03.2045"), - testDateFormat.parse("09.04.2016"), - testDateFormat.parse("08.05.2017"), - testDateFormat.parse("07.06.1945"), - testDateFormat.parse("06.07.1998"), - testDateFormat.parse("05.08.2099"), - testDateFormat.parse("04.09.1988"), - testDateFormat.parse("03.10.2023"), - testDateFormat.parse("02.11.1978"), - testDateFormat.parse("01.12.1890")); + List testDates = Stream.of("1980-01-12", "1995-02-11", "2045-03-10", "2016-04-09", "2017-05-08", + "1945-06-07", "1998-07-06", "2099-08-05", "1988-09-04", "2023-10-03", "1978-11-02", "1890-12-01") + .map(this::parseDate).collect(Collectors.toList()); // Let's iterate over the test setup. - for (Locale locale : testMap.keySet()) { - ExcelStyleDateFormatter formatter = new ExcelStyleDateFormatter(EXCEL_DATE_FORMAT, new DateFormatSymbols(locale)); - for (int i = 0; i < testDates.size(); i++) { - // Call the method to be tested! - String result = - formatter.format(testDates.get(i), - new StringBuffer(), - new FieldPosition(java.text.DateFormat.MONTH_FIELD)).toString(); - //System.err.println(result + " - " + getUnicode(result.charAt(0))); - assertEquals("Failed for locale " + locale + ", provider: " + System.getProperty("java.locale.providers") + - " and date " + testDates.get(i) + ", having: " + result, - getUnicode(testMap.get(locale).get(i).charAt(0)), getUnicode(result.charAt(0))); + final String provider = System.getProperty("java.locale.providers"); + final FieldPosition fp = new FieldPosition(java.text.DateFormat.MONTH_FIELD); + final ExcelStyleDateFormatter formatter = new ExcelStyleDateFormatter(EXCEL_DATE_FORMAT); + final StringBuffer sb = new StringBuffer(); + + for (Map.Entry me : testMap.entrySet()) { + final Locale locale = me.getKey(); + final String expected = me.getValue(); + formatter.setDateFormatSymbols(DateFormatSymbols.getInstance(locale)); + int month = 0; + for (Date d : testDates) { + sb.setLength(0); + String result = formatter.format(d, sb, fp).toString(); + String msg = "Failed testDates for locale " + locale + ", provider: " + provider + + " and date " + d + ", having: " + result; + + int actIdx = (Locale.CHINESE.equals(locale) && jreVersion >= 12) ? 1 : 0; + + assertEquals(msg, expected.charAt(month), result.charAt(actIdx)); + month++; } } } - private Map> initializeLocales() { - // Setting up the locale to be tested together with a list of asserted unicode-formatted results and put them in a map. - Locale germanLocale = Locale.GERMAN; - List germanResultList = Arrays.asList("\u004a", "\u0046", "\u004d", "\u0041", "\u004d", - "\u004a", "\u004a", "\u0041", "\u0053", "\u004f", "\u004e", "\u0044"); - - Locale russianLocale = new Locale("ru", "RU"); - List russianResultList = Arrays.asList("\u044f", "\u0444", "\u043c", "\u0430", "\u043c", - "\u0438", "\u0438", "\u0430", "\u0441", "\u043e", "\u043d", "\u0434"); - - Locale austrianLocale = new Locale("de", "AT"); - List austrianResultList = Arrays.asList("\u004a", "\u0046", "\u004d", "\u0041", "\u004d", - "\u004a", "\u004a", "\u0041", "\u0053", "\u004f", "\u004e", "\u0044"); - - Locale englishLocale = Locale.UK; - List englishResultList = Arrays.asList("\u004a", "\u0046", "\u004d", "\u0041", "\u004d", - "\u004a", "\u004a", "\u0041", "\u0053", "\u004f", "\u004e", "\u0044"); - - Locale frenchLocale = Locale.FRENCH; - List frenchResultList = Arrays.asList("\u006a", "\u0066", "\u006d", "\u0061", "\u006d", - "\u006a", "\u006a", "\u0061", "\u0073", "\u006f", "\u006e", "\u0064"); - - Locale chineseLocale = Locale.CHINESE; - List chineseResultList = Arrays.asList("\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", - "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341", "\u5341", "\u5341"); - - Locale turkishLocale = new Locale("tr", "TR"); - List turkishResultList = Arrays.asList("\u004f", "\u015e", "\u004d", "\u004e", "\u004d", - "\u0048", "\u0054", "\u0041", "\u0045", "\u0045", "\u004b", "\u0041"); - - Locale hungarianLocale = new Locale("hu", "HU"); - List hungarianResultList = Arrays.asList("\u006a", "\u0066", "\u006d", "\u00e1", "\u006d", - "\u006a", "\u006a", "\u0061", "\u0073", "\u006f", "\u006e", "\u0064"); - - Locale indianLocale = new Locale("en", "IN"); - List indianResultList = Arrays.asList("\u004a", "\u0046", "\u004d", "\u0041", "\u004d", - "\u004a", "\u004a", "\u0041", "\u0053", "\u004f", "\u004e", "\u0044"); - - Locale indonesianLocale = new Locale("in", "ID"); - List indonesianResultList = Arrays.asList("\u004a", "\u0046", "\u004d", "\u0041", "\u004d", - "\u004a", "\u004a", "\u0041", "\u0053", "\u004f", "\u004e", "\u0044"); - - - Map> testMap = new HashMap<>(); - testMap.put(germanLocale, germanResultList); - testMap.put(russianLocale, russianResultList); - testMap.put(austrianLocale, austrianResultList); - testMap.put(englishLocale, englishResultList); - testMap.put(frenchLocale, frenchResultList); - testMap.put(chineseLocale, chineseResultList); - testMap.put(turkishLocale, turkishResultList); - testMap.put(hungarianLocale, hungarianResultList); - testMap.put(indianLocale, indianResultList); - testMap.put(indonesianLocale, indonesianResultList); - - return testMap; + private Date parseDate(String dateStr) { + try { + return DATE_FORMAT.parse(dateStr); + } catch (ParseException e) { + return new Date(0); + } } - private String getUnicode(char c) { - return "\\u" + Integer.toHexString(c | 0x10000).substring(1); + /** + * Setting up the locale to be tested together with a list of asserted + * unicode-formatted results and put them in a map. + */ + private Map initializeLocales() { + Map testMap = new HashMap<>(); + + testMap.put(Locale.GERMAN, "JFMAMJJASOND"); + testMap.put(new Locale("de", "AT"), "JFMAMJJASOND"); + testMap.put(Locale.UK, "JFMAMJJASOND"); + testMap.put(new Locale("en", "IN"), "JFMAMJJASOND"); + testMap.put(new Locale("in", "ID"), "JFMAMJJASOND"); + testMap.put(Locale.FRENCH, "jfmamjjasond"); + + testMap.put(new Locale("ru", "RU"), + "\u044f\u0444\u043c\u0430\u043c\u0438\u0438\u0430\u0441\u043e\u043d\u0434"); + + testMap.put(Locale.CHINESE, jreVersion < 12 + ? "\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u5341\u5341" + : "123456789111"); + + testMap.put(new Locale("tr", "TR"), + "\u004f\u015e\u004d\u004e\u004d\u0048\u0054\u0041\u0045\u0045\u004b\u0041"); + + testMap.put(new Locale("hu", "HU"), + "\u006a\u0066\u006d\u00e1\u006d\u006a\u006a\u0061\u0073\u006f\u006e\u0064"); + + return testMap; } @Test @@ -150,7 +131,7 @@ public class TestExcelStyleDateFormatter { try { LocaleUtil.setUserLocale(Locale.GERMAN); String dateStr = new ExcelStyleDateFormatter(EXCEL_DATE_FORMAT).format( - new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT).parse("2016-03-26")); + DATE_FORMAT.parse("2016-03-26")); assertEquals("M", dateStr); } finally { LocaleUtil.setUserLocale(before); @@ -160,7 +141,7 @@ public class TestExcelStyleDateFormatter { @Test public void testWithPattern() throws ParseException { String dateStr = new ExcelStyleDateFormatter("yyyy|" + EXCEL_DATE_FORMAT + "|").format( - new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT).parse("2016-03-26")); + DATE_FORMAT.parse("2016-03-26")); assertEquals("2016|M|", dateStr); } } -- 2.39.5