Files
Momento/.claude/skills/suno-lyric-transformer/scripts/tests/test-validate-lyrics.py
Antigravity bd495be965
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 12s
feat: design system overhaul — sidebar, AI chats, settings, brainstorm, color cleanup
- Sidebar: dynamic brand-accent colors, brainstorm section restyled
- AI chat general: popup panel with expand/collapse, hides when contextual AI open
- AI chat contextual: tabs reordered (Actions first), X close button, height fix
- Settings: all tabs restyled, 6 new color presets (sage, terracotta, iron, etc.)
- Global color cleanup: emerald/orange hardcoded → brand-accent dynamic
- Brainstorm page: orange → brand-accent throughout
- PageEntry animation component added to key pages
- Floating AI button: bg-brand-accent instead of hardcoded black
- i18n: all 15 locales updated with new AI/billing keys
- Billing: freemium quota tracking, BYOK, stripe subscription scaffolding
- Admin: integrated into new design
- AGENTS.md + CLAUDE.md project rules added
2026-05-16 12:59:30 +00:00

227 lines
9.2 KiB
Python

#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = ["pytest>=7.0"]
# ///
"""Tests for validate-lyrics.py"""
import json
import subprocess
import sys
from pathlib import Path
SCRIPT = str(Path(__file__).parent.parent / "validate-lyrics.py")
def run_script(*args):
"""Run the script and return parsed JSON output."""
result = subprocess.run(
[sys.executable, SCRIPT, *args],
capture_output=True, text=True
)
return json.loads(result.stdout) if result.stdout else None, result.returncode
class TestValidateLyrics:
def test_valid_structured_lyrics(self):
lyrics = (
"[Verse 1]\n"
"Walking through the morning light\n"
"Counting shadows on the wall\n"
"\n"
"[Chorus]\n"
"Come undone, come undone\n"
"Let the weight fall where it may\n"
"\n"
"[Verse 2]\n"
"Fingerprints on frosted glass\n"
"Letters folded into cranes\n"
"\n"
"[Chorus]\n"
"Come undone, come undone\n"
"Let the weight fall where it may\n"
)
report, code = run_script("--text", lyrics)
assert report is not None
assert report["script"] == "validate-lyrics"
assert report["metrics"]["section_count"] == 4
assert "Verse 1" in report["metrics"]["sections"]
assert "Chorus" in report["metrics"]["sections"]
def test_no_section_tags(self):
lyrics = "Just some raw text\nWith no structure at all\nThree lines of poetry"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f["issue"] for f in report["findings"]]
assert any("No section metatags" in i for i in issues)
def test_style_cue_contamination(self):
lyrics = "[Verse 1]\nThe punchy drums echo through my mind\n"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f["issue"] for f in report["findings"]]
assert any("style cue" in i.lower() for i in issues)
def test_asterisk_detection(self):
lyrics = "[Verse 1]\n*This line has asterisks*\n"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f["issue"] for f in report["findings"]]
assert any("Asterisk" in i for i in issues)
def test_empty_lyrics(self):
report, code = run_script("--text", "")
assert report is not None
assert report["status"] == "fail"
assert any(f["severity"] == "critical" for f in report["findings"])
def test_unrecognized_metatag(self):
lyrics = "[Verse 1]\nSome line\n\n[Banana]\nAnother line\n"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f["issue"] for f in report["findings"]]
assert any("Unrecognized metatag" in i for i in issues)
def test_valid_descriptor_metatags(self):
lyrics = (
"[Mood: haunting]\n\n"
"[Verse 1]\n"
"Walking through the fog\n"
"Counting all the windows\n"
)
report, code = run_script("--text", lyrics)
assert report is not None
# Descriptor metatags should not be flagged as unrecognized
issues = [f["issue"] for f in report["findings"]]
assert not any("Mood" in i and "Unrecognized" in i for i in issues)
def test_empty_section(self):
lyrics = "[Verse 1]\n\n[Chorus]\nSome chorus line\n"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f["issue"] for f in report["findings"]]
assert any("Empty section" in i for i in issues)
def test_report_structure(self):
lyrics = "[Verse 1]\nA simple test line here\n"
report, code = run_script("--text", lyrics)
assert report is not None
assert "script" in report
assert "version" in report
assert "timestamp" in report
assert "status" in report
assert "metrics" in report
assert "findings" in report
assert "summary" in report
def test_help_flag(self):
result = subprocess.run(
[sys.executable, SCRIPT, "--help"],
capture_output=True, text=True
)
assert result.returncode == 0
assert "validate" in result.stdout.lower()
def test_character_count_error(self):
"""Lyrics exceeding 5000 chars (hard limit) should produce high severity finding."""
# Build lyrics over 5000 characters (hard limit for v4.5+/v5/v5.5)
line = "This is a long line of lyrics for testing character count limits yeah\n"
lyrics = "[Verse 1]\n" + line * 80 # well over 5000 chars
assert len(lyrics) > 5000
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f for f in report["findings"] if "character count" in f["issue"].lower()]
assert len(issues) >= 1
assert any(f["severity"] == "high" for f in issues)
def test_character_count_warning(self):
"""Lyrics between 3000 and 5000 chars should produce medium severity finding (quality degrades)."""
# Build lyrics between 3000 and 5000 characters (quality budget exceeded)
line = "This is a medium line of lyrics for testing\n"
base = "[Verse 1]\n"
# Each line is 45 chars. Need total between 3000 and 5000.
count = 72 # 10 + 72*45 = 3250
lyrics = base + line * count
total = len(lyrics)
assert 3000 < total < 5000, f"Got {total} chars"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f for f in report["findings"] if "character count" in f["issue"].lower()]
assert len(issues) >= 1
assert any(f["severity"] == "medium" for f in issues)
def test_character_count_in_metrics(self):
"""Report metrics should include character_count."""
lyrics = "[Verse 1]\nHello world\n"
report, code = run_script("--text", lyrics)
assert report is not None
assert "character_count" in report["metrics"]
assert report["metrics"]["character_count"] == len(lyrics)
def test_punctuation_density_detection(self):
"""Lines with heavy punctuation should trigger a rhythm finding."""
lyrics = "[Verse 1]\nwell, - ; : ... yes\n"
report, code = run_script("--text", lyrics)
assert report is not None
issues = [f for f in report["findings"] if "punctuation" in f["issue"].lower()]
assert len(issues) >= 1
assert issues[0]["severity"] == "low"
assert issues[0]["category"] == "rhythm"
def test_clean_lyrics_normal_punctuation_passes(self):
"""Clean lyrics with normal punctuation should pass without punctuation findings."""
lyrics = (
"[Verse 1]\n"
"Walking through the morning light\n"
"Counting shadows on the wall\n"
"\n"
"[Chorus]\n"
"Come undone, come undone\n"
"Let the weight fall where it may\n"
"\n"
"[Verse 2]\n"
"Fingerprints on frosted glass\n"
"Letters folded into cranes\n"
"\n"
"[Chorus]\n"
"Come undone, come undone\n"
"Let the weight fall where it may\n"
)
report, code = run_script("--text", lyrics)
assert report is not None
punct_issues = [f for f in report["findings"] if "punctuation" in f["issue"].lower()]
assert len(punct_issues) == 0
def test_new_section_tags_recognized(self):
"""New section tags like Guitar Solo, Instrumental, etc. should not be flagged."""
new_tags = [
"Guitar Solo", "Piano Solo", "Sax Solo", "Saxophone Solo",
"Drum Solo", "Bass Solo", "Solo", "Instrumental", "Interlude",
"Build", "Build-Up", "Buildup", "Drop", "Hook", "Refrain",
"Post-Chorus", "End", "Fade Out", "Fade In", "Break",
]
for tag in new_tags:
lyrics = f"[Verse 1]\nSome line one\nSome line two\n\n[{tag}]\nContent here\n"
report, code = run_script("--text", lyrics)
assert report is not None, f"No report for [{tag}]"
unrecognized = [f for f in report["findings"]
if "Unrecognized" in f.get("issue", "") and tag in f.get("issue", "")]
assert len(unrecognized) == 0, f"[{tag}] was flagged as unrecognized"
def test_vocal_cues_recognized(self):
"""Vocal delivery cues like [Harmonized] should not be flagged as unrecognized."""
cues = ["Harmonized", "Hummed", "Humming", "Whistled", "Whistling",
"Crooning", "Scat", "Call and Response"]
for cue in cues:
lyrics = f"[Verse 1]\nSome line here\n[{cue}]\nMore content\n"
report, code = run_script("--text", lyrics)
assert report is not None, f"No report for [{cue}]"
unrecognized = [f for f in report["findings"]
if "Unrecognized" in f.get("issue", "") and cue in f.get("issue", "")]
assert len(unrecognized) == 0, f"[{cue}] was flagged as unrecognized"
if __name__ == "__main__":
import pytest
pytest.main([__file__, "-v"])