• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2024 Huawei Device Co., Ltd.
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
17from glob import glob
18import argparse
19import copy
20import json
21import os
22import stat
23import subprocess
24
25JAVA_CASES = 'java_cases'
26DEX_FILE = 'classes.dex'
27DEX_SIZE_DATA = 'dex_size.dat'
28
29
30def is_file(parser, arg):
31    if not os.path.isfile(arg):
32        parser.error("The file '%s' does not exist" % arg)
33    return os.path.abspath(arg)
34
35
36def check_timeout(value):
37    ivalue = int(value)
38    if ivalue <= 0:
39        raise argparse.ArgumentTypeError("%s is an invalid timeout value" % value)
40    return ivalue
41
42
43def get_args():
44    description = "Execute Java test cases and generate a data file with the bytecode file size of the test cases."
45    parser = argparse.ArgumentParser(description=description)
46    parser.add_argument('--javac-path', dest='javac_path', type=lambda arg : is_file(parser, arg),
47                        help='Path to javac compiler', required=True)
48    parser.add_argument('--d8-path', dest='d8_path', type=lambda arg : is_file(parser, arg),
49                        help='Path to the executable program d8', required=True)
50    parser.add_argument('--timeout', type=check_timeout, dest='timeout', default=180,
51                        help='Time limits for use case execution (In seconds)')
52    return parser.parse_args()
53
54
55class JavaD8Runner:
56    def __init__(self, args):
57        self.args = args
58        self.test_root = os.path.dirname(os.path.abspath(__file__))
59        self.output = {}
60        self.case_list = []
61        self.cmd_list = [[args.javac_path], [args.d8_path]] # Contain [cmd_java2class, cmd_class2dex]
62
63    @staticmethod
64    def get_case_name(case_path):
65        filename = case_path.split('/')[-1]
66        case_name = filename[:filename.rfind('.')]
67        return case_name
68
69    def add_case(self, case_path, extension):
70        if not os.path.isabs(case_path):
71            case_path = os.path.join(self.test_root, case_path)
72        abs_case_path = os.path.abspath(case_path)
73        if abs_case_path not in self.case_list and abs_case_path.endswith(extension):
74            self.case_list.append(case_path)
75
76    def add_directory(self, directory, extension):
77        if not os.path.isabs(directory):
78            directory = os.path.join(self.test_root, directory)
79        glob_expression = os.path.join(os.path.abspath(directory), "**/*%s" % (extension))
80        cases = glob(glob_expression, recursive=True)
81        for case in cases:
82            self.add_case(case, extension)
83
84    def save_output_to_file(self):
85        dex_size_data = os.path.join(self.test_root, DEX_SIZE_DATA)
86        flags = os.O_RDWR | os.O_CREAT
87        mode = stat.S_IWUSR | stat.S_IRUSR
88        with os.fdopen(os.open(dex_size_data, flags, mode), 'w') as f:
89            f.truncate()
90            json.dump(self.output, f)
91
92    def run(self):
93        self.case_list.sort()
94        for file_path in self.case_list:
95            [cmd_java2class, cmd_class2dex] = copy.deepcopy(self.cmd_list)
96            cmd_java2class.extend([file_path])
97            class_files = []
98            case_root = os.path.dirname(file_path)
99            try:
100                subprocess.run(cmd_java2class, timeout=self.args.timeout)
101
102                for file in os.listdir(case_root):
103                    if file.endswith('.class'):
104                        class_files.append(os.path.join(case_root, file))
105
106                cmd_class2dex.extend(class_files)
107                cmd_class2dex.extend(['--output', case_root])
108
109                subprocess.run(cmd_class2dex, timeout=self.args.timeout)
110
111            except subprocess.TimeoutExpired:
112                print(f'[WARNING]: Timeout! {file_path}')
113            except Exception as e:
114                print(f"[ERROR]: {e}")
115            finally:
116                for class_file in class_files:
117                    if os.path.exists(class_file):
118                        os.remove(class_file)
119
120                dex_file = os.path.join(case_root, DEX_FILE)
121                dex_file_size = 0
122                if os.path.exists(dex_file):
123                    dex_file_size = os.path.getsize(dex_file)
124                    os.remove(dex_file)
125                self.output[self.get_case_name(file_path)] = dex_file_size
126                print(f'[INFO]: FINISH: {file_path}!')
127
128        self.save_output_to_file()
129
130
131def main():
132    args = get_args()
133    java_runner = JavaD8Runner(args)
134    java_runner.add_directory(JAVA_CASES, '.java')
135    java_runner.run()
136
137
138if __name__ == "__main__":
139    main()