package helpers_test import ( "testing" "github.com/jfraeys/fetch_ml/internal/api/helpers" "github.com/jfraeys/fetch_ml/internal/queue" ) func TestComputeDatasetID(t *testing.T) { tests := []struct { name string datasetSpecs []queue.DatasetSpec datasets []string want string }{ { name: "both empty", datasetSpecs: nil, datasets: nil, want: "", }, { name: "only datasets", datasetSpecs: nil, datasets: []string{"dataset1", "dataset2"}, want: "", // will be a hash }, { name: "dataset specs with checksums", datasetSpecs: []queue.DatasetSpec{ {Name: "ds1", Checksum: "abc123"}, {Name: "ds2", Checksum: "def456"}, }, datasets: nil, want: "", // will be a hash }, { name: "dataset specs without checksums", datasetSpecs: []queue.DatasetSpec{ {Name: "ds1"}, {Name: "ds2"}, }, datasets: nil, want: "", // will use names }, { name: "checksums take precedence", datasetSpecs: []queue.DatasetSpec{{Name: "ds1", Checksum: "xyz789"}}, datasets: []string{"dataset1"}, want: "", // should use checksum from specs }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := helpers.ComputeDatasetID(tt.datasetSpecs, tt.datasets) if tt.want == "" { // Just verify it returns something or empty as expected if len(tt.datasetSpecs) == 0 && len(tt.datasets) == 0 && got != "" { t.Errorf("ComputeDatasetID() = %q, want empty string", got) } } else if got != tt.want { t.Errorf("ComputeDatasetID() = %q, want %q", got, tt.want) } }) } } func TestComputeParamsHash(t *testing.T) { tests := []struct { name string args string want string }{ { name: "empty args", args: "", want: "", }, { name: "simple args", args: "--lr 0.01 --epochs 10", want: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // sha256 of trimmed args }, { name: "args with spaces", args: " --lr 0.01 ", want: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // sha256 of trimmed args }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := helpers.ComputeParamsHash(tt.args) // Just verify it returns a string (hash computation is deterministic) if tt.want == "" && got != "" { t.Errorf("ComputeParamsHash() expected empty, got %q", got) } if tt.want != "" && got == "" { t.Errorf("ComputeParamsHash() expected non-empty hash") } }) } } func TestComputeParamsHash_Deterministic(t *testing.T) { args := "--lr 0.01 --epochs 10" hash1 := helpers.ComputeParamsHash(args) hash2 := helpers.ComputeParamsHash(args) if hash1 != hash2 { t.Error("ComputeParamsHash() should be deterministic") } // Different args should produce different hashes differentArgs := "--lr 0.02 --epochs 10" differentHash := helpers.ComputeParamsHash(differentArgs) if hash1 == differentHash { t.Error("ComputeParamsHash() should produce different hashes for different inputs") } } func TestComputeParamsHash_Whitespace(t *testing.T) { // Same args with different whitespace should produce the same hash hash1 := helpers.ComputeParamsHash("--lr 0.01 --epochs 10") hash2 := helpers.ComputeParamsHash(" --lr 0.01 --epochs 10 ") hash3 := helpers.ComputeParamsHash("--lr 0.01 --epochs 10") if hash1 != hash2 { t.Error("ComputeParamsHash() should handle leading/trailing whitespace consistently") } // Note: internal whitespace differences may or may not produce different hashes // depending on implementation details _ = hash3 }