test_variants.py•13.5 kB
"""
Tests for variant system.
"""
from chuk_mcp_linkedin import ThemeManager
from chuk_mcp_linkedin.variants import PostVariants, VariantConfig, VariantResolver
class TestVariantConfig:
"""Test VariantConfig dataclass"""
def test_variant_config_creation(self):
"""Test creating a variant config"""
config = VariantConfig(
name="story", properties={"structure": "story_arc"}, description="Narrative-driven post"
)
assert config.name == "story"
assert config.properties["structure"] == "story_arc"
assert config.description == "Narrative-driven post"
class TestPostVariants:
"""Test PostVariants class"""
def test_text_post_variants(self):
"""Test text post variants structure"""
variants = PostVariants.text_post_variants()
assert "base" in variants
assert "variants" in variants
assert "compound_variants" in variants
assert "default_variant" in variants
def test_text_post_has_style_variants(self):
"""Test text post has style variants"""
variants = PostVariants.text_post_variants()
assert "style" in variants["variants"]
styles = variants["variants"]["style"]
assert "story" in styles
assert "insight" in styles
assert "question" in styles
assert "listicle" in styles
assert "hot_take" in styles
def test_text_post_has_tone_variants(self):
"""Test text post has tone variants"""
variants = PostVariants.text_post_variants()
assert "tone" in variants["variants"]
tones = variants["variants"]["tone"]
assert "professional" in tones
assert "conversational" in tones
assert "casual" in tones
assert "inspiring" in tones
assert "humorous" in tones
def test_text_post_has_length_variants(self):
"""Test text post has length variants"""
variants = PostVariants.text_post_variants()
assert "length" in variants["variants"]
lengths = variants["variants"]["length"]
assert "micro" in lengths
assert "short" in lengths
assert "medium" in lengths
assert "long" in lengths
assert "story" in lengths
def test_text_post_compound_variants(self):
"""Test text post has compound variants"""
variants = PostVariants.text_post_variants()
compounds = variants["compound_variants"]
assert len(compounds) > 0
# Check structure of compound variants
for compound in compounds:
assert "conditions" in compound
assert "applies" in compound
def test_poll_post_variants(self):
"""Test poll post variants structure"""
variants = PostVariants.poll_post_variants()
assert "base" in variants
assert "variants" in variants
assert "default_variant" in variants
def test_poll_post_has_purpose_variants(self):
"""Test poll post has purpose variants"""
variants = PostVariants.poll_post_variants()
assert "purpose" in variants["variants"]
purposes = variants["variants"]["purpose"]
assert "engagement" in purposes
assert "research" in purposes
assert "decision" in purposes
assert "fun" in purposes
def test_poll_post_has_question_type_variants(self):
"""Test poll post has question type variants"""
variants = PostVariants.poll_post_variants()
assert "question_type" in variants["variants"]
types = variants["variants"]["question_type"]
assert "binary" in types
assert "multiple_choice" in types
def test_document_post_variants(self):
"""Test document post variants structure"""
variants = PostVariants.document_post_variants()
assert "base" in variants
assert "variants" in variants
assert "default_variant" in variants
def test_document_post_has_content_type_variants(self):
"""Test document post has content type variants"""
variants = PostVariants.document_post_variants()
assert "content_type" in variants["variants"]
types = variants["variants"]["content_type"]
assert "guide" in types
assert "checklist" in types
assert "stats" in types
assert "report" in types
def test_document_post_has_design_style_variants(self):
"""Test document post has design style variants"""
variants = PostVariants.document_post_variants()
assert "design_style" in variants["variants"]
styles = variants["variants"]["design_style"]
assert "minimal" in styles
assert "professional" in styles
assert "vibrant" in styles
class TestVariantResolver:
"""Test VariantResolver class"""
def test_resolve_basic_variant(self):
"""Test resolving basic variant selection"""
base_variants = PostVariants.text_post_variants()
selected = {"style": "story", "tone": "conversational", "length": "long"}
config = VariantResolver.resolve(base_variants, selected)
assert config["type"] == "text"
assert config["structure"] == "story_arc"
def test_resolve_applies_multiple_variants(self):
"""Test resolving applies settings from multiple variants"""
base_variants = PostVariants.text_post_variants()
selected = {"style": "insight", "tone": "professional", "length": "medium"}
config = VariantResolver.resolve(base_variants, selected)
# Should have properties from all selected variants
assert "structure" in config # From style
assert "formality" in config # From tone
assert "ideal_length" in config # From length
def test_resolve_applies_compound_variants(self):
"""Test resolving applies compound variants"""
base_variants = PostVariants.text_post_variants()
# Select combination that triggers compound variant
selected = {"style": "story", "tone": "inspiring"}
config = VariantResolver.resolve(base_variants, selected)
# Compound should have applied additional properties
assert config["vulnerability_level"] == "raw"
assert config["line_break_style"] == "extreme"
def test_resolve_with_theme_override(self):
"""Test resolving with theme overrides"""
theme_manager = ThemeManager()
theme = theme_manager.get_theme("technical_expert")
base_variants = PostVariants.text_post_variants()
selected = {"style": "insight"}
config = VariantResolver.resolve(base_variants, selected, theme)
# Theme should override emoji_level
assert config["emoji_level"] == "none"
def test_resolve_theme_does_not_override_explicit_selections(self):
"""Test theme doesn't override explicitly selected variants"""
theme_manager = ThemeManager()
theme = theme_manager.get_theme("entertainer") # Has expressive emoji
base_variants = PostVariants.text_post_variants()
# Explicitly select professional tone (no emojis)
selected = {"style": "insight", "tone": "professional"}
config = VariantResolver.resolve(base_variants, selected, theme)
# Theme will apply since tone isn't in the selected keys
# Professional tone sets emoji_level, then theme can override if key not in selected
# The logic in VariantResolver applies theme if key not in selected
# So the theme's emoji_level will be applied
assert (
config["emoji_level"] == "expressive"
) # Theme wins since emoji_level not explicitly selected
def test_suggest_variants_text_authority(self):
"""Test suggesting variants for text authority goal"""
suggestions = VariantResolver.suggest_variants("text", "authority")
assert suggestions["style"] == "insight"
assert suggestions["tone"] == "professional"
assert suggestions["length"] == "medium"
def test_suggest_variants_text_engagement(self):
"""Test suggesting variants for text engagement goal"""
suggestions = VariantResolver.suggest_variants("text", "engagement")
assert suggestions["style"] == "question"
assert suggestions["tone"] == "conversational"
assert suggestions["length"] == "short"
def test_suggest_variants_text_virality(self):
"""Test suggesting variants for text virality goal"""
suggestions = VariantResolver.suggest_variants("text", "virality")
assert suggestions["style"] == "hot_take"
assert suggestions["length"] == "micro"
def test_suggest_variants_document_authority(self):
"""Test suggesting variants for document authority goal"""
suggestions = VariantResolver.suggest_variants("document", "authority")
assert suggestions["content_type"] == "report"
assert suggestions["design_style"] == "professional"
def test_suggest_variants_poll_engagement(self):
"""Test suggesting variants for poll engagement goal"""
suggestions = VariantResolver.suggest_variants("poll", "engagement")
assert suggestions["purpose"] == "engagement"
assert suggestions["question_type"] == "binary"
def test_suggest_variants_unknown_goal(self):
"""Test suggesting variants for unknown goal returns empty"""
suggestions = VariantResolver.suggest_variants("text", "unknown_goal")
assert suggestions == {}
def test_suggest_variants_unknown_post_type(self):
"""Test suggesting variants for unknown post type returns empty"""
suggestions = VariantResolver.suggest_variants("unknown_type", "authority")
assert suggestions == {}
def test_get_all_variants_text(self):
"""Test getting all variants for text post"""
variants = VariantResolver.get_all_variants("text")
assert variants is not None
assert "base" in variants
assert "variants" in variants
def test_get_all_variants_poll(self):
"""Test getting all variants for poll post"""
variants = VariantResolver.get_all_variants("poll")
assert variants is not None
assert "base" in variants
def test_get_all_variants_document(self):
"""Test getting all variants for document post"""
variants = VariantResolver.get_all_variants("document")
assert variants is not None
assert "base" in variants
def test_get_all_variants_unknown(self):
"""Test getting variants for unknown post type"""
variants = VariantResolver.get_all_variants("unknown")
assert variants == {}
class TestVariantIntegration:
"""Integration tests for variant system"""
def test_resolve_complete_workflow(self):
"""Test complete variant resolution workflow"""
theme_manager = ThemeManager()
theme = theme_manager.get_theme("thought_leader")
# Get base variants
base_variants = PostVariants.text_post_variants()
# Get suggestions based on goal
suggestions = VariantResolver.suggest_variants("text", "authority")
# Resolve with theme
config = VariantResolver.resolve(base_variants, suggestions, theme)
# Verify final config has all necessary properties
assert "type" in config
assert "structure" in config
assert "emoji_level" in config
assert "hook_style" in config
def test_different_goals_produce_different_configs(self):
"""Test different goals produce different configurations"""
base_variants = PostVariants.text_post_variants()
authority_suggestions = VariantResolver.suggest_variants("text", "authority")
authority_config = VariantResolver.resolve(base_variants, authority_suggestions)
virality_suggestions = VariantResolver.suggest_variants("text", "virality")
virality_config = VariantResolver.resolve(base_variants, virality_suggestions)
# Configs should be different
assert authority_config["structure"] != virality_config["structure"]
def test_theme_personalizes_variant_output(self):
"""Test that different themes personalize the same variants"""
theme_manager = ThemeManager()
professional_theme = theme_manager.get_theme("corporate_professional")
fun_theme = theme_manager.get_theme("entertainer")
base_variants = PostVariants.text_post_variants()
selected = {"style": "insight", "tone": "conversational"}
professional_config = VariantResolver.resolve(base_variants, selected, professional_theme)
fun_config = VariantResolver.resolve(base_variants, selected, fun_theme)
# Should have different emoji levels based on theme
assert professional_config["emoji_level"] != fun_config["emoji_level"]
def test_compound_variants_enhance_combinations(self):
"""Test compound variants add extra properties for specific combinations"""
base_variants = PostVariants.text_post_variants()
# Compound-triggering selection
compound_selected = {"style": "story", "tone": "inspiring"}
compound_config = VariantResolver.resolve(base_variants, compound_selected)
# Compound config should have extra properties
assert "vulnerability_level" in compound_config
assert compound_config["line_break_style"] == "extreme"