package main import ( "encoding/json" "strings" "testing" ) // A profile stores effect names, and names belong to a board, so a profile has // to say which board it came from. Otherwise a profile written for one keyboard // is applied to another without a word. func TestProfileCarriesTheBoardIdentity(t *testing.T) { p := &Profile{Name: "x", Board: &Board{VendorID: "0x36B0", ProductID: "0x309F"}} data, err := json.MarshalIndent(p, "", " ") if err != nil { t.Fatalf("marshal: %v", err) } if !strings.Contains(string(data), `"vendorId": "0x36B0"`) { t.Errorf("profile JSON = %s, want the vendor ID", data) } if !strings.Contains(string(data), `"productId": "0x309F"`) { t.Errorf("profile JSON = %s, want the product ID", data) } var back Profile if err := json.Unmarshal(data, &back); err != nil { t.Fatalf("unmarshal: %v", err) } if back.Board == nil || back.Board.ProductID != "0x309F" { t.Errorf("round trip = %+v, want the board back", back.Board) } } // A profile written before the field existed must still load, and must not be // reported as a mismatch. func TestProfileWithoutABoardStillLoads(t *testing.T) { var p Profile if err := json.Unmarshal([]byte(`{"name":"old","version":1,"zones":{}}`), &p); err != nil { t.Fatalf("unmarshal: %v", err) } if p.Board != nil { t.Errorf("Board = %+v, want nil for a profile that has none", p.Board) } if got := p.MatchesBoard(0x36B0, 0x309F); got != boardUnknown { t.Errorf("MatchesBoard() = %v, want %v for a profile with no board", got, boardUnknown) } } func TestProfileBoardComparison(t *testing.T) { same := &Profile{Board: &Board{VendorID: "0x36B0", ProductID: "0x309F"}} other := &Profile{Board: &Board{VendorID: "0x1111", ProductID: "0x2222"}} tests := []struct { name string profile *Profile vendorID, prodID uint16 want boardMatch }{ {"same board", same, 0x36B0, 0x309F, boardSame}, {"other board", other, 0x36B0, 0x309F, boardOther}, {"no board", &Profile{}, 0x36B0, 0x309F, boardUnknown}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.profile.MatchesBoard(tt.vendorID, tt.prodID); got != tt.want { t.Errorf("MatchesBoard() = %v, want %v", got, tt.want) } }) } } // The warning has to name both keyboards, or the user cannot tell which // profile is the wrong one. func TestBoardMismatchWarningNamesBothKeyboards(t *testing.T) { p := &Profile{ Name: "paul", Board: &Board{VendorID: "0x1111", ProductID: "0x2222"}, } msg := p.boardMismatchWarning(0x36B0, 0x309F) for _, want := range []string{"paul", "0x1111/0x2222", "0x36B0/0x309F"} { if !strings.Contains(msg, want) { t.Errorf("warning = %q, want it to name %q", msg, want) } } } func TestBoardIdentityIsShownNextToTheName(t *testing.T) { p := &Profile{Name: "paul", Board: &Board{VendorID: "0x36B0", ProductID: "0x309F"}} line := p.listLine() if !strings.HasPrefix(line, "paul") { t.Errorf("listLine() = %q, want it to start with the name", line) } if !strings.Contains(line, "0x36B0/0x309F") { t.Errorf("listLine() = %q, want the board", line) } } // A profile with no board must not claim to belong to one. func TestListLineWithoutABoardSaysNothingAboutIt(t *testing.T) { line := (&Profile{Name: "old"}).listLine() if strings.Contains(line, "0x") { t.Errorf("listLine() = %q, want no board for a profile that has none", line) } }