diff --git a/test/chromaprint_test.exs b/test/chromaprint_test.exs new file mode 100644 index 0000000..98aba2a --- /dev/null +++ b/test/chromaprint_test.exs @@ -0,0 +1,94 @@ +defmodule ChromaprintTest do + use ExUnit.Case, async: true + import Bitwise + doctest Chromaprint + + @sample_rate 44_100 + # Chromaprint needs ~3+ seconds of audio to produce a fingerprint. + @duration_seconds 4 + + defp sine_pcm(freq_hz, duration_s, sample_rate) do + n = duration_s * sample_rate + two_pi = 2.0 * :math.pi() + + for i <- 0..(n - 1), into: <<>> do + sample = trunc(:math.sin(two_pi * freq_hz * i / sample_rate) * 32_000) + <> + end + end + + test "library version is reported" do + assert is_binary(Chromaprint.version()) + assert byte_size(Chromaprint.version()) > 0 + end + + test "lists supported algorithms" do + assert :test2 in Chromaprint.algorithms() + end + + describe "streaming API" do + setup do + {:ok, pcm: sine_pcm(440, @duration_seconds, @sample_rate)} + end + + test "produces a non-empty fingerprint for a sine wave", %{pcm: pcm} do + {:ok, ctx} = Chromaprint.new() + :ok = Chromaprint.start(ctx, sample_rate: @sample_rate, channels: 1) + :ok = Chromaprint.feed(ctx, pcm) + :ok = Chromaprint.finish(ctx) + assert {:ok, fp} = Chromaprint.fingerprint(ctx) + assert is_binary(fp) + assert byte_size(fp) > 0 + end + + test "raw fingerprint is a non-empty list of uint32", %{pcm: pcm} do + {:ok, ctx} = Chromaprint.new() + :ok = Chromaprint.start(ctx, sample_rate: @sample_rate, channels: 1) + :ok = Chromaprint.feed(ctx, pcm) + :ok = Chromaprint.finish(ctx) + assert {:ok, raw} = Chromaprint.raw_fingerprint(ctx) + assert is_list(raw) + assert length(raw) > 0 + assert Enum.all?(raw, fn x -> is_integer(x) and x >= 0 and x < 1 <<< 32 end) + end + + test "hash returns a 32-bit unsigned integer", %{pcm: pcm} do + {:ok, ctx} = Chromaprint.new() + :ok = Chromaprint.start(ctx, sample_rate: @sample_rate, channels: 1) + :ok = Chromaprint.feed(ctx, pcm) + :ok = Chromaprint.finish(ctx) + assert {:ok, h} = Chromaprint.hash(ctx) + assert is_integer(h) and h >= 0 and h < 1 <<< 32 + end + end + + describe "compute/2 one-shot" do + test "matches the streaming result on the same input" do + pcm = sine_pcm(440, @duration_seconds, @sample_rate) + + {:ok, ctx} = Chromaprint.new() + :ok = Chromaprint.start(ctx, sample_rate: @sample_rate, channels: 1) + :ok = Chromaprint.feed(ctx, pcm) + :ok = Chromaprint.finish(ctx) + {:ok, streamed} = Chromaprint.fingerprint(ctx) + + assert {:ok, ^streamed} = + Chromaprint.compute(pcm, sample_rate: @sample_rate, channels: 1) + end + end + + describe "encode/2 and decode/2 round-trip" do + test "raw → encode → decode → raw" do + pcm = sine_pcm(440, @duration_seconds, @sample_rate) + {:ok, ctx} = Chromaprint.new() + :ok = Chromaprint.start(ctx, sample_rate: @sample_rate, channels: 1) + :ok = Chromaprint.feed(ctx, pcm) + :ok = Chromaprint.finish(ctx) + {:ok, raw} = Chromaprint.raw_fingerprint(ctx) + {:ok, fp} = Chromaprint.fingerprint(ctx) + + assert {:ok, ^fp} = Chromaprint.encode(raw, algorithm: :test2, base64: true) + assert {:ok, %{algorithm: :test2, raw: ^raw}} = Chromaprint.decode(fp) + end + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()