You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
motief/tests/test_svd_labels.py

179 lines
6.7 KiB

"""Tests for analysis/svd_labels module."""
def test_canonical_party_sets_contain_expected_parties():
"""Verify CANONICAL_RIGHT and CANONICAL_LEFT contain the expected parties."""
from analysis.config import CANONICAL_LEFT, CANONICAL_RIGHT
assert "PVV" in CANONICAL_RIGHT
assert "FVD" in CANONICAL_RIGHT
assert "JA21" in CANONICAL_RIGHT
assert "SGP" in CANONICAL_RIGHT
assert "SP" in CANONICAL_LEFT
assert "PvdA" in CANONICAL_LEFT
assert "PvdD" in CANONICAL_LEFT
assert "DENK" in CANONICAL_LEFT
assert "Volt" in CANONICAL_LEFT
def test_compute_flip_direction_uses_all_canonical_right_parties():
"""Test that flip computation correctly uses all four canonical right parties."""
from analysis.config import CANONICAL_LEFT, CANONICAL_RIGHT
from analysis.svd_labels import compute_flip_direction
# Build party scores where ALL canonical right parties are on the left (negative)
# and ALL canonical left parties are on the right (positive)
party_scores = {}
for party in CANONICAL_RIGHT:
party_scores[party] = [-0.5]
for party in CANONICAL_LEFT:
party_scores[party] = [0.5]
# All right parties on left → should flip
assert compute_flip_direction(1, party_scores) is True
# Invert: all right parties on right (positive), left parties on left (negative)
party_scores_inverted = {}
for party in CANONICAL_RIGHT:
party_scores_inverted[party] = [0.5]
for party in CANONICAL_LEFT:
party_scores_inverted[party] = [-0.5]
# All right parties on right → should not flip
assert compute_flip_direction(1, party_scores_inverted) is False
def test_compute_flip_direction_all_components_canonical_parties():
"""Test flip for all 10 components using full canonical party sets."""
from analysis.config import CANONICAL_LEFT, CANONICAL_RIGHT
from analysis.svd_labels import compute_flip_direction
# Right parties on left (negative), left parties on right (positive)
party_scores = {}
for party in CANONICAL_RIGHT:
party_scores[party] = [-0.7] * 10
for party in CANONICAL_LEFT:
party_scores[party] = [0.3] * 10
for comp in range(1, 11):
flip = compute_flip_direction(comp, party_scores)
assert flip is True, f"Component {comp} should flip (right parties on left)"
# Inverted: right on right, left on left
party_scores_inverted = {}
for party in CANONICAL_RIGHT:
party_scores_inverted[party] = [0.7] * 10
for party in CANONICAL_LEFT:
party_scores_inverted[party] = [-0.3] * 10
for comp in range(1, 11):
flip = compute_flip_direction(comp, party_scores_inverted)
assert flip is False, (
f"Component {comp} should not flip (right parties on right)"
)
def test_get_svd_label_returns_correct_label():
"""Test that get_svd_label returns the correct label for each component."""
from analysis.svd_labels import get_svd_label
# Component 1 should return Rechts versus links label
label1 = get_svd_label(1)
assert "Rechts versus links" in label1 or "links" in label1.lower()
# Component 2 should return Nationalistisch versus kosmopolitisch label
label2 = get_svd_label(2)
assert "Nationalistisch" in label2 or "kosmopolitisch" in label2
# Component 3 should return Verzorgingsstaat label
label3 = get_svd_label(3)
assert "Verzorgingsstaat" in label3 or "Marktwerking" in label3
def test_compute_flip_direction_right_on_left():
"""Test that flip is True when right parties are on the left."""
from analysis.svd_labels import compute_flip_direction
# Right parties (PVV, FVD) have negative scores (on left), left parties have positive
party_scores = {
"PVV": [-0.8, 0.0], # Right party
"FVD": [-0.6, 0.0], # Right party
"SP": [0.6, 0.0], # Left party
"DENK": [0.4, 0.0], # Left party
}
# Component 1: right_mean = -0.7, left_mean = 0.5
# right_mean < left_mean, so flip = True
assert compute_flip_direction(1, party_scores) is True
def test_compute_flip_direction_right_on_right():
"""Test that flip is False when right parties are already on the right."""
from analysis.svd_labels import compute_flip_direction
# Right parties (PVV, FVD) have positive scores (on right), left parties have negative
party_scores = {
"PVV": [0.8, 0.0], # Right party
"FVD": [0.6, 0.0], # Right party
"SP": [-0.6, 0.0], # Left party
"DENK": [-0.4, 0.0], # Left party
}
# Component 1: right_mean = 0.7, left_mean = -0.5
# right_mean > left_mean, so flip = False
assert compute_flip_direction(1, party_scores) is False
def test_compute_flip_direction_insufficient_data():
"""Test that flip is False when there's insufficient data."""
from analysis.svd_labels import compute_flip_direction
# No right parties in data
party_scores = {
"SP": [0.6, 0.0],
"DENK": [0.4, 0.0],
}
assert compute_flip_direction(1, party_scores) is False
# No left parties in data
party_scores = {
"VVD": [0.5, 0.0],
"PVV": [0.8, 0.0],
}
assert compute_flip_direction(1, party_scores) is False
def test_auto_flip_computation_for_all_components():
"""Test that flip directions are computed correctly for all components."""
from analysis.svd_labels import compute_flip_direction
# Simulate party scores for 10 components using CANONICAL_RIGHT/LEFT
# Right parties should have positive scores on component 1
# Left parties should have negative scores on component 1
party_scores = {
"PVV": [0.8] * 10, # Right party (CANONICAL_RIGHT), positive on all
"FVD": [0.6] * 10, # Right party (CANONICAL_RIGHT), positive on all
"SP": [-0.6] * 10, # Left party (CANONICAL_LEFT), negative on all
"DENK": [-0.4] * 10, # Left party (CANONICAL_LEFT), negative on all
}
# For all components, right_mean > left_mean, so flip should be False
for comp in range(1, 11):
flip = compute_flip_direction(comp, party_scores)
assert flip is False, f"Component {comp} should not flip"
# Now test with right parties on left (negative scores)
party_scores_left = {
"PVV": [-0.8] * 10, # Right party (CANONICAL_RIGHT), negative
"FVD": [-0.6] * 10, # Right party (CANONICAL_RIGHT), negative
"SP": [0.6] * 10, # Left party (CANONICAL_LEFT), positive
"DENK": [0.4] * 10, # Left party (CANONICAL_LEFT), positive
}
# For all components, right_mean < left_mean, so flip should be True
for comp in range(1, 11):
flip = compute_flip_direction(comp, party_scores_left)
assert flip is True, f"Component {comp} should flip"