File size: 3,900 Bytes
b2e4883 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | # Test harness for gp5_to_keyswitched_mid.py
This directory holds the test suite that validates the Guitar Pro 5 β keyswitched MIDI conversion script. The goal is to catch regressions before they break a recording session.
## What it tests
For each track in each song, the suite verifies:
1. **Conductor tempo** β must match the source GP file's BPM (was off by 60,000,000Γ·x in earlier versions).
2. **Conductor time signature** β must be 4/4 for the test corpus (was 4/16 when we read the wrong field).
3. **First event at tick 0** β no empty intro bars (the 35-bar silent intro was a real bug).
4. **Channel preserved** β output channel matches the GP file's channel assignment.
5. **Keyswitch counts exact** β every PalmDown, SlideIn, SlideUp, SlideDown, Hammer, Bend, Harm, Sustain key counted and matched against the baseline.
6. **Total keyswitchs** β sanity check on the count.
7. **Not empty** β placeholder MIDIs (54 bytes) are rejected.
8. **Track count** β exactly 2 tracks (conductor + audio).
9. **MIDI Type 1** β multi-track format.
10. **960 ticks per beat** β matches PyGuitarPro's resolution.
## How to run
```bash
cd D:/CODE/unstable-drums
python -m pytest tests/
```
A clean run takes ~2 minutes (the script regenerates every track). A focused run with `-k`:
```bash
python -m pytest tests/ -k "Dany_Rhythm_Guitar"
```
## How to add a new song
1. Copy the GP5 file into `D:/CODE/unstable-drums/gp5_songs/`.
2. Re-run the baseline recorder:
```bash
python tests/record_expected.py
```
This regenerates `tests/expected/baseline.yaml` with the current script's output.
3. Inspect the YAML to confirm the keyswitch counts and structural facts look right.
4. Commit the updated baseline.yaml.
## How to add a new test scenario
If you find a new edge case (e.g., a new articulation the script doesn't handle yet), add a test function to `tests/test_gp5_conversion.py` and re-run the suite. The test should run against every track in the baseline. Example:
```python
def test_my_new_scenario(track_setup):
"""Every track should have ... whatever."""
actual = ...
expected = ...
assert actual == expected, f"{track_setup['song_name']}/{...}"
```
The new test runs against every (song, track) pair automatically β no need to parametrize manually.
## How to update the baseline
The baseline is the *contract*. When you fix the GP file (e.g., add 5 more grace notes), the baseline's keyswitch counts become stale. Re-run `record_expected.py` to update them, then commit the new YAML.
The expected YAML is **not** a measurement of "what the script does" β it's a measurement of "what the script should do, given the user's intent for the GP file." If you change the GP file on purpose, you update the baseline on purpose.
## How the script handles things
The script writes outputs to subfolders named after the song:
- `D:/CODE/unstable-drums/The Summoning Aug 2026/*.mid`
- `D:/CODE/unstable-drums/Sacrifice ReDrum Full v2 gracenotes/*.mid`
These directories are gitignored. The test suite regenerates them on every run.
## How regressions are caught
The tests re-run the script for every track before testing. If a code change breaks the keyswitch counts, the test fails with a clear message like:
```
Sacrifice ReDrum Full v2 gracenotes/Dany Rhythm Guitar: keyswitch counts mismatch
Missing (expected but not emitted): {'PalmDown': 2}
Extra (emitted but not expected): {'C1(SlideUp)': 2}
```
That tells you exactly which song, which track, and which keyswitch is wrong.
## When the test fails for a "good" reason
If the user changes the GP file deliberately, the baseline is stale. Run `python tests/record_expected.py` to refresh the baseline, review the diff, and commit.
If the test fails because the script has a bug, fix the script and re-run the tests. The baseline shouldn't change for a bug fix.
|