1#!/usr/bin/env python 2# coding: utf-8 3# 4# Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without modification, 7# are permitted provided that the following conditions are met: 8# 9# 1. Redistributions of source code must retain the above copyright notice, this list of 10# conditions and the following disclaimer. 11# 12# 2. Redistributions in binary form must reproduce the above copyright notice, this list 13# of conditions and the following disclaimer in the documentation and/or other materials 14# provided with the distribution. 15# 16# 3. Neither the name of the copyright holder nor the names of its contributors may be used 17# to endorse or promote products derived from this software without specific prior written 18# permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 24# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32import os 33import platform 34import shutil 35import stat 36import subprocess 37import sys 38import base64 39 40 41class TestConfig(object): 42 CMAKE_GEN_PATH = "cmake-build-debug/" 43 WORK_DIR = "" 44 ERROR_COLOR_PREFIX = "\033[31m" 45 ERROR_COLOR_END = "\033[0m" 46 ALIGNED_PARM = '' 47 48 49def setup_hcgen_compiler(): 50 if len(sys.argv) > 1: 51 hcgen_path = os.path.abspath(sys.argv[1]) 52 if hcgen_path.find('hc-gen') >= 0 and os.access(hcgen_path, os.X_OK): 53 print('use specified hsc:' + hcgen_path) 54 return hcgen_path 55 56 source_root = '../../' 57 compiler_name = "hc-gen" 58 if platform.system() == "Windows": 59 source_root = source_root.replace("/", "\\") 60 compiler_name += ".exe" 61 62 source_root = os.path.abspath(os.path.join(TestConfig.WORK_DIR, source_root)) 63 hcgen_path = os.path.join(source_root, compiler_name) 64 if not os.access(hcgen_path, os.X_OK): 65 hcgen_path = os.path.join(source_root, TestConfig.CMAKE_GEN_PATH, compiler_name) 66 if not os.access(hcgen_path, os.X_OK): 67 print("Error: hcgen not found, please make first") 68 exit(1) 69 70 return hcgen_path 71 72 73def index_case(case_path): 74 cases = [] 75 for directory in os.listdir(case_path): 76 if os.path.isdir(os.path.join(case_path, directory)): 77 cases.append(directory) 78 cases.sort() 79 return cases 80 81 82def save_compile_result(mode, case_name, status, output): 83 result_file_name = os.path.join(TestConfig.WORK_DIR, case_name, 84 'golden_%s_compile_result.txt' % mode) 85 flags = os.O_RDWR | os.O_CREAT 86 modes = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH 87 with os.fdopen(os.open(result_file_name, flags, modes), 88 "w", encoding="utf-8") as result_output: 89 status_str = "[compile exit status]:" + str(status) 90 output_str = "\n[compile console output]:\n" + output 91 result_output.write(status_str) 92 result_output.write(output_str) 93 94 95def gen_decompile_golden(hcgen_path, case_name): 96 source_file = os.path.join(TestConfig.WORK_DIR, case_name, 'golden.hcb') 97 target_file = os.path.join(TestConfig.WORK_DIR, case_name, 'golden') 98 command = "%s -o %s -d %s" % (hcgen_path, target_file, source_file) 99 status, output = subprocess.getstatusoutput(command) 100 if status: 101 print('case %s decompile fail:\n %s, status=%d' % 102 (case_name, output, status)) 103 104 return status == 0 105 106 107def recode_hcb_file(file_path): 108 with open(file_path, 'rb') as hcb_file: 109 content = hcb_file.read() 110 hcb_file.close() 111 112 with open(file_path, 'wb') as hcb_file: 113 base64_content = base64.b64encode(content) 114 hcb_file.write(base64_content) 115 hcb_file.close() 116 117 118def build_binary(hcgen_path, case_name): 119 source_file = os.path.join(TestConfig.WORK_DIR, case_name, 'case.hcs') 120 target_file = os.path.join(TestConfig.WORK_DIR, case_name, 'golden') 121 command = "%s %s -o %s %s" % \ 122 (hcgen_path, TestConfig.ALIGNED_PARM, target_file, source_file) 123 status, output = subprocess.getstatusoutput(command) 124 if case_name.endswith('_ei'): 125 if status == 0: 126 print("CASE_ERROR:error identify case " + case_name 127 + "expect build fail but success at binary mode") 128 return False 129 elif status != 0: 130 print("CASE_ERROR:case " + case_name 131 + " expect build success but failed at binary mode") 132 return False 133 output = output.replace(TestConfig.WORK_DIR, ".").replace('\\', '/') \ 134 .replace(TestConfig.ERROR_COLOR_PREFIX, "") \ 135 .replace(TestConfig.ERROR_COLOR_END, "").strip() 136 137 save_compile_result('binary', case_name, status, output) 138 139 result = True 140 if status == 0: 141 result = gen_decompile_golden(hcgen_path, case_name) 142 if result: 143 recode_hcb_file(target_file + '.hcb') 144 return result 145 146 147def build_text(hcgen_path, case_name): 148 source_file = os.path.join(TestConfig.WORK_DIR, case_name, 'case.hcs') 149 target_file = os.path.join(TestConfig.WORK_DIR, case_name, 'golden') 150 command = "%s -t -o %s %s" % (hcgen_path, target_file, source_file) 151 status, output = subprocess.getstatusoutput(command) 152 if case_name.endswith('_ei') or case_name.find('node_duplicate_name') >= 0: 153 if status == 0: 154 print("CASE_ERROR:error identify case " 155 + case_name + " expect build fail but success at text mode") 156 print(output) 157 return False 158 elif status != 0: 159 print("CASE_ERROR:case " + case_name 160 + " expect build success but failed at text mode") 161 print(output) 162 return False 163 output = output.replace(TestConfig.WORK_DIR, ".").replace('\\', '/') \ 164 .replace(TestConfig.ERROR_COLOR_PREFIX, "") \ 165 .replace(TestConfig.ERROR_COLOR_END, "").strip() 166 167 save_compile_result('text', case_name, status, output) 168 169 if status == 0: 170 os.rename(target_file + '.c', target_file + '.c.gen') 171 os.rename(target_file + '.h', target_file + '.h.gen') 172 return True 173 174 175def build_macro(hcgen_path, case_name): 176 source_file = os.path.join(TestConfig.WORK_DIR, case_name, 'case.hcs') 177 target_file = os.path.join(TestConfig.WORK_DIR, case_name, 'macro') 178 command = "%s -m -o %s %s" % (hcgen_path, target_file, source_file) 179 status, output = subprocess.getstatusoutput(command) 180 if case_name.endswith('_ei'): 181 if status == 0: 182 print("CASE_ERROR:error identify case " 183 + case_name + " expect build fail but success at macro mode") 184 print(output) 185 return False 186 elif status != 0: 187 print("CASE_ERROR:case " + case_name 188 + " expect build success but failed at macro mode") 189 print(output) 190 return False 191 output = output.replace(TestConfig.WORK_DIR, ".").replace('\\', '/') \ 192 .replace(TestConfig.ERROR_COLOR_PREFIX, "") \ 193 .replace(TestConfig.ERROR_COLOR_END, "").strip() 194 195 save_compile_result('macro', case_name, status, output) 196 197 if status == 0: 198 os.rename(target_file + '.h', target_file + '.h.gen') 199 return True 200 201 202def build_cases(hcgen_path, cases): 203 index = 1 204 failed_cases = [] 205 for case in cases: 206 print('[%02d/%d] build %s' % (index, len(cases), case)) 207 text_compile = build_text(hcgen_path, case) 208 binary_compile = build_binary(hcgen_path, case) 209 macro_compile = build_macro(hcgen_path, case) 210 if not text_compile or not binary_compile or not macro_compile: 211 failed_cases.append(case) 212 index += 1 213 214 print("\nUpdate cases result :\ntotal case: %d, failed: %d, success: %d" % 215 (len(cases), len(failed_cases), len(cases) - len(failed_cases))) 216 if len(failed_cases) > 0: 217 print("Failed case as below:") 218 for case in failed_cases: 219 print(case) 220 221 222def setup_work_dir(): 223 pwd = os.path.abspath(sys.argv[0]) 224 pwd = pwd[:pwd.rfind(os.sep)] 225 TestConfig.WORK_DIR = pwd 226 227 228def clean_up(): 229 list_dirs = os.walk(TestConfig.WORK_DIR) 230 for root, dirs, files in list_dirs: 231 for file in files: 232 if file.startswith('golden'): 233 os.remove(os.path.join(root, file)) 234 235 temp_dir = os.path.join(TestConfig.WORK_DIR, 'temp') 236 if os.path.exists(temp_dir): 237 shutil.rmtree(temp_dir) 238 239 240if __name__ == "__main__": 241 if len(sys.argv) > 1 and sys.argv[-1] == '--align': 242 TestConfig.ALIGNED_PARM = ' -a ' 243 setup_work_dir() 244 hc_gen = setup_hcgen_compiler() 245 clean_up() 246 print("hc-gen path : " + hc_gen) 247 test_case_list = index_case(TestConfig.WORK_DIR) 248 build_cases(hc_gen, test_case_list) 249