1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2024 Huawei Device Co., Ltd.
5#
6# HDF is dual licensed: you can use it either under the terms of
7# the GPL, or the BSD license, at your option.
8# See the LICENSE file in the root of this repository for complete details.
9
10import os
11import subprocess
12import time
13
14
15def get_time_stamp():
16    return int(round(time.time() * 1000))
17
18
19def print_success(info):
20    print("\033[32m{}\033[0m".format(info))
21
22
23def print_failure(info):
24    print("\033[31m{}\033[0m".format(info))
25
26
27def is_subsequence(first_file, second_file):
28    first_info = first_file.read()
29    second_info = second_file.readline()
30    while second_info:
31        if first_info.find(second_info) == -1:
32            print("line\n", second_info, "is not in output file")
33            return False
34        second_info = second_file.readline()
35    return True
36
37
38def compare_file(first_file_path, second_file_path):
39    with open(first_file_path, 'r') as first_file:
40        with open(second_file_path, 'r') as second_file:
41            return is_subsequence(first_file, second_file)
42
43
44def compare_target_files(first_file_path, second_file_path):
45    first_files_list = get_all_files(first_file_path)
46    second_files_list = get_all_files(second_file_path)
47
48    first_files = set([file[len(first_file_path):] for file in first_files_list])
49    second_files = set([file[len(second_file_path):-4] for file in second_files_list])
50
51    common_files = first_files & second_files
52
53    for files in common_files:
54        if not compare_file("{}{}".format(first_file_path, files), "{}{}.txt".format(second_file_path, files)):
55            print("file ", "{}{}".format(first_file_path, files), "{}{}.txt".format(second_file_path, files), \
56                "is different")
57            return False
58    return True
59
60
61def exec_command(command):
62    return subprocess.getstatusoutput(command)
63
64
65def file_exists(file_path):
66    return os.path.isfile(file_path)
67
68
69def make_binary_file(file_path):
70    print("making hdi-gen...")
71    return exec_command("make --directory={} --jobs=4".format(file_path))
72
73
74def clean_binary_file(file_path):
75    return exec_command("make --directory={} clean".format(file_path))
76
77
78def get_all_files(path):
79    file_list = []
80    items = os.listdir(path)
81    for item in items:
82        item_path = os.path.join(path, item)
83        if not os.path.isdir(item_path):
84            file_list.append(item_path)
85        else:
86            file_list += get_all_files(item_path)
87    return file_list
88
89
90def get_all_idl_files(idl_path):
91    file_list = get_all_files(idl_path)
92    idl_file_list = []
93    for file in file_list:
94        if os.path.splitext(file)[-1] == ".idl":
95            idl_file_list.append(file)
96    return idl_file_list
97
98
99
100class Test:
101    def __init__(self, name, working_dir):
102        self.name = name
103        self.working_dir = working_dir
104        self.idl_dir = os.path.join(self.working_dir, "foo")
105        self.output_dir = os.path.join(working_dir, "out")
106        self.target_dir = os.path.join(working_dir, "target")
107        self.command = "../../hdi-gen -s full -m ipc -l cpp -r ohos.hdi:{} -d {}".format(working_dir, self.output_dir)
108
109    def run(self):
110        # please add test code here
111        return False
112
113    def run_success(self):
114        self.add_idl_files()
115        status, _ = exec_command(self.command)
116        if status == 0 and compare_target_files(self.output_dir, self.target_dir):
117            return True
118        return False
119
120    def run_fail(self):
121        self.add_idl_files()
122        status, _ = exec_command(self.command)
123
124        expected_fail_output = ""
125        with open(os.path.join(self.target_dir, "fail_output.txt"), 'r') as target_output:
126            expected_fail_output = target_output.read()
127
128        if status != 0 and expected_fail_output == _:
129            return True
130        return False
131
132    def remove_output(self):
133        exec_command("rm -rf {}".format(self.output_dir))
134        return True
135
136    def add_idl_files(self):
137        idl_list = get_all_idl_files(self.idl_dir)
138        for idl in idl_list:
139            self.command = "".join((self.command, " -c {}".format(idl)))
140
141    def test(self):
142        print_success("[ RUN       ] {}".format(self.name))
143        start_time = get_time_stamp()
144        result = self.run()
145        end_time = get_time_stamp()
146
147        if result:
148            print_success("[        OK ] {} ({}ms)".format(self.name, end_time - start_time))
149        else:
150            print_failure("[    FAILED ] {} ({}ms)".format(self.name, end_time - start_time))
151        return result
152
153
154# compile empty idl file
155class UnitTest01(Test):
156    def run(self):
157        return self.run_fail()
158
159
160# standard interface idl file
161class UnitTest02(Test):
162    def run(self):
163        return self.run_success()
164
165
166# standard callback idl file
167class UnitTest03(Test):
168    def run(self):
169        return self.run_success()
170
171
172# extended interface idl file
173class UnitTest04(Test):
174    def run(self):
175        return self.run_success()
176
177
178# interface with types idl file
179class UnitTest05(Test):
180    def run(self):
181        return self.run_success()
182
183
184# extended enum idl file
185class UnitTest06(Test):
186    def run(self):
187        return self.run_success()
188
189
190# extended struct idl file
191class UnitTest07(Test):
192    def run(self):
193        return self.run_success()
194
195
196# overload method idl file
197class UnitTest08(Test):
198    def run(self):
199        return self.run_success()
200
201
202# enum nesting idl file
203class UnitTest09(Test):
204    def run(self):
205        return self.run_success()
206
207
208class Tests:
209    test_cases = [
210        UnitTest01("UnitTestEmptyIdl", "01_empty_idl"),
211        UnitTest02("UnitTestStandardInterface", "02_standard_interface_idl"),
212        UnitTest03("UnitTestStandardCallback", "03_standard_callback_idl"),
213        UnitTest04("UnitTestExtendedInterface", "04_extended_interface_idl"),
214        UnitTest05("UnitTestTypesIdl", "05_types_idl"),
215        UnitTest06("UnitTestEnumExtension", "06_extended_enum_idl"),
216        UnitTest07("UnitTestStructExtension", "07_extended_struct_idl"),
217        UnitTest08("UnitTestOverloadMethod", "08_overload_method_idl"),
218        UnitTest09("UnitTestEnumNesting", "09_enum_nesting_idl"),
219    ]
220
221    @staticmethod
222    def set_up_test_case():
223        hdi_gen_file = "../../hdi-gen"
224        ret = file_exists(hdi_gen_file)
225        if not ret:
226            hdi_gen_path = "../../"
227            if make_binary_file(hdi_gen_path)[0] == 0:
228                ret = True
229        if not ret:
230            print_failure("[===========] failed to make hdi-gen")
231        return ret
232
233    @staticmethod
234    def tear_down_test_case():
235        for case in Tests.test_cases:
236            case.remove_output()
237        hdi_gen_path = "../../"
238        clean_binary_file(hdi_gen_path)
239
240    @staticmethod
241    def test():
242        test_case_num = len(Tests.test_cases)
243        success_case_num = 0
244        print_success("[===========] start {} test".format(test_case_num))
245        for test_case in Tests.test_cases:
246            if test_case.test():
247                success_case_num += 1
248        print_success("[    PASSED ] {} test".format(success_case_num))
249        failure_case_num = test_case_num - success_case_num
250        if failure_case_num > 0:
251            print_failure("[    FAILED ] {} test".format(failure_case_num))
252
253
254if __name__ == "__main__":
255    if not Tests.set_up_test_case():
256        print_failure("test case set up failed!")
257        exit(-1)
258    Tests.test()
259    Tests.tear_down_test_case()
260