From 379f21af8e27e05eba50aef6ab1a1e6053f4f4a1 Mon Sep 17 00:00:00 2001 From: Nikhil Badyal Date: Sat, 23 Sep 2023 22:09:59 +0530 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Added=20sort=20test=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- src/click_opt/click_custom.py | 16 ++------ src/strings.py | 3 +- test/click/cli_test.py | 72 ++++++++++++++++++++++++++++++++++- test/esxport/_export_test.py | 1 + 5 files changed, 79 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f3b6563..d59233d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ warn_unused_configs = true pythonpath = ["src"] [tool.pytest.ini_options] -addopts = "--cov=. --cov-report=xml --cov-report term-missing --ff -x --no-cov-on-fail --emoji -n4 -rP" +addopts = "--cov=. --cov-report=xml --cov-report term-missing --ff -x --no-cov-on-fail --emoji -n4" [tool.coverage.run] #branch = true #https://github.com/nedbat/coveragepy/issues/605 diff --git a/src/click_opt/click_custom.py b/src/click_opt/click_custom.py index ae48243..3d1a673 100644 --- a/src/click_opt/click_custom.py +++ b/src/click_opt/click_custom.py @@ -7,6 +7,8 @@ from click import Context, Parameter, ParamType from click_params.miscellaneous import JsonParamType +from src.strings import invalid_query_format, invalid_sort_format + if TYPE_CHECKING: from typing_extensions import Self @@ -35,14 +37,10 @@ def convert(self: Self, value: Any, param: Parameter | None, ctx: Context | None except FormatError as e: self.fail(str(e), param, ctx) except ValueError: - self.fail(f'Invalid input format: "{value}". Use the format "field:sort_order".', param, ctx) + self.fail(invalid_sort_format.format(value=value), param, ctx) else: return {field: sort_order} - def __repr__(self: Self) -> str: - """Return a string representation.""" - return str(self.name) - sort = Sort() @@ -55,8 +53,6 @@ class Json(JsonParamType): # type: ignore[misc] def convert(self: Self, value: Any, param: Parameter, ctx: Context) -> dict[str, Any]: # type: ignore[return] """Convert input to json.""" try: - if isinstance(value, dict): - return value return json.loads( # type: ignore[no-any-return] value, cls=self._cls, @@ -68,11 +64,7 @@ def convert(self: Self, value: Any, param: Parameter, ctx: Context) -> dict[str, **self._kwargs, ) except json.JSONDecodeError as exc: - self.fail(f"{value} is not a valid json string, caused {exc}", param, ctx) - - def __repr__(self: Self) -> str: - """String representation of the object.""" - return self.name.upper() + self.fail(invalid_query_format.format(value=value, exc=exc), param, ctx) JSON = Json() diff --git a/src/strings.py b/src/strings.py index 298e27e..048b4f1 100644 --- a/src/strings.py +++ b/src/strings.py @@ -5,4 +5,5 @@ output_fields = "Output fields : {fields}." sorting_by = "Sorting by: {sort}." meta_field_not_found = "Meta Field {field} not found" -meta_field_not_found = "Meta Field {field} not found" +invalid_sort_format = 'Invalid input format: "{value}". Use the format "field:sort_order".' +invalid_query_format = "{value} is not a valid json string, caused {exc}" diff --git a/test/click/cli_test.py b/test/click/cli_test.py index baddc72..18c9fed 100644 --- a/test/click/cli_test.py +++ b/test/click/cli_test.py @@ -1,7 +1,9 @@ """Click CLI test cases.""" import inspect +import json from pathlib import Path from test.esxport._export_test import TestExport +from test.esxport._prepare_search_query_test import TestSearchQuery from unittest.mock import patch from click.testing import CliRunner @@ -9,6 +11,7 @@ from src.esxport import EsXport from src.esxport_cli import cli +from src.strings import invalid_query_format, invalid_sort_format args = { "q": '{"query":{"match_all":{}}}', @@ -16,6 +19,8 @@ "i": "index1", } usage_error_code = 2 +random_pass = "password\n" # noqa: S105 +export_module = "src.esxport.EsXport" # noinspection PyTypeChecker @@ -46,7 +51,7 @@ def test_index_is_mandatory(self: Self, cli_runner: CliRunner) -> None: def test_mandatory(self: Self, cli_runner: CliRunner, esxport_obj_with_data: EsXport) -> None: """Test Index param is mandatory.""" esxport_obj_with_data.opts.output_file = f"{inspect.stack()[0].function}.csv" - with patch("src.esxport.EsXport", return_value=esxport_obj_with_data): + with patch(export_module, return_value=esxport_obj_with_data): result = cli_runner.invoke( cli, ["-q", args["q"], "-o", args["o"], "-i", args["i"]], @@ -58,3 +63,68 @@ def test_mandatory(self: Self, cli_runner: CliRunner, esxport_obj_with_data: EsX lines = len(fp.readlines()) assert lines == esxport_obj_with_data.es_client.search()["hits"]["total"]["value"] + 1 # 1 for header TestExport.rm_csv_export_file(esxport_obj_with_data.opts.output_file) + + def test_sort_type(self: Self, cli_runner: CliRunner, esxport_obj_with_data: EsXport) -> None: + """Test sort type is asc or desc.""" + esxport_obj_with_data.opts.output_file = f"{inspect.stack()[0].function}.csv" + random_string = TestSearchQuery.random_string(10) + with patch(export_module, return_value=esxport_obj_with_data): + result = cli_runner.invoke( + cli, + ["-q", args["q"], "-o", args["o"], "-i", args["i"], "-S", f"field:{random_string}"], + input=random_pass, + catch_exceptions=False, + ) + error_msg = f"Error: Invalid value for '-S' / '--sort': Invalid sort type {random_string}." + assert error_msg in result.output + assert result.exit_code == usage_error_code + + result = cli_runner.invoke( + cli, + ["-q", args["q"], "-o", args["o"], "-i", args["i"], "-S", "field:desc"], + input=random_pass, + catch_exceptions=False, + ) + error_msg = f"Error: Invalid value for '-S' / '--sort': Invalid sort type {random_string}." + assert error_msg not in result.output + assert result.exit_code == 0 + TestExport.rm_csv_export_file(esxport_obj_with_data.opts.output_file) + + def test_sort_format(self: Self, cli_runner: CliRunner, esxport_obj_with_data: EsXport) -> None: + """Test sort input is in the form field:sort_order.""" + esxport_obj_with_data.opts.output_file = f"{inspect.stack()[0].function}.csv" + random_string = TestSearchQuery.random_string(10) + with patch(export_module, return_value=esxport_obj_with_data): + result = cli_runner.invoke( + cli, + ["-q", args["q"], "-o", args["o"], "-i", args["i"], "-S", f"field@{random_string}"], + input=random_pass, + catch_exceptions=False, + ) + error_msg = invalid_sort_format.format(value=f"field@{random_string}") + assert error_msg in result.output + assert result.exit_code == usage_error_code + + def test_query_accepts_dict(self: Self, cli_runner: CliRunner, esxport_obj_with_data: EsXport) -> None: + """Test sort input is in the form field:sort_order.""" + esxport_obj_with_data.opts.output_file = f"{inspect.stack()[0].function}.csv" + with patch(export_module, return_value=esxport_obj_with_data): + result = cli_runner.invoke( + cli, + ["-q", json.dumps(args["q"]), "-o", args["o"], "-i", args["i"]], + input=random_pass, + catch_exceptions=False, + ) + assert result.exit_code == 0 + + def test_error_is_rasied_on_invalid_json(self: Self, cli_runner: CliRunner) -> None: + """Test sort input is in the form field:sort_order.""" + result = cli_runner.invoke( + cli, + ["-q", "@", "-o", args["o"], "-i", args["i"]], + input=random_pass, + catch_exceptions=False, + ) + json_error_message = invalid_query_format.format(value="@", exc="") + assert json_error_message in result.output + assert result.exit_code == usage_error_code diff --git a/test/esxport/_export_test.py b/test/esxport/_export_test.py index 88973b3..b715c61 100644 --- a/test/esxport/_export_test.py +++ b/test/esxport/_export_test.py @@ -63,6 +63,7 @@ def test_headers_extraction( with Path(f"{esxport_obj.opts.output_file}.tmp").open(mode="w", encoding="utf-8") as tmp_file: tmp_file.write(json.dumps(test_json)) tmp_file.write("\n") + assert Path(f"{esxport_obj.opts.output_file}.tmp").exists() is True keys = list(test_json.keys()) assert esxport_obj._extract_headers() == keys TestExport.rm_export_file(f"{inspect.stack()[0].function}.csv")