branch: elpa/datetime
commit 38a85cb35253a15f10f7451fe4a03990044a31b8
Author: Paul Pogonyshev <pogonys...@gmail.com>
Commit: Paul Pogonyshev <pogonys...@gmail.com>

    Fix another bug in 'HarvestData' tool; no effect currently, but would be 
uncovered by future changes.
---
 Eldev                |   3 +-
 dev/HarvestData.java | 140 +++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 115 insertions(+), 28 deletions(-)

diff --git a/Eldev b/Eldev
index ef79863fca..c4e38c2cde 100644
--- a/Eldev
+++ b/Eldev
@@ -55,7 +55,8 @@
     :destination    '(t nil)
     :forward-output 'stderr
     (unless (= exit-code 0)
-      (signal 'eldev-error `("`HarvestData' tool exited with error code %d: 
%s" ,exit-code ,(buffer-string))))
+      (signal 'eldev-error `(:hint "stderr output, if any, is shown above"
+                                   "`HarvestData' tool exited with error code 
%d:\n%s" ,exit-code ,(if (eobp) "[no stdout output]" (buffer-string)))))
     (eldev-trace "Building an extmap out of it...")
     (apply #'extmap-from-alist target (eldev-read-wholly (buffer-string) 
"`HarvestData' output") :overwrite t extmap-flags)))
 
diff --git a/dev/HarvestData.java b/dev/HarvestData.java
index eabd023a40..cb242de90f 100644
--- a/dev/HarvestData.java
+++ b/dev/HarvestData.java
@@ -1,3 +1,4 @@
+import java.lang.reflect.*;
 import java.time.*;
 import java.time.chrono.*;
 import java.time.format.*;
@@ -20,6 +21,8 @@ public class HarvestData
 
     public static void main (String[] args) throws Exception
     {
+        SelfTests.run ();
+
         if (Arrays.asList (args).contains ("--locales"))
             printLocaleData ();
 
@@ -235,49 +238,67 @@ public class HarvestData
         return toLispPlist (data, false);
     }
 
+
+    private static Map <String, String>  LOCALE_FALLBACK_KEYS  = Map.of 
(":month-standalone-abbr",    ":month-context-abbr",
+                                                                         
":month-standalone-names",   ":month-context-names",
+                                                                         
":weekday-standalone-abbr",  ":weekday-context-abbr",
+                                                                         
":weekday-standalone-names", ":weekday-context-names");
+    private static Map <String, String>  LOCALE_DEFAULT_VALUES = Map.of 
(":decimal-separator",        "?.",
+                                                                         
":eras",                     ENGLISH_ERAS,
+                                                                         
":am-pm",                    ENGLISH_AM_PM,
+                                                                         
":date-time-pattern-rule",   "(t . \" \")");
+
     protected static void removeUnnecessaryLocaleData (Map <Locale, Map 
<String, String>> data, Locale locale)
     {
         Map <String, String>  locale_data = data.get (locale);
         Locale                parent      = new Locale (locale.getLanguage ());
-        Map <String, String>  parent_data;
+        Map <String, String>  parent_data = null;
 
-        if (Objects.equals (locale, parent))
-            parent_data = new HashMap <> ();
-        else {
+        if (!Objects.equals (locale, parent)) {
             removeUnnecessaryLocaleData (data, parent);
             parent_data = data.get (parent);
 
             locale_data.put (":parent", parent.toLanguageTag ());
         }
 
-        removeForFallback1 (locale_data, parent_data, ":decimal-separator",    
  "?.");
-        removeForFallback1 (locale_data, parent_data, ":eras",                 
  ENGLISH_ERAS);
-        removeForFallback1 (locale_data, parent_data, ":am-pm",                
  ENGLISH_AM_PM);
-        removeForFallback1 (locale_data, parent_data, ":day-periods",          
  null);
-        removeForFallback1 (locale_data, parent_data, 
":date-time-pattern-rule", "(t . \" \")");
-
-        removeForFallback2 (locale_data, parent_data, 
":month-standalone-abbr",    ":month-context-abbr");
-        removeForFallback2 (locale_data, parent_data, 
":month-standalone-names",   ":month-context-names");
-        removeForFallback2 (locale_data, parent_data, 
":weekday-standalone-abbr",  ":weekday-context-abbr");
-        removeForFallback2 (locale_data, parent_data, 
":weekday-standalone-names", ":weekday-context-names");
-
-        for (Iterator <Map.Entry <String, String>> it = locale_data.entrySet 
().iterator (); it.hasNext ();) {
-            Map.Entry <String, String>  entry = it.next ();
-            if (Objects.equals (entry.getValue (), parent_data.get 
(entry.getKey ())))
-                it.remove ();
+        // See the various tests for this method.  Removals below need to 
satisfy them all.
+
+        for (var entry : LOCALE_FALLBACK_KEYS.entrySet ()) {
+            var  key         = entry.getKey ();
+            var  fallback_to = entry.getValue ();
+
+            if (locale_data.containsKey (key) && Objects.equals 
(locale_data.get (key), locale_data.get (fallback_to)))
+                locale_data.remove (key);
         }
-    }
 
-    protected static void removeForFallback1 (Map <String, String> 
locale_data, Map <String, String> parent_data, String key, String default_value)
-    {
-        if (Objects.equals (locale_data.get (key), parent_data.getOrDefault 
(key, default_value)))
-            locale_data.remove (key);
+        for (var it = locale_data.entrySet ().iterator (); it.hasNext ();) {
+            var  entry = it.next ();
+            var  key   = entry.getKey ();
+
+            if (!key.equals (":parent") && !LOCALE_FALLBACK_KEYS.containsKey 
(key)) {
+                if (Objects.equals (entry.getValue (), getEffectiveValue 
(parent_data, entry.getKey ())))
+                    it.remove ();
+            }
+        }
+
+        if (parent_data != null) {
+            for (var entry : LOCALE_FALLBACK_KEYS.entrySet ()) {
+                var  key         = entry.getKey ();
+                var  fallback_to = entry.getValue ();
+
+                if (locale_data.containsKey (key) && locale_data.get 
(fallback_to) == null && Objects.equals (locale_data.get (key), parent_data.get 
(key)))
+                    locale_data.remove (key);
+            }
+        }
     }
 
-    protected static void removeForFallback2 (Map <String, String> 
locale_data, Map <String, String> parent_data, String main_key, String 
fallback_key)
+    protected static String getEffectiveValue (Map <String, String> 
locale_data, String key)
     {
-        if (Objects.equals (locale_data.get (main_key), locale_data.get 
(fallback_key)))
-            locale_data.remove (main_key);
+        String  value = (locale_data != null ? locale_data.get (key) : null);
+        if (value != null)
+            return value;
+        else
+            return LOCALE_DEFAULT_VALUES.get (key);
     }
 
 
@@ -637,4 +658,69 @@ public class HarvestData
             return String.format (dst ? "%d.0" : "%d", seconds);
         }
     }
+
+
+    // Normally tests should be separate, but since this is a run-once tool 
and we don't
+    // have a proper Java setup for testing in this project, it's fine to do 
it like this.
+    protected static class SelfTests
+    {
+        public void testRemoveUnnecessaryLocaleData ()
+        {
+            var  xx    = Locale.forLanguageTag ("xx");
+            var  xx_yy = Locale.forLanguageTag ("xx-YY");
+            var  data1 = Map.of (xx,    modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "1"),
+                                 xx_yy, modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "1"));
+
+            removeUnnecessaryLocaleData (data1, xx_yy);
+            assertEquals (data1, Map.of (xx,    modifiableMap 
(":month-context-abbr", "1"),
+                                         xx_yy, modifiableMap (":parent", 
"xx")));
+
+            var  data2 = Map.of (xx,    modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "2"),
+                                 xx_yy, modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "2"));
+
+            removeUnnecessaryLocaleData (data2, xx_yy);
+            assertEquals (data2, Map.of (xx,    modifiableMap 
(":month-context-abbr", "1", ":month-standalone-abbr", "2"),
+                                         xx_yy, modifiableMap (":parent", 
"xx")));
+
+            var  data3 = Map.of (xx,    modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "2"),
+                                 xx_yy, modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "3"));
+
+            removeUnnecessaryLocaleData (data3, xx_yy);
+            assertEquals (data3, Map.of (xx,    modifiableMap 
(":month-context-abbr", "1", ":month-standalone-abbr", "2"),
+                                         xx_yy, modifiableMap (":parent", 
"xx", ":month-standalone-abbr", "3")));
+
+            var  data4 = Map.of (xx,    modifiableMap 
(":month-standalone-abbr", "2"),
+                                 xx_yy, modifiableMap (":month-context-abbr", 
"1", ":month-standalone-abbr", "2"));
+
+            removeUnnecessaryLocaleData (data4, xx_yy);
+            assertEquals (data4, Map.of (xx,    modifiableMap 
(":month-standalone-abbr", "2"),
+                                         xx_yy, modifiableMap (":parent", 
"xx", ":month-context-abbr", "1", ":month-standalone-abbr", "2")));
+        }
+
+
+        protected Map <String, String> modifiableMap (String... 
key_value_pairs)
+        {
+            var  map = new LinkedHashMap <String, String> ();
+            for (int k = 0; k < key_value_pairs.length; k += 2)
+                map.put (key_value_pairs[k], key_value_pairs[k + 1]);
+
+            return map;
+        }
+
+        protected void assertEquals (Object actual, Object expected)
+        {
+            if (!Objects.equals (actual, expected))
+                throw new Error (String.format ("self-test has failed:\n    
expected: %s\n    but was:  %s", expected, actual));
+        }
+
+
+        public static void run () throws Exception
+        {
+            var  me = new SelfTests ();
+            for (var method : me.getClass ().getDeclaredMethods ()) {
+                if (method.getName ().startsWith ("test") && 
method.getParameterCount () == 0 && !Modifier.isStatic (method.getModifiers ()))
+                    method.invoke (me);
+            }
+        }
+    }
 }

Reply via email to