File size: 4,512 Bytes
63dd946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
90
91
92
93
94
# Copyright (c) 2026 The Anuvani-Diarization authors
# SPDX-License-Identifier: MIT OR Apache-2.0
"""Shared test fixtures. Every comparison is bitwise: arrays are compared through their raw bytes, so -0.0 vs 0.0
and NaN payloads count as differences."""
import os
import sys
from pathlib import Path

import numpy as np
import pytest
from hypothesis import settings

PROJ = Path(__file__).resolve().parents[1]
# untracked reference data (the release's weights, the benchmark manifest, artifacts/) lives in the main checkout; a
# linked git worktree reads it there with ANUVANI_DIAR_MAIN_TREE=<the main checkout's SPEAKER-ID> (read only)
_MAIN = os.environ.get("ANUVANI_DIAR_MAIN_TREE")
SID = Path(_MAIN) if _MAIN else PROJ.parents[1]
# frozen reference package (read-only)
REL = SID / "release/anuvani_diar_v1"
ART = SID / "release/anuvani_diar_rs/artifacts" if _MAIN else PROJ / "artifacts"
# development data (benchmark manifests, cached front-end records, the research pipeline's outputs): not part of the
# repository; ANUVANI_DIAR_DEV_DATA names it, by default artifacts/dev_data (docs/TESTING.md)
DEV = Path(os.environ.get("ANUVANI_DIAR_DEV_DATA") or ART / "dev_data")

# deterministic property tests: fixed derandomised seed, no example database
settings.register_profile("det", derandomize=True, database=None, max_examples=2000, deadline=None, print_blob=True)
settings.load_profile("det")

# the differential tests compute their references with numpy in this process, whose BLAS bits depend on its thread
# count; a test that only compares engine output with stored oracles may run with other thread settings on purpose
# (it sets ANUVANI_DIAR_ANY_BLAS_THREADS=1 for its own subprocess)
if ((os.environ.get("OPENBLAS_NUM_THREADS") != "1" and not os.environ.get("ANUVANI_DIAR_ANY_BLAS_THREADS"))
        or not sys.flags.no_user_site):
    raise RuntimeError("run tests through `make` (canonical environment: env/canonical.sh, python -s)")


def bits_equal(a, b):
    """Same dtype, shape and bits for every non-NaN value (so -0.0 != 0.0), and NaN in exactly the same places.

    NaN payload and sign bits are not compared: the compiled numpy loops may pick a different NaN payload when two
    NaNs meet, and no NaN payload can reach an RTTM (every downstream use only tests NaN-ness)."""
    a, b = np.asarray(a), np.asarray(b)
    if a.dtype != b.dtype or a.shape != b.shape:
        return False
    if a.dtype.kind != "f":
        return a.tobytes() == b.tobytes()
    na, nb = np.isnan(a), np.isnan(b)
    if not np.array_equal(na, nb):
        return False
    return a[~na].tobytes() == b[~nb].tobytes()


@pytest.fixture(scope="session")
def core():
    from anuvani_diar import _core
    return _core


# ---------------------------------------------------------------- the release with stand-in networks (CPU)

def fake_inputs(tmp):
    """The robustness files, window-count edges cut from one benchmark file, and five whole benchmark files."""
    import json
    import soundfile as sf
    win, step = 256000, 25600
    items = [dict(sid=i["sid"], path=i["path"]) for i in json.loads((ART / "test_audio/MANIFEST.json").read_text())
             if i["set"] == "robust"]
    rows = json.loads((DEV / "manifests/bench_manifest.json").read_text())["rows"]
    src = sorted(rows, key=lambda r: r["sample_id"])
    a, _ = sf.read(src[0]["flac_path"], dtype="float32")
    for n in (win - 1, win, win + 1, win + 7 * step, win + 8 * step - 1, win + 8 * step, win + 8 * step + 1,
              win + 15 * step + 5, win + 16 * step, 30 * 16000 + 7):
        p = tmp / f"len_{n}.flac"
        sf.write(p, a[:n], 16000, subtype="PCM_16")
        items.append(dict(sid=p.stem, path=str(p)))
    # five whole benchmark files
    for r in src[1:6]:
        items.append(dict(sid=r["sample_id"], path=r["flac_path"]))
    return items


@pytest.fixture(scope="session")
def fake_reference(tmp_path_factory):
    """(inputs, folder): the release's own `analyse` and `indic_mode` on `fake_inputs` with the stand-in networks of
    fake_nn.py; the folder holds log.json (errors), <sid>.npz (records) and <sid>.rttm."""
    import json
    import subprocess
    tmp = tmp_path_factory.mktemp("fake")
    items = fake_inputs(tmp)
    (tmp / "inputs.json").write_text(json.dumps(items))
    subprocess.run([sys.executable, "-s", "-W", "ignore", str(PROJ / "tests/ref_fake_run.py"), str(tmp / "inputs.json"),
                    str(tmp / "ref")], check=True, capture_output=True)
    return items, tmp / "ref"