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
17import argparse
18import datetime
19import os
20import subprocess
21import shutil
22from config import JS_FILE, API_VERSION_MAP, Color
23
24
25def parse_args():
26    parser = argparse.ArgumentParser(description="Version compatibility testing for Verifier.")
27    parser.add_argument(
28        "--verifier-dir", required=True, help="Path to the ark_verifier.")
29    parser.add_argument(
30        "--es2abc-dir", required=True, help="Path to the es2abc.")
31    parser.add_argument(
32        "--keep-files", action="store_true", help="Keep the diff_version_abcs directory.")
33    return parser.parse_args()
34
35
36def create_output_dir():
37    output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "diff_version_abcs")
38    if os.path.exists(output_dir):
39        shutil.rmtree(output_dir)
40    os.makedirs(output_dir)
41    return output_dir
42
43
44def split_api_version(version_str):
45    if not version_str.startswith("API"):
46        raise ValueError(f"Invalid version string format: {version_str}")
47
48    parts = version_str.split("API")[1].split("beta")
49    main_part = parts[0]
50    # Create "beta*" if there is a beta part; otherwise, set to empty string
51    beta_part = f"beta{parts[1]}" if len(parts) > 1 else ""
52
53    return (main_part, beta_part)
54
55
56def compile_abc(es2abc_path, js_file, output_file, target_api_version, target_api_sub_version):
57    cmd = [
58        es2abc_path,
59        "--module", js_file,
60        "--output", output_file,
61        f"--target-api-version={target_api_version}",
62    ]
63
64    if target_api_sub_version:
65        cmd.append(f"--target-api-sub-version={target_api_sub_version}")
66
67    result = subprocess.run(cmd, capture_output=True, text=True)
68
69    print(f"Executing command: {' '.join(cmd)}")
70
71    if result.returncode != 0:
72        print(f"Error in compiling {output_file}: {result.stderr}")
73        raise subprocess.CalledProcessError(result.returncode, cmd)
74    else:
75        print(f"Compiled {output_file}: {result.stdout}")
76
77
78def verify_abcs(verifier_dir, output_dir):
79    input_files = [os.path.join(output_dir, f) for f in os.listdir(output_dir) if f.endswith(".abc")]
80    passed_count = 0
81    failed_count = 0
82    failed_files = []
83
84    for abc_file in input_files:
85        cmd = [os.path.join(verifier_dir, "ark_verifier"), "--input_file", abc_file]
86        result = subprocess.run(cmd, capture_output=True, text=True)
87
88        if result.returncode == 0:
89            print(f"Verification passed for {abc_file}: {result.stdout}")
90            passed_count += 1
91        else:
92            print(f"Verification failed for {abc_file}: {result.stderr}")
93            failed_count += 1
94            failed_files.append(abc_file)
95
96    total_count = passed_count + failed_count
97    return passed_count, failed_count, total_count, failed_files
98
99
100def report_results(passed, failed, total, failed_files):
101    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
102
103    print(Color.apply(Color.WHITE, f"Total ABC files: {total}"))
104    print(Color.apply(Color.GREEN, f"Passed: {passed}"))
105    print(Color.apply(Color.RED, f"Failed: {failed}"))
106    print(f"Report generated at: {timestamp}")
107    if failed > 0:
108        print("Failed files:")
109        for file in failed_files:
110            print(f"  - {file}")
111
112
113def main():
114    args = parse_args()
115
116    verifier_dir = args.verifier_dir
117    es2abc_dir = args.es2abc_dir
118
119    script_dir = os.path.dirname(os.path.realpath(__file__))
120    js_file = os.path.join(script_dir, "js", JS_FILE)
121
122    if not os.path.exists(js_file):
123        raise FileNotFoundError(f"{js_file} not found.")
124
125    output_dir = create_output_dir()
126
127    es2abc_path = os.path.join(es2abc_dir, "es2abc")
128    if not os.path.exists(es2abc_path):
129        raise FileNotFoundError(f"{es2abc_path} not found.")
130
131    for api_key in API_VERSION_MAP.keys():
132        target_api_version, target_api_sub_version = split_api_version(api_key)
133
134        output_file = os.path.join(output_dir, f"{api_key}.abc")
135        compile_abc(
136            es2abc_path, js_file, output_file, target_api_version,
137            target_api_sub_version if target_api_version == "12" else ""
138        )
139
140    passed, failed, total, failed_files = verify_abcs(verifier_dir, output_dir)
141    report_results(passed, failed, total, failed_files)
142
143    if failed == 0 and not args.keep_files:
144        shutil.rmtree(output_dir)
145        print(f"Deleted {output_dir} as all verifications passed.")
146    else:
147        print(f"Verification failed or keep-files flag is set, keeping {output_dir} for inspection.")
148
149
150if __name__ == "__main__":
151    main()
152