From c44f4ae1bf89e35ea614141562e30eaca0f1f39f Mon Sep 17 00:00:00 2001 From: Omar Agiez Date: Mon, 21 Oct 2024 00:59:29 +0300 Subject: [PATCH 1/3] Refactor list_languages and list_languages_for_data_type functions: Dynamic spacing and improved test coverage - Implement dynamic spacing for language, ISO, and QID columns in both functions. - Update unit tests to verify header formatting and first language entry dynamically for each function. - Enhance total print call count validation to ensure accuracy. --- tests/cli/test_list.py | 87 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 15 deletions(-) diff --git a/tests/cli/test_list.py b/tests/cli/test_list.py index 238ae8049..b39da0817 100644 --- a/tests/cli/test_list.py +++ b/tests/cli/test_list.py @@ -26,18 +26,46 @@ from scribe_data.cli.list import ( list_all, list_data_types, - # list_languages, - # list_languages_for_data_type, + list_languages, + list_languages_for_data_type, list_wrapper, + list_all_languages, + get_language_iso, + get_language_qid, + list_languages_with_metadata_for_data_type, ) from scribe_data.cli.main import main class TestListFunctions(unittest.TestCase): - # @patch("builtins.print") - # def test_list_languages(self, mock_print): - # list_languages() - # mock_print.assert_has_calls(expected_calls) + @patch("builtins.print") + def test_list_languages(self, mock_print): + # Call the function + list_languages() + + # Verify the headers + mock_print.assert_any_call("Language ISO QID ") + mock_print.assert_any_call("--------------------------") + + # Dynamically get the first language from the metadata + languages = list_all_languages() + first_language = languages[0] + first_iso = get_language_iso(first_language) + first_qid = get_language_qid(first_language) + + # Verify the first language entry + # Calculate column widths as in the actual function + language_col_width = max(len(lang) for lang in languages) + 2 + iso_col_width = max(len(get_language_iso(lang)) for lang in languages) + 2 + qid_col_width = max(len(get_language_qid(lang)) for lang in languages) + 2 + + # Verify the first language entry with dynamic spacing + mock_print.assert_any_call( + f"{first_language.capitalize():<{language_col_width}} {first_iso:<{iso_col_width}} {first_qid:<{qid_col_width}}" + ) + self.assertEqual( + mock_print.call_count, len(languages) + 5 + ) # Total print calls: N (languages) + 5 (initial line, header, two separators, final line). @patch("builtins.print") def test_list_data_types_all_languages(self, mock_print): @@ -129,15 +157,44 @@ def test_list_wrapper_data_types_for_language(self, mock_list_data_types): list_wrapper(language="English", data_type=True) mock_list_data_types.assert_called_with("English") - # @patch("builtins.print") - # def test_list_languages_for_data_type_valid(self, mock_print): - # list_languages_for_data_type("nouns") - # expected_calls = [ - # call(), - # call("Available languages: nouns"), - # call("--------------------------"), - # ] - # mock_print.assert_has_calls(expected_calls) + @patch("builtins.print") + def test_list_languages_for_data_type_valid(self, mock_print): + # Call the function with a specific data type + list_languages_for_data_type("nouns") + + # Dynamically create the header based on column widths + all_languages = list_languages_with_metadata_for_data_type() + + # Calculate column widths as in the actual function + language_col_width = max(len(lang["name"]) for lang in all_languages) + 2 + iso_col_width = max(len(lang["iso"]) for lang in all_languages) + 2 + qid_col_width = max(len(lang["qid"]) for lang in all_languages) + 2 + + # Dynamically generate the expected header string + expected_header = f"{'Language':<{language_col_width}} {'ISO':<{iso_col_width}} {'QID':<{qid_col_width}}" + + # Verify the headers dynamically + mock_print.assert_any_call(expected_header) + mock_print.assert_any_call( + "-" * (language_col_width + iso_col_width + qid_col_width) + ) + + # Verify the first language entry if there are any languages + + first_language = all_languages[0]["name"].capitalize() + first_iso = all_languages[0]["iso"] + first_qid = all_languages[0]["qid"] + + # Verify the first language entry with dynamic spacing + mock_print.assert_any_call( + f"{first_language:<{language_col_width}} {first_iso:<{iso_col_width}} {first_qid:<{qid_col_width}}" + ) + + # Check the total number of calls + expected_calls = ( + len(all_languages) + 5 + ) # Total calls = N (languages) + 5 (initial line, header, two separators, final line) + self.assertEqual(mock_print.call_count, expected_calls) @patch("scribe_data.cli.list.list_languages") def test_list_languages_command(self, mock_list_languages): From 5710a705c719b670843d1b3eccde656737edd3ce Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Thu, 24 Oct 2024 01:14:26 +0200 Subject: [PATCH 2/3] Fix tests --- tests/cli/test_list.py | 45 ++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/tests/cli/test_list.py b/tests/cli/test_list.py index e0d35dfec..1e4d708a7 100644 --- a/tests/cli/test_list.py +++ b/tests/cli/test_list.py @@ -24,15 +24,15 @@ from unittest.mock import call, patch from scribe_data.cli.list import ( + get_language_iso, + get_language_qid, list_all, + list_all_languages, list_data_types, list_languages, list_languages_for_data_type, - list_wrapper, - list_all_languages, - get_language_iso, - get_language_qid, list_languages_with_metadata_for_data_type, + list_wrapper, ) from scribe_data.cli.main import main @@ -40,32 +40,30 @@ class TestListFunctions(unittest.TestCase): @patch("builtins.print") def test_list_languages(self, mock_print): - # Call the function list_languages() # Verify the headers mock_print.assert_any_call("Language ISO QID ") - mock_print.assert_any_call("--------------------------") + mock_print.assert_any_call("==========================") - # Dynamically get the first language from the metadata + # Dynamically get the first language from the metadata. languages = list_all_languages() first_language = languages[0] first_iso = get_language_iso(first_language) first_qid = get_language_qid(first_language) - # Verify the first language entry - # Calculate column widths as in the actual function + # Verify the first language entry. + # Calculate column widths as in the actual function. language_col_width = max(len(lang) for lang in languages) + 2 iso_col_width = max(len(get_language_iso(lang)) for lang in languages) + 2 qid_col_width = max(len(get_language_qid(lang)) for lang in languages) + 2 - # Verify the first language entry with dynamic spacing + # Verify the first language entry with dynamic spacing. mock_print.assert_any_call( f"{first_language.capitalize():<{language_col_width}} {first_iso:<{iso_col_width}} {first_qid:<{qid_col_width}}" ) - self.assertEqual( - mock_print.call_count, len(languages) + 5 - ) # Total print calls: N (languages) + 5 (initial line, header, two separators, final line). + # Total print calls: N (languages) + 5 (initial line, header, one separator, final line). + self.assertEqual(mock_print.call_count, len(languages) + 4) @patch("builtins.print") def test_list_data_types_all_languages(self, mock_print): @@ -157,41 +155,40 @@ def test_list_wrapper_data_types_for_language(self, mock_list_data_types): @patch("builtins.print") def test_list_languages_for_data_type_valid(self, mock_print): - # Call the function with a specific data type + # Call the function with a specific data type. list_languages_for_data_type("nouns") - # Dynamically create the header based on column widths + # Dynamically create the header based on column widths. all_languages = list_languages_with_metadata_for_data_type() - # Calculate column widths as in the actual function + # Calculate column widths as in the actual function. language_col_width = max(len(lang["name"]) for lang in all_languages) + 2 iso_col_width = max(len(lang["iso"]) for lang in all_languages) + 2 qid_col_width = max(len(lang["qid"]) for lang in all_languages) + 2 - # Dynamically generate the expected header string + # Dynamically generate the expected header string. expected_header = f"{'Language':<{language_col_width}} {'ISO':<{iso_col_width}} {'QID':<{qid_col_width}}" # Verify the headers dynamically mock_print.assert_any_call(expected_header) mock_print.assert_any_call( - "-" * (language_col_width + iso_col_width + qid_col_width) + "=" * (language_col_width + iso_col_width + qid_col_width) ) - # Verify the first language entry if there are any languages + # Verify the first language entry if there are any languages. first_language = all_languages[0]["name"].capitalize() first_iso = all_languages[0]["iso"] first_qid = all_languages[0]["qid"] - # Verify the first language entry with dynamic spacing + # Verify the first language entry with dynamic spacing. mock_print.assert_any_call( f"{first_language:<{language_col_width}} {first_iso:<{iso_col_width}} {first_qid:<{qid_col_width}}" ) - # Check the total number of calls - expected_calls = ( - len(all_languages) + 5 - ) # Total calls = N (languages) + 5 (initial line, header, two separators, final line) + # Check the total number of calls. + # Total calls = N (languages) + 5 (initial line, header, one separator, final line) + expected_calls = len(all_languages) + 4 self.assertEqual(mock_print.call_count, expected_calls) @patch("scribe_data.cli.list.list_languages") From bbf11fb548de3cc17ebcc8ada391a79829651c89 Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Thu, 24 Oct 2024 01:19:27 +0200 Subject: [PATCH 3/3] Remove mid process language capitalization --- src/scribe_data/cli/list.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/scribe_data/cli/list.py b/src/scribe_data/cli/list.py index cc69dbdea..d1082688c 100644 --- a/src/scribe_data/cli/list.py +++ b/src/scribe_data/cli/list.py @@ -105,9 +105,8 @@ def list_data_types(language: str = None) -> None: else: data_types = set() for lang in languages: - language_dir = ( - LANGUAGE_DATA_EXTRACTION_DIR - / format_sublanguage_name(lang, language_metadata).capitalize() + language_dir = LANGUAGE_DATA_EXTRACTION_DIR / format_sublanguage_name( + lang, language_metadata ) if language_dir.is_dir(): data_types.update(f.name for f in language_dir.iterdir() if f.is_dir())