From e9ca6bb892b5358a273807bff834945ffe7b0cee Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Tue, 7 Mar 2017 18:01:22 +0100 Subject: [PATCH] Make bundle R/W: improvement + unit tests --- src/be/nikiroo/utils/resources/Bundle.java | 77 ++++++-- .../nikiroo/utils/resources/TransBundle.java | 20 +- src/be/nikiroo/utils/test/BundleTest.java | 174 ++++++++++++++---- src/be/nikiroo/utils/test/TestLauncher.java | 14 +- 4 files changed, 225 insertions(+), 60 deletions(-) diff --git a/src/be/nikiroo/utils/resources/Bundle.java b/src/be/nikiroo/utils/resources/Bundle.java index b4019de5..4420109c 100644 --- a/src/be/nikiroo/utils/resources/Bundle.java +++ b/src/be/nikiroo/utils/resources/Bundle.java @@ -52,7 +52,7 @@ public class Bundle> { this.type = type; this.name = name; this.changeMap = new HashMap(); - setBundle(name, Locale.getDefault()); + setBundle(name, Locale.getDefault(), false); } /** @@ -330,9 +330,14 @@ public class Bundle> { /** * Reload the {@link Bundle} data files. + * + * @param resetToDefault + * reset to the default configuration (do not look into the + * possible user configuration files, only take the original + * configuration) */ - public void reload() { - setBundle(name, null); + public void reload(boolean resetToDefault) { + setBundle(name, null, resetToDefault); } /** @@ -348,12 +353,15 @@ public class Bundle> { return true; } - try { - map.getObject(key); - return true; - } catch (MissingResourceException e) { - return false; + if (map != null) { + try { + map.getObject(key); + return true; + } catch (MissingResourceException e) { + } } + + return false; } /** @@ -370,7 +378,7 @@ public class Bundle> { return changeMap.get(key); } - if (containsKey(key)) { + if (map != null && containsKey(key)) { return map.getString(key); } @@ -536,13 +544,17 @@ public class Bundle> { * the name of the bundle to load * @param locale * the {@link Locale} to use + * @param resetToDefault + * reset to the default configuration (do not look into the + * possible user configuration files, only take the original + * configuration) */ - protected void setBundle(Enum name, Locale locale) { + protected void setBundle(Enum name, Locale locale, boolean resetToDefault) { map = null; changeMap.clear(); String dir = Bundles.getDirectory(); - if (dir != null) { + if (!resetToDefault && dir != null) { try { File file = getPropertyFile(dir, name.name(), locale); if (file != null) { @@ -556,8 +568,47 @@ public class Bundle> { } if (map == null) { - map = ResourceBundle.getBundle(type.getPackage().getName() + "." - + name.name(), locale, new FixedResourceBundleControl()); + try { + map = ResourceBundle.getBundle(type.getPackage().getName() + + "." + name.name(), locale, + new FixedResourceBundleControl()); + } catch (Exception e) { + // We have no bundle for this Bundle + map = null; + } + } + } + + /** + * Take a snapshot of the changes in memory in this {@link Bundle} made by + * the "set" methods ( {@link Bundle#setString(Enum, String)}...) at the + * current time. + * + * @return a snapshot to use with {@link Bundle#restoreChanges(Object)} + */ + protected Object takeChangesSnapshot() { + return new HashMap(changeMap); + } + + /** + * Restore a snapshot taken with {@link Bundle}, or reset the current + * changes if the snapshot is NULL. + * + * @param snap + * the snapshot or NULL + */ + @SuppressWarnings("unchecked") + protected void restoreChanges(Object snap) { + if (snap == null) { + changeMap.clear(); + } else { + if (snap instanceof Map) { + changeMap = (Map) snap; + } else { + throw new Error( + "Restoring changes in a Bundle must be done on a changes snapshot, " + + "or NULL to discard current changes"); + } } } diff --git a/src/be/nikiroo/utils/resources/TransBundle.java b/src/be/nikiroo/utils/resources/TransBundle.java index a3804401..125075a8 100644 --- a/src/be/nikiroo/utils/resources/TransBundle.java +++ b/src/be/nikiroo/utils/resources/TransBundle.java @@ -8,8 +8,6 @@ import java.util.List; import java.util.Locale; import java.util.regex.Pattern; -import be.nikiroo.utils.resources.Bundles; - /** * This class manages a translation-dedicated Bundle. *

@@ -171,12 +169,12 @@ public class TransBundle> extends Bundle { private void setLanguage(String language) { defaultLocale = (language == null || language.length() == 0); locale = getLocaleFor(language); - setBundle(name, locale); + setBundle(name, locale, false); } @Override - public void reload() { - setBundle(name, locale); + public void reload(boolean resetToDefault) { + setBundle(name, locale, resetToDefault); } @Override @@ -199,16 +197,26 @@ public class TransBundle> extends Bundle { @Override public void updateFile(String path) throws IOException { String prev = locale.getLanguage(); + Object status = takeChangesSnapshot(); - setLanguage(null); // default locale + // default locale + setLanguage(null); + if (prev.equals(getLocaleFor(null).getLanguage())) { + // restore snapshot if default locale = current locale + restoreChanges(status); + } super.updateFile(path); for (String lang : getKnownLanguages()) { setLanguage(lang); + if (lang.equals(prev)) { + restoreChanges(status); + } super.updateFile(path); } setLanguage(prev); + restoreChanges(status); } @Override diff --git a/src/be/nikiroo/utils/test/BundleTest.java b/src/be/nikiroo/utils/test/BundleTest.java index 119f3b9d..4b9ac7dd 100644 --- a/src/be/nikiroo/utils/test/BundleTest.java +++ b/src/be/nikiroo/utils/test/BundleTest.java @@ -1,6 +1,8 @@ package be.nikiroo.utils.test; import java.io.File; +import java.util.ArrayList; +import java.util.List; import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.resources.Bundle; @@ -11,10 +13,6 @@ class BundleTest extends TestLauncher { private File tmp; private B b = new B(); - protected boolean isMain() { - return true; - } - public BundleTest(String[] args) { this("Bundle test", args); } @@ -22,78 +20,175 @@ class BundleTest extends TestLauncher { protected BundleTest(String name, String[] args) { super(name, args); - addTests(); - - if (isMain()) { - addSeries(new BundleTest("After saving/reloading the resources", - args) { - @Override - protected void start() throws Exception { - tmp = File.createTempFile("nikiroo-utils", ".test"); - tmp.delete(); - tmp.mkdir(); - b.updateFile(tmp.getAbsolutePath()); - Bundles.setDirectory(tmp.getAbsolutePath()); - b.reload(); - } + for (TestCase test : getSimpleTests()) { + addTest(test); + } - @Override - protected void stop() { - IOUtils.deltree(tmp); + addSeries(new TestLauncher("After saving/reloading the resources", args) { + { + for (TestCase test : getSimpleTests()) { + addTest(test); } + } - @Override - protected boolean isMain() { - return false; - } - }); - } + @Override + protected void start() throws Exception { + tmp = File.createTempFile("nikiroo-utils", ".test"); + tmp.delete(); + tmp.mkdir(); + b.updateFile(tmp.getAbsolutePath()); + Bundles.setDirectory(tmp.getAbsolutePath()); + b.reload(false); + } + + @Override + protected void stop() { + IOUtils.deltree(tmp); + } + }); + + addSeries(new TestLauncher("Read/Write support", args) { + { + addTest(new TestCase("Reload") { + @Override + public void test() throws Exception { + String now = b.getString(E.ONE); + b.reload(true); + String def = b.getString(E.ONE); + b.reload(false); + + assertEquals("We should not have a bundle to load", + null, def); + assertEquals("We should have reloaded the same files", + now, b.getString(E.ONE)); + + // reset values for next tests + b.reload(false); + } + }); + + addTest(new TestCase("Set/Get") { + @Override + public void test() throws Exception { + String val = "Newp"; + b.setString(E.ONE, val); + String setGet = b.getString(E.ONE); + + assertEquals(val, setGet); + + // reset values for next tests + b.restoreChanges(null); + } + }); + + addTest(new TestCase("Snapshots") { + @Override + public void test() throws Exception { + String val = "Newp"; + String def = b.getString(E.ONE); + + b.setString(E.ONE, val); + Object snap = b.takeChangesSnapshot(); + + b.restoreChanges(null); + assertEquals( + "restoreChanges(null) should clear the changes", + def, b.getString(E.ONE)); + b.restoreChanges(snap); + assertEquals( + "restoreChanges(snapshot) should restore the changes", + val, b.getString(E.ONE)); + + // reset values for next tests + b.restoreChanges(null); + } + }); + + addTest(new TestCase("updateFile with changes") { + @Override + public void test() throws Exception { + String val = "Go to disk! (UTF-8 test: 日本語)"; + + String def = b.getString(E.ONE); + b.setString(E.ONE, val); + b.updateFile(tmp.getAbsolutePath()); + b.reload(false); + + assertEquals(val, b.getString(E.ONE)); + + // reset values for next tests + b.setString(E.ONE, def); + b.updateFile(tmp.getAbsolutePath()); + b.reload(false); + } + }); + } + + @Override + protected void start() throws Exception { + tmp = File.createTempFile("nikiroo-utils", ".test"); + tmp.delete(); + tmp.mkdir(); + b.updateFile(tmp.getAbsolutePath()); + Bundles.setDirectory(tmp.getAbsolutePath()); + b.reload(false); + } + + @Override + protected void stop() { + IOUtils.deltree(tmp); + } + }); } - private void addTests() { + private List getSimpleTests() { String pre = ""; - addTest(new TestCase(pre + "getString simple") { + List list = new ArrayList(); + + list.add(new TestCase(pre + "getString simple") { @Override public void test() throws Exception { assertEquals("un", b.getString(E.ONE)); } }); - addTest(new TestCase(pre + "getStringX with null suffix") { + list.add(new TestCase(pre + "getStringX with null suffix") { @Override public void test() throws Exception { assertEquals("un", b.getStringX(E.ONE, null)); } }); - addTest(new TestCase(pre + "getStringX with empty suffix") { + list.add(new TestCase(pre + "getStringX with empty suffix") { @Override public void test() throws Exception { assertEquals(null, b.getStringX(E.ONE, "")); } }); - addTest(new TestCase(pre + "getStringX with existing suffix") { + list.add(new TestCase(pre + "getStringX with existing suffix") { @Override public void test() throws Exception { assertEquals("un + suffix", b.getStringX(E.ONE, "suffix")); } }); - addTest(new TestCase(pre + "getStringX with not existing suffix") { + list.add(new TestCase(pre + "getStringX with not existing suffix") { @Override public void test() throws Exception { assertEquals(null, b.getStringX(E.ONE, "fake")); } }); - addTest(new TestCase(pre + "getString with UTF-8 content") { + list.add(new TestCase(pre + "getString with UTF-8 content") { @Override public void test() throws Exception { assertEquals("日本語 Nihongo", b.getString(E.JAPANESE)); } }); + + return list; } /** @@ -106,6 +201,17 @@ class BundleTest extends TestLauncher { super(E.class, N.bundle_test); } + @Override + // ...and make it public + public Object takeChangesSnapshot() { + return super.takeChangesSnapshot(); + } + + @Override + // ...and make it public + public void restoreChanges(Object snap) { + super.restoreChanges(snap); + } } /** diff --git a/src/be/nikiroo/utils/test/TestLauncher.java b/src/be/nikiroo/utils/test/TestLauncher.java index 10a6e279..d01e0f80 100644 --- a/src/be/nikiroo/utils/test/TestLauncher.java +++ b/src/be/nikiroo/utils/test/TestLauncher.java @@ -20,7 +20,7 @@ public class TestLauncher { private class SetupException extends Exception { private static final long serialVersionUID = 1L; - public SetupException(Exception e) { + public SetupException(Throwable e) { super(e); } } @@ -33,7 +33,7 @@ public class TestLauncher { private class TearDownException extends Exception { private static final long serialVersionUID = 1L; - public TearDownException(Exception e) { + public TearDownException(Throwable e) { super(e); } } @@ -185,20 +185,20 @@ public class TestLauncher { for (TestCase test : tests) { print(depth, test.getName()); - Exception ex = null; + Throwable ex = null; try { try { test.setUp(); - } catch (Exception e) { + } catch (Throwable e) { throw new SetupException(e); } test.test(); try { test.tearDown(); - } catch (Exception e) { + } catch (Throwable e) { throw new TearDownException(e); } - } catch (Exception e) { + } catch (Throwable e) { ex = e; } @@ -300,7 +300,7 @@ public class TestLauncher { * @param error * the {@link Exception} it ran into if any */ - private void print(int depth, Exception error) { + private void print(int depth, Throwable error) { if (error != null) { System.out.println(" " + koString); StringWriter sw = new StringWriter(); -- 2.27.0