"""Tests du calcul de rareté des pièces.""" import csv from pathlib import Path from lib.rebrickable.part_rarity import build_part_rarity, select_until_reused, write_part_rarity def write_csv(path: Path, headers: list[str], rows: list[list[str]]) -> None: """Écrit un CSV utilitaire pour les cas de test.""" with path.open("w", newline="") as csv_file: writer = csv.writer(csv_file) writer.writerow(headers) writer.writerows(rows) def test_build_part_rarity_counts_spares_and_ignores_categories(tmp_path: Path) -> None: """Comptabilise les pièces (rechanges incluses) et ignore les catégories animales.""" parts_filtered = tmp_path / "parts_filtered.csv" write_csv( parts_filtered, [ "part_num", "color_rgb", "is_translucent", "set_num", "set_id", "year", "quantity_in_set", "is_spare", "is_minifig_part", ], [ ["p1", "AAAAAA", "false", "1000-1", "1000", "2020", "2", "false", "false"], ["p1", "AAAAAA", "false", "2000-1", "2000", "2021", "1", "true", "false"], ["p2", "BBBBBB", "false", "1000-1", "1000", "2020", "5", "false", "false"], ["p4", "CCCCCC", "false", "2000-1", "2000", "2021", "2", "false", "false"], ["p6", "DDDDDD", "false", "2000-1", "2000", "2021", "1", "false", "false"], ], ) sets_enriched = tmp_path / "sets_enriched.csv" write_csv( sets_enriched, ["set_num", "name", "year", "theme_id", "num_parts", "img_url", "set_id", "rebrickable_url", "in_collection"], [ ["1000-1", "Set A", "2020", "1", "10", "http://example.com", "1000", "http://example.com", "false"], ["2000-1", "Set B", "2021", "1", "10", "http://example.com", "2000", "http://example.com", "false"], ], ) parts_catalog = tmp_path / "parts.csv" write_csv( parts_catalog, ["part_num", "name", "part_cat_id", "part_material"], [ ["p1", "Brick 1x1", "1", "Plastic"], ["p2", "Baby Dino", "28", "Plastic"], ["p3", "Raptor Body", "75", "Plastic"], ["p4", "Figure Limb", "41", "Plastic"], ["p5", "Sticker Sheet", "58", "Plastic"], ["p6", "Exclusive Tile", "1", "Plastic"], ["p7", "Slope 45 print", "1", "Plastic"], ], ) part_categories = tmp_path / "part_categories.csv" write_csv( part_categories, ["id", "name"], [ ["1", "Bricks"], ["28", "Animals / Creatures"], ["41", "Large Buildable Figures"], ["75", "Animal / Creature Body Parts"], ["58", "Stickers"], ], ) inventories = tmp_path / "inventories.csv" write_csv( inventories, ["id", "version", "set_num"], [ ["1", "1", "3000-1"], ["2", "2", "3000-1"], ["3", "1", "4000-1"], ["4", "1", "1000-1"], ["5", "1", "5000-1"], ], ) inventory_parts = tmp_path / "inventory_parts.csv" write_csv( inventory_parts, ["inventory_id", "part_num", "color_id", "quantity", "is_spare", "img_url"], [ ["1", "p1", "1", "1", "False", ""], ["2", "p1", "1", "3", "False", ""], ["2", "p2", "1", "2", "False", ""], ["3", "p4", "1", "4", "True", ""], ["4", "p1", "1", "8", "False", ""], ["5", "p5", "1", "9", "False", ""], ["5", "p7", "1", "5", "False", ""], ], ) rows = build_part_rarity( parts_filtered, inventories, inventory_parts, parts_catalog, part_categories, sets_enriched, ) assert rows == [ { "part_num": "p6", "part_name": "Exclusive Tile", "part_cat_id": "1", "part_category": "Bricks", "sample_set_num": "2000-1", "sample_set_id": "2000", "sample_set_year": "2021", "filtered_quantity": "1", "filtered_set_count": "1", "other_sets_quantity": "0", "catalog_total_quantity": "1", "filtered_share": "1.0000", }, { "part_num": "p1", "part_name": "Brick 1x1", "part_cat_id": "1", "part_category": "Bricks", "sample_set_num": "1000-1", "sample_set_id": "1000", "sample_set_year": "2020", "filtered_quantity": "3", "filtered_set_count": "2", "other_sets_quantity": "3", "catalog_total_quantity": "6", "filtered_share": "0.5000", }, { "part_num": "p4", "part_name": "Figure Limb", "part_cat_id": "41", "part_category": "Large Buildable Figures", "sample_set_num": "2000-1", "sample_set_id": "2000", "sample_set_year": "2021", "filtered_quantity": "2", "filtered_set_count": "1", "other_sets_quantity": "4", "catalog_total_quantity": "6", "filtered_share": "0.3333", }, ] assert select_until_reused(rows) == [rows[0], rows[1]] rows_no_print = build_part_rarity( parts_filtered, inventories, inventory_parts, parts_catalog, part_categories, sets_enriched, exclude_printed=True, ) assert all(r["part_num"] != "p7" for r in rows_no_print) def test_write_part_rarity_outputs_csv(tmp_path: Path) -> None: """Sérialise le classement de rareté.""" destination = tmp_path / "part_rarity.csv" rows = [ { "part_num": "p1", "part_name": "Brick 1x1", "part_cat_id": "1", "part_category": "Bricks", "sample_set_num": "123-1", "sample_set_id": "123", "sample_set_year": "2020", "filtered_quantity": "3", "filtered_set_count": "2", "other_sets_quantity": "3", "catalog_total_quantity": "6", "filtered_share": "0.5000", } ] write_part_rarity(destination, rows) assert destination.exists() content = destination.read_text().strip().splitlines() assert content[0] == ( "part_num,part_name,part_cat_id,part_category,sample_set_num,sample_set_id,sample_set_year,filtered_quantity,filtered_set_count," "other_sets_quantity,catalog_total_quantity,filtered_share" ) assert content[1] == "p1,Brick 1x1,1,Bricks,123-1,123,2020,3,2,3,6,0.5000"