calls_remove_test.go
package calls
import (
"os"
"path/filepath"
"testing"
"skraak/datafile"
)
func TestCallsRemoveLabel(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60, Reviewer: "AI"},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
{Species: "Tui", Certainty: 90, Filter: "BirdNET"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Removed != "label" {
t.Errorf("expected removed=label, got %s", result.Removed)
}
if result.Species != "Kiwi" {
t.Errorf("expected species=Kiwi, got %s", result.Species)
}
// Verify: segment should still exist with BirdNET label
df2, err := datafile.ParseDataFile(dataPath)
if err != nil {
t.Fatalf("failed to parse file: %v", err)
}
if len(df2.Segments) != 1 {
t.Fatalf("expected 1 segment, got %d", len(df2.Segments))
}
if len(df2.Segments[0].Labels) != 1 {
t.Errorf("expected 1 label remaining, got %d", len(df2.Segments[0].Labels))
}
if df2.Segments[0].Labels[0].Species != "Tui" {
t.Errorf("expected remaining label=Tui, got %s", df2.Segments[0].Labels[0].Species)
}
if df2.Meta.Reviewer != "David" {
t.Errorf("expected Reviewer=David, got %s", df2.Meta.Reviewer)
}
}
func TestCallsRemoveSegment(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
},
},
{
StartTime: 10,
EndTime: 15,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Tui", Certainty: 90, Filter: "Manual"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Removed != "segment" {
t.Errorf("expected removed=segment, got %s", result.Removed)
}
// Verify: only one segment remains
df2, err := datafile.ParseDataFile(dataPath)
if err != nil {
t.Fatalf("failed to parse file: %v", err)
}
if len(df2.Segments) != 1 {
t.Errorf("expected 1 segment, got %d", len(df2.Segments))
}
if df2.Segments[0].Labels[0].Species != "Tui" {
t.Errorf("expected remaining segment with Tui, got %s", df2.Segments[0].Labels[0].Species)
}
}
func TestCallsRemoveFile(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Removed != "file" {
t.Errorf("expected removed=file, got %s", result.Removed)
}
// Verify: file should be deleted
if _, err := os.Stat(dataPath); !os.IsNotExist(err) {
t.Error("expected .data file to be deleted")
}
}
func TestCallsRemoveAmbiguousCallType(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual", CallType: "Duet"},
{Species: "Kiwi", Certainty: 90, Filter: "Manual", CallType: "Alarm"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
// Remove without calltype should error
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err == nil {
t.Error("expected error for ambiguous calltype, got nil")
}
if result.Error == "" {
t.Error("expected error message in output")
}
}
func TestCallsRemoveWithCallType(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual", CallType: "Duet"},
{Species: "Kiwi", Certainty: 90, Filter: "Manual", CallType: "Alarm"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
// Remove with specific calltype
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi+Duet",
Filter: "Manual",
Reviewer: "David",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Removed != "label" {
t.Errorf("expected removed=label, got %s", result.Removed)
}
// Verify: one label remains
df2, err := datafile.ParseDataFile(dataPath)
if err != nil {
t.Fatalf("failed to parse file: %v", err)
}
if len(df2.Segments[0].Labels) != 1 {
t.Errorf("expected 1 label remaining, got %d", len(df2.Segments[0].Labels))
}
if df2.Segments[0].Labels[0].CallType != "Alarm" {
t.Errorf("expected remaining calltype=Alarm, got %s", df2.Segments[0].Labels[0].CallType)
}
}
func TestCallsRemoveAmbiguousFreq(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 8000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
},
},
{
StartTime: 2,
EndTime: 5,
FreqLow: 200,
FreqHigh: 4500,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 90, Filter: "Manual"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
// Remove without frequency should error (ambiguous)
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err == nil {
t.Error("expected error for ambiguous frequency, got nil")
}
if result.Error == "" {
t.Error("expected error message in output")
}
}
func TestCallsRemoveWithFrequency(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 8000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
},
},
{
StartTime: 2,
EndTime: 5,
FreqLow: 200,
FreqHigh: 4500,
Labels: []*datafile.Label{
{Species: "Tui", Certainty: 90, Filter: "Manual"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
// Remove with specific frequency
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Frequency: "200-4500",
Species: "Tui",
Filter: "Manual",
Reviewer: "David",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Removed != "segment" {
t.Errorf("expected removed=segment, got %s", result.Removed)
}
// Verify: one segment remains
df2, err := datafile.ParseDataFile(dataPath)
if err != nil {
t.Fatalf("failed to parse file: %v", err)
}
if len(df2.Segments) != 1 {
t.Errorf("expected 1 segment, got %d", len(df2.Segments))
}
if df2.Segments[0].Labels[0].Species != "Kiwi" {
t.Errorf("expected remaining species=Kiwi, got %s", df2.Segments[0].Labels[0].Species)
}
}
func TestCallsRemoveFileNotFound(t *testing.T) {
result, err := CallsRemove(CallsRemoveInput{
File: "/tmp/nonexistent_xyz.data",
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err == nil {
t.Error("expected error for missing file, got nil")
}
if result.Error == "" {
t.Error("expected error message in output")
}
}
func TestCallsRemoveNoMatchingLabel(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 0,
FreqHigh: 16000,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
// Try to remove a species that doesn't exist
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Tui",
Filter: "Manual",
Reviewer: "David",
})
if err == nil {
t.Error("expected error for no matching label, got nil")
}
if result.Error == "" {
t.Error("expected error message in output")
}
}
func TestCallsRemoveSingleSegmentNoFreqNeeded(t *testing.T) {
tmpDir := t.TempDir()
dataPath := filepath.Join(tmpDir, "test.data")
df := &datafile.DataFile{
Meta: &datafile.DataMeta{Operator: "Manual", Duration: 60},
Segments: []*datafile.Segment{
{
StartTime: 2,
EndTime: 5,
FreqLow: 200,
FreqHigh: 4500,
Labels: []*datafile.Label{
{Species: "Kiwi", Certainty: 80, Filter: "Manual"},
},
},
},
}
if err := df.Write(dataPath); err != nil {
t.Fatalf("failed to write test file: %v", err)
}
// Only one segment matches 2-5, so frequency not needed
result, err := CallsRemove(CallsRemoveInput{
File: dataPath,
Segment: "2-5",
Species: "Kiwi",
Filter: "Manual",
Reviewer: "David",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Removed != "file" {
t.Errorf("expected removed=file, got %s", result.Removed)
}
// Check that LowFreq/HighFreq are populated from the segment
if result.LowFreq != 200 {
t.Errorf("expected low_freq=200, got %f", result.LowFreq)
}
if result.HighFreq != 4500 {
t.Errorf("expected high_freq=4500, got %f", result.HighFreq)
}
}