HYCZTLSZ5WVJFMP4EPVHAVWRYSYNCIBJ62LLBNO4IRVEBY7WJI6QC // assertWAVHeader creates a WAV file and verifies ParseWAVHeaderMinimal returns expected values.func assertWAVHeader(t *testing.T, tmpDir, filename string, wantSR int, wantDur float64, opts struct {duration float64sampleRate intchannels intbitsPerSample intcomment stringartist string}) {t.Helper()path := createTestWAVFile(t, tmpDir, filename, opts)sr, dur, err := ParseWAVHeaderMinimal(path)if err != nil {t.Fatalf("Failed to parse WAV header: %v", err)}if sr != wantSR {t.Errorf("SampleRate: got %d, want %d", sr, wantSR)}if dur < wantDur-0.1 || dur > wantDur+0.1 {t.Errorf("Duration: got %f, want ~%f", dur, wantDur)}}
}{duration: 10.0,sampleRate: 44100,channels: 1,bitsPerSample: 16,comment: "",artist: "",})sampleRate, duration, err := ParseWAVHeaderMinimal(path)if err != nil {t.Fatalf("Failed to parse WAV header: %v", err)}if sampleRate != 44100 {t.Errorf("SampleRate incorrect: got %d, want 44100", sampleRate)}if duration < 9.9 || duration > 10.1 {t.Errorf("Duration incorrect: got %f, want ~10.0", duration)}
}{10.0, 44100, 1, 16, "", ""})
t.Run("should handle different sample rates", func(t *testing.T) {sampleRates := []int{8000, 22050, 44100, 48000, 96000}for _, sr := range sampleRates {
t.Run("sample_rates", func(t *testing.T) {for _, sr := range []int{8000, 22050, 44100, 48000, 96000} {
}{duration: 5.0,sampleRate: sr,channels: 1,bitsPerSample: 16,comment: "",artist: "",})sampleRate, duration, err := ParseWAVHeaderMinimal(path)if err != nil {t.Fatalf("Failed to parse WAV header: %v", err)}if sampleRate != sr {t.Errorf("SampleRate incorrect: got %d, want %d", sampleRate, sr)}if duration < 4.9 || duration > 5.1 {t.Errorf("Duration incorrect: got %f, want ~5.0", duration)}
}{5.0, sr, 1, 16, "", ""})
}{duration: 3.0,sampleRate: 44100,channels: 2,bitsPerSample: 16,comment: "",artist: "",})sampleRate, duration, err := ParseWAVHeaderMinimal(path)if err != nil {t.Fatalf("Failed to parse WAV header: %v", err)}if sampleRate != 44100 {t.Errorf("SampleRate incorrect: got %d, want 44100", sampleRate)}if duration < 2.9 || duration > 3.1 {t.Errorf("Duration incorrect: got %f, want ~3.0", duration)}
}{3.0, 44100, 2, 16, "", ""})
}}// assertRGBAPixel checks that the pixel at (x,y) in an RGBA image matches the expected RGBA values.func assertRGBAPixel(t *testing.T, rgba *image.RGBA, x, y int, wantR, wantG, wantB, wantA uint8) {t.Helper()off := y*rgba.Stride + x*4got := rgba.Pix[off : off+4]if got[0] != wantR || got[1] != wantG || got[2] != wantB || got[3] != wantA {t.Errorf("pixel (%d,%d) = [%d,%d,%d,%d], want [%d,%d,%d,%d]",x, y, got[0], got[1], got[2], got[3], wantR, wantG, wantB, wantA)
// Check red pixel (0,0)if rgba.Pix[0] != 255 || rgba.Pix[1] != 0 || rgba.Pix[2] != 0 || rgba.Pix[3] != 255 {t.Errorf("pixel (0,0) = %v, want red+alpha", rgba.Pix[0:4])}// Check green pixel (1,0)if rgba.Pix[4] != 0 || rgba.Pix[5] != 255 || rgba.Pix[6] != 0 || rgba.Pix[7] != 255 {t.Errorf("pixel (1,0) = %v, want green+alpha", rgba.Pix[4:8])}// Check blue pixel (0,1) - row 1off := rgba.Strideif rgba.Pix[off] != 0 || rgba.Pix[off+1] != 0 || rgba.Pix[off+2] != 255 || rgba.Pix[off+3] != 255 {t.Errorf("pixel (0,1) = %v, want blue+alpha", rgba.Pix[off:off+4])}
assertRGBAPixel(t, rgba, 0, 0, 255, 0, 0, 255) // redassertRGBAPixel(t, rgba, 1, 0, 0, 255, 0, 255) // greenassertRGBAPixel(t, rgba, 0, 1, 0, 0, 255, 255) // blue
// mustGenerateID is a test helper that calls GenerateLongID and fatals on error.func mustGenerateID(t *testing.T) string {t.Helper()id, err := GenerateLongID()if err != nil {t.Fatalf("unexpected error: %v", err)}return id}// isValidAlphabetChar checks if c is in the nanoid default alphabet (0-9, A-Z, a-z, _, -).func isValidAlphabetChar(c rune) bool {return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || c == '-'}
}// mustResolveTimestamp is a test helper that calls ResolveTimestamp and fatals on error.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
result, err := ResolveTimestamp(meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)if err != nil {t.Fatalf("unexpected error: %v", err)}
result := mustResolveTimestamp(t, meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)
meta := &WAVMetadata{Comment: "",Artist: "",}result, err := ResolveTimestamp(meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)if err != nil {t.Fatalf("unexpected error: %v", err)}
result := mustResolveTimestamp(t, &WAVMetadata{}, "20250224_210000.wav", "Pacific/Auckland", false, nil)
meta := &WAVMetadata{Comment: "",Artist: "",FileModTime: modTime,}result, err := ResolveTimestamp(meta, "nopattern.wav", "Pacific/Auckland", true, nil)if err != nil {t.Fatalf("unexpected error: %v", err)}
meta := &WAVMetadata{FileModTime: modTime}result := mustResolveTimestamp(t, meta, "nopattern.wav", "Pacific/Auckland", true, nil)
t.Run("errors when no timestamp available and file mod time disabled", func(t *testing.T) {meta := &WAVMetadata{Comment: "",Artist: "",
t.Run("errors_on_no_timestamp", func(t *testing.T) {cases := []struct {name stringuseModTime bool}{{"mod_time_disabled", false},{"no_file_mod_time", true},
_, err := ResolveTimestamp(meta, "nopattern.wav", "Pacific/Auckland", false, nil)if err == nil {t.Error("expected error when no timestamp available")
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("errors when no timestamp available and no file mod time", func(t *testing.T) {meta := &WAVMetadata{Comment: "",Artist: "",}_, err := ResolveTimestamp(meta, "nopattern.wav", "Pacific/Auckland", true, nil)if err == nil {t.Error("expected error when no timestamp available")}})
meta := &WAVMetadata{Comment: "AudioMoth garbage data",Artist: "",}result, err := ResolveTimestamp(meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)if err != nil {t.Fatalf("unexpected error: %v", err)}
meta := &WAVMetadata{Comment: "AudioMoth garbage data"}result := mustResolveTimestamp(t, meta, "20250224_210000.wav", "Pacific/Auckland", false, nil)
input := ExecuteSQLInput{Query: "SELECT id, record_s, sleep_s FROM cyclic_recording_pattern WHERE active = true ORDER BY record_s, sleep_s",}output, err := ExecuteSQL(ctx, input)if err != nil {t.Fatalf("Failed to query patterns: %v", err)}if len(output.Rows) == 0 {t.Fatal("Expected at least one pattern")}t.Logf("Found %d patterns", len(output.Rows))for i, row := range output.Rows {t.Logf("Pattern %d: ID=%v, record_s=%v, sleep_s=%v", i+1, row["id"], row["record_s"], row["sleep_s"])}
testQueryExistingPatterns(t, ctx)
// First, find a valid dataset and locationdatasetSQL := ExecuteSQLInput{Query: "SELECT id FROM dataset WHERE active = true LIMIT 1",}datasetOutput, err := ExecuteSQL(ctx, datasetSQL)if err != nil || len(datasetOutput.Rows) == 0 {t.Skip("No active datasets found in test database")}datasetID := datasetOutput.Rows[0]["id"].(string)
testCreateClusterWithPattern(t, ctx)})}
locationSQL := ExecuteSQLInput{Query: "SELECT id FROM location WHERE dataset_id = ? AND active = true LIMIT 1",Parameters: []any{datasetID},}locationOutput, err := ExecuteSQL(ctx, locationSQL)if err != nil || len(locationOutput.Rows) == 0 {t.Skip("No active locations found in test database")}locationID := locationOutput.Rows[0]["id"].(string)t.Logf("Using dataset: %s, location: %s", datasetID, locationID)sampleRate := 16000input := ClusterInput{DatasetID: &datasetID,LocationID: &locationID,Name: new("Integration Test Cluster"),SampleRate: &sampleRate,CyclicRecordingPatternID: new("IBv_KxDGsNQs"), // 60s/1740s pattern}output, err := CreateOrUpdateCluster(ctx, input)if err != nil {t.Fatalf("Failed to create cluster: %v", err)}
func testQueryExistingPatterns(t *testing.T, ctx context.Context) {t.Helper()input := ExecuteSQLInput{Query: "SELECT id, record_s, sleep_s FROM cyclic_recording_pattern WHERE active = true ORDER BY record_s, sleep_s",}
// Verify the cluster has the pattern referencesqlInput := ExecuteSQLInput{Query: "SELECT c.name, c.cyclic_recording_pattern_id, p.record_s, p.sleep_s FROM cluster c LEFT JOIN cyclic_recording_pattern p ON c.cyclic_recording_pattern_id = p.id WHERE c.id = ?",Parameters: []any{clusterID},}
if len(output.Rows) == 0 {t.Fatal("Expected at least one pattern")}
sqlOutput, err := ExecuteSQL(ctx, sqlInput)if err != nil {t.Fatalf("Failed to verify cluster: %v", err)}
t.Logf("Found %d patterns", len(output.Rows))for i, row := range output.Rows {t.Logf("Pattern %d: ID=%v, record_s=%v, sleep_s=%v", i+1, row["id"], row["record_s"], row["sleep_s"])}}
if len(sqlOutput.Rows) != 1 {t.Fatalf("Expected 1 row, got %d", len(sqlOutput.Rows))}
func testCreateClusterWithPattern(t *testing.T, ctx context.Context) {t.Helper()// Find a valid datasetdatasetOutput, err := ExecuteSQL(ctx, ExecuteSQLInput{Query: "SELECT id FROM dataset WHERE active = true LIMIT 1",})if err != nil || len(datasetOutput.Rows) == 0 {t.Skip("No active datasets found in test database")}datasetID := datasetOutput.Rows[0]["id"].(string)
row := sqlOutput.Rows[0]
// Find a valid locationlocationOutput, err := ExecuteSQL(ctx, ExecuteSQLInput{Query: "SELECT id FROM location WHERE dataset_id = ? AND active = true LIMIT 1",Parameters: []any{datasetID},})if err != nil || len(locationOutput.Rows) == 0 {t.Skip("No active locations found in test database")}locationID := locationOutput.Rows[0]["id"].(string)
// Check the pattern IDpatternIDStr := row["cyclic_recording_pattern_id"]if patternIDStr != "IBv_KxDGsNQs" {t.Errorf("Expected pattern ID 'IBv_KxDGsNQs', got '%v'", patternIDStr)}
sampleRate := 16000output, err := CreateOrUpdateCluster(ctx, ClusterInput{DatasetID: &datasetID,LocationID: &locationID,Name: new("Integration Test Cluster"),SampleRate: &sampleRate,CyclicRecordingPatternID: new("IBv_KxDGsNQs"),})if err != nil {t.Fatalf("Failed to create cluster: %v", err)}clusterID := output.Cluster.IDt.Logf("Created cluster: %s with pattern reference", clusterID)
// Check record_s and sleep_srecordSVal := row["record_s"]sleepSVal := row["sleep_s"]
// Verify the cluster has the pattern referencesqlOutput, err := ExecuteSQL(ctx, ExecuteSQLInput{Query: "SELECT c.name, c.cyclic_recording_pattern_id, p.record_s, p.sleep_s FROM cluster c LEFT JOIN cyclic_recording_pattern p ON c.cyclic_recording_pattern_id = p.id WHERE c.id = ?",Parameters: []any{clusterID},})if err != nil {t.Fatalf("Failed to verify cluster: %v", err)}if len(sqlOutput.Rows) != 1 {t.Fatalf("Expected 1 row, got %d", len(sqlOutput.Rows))}
if patternIDStr == nil || patternIDStr == "" {t.Error("Pattern ID is empty")}if recordSVal == nil {t.Error("record_s is nil")}if sleepSVal == nil {t.Error("sleep_s is nil")}})
if row["cyclic_recording_pattern_id"] != "IBv_KxDGsNQs" {t.Errorf("Expected pattern ID 'IBv_KxDGsNQs', got '%v'", row["cyclic_recording_pattern_id"])}if row["cyclic_recording_pattern_id"] == nil || row["cyclic_recording_pattern_id"] == "" {t.Error("Pattern ID is empty")}if row["record_s"] == nil {t.Error("record_s is nil")}if row["sleep_s"] == nil {t.Error("sleep_s is nil")}
}// assertPropagateStats checks output stats against expected values.func assertPropagateStats(t *testing.T, got, want CallsPropagateFolderOutput) {t.Helper()checks := []struct {name stringgot intwant int}{{"FilesTotal", got.FilesTotal, want.FilesTotal},{"FilesWithBothFilters", got.FilesWithBothFilters, want.FilesWithBothFilters},{"FilesSkippedNoFilter", got.FilesSkippedNoFilter, want.FilesSkippedNoFilter},{"FilesChanged", got.FilesChanged, want.FilesChanged},{"FilesErrored", got.FilesErrored, want.FilesErrored},{"TargetsExamined", got.TargetsExamined, want.TargetsExamined},{"Propagated", got.Propagated, want.Propagated},{"SkippedNoOverlap", got.SkippedNoOverlap, want.SkippedNoOverlap},}for _, c := range checks {if c.got != c.want {t.Errorf("%s: got %d, want %d", c.name, c.got, c.want)}}
if out.FilesTotal != 4 {t.Errorf("FilesTotal: got %d, want 4", out.FilesTotal)}if out.FilesWithBothFilters != 2 {t.Errorf("FilesWithBothFilters: got %d, want 2", out.FilesWithBothFilters)}if out.FilesSkippedNoFilter != 2 {t.Errorf("FilesSkippedNoFilter: got %d, want 2", out.FilesSkippedNoFilter)}if out.FilesChanged != 1 {t.Errorf("FilesChanged: got %d, want 1", out.FilesChanged)}if out.FilesErrored != 0 {t.Errorf("FilesErrored: got %d, want 0", out.FilesErrored)}if out.TargetsExamined != 2 {t.Errorf("TargetsExamined: got %d, want 2", out.TargetsExamined)}if out.Propagated != 1 {t.Errorf("Propagated: got %d, want 1", out.Propagated)}if out.SkippedNoOverlap != 1 {t.Errorf("SkippedNoOverlap: got %d, want 1", out.SkippedNoOverlap)}
assertPropagateStats(t, out, CallsPropagateFolderOutput{FilesTotal: 4,FilesWithBothFilters: 2,FilesSkippedNoFilter: 2,FilesChanged: 1,FilesErrored: 0,TargetsExamined: 2,Propagated: 1,SkippedNoOverlap: 1,})
// File A was changed; check on-disk state.aDf := readFile(t, aPath)if aDf.Meta.Reviewer != "Skraak" {t.Errorf("a.wav.data reviewer: got %q, want Skraak", aDf.Meta.Reviewer)}if l := findLabel(aDf, fTo, 100, 125); l == nil || l.Certainty != 90 || l.CallType != "Male" {t.Errorf("a.wav.data target label: got %+v, want cert=90 calltype=Male", l)}
t.Run("file_a_propagated", func(t *testing.T) {aDf := readFile(t, aPath)if aDf.Meta.Reviewer != "Skraak" {t.Errorf("reviewer: got %q, want Skraak", aDf.Meta.Reviewer)}if l := findLabel(aDf, fTo, 100, 125); l == nil || l.Certainty != 90 || l.CallType != "Male" {t.Errorf("target label: got %+v, want cert=90 calltype=Male", l)}})
// File B was skipped — reviewer untouched.bDf := readFile(t, bPath)if bDf.Meta.Reviewer != "David" {t.Errorf("b.wav.data reviewer should not be touched, got %q", bDf.Meta.Reviewer)}
t.Run("file_b_skipped", func(t *testing.T) {bDf := readFile(t, bPath)if bDf.Meta.Reviewer != "David" {t.Errorf("reviewer should not be touched, got %q", bDf.Meta.Reviewer)}})
// File D had no overlap — reviewer untouched, target still cert=70.dDf := readFile(t, dPath)if dDf.Meta.Reviewer != "David" {t.Errorf("d.wav.data reviewer should not be touched, got %q", dDf.Meta.Reviewer)}if l := findLabel(dDf, fTo, 500, 525); l == nil || l.Certainty != 70 {t.Errorf("d.wav.data target label should be unchanged cert=70, got %+v", l)}
t.Run("file_d_no_overlap", func(t *testing.T) {dDf := readFile(t, dPath)if dDf.Meta.Reviewer != "David" {t.Errorf("reviewer should not be touched, got %q", dDf.Meta.Reviewer)}if l := findLabel(dDf, fTo, 500, 525); l == nil || l.Certainty != 70 {t.Errorf("target label should be unchanged cert=70, got %+v", l)}})
func TestLoadDataFilesFiltersFilesWithNoMatchingSegments(t *testing.T) {// Create a temp directory with test .data filestempDir := t.TempDir()// File 1: Kiwi segmentsfile1 := `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 90}]]]`if err := os.WriteFile(filepath.Join(tempDir, "file1.data"), []byte(file1), 0644); err != nil {
// writeDataFileContent creates a .data file in dir with the given raw content.func writeDataFileContent(t *testing.T, dir, name, content string) {t.Helper()if err := os.WriteFile(filepath.Join(dir, name), []byte(content), 0644); err != nil {
// File 2: Tomtit segments onlyfile2 := `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Tomtit", "certainty": 90}]]]`if err := os.WriteFile(filepath.Join(tempDir, "file2.data"), []byte(file2), 0644); err != nil {t.Fatal(err)}// File 3: Kiwi segmentsfile3 := `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 90}]]]`if err := os.WriteFile(filepath.Join(tempDir, "file3.data"), []byte(file3), 0644); err != nil {t.Fatal(err)}// Test 1: No filter - should load all 3 filesconfig1 := ClassifyConfig{Folder: tempDir, Certainty: -1}state1, err := LoadDataFiles(config1)
// mustLoadDataFiles is a test helper that calls LoadDataFiles and fatals on error.func mustLoadDataFiles(t *testing.T, config ClassifyConfig) *ClassifyState {t.Helper()state, err := LoadDataFiles(config)
// Test 2: Filter by Species "Kiwi" - should load only files 1 and 3config2 := ClassifyConfig{Folder: tempDir, Species: "Kiwi", Certainty: -1}state2, err := LoadDataFiles(config2)if err != nil {t.Fatal(err)
// assertFileSegCounts checks file count and total segment count match expected values.func assertFileSegCounts(t *testing.T, state *ClassifyState, wantFiles, wantSegs int, label string) {t.Helper()if len(state.DataFiles) != wantFiles {t.Errorf("%s: expected %d files, got %d", label, wantFiles, len(state.DataFiles))
if state2.TotalSegments() != 2 {t.Errorf("Species=Kiwi: expected 2 segments total, got %d", state2.TotalSegments())}
}const (kiwiSeg = `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 90}]]]`tomtitSeg = `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Tomtit", "certainty": 90}]]]`)func TestLoadDataFilesFiltersFilesWithNoMatchingSegments(t *testing.T) {tempDir := t.TempDir()writeDataFileContent(t, tempDir, "file1.data", kiwiSeg)writeDataFileContent(t, tempDir, "file2.data", tomtitSeg)writeDataFileContent(t, tempDir, "file3.data", kiwiSeg)t.Run("no_filter", func(t *testing.T) {state := mustLoadDataFiles(t, ClassifyConfig{Folder: tempDir, Certainty: -1})assertFileSegCounts(t, state, 3, 3, "No filter")})t.Run("species_kiwi", func(t *testing.T) {state := mustLoadDataFiles(t, ClassifyConfig{Folder: tempDir, Species: "Kiwi", Certainty: -1})assertFileSegCounts(t, state, 2, 2, "Species=Kiwi")})
// Test 3: Filter by Species "Tomtit" - should load only file 2config3 := ClassifyConfig{Folder: tempDir, Species: "Tomtit", Certainty: -1}state3, err := LoadDataFiles(config3)if err != nil {t.Fatal(err)}if len(state3.DataFiles) != 1 {t.Errorf("Species=Tomtit: expected 1 file, got %d", len(state3.DataFiles))}if state3.TotalSegments() != 1 {t.Errorf("Species=Tomtit: expected 1 segment total, got %d", state3.TotalSegments())}
t.Run("species_tomtit", func(t *testing.T) {state := mustLoadDataFiles(t, ClassifyConfig{Folder: tempDir, Species: "Tomtit", Certainty: -1})assertFileSegCounts(t, state, 1, 1, "Species=Tomtit")})
// Test 4: Filter by non-existent species - should return empty file list// (handled gracefully by caller in cmd/calls_classify.go)config4 := ClassifyConfig{Folder: tempDir, Species: "NonExistent", Certainty: -1}state4, err := LoadDataFiles(config4)if err != nil {t.Fatalf("Species=NonExistent: unexpected error: %v", err)}if len(state4.DataFiles) != 0 {t.Errorf("Species=NonExistent: expected 0 files, got %d", len(state4.DataFiles))}if state4.TotalSegments() != 0 {t.Errorf("Species=NonExistent: expected 0 segments, got %d", state4.TotalSegments())}
t.Run("species_nonexistent", func(t *testing.T) {state := mustLoadDataFiles(t, ClassifyConfig{Folder: tempDir, Species: "NonExistent", Certainty: -1})assertFileSegCounts(t, state, 0, 0, "Species=NonExistent")})
if err := os.WriteFile(filepath.Join(tempDir, "mixed.data"), []byte(file), 0644); err != nil {t.Fatal(err)}
writeDataFileContent(t, tempDir, "mixed.data", file)state := mustLoadDataFiles(t, ClassifyConfig{Folder: tempDir, Species: "Kiwi", Certainty: -1})
// File 1: certainty 70file1 := `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 70}]]]`if err := os.WriteFile(filepath.Join(tempDir, "file1.data"), []byte(file1), 0644); err != nil {t.Fatal(err)}
writeDataFileContent(t, tempDir, "file1.data", `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 70}]]]`)writeDataFileContent(t, tempDir, "file2.data", `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 100}]]]`)
// File 2: certainty 100file2 := `[{"Operator": "test"}, [0, 10, 100, 1000, [{"species": "Kiwi", "certainty": 100}]]]`if err := os.WriteFile(filepath.Join(tempDir, "file2.data"), []byte(file2), 0644); err != nil {t.Fatal(err)}
state := mustLoadDataFiles(t, ClassifyConfig{Folder: tempDir, Certainty: 100})
// Filter by certainty 100 - should load only file2config := ClassifyConfig{Folder: tempDir, Certainty: 100}state, err := LoadDataFiles(config)if err != nil {t.Fatal(err)}if len(state.DataFiles) != 1 {t.Errorf("Certainty=100: expected 1 file, got %d", len(state.DataFiles))}if state.TotalSegments() != 1 {t.Errorf("Certainty=100: expected 1 segment, got %d", state.TotalSegments())}
assertFileSegCounts(t, state, 1, 1, "Certainty=100")