| LEFT | RIGHT |
| 1 # This Source Code Form is subject to the terms of the Mozilla Public | 1 # This Source Code Form is subject to the terms of the Mozilla Public |
| 2 # License, v. 2.0. If a copy of the MPL was not distributed with this | 2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 4 | 4 |
| 5 import xml.etree.ElementTree as ET | 5 import xml.etree.ElementTree as ET |
| 6 import zipfile | |
| 7 | 6 |
| 8 import pytest | 7 import pytest |
| 9 | 8 |
| 10 from buildtools import packager, packagerEdge | 9 from buildtools import packager, packagerEdge |
| 10 |
| 11 |
| 12 @pytest.fixture |
| 13 def files(): |
| 14 """Minimal Files() for testing blockmap.""" |
| 15 str500 = b''.join(chr(i % 200 + 30) for i in range(500)) |
| 16 files = packager.Files(set(), set()) |
| 17 files['Extension/foo.xml'] = str500 |
| 18 files['Extension/bar.png'] = str500 * 200 |
| 19 return files |
| 11 | 20 |
| 12 | 21 |
| 13 def blockmap2dict(xml_data): | 22 def blockmap2dict(xml_data): |
| 14 """Convert AppxBlockMap.xml to a dict of dicts easier to inspect.""" | 23 """Convert AppxBlockMap.xml to a dict of dicts easier to inspect.""" |
| 15 return { | 24 return { |
| 16 file.get('Name'): { | 25 file.get('Name'): { |
| 17 'size': file.get('Size'), | 26 'size': file.get('Size'), |
| 18 'lfhsize': file.get('LfhSize'), | 27 'lfhsize': file.get('LfhSize'), |
| 19 'blocks': [b.get('Hash') for b in file] | 28 'blocks': [b.get('Hash') for b in file] |
| 20 } | 29 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 'js': 'application/javascript', | 78 'js': 'application/javascript', |
| 70 'json': 'application/json', | 79 'json': 'application/json', |
| 71 'otf': 'application/octet-stream', | 80 'otf': 'application/octet-stream', |
| 72 'png': 'image/png', | 81 'png': 'image/png', |
| 73 'xml': 'application/xml' | 82 'xml': 'application/xml' |
| 74 } | 83 } |
| 75 assert ctm_dict['overrides'] == { | 84 assert ctm_dict['overrides'] == { |
| 76 '/AppxBlockMap.xml': 'application/vnd.ms-appx.blockmap+xml', | 85 '/AppxBlockMap.xml': 'application/vnd.ms-appx.blockmap+xml', |
| 77 '/AppxManifest.xml': 'application/vnd.ms-appx.manifest+xml' | 86 '/AppxManifest.xml': 'application/vnd.ms-appx.manifest+xml' |
| 78 } | 87 } |
| 79 | |
| 80 | |
| 81 @pytest.mark.parametrize('metadata_files', ['metadata.edge'], indirect=True) | |
| 82 @pytest.mark.usefixtures('metadata_files') | |
| 83 def test_create_appx_manifest(files, srcdir): | |
| 84 namespaces = { | |
| 85 'ns': 'http://schemas.microsoft.com/' | |
| 86 'appx/manifest/foundation/windows10', | |
| 87 'uap': 'http://schemas.microsoft.com/appx/manifest/uap/windows10', | |
| 88 'uap3': 'http://schemas.microsoft.com/appx/manifest/uap/windows10/3', | |
| 89 } | |
| 90 | |
| 91 def first(elem): | |
| 92 return elem[0] | |
| 93 | |
| 94 def text(elem): | |
| 95 return elem.text | |
| 96 | |
| 97 def attr(attr): | |
| 98 def wrapper(elem): | |
| 99 return elem.attrib[attr] | |
| 100 return wrapper | |
| 101 | |
| 102 base = [ | |
| 103 ('.//*', [len], 21.0), | |
| 104 ('./ns:Identity', [first, attr('Publisher')], | |
| 105 'CN=4F066043-8AFE-41C9-B762-6C15E77E3F88'), | |
| 106 ('./ns:Identity', [first, attr('Version')], '1.2.3.0'), | |
| 107 ('./ns:Properties/ns:PublisherDisplayName', [first, text], | |
| 108 'Eyeo GmbH'), | |
| 109 ('./ns:Properties/ns:Logo', [first, text], 'Assets\\logo_50.png'), | |
| 110 ('./ns:Dependencies/ns:TargetDeviceFamily', | |
| 111 [first, attr('MinVersion')], | |
| 112 '10.0.14332.0'), | |
| 113 ('./ns:Dependencies/ns:TargetDeviceFamily', | |
| 114 [first, attr('MaxVersionTested')], | |
| 115 '12.0.0.0'), | |
| 116 ('./ns:Applications/ns:Application/uap:VisualElements', | |
| 117 [first, attr('Square150x150Logo')], | |
| 118 'Assets\\logo_150.png'), | |
| 119 ('./ns:Applications/ns:Application/uap:VisualElements', | |
| 120 [first, attr('Square44x44Logo')], | |
| 121 'Assets\\logo_44.png'), | |
| 122 ('./ns:Applications/ns:Application/uap:VisualElements', | |
| 123 [first, attr('Description')], | |
| 124 'Adblock Plus is the most popular ad blocker ever, and also ' | |
| 125 'supports websites by not blocking unobstrusive ads by ' | |
| 126 'default (configurable).'), | |
| 127 ('./ns:Applications/ns:Application/uap:VisualElements', | |
| 128 [first, attr('BackgroundColor')], | |
| 129 'red'), | |
| 130 ] | |
| 131 | |
| 132 devbuild = base + [ | |
| 133 ('./ns:Identity', [first, attr('Name')], | |
| 134 'EyeoGmbH.AdblockPlusdevelopmentbuild'), | |
| 135 ('./ns:Properties/ns:DisplayName', [first, text], 'devbuild-marker'), | |
| 136 ('./ns:Applications/ns:Application/uap:VisualElements', | |
| 137 [first, attr('DisplayName')], | |
| 138 'devbuild-marker'), | |
| 139 ('./ns:Applications/ns:Application/ns:Extensions/uap3:Extension/' | |
| 140 'uap3:AppExtension', | |
| 141 [first, attr('Id')], | |
| 142 'EdgeExtension'), | |
| 143 ('./ns:Applications/ns:Application/ns:Extensions/uap3:Extension/' | |
| 144 'uap3:AppExtension', | |
| 145 [first, attr('DisplayName')], | |
| 146 'devbuild-marker'), | |
| 147 ] | |
| 148 | |
| 149 release = base + [ | |
| 150 ('./ns:Identity', [first, attr('Name')], 'EyeoGmbH.AdblockPlus'), | |
| 151 ('./ns:Properties/ns:DisplayName', [first, text], 'Adblock Plus'), | |
| 152 ('./ns:Applications/ns:Application/uap:VisualElements', | |
| 153 [first, attr('DisplayName')], | |
| 154 'Adblock Plus'), | |
| 155 ('./ns:Applications/ns:Application/ns:Extensions/uap3:Extension/' | |
| 156 'uap3:AppExtension', | |
| 157 [first, attr('Id')], | |
| 158 '1.0'), | |
| 159 ('./ns:Applications/ns:Application/ns:Extensions/uap3:Extension/' | |
| 160 'uap3:AppExtension', | |
| 161 [first, attr('DisplayName')], | |
| 162 'Adblock Plus'), | |
| 163 ] | |
| 164 | |
| 165 metadata = packager.readMetadata(str(srcdir), 'edge') | |
| 166 | |
| 167 for release_build, pairs in [(False, devbuild), (True, release)]: | |
| 168 manifest = ET.fromstring(packagerEdge.create_appx_manifest( | |
| 169 {'metadata': metadata}, | |
| 170 files, | |
| 171 release_build=release_build)) | |
| 172 for expression, modifiers, value in pairs: | |
| 173 res = reduce( | |
| 174 lambda val, func: func(val), | |
| 175 modifiers, | |
| 176 manifest.findall(expression, namespaces=namespaces)) | |
| 177 assert res == value | |
| 178 | |
| 179 | |
| 180 def test_move_files_to_extension(chars): | |
| 181 files = packager.Files(set(), set()) | |
| 182 files['foo.xml'] = chars | |
| 183 files['foo/bar.xml'] = chars | |
| 184 files['Extension/foo.xml'] = chars | |
| 185 packagerEdge.move_files_to_extension(files) | |
| 186 assert set(files.keys()) == { | |
| 187 'Extension/foo.xml', | |
| 188 'Extension/foo/bar.xml', | |
| 189 'Extension/Extension/foo.xml' | |
| 190 } | |
| 191 | |
| 192 | |
| 193 @pytest.mark.parametrize('metadata_files', ['metadata.edge'], indirect=True) | |
| 194 @pytest.mark.usefixtures('metadata_files') | |
| 195 def test_create_build(tmpdir, srcdir): | |
| 196 out_file = str(tmpdir.join('abp.appx')) | |
| 197 packagerEdge.createBuild(str(srcdir), outFile=out_file, releaseBuild=True) | |
| 198 appx = zipfile.ZipFile(out_file) | |
| 199 | |
| 200 names = set(appx.namelist()) | |
| 201 assert 'AppxManifest.xml' in names | |
| 202 assert 'AppxBlockMap.xml' in names | |
| 203 assert '[Content_Types].xml' in names | |
| 204 | |
| 205 assert 'devbuild-marker' not in appx.read('AppxManifest.xml') | |
| 206 assert appx.read('Assets/logo_44.png') == '44' | |
| 207 assert appx.read('Extension/icons/abp-44.png') == '44' | |
| 208 | |
| 209 | |
| 210 @pytest.mark.parametrize('metadata_files', ['metadata.edge'], indirect=True) | |
| 211 @pytest.mark.usefixtures('metadata_files') | |
| 212 def test_create_devbuild(tmpdir, srcdir): | |
| 213 out_file = str(tmpdir.join('abp.appx')) | |
| 214 packagerEdge.createBuild(str(srcdir), outFile=out_file, releaseBuild=False) | |
| 215 appx = zipfile.ZipFile(out_file) | |
| 216 assert 'devbuild-marker' in appx.read('AppxManifest.xml') | |
| LEFT | RIGHT |