Download test_logic.py from batoon/hum: direct link, hf CLI and curl.
- Browser
- Download file 3.47 kB
-
https://huggingface.co/spaces/batoon/hum/resolve/main/test_logic.py
- Command line
-
hf download hf://spaces/batoon/hum/test_logic.py
-
curl -L -o test_logic.py https://huggingface.co/spaces/batoon/hum/resolve/main/test_logic.py
3.47 kB
| """Contracts that prevent vocal ABC leakage and accidental timing expansion.""" | |
| from __future__ import annotations | |
| import unittest | |
| from logic import drum_hits, instrumental_abc, notes_to_abc, validate_duration | |
| NATIVE = '''X:1 | |
| M:4/4 | |
| L:1/16 | |
| V: Vocal clef=treble name="Vocal Melody" snm="Vocal" | |
| V: Ins clef=treble name="Ins Melody" snm="Inst." | |
| K:B | |
| % chorus | |
| V: Vocal | |
| "Bm"z12F,4| | |
| V: Ins | |
| Z1| | |
| V: Vocal | |
| Z| | |
| V: Ins | |
| Z1| | |
| ''' | |
| class LogicTest(unittest.TestCase): | |
| def test_move_melody_to_instrument_without_chord_or_voice(self): | |
| result = instrumental_abc(NATIVE) | |
| self.assertNotIn("Vocal", result) | |
| self.assertNotIn('"Bm"', result) | |
| self.assertIn("z12F,4|", result) | |
| self.assertIn("V: Ins\nz12F,4|", result) | |
| self.assertIn("V: Ins\nZ|", result) | |
| self.assertLess(result.index("V: Ins clef"), result.index("K:B")) | |
| def test_composition_keeps_chords_but_no_vocal_slot(self): | |
| result = instrumental_abc(NATIVE, keep_chords=True) | |
| self.assertIn('"Bm"z12F,4|', result) | |
| self.assertNotIn("Vocal", result) | |
| def test_unknown_layout_fails(self): | |
| with self.assertRaises(ValueError): | |
| instrumental_abc(NATIVE.replace("Z1|", "z16|", 1)) | |
| def test_fallback_abc_is_instrumental_and_has_source_order(self): | |
| abc = notes_to_abc([(.08, .52, 60), (.68, 1.1, 60), | |
| (1.3, 1.7, 62)], 2.) | |
| self.assertEqual(instrumental_abc(abc), abc) | |
| self.assertNotIn("Vocal", abc) | |
| self.assertIn("V: Ins", abc) | |
| self.assertIn("C7", abc) | |
| self.assertIn("D6", abc) | |
| def test_duration_bounds(self): | |
| validate_duration(0.4) | |
| validate_duration(35) | |
| for seconds in (0.1, 35.1): | |
| with self.assertRaises(ValueError): | |
| validate_duration(seconds) | |
| def test_drums_follow_beats_and_skip_long_melody_pause(self): | |
| beats = "".join(f"{i * .5}\t{i % 4 + 1}\t4\t4\n" for i in range(12)) | |
| hits = drum_hits(beats, [(0.2, 0.5), (2.2, 5.8)], 6.0) | |
| self.assertIn((0.0, 36, 90), hits) | |
| self.assertIn((2.0, 36, 90), hits) | |
| self.assertIn((2.5, 38, 76), hits) | |
| self.assertFalse(any(0.75 <= time <= 1.75 for time, _, _ in hits)) | |
| self.assertTrue(all(0 <= time < 6 for time, _, _ in hits)) | |
| def test_drums_reject_bad_beat_grid(self): | |
| for beats in ("0\t1\t4\t4\n0\t2\t4\t4\n1\t3\t4\t4\n", | |
| "0\t1\t5\t4\n.5\t2\t5\t4\n1\t3\t5\t4\n"): | |
| with self.assertRaises(ValueError): | |
| drum_hits(beats, [(0.1, 1.1)], 2.0) | |
| def test_drums_ignore_duplicate_zero_anchor_before_first_downbeat(self): | |
| # Seen in the source-time SheetSage2 beat.lab for input-001. | |
| beats = ("0\t1\t4\t4\n.44\t1\t4\t4\n.92\t2\t4\t4\n" | |
| "1.44\t3\t4\t4\n1.92\t4\t4\t4\n2.44\t1\t4\t4\n") | |
| hits = drum_hits(beats, [(.22, 2.5)], 2.6) | |
| self.assertFalse(any(time == 0 for time, _, _ in hits)) | |
| self.assertIn((.44, 36, 90), hits) | |
| def test_drums_ignore_sheet_sage_initial_one_eighth_anchor(self): | |
| # Seen in HumTrans F05/M01: 1/8 at zero precedes a real 3/4 or 4/4 grid. | |
| beats = ("0.0\t1\t1\t8\n.19\t1\t3\t4\n.67\t2\t3\t4\n" | |
| "1.16\t3\t3\t4\n1.67\t1\t3\t4\n") | |
| hits = drum_hits(beats, [(.2, 1.8)], 2.0) | |
| self.assertFalse(any(time == 0 for time, _, _ in hits)) | |
| self.assertIn((.19, 36, 90), hits) | |
| if __name__ == "__main__": | |
| unittest.main() | |