Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build-whisper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ jobs:
if: inputs.release_tag != ''
env:
GH_TOKEN: ${{ github.token }}
# These jobs do not check out the repo, so gh has no git remote to
# infer the repo from — set it explicitly.
GH_REPO: ${{ github.repository }}
run: |
# Create the release if it does not exist (|| true tolerates a race
# with the sibling arch job creating it concurrently).
Expand Down
17 changes: 8 additions & 9 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,14 @@ jobs:
curl -L -o .whisper-cache/ggml-small.bin "$WHISPER_MODEL_URL"
fi
cp .whisper-cache/ggml-small.bin addons/whisper/models/ggml-small.bin
# No prebuilt Linux whisper-cli is published (macOS uses a Homebrew
# bottle, Windows a release zip), so build whisper.cpp from source.
# Static build (BUILD_SHARED_LIBS=OFF) => a self-contained whisper-cli
# with no lib/ dir to manage; GGML_NATIVE=OFF for runner portability.
git clone --depth 1 -b v1.8.3 https://github.com/ggml-org/whisper.cpp /tmp/whisper.cpp
cmake -S /tmp/whisper.cpp -B /tmp/whisper.cpp/build \
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DGGML_NATIVE=OFF
cmake --build /tmp/whisper.cpp/build --config Release -j"$(nproc)"
cp "$(find /tmp/whisper.cpp/build -name whisper-cli -type f | head -1)" addons/whisper/bin/whisper-cli
# Download the same published whisper-cli the app fetches at runtime
# (the linux-x64 source in whisper-addon.json), so the test exercises
# the real add-on artifact + tar layout instead of building from
# source. Mirrors the Windows job, which curls its release zip.
WHISPER_URL=$(python3 -c "import json;print(json.load(open('app/assets/whisper-addon.json'))['binary']['platforms']['linux-x64']['url'])")
echo "whisper-cli: $WHISPER_URL"
curl -L -o /tmp/whisper-cli.tar.gz "$WHISPER_URL"
tar xzf /tmp/whisper-cli.tar.gz -C addons/whisper # => addons/whisper/bin/whisper-cli
chmod +x addons/whisper/bin/whisper-cli
ls -la addons/whisper/bin addons/whisper/models

Expand Down
71 changes: 60 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,25 +410,74 @@ The most important parameters:

## Testing

VapourBox has **three distinct test suites**. Know which is which before adding
or changing tests — they live in different places and run differently.

### 1. Rust worker tests — `worker/tests/`, run by `cargo test`

```bash
# Rust tests
cd worker && cargo test
cd worker && cargo test --test subtitle_integration_test -- --nocapture
```

- `filter_integration_test.rs` — **every filter/parameter change must add a
numbered test here** (see "Adding a New Filter"). It generates `.vpy` scripts
and, via `run_job`, runs the `vspipe | ffmpeg` pipeline, so it needs `deps/`.
- `subtitle_integration_test.rs` — runs `whisper-cli` on
`Tests/TestResources/small_clip.mp4`; needs the whisper add-on + ffmpeg.
- In **debug** builds `DependencyLocator` finds repo-root `deps/`/`addons/` by
searching upward — **except Linux**, which only reads
`~/.local/share/VapourBox/` (no upward search), so CI symlinks those there.

# Flutter tests
### 2. Flutter `test/` suite — `app/test/`, run by `flutter test` ← the CI gate

```bash
cd app && flutter test
```

# Test worker standalone
Headless Dart-VM tests. A mix of pure unit tests (`dynamic_parameters`,
`filter_schema`, `parameter_converter`, `widget_test`, `scan_type_detection`)
and integration-style tests that shell out to the bundled binaries
(`vapoursynth_integration_test`, `schema_converter_integration_test`); the latter
need the per-arch `deps/` and (for whisper) `addons/`. **This is the Flutter
suite CI runs** — put new shell-out Dart tests here so CI covers them.

### 3. Flutter `integration_test/` suite — `app/integration_test/`, NOT in CI

```bash
cd app && flutter test integration_test # separate invocation; needs a display/device
```

- Flutter routes **anything** under `integration_test/` through the device
launcher (even plain `package:test` files), so it can't be combined with the
`test/` suite in one `flutter test` call and won't run on a headless CI runner
without a display (e.g. `xvfb`). These are **local/manual** tests.
- **Not maintained by CI, so they drift.** As of this writing
`filter_pipeline_test.dart` is stale and does not compile — it references a
removed API (`EncodingSettings.audioCopy`, now the `AudioMode` enum;
`ChromaFixParameters.vinverseScl`, now `vinverseSstr`/`vinverseAmnt`). Fix or
delete before relying on it; prefer adding shell-out tests to suite #2 instead.

```bash
# Run the worker standalone (no test harness)
cd worker && cargo run --release -- --config test_job.json
```

**CI test gate** (`.github/workflows/ci-test.yml`): runs on push to `main` + PRs. It
pulls the published deps bundle and the whisper add-on (binary + small model),
then runs the full Rust + Flutter suites — including the subtitle integration
test — on macOS **arm64** (`macos-15`) and **x64** (`macos-15-intel`) and Windows x64. The
subtitle test needs `addons/whisper/{bin/whisper-cli,models/ggml-small.bin}` and
ffmpeg from `deps/`; the scan-type/vapoursynth Flutter tests need the per-arch
`deps/` dir. The `small_clip.mp4` + telecine/interlaced fixtures are committed
under `Tests/TestResources/`.
### CI test gate (`.github/workflows/ci-test.yml`)

Runs on push to `main` + PRs (skipped for doc-only changes via `paths-ignore`).
Each job pulls the published deps bundle + the whisper add-on, then runs
**suite #1 (`cargo test`) and suite #2 (`flutter test`)** — including the subtitle
integration test. Matrix: macOS **arm64** (`macos-15`), macOS **x64**
(`macos-15-intel`), **Windows x64**, **Linux x64** (`ubuntu-22.04`). Notes:

- whisper-cli is provisioned from the **same source the app uses at runtime**
(`app/assets/whisper-addon.json`): macOS via a Homebrew bottle, Windows/Linux
by downloading the published release zip/tarball (Linux from `whisper-vX.Y.Z`,
built by `build-whisper.yml`).
- Fixtures (`small_clip.mp4`, telecine/interlaced clips) are committed under
`Tests/TestResources/`.
- Suite #3 (`integration_test/`) is **not** part of this gate (see above).

## Code Style

Expand Down
14 changes: 14 additions & 0 deletions app/assets/whisper-addon.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@
"format": "zip",
"executable": "whisper-cli.exe",
"size": 3968674
},
"linux-x64": {
"url": "https://github.com/StuartCameronCode/VapourBox/releases/download/whisper-v1.8.3/whisper-cli-linux-x64.tar.gz",
"format": "tar",
"executable": "whisper-cli",
"size": 1573360,
"sha256": "4ea12345281a210937ce900984721d650adf834e308d03e520c506923ec4c8e6"
},
"linux-arm64": {
"url": "https://github.com/StuartCameronCode/VapourBox/releases/download/whisper-v1.8.3/whisper-cli-linux-arm64.tar.gz",
"format": "tar",
"executable": "whisper-cli",
"size": 1527325,
"sha256": "2ffb99a5432bb6153b2a6e29ce7034465358f2fb5b98dad99c69663f6305c1c4"
}
}
},
Expand Down
Loading