Skip to content

Add a test suite and fix 7 bugs it found - #76

Closed
Xehanort88 wants to merge 2 commits into
arkrow:masterfrom
Xehanort88:tests-and-bug-fixes
Closed

Xehanort88 wants to merge 2 commits into
arkrow:masterfrom
Xehanort88:tests-and-bug-fixes

Conversation

@Xehanort88

Copy link
Copy Markdown

Summary

This adds a pytest suite (the project currently has none) and fixes the bugs it uncovered. It's split into two commits so the fixes can be reviewed against the tests that demonstrate them.

1. Test suite

The tests generate their own audio: a short intro followed by the same 8-note pattern repeated several times. Since any loop spanning a whole number of patterns is seamless, the correct loop points are known in advance, so loop detection is checked for correctness, not just for running without errors.

File Covers
tests/test_audio.py Loading mono/stereo files, rejecting silent or non-audio files, silence trimming, time conversions
tests/test_analysis.py End-to-end loop detection, duration and approximate-position options, scoring, zero-crossing snapping
tests/test_core.py split, extend (with and without fade), txt export, writing and reading tags
tests/test_handler.py The interactive picker, batch file discovery
tests/test_cli.py Every command run as a user would, including a batch folder containing a non-audio file

The whole suite runs in about 5–10 seconds (uv run pytest). pytest is added as a dev dependency (the uv.lock diff is only pytest and its dependencies), and a Tests workflow runs the suite on Ubuntu and Windows with Python 3.10 and 3.13.

In the first commit, each bug below has a test marked xfail(strict=True); the second commit fixes them and removes the markers.

2. Bug fixes

  • Mono tracks are played and exported louder than the original. For mono input, librosa.to_mono returns its input unchanged, so the in-place normalization meant for analysis (mono_signal /= ...) also rescaled playback_audio. play, split-audio and extend were affected; stereo files were not.
  • "Prefer longer loops" never did anything. _prioritize_duration ran before loop_start/loop_end were set, so every duration it compared was 0 - 0. It now runs after the loop positions are set.
  • Loops starting in the first seconds of a track were underscored. When the look-behind window in _calculate_subseq_beat_similarity is truncated, it was zero-padded at the end, i.e. next to the loop point, where the weights are heaviest. It's now padded on the side farthest from the loop point.
  • Interactive more / all / reset discarded the choice made afterwards and prompted again, because the redrawn table's result wasn't returned.
  • extend --fade-length 0 crashed: x[-0:] selects the whole array, which then fails to broadcast.
  • MusicLooper.export_tags() without output_dir used the file path instead of its directory (the CLI always passes one, so only API use was affected).
  • The txt export message named loop.txt while the file written is loops.txt; export_txt now returns the path it wrote.

Test plan

  • uv run pytest on the first commit: 45 passed, 7 xfailed (the bugs above)
  • uv run pytest on the second commit: 52 passed
  • Workflow run on Ubuntu and Windows, Python 3.10 and 3.13

Tests generate their own audio: an intro followed by a repeated 8-note
pattern, so the correct loop points are known in advance and loop
detection can be checked for correctness, not just for running.

Covers audio loading, loop detection and scoring, zero-crossing
snapping, split/extend/tag/txt exports, the interactive picker, batch
file discovery and every CLI command.

Known bugs are marked as strict xfail, so each fix is flagged until its
marker is removed.

Also adds pytest as a dev dependency and a CI workflow running the tests
on Ubuntu and Windows with Python 3.10 and 3.13.
- Mono tracks were played and exported louder than the original: the
  analysis-only normalization was applied in place to the audio array
  that is also used for playback, since to_mono returns its input as-is
  for mono audio.
- Longer loops were never preferred among near-identical scores:
  _prioritize_duration ran before loop_start/loop_end were set, so every
  duration it compared was 0.
- Loops starting in the first seconds of a track were underscored: the
  truncated look-behind window was zero-padded on the side nearest the
  loop point, where the weights are heaviest.
- Interactive mode discarded the choice made after 'more', 'all' or
  'reset' and prompted again.
- extend with fade_length=0 crashed (x[-0:] selects the whole array).
- export_tags() without output_dir used the file path as the directory.
- The txt export message named loop.txt instead of loops.txt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant