"""Unit tests for the helpers in ``depicts.utils``. These tests cover common paths and a few edge cases to ensure stable behavior across refactors. """ from depicts import utils from flask import Flask import pytest def test_ordinal() -> None: """Convert integers to the expected English ordinals.""" assert utils.ordinal(1) == "1st" assert utils.ordinal(2) == "2nd" assert utils.ordinal(3) == "3rd" assert utils.ordinal(4) == "4th" def test_chunk_basic() -> None: """Chunk an iterable into fixed-size tuples with a remainder.""" data = list(range(10)) chunks = list(utils.chunk(data, 3)) assert chunks == [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9,)] def test_drop_start_success_and_failure() -> None: """Drop a matching prefix and assert on missing prefix.""" assert utils.drop_start("Category:Painting", "Category:") == "Painting" with pytest.raises(AssertionError): utils.drop_start("Painting", "Category:") def test_drop_category_ns() -> None: """Remove the "Category:" namespace from a string.""" assert utils.drop_category_ns("Category:Portraits") == "Portraits" def test_parse_sitelink() -> None: """Decode sitelink by removing prefix, unquoting, and de-underscoring.""" start = "https://en.wikipedia.org/wiki/" s = "https://en.wikipedia.org/wiki/Hello_World%21" assert utils.parse_sitelink(s, start) == "Hello World!" def test_word_contains_letter() -> None: """Detect whether a token contains at least one letter.""" assert utils.word_contains_letter("abc123") is True assert utils.word_contains_letter("12345") is False assert utils.word_contains_letter("!!!") is False def test_also_singular_main_plural_and_singular() -> None: """Return both plural and singular when appropriate.""" # plural should include both plural and singular assert set(utils.also_singular_main("Dogs")) == {"Dogs", "Dog"} # singular should return as-is assert utils.also_singular_main("Dog") == ["Dog"] def test_also_singular_gender_and_skip_names() -> None: """Add gender-derived forms and honor the skip list.""" # Adds gender-derived singulars names = utils.also_singular("Women") assert "Women" in names assert "woman" in names # Skips configured names assert utils.also_singular("National Gallery") == [] def test_wiki_url_capitalization_and_ns() -> None: """Build proper MediaWiki URLs with capitalization and namespace.""" # lowercase first letter should be capitalized, spaces become underscores url = utils.wiki_url("example page", site="enwiki") expected = "https://en.wikipedia.org/wiki/Example_page" assert url == expected # namespace prefix when provided url_cat = utils.wiki_url("Portraits", site="commons", ns="Category") expected_cat = "https://commons.wikimedia.org/wiki/Category:Portraits" assert url_cat == expected_cat def test_get_int_arg_present_and_missing() -> None: """Parse integer query args and ignore missing/non-integer values.""" app = Flask(__name__) with app.test_request_context("/?page=10&foo=bar"): assert utils.get_int_arg("page") == 10 assert utils.get_int_arg("foo") is None assert utils.get_int_arg("missing") is None def test_format_time_precisions() -> None: """Format time strings for multiple precision levels.""" # Full date assert utils.format_time("+1965-04-23T00:00:00Z", 11) == "23 April 1965" # Month precision assert utils.format_time("+1965-04-00T00:00:00Z", 10) == "April 1965" # Year precision assert utils.format_time("+1965-00-00T00:00:00Z", 9) == "1965" # Decade precision assert utils.format_time("+1960-00-00T00:00:00Z", 8) == "1960s" # Century precision assert utils.format_time("+1965-00-00T00:00:00Z", 7) == "20th century" # Millennium precision assert utils.format_time("+2001-00-00T00:00:00Z", 6) == "3rd millennium" # Unparseable falls back to input assert utils.format_time("not-a-date", 9) == "not-a-date" # BC year with unknown month/day should still return year for precision 9 assert utils.format_time("-0123-00-00T00:00:00Z", 9) == "-123"