From 1962c3616a6cb38ecfedbc06d60a7159e6c39c4b Mon Sep 17 00:00:00 2001 From: bergamot88 Date: Sat, 21 Jun 2025 02:53:00 +0300 Subject: [PATCH 1/2] first --- ets2panda/test/tsconfig/CMakeLists.txt | 1 + .../CMakeLists.txt | 0 .../file_creator.py | 48 ++++++++++ .../test-compilation-multiple-files/main.py | 92 +++++++++++++++++++ .../parse_options.py | 45 +++++++++ .../cycle_imports_100_methods.ets.j2 | 20 ++++ .../templates/cycle_imports_1k_method.ets.j2 | 20 ++++ ..._each_previous_file_and_first_large.ets.j2 | 45 +++++++++ ...t_each_previous_file_in_empty_files.ets.j2 | 5 + .../import_in_file_100_methods.ets.j2 | 19 ++++ .../import_in_file_1k_methods.ets.j2 | 19 ++++ .../test_list.kfl | 0 .../test_runner.py | 58 ++++++++++++ 13 files changed, 372 insertions(+) create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/file_creator.py create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/main.py create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/parse_options.py create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_100_methods.ets.j2 create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_1k_method.ets.j2 create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_and_first_large.ets.j2 create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_in_empty_files.ets.j2 create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_100_methods.ets.j2 create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_1k_methods.ets.j2 create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/test_list.kfl create mode 100644 ets2panda/test/tsconfig/test-compilation-multiple-files/test_runner.py diff --git a/ets2panda/test/tsconfig/CMakeLists.txt b/ets2panda/test/tsconfig/CMakeLists.txt index 182e3aaa09..c8760cfa53 100644 --- a/ets2panda/test/tsconfig/CMakeLists.txt +++ b/ets2panda/test/tsconfig/CMakeLists.txt @@ -16,6 +16,7 @@ if(NOT PANDA_REGRESSION_TESTS) endif() add_subdirectory(test-config) +add_subdirectory(test-compilation-multiple-files) # 25872 # add_subdirectory(test-build) # add_subdirectory(test-decl) diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt b/ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/file_creator.py b/ets2panda/test/tsconfig/test-compilation-multiple-files/file_creator.py new file mode 100644 index 0000000000..aa71fb087e --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/file_creator.py @@ -0,0 +1,48 @@ +import jinja2 +import os +import argparse +import shutil +import json +import random +from pathlib import Path +from typing import Any + +class FileCreator: + def create_log_file(self, file_path: Path, contain: Any): + with open(file_path, 'w') as f: + f.write(contain) + + def create_ets_files(self, num_files: int, template_path: Path, target_dir: Path) -> list[Path]: + target_dir.mkdir(parents=True, exist_ok=True) + + with open(template_path, 'r', encoding='utf-8') as file: + template_content = file.read() + + template = jinja2.Template(template_content) + ets_files = list() + for i in range(1, num_files + 1): + rendered_content = template.render(file_number=i, files_number=num_files) + file_name = f"file_{i}.ets" + file_path = target_dir.joinpath(file_name) + with open(file_path, 'w', encoding='utf-8') as file: + file.write(rendered_content) + ets_files.append(file_path) + print(f" ⚒️ Created {len(ets_files)} .ets files") + return ets_files + + + def create_arktsconfig_file(self, out_dir_root: Path, ets_files: list[Path]) -> Path: + out_dir = out_dir_root.joinpath('compiled_abc_files') + out_dir.mkdir(parents=True, exist_ok=True) + filename = 'arktsconfig.json' + file_path = out_dir_root.joinpath(filename) + data = { + "compilerOptions": { + "outDir": str(out_dir) + }, + "files": [str(path) for path in ets_files] + } + with open(file_path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=4) + print(f" ⚒️ The {filename} file has been created successfully.") + return file_path diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/main.py b/ets2panda/test/tsconfig/test-compilation-multiple-files/main.py new file mode 100644 index 0000000000..bf1cfee43c --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/main.py @@ -0,0 +1,92 @@ +import argparse +import shutil +from sys import exit +from typing import Dict +from pathlib import Path +from parse_options import Parser +from file_creator import FileCreator +from test_runner import Runner +from subprocess import CompletedProcess + +def run_es2panda_test( + runner: Runner, + suite_name: str, + files_number: int, + template_path: Path, + generated_ets_files_root: Path + ) -> CompletedProcess: + suite_output_dir = generated_ets_files_root.joinpath(suite_name) + ets_files = FileCreator().create_ets_files(files_number, template_path, suite_output_dir) + arktsconfig_file = FileCreator().create_arktsconfig_file(suite_output_dir, ets_files) + return runner.run_es2panda_test(suite_name, ets_files, arktsconfig_file) + +def load_kfl(kfl: Path) -> list[str]: + lines = [] + with open(kfl, 'r') as file: + for line in file: + lines.append(line.strip()) + return lines + +def main() -> None: + args = Parser(argparse.ArgumentParser()).get_parse_args() + + current_dir = Path(__file__).resolve().parent + generated_ets_files_root = current_dir.joinpath('generated_ets_files') + templates_root = current_dir.joinpath('templates') + log_files_root = current_dir.joinpath('logs') + kfl_file = current_dir.joinpath('test_list.kfl') + kfl = load_kfl(kfl_file) + + files_number: int = args.files_number + template_path: Path = args.template_path + is_clean_generated_artifacts: bool = args.is_clean_generated_artifacts + build_dir_path: Path = args.build_dir_path + stdlib_path: Path = args.stdlib_path + + runner = Runner(build_dir_path, stdlib_path) + + result: Dict[str, CompletedProcess] = {} + new_failures: Dict[str, CompletedProcess] = {} + if template_path: + for template in template_path: + name = Path(template.stem).stem + print(f"\n🏁 Start process for : {template.name}") + es2panda_result = run_es2panda_test(runner, name, files_number, template.resolve(), generated_ets_files_root) + result[name] = es2panda_result + else: + for template in templates_root.iterdir(): + name = Path(template.stem).stem + print(f"\n🏁 Start process for : {template.name}") + es2panda_result = run_es2panda_test(runner, name, files_number, template.resolve(), generated_ets_files_root) + result[name] = es2panda_result + + print('\n📈 Result:') + print(f"\n ℹ️ Number of files to compile: {files_number}\n") + for suite, process_result in result.items(): + if process_result.returncode == 0: + print(f" 🟢 Suite: {suite}") + print(f" Exit code: {process_result.returncode}\n") + else: + print(f" 🔴 Suite: {suite}") + print(f" Exit code: {process_result.returncode}\n") + if suite not in kfl: + new_failures[suite] = process_result + + if is_clean_generated_artifacts: + shutil.rmtree(generated_ets_files_root) + + if len(new_failures): + print(f"💀 New failures:") + log_files_root.mkdir(parents=True, exist_ok=True) + for suite, process_result in new_failures.items(): + print(f" 🔴 Suite: {suite}") + if process_result.stdout: + FileCreator().create_log_file(log_files_root.joinpath(f"{suite}-stdout.txt"), process_result.stdout) + if process_result.stderr: + FileCreator().create_log_file(log_files_root.joinpath(f"{suite}-stderr.txt"), process_result.stderr) + exit(1) + else: + exit(0) + +if __name__ == "__main__": + main() diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/parse_options.py b/ets2panda/test/tsconfig/test-compilation-multiple-files/parse_options.py new file mode 100644 index 0000000000..916a29c5f8 --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/parse_options.py @@ -0,0 +1,45 @@ +import argparse +from typing import Any +from pathlib import Path + +class Parser: + def __init__(self, parser: argparse.ArgumentParser) -> None: + self.parser: argparse.ArgumentParser = parser + + def check_positive_int(self, value: str, min_value: int = 1) -> int: + ivalue = int(value) + if ivalue < min_value: + raise argparse.ArgumentTypeError(f"The value must be an integer greater than or equal to {min_value}") + return ivalue + + def get_parse_args(self) -> Any: + self.parser.add_argument( + '-n', '--files-number', + type=lambda x: self.check_positive_int(x, 2), + required=True, + help='Amount .ets files to create (minimum 2)' + ) + self.parser.add_argument( + '-std', '--stdlib-path', + type=Path, + required=True, + help='Path to build directory' + ) + self.parser.add_argument( + '-b', '--build-dir-path', + type=Path, + required=True, + help='Path to build directory' + ) + self.parser.add_argument( + '-t', '--template-path', + type=Path, + action='append', + help='Path to template of .ets file (default: template.etc.j2)' + ) + self.parser.add_argument( + '-clr', '--is-clean-generated-artifacts', + action='store_true', + help='Remove artifacts (generated by a template .etc files compiled .abc) after executing the script' + ) + return self.parser.parse_args() diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_100_methods.ets.j2 b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_100_methods.ets.j2 new file mode 100644 index 0000000000..10f720d5fd --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_100_methods.ets.j2 @@ -0,0 +1,20 @@ +{% set methods_number = 100 -%} +{% set suffix = suffix | default('') -%} + +{% for file_idx in range(1, files_number + 1) -%} +{% if (file_number > 1 and file_idx < file_number) or (file_number == 1 and file_idx >= 2) -%} +{% set current_imports = [] -%} +{% for method_idx in range(1, methods_number + 1) -%} +{% set method_name = 'method_' ~ method_idx -%} +{% set import_alias = 'method_' ~ method_idx ~ '_alias' ~ suffix ~ '_' ~ file_idx -%} +{% set _ = current_imports.append(method_name ~ ' as ' ~ import_alias) -%} +{% endfor -%} +import { {{ current_imports|join(', ') }} } from './file_{{ file_idx }}'; +{% endif -%} +{% endfor -%} + +{% for i in range(1, methods_number + 1) -%} +export function method_{{ i }}() { + console.log("call file_{{ file_number }} method_{{ i }}"); +} +{% endfor -%} \ No newline at end of file diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_1k_method.ets.j2 b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_1k_method.ets.j2 new file mode 100644 index 0000000000..5c39654e38 --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/cycle_imports_1k_method.ets.j2 @@ -0,0 +1,20 @@ +{% set methods_number = 1000 -%} +{% set suffix = suffix | default('') -%} + +{% for file_idx in range(1, files_number + 1) -%} +{% if (file_number > 1 and file_idx < file_number) or (file_number == 1 and file_idx >= 2) -%} +{% set current_imports = [] -%} +{% for method_idx in range(1, methods_number + 1) -%} +{% set method_name = 'method_' ~ method_idx -%} +{% set import_alias = 'method_' ~ method_idx ~ '_alias' ~ suffix ~ '_' ~ file_idx -%} +{% set _ = current_imports.append(method_name ~ ' as ' ~ import_alias) -%} +{% endfor -%} +import { {{ current_imports|join(', ') }} } from './file_{{ file_idx }}'; +{% endif -%} +{% endfor -%} + +{% for i in range(1, methods_number + 1) -%} +export function method_{{ i }}() { + console.log("call file_{{ file_number }} method_{{ i }}"); +} +{% endfor -%} \ No newline at end of file diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_and_first_large.ets.j2 b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_and_first_large.ets.j2 new file mode 100644 index 0000000000..ede28d1630 --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_and_first_large.ets.j2 @@ -0,0 +1,45 @@ +{% if file_number > 1 -%} +{% for i in range(1, file_number) -%} +import * as file_{{ i }} from './file_{{ i }}.ets' +{% endfor -%} +{% endif -%} + +{% if file_number > 1 -%} +import * as first_file from './file_1.ets' +{% endif -%} + +export class Class{{ file_number }} { + constructor() { + console.log("Constructor of Class{{ file_number }}") + } + method() { + console.log("Method of Class{{ file_number }}") + } +} + +{% if file_number > 1 -%} +function useFirstFileMethod() { + let inst = new first_file.Class1() + inst.method() +} + +function usePreviousClasses() { +{% for i in range(1, file_number) -%} + let instance_{{ i }} = new file_{{ i }}.Class{{ i }}() + instance_{{ i }}.method() +{% endfor -%} +} +{% endif -%} + +{% if file_number > 1 -%} +usePreviousClasses() +useFirstFileMethod() +{% endif -%} + +{% if file_number == 1 -%} +{% for i in range(1, 1000) -%} +export function method_{{ i }}() { + console.log("Method {{ i }} of Class{{ file_number }}") +} +{% endfor -%} +{% endif -%} \ No newline at end of file diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_in_empty_files.ets.j2 b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_in_empty_files.ets.j2 new file mode 100644 index 0000000000..5d26e38f0f --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_each_previous_file_in_empty_files.ets.j2 @@ -0,0 +1,5 @@ +{% if file_number > 1 -%} +{% for i in range(1, file_number) -%} +import * as file_{{ i }} from './file_{{ i }}.ets' +{% endfor -%} +{% endif -%} diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_100_methods.ets.j2 b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_100_methods.ets.j2 new file mode 100644 index 0000000000..55f0bc85ad --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_100_methods.ets.j2 @@ -0,0 +1,19 @@ +{% set imports = [] -%} +{% set methods_number = 100 -%} + +{% for i in range(1, methods_number) -%} + {% set method_name = 'method_' ~ i -%} + {% set _ = imports.append(method_name) -%} +{% endfor -%} + +{% if file_number > 1 -%} +{% for i in range(1, file_number) -%} +import { {{ imports|join(', ') }} } from './file_{{ i }}' +{% endfor -%} +{% endif -%} + +{% for i in range(1, methods_number) -%} +export function method_{{ i }}() { + console.log("call file_{{ i }} method") +} +{% endfor -%} \ No newline at end of file diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_1k_methods.ets.j2 b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_1k_methods.ets.j2 new file mode 100644 index 0000000000..d07a4987d9 --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/templates/import_in_file_1k_methods.ets.j2 @@ -0,0 +1,19 @@ +{% set imports = [] -%} +{% set methods_number = 1000 -%} + +{% for i in range(1, methods_number) -%} + {% set method_name = 'method_' ~ i -%} + {% set _ = imports.append(method_name) -%} +{% endfor -%} + +{% if file_number > 1 -%} +{% for i in range(1, file_number) -%} +import { {{ imports|join(', ') }} } from './file_{{ i }}' +{% endfor -%} +{% endif -%} + +{% for i in range(1, methods_number) -%} +export function method_{{ i }}() { + console.log("call file_{{ i }} method") +} +{% endfor -%} \ No newline at end of file diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/test_list.kfl b/ets2panda/test/tsconfig/test-compilation-multiple-files/test_list.kfl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/test_runner.py b/ets2panda/test/tsconfig/test-compilation-multiple-files/test_runner.py new file mode 100644 index 0000000000..a021f639bc --- /dev/null +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/test_runner.py @@ -0,0 +1,58 @@ +import subprocess +import textwrap +import shutil +from pathlib import Path +from datetime import datetime + + +class Runner: + def __init__(self, build_dir_path: Path, stdlib_path: Path) -> None: + self.build_dir_path = build_dir_path + self.stdlib_path = stdlib_path + self.es2panda_bin = build_dir_path.joinpath('bin').joinpath('es2panda') + + + def run_es2panda(self, args: list[str]) -> subprocess.CompletedProcess: + command = [str(self.es2panda_bin)] + command.extend(args) + result = subprocess.run(command, capture_output=True, text=True) + return result + + + def process_es2panda(self, ets_files: list[Path], arktsconfig_file: Path) -> list: + start_time = datetime.now() + process_result = self.run_es2panda(['--arktsconfig', str(arktsconfig_file), '--stdlib', str(self.stdlib_path)]) + finish_time = datetime.now() + duration = finish_time - start_time + + not_found_files = [] + found_files = [] + for ets_file in ets_files: + file = ets_file.parent.joinpath('compiled_abc_files').joinpath(ets_file.name).with_suffix('.abc') + if not file.is_file(): + not_found_files.append(file) + else: + found_files.append(file) + return duration.total_seconds(), process_result, not_found_files, found_files + + + def run_es2panda_test( + self, + suite_name: str, + ets_files: list[Path], + arktsconfig_file: Path + ) -> subprocess.CompletedProcess: + duration, process_result, not_found_files, found_files = self.process_es2panda(ets_files, arktsconfig_file) + if process_result.returncode == 0 and len(not_found_files) == 0: + print(f" ✅ es2panda compilation for: {suite_name} IS SUCCESSED") + print(f"\t⏱️ Execute time: {duration} sec.") + print(f"\t⚒️ Compiled files number: {len(found_files)}") + print(f"\t💻 Command: \n\t {' '.join(process_result.args)}") + else: + print(f" ❌ es2panda compilation for: {suite_name} IS NOT PASSED") + print(f"\t💻 Command: \n\t {' '.join(process_result.args)}") + if len(not_found_files): + print('\t⚠️ Not founded files:') + for file in not_found_files: + print(f"\t 🔴 {file}") + return process_result -- Gitee From e4f96eddf639fdcc3368e32a5eb6a23feabbf688 Mon Sep 17 00:00:00 2001 From: bergamot88 Date: Sat, 21 Jun 2025 03:01:16 +0300 Subject: [PATCH 2/2] f --- .../CMakeLists.txt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt b/ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt index e69de29bb2..23d166c95d 100644 --- a/ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt +++ b/ets2panda/test/tsconfig/test-compilation-multiple-files/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +function(add_test project) + set(PROJECT_TARGET_NAME es2panda-tsconfig-test-config-${project}) + add_custom_target(${PROJECT_TARGET_NAME} + COMMENT "Testing tsconfig for: ${project}" + DEPENDS es2panda + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + COMMAND python3 create_ets_files.py + --files-number 5 + --stdlib-path ${PANDA_ROOT}/plugins/ets/stdlib + --build-dir-path ${PANDA_BINARY_ROOT} + --is-clean-generated-artifacts + ) + add_dependencies(es2panda_tests ${PROJECT_TARGET_NAME}) +endfunction() + +add_test(compilation-multiple-files) -- Gitee