diff options
author | alevitskii <[email protected]> | 2025-09-04 10:00:21 +0300 |
---|---|---|
committer | alevitskii <[email protected]> | 2025-09-04 10:19:32 +0300 |
commit | 8da3e97c84353501738d1ff485708bf8b7185eb8 (patch) | |
tree | dfe1363035f5daa04064c8cdacc3835b3a5cdf90 /library/python/testing/custom_linter_util | |
parent | 4c3f3af78aac956c2d034edb4a0d7c778b9fe9d3 (diff) |
DEPENDS on linter wrappers to get them exported to opensource
DEPENDS on linter wrappers to get them exported to oss
commit_hash:286fa6981744f667a509749a33afcc3421903842
Diffstat (limited to 'library/python/testing/custom_linter_util')
6 files changed, 299 insertions, 0 deletions
diff --git a/library/python/testing/custom_linter_util/linter_params.py b/library/python/testing/custom_linter_util/linter_params.py new file mode 100644 index 00000000000..d3d00b51465 --- /dev/null +++ b/library/python/testing/custom_linter_util/linter_params.py @@ -0,0 +1,83 @@ +# XXX: This module is used in linter tools in `tools/` which are run by test_tool. +# test_tool and `tools/` have different release cycles. Beware when modifying. +import argparse +import json +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class LinterArgs: + source_root: str + project_path: str + output_path: str + lint_name: str + depends: dict[str, str] + global_resources: dict[str, str] + configs: list[str] + extra_params: dict[str, str] + report_file: str + files: list[str] + + +def get_params(raw_args: Optional[list[str]] = None) -> LinterArgs: + parser = argparse.ArgumentParser() + parser.add_argument("--params") + parser.add_argument("--source-root") + parser.add_argument("--project-path") + parser.add_argument("--output-path") + parser.add_argument("--lint-name", default="") + parser.add_argument("--depends", action="append") + parser.add_argument("--global-resource", action="append", dest="global_resources") + parser.add_argument("--config", action="append", dest="configs") + parser.add_argument("--extra-param", action="append", dest="extra_params") + parser.add_argument("--report-file", default="-") + parser.add_argument("files", nargs="*") + args = parser.parse_args(raw_args) + + if args.params: + with open(args.params) as f: + params = json.load(f) + source_root = params["source_root"] + project_path = params["project_path"] + output_path = params["output_path"] + lint_name = params.get("lint_name", "") + depends = params.get("depends", {}) + global_resources = params.get("global_resources", {}) + configs = params.get("configs", []) + extra_params = params.get("extra_params", {}) + report_file = params["report_file"] + files = params["files"] + else: + source_root = args.source_root + project_path = args.project_path + output_path = args.output_path + lint_name = args.lint_name + depends = _parse_kv_arg(args.depends, ":") + global_resources = _parse_kv_arg(args.global_resources, ":") + configs = args.configs if args.configs else [] + extra_params = _parse_kv_arg(args.extra_params, "=") + report_file = args.report_file + files = args.files + + return LinterArgs( + source_root=source_root, + project_path=project_path, + output_path=output_path, + lint_name=lint_name, + depends=depends, + global_resources=global_resources, + configs=configs, + extra_params=extra_params, + report_file=report_file, + files=files, + ) + + +def _parse_kv_arg(arg, sep): + result = {} + if arg: + for item in arg: + var, val = item.split(sep, 1) + result[var] = val + return result diff --git a/library/python/testing/custom_linter_util/reporter.py b/library/python/testing/custom_linter_util/reporter.py new file mode 100644 index 00000000000..5e3d11bd339 --- /dev/null +++ b/library/python/testing/custom_linter_util/reporter.py @@ -0,0 +1,41 @@ +# XXX: This module is used in linter tools in `tools/` which are run by test_tool. +# test_tool and `tools/` have different release cycles. Beware when modifying. +import json +import sys +from enum import Enum +from typing import Optional + + +class LintStatus(Enum): + GOOD = "GOOD" + FAIL = "FAIL" + SKIPPED = "SKIPPED" + + +class LintReport(): + def __init__(self): + self._report = {} + + def add(self, file_name: str, status: LintStatus, message: str = "", elapsed: float = 0.0): + self._report[file_name] = { + "status": status.value, + "message": message, + "elapsed": elapsed, + } + + def dump(self, report_file, pretty: Optional[bool] = None): + data = { + "report": self._report, + } + if report_file == "-": + if pretty is None: + pretty = True + self._do_dump(sys.stdout, data, pretty) + else: + with open(report_file, "w") as f: + self._do_dump(f, data, pretty) + + @staticmethod + def _do_dump(dest, data, pretty): + indent = 4 if pretty else None + json.dump(data, dest, indent=indent) diff --git a/library/python/testing/custom_linter_util/tests/test_params.py b/library/python/testing/custom_linter_util/tests/test_params.py new file mode 100644 index 00000000000..025bb3eef22 --- /dev/null +++ b/library/python/testing/custom_linter_util/tests/test_params.py @@ -0,0 +1,83 @@ +import json + +from library.python.testing.custom_linter_util import linter_params +from yatest.common import work_path + + +SOURCE_ROOT = "TEST_SOURCE_ROOT" +PROJECT_PATH = "TEST_PROJECT_PATH" +OUTPUT_PATH = "TEST_OUTPUT_PATH" +REPORT_FILE = "TEST_REPORT_FILE" +LINT_NAME = "important-lint" +DEPS = { + "dep1": "/path/to/dep1", + "dep2": "/path/to/dep2", +} +GLOBAL_RESOURCES = { + "TOOL1_GLOBAL_RESOURCES": "/path/to/resource1", + "TOOL2_GLOBAL_RESOURCES": "/path/to/resource2", +} +CONFIGS = ["path/to/config1", "path/to/config2"] +EXTRA_PARAMS = { + "var1": "val1", + "var2": "val2", +} +FILES = ["file1.cpp", "file2.cpp"] + +EXPECTED = linter_params.LinterArgs( + source_root=SOURCE_ROOT, + project_path=PROJECT_PATH, + output_path=OUTPUT_PATH, + report_file=REPORT_FILE, + lint_name=LINT_NAME, + depends=DEPS, + global_resources=GLOBAL_RESOURCES, + configs=CONFIGS, + extra_params=EXTRA_PARAMS, + files=FILES, +) + + +def test_cmd_line_params(): + raw_args = [ + "--source-root", SOURCE_ROOT, + "--project-path", PROJECT_PATH, + "--output-path", OUTPUT_PATH, + "--report-file", REPORT_FILE, + "--lint-name", LINT_NAME, + ] + for rel, abs in DEPS.items(): + raw_args += ["--depends", ":".join([rel, abs])] + for var, path in GLOBAL_RESOURCES.items(): + raw_args += ["--global-resource", ":".join([var, path])] + for cfg in CONFIGS: + raw_args += ["--config", cfg] + for var, val in EXTRA_PARAMS.items(): + raw_args += ["--extra-param", "=".join([var, val])] + raw_args += FILES + + got = linter_params.get_params(raw_args) + + assert got == EXPECTED + + +def test_json_params(): + params_file = work_path("params.josn") + params = { + "source_root": SOURCE_ROOT, + "project_path": PROJECT_PATH, + "output_path": OUTPUT_PATH, + "report_file": REPORT_FILE, + "lint_name": LINT_NAME, + "depends": DEPS, + "global_resources": GLOBAL_RESOURCES, + "configs": CONFIGS, + "extra_params": EXTRA_PARAMS, + "files": FILES, + } + with open(params_file, "w") as f: + json.dump(params, f) + + got = linter_params.get_params(["--params", params_file]) + + assert got == EXPECTED diff --git a/library/python/testing/custom_linter_util/tests/test_reporter.py b/library/python/testing/custom_linter_util/tests/test_reporter.py new file mode 100644 index 00000000000..81bfa3c9ef0 --- /dev/null +++ b/library/python/testing/custom_linter_util/tests/test_reporter.py @@ -0,0 +1,68 @@ +import json + +from library.python.testing.custom_linter_util.reporter import LintReport, LintStatus +from yatest.common import output_path, context + + +def dump_and_load(report): + report_file = output_path(context.test_name) + report.dump(report_file=report_file) + with open(report_file) as f: + return json.load(f) + + +def test_empty_report(): + report = LintReport() + got = dump_and_load(report) + assert got == {"report": {}} + + +def test_good_test(): + report = LintReport() + report.add("file.cpp", LintStatus.GOOD) + + got = dump_and_load(report) + + assert got == { + "report": { + "file.cpp": { + "status": "GOOD", + "message": "", + "elapsed": 0.0, + } + } + } + + +def test_skipped_test(): + report = LintReport() + report.add("file.cpp", LintStatus.SKIPPED, "Generated file", elapsed=1.0) + + got = dump_and_load(report) + + assert got == { + "report": { + "file.cpp": { + "status": "SKIPPED", + "message": "Generated file", + "elapsed": 1.0, + } + } + } + + +def test_failed_test(): + report = LintReport() + report.add("file.cpp", LintStatus.FAIL, "Test failed", elapsed=2.0) + + got = dump_and_load(report) + + assert got == { + "report": { + "file.cpp": { + "status": "FAIL", + "message": "Test failed", + "elapsed": 2.0, + } + } + } diff --git a/library/python/testing/custom_linter_util/tests/ya.make b/library/python/testing/custom_linter_util/tests/ya.make new file mode 100644 index 00000000000..1fde32d937a --- /dev/null +++ b/library/python/testing/custom_linter_util/tests/ya.make @@ -0,0 +1,12 @@ +PY3TEST() + +TEST_SRCS( + test_params.py + test_reporter.py +) + +PEERDIR( + library/python/testing/custom_linter_util +) + +END() diff --git a/library/python/testing/custom_linter_util/ya.make b/library/python/testing/custom_linter_util/ya.make new file mode 100644 index 00000000000..c761b09afcd --- /dev/null +++ b/library/python/testing/custom_linter_util/ya.make @@ -0,0 +1,12 @@ +PY3_LIBRARY() + +PY_SRCS( + linter_params.py + reporter.py +) + +END() + +RECURSE_FOR_TESTS( + tests +) |