1#!/usr/bin/env python3 2# 3# Copyright (C) 2021 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import io 18from pathlib import Path 19import tempfile 20import unittest 21import zipfile 22 23import merge_annotation_zips 24 25 26zip_a = { 27 'android/provider/annotations.xml': 28 """<?xml version="1.0" encoding="UTF-8"?> 29<root> 30 <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)"> 31 <annotation name="androidx.annotation.WorkerThread"/> 32 </item> 33 <item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2"> 34 <annotation name="androidx.annotation.IntRange"> 35 <val name="from" val="1" /> 36 </annotation> 37 </item> 38</root>""", 39 'android/os/annotations.xml': 40 """<?xml version="1.0" encoding="UTF-8"?> 41<root> 42 <item name="android.app.ActionBar void setCustomView(int) 0"> 43 <annotation name="androidx.annotation.LayoutRes"/> 44 </item> 45</root> 46""" 47} 48 49zip_b = { 50 'android/provider/annotations.xml': 51 """<?xml version="1.0" encoding="UTF-8"?> 52<root> 53 <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE"> 54 <annotation name="androidx.annotation.IntDef"> 55 <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> 56 <val name="flag" val="true" /> 57 </annotation> 58 </item> 59 <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING"> 60 <annotation name="androidx.annotation.IntDef"> 61 <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> 62 <val name="flag" val="true" /> 63 </annotation> 64 </item> 65</root>""" 66} 67 68zip_c = { 69 'android/app/annotations.xml': 70 """<?xml version="1.0" encoding="UTF-8"?> 71<root> 72 <item name="android.app.ActionBar void setCustomView(int) 0"> 73 <annotation name="androidx.annotation.LayoutRes"/> 74 </item> 75</root>""" 76} 77 78merged_provider = """<?xml version='1.0' encoding='UTF-8'?> 79<root> 80 <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)"> 81 <annotation name="androidx.annotation.WorkerThread" /> 82 </item> 83 <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE"> 84 <annotation name="androidx.annotation.IntDef"> 85 <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> 86 <val name="flag" val="true" /> 87 </annotation> 88 </item> 89 <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING"> 90 <annotation name="androidx.annotation.IntDef"> 91 <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> 92 <val name="flag" val="true" /> 93 </annotation> 94 </item> 95<item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2"> 96 <annotation name="androidx.annotation.IntRange"> 97 <val name="from" val="1" /> 98 </annotation> 99 </item> 100</root>""" 101 102 103 104class MergeAnnotationZipsTest(unittest.TestCase): 105 106 def test_merge_zips(self): 107 with tempfile.TemporaryDirectory() as out_dir: 108 for zip_content in [zip_a, zip_b, zip_c]: 109 f = io.BytesIO() 110 with zipfile.ZipFile(f, "w") as zip_file: 111 for filename, content in zip_content.items(): 112 zip_file.writestr(filename, content) 113 merge_annotation_zips.merge_zip_file(out_dir, zip_file) 114 115 # Unchanged 116 self.assertEqual(zip_a['android/os/annotations.xml'], Path(out_dir, 'android/os/annotations.xml').read_text()) 117 self.assertEqual(zip_c['android/app/annotations.xml'], Path(out_dir, 'android/app/annotations.xml').read_text()) 118 119 # Merged 120 self.assertEqual(merged_provider, Path(out_dir, 'android/provider/annotations.xml').read_text()) 121 122 123if __name__ == "__main__": 124 unittest.main(verbosity=2) 125