1
etude_lego_jurassic_world/tests/test_minifig_characters.py

393 lines
13 KiB
Python

"""Tests de l'agrégation des minifigs par personnage."""
from pathlib import Path
from lib.rebrickable.minifig_characters import (
aggregate_by_character,
aggregate_by_gender,
aggregate_new_character_sets,
aggregate_new_characters_by_year,
aggregate_variations_and_totals,
aggregate_character_spans,
aggregate_presence_by_year,
load_sets_enriched,
write_character_counts,
write_new_character_sets_csv,
write_new_character_sets_markdown,
write_new_characters_by_year,
write_character_variations_totals,
write_gender_counts,
)
from lib.rebrickable.minifig_character_sets import load_sets
def test_aggregate_by_character_counts_unique_figs() -> None:
"""Compter les minifigs distinctes par personnage en excluant les noms vides."""
aggregates = aggregate_by_character(
[
{
"set_num": "123-1",
"part_num": "head-a",
"known_character": "Owen Grady",
"fig_num": "fig-owen-1",
"gender": "male",
},
{
"set_num": "124-1",
"part_num": "head-b",
"known_character": "Owen Grady",
"fig_num": "fig-owen-1",
"gender": "male",
},
{
"set_num": "125-1",
"part_num": "head-c",
"known_character": "Owen Grady",
"fig_num": "fig-owen-2",
"gender": "male",
},
{
"set_num": "126-1",
"part_num": "head-d",
"known_character": "Figurant",
"fig_num": "fig-guard-1",
"gender": "unknown",
},
{
"set_num": "128-1",
"part_num": "head-f",
"known_character": "Figurant",
"fig_num": "fig-guard-1",
"gender": "unknown",
},
{
"set_num": "129-1",
"part_num": "head-g",
"known_character": "",
"fig_num": "fig-guard-2",
"gender": "unknown",
},
]
)
assert aggregates == [
{"known_character": "Owen Grady", "gender": "male", "minifig_count": 2},
{"known_character": "Figurant", "gender": "unknown", "minifig_count": 1},
]
def test_aggregate_variations_and_totals_excludes_figurants() -> None:
"""Compter le total et les variations en excluant les figurants."""
aggregates = aggregate_variations_and_totals(
[
{
"set_num": "123-1",
"part_num": "head-a",
"known_character": "Owen Grady",
"fig_num": "fig-owen-1",
"gender": "male",
},
{
"set_num": "124-1",
"part_num": "head-b",
"known_character": "Owen Grady",
"fig_num": "fig-owen-1",
"gender": "male",
},
{
"set_num": "125-1",
"part_num": "head-c",
"known_character": "Owen Grady",
"fig_num": "fig-owen-2",
"gender": "male",
},
{
"set_num": "126-1",
"part_num": "head-d",
"known_character": "Ellie Sattler",
"fig_num": "fig-ellie-1",
"gender": "female",
},
{
"set_num": "127-1",
"part_num": "head-e",
"known_character": "Figurant",
"fig_num": "fig-guard-1",
"gender": "unknown",
},
],
excluded_characters=["Figurant"],
)
assert aggregates == [
{"known_character": "Owen Grady", "gender": "male", "variation_count": 2, "total_minifigs": 3},
{"known_character": "Ellie Sattler", "gender": "female", "variation_count": 1, "total_minifigs": 1},
]
def test_aggregate_by_gender_counts_unique_figs() -> None:
"""Compter les minifigs distinctes par genre."""
aggregates = aggregate_by_gender(
[
{"fig_num": "fig-a", "gender": "male"},
{"fig_num": "fig-a", "gender": "male"},
{"fig_num": "fig-b", "gender": "female"},
{"fig_num": "fig-c", "gender": ""},
]
)
assert aggregates == [
{"gender": "female", "minifig_count": "1"},
{"gender": "male", "minifig_count": "1"},
{"gender": "unknown", "minifig_count": "1"},
]
def test_aggregate_new_characters_by_year_limits_range(tmp_path: Path) -> None:
"""Compter les nouveaux personnages par année en respectant la plage."""
sets_path = tmp_path / "sets_enriched.csv"
sets_path.write_text(
"set_num,name,year,theme_id,num_parts,img_url,set_id,rebrickable_url,in_collection\n"
"123-1,Set A,2015,0,0,,-,http://r/123-1,true\n"
"124-1,Set B,2016,0,0,,-,http://r/124-1,true\n"
"125-1,Set C,2017,0,0,,-,http://r/125-1,true\n"
"126-1,Set D,2014,0,0,,-,http://r/126-1,true\n"
)
sets_years = load_sets_enriched(sets_path)
minifigs_rows = [
{"set_num": "123-1", "known_character": "Owen Grady", "fig_num": "fig-owen-1", "part_num": "head-a"},
{"set_num": "124-1", "known_character": "Owen Grady", "fig_num": "fig-owen-2", "part_num": "head-b"},
{"set_num": "125-1", "known_character": "Ellie Sattler", "fig_num": "fig-ellie-1", "part_num": "head-c"},
{"set_num": "126-1", "known_character": "Alan Grant", "fig_num": "fig-grant-1", "part_num": "head-d"},
]
counts = aggregate_new_characters_by_year(
minifigs_rows,
sets_years,
excluded_characters=["Figurant"],
start_year=2015,
end_year=2017,
)
assert counts == [
{"year": "2015", "new_characters": "1"},
{"year": "2016", "new_characters": "0"},
{"year": "2017", "new_characters": "1"},
]
def test_aggregate_new_character_sets_returns_intro_sets(tmp_path: Path) -> None:
"""Lister les personnages introduits avec les sets de l'année d'introduction."""
sets_path = tmp_path / "sets_enriched.csv"
sets_path.write_text(
"set_num,name,year,theme_id,num_parts,img_url,set_id,rebrickable_url,in_collection\n"
"123-1,Set A,2015,0,0,,123,http://r/123-1,true\n"
"124-1,Set B,2015,0,0,,124,http://r/124-1,true\n"
"125-1,Set C,2016,0,0,,125,http://r/125-1,true\n"
)
sets_lookup = load_sets(sets_path)
minifigs_rows = [
{"set_num": "123-1", "known_character": "Owen Grady", "fig_num": "fig-owen-1", "part_num": "head-a"},
{"set_num": "124-1", "known_character": "Owen Grady", "fig_num": "fig-owen-2", "part_num": "head-b"},
{"set_num": "125-1", "known_character": "Owen Grady", "fig_num": "fig-owen-3", "part_num": "head-c"},
{"set_num": "125-1", "known_character": "Ellie Sattler", "fig_num": "fig-ellie-1", "part_num": "head-d"},
]
rows = aggregate_new_character_sets(
minifigs_rows,
sets_lookup,
excluded_characters=["Figurant"],
start_year=2015,
end_year=2016,
)
assert rows == [
{
"year": "2015",
"known_character": "Owen Grady",
"set_num": "123-1",
"set_id": "123",
"set_name": "Set A",
"rebrickable_url": "http://r/123-1",
},
{
"year": "2015",
"known_character": "Owen Grady",
"set_num": "124-1",
"set_id": "124",
"set_name": "Set B",
"rebrickable_url": "http://r/124-1",
},
{
"year": "2016",
"known_character": "Ellie Sattler",
"set_num": "125-1",
"set_id": "125",
"set_name": "Set C",
"rebrickable_url": "http://r/125-1",
},
]
def test_write_character_counts_outputs_csv(tmp_path: Path) -> None:
"""Écrit le CSV des comptes par personnage."""
destination = tmp_path / "counts.csv"
rows = [
{"known_character": "A", "gender": "male", "minifig_count": 2},
{"known_character": "B", "gender": "female", "minifig_count": 1},
]
write_character_counts(destination, rows)
assert destination.read_text() == "known_character,gender,minifig_count\nA,male,2\nB,female,1\n"
def test_write_gender_counts_outputs_csv(tmp_path: Path) -> None:
"""Écrit le CSV des comptes par genre."""
destination = tmp_path / "gender_counts.csv"
rows = [
{"gender": "male", "minifig_count": "2"},
{"gender": "female", "minifig_count": "1"},
]
write_gender_counts(destination, rows)
assert destination.read_text() == "gender,minifig_count\nmale,2\nfemale,1\n"
def test_write_character_variations_totals_outputs_csv(tmp_path: Path) -> None:
"""Écrit le CSV comparatif variations/total."""
destination = tmp_path / "variations.csv"
rows = [
{"known_character": "A", "gender": "male", "variation_count": 2, "total_minifigs": 3},
{"known_character": "B", "gender": "female", "variation_count": 1, "total_minifigs": 1},
]
write_character_variations_totals(destination, rows)
assert destination.read_text() == "known_character,gender,variation_count,total_minifigs\nA,male,2,3\nB,female,1,1\n"
def test_write_new_characters_by_year_outputs_csv(tmp_path: Path) -> None:
"""Écrit le CSV des nouveaux personnages par année."""
destination = tmp_path / "new_characters.csv"
rows = [
{"year": "2015", "new_characters": "3"},
{"year": "2016", "new_characters": "1"},
]
write_new_characters_by_year(destination, rows)
assert destination.read_text() == "year,new_characters\n2015,3\n2016,1\n"
def test_write_new_character_sets_markdown_outputs_md(tmp_path: Path) -> None:
"""Écrit le Markdown listant les nouveaux personnages et leurs sets."""
destination = tmp_path / "new_characters.md"
rows = [
{
"year": "2015",
"known_character": "Owen Grady",
"set_num": "123-1",
"set_id": "123",
"set_name": "Set A",
"rebrickable_url": "http://r/123-1",
},
{
"year": "2016",
"known_character": "Ellie Sattler",
"set_num": "125-1",
"set_id": "125",
"set_name": "Set C",
"rebrickable_url": "http://r/125-1",
},
]
write_new_character_sets_markdown(destination, rows)
assert destination.read_text() == (
"##### 2015\n\n"
"- Owen Grady\n"
" - [123](http://r/123-1) - Set A\n"
"\n"
"##### 2016\n\n"
"- Ellie Sattler\n"
" - [125](http://r/125-1) - Set C\n"
"\n"
)
def test_aggregate_presence_by_year_excludes_figurants(tmp_path: Path) -> None:
"""Calcule le total annuel en excluant les figurants."""
sets_path = tmp_path / "sets_enriched.csv"
sets_path.write_text(
"set_num,year\n"
"123-1,2020\n"
"124-1,2021\n"
)
minifigs_rows = [
{
"set_num": "123-1",
"known_character": "Owen Grady",
"fig_num": "fig-owen",
"part_num": "head-a",
"gender": "male",
},
{
"set_num": "124-1",
"known_character": "Figurant",
"fig_num": "fig-guard",
"part_num": "head-b",
"gender": "unknown",
},
]
sets_years = load_sets_enriched(sets_path)
presence = aggregate_presence_by_year(minifigs_rows, sets_years, excluded_characters=["Figurant"])
assert presence == [
{"known_character": "Owen Grady", "year": "2020", "minifig_count": "1"},
{"known_character": "Owen Grady", "year": "2021", "minifig_count": "0"},
]
def test_aggregate_character_spans_excludes_figurants(tmp_path: Path) -> None:
"""Calcule les bornes min/max par personnage."""
sets_path = tmp_path / "sets_enriched.csv"
sets_path.write_text(
"set_num,year\n"
"123-1,2020\n"
"124-1,2021\n"
"125-1,2022\n"
)
sets_years = load_sets_enriched(sets_path)
minifigs_rows = [
{
"set_num": "123-1",
"known_character": "Owen Grady",
"fig_num": "fig-owen",
"part_num": "head-a",
"gender": "male",
},
{
"set_num": "124-1",
"known_character": "Owen Grady",
"fig_num": "fig-owen",
"part_num": "head-a",
"gender": "male",
},
{
"set_num": "125-1",
"known_character": "Figurant",
"fig_num": "fig-guard",
"part_num": "head-b",
"gender": "unknown",
},
]
spans = aggregate_character_spans(minifigs_rows, sets_years, excluded_characters=["Figurant"])
assert spans == [
{"known_character": "Owen Grady", "start_year": "2020", "end_year": "2021", "total_minifigs": "2", "gender": "male"},
]