package bambulab import ( "context" "encoding/json" "testing" "gitea.stevedudenhoeffer.com/steve/go-extractor" "gitea.stevedudenhoeffer.com/steve/go-extractor/extractortest" ) func makeNextDataJSON(printerMap map[string]printerEntry) string { data := nextData{} data.Props.PageProps.PrinterMap = printerMap b, _ := json.Marshal(data) return string(b) } var samplePrinterMap = map[string]printerEntry{ "x1": { Key: "x1", DevModel: "BL-P001", Name: "Bambu Lab X1 Series", Versions: []firmwareVersion{ { Version: "01.11.02.00", URL: "https://public-cdn.bblmw.com/upgrade/device/offline/BL-P001/01.11.02.00/e63e21a87c/offline-ota-p001_v01.11.02.00-20251210083345.zip", MD5: "1aa2c8400b4a3d599f8b4a09db60635c", ReleaseTime: "2025-12-10T12:01:58Z", ReleaseNotesEN: "# Version 01.11.02.00\n## Feature Optimization:\n* Enhanced accuracy", }, { Version: "01.10.01.00", URL: "https://public-cdn.bblmw.com/upgrade/device/offline/BL-P001/01.10.01.00/abc123/offline-ota-p001_v01.10.01.00.zip", MD5: "abc123def456", ReleaseTime: "2025-06-15T10:00:00Z", ReleaseNotesEN: "# Version 01.10.01.00\n## Bug Fixes:\n* Fixed connectivity issue", }, { Version: "01.09.00.00", URL: "https://public-cdn.bblmw.com/upgrade/device/offline/BL-P001/01.09.00.00/def456/offline-ota-p001_v01.09.00.00.zip", MD5: "def456ghi789", ReleaseTime: "2025-03-01T08:00:00Z", ReleaseNotesEN: "", }, }, }, "a1-mini": { Key: "a1-mini", DevModel: "BL-A001", Name: "Bambu Lab A1 mini", Versions: []firmwareVersion{ { Version: "01.05.00.00", URL: "https://public-cdn.bblmw.com/upgrade/device/offline/BL-A001/01.05.00.00/xyz/firmware.zip", MD5: "xyz789", ReleaseTime: "2025-11-01T09:00:00Z", }, }, }, } func makeFirmwareDoc(model string) *extractortest.MockDocument { return &extractortest.MockDocument{ URLValue: firmwarePageURL(model), MockNode: extractortest.MockNode{ Children: map[string]extractor.Nodes{ "script#__NEXT_DATA__": { &extractortest.MockNode{TextValue: makeNextDataJSON(samplePrinterMap)}, }, }, }, } } func TestExtractAllFirmware(t *testing.T) { doc := makeFirmwareDoc("x1") results, err := extractAllFirmware(doc, "x1") if err != nil { t.Fatalf("extractAllFirmware() error: %v", err) } if len(results) != 3 { t.Fatalf("len(results) = %d, want 3", len(results)) } // Should be sorted newest first if results[0].Version != "01.11.02.00" { t.Errorf("results[0].Version = %q, want %q", results[0].Version, "01.11.02.00") } if results[0].ReleaseDate != "2025-12-10" { t.Errorf("results[0].ReleaseDate = %q, want %q", results[0].ReleaseDate, "2025-12-10") } if results[0].MD5 != "1aa2c8400b4a3d599f8b4a09db60635c" { t.Errorf("results[0].MD5 = %q, want %q", results[0].MD5, "1aa2c8400b4a3d599f8b4a09db60635c") } if results[0].Model != "x1" { t.Errorf("results[0].Model = %q, want %q", results[0].Model, "x1") } if results[0].DownloadURL == "" { t.Error("results[0].DownloadURL is empty") } if results[0].ReleaseNotes == "" { t.Error("results[0].ReleaseNotes is empty") } // Second result if results[1].Version != "01.10.01.00" { t.Errorf("results[1].Version = %q, want %q", results[1].Version, "01.10.01.00") } if results[1].ReleaseDate != "2025-06-15" { t.Errorf("results[1].ReleaseDate = %q, want %q", results[1].ReleaseDate, "2025-06-15") } // Third result (oldest) if results[2].Version != "01.09.00.00" { t.Errorf("results[2].Version = %q, want %q", results[2].Version, "01.09.00.00") } } func TestExtractAllFirmware_UnknownModel(t *testing.T) { doc := makeFirmwareDoc("x1") _, err := extractAllFirmware(doc, "nonexistent") if err == nil { t.Fatal("expected error for unknown model, got nil") } } func TestExtractAllFirmware_NoScript(t *testing.T) { doc := &extractortest.MockDocument{ MockNode: extractortest.MockNode{ Children: map[string]extractor.Nodes{}, }, } _, err := extractAllFirmware(doc, "x1") if err == nil { t.Fatal("expected error for missing __NEXT_DATA__, got nil") } } func TestGetLatestFirmware_MockBrowser(t *testing.T) { doc := makeFirmwareDoc("x1") browser := &extractortest.MockBrowser{ Documents: map[string]*extractortest.MockDocument{ firmwarePageURL("x1"): doc, }, } fw, err := DefaultConfig.GetLatestFirmware(context.Background(), browser, "x1") if err != nil { t.Fatalf("GetLatestFirmware() error: %v", err) } if fw.Version != "01.11.02.00" { t.Errorf("Version = %q, want %q", fw.Version, "01.11.02.00") } if fw.ReleaseDate != "2025-12-10" { t.Errorf("ReleaseDate = %q, want %q", fw.ReleaseDate, "2025-12-10") } if fw.Model != "x1" { t.Errorf("Model = %q, want %q", fw.Model, "x1") } } func TestGetAllFirmware_MockBrowser(t *testing.T) { doc := makeFirmwareDoc("a1-mini") browser := &extractortest.MockBrowser{ Documents: map[string]*extractortest.MockDocument{ firmwarePageURL("a1-mini"): doc, }, } results, err := DefaultConfig.GetAllFirmware(context.Background(), browser, "a1-mini") if err != nil { t.Fatalf("GetAllFirmware() error: %v", err) } if len(results) != 1 { t.Fatalf("len(results) = %d, want 1", len(results)) } if results[0].Version != "01.05.00.00" { t.Errorf("Version = %q, want %q", results[0].Version, "01.05.00.00") } if results[0].Model != "a1-mini" { t.Errorf("Model = %q, want %q", results[0].Model, "a1-mini") } } func TestGetLatestFirmware_Convenience(t *testing.T) { doc := makeFirmwareDoc("x1") browser := &extractortest.MockBrowser{ Documents: map[string]*extractortest.MockDocument{ firmwarePageURL("x1"): doc, }, } fw, err := GetLatestFirmware(context.Background(), browser, "x1") if err != nil { t.Fatalf("GetLatestFirmware() error: %v", err) } if fw.Version != "01.11.02.00" { t.Errorf("Version = %q, want %q", fw.Version, "01.11.02.00") } } func TestGetAllFirmware_Convenience(t *testing.T) { doc := makeFirmwareDoc("x1") browser := &extractortest.MockBrowser{ Documents: map[string]*extractortest.MockDocument{ firmwarePageURL("x1"): doc, }, } results, err := GetAllFirmware(context.Background(), browser, "x1") if err != nil { t.Fatalf("GetAllFirmware() error: %v", err) } if len(results) != 3 { t.Fatalf("len(results) = %d, want 3", len(results)) } } func TestFirmwarePageURL(t *testing.T) { tests := []struct { model string want string }{ {"x1", "https://bambulab.com/en/support/firmware-download/x1"}, {"a1-mini", "https://bambulab.com/en/support/firmware-download/a1-mini"}, {"p1", "https://bambulab.com/en/support/firmware-download/p1"}, } for _, tt := range tests { got := firmwarePageURL(tt.model) if got != tt.want { t.Errorf("firmwarePageURL(%q) = %q, want %q", tt.model, got, tt.want) } } } func TestFormatReleaseDate(t *testing.T) { tests := []struct { input string want string }{ {"2025-12-10T12:01:58Z", "2025-12-10"}, {"2025-06-15T10:00:00Z", "2025-06-15"}, {"2025-03-01", "2025-03-01"}, {"invalid", "invalid"}, } for _, tt := range tests { got := formatReleaseDate(tt.input) if got != tt.want { t.Errorf("formatReleaseDate(%q) = %q, want %q", tt.input, got, tt.want) } } }