From 66dcd6bd12d2061b988d11829652c7adc1640857 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:02:44 +0000 Subject: [PATCH 1/7] Initial plan From 04721bc811e2befb0252e59330cbdcb0a077827f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:08:18 +0000 Subject: [PATCH 2/7] Add comprehensive tests for tools.core, encoding, ancient, and misspell modules Co-authored-by: bact <128572+bact@users.noreply.github.com> --- tests/compact/testc_tools.py | 60 ++++++++++++++++++++++++++++++- tests/core/test_ancient.py | 26 ++++++++++++++ tests/core/test_tools.py | 69 ++++++++++++++++++++++++++++++++++++ tests/core/test_util.py | 9 +++++ 4 files changed, 163 insertions(+), 1 deletion(-) diff --git a/tests/compact/testc_tools.py b/tests/compact/testc_tools.py index 6b04c0a1f..f15668717 100644 --- a/tests/compact/testc_tools.py +++ b/tests/compact/testc_tools.py @@ -6,7 +6,11 @@ import numpy as np -from pythainlp.tools.misspell import misspell +from pythainlp.tools.misspell import ( + find_misspell_candidates, + misspell, + search_location_of_character, +) def _count_difference(st1: str, st2: str) -> int: @@ -85,3 +89,57 @@ def test_misspell_with_ratio_100_percent(self): 2, f"expect len(text)-2 misspells with ratio=1.5. (Δ={diff})", ) + + def test_search_location_of_character(self): + """Test search_location_of_character function.""" + # Test Thai characters + loc = search_location_of_character("ก") + self.assertIsNotNone(loc) + self.assertEqual(len(loc), 4) # (language_ix, is_shift, row, pos) + + # Test English characters + loc = search_location_of_character("a") + self.assertIsNotNone(loc) + self.assertEqual(len(loc), 4) + + # Test shifted characters + loc = search_location_of_character("A") + self.assertIsNotNone(loc) + + # Test numbers + loc = search_location_of_character("1") + self.assertIsNotNone(loc) + + # Test character not in keyboard + loc = search_location_of_character("€") + self.assertIsNone(loc) + + # Test empty string (returns first position due to "in" check) + loc = search_location_of_character("") + # Empty string matches "" in row so it returns a location + self.assertIsNotNone(loc) + + def test_find_misspell_candidates(self): + """Test find_misspell_candidates function.""" + # Test Thai character + candidates = find_misspell_candidates("ก") + self.assertIsNotNone(candidates) + self.assertIsInstance(candidates, list) + self.assertGreater(len(candidates), 0) + + # Test English character + candidates = find_misspell_candidates("a") + self.assertIsNotNone(candidates) + self.assertIsInstance(candidates, list) + self.assertGreater(len(candidates), 0) + + # Test character not in keyboard + candidates = find_misspell_candidates("€") + self.assertIsNone(candidates) + + # Test that candidates are different from input + candidates = find_misspell_candidates("ด") + if candidates: + for candidate in candidates: + # Candidates should be strings + self.assertIsInstance(candidate, str) diff --git a/tests/core/test_ancient.py b/tests/core/test_ancient.py index 66bac54cf..78c4afe98 100644 --- a/tests/core/test_ancient.py +++ b/tests/core/test_ancient.py @@ -23,6 +23,11 @@ def test_aksonhan_to_current(self): self.assertEqual(aksonhan_to_current("บงงคบบ"), "บังคับ") self.assertEqual(aksonhan_to_current("สรรเพชญ"), "สรรเพชญ") + # Edge cases + self.assertEqual(aksonhan_to_current(""), "") # empty string + self.assertEqual(aksonhan_to_current("ก"), "ก") # single char + self.assertEqual(aksonhan_to_current("กา"), "กา") # two chars + def test_convert_currency(self): self.assertEqual( convert_currency(80, "บาท")["ตำลึง"], @@ -44,3 +49,24 @@ def test_convert_currency(self): convert_currency(1,"ชั่ง")["ชั่ง"], 1.0 ) + + # Test all supported units + result = convert_currency(1, "บาท") + self.assertIn("เบี้ย", result) + self.assertIn("อัฐ", result) + self.assertIn("ไพ", result) + self.assertIn("เฟื้อง", result) + self.assertIn("สลึง", result) + self.assertIn("ตำลึง", result) + + # Test with zero value + result = convert_currency(0, "บาท") + self.assertEqual(result["บาท"], 0.0) + + # Test with fractional value + result = convert_currency(0.5, "บาท") + self.assertEqual(result["บาท"], 0.5) + + # Test invalid unit + with self.assertRaises(NotImplementedError): + convert_currency(1, "invalid_unit") diff --git a/tests/core/test_tools.py b/tests/core/test_tools.py index 8a535446a..e2e606295 100644 --- a/tests/core/test_tools.py +++ b/tests/core/test_tools.py @@ -3,14 +3,17 @@ # SPDX-License-Identifier: Apache-2.0 import os +import sys import tempfile import unittest +import warnings from pythainlp.tools import ( get_full_data_path, get_pythainlp_data_path, get_pythainlp_path, ) +from pythainlp.tools.core import safe_print, warn_deprecation class ToolsTestCase(unittest.TestCase): @@ -57,3 +60,69 @@ def test_custom_data_dir(self): os.environ["PYTHAINLP_DATA_DIR"] = original_value elif "PYTHAINLP_DATA_DIR" in os.environ: del os.environ["PYTHAINLP_DATA_DIR"] + + def test_warn_deprecation(self): + """Test deprecation warning function.""" + # Test basic deprecation warning + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + warn_deprecation("old_func") + self.assertEqual(len(w), 1) + self.assertTrue(issubclass(w[0].category, DeprecationWarning)) + self.assertIn("old_func", str(w[0].message)) + self.assertIn("deprecated", str(w[0].message)) + + # Test with replacement function + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + warn_deprecation("old_func", replacing_func="new_func") + self.assertEqual(len(w), 1) + self.assertIn("old_func", str(w[0].message)) + self.assertIn("new_func", str(w[0].message)) + + # Test with version information + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + warn_deprecation( + "old_func", + deprecated_version="1.0", + removal_version="2.0" + ) + self.assertEqual(len(w), 1) + self.assertIn("1.0", str(w[0].message)) + self.assertIn("2.0", str(w[0].message)) + + # Test with all parameters + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + warn_deprecation( + "old_func", + replacing_func="new_func", + deprecated_version="1.0", + removal_version="2.0" + ) + self.assertEqual(len(w), 1) + message = str(w[0].message) + self.assertIn("old_func", message) + self.assertIn("new_func", message) + self.assertIn("1.0", message) + self.assertIn("2.0", message) + + def test_safe_print(self): + """Test safe_print function.""" + # Test normal printing + safe_print("Hello, World!") + safe_print("สวัสดีครับ") + + # Test with Unicode characters + safe_print("Hello 👋 World") + safe_print("ภาษาไทย") + + # Test with empty string + safe_print("") + + # Test with special characters + safe_print("\n\t") + + # Note: Testing actual UnicodeEncodeError is environment-dependent + # and would require mocking sys.stdout.encoding diff --git a/tests/core/test_util.py b/tests/core/test_util.py index 209d0521e..93d9d11b3 100644 --- a/tests/core/test_util.py +++ b/tests/core/test_util.py @@ -863,6 +863,10 @@ def test_syllable_open_close_detector(self): def test_to_idna(self): self.assertEqual(to_idna("คนละครึ่ง.com"), "xn--42caj4e6bk1f5b1j.com") + # Additional test cases for IDNA encoding + self.assertEqual(to_idna("ไทย.com"), "xn--o3cw4h.com") + self.assertEqual(to_idna("example.com"), "example.com") # ASCII unchanged + self.assertEqual(to_idna("ภาษาไทย.th"), "xn--o3crh0a8bb0k.th") def test_thai_strptime(self): self.assertIsNotNone( @@ -923,6 +927,11 @@ def test_tis620_to_utf8(self): self.assertEqual( tis620_to_utf8("¡ÃзÃÇ§ÍØµÊÒË¡ÃÃÁ"), "กระทรวงอุตสาหกรรม" ) + # Additional test cases + self.assertEqual(tis620_to_utf8("»ÃÐà·Èä·Â"), "ประเทศไทย") + self.assertEqual(tis620_to_utf8("ÀÒÉÒä·Â"), "ภาษาไทย") + # Empty string + self.assertEqual(tis620_to_utf8(""), "") def test_remove_repeat_consonants(self): # update of pythainlp.copus.thai_words() able to break this From 6748029ca7ac40783fb46ddc2965b08d4b8bb609 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:10:09 +0000 Subject: [PATCH 3/7] Add edge case tests for LCS, emoji, and collate functions Co-authored-by: bact <128572+bact@users.noreply.github.com> --- tests/core/test_util.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/core/test_util.py b/tests/core/test_util.py index 93d9d11b3..578398428 100644 --- a/tests/core/test_util.py +++ b/tests/core/test_util.py @@ -97,6 +97,14 @@ def test_collate(self): collate(["ไก่", "เป็ด", "หมู", "วัว"], reverse=True), ["หมู", "วัว", "เป็ด", "ไก่"], ) + # Edge cases: mixed Thai and numbers + self.assertEqual(collate(["ก", "1", "ข"]), ["1", "ก", "ข"]) + # Edge cases: with spaces (spaces sort before letters) + result = collate([" ก", "ก", " ก"]) + self.assertEqual(len(result), 3) + self.assertIn(" ก", result) + self.assertIn("ก", result) + self.assertIn(" ก", result) # ### pythainlp.util.numtoword @@ -720,6 +728,11 @@ def test_emoji_to_thai(self): ":ธง_ไทย: นี่คือธงประเทศไทย", ) + # Edge cases + self.assertEqual(emoji_to_thai(""), "") # empty string + self.assertEqual(emoji_to_thai("no emoji"), "no emoji") # no emoji + self.assertEqual(emoji_to_thai("ไม่มีอีโมจิ"), "ไม่มีอีโมจิ") # Thai no emoji + def test_sound_syllable(self): test = [ ("มา", "live"), @@ -997,6 +1010,19 @@ def test_longest_common_subsequence(self): self.assertEqual(longest_common_subsequence("ABCBDAB", "BDCAB"), "BDAB") self.assertEqual(longest_common_subsequence("AGGTAB", "GXTXAYB"), "GTAB") self.assertEqual(longest_common_subsequence("ABCDGH", "AEDFHR"), "ADH") + + # Edge cases + self.assertEqual(longest_common_subsequence("", ""), "") # empty strings + self.assertEqual(longest_common_subsequence("ABC", ""), "") # one empty + self.assertEqual(longest_common_subsequence("", "ABC"), "") # other empty + self.assertEqual(longest_common_subsequence("A", "A"), "A") # single char match + self.assertEqual(longest_common_subsequence("A", "B"), "") # single char no match + self.assertEqual(longest_common_subsequence("ABC", "ABC"), "ABC") # identical + self.assertEqual(longest_common_subsequence("ABC", "XYZ"), "") # no common chars + + # Thai text + self.assertEqual(longest_common_subsequence("ไทย", "ไทย"), "ไทย") + self.assertEqual(longest_common_subsequence("ภาษาไทย", "ไทย"), "ไทย") self.assertEqual(longest_common_subsequence("ABC", "AC"), "AC") self.assertEqual(longest_common_subsequence("ABC", "DEF"), "") self.assertEqual(longest_common_subsequence("", "ABC"), "") From e4e0507204ecffd6c4d4c708f0b4c143df01092e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:11:08 +0000 Subject: [PATCH 4/7] Add test coverage improvements documentation Co-authored-by: bact <128572+bact@users.noreply.github.com> --- TEST_COVERAGE_IMPROVEMENTS.md | 173 ++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 TEST_COVERAGE_IMPROVEMENTS.md diff --git a/TEST_COVERAGE_IMPROVEMENTS.md b/TEST_COVERAGE_IMPROVEMENTS.md new file mode 100644 index 000000000..7b76ff733 --- /dev/null +++ b/TEST_COVERAGE_IMPROVEMENTS.md @@ -0,0 +1,173 @@ +# Test Coverage Improvements + +## Summary + +This document summarizes the test coverage improvements made to the PyThaiNLP project based on the analysis of the Coveralls test coverage report. + +## Modules with Improved Coverage + +### Core Tests (test_*.py) + +#### 1. `pythainlp.tools.core` Module +**File**: `tests/core/test_tools.py` + +Added comprehensive tests for: +- `warn_deprecation()` - Deprecation warning function + - Test basic deprecation warning + - Test with replacement function + - Test with version information + - Test with all parameters combined +- `safe_print()` - Safe printing with UnicodeEncodeError handling + - Test normal printing + - Test with Unicode characters + - Test with empty strings + - Test with special characters + +**New Test Count**: 2 test methods covering 8+ test cases + +#### 2. `pythainlp.util.encoding` Module +**File**: `tests/core/test_util.py` + +Enhanced existing tests with edge cases for: +- `tis620_to_utf8()` - TIS-620 to UTF-8 conversion + - Additional Thai text conversions + - Empty string handling +- `to_idna()` - IDNA encoding for internationalized domain names + - Multiple Thai domain examples + - ASCII domain handling (unchanged) + +**Enhanced Test Count**: 2 test methods with 4+ additional test cases + +#### 3. `pythainlp.ancient` Module +**File**: `tests/core/test_ancient.py` + +Enhanced existing tests with edge cases for: +- `aksonhan_to_current()` - AksonHan to current Thai conversion + - Empty string handling + - Single character handling + - Two character strings +- `convert_currency()` - Ancient Thai currency conversion + - All supported currency units + - Zero value handling + - Fractional value handling + - Invalid unit error handling + +**Enhanced Test Count**: 2 test methods with 7+ additional test cases + +#### 4. Utility Functions Edge Cases +**File**: `tests/core/test_util.py` + +Enhanced existing tests for: +- `longest_common_subsequence()` - LCS algorithm + - Empty strings (both, one, other) + - Single character matches and non-matches + - Identical strings + - No common characters + - Thai text examples +- `emoji_to_thai()` - Emoji to Thai text conversion + - Empty strings + - Text with no emoji + - Thai text with no emoji +- `collate()` - Thai text collation + - Mixed Thai and numbers + - Strings with spaces + +**Enhanced Test Count**: 3 test methods with 12+ additional test cases + +### Compact Tests (testc_*.py) + +#### 5. `pythainlp.tools.misspell` Module +**File**: `tests/compact/testc_tools.py` + +Added comprehensive tests for helper functions: +- `search_location_of_character()` - Find character location on keyboard + - Thai character handling + - English character handling + - Shifted character handling + - Number handling + - Characters not on keyboard (returns None) + - Empty string handling +- `find_misspell_candidates()` - Find possible misspelling candidates + - Thai character candidates + - English character candidates + - Characters not on keyboard + - Validation that candidates are strings + +**New Test Count**: 2 test methods covering 12+ test cases + +## Coverage Statistics + +### Before +Based on Coveralls report analysis, several modules had no or minimal test coverage: +- `pythainlp.tools.core` - No tests for `warn_deprecation()` and `safe_print()` +- `pythainlp.tools.misspell` helper functions - Only the main `misspell()` function was tested +- Edge cases in utility functions - Missing edge case coverage for empty inputs, special characters, etc. +- `pythainlp.ancient` module - Basic tests only, missing edge cases + +### After +- **Core module tests added**: 4 new test methods, 27+ new test cases +- **Compact module tests added**: 2 new test methods, 12+ new test cases +- **Total new test coverage**: 6 test methods, 39+ test cases + +## Test Categories + +All tests follow the established test categorization: + +1. **Core Tests** (`test_*.py`) + - No external dependencies beyond standard library + - Test case class suffix: `TestCase` + - Run with: `python -m unittest tests.core` + +2. **Compact Tests** (`testc_*.py`) + - Depend on: PyYAML, nlpo3, numpy, pyicu, python-crfsuite, requests + - Test case class suffix: `TestCaseC` + - Run with: `python -m unittest tests.compact` + +## Files Modified + +1. `tests/core/test_tools.py` - Added 2 new test methods +2. `tests/core/test_ancient.py` - Enhanced with edge cases +3. `tests/core/test_util.py` - Enhanced 5 test methods with edge cases +4. `tests/compact/testc_tools.py` - Added 2 new test methods + +## Running the New Tests + +```bash +# Run all modified core tests +python -m unittest tests.core.test_tools tests.core.test_ancient tests.core.test_util -v + +# Run compact tests +python -m unittest tests.compact.testc_tools -v + +# Run specific new test methods +python -m unittest tests.core.test_tools.ToolsTestCase.test_warn_deprecation -v +python -m unittest tests.core.test_tools.ToolsTestCase.test_safe_print -v +python -m unittest tests.compact.testc_tools.MisspellTestCaseC.test_search_location_of_character -v +python -m unittest tests.compact.testc_tools.MisspellTestCaseC.test_find_misspell_candidates -v +``` + +## Recommendations for Further Testing + +Based on the analysis, these modules still need more test coverage: + +### High Priority (Core functionality, no tests) +1. `pythainlp.chat.core` - ChatBot model loading and chat functions +2. `pythainlp.coref._fastcoref` - Coreference resolution +3. `pythainlp.benchmarks` - Benchmarking utilities + +### Medium Priority (Utility functions, minimal tests) +1. `pythainlp.util.keyboard` - More edge cases for keyboard distance +2. `pythainlp.util.thai_lunar_date` - Date conversion functions +3. `pythainlp.util.morse` - More edge cases for encoding/decoding + +### Low Priority (Advanced features, require heavy dependencies) +1. Specialized tokenizers (ssg, deepcut, etcc, etc.) +2. Parser modules (spacy_thai_engine, transformers_ud, etc.) +3. Model-based taggers and classifiers + +## Notes + +- All new tests follow the project's test categorization system +- Tests are written to pass existing linting and formatting requirements +- Edge cases focus on empty inputs, boundary conditions, and error handling +- Tests maintain consistency with existing test patterns in the codebase From 337941b5bb009ef22be2970f81a424073ad3ba4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:12:41 +0000 Subject: [PATCH 5/7] Fix code review feedback: Remove duplicate test cases and improve comments Co-authored-by: bact <128572+bact@users.noreply.github.com> --- tests/compact/testc_tools.py | 5 +++-- tests/core/test_util.py | 6 +----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/compact/testc_tools.py b/tests/compact/testc_tools.py index f15668717..0683c9bb2 100644 --- a/tests/compact/testc_tools.py +++ b/tests/compact/testc_tools.py @@ -114,9 +114,10 @@ def test_search_location_of_character(self): loc = search_location_of_character("€") self.assertIsNone(loc) - # Test empty string (returns first position due to "in" check) + # Test empty string + # Note: Empty string returns a location because Python's "in" operator + # matches empty string at the beginning of any string loc = search_location_of_character("") - # Empty string matches "" in row so it returns a location self.assertIsNotNone(loc) def test_find_misspell_candidates(self): diff --git a/tests/core/test_util.py b/tests/core/test_util.py index 578398428..bd715bda9 100644 --- a/tests/core/test_util.py +++ b/tests/core/test_util.py @@ -1019,15 +1019,11 @@ def test_longest_common_subsequence(self): self.assertEqual(longest_common_subsequence("A", "B"), "") # single char no match self.assertEqual(longest_common_subsequence("ABC", "ABC"), "ABC") # identical self.assertEqual(longest_common_subsequence("ABC", "XYZ"), "") # no common chars + self.assertEqual(longest_common_subsequence("ABC", "AC"), "AC") # Thai text self.assertEqual(longest_common_subsequence("ไทย", "ไทย"), "ไทย") self.assertEqual(longest_common_subsequence("ภาษาไทย", "ไทย"), "ไทย") - self.assertEqual(longest_common_subsequence("ABC", "AC"), "AC") - self.assertEqual(longest_common_subsequence("ABC", "DEF"), "") - self.assertEqual(longest_common_subsequence("", "ABC"), "") - self.assertEqual(longest_common_subsequence("ABC", ""), "") - self.assertEqual(longest_common_subsequence("", ""), "") def test_analyze_thai_text(self): self.assertEqual( From df7dd308cae90bcbf167a89eb15e00e5bef627b0 Mon Sep 17 00:00:00 2001 From: Arthit Suriyawongkul Date: Mon, 2 Feb 2026 09:21:50 +0000 Subject: [PATCH 6/7] Remove unused import --- pyproject.toml | 2 +- tests/README.md | 4 ++-- tests/core/test_tools.py | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1ad41fd39..9724eb0ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -226,7 +226,7 @@ full = [ "sefr_cut>=1.1", "symspellpy==6.9.0", "thai-nner==0.3", - "tltk>=1.6.8,<2", + "tltk>=1.10,<2", "torch>=1.13.1,<3", "transformers==4.57.6", "ufal.chu-liu-edmonds==1.0.3", diff --git a/tests/README.md b/tests/README.md index 137a2caaf..49e47b131 100644 --- a/tests/README.md +++ b/tests/README.md @@ -22,7 +22,7 @@ supported Python versions and operating systems: The CI/CD test workflow is at . - + ## Core tests (test_*.py) - Run `unittest tests.core` @@ -65,7 +65,7 @@ The CI/CD test workflow is at A comprehensive test suite within core tests that tests edge cases important for real-world usage: -- Empty strings and various whitespace handling (spaces, tabs, unicode spaces) +- Empty strings and various whitespace handling (spaces, tabs, Unicode spaces) - Special characters from encoding issues, BOM, terminal copy/paste - Truncated/malformed Unicode and surrogate pairs - Emoji and modern Unicode sequences (ZWJ, modifiers, flags) diff --git a/tests/core/test_tools.py b/tests/core/test_tools.py index e2e606295..72c473395 100644 --- a/tests/core/test_tools.py +++ b/tests/core/test_tools.py @@ -3,7 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 import os -import sys import tempfile import unittest import warnings From 5e582c14a59a707a8c6a835e17547a75442a263c Mon Sep 17 00:00:00 2001 From: Arthit Suriyawongkul Date: Mon, 2 Feb 2026 09:22:14 +0000 Subject: [PATCH 7/7] Delete TEST_COVERAGE_IMPROVEMENTS.md --- TEST_COVERAGE_IMPROVEMENTS.md | 173 ---------------------------------- 1 file changed, 173 deletions(-) delete mode 100644 TEST_COVERAGE_IMPROVEMENTS.md diff --git a/TEST_COVERAGE_IMPROVEMENTS.md b/TEST_COVERAGE_IMPROVEMENTS.md deleted file mode 100644 index 7b76ff733..000000000 --- a/TEST_COVERAGE_IMPROVEMENTS.md +++ /dev/null @@ -1,173 +0,0 @@ -# Test Coverage Improvements - -## Summary - -This document summarizes the test coverage improvements made to the PyThaiNLP project based on the analysis of the Coveralls test coverage report. - -## Modules with Improved Coverage - -### Core Tests (test_*.py) - -#### 1. `pythainlp.tools.core` Module -**File**: `tests/core/test_tools.py` - -Added comprehensive tests for: -- `warn_deprecation()` - Deprecation warning function - - Test basic deprecation warning - - Test with replacement function - - Test with version information - - Test with all parameters combined -- `safe_print()` - Safe printing with UnicodeEncodeError handling - - Test normal printing - - Test with Unicode characters - - Test with empty strings - - Test with special characters - -**New Test Count**: 2 test methods covering 8+ test cases - -#### 2. `pythainlp.util.encoding` Module -**File**: `tests/core/test_util.py` - -Enhanced existing tests with edge cases for: -- `tis620_to_utf8()` - TIS-620 to UTF-8 conversion - - Additional Thai text conversions - - Empty string handling -- `to_idna()` - IDNA encoding for internationalized domain names - - Multiple Thai domain examples - - ASCII domain handling (unchanged) - -**Enhanced Test Count**: 2 test methods with 4+ additional test cases - -#### 3. `pythainlp.ancient` Module -**File**: `tests/core/test_ancient.py` - -Enhanced existing tests with edge cases for: -- `aksonhan_to_current()` - AksonHan to current Thai conversion - - Empty string handling - - Single character handling - - Two character strings -- `convert_currency()` - Ancient Thai currency conversion - - All supported currency units - - Zero value handling - - Fractional value handling - - Invalid unit error handling - -**Enhanced Test Count**: 2 test methods with 7+ additional test cases - -#### 4. Utility Functions Edge Cases -**File**: `tests/core/test_util.py` - -Enhanced existing tests for: -- `longest_common_subsequence()` - LCS algorithm - - Empty strings (both, one, other) - - Single character matches and non-matches - - Identical strings - - No common characters - - Thai text examples -- `emoji_to_thai()` - Emoji to Thai text conversion - - Empty strings - - Text with no emoji - - Thai text with no emoji -- `collate()` - Thai text collation - - Mixed Thai and numbers - - Strings with spaces - -**Enhanced Test Count**: 3 test methods with 12+ additional test cases - -### Compact Tests (testc_*.py) - -#### 5. `pythainlp.tools.misspell` Module -**File**: `tests/compact/testc_tools.py` - -Added comprehensive tests for helper functions: -- `search_location_of_character()` - Find character location on keyboard - - Thai character handling - - English character handling - - Shifted character handling - - Number handling - - Characters not on keyboard (returns None) - - Empty string handling -- `find_misspell_candidates()` - Find possible misspelling candidates - - Thai character candidates - - English character candidates - - Characters not on keyboard - - Validation that candidates are strings - -**New Test Count**: 2 test methods covering 12+ test cases - -## Coverage Statistics - -### Before -Based on Coveralls report analysis, several modules had no or minimal test coverage: -- `pythainlp.tools.core` - No tests for `warn_deprecation()` and `safe_print()` -- `pythainlp.tools.misspell` helper functions - Only the main `misspell()` function was tested -- Edge cases in utility functions - Missing edge case coverage for empty inputs, special characters, etc. -- `pythainlp.ancient` module - Basic tests only, missing edge cases - -### After -- **Core module tests added**: 4 new test methods, 27+ new test cases -- **Compact module tests added**: 2 new test methods, 12+ new test cases -- **Total new test coverage**: 6 test methods, 39+ test cases - -## Test Categories - -All tests follow the established test categorization: - -1. **Core Tests** (`test_*.py`) - - No external dependencies beyond standard library - - Test case class suffix: `TestCase` - - Run with: `python -m unittest tests.core` - -2. **Compact Tests** (`testc_*.py`) - - Depend on: PyYAML, nlpo3, numpy, pyicu, python-crfsuite, requests - - Test case class suffix: `TestCaseC` - - Run with: `python -m unittest tests.compact` - -## Files Modified - -1. `tests/core/test_tools.py` - Added 2 new test methods -2. `tests/core/test_ancient.py` - Enhanced with edge cases -3. `tests/core/test_util.py` - Enhanced 5 test methods with edge cases -4. `tests/compact/testc_tools.py` - Added 2 new test methods - -## Running the New Tests - -```bash -# Run all modified core tests -python -m unittest tests.core.test_tools tests.core.test_ancient tests.core.test_util -v - -# Run compact tests -python -m unittest tests.compact.testc_tools -v - -# Run specific new test methods -python -m unittest tests.core.test_tools.ToolsTestCase.test_warn_deprecation -v -python -m unittest tests.core.test_tools.ToolsTestCase.test_safe_print -v -python -m unittest tests.compact.testc_tools.MisspellTestCaseC.test_search_location_of_character -v -python -m unittest tests.compact.testc_tools.MisspellTestCaseC.test_find_misspell_candidates -v -``` - -## Recommendations for Further Testing - -Based on the analysis, these modules still need more test coverage: - -### High Priority (Core functionality, no tests) -1. `pythainlp.chat.core` - ChatBot model loading and chat functions -2. `pythainlp.coref._fastcoref` - Coreference resolution -3. `pythainlp.benchmarks` - Benchmarking utilities - -### Medium Priority (Utility functions, minimal tests) -1. `pythainlp.util.keyboard` - More edge cases for keyboard distance -2. `pythainlp.util.thai_lunar_date` - Date conversion functions -3. `pythainlp.util.morse` - More edge cases for encoding/decoding - -### Low Priority (Advanced features, require heavy dependencies) -1. Specialized tokenizers (ssg, deepcut, etcc, etc.) -2. Parser modules (spacy_thai_engine, transformers_ud, etc.) -3. Model-based taggers and classifiers - -## Notes - -- All new tests follow the project's test categorization system -- Tests are written to pass existing linting and formatting requirements -- Edge cases focus on empty inputs, boundary conditions, and error handling -- Tests maintain consistency with existing test patterns in the codebase