trisquel-icecat/icecat/l10n/compare-locales/compare_locales/tests/test_merge.py

1586 lines
46 KiB
Python

# 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 <em:contributor>Suzy Solon</em:contributor>
#unfilter emptyLines
"""
)
self.localized(
"""#filter emptyLines
#define MOZ_LANGPACK_CREATOR mozilla.org
#define MOZ_LANGPACK_CONTRIBUTORS <em:contributor>Jane Doe</em:contributor>
#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 <em:contributor>Suzy Solon</em:contributor>
#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(
"""<!ENTITY foo 'fooVal'>
<!ENTITY bar 'barVal'>
<!ENTITY eff 'effVal'>"""
)
self.localized(
"""<!ENTITY foo 'lFoo'>
<!ENTITY bar 'lBar'>
<!ENTITY eff 'lEff'>
"""
)
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(
"""<!ENTITY foo 'fooVal'>
<!ENTITY bar 'barVal'>
<!ENTITY eff 'effVal'>"""
)
self.localized(
"""<!ENTITY bar 'lBar'>
"""
)
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(
"""<!ENTITY foo 'fooVal'>
<!ENTITY bar 'barVal'>
<!ENTITY eff 'effVal'>"""
)
self.localized(
"""<!ENTITY foo 'fooVal'>
<!ENTY bar 'gimmick'>
<!ENTITY eff 'effVal'>
"""
)
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 "<!ENTY bar '
"'gimmick'>\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(
"""<!ENTITY foo 'fooVal'>
<!ENT bar 'bad val'>
<!ENTITY eff 'effVal'>"""
)
self.localized(
"""<!ENTITY foo 'fooVal'>
<!ENTITY eff 'effVal'>
"""
)
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(
"""<!ENTITY foo 'fooVal'>
<!ENTITY bar 'bad &val'>
<!ENTITY eff 'effVal'>"""
)
self.localized(
"""<!ENTITY foo 'fooVal'>
<!ENTITY bar 'good val'>
<!ENTITY eff 'effVal'>
"""
)
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()