# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. import unittest import filecmp import os from tempfile import mkdtemp import shutil from compare_locales.parser import getParser from compare_locales.paths import File from compare_locales.compare.content import ContentComparer from compare_locales.compare.observer import Observer from compare_locales import mozpath class ContentMixin: extension = None # OVERLOAD @property def ref(self): return mozpath.join(self.tmp, "en-reference" + self.extension) @property def l10n(self): return mozpath.join(self.tmp, "l10n" + self.extension) def reference(self, content): with open(self.ref, "w") as f: f.write(content) def localized(self, content): with open(self.l10n, "w") as f: f.write(content) class TestNonSupported(unittest.TestCase, ContentMixin): extension = ".js" def setUp(self): self.maxDiff = None self.tmp = mkdtemp() os.mkdir(mozpath.join(self.tmp, "merge")) def tearDown(self): shutil.rmtree(self.tmp) del self.tmp def test_good(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference("""foo = 'fooVal';""") self.localized("""foo = 'lfoo';""") cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.js", ""), File(self.l10n, "l10n.js", ""), mozpath.join(self.tmp, "merge", "l10n.js"), ) self.assertDictEqual(cc.observers.toJSON(), {"summary": {}, "details": {}}) self.assertTrue( filecmp.cmp(self.l10n, mozpath.join(self.tmp, "merge", "l10n.js")) ) def test_missing(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference("""foo = 'fooVal';""") cc = ContentComparer() cc.observers.append(Observer()) cc.add( File(self.ref, "en-reference.js", ""), File(self.l10n, "l10n.js", ""), mozpath.join(self.tmp, "merge", "l10n.js"), ) self.assertDictEqual( cc.observers.toJSON(), {"summary": {}, "details": {"l10n.js": [{"missingFile": "error"}]}}, ) self.assertTrue( filecmp.cmp(self.ref, mozpath.join(self.tmp, "merge", "l10n.js")) ) def test_missing_ignored(self): def ignore(*args): return "ignore" self.assertTrue(os.path.isdir(self.tmp)) self.reference("""foo = 'fooVal';""") cc = ContentComparer() cc.observers.append(Observer(filter=ignore)) cc.add( File(self.ref, "en-reference.js", ""), File(self.l10n, "l10n.js", ""), mozpath.join(self.tmp, "merge", "l10n.js"), ) self.assertDictEqual(cc.observers.toJSON(), {"summary": {}, "details": {}}) self.assertTrue( filecmp.cmp(self.ref, mozpath.join(self.tmp, "merge", "l10n.js")) ) class TestDefines(unittest.TestCase, ContentMixin): """Test case for parsers with just CAN_COPY""" extension = ".inc" def setUp(self): self.maxDiff = None self.tmp = mkdtemp() os.mkdir(mozpath.join(self.tmp, "merge")) def tearDown(self): shutil.rmtree(self.tmp) del self.tmp def testGood(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """#filter emptyLines #define MOZ_LANGPACK_CREATOR mozilla.org #define MOZ_LANGPACK_CONTRIBUTORS Suzy Solon #unfilter emptyLines """ ) self.localized( """#filter emptyLines #define MOZ_LANGPACK_CREATOR mozilla.org #define MOZ_LANGPACK_CONTRIBUTORS Jane Doe #unfilter emptyLines """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.inc", ""), File(self.l10n, "l10n.inc", ""), mozpath.join(self.tmp, "merge", "l10n.inc"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 2, "unchanged": 1, "unchanged_w": 1, "keys": 0, } }, "details": {}, }, ) self.assertTrue( filecmp.cmp(self.l10n, mozpath.join(self.tmp, "merge", "l10n.inc")) ) def testMissing(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """#filter emptyLines #define MOZ_LANGPACK_CREATOR mozilla.org #define MOZ_LANGPACK_CONTRIBUTORS Suzy Solon #unfilter emptyLines """ ) self.localized( """#filter emptyLines #define MOZ_LANGPACK_CREATOR mozilla.org #unfilter emptyLines """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.inc", ""), File(self.l10n, "l10n.inc", ""), mozpath.join(self.tmp, "merge", "l10n.inc"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 1, "missing_w": 2, "report": 0, "obsolete": 0, "changed": 0, "changed_w": 0, "unchanged": 1, "unchanged_w": 1, "keys": 0, } }, "details": { "l10n.inc": [{"missingEntity": "MOZ_LANGPACK_CONTRIBUTORS"}] }, }, ) self.assertTrue( filecmp.cmp(self.ref, mozpath.join(self.tmp, "merge", "l10n.inc")) ) class TestProperties(unittest.TestCase, ContentMixin): extension = ".properties" def setUp(self): self.maxDiff = None self.tmp = mkdtemp() os.mkdir(mozpath.join(self.tmp, "merge")) def tearDown(self): shutil.rmtree(self.tmp) del self.tmp def testGood(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal word bar = barVal word eff = effVal""" ) self.localized( """foo = lFoo bar = lBar eff = lEff word """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 5, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": {}, }, ) self.assertTrue( filecmp.cmp(self.l10n, mozpath.join(self.tmp, "merge", "l10n.properties")) ) def testMissing(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal bar = barVal eff = effVal""" ) self.localized( """bar = lBar """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 2, "missing_w": 2, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 1, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": { "l10n.properties": [ {"missingEntity": "foo"}, {"missingEntity": "eff"}, ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") self.assertTrue(os.path.isfile(mergefile)) p = getParser(mergefile) p.readFile(mergefile) entities = p.parse() self.assertEqual(list(entities.keys()), ["bar", "foo", "eff"]) def test_missing_file(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal bar = barVal eff = effVal""" ) cc = ContentComparer() cc.observers.append(Observer()) cc.add( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 3, "missing_w": 3, "report": 0, "obsolete": 0, "changed": 0, "changed_w": 0, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": {"l10n.properties": [{"missingFile": "error"}]}, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") self.assertTrue(filecmp.cmp(self.ref, mergefile)) def testError(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal bar = %d barVal eff = effVal""" ) self.localized( """\ bar = %S lBar eff = leffVal """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 1, "warnings": 0, "missing": 1, "missing_w": 1, "report": 0, "obsolete": 0, "changed": 2, "changed_w": 3, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": { "l10n.properties": [ {"missingEntity": "foo"}, { "error": "argument 1 `S` should be `d` " "at line 1, column 7 for bar" }, ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") self.assertTrue(os.path.isfile(mergefile)) p = getParser(mergefile) p.readFile(mergefile) entities = p.parse() self.assertEqual(list(entities.keys()), ["eff", "foo", "bar"]) self.assertEqual(entities["bar"].val, "%d barVal") def testObsolete(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal eff = effVal""" ) self.localized( """foo = fooVal other = obsolete eff = leffVal """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 1, "changed": 1, "changed_w": 1, "unchanged": 1, "unchanged_w": 1, "keys": 0, } }, "details": {"l10n.properties": [{"obsoleteEntity": "other"}]}, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") self.assertTrue(filecmp.cmp(self.l10n, mergefile)) def test_obsolete_file(self): self.assertTrue(os.path.isdir(self.tmp)) self.localized( """foo = fooVal eff = leffVal """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.remove( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": {}, "details": {"l10n.properties": [{"obsoleteFile": "error"}]}, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") self.assertTrue(os.path.isfile(mergefile)) def test_duplicate(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal bar = barVal eff = effVal foo = other val for foo""" ) self.localized( """foo = localized bar = lBar eff = localized eff bar = duplicated bar """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.properties", ""), File(self.l10n, "l10n.properties", ""), mozpath.join(self.tmp, "merge", "l10n.properties"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 1, "warnings": 1, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 6, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": { "l10n.properties": [ {"warning": "foo occurs 2 times"}, {"error": "bar occurs 2 times"}, ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") self.assertTrue(filecmp.cmp(self.l10n, mergefile)) class TestDTD(unittest.TestCase, ContentMixin): extension = ".dtd" def setUp(self): self.maxDiff = None self.tmp = mkdtemp() os.mkdir(mozpath.join(self.tmp, "merge")) def tearDown(self): shutil.rmtree(self.tmp) del self.tmp def testGood(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """ """ ) self.localized( """ """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.dtd", ""), File(self.l10n, "l10n.dtd", ""), mozpath.join(self.tmp, "merge", "l10n.dtd"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 3, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": {}, }, ) self.assertTrue( filecmp.cmp(self.l10n, mozpath.join(self.tmp, "merge", "l10n.dtd")) ) def testMissing(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """ """ ) self.localized( """ """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.dtd", ""), File(self.l10n, "l10n.dtd", ""), mozpath.join(self.tmp, "merge", "l10n.dtd"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 2, "missing_w": 2, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 1, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": { "l10n.dtd": [{"missingEntity": "foo"}, {"missingEntity": "eff"}] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") self.assertTrue(os.path.isfile(mergefile)) p = getParser(mergefile) p.readFile(mergefile) entities = p.parse() self.assertEqual(list(entities.keys()), ["bar", "foo", "eff"]) def testJunk(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """ """ ) self.localized( """ """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.dtd", ""), File(self.l10n, "l10n.dtd", ""), mozpath.join(self.tmp, "merge", "l10n.dtd"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 1, "warnings": 0, "missing": 1, "missing_w": 1, "report": 0, "obsolete": 0, "changed": 0, "changed_w": 0, "unchanged": 2, "unchanged_w": 2, "keys": 0, } }, "details": { "l10n.dtd": [ { "error": 'Unparsed content "\n\" " "from line 2 column 1 to " "line 3 column 1" }, {"missingEntity": "bar"}, ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") self.assertTrue(os.path.isfile(mergefile)) p = getParser(mergefile) p.readFile(mergefile) entities = p.parse() self.assertEqual(list(entities.keys()), ["foo", "eff", "bar"]) def test_reference_junk(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """ """ ) self.localized( """ """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.dtd", ""), File(self.l10n, "l10n.dtd", ""), mozpath.join(self.tmp, "merge", "l10n.dtd"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 1, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 0, "changed_w": 0, "unchanged": 2, "unchanged_w": 2, "keys": 0, } }, "details": {"l10n.dtd": [{"warning": "Parser error in en-US"}]}, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") self.assertTrue(filecmp.cmp(self.l10n, mergefile)) def test_reference_xml_error(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """ """ ) self.localized( """ """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.dtd", ""), File(self.l10n, "l10n.dtd", ""), mozpath.join(self.tmp, "merge", "l10n.dtd"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 1, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 2, "unchanged": 2, "unchanged_w": 2, "keys": 0, } }, "details": { "l10n.dtd": [ { "warning": "can't parse en-US value at line 1, " "column 0 for bar" } ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") self.assertTrue(filecmp.cmp(self.l10n, mergefile)) class TestFluent(unittest.TestCase): maxDiff = None # we got big dictionaries to compare def reference(self, content): self.ref = os.path.join(self.tmp, "en-reference.ftl") with open(self.ref, "w") as f: f.write(content) def localized(self, content): self.l10n = os.path.join(self.tmp, "l10n.ftl") with open(self.l10n, "w") as f: f.write(content) def setUp(self): self.tmp = mkdtemp() os.mkdir(os.path.join(self.tmp, "merge")) self.ref = self.l10n = None def tearDown(self): shutil.rmtree(self.tmp) del self.tmp del self.ref del self.l10n def testGood(self): self.reference( """\ foo = fooVal bar = barVal -eff = effVal """ ) self.localized( """\ foo = lFoo bar = lBar -eff = lEff """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 3, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": {}, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testMissing(self): self.reference( """\ foo = fooVal bar = barVal -baz = bazVal eff = effVal """ ) self.localized( """\ foo = lFoo eff = lEff """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": { "l10n.ftl": [ {"missingEntity": "bar"}, {"missingEntity": "-baz"}, ], }, "summary": { None: { "errors": 0, "warnings": 0, "missing": 2, "missing_w": 2, "report": 0, "obsolete": 0, "changed": 2, "changed_w": 2, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testBroken(self): self.reference( """\ foo = fooVal bar = barVal eff = effVal """ ) self.localized( """\ -- Invalid Comment foo = lFoo bar lBar eff = lEff { """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": { "l10n.ftl": [ { "error": 'Unparsed content "-- Invalid Comment" ' "from line 1 column 1 " "to line 1 column 19" }, { "error": 'Unparsed content "bar lBar" ' "from line 3 column 1 " "to line 3 column 9" }, { "error": 'Unparsed content "eff = lEff {" ' "from line 4 column 1 " "to line 4 column 13" }, {"missingEntity": "bar"}, {"missingEntity": "eff"}, ], }, "summary": { None: { "errors": 3, "warnings": 0, "missing": 2, "missing_w": 2, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 1, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(os.path.exists(mergepath)) p = getParser(mergepath) p.readFile(mergepath) merged_entities = p.parse() self.assertEqual(list(merged_entities.keys()), ["foo"]) merged_foo = merged_entities["foo"] # foo should be l10n p.readFile(self.l10n) l10n_entities = p.parse() l10n_foo = l10n_entities["foo"] self.assertTrue(merged_foo.equals(l10n_foo)) def testMatchingReferences(self): self.reference( """\ foo = Reference { bar } """ ) self.localized( """\ foo = Localized { bar } """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": {}, "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 1, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testMismatchingReferences(self): self.reference( """\ foo = Reference { bar } bar = Reference { baz } baz = Reference """ ) self.localized( """\ foo = Localized { qux } bar = Localized baz = Localized { qux } """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": { "l10n.ftl": [ { "warning": "Missing message reference: bar " "at line 1, column 1 for foo" }, { "warning": "Obsolete message reference: qux " "at line 1, column 19 for foo" }, { "warning": "Missing message reference: baz " "at line 2, column 1 for bar" }, { "warning": "Obsolete message reference: qux " "at line 3, column 19 for baz" }, ], }, "summary": { None: { "errors": 0, "warnings": 4, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 3, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testMismatchingAttributes(self): self.reference( """ foo = Foo bar = Bar .tender = Attribute value eff = Eff """ ) self.localized( """\ foo = lFoo .obsolete = attr bar = lBar eff = lEff """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": { "l10n.ftl": [ { "error": "Obsolete attribute: " "obsolete at line 2, column 3 for foo" }, { "error": "Missing attribute: tender at line 3," " column 1 for bar", }, ], }, "summary": { None: { "errors": 2, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 5, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(os.path.exists(mergepath)) p = getParser(mergepath) p.readFile(mergepath) merged_entities = p.parse() self.assertEqual(list(merged_entities.keys()), ["eff"]) merged_eff = merged_entities["eff"] # eff should be l10n p.readFile(self.l10n) l10n_entities = p.parse() l10n_eff = l10n_entities["eff"] self.assertTrue(merged_eff.equals(l10n_eff)) def test_term_attributes(self): self.reference( """ -foo = Foo -bar = Bar -baz = Baz .attr = Baz Attribute -qux = Qux .attr = Qux Attribute -missing = Missing .attr = An Attribute """ ) self.localized( """\ -foo = Localized Foo -bar = Localized Bar .attr = Locale-specific Bar Attribute -baz = Localized Baz -qux = Localized Qux .other = Locale-specific Qux Attribute """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": { "l10n.ftl": [ {"missingEntity": "-missing"}, ], }, "summary": { None: { "errors": 0, "warnings": 0, "missing": 1, "missing_w": 1, "report": 0, "obsolete": 0, "changed": 4, "changed_w": 4, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testMismatchingValues(self): self.reference( """ foo = Foo .foottr = something bar = .tender = Attribute value """ ) self.localized( """\ foo = .foottr = attr bar = lBar .tender = localized """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": { "l10n.ftl": [ {"error": "Missing value at line 1, column 1 for foo"}, { "error": "Obsolete value at line 3, column 7 for bar", }, ] }, "summary": { None: { "errors": 2, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 2, "changed_w": 4, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(os.path.exists(mergepath)) p = getParser(mergepath) p.readFile(mergepath) merged_entities = p.parse() self.assertEqual(merged_entities, tuple()) def testMissingGroupComment(self): self.reference( """\ foo = fooVal ## Group Comment bar = barVal """ ) self.localized( """\ foo = lFoo bar = lBar """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": {}, "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 2, "changed_w": 2, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testMissingAttachedComment(self): self.reference( """\ foo = fooVal # Attached Comment bar = barVal """ ) self.localized( """\ foo = lFoo bar = barVal """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": {}, "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 1, "unchanged": 1, "unchanged_w": 1, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def testObsoleteStandaloneComment(self): self.reference( """\ foo = fooVal bar = barVal """ ) self.localized( """\ foo = lFoo # Standalone Comment bar = lBar """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "details": {}, "summary": { None: { "errors": 0, "warnings": 0, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 2, "changed_w": 2, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, }, ) # validate merge results mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergepath)) def test_duplicate(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal bar = barVal eff = effVal foo = other val for foo""" ) self.localized( """foo = localized bar = lBar eff = localized eff bar = duplicated bar """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 1, "warnings": 1, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 3, "changed_w": 6, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": { "l10n.ftl": [ {"warning": "foo occurs 2 times"}, {"error": "bar occurs 2 times"}, ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergefile)) def test_duplicate_attributes(self): self.assertTrue(os.path.isdir(self.tmp)) self.reference( """foo = fooVal .attr = good""" ) self.localized( """foo = localized .attr = not .attr = so .attr = good """ ) cc = ContentComparer() cc.observers.append(Observer()) cc.compare( File(self.ref, "en-reference.ftl", ""), File(self.l10n, "l10n.ftl", ""), mozpath.join(self.tmp, "merge", "l10n.ftl"), ) self.assertDictEqual( cc.observers.toJSON(), { "summary": { None: { "errors": 0, "warnings": 3, "missing": 0, "missing_w": 0, "report": 0, "obsolete": 0, "changed": 1, "changed_w": 2, "unchanged": 0, "unchanged_w": 0, "keys": 0, } }, "details": { "l10n.ftl": [ { "warning": 'Attribute "attr" is duplicated ' "at line 2, column 5 for foo" }, { "warning": 'Attribute "attr" is duplicated ' "at line 3, column 5 for foo" }, { "warning": 'Attribute "attr" is duplicated ' "at line 4, column 5 for foo" }, ] }, }, ) mergefile = mozpath.join(self.tmp, "merge", "l10n.ftl") self.assertTrue(filecmp.cmp(self.l10n, mergefile)) if __name__ == "__main__": unittest.main()