package wav
import (
"path/filepath"
"testing"
"time"
)
func mustResolveTimestamp(t *testing.T, meta *WAVMetadata, filename, tz string, useModTime bool, preParsed *time.Time) *TimestampResult {
t.Helper()
result, err := ResolveTimestamp(meta, filename, tz, useModTime, preParsed)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
return result
}
func TestResolveTimestamp(t *testing.T) {
t.Run("resolves AudioMoth timestamp", func(t *testing.T) {
meta := &WAVMetadata{
Comment: "Recorded at 21:00:00 24/02/2025 (UTC+13) by AudioMoth 248AB50153AB0549 at medium gain while battery was 4.3V and temperature was 15.8C.",
Artist: "AudioMoth",
}
result := mustResolveTimestamp(t, meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)
if !result.IsAudioMoth {
t.Error("expected IsAudioMoth to be true")
}
if result.MothData == nil {
t.Error("expected MothData to be non-nil")
}
expectedUTC := time.Date(2025, 2, 24, 8, 0, 0, 0, time.UTC)
if !result.Timestamp.UTC().Equal(expectedUTC) {
t.Errorf("expected UTC timestamp %v, got %v", expectedUTC, result.Timestamp.UTC())
}
})
t.Run("falls back to filename timestamp", func(t *testing.T) {
result := mustResolveTimestamp(t, &WAVMetadata{}, "20250224_210000.wav", "Pacific/Auckland", false, nil)
if result.IsAudioMoth {
t.Error("expected IsAudioMoth to be false")
}
if result.Timestamp.IsZero() {
t.Error("expected non-zero timestamp")
}
})
t.Run("falls back to file mod time when enabled", func(t *testing.T) {
modTime := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC)
meta := &WAVMetadata{FileModTime: modTime}
result := mustResolveTimestamp(t, meta, "nopattern.wav", "Pacific/Auckland", true, nil)
if !result.Timestamp.Equal(modTime) {
t.Errorf("expected timestamp %v, got %v", modTime, result.Timestamp)
}
})
t.Run("errors_on_no_timestamp", func(t *testing.T) {
cases := []struct {
name string
useModTime bool
}{
{"mod_time_disabled", false},
{"no_file_mod_time", true},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
_, err := ResolveTimestamp(&WAVMetadata{}, "nopattern.wav", "Pacific/Auckland", tc.useModTime, nil)
if err == nil {
t.Error("expected error when no timestamp available")
}
})
}
})
t.Run("AudioMoth detected but parse fails falls back to filename", func(t *testing.T) {
meta := &WAVMetadata{Comment: "AudioMoth garbage data"}
result := mustResolveTimestamp(t, meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)
if !result.IsAudioMoth {
t.Error("expected IsAudioMoth to be true (detected even if parse failed)")
}
if result.MothData != nil {
t.Error("expected MothData to be nil since parsing failed")
}
if result.Timestamp.IsZero() {
t.Error("expected non-zero timestamp from filename fallback")
}
})
}
func TestProcessSingleFile(t *testing.T) {
tmpPath := filepath.Join(t.TempDir(), "20240101_120000.wav")
err := WriteWAVFile(tmpPath, []float64{0.0, 0.0}, 8000)
if err != nil {
t.Fatalf("failed to create temp wav: %v", err)
}
res, err := ProcessSingleFile(tmpPath, -41.0, 174.0, "Pacific/Auckland", false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res.SampleRate != 8000 {
t.Errorf("expected sample rate 8000, got %d", res.SampleRate)
}
if res.Hash == "" {
t.Error("expected non-empty hash")
}
}