Compare commits
	
		
			No commits in common. "dcb0849d2615f0b3d94b168c67307152003e016e" and "fe664be570b8cf210d9e95ba613351cf79198c96" have entirely different histories.
		
	
	
		
			dcb0849d26
			...
			fe664be570
		
	
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
__pycache__
 | 
			
		||||
| 
						 | 
				
			
			@ -1,74 +0,0 @@
 | 
			
		|||
"""Unit tests for pagination helpers in ``depicts.pager``.
 | 
			
		||||
 | 
			
		||||
Covers page counting, slicing, page iteration, URL building, and Jinja init.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from depicts.pager import Pagination, init_pager, url_for_other_page
 | 
			
		||||
from flask import Flask
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _make_app() -> Flask:
 | 
			
		||||
    """Create a minimal Flask app with a paging route."""
 | 
			
		||||
    app = Flask(__name__)
 | 
			
		||||
 | 
			
		||||
    @app.get("/items/<int:category_id>")
 | 
			
		||||
    def items(category_id: int) -> str:  # noqa: ARG001 - used via request
 | 
			
		||||
        # Return a URL for a different page while preserving args.
 | 
			
		||||
        return url_for_other_page(5)
 | 
			
		||||
 | 
			
		||||
    return app
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_pagination_basic_properties() -> None:
 | 
			
		||||
    """Compute total pages and prev/next boundaries."""
 | 
			
		||||
    p = Pagination(page=1, per_page=10, total_count=95)
 | 
			
		||||
    assert p.pages == 10
 | 
			
		||||
    assert p.has_prev is False
 | 
			
		||||
    assert p.has_next is True
 | 
			
		||||
 | 
			
		||||
    p2 = Pagination(page=10, per_page=10, total_count=95)
 | 
			
		||||
    assert p2.pages == 10
 | 
			
		||||
    assert p2.has_prev is True
 | 
			
		||||
    assert p2.has_next is False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_pagination_slice() -> None:
 | 
			
		||||
    """Return the correct slice for a page window."""
 | 
			
		||||
    items = list(range(25))
 | 
			
		||||
    p = Pagination(page=2, per_page=10, total_count=len(items))
 | 
			
		||||
    assert p.slice(items) == list(range(10, 20))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_iter_pages_first_middle_last() -> None:
 | 
			
		||||
    """Iterate pages with ellipses represented by ``None`` when skipping."""
 | 
			
		||||
    p = Pagination(page=1, per_page=10, total_count=100)
 | 
			
		||||
    pages = list(p.iter_pages())
 | 
			
		||||
    # First page shows early pages, ellipsis, then tail pages
 | 
			
		||||
    assert pages == [1, 2, 3, 4, 5, 6, None, 9, 10]
 | 
			
		||||
 | 
			
		||||
    mid = Pagination(page=5, per_page=10, total_count=100)
 | 
			
		||||
    # In the middle, defaults show all pages without gaps
 | 
			
		||||
    assert list(mid.iter_pages()) == list(range(1, 11))
 | 
			
		||||
 | 
			
		||||
    last = Pagination(page=10, per_page=10, total_count=100)
 | 
			
		||||
    # Near the end, elide the early middle (3), keep a window around current
 | 
			
		||||
    assert list(last.iter_pages()) == [1, 2, None, 4, 5, 6, 7, 8, 9, 10]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_url_for_other_page_preserves_args_and_view_args() -> None:
 | 
			
		||||
    """Build a URL for another page preserving args."""
 | 
			
		||||
    app = _make_app()
 | 
			
		||||
    with app.test_client() as client:
 | 
			
		||||
        resp = client.get("/items/42?q=abc&page=3")
 | 
			
		||||
        assert resp.status_code == 200
 | 
			
		||||
        # The route returns the URL generated for page=5
 | 
			
		||||
        assert resp.get_data(as_text=True) == "/items/42?q=abc&page=5"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_init_pager_registers_jinja_helper() -> None:
 | 
			
		||||
    """Register the helper in the Jinja environment globals."""
 | 
			
		||||
    app = Flask(__name__)
 | 
			
		||||
    init_pager(app)
 | 
			
		||||
    assert app.jinja_env.globals["url_for_other_page"] is url_for_other_page
 | 
			
		||||
| 
						 | 
				
			
			@ -1,109 +0,0 @@
 | 
			
		|||
"""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"
 | 
			
		||||
		Loading…
	
		Reference in a new issue