# Framework for testing translations # # Copyright (C) 2015 Red Hat, Inc. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU Lesser General Public License v.2, or (at your option) any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY expressed or implied, including the implied # warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See # the GNU Lesser General Public License for more details. You should have # received a copy of the GNU Lesser General Public License along with this # program; if not, write to the Free Software Foundation, Inc., 51 Franklin # Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat trademarks # that are incorporated in the source code or documentation are not subject # to the GNU Lesser General Public License and may only be used or # replicated with the express permission of Red Hat, Inc. # # Red Hat Author(s): David Shea """ Framework for running tests against translations. Tests are loaded from modules in this directory. A test is any callable object within the module with a name that starts with 'test_'. Each test is called with the name of .po file to test as an argument. A test passes if it returns without raising an exception. """ import os, warnings _tests = [] # Gather tests from this directory import pkgutil import importlib for finder, mod_name, _ispkg in pkgutil.iter_modules(__path__): # Skip __main__ if mod_name == "__main__": continue # Load the module full_name = "{}.{}".format(__name__, mod_name) module = importlib.import_module(full_name) # Look for attributes that start with 'test_' and add them to the test list for attrname, attr in module.__dict__.items(): if attrname.startswith('test_') and callable(attr): _tests.append(attr) def _remove_lingua(linguas, language): # Read in the LINGUAS file with open(linguas, "rt") as f: lingua_lines = f.readlines() output_lines = [] for line in lingua_lines: # Leave comments alone if line.startswith('#'): output_lines.append(line) continue # Split the line into a list of languages, remove the one we don't # want, and put it back together lingua_list = line.split() lingua_list.remove(language) output_lines.append(" ".join(lingua_list)) # Write LINGUAS back out with open(linguas, "wt") as f: f.writelines(output_lines) def testFile(pofile, prefix=None, releaseMode=False, modifyLinguas=True): """Run all registered tests against the given .mo file. If run in release mode, this function will always return true, and if the mofile does not pass the tests the langauge will be removed. :param str mofile: The .mo file name to check :param str prefix: An optional directory prefix to strip from error messages :param bool releaseMode: whether to run in release mode :param bool modifyLinguas: whether to remove translations from LINGUAS in release mode :return: whether the checks succeeded or not :rtype: bool """ success = True for test in _tests: # Don't print the tmpdir path in error messages if prefix is not None and pofile.startswith(prefix): poerror = pofile[len(prefix):] else: poerror = pofile try: with warnings.catch_warnings(record=True) as w: test(pofile) # Print any warnings collected for warn in w: print("%s warned on %s: %s" % (test.__name__, poerror, warn.message)) except Exception as e: # pylint: disable=broad-except print("%s failed on %s: %s" % (test.__name__, poerror, str(e))) if releaseMode: # Remove the po file and the .mo file built from it print("Removing %s" % pofile) os.remove(pofile) # Check for both .mo and .gmo mofile = os.path.splitext(pofile)[0] + '.mo' if os.path.exists(mofile): print("Removing %s" % mofile) os.remove(mofile) gmofile = os.path.splitext(pofile)[0] + '.gmo' if os.path.exists(gmofile): print("Removing %s" % gmofile) os.remove(gmofile) if modifyLinguas: # If there is a LINGUAS file in the po directory, remove the # language from it linguas = os.path.join(os.path.dirname(mofile), 'LINGUAS') if os.path.exists(linguas): language = os.path.splitext(os.path.basename(pofile))[0] print("Removing %s from LINGUAS" % language) _remove_lingua(linguas, language) # No need to run the rest of the tests since we just killed the file break else: success = False return success def testSourceTree(srcdir, releaseMode=False, modifyLinguas=True): """Runs all registered tests against all .po files in the given directory. If run in release mode, this function will always return True and the languages that do not pass the tests will be removed. :param str srcdir: The path to the source directory to check :param bool releaseMode: whether to run in release mode :param bool modifyLinguas: whether to remove translations from LINGUAS in release mode :return: whether the checks succeeded or not :rtype: bool """ success = True srcdir = os.path.normpath(srcdir) for dirpath, _dirnames, paths in os.walk(srcdir): for pofile in (os.path.join(dirpath, path) for path in paths if path.endswith('.po')): if not testFile(pofile, prefix=srcdir + "/", releaseMode=releaseMode, modifyLinguas=modifyLinguas): success = False return success