#! /usr/bin/env python3 import unittest import os from os.path import join import lxml.etree as ET from shutil import rmtree from tempfile import mkdtemp import zipfile from flightgear.meta import sgprops from flightgear.meta.aircraft_catalogs import catalog catalog.quiet = True class UpdateCatalogTests(unittest.TestCase): def test_scan_set(self): info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"]) self.assertEqual(info['id'], 'f16a') self.assertEqual(info['name'], 'F16-A') self.assertEqual(info['primary-set'], True) self.assertEqual(info['variant-of'], None) # self.assertEqual(info['rating_FDM'], 3) # self.assertEqual(info['rating_model'], 5) ratings = info['rating'] self.assertEqual(ratings.getValue('FDM'), 3) self.assertEqual(ratings.getValue('model'), 5) self.assertEqual(len(info['tags']), 3) self.assertEqual(info['minimum-fg-version'], '2017.4') authors = info['authors'] self.assertNotIn('author', info) self.assertEqual(len(authors.getChildren()), 2) self.assertEqual(authors.getValue('author[0]/name'), 'Wilbur Wright') self.assertEqual(authors.getValue('author[0]/nick'), 'wilburw') self.assertEqual(authors.getValue('author[0]/email'), 'ww@wright.com') self.assertEqual(authors.getValue('author[1]/name'), 'Orville Wright') locDe = info['localized']['de'] self.assertEqual(locDe["long-description"], "Describe the F16-A in German") def test_scan_dir(self): (pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/f16", ["testData/OtherDir"]) self.assertEqual(pkg['id'], 'f16a') f16trainer = next(v for v in variants if v['id'] == 'f16-trainer') self.assertEqual(len(variants), 3) self.assertEqual(pkg['minimum-fg-version'], '2017.4') # test variant relatonship between self.assertEqual(pkg['variant-of'], None) self.assertEqual(pkg['primary-set'], True) self.assertEqual(f16trainer['variant-of'], None) self.assertEqual(f16trainer['primary-set'], False) f16b = next(v for v in variants if v['id'] == 'f16b') self.assertEqual(f16b['variant-of'], 'f16a') self.assertEqual(f16b['primary-set'], False) locFr = f16b['localized']['fr'] self.assertEqual(locFr["long-description"], "Describe the F16-B in French") authorsArray = f16b['authors'] self.assertNotIn('author', f16b) self.assertEqual(authorsArray.getValue('author[0]/name'), 'James T Kirk') self.assertEqual(authorsArray.getValue('author[0]/nick'), 'starlover') f16c = next(v for v in variants if v['id'] == 'f16c') self.assertEqual(f16c['variant-of'], 'f16a') self.assertEqual(f16c['primary-set'], False) authors = f16c['authors'] self.assertNotIn('author', f16c) self.assertEqual(len(authors.getChildren()), 2) # test some older constructs for compat def test_scan_dir_legacy(self): (pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/c172", []) self.assertEqual(pkg['id'], 'c172') self.assertEqual(pkg['author'], 'Wilbur Wright') def test_extract_previews(self): info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"]) previews = info['previews'] self.assertEqual(len(previews), 3) self.assertEqual(2, len([p for p in previews if p['type'] == 'exterior'])) self.assertEqual(1, len([p for p in previews if p['type'] == 'panel'])) self.assertEqual(1, len([p for p in previews if p['path'] == 'Previews/exterior-1.png'])) def test_extract_tags(self): info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"]) tags = info['tags'] def test_node_creation(self): (pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/f16", ["testData/OtherDir"]) catalog_node = ET.Element('PropertyList') catalog_root = ET.ElementTree(catalog_node) pkgNode = catalog.make_aircraft_node('f16', pkg, variants, "http://foo.com/testOutput/", []) catalog_node.append(pkgNode) # write out so we can parse using sgprops # yes we are round-tripping via the disk, if you can improve # then feel free.. if not os.path.isdir("testOutput"): os.mkdir("testOutput") cat_file = os.path.join("testOutput", 'catalog_fragment.xml') catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True) parsed = sgprops.readProps(cat_file) parsedPkgNode = parsed.getChild("package") self.assertEqual(parsedPkgNode.name, "package"); self.assertEqual(parsedPkgNode.getValue('id'), pkg['id']); self.assertEqual(parsedPkgNode.getValue('dir'), 'f16'); self.assertEqual(parsedPkgNode.getValue('url'), 'http://foo.com/testOutput/f16.zip'); self.assertEqual(parsedPkgNode.getValue('thumbnail'), 'http://foo.com/testOutput/thumbnails/f16_thumbnail.jpg'); self.assertEqual(parsedPkgNode.getValue('thumbnail-path'), 'thumbnail.jpg'); self.assertEqual(parsedPkgNode.getValue('name'), pkg['name']); self.assertEqual(parsedPkgNode.getValue('description'), pkg['description']); self.assertEqual(parsedPkgNode.getValue('minimum-fg-version'), "2017.4"); parsedVariants = parsedPkgNode.getChildren("variant") self.assertEqual(len(parsedVariants), 3) # verify rating copying self.assertEqual(parsedPkgNode.getValue('rating/FDM'), 3) self.assertEqual(parsedPkgNode.getValue('rating/cockpit'), 2) self.assertEqual(parsedPkgNode.getValue('rating/model'), 5) self.assertEqual(parsedPkgNode.getValue('localized/de/long-description'), "Describe the F16-A in German") # author data verification self.assertFalse(parsedPkgNode.hasChild('author')); parsedAuthors = parsedPkgNode.getChild("authors").getChildren('author') self.assertEqual(len(parsedAuthors), 2) author1 = parsedAuthors[0] self.assertEqual(author1.getValue("name"), "Wilbur Wright") self.assertEqual(author1.getValue("nick"), "wilburw") self.assertEqual(author1.getValue("email"), "ww@wright.com") author2 = parsedAuthors[1] self.assertEqual(author2.getValue("name"), "Orville Wright") f16ANode = parsedPkgNode self.assertEqual(f16ANode.getValue('name'), 'F16-A'); for index, pv in enumerate(parsedVariants): var = variants[index] self.assertEqual(pv.getValue('name'), var['name']); self.assertEqual(pv.getValue('description'), var['description']); if (var['id'] == 'f16-trainer'): self.assertEqual(pv.getValue('variant-of'), '_primary_') # self.assertEqual(pv.getValue('author'), "Wilbur Wright"); elif (var['id'] == 'f16b'): self.assertEqual(pv.getValue('variant-of'), 'f16a') self.assertEqual(pv.getValue('description'), 'The F16-B is an upgraded version of the F16A.') # variant author verification parsedAuthors = pv.getChild("authors").getChildren('author') author1 = parsedAuthors[0] self.assertEqual(author1.getValue("name"), "James T Kirk") self.assertEqual(author1.getValue("nick"), "starlover") self.assertEqual(author1.getValue("email"), "shatner@enterprise.com") self.assertEqual(author1.getValue("description"), "Everything") self.assertEqual(pv.getValue('localized/de/long-description'), "Describe the F16-B in German") def test_node_creation2(self): (pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/dc3", ["testData/OtherDir"]) catalog_node = ET.Element('PropertyList') catalog_root = ET.ElementTree(catalog_node) pkgNode = catalog.make_aircraft_node('dc3', pkg, variants, "http://foo.com/testOutput/", []) catalog_node.append(pkgNode) if not os.path.isdir("testOutput"): os.mkdir("testOutput") cat_file = os.path.join("testOutput", 'catalog_fragment2.xml') catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True) parsed = sgprops.readProps(cat_file) parsedPkgNode = parsed.getChild("package") self.assertEqual(parsedPkgNode.name, "package"); self.assertEqual(parsedPkgNode.getValue('id'), pkg['id']); self.assertEqual(parsedPkgNode.getValue('dir'), 'dc3'); self.assertEqual(parsedPkgNode.getValue('url'), 'http://foo.com/testOutput/dc3.zip'); self.assertEqual(parsedPkgNode.getValue('author'), 'Donald Douglas'); parsedAuthors = parsedPkgNode.getChild("authors").getChildren('author') self.assertEqual(len(parsedAuthors), 1) author1 = parsedAuthors[0] self.assertEqual(author1.getValue("name"), "Donald Douglas") self.assertEqual(author1.getValue("nick"), "dd") self.assertEqual(author1.getValue("email"), "dd@douglas.com") urls = parsedPkgNode.getChild('urls') self.assertEqual(urls.getValue('home-page'), 'http://www.douglas.com') def test_minimalAircraft(self): # test an aircraft with a deliberately spartan -set.xml file with # most interesting data missing (pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/c150", ["testData/OtherDir"]) catalog_node = ET.Element('PropertyList') catalog_root = ET.ElementTree(catalog_node) pkgNode = catalog.make_aircraft_node('c150', pkg, variants, "http://foo.com/testOutput/", []) catalog_node.append(pkgNode) if not os.path.isdir("testOutput2"): os.mkdir("testOutput2") cat_file = os.path.join("testOutput2", 'catalog_fragment.xml') catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True) parsed = sgprops.readProps(cat_file) parsedPkgNode = parsed.getChild("package") self.assertEqual(parsedPkgNode.getValue('id'), pkg['id']) self.assertEqual(parsedPkgNode.getValue('dir'), 'c150') self.assertEqual(parsedPkgNode.getValue('url'), 'http://foo.com/testOutput/c150.zip') self.assertFalse(parsedPkgNode.hasChild('thumbnail')) self.assertFalse(parsedPkgNode.hasChild('thumbnail-path')); self.assertEqual(parsedPkgNode.getValue('name'), pkg['name']); self.assertFalse(parsedPkgNode.hasChild('description')); self.assertFalse(parsedPkgNode.hasChild('author')); self.assertFalse(parsedPkgNode.hasChild('minimum-fg-version')); self.assertFalse(parsedPkgNode.hasChild('variant')); class ZipTests(unittest.TestCase): """Specific craft zip file creation tests.""" def check_zip(self, file_name, expected_content=None): """General checks for the zip file.""" # Check for file existence. self.assertTrue(os.access(file_name, os.F_OK)) # Check the contents. file = zipfile.ZipFile(file_name) zip_contents = file.namelist() if len(zip_contents) != len(expected_content): print("Zip contents:\n %s" % zip_contents) print("Expected contents:\n %s" % expected_content) self.assertEqual(len(zip_contents), len(expected_content)) for i in range(len(zip_contents)): self.assertEqual(zip_contents[i], expected_content[i]) def setUp(self): """Common set up for these system tests.""" # Store the current directory. self._cwd = os.getcwd() # Create a temporary directory for dumping files. self.tmpdir = mkdtemp() def tearDown(self): """Delete temp files.""" # Force return to the correct directory. os.chdir(self._cwd) # Remove temporary file (if there is a deletion failure, continue to allow the test suite to survive). try: rmtree(self.tmpdir) except: pass # Remove the variable. del self.tmpdir def test_zip_creation(self): """Test the creation of a basic craft zip archive.""" # Create a basic zip file. name = "c172" catalog.make_aircraft_zip(join(os.getcwd(), "testData/Aircraft"), name, join(self.tmpdir, name+'.zip'), join(os.getcwd(), 'fgaddon-catalog/zip-excludes.lst'), verbose=False) # Checks. self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['c172/c172-set.xml']) def test_zip_exclusion_global(self): """Test file exclusion in a craft zip archive using the global catalog exclusion list.""" # Create a basic zip file. name = "dc3" catalog.make_aircraft_zip(join(os.getcwd(), "testData/Aircraft"), name, join(self.tmpdir, name+'.zip'), join(os.getcwd(), 'fgaddon-catalog/zip-excludes.lst'), verbose=False) # Checks. self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['dc3/dc3-set.xml']) def test_zip_exclusion_local(self): """Test file exclusion in a craft zip archive using a local catalog exclusion list.""" # Create a basic zip file. name = "c150" catalog.make_aircraft_zip(join(os.getcwd(), "testData/Aircraft"), name, join(self.tmpdir, name+'.zip'), join(os.getcwd(), 'testData/Aircraft/c150/zip-excludes.lst'), verbose=False) # Checks. self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['c150/c150-set.xml', 'c150/Resources/crazy_20Gb_file']) if __name__ == '__main__': unittest.main()