test_normalize_path.py

scripts/analytics/tests/test_normalize_path.py(110 行)

test_normalize_path.py
"""common.normalize_path() のサイト別名寄せ規則の回帰テスト。

対象: strip_html_suffix / strip_index_html / strip_path_prefix と、
規則なしのドメイン・domain=None の挙動。

DB にも設定ファイルにも触れない。テスト用の設定 dict を register_path_aliases() に
渡して規則を登録し、normalize_path() の入出力だけを検証する。

実行(プロジェクトのルートで): python -X utf8 scripts/analytics/tests/test_normalize_path.py
失敗があれば exit 1。
"""

from __future__ import annotations

import os
import sys

# common.py は1つ上のフォルダにあるので import パスに追加する。
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import common  # noqa: E402


# テスト用のサイト設定(実在しない例示用ドメイン)
TEST_CONFIG = {
    "sites": [
        # .html を落とし、/articles 配下のプレフィックスも剥がすサイト
        {"site": "suffix_prefix", "domain": "example.com",
         "strip_html_suffix": True, "strip_path_prefix": "/articles"},
        # ディレクトリ index だけを丸めるサイト(.html 一般は正規URL)
        {"site": "index_only", "domain": "example.org",
         "strip_index_html": True},
        # .html を落とすだけのサイト
        {"site": "suffix_only", "domain": "example.net",
         "strip_html_suffix": True},
        # 名寄せ規則なしのサイト
        {"site": "no_rule", "domain": "example.edu"},
    ]
}


# (domain, 入力, 期待出力) のリスト。
CASES: list[tuple[str | None, str, str]] = [
    # --- example.com: strip_html_suffix + strip_path_prefix ---
    ("example.com", "/tool.html", "/tool"),
    ("example.com", "/tool/", "/tool"),
    ("example.com", "/articles/sample-post.html", "/sample-post"),
    ("example.com", "/index.html", "/"),
    ("example.com", "/privacy.html", "/privacy"),
    ("example.com", "/articles", "/articles"),
    ("example.com", "https://example.com/articles/about.html", "/about"),

    # --- example.org: strip_index_html のみ(.html 一般は変えない) ---
    ("example.org", "/guide/index.html", "/guide"),
    ("example.org", "/guide/", "/guide"),
    ("example.org", "/index.html", "/"),
    ("example.org", "/docs/intro/index.html", "/docs/intro"),
    ("example.org", "/list.html", "/list.html"),
    ("example.org", "/guide/first-steps.html", "/guide/first-steps.html"),

    # --- example.net: strip_html_suffix ---
    ("example.net", "/howto.html", "/howto"),
    ("example.net", "/index.html", "/"),
    ("example.net", "/policy.html", "/policy"),
    ("example.net", "/howto", "/howto"),

    # --- example.edu: 規則なし(共通の正規化だけ) ---
    ("example.edu", "/articles/sample-post", "/articles/sample-post"),
    ("example.edu", "/articles/foo.html", "/articles/foo.html"),
    ("example.edu", "/index.html", "/index.html"),

    # --- domain=None: 登録なし ---
    (None, "/foo.html", "/foo.html"),

    # --- 共通の正規化(ドメイン・クエリ・フラグメント・末尾スラッシュ) ---
    (None, "https://example.edu/blog/post/?utm_source=x#top", "/blog/post"),
    (None, "/blog/post?page=2", "/blog/post"),
    (None, "/", "/"),
    (None, "", "/"),
]


def main() -> int:
    common.register_path_aliases(TEST_CONFIG)

    failures: list[str] = []
    for domain, input_path, expected in CASES:
        actual = common.normalize_path(input_path, domain=domain)
        status = "OK" if actual == expected else "NG"
        if actual != expected:
            failures.append(
                f"[NG] domain={domain!r} input={input_path!r} "
                f"expected={expected!r} actual={actual!r}"
            )
        print(f"[{status}] domain={domain!r} input={input_path!r} -> {actual!r}")

    total = len(CASES)
    failed = len(failures)
    print(f"\n合計 {total} 件 / 失敗 {failed} 件")

    if failures:
        print("\n--- 失敗内訳 ---")
        for line in failures:
            print(line)
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())

MIT ライセンスで配布しています。