|
| 1 | +import random |
| 2 | +from fractions import Fraction |
1 | 3 | from itertools import permutations |
2 | 4 | from pathlib import Path |
3 | 5 | from typing import Literal, cast |
@@ -359,6 +361,33 @@ def test_mentions_from_df_duplicate_ballot_index(): |
359 | 361 | assert _mentions_from_ballots(profile) == correct |
360 | 362 |
|
361 | 363 |
|
| 364 | +def _random_mentions_profile(rng: random.Random) -> RankProfile: |
| 365 | + # samples every dimension that has produced a path divergence: ties, duplicate candidates, |
| 366 | + # short ballots, zero and Fraction weights, mixed str/int candidates |
| 367 | + cands = ["A", "B", 1, 2, "C"][: rng.randint(2, 5)] |
| 368 | + ballots = [] |
| 369 | + for _ in range(rng.randint(1, 8)): |
| 370 | + pool = [rng.choice(cands) for _ in range(rng.randint(1, len(cands)))] |
| 371 | + ranking = [] |
| 372 | + while pool: |
| 373 | + n = rng.randint(1, min(2, len(pool))) |
| 374 | + ranking.append(frozenset(pool[:n])) |
| 375 | + pool = pool[n:] |
| 376 | + weight = rng.choice([0, 1, 3, 1 / 2, Fraction(1, 3)]) |
| 377 | + ballots.append(RankBallot(ranking=tuple(ranking), weight=weight)) |
| 378 | + # sometimes omit the explicit candidate list so profile.candidates can exclude candidates |
| 379 | + # that appear only on zero-weight ballots |
| 380 | + if rng.random() < 0.5: |
| 381 | + return RankProfile(ballots=tuple(ballots), max_ranking_length=len(cands)) |
| 382 | + return RankProfile(ballots=tuple(ballots), candidates=cands, max_ranking_length=len(cands)) |
| 383 | + |
| 384 | + |
| 385 | +@pytest.mark.parametrize("seed", range(25)) |
| 386 | +def test_mentions_paths_stay_in_sync(seed): |
| 387 | + profile = _random_mentions_profile(random.Random(seed)) |
| 388 | + assert _mentions_from_ballots(profile) == _mentions_from_df(profile) |
| 389 | + |
| 390 | + |
362 | 391 | def test_mentions_errors(): |
363 | 392 | with pytest.raises(TypeError, match="Profile must be of type RankProfile"): |
364 | 393 | mentions(cast(RankProfile, ScoreProfile(ballots=(ScoreBallot(scores={"A": 3}),)))) |
|
0 commit comments