|
@@ -4,6 +4,7 @@ import (
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
"os"
|
|
"os"
|
|
|
"path/filepath"
|
|
"path/filepath"
|
|
|
|
|
+ "strconv"
|
|
|
"strings"
|
|
"strings"
|
|
|
"testing"
|
|
"testing"
|
|
|
|
|
|
|
@@ -31,12 +32,16 @@ func (g generateStub) DetectChannels() ([]intvia.Channel, error) { return nil, n
|
|
|
|
|
|
|
|
func (g generateStub) Close() error { return nil }
|
|
func (g generateStub) Close() error { return nil }
|
|
|
|
|
|
|
|
-func stubGenerateTarget(t *testing.T, channels []intvia.Channel, tops map[intvia.Channel]int) {
|
|
|
|
|
|
|
+// stubGenerateTarget makes the connected keyboard a fixed one. The identifiers
|
|
|
|
|
+// are a parameter because a board the binary carries a definition for is the
|
|
|
|
|
+// case `generate` has to refuse, and a stub for the wrong board would test
|
|
|
|
|
+// nothing.
|
|
|
|
|
+func stubGenerateTarget(t *testing.T, vendorID, productID uint16, channels []intvia.Channel, tops map[intvia.Channel]int) {
|
|
|
t.Helper()
|
|
t.Helper()
|
|
|
original := openTarget
|
|
original := openTarget
|
|
|
t.Cleanup(func() { openTarget = original })
|
|
t.Cleanup(func() { openTarget = original })
|
|
|
openTarget = func(string) (rgbProtocol, targetDeviceData, []intvia.Channel, error) {
|
|
openTarget = func(string) (rgbProtocol, targetDeviceData, []intvia.Channel, error) {
|
|
|
- return generateStub{tops: tops}, stubTargetData(0x36B0, 0x309F), channels, nil
|
|
|
|
|
|
|
+ return generateStub{tops: tops}, stubTargetData(vendorID, productID), channels, nil
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -55,7 +60,7 @@ func TestGeneratedDefinitionNamesNoEffectUntilTheUserFillsItIn(t *testing.T) {
|
|
|
t.Cleanup(definitionFlagRestore(t))
|
|
t.Cleanup(definitionFlagRestore(t))
|
|
|
t.Cleanup(forceDefinitionsDir(t, dir))
|
|
t.Cleanup(forceDefinitionsDir(t, dir))
|
|
|
t.Cleanup(forceGenerateRestore(t))
|
|
t.Cleanup(forceGenerateRestore(t))
|
|
|
- stubGenerateTarget(t, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
|
|
+ stubGenerateTarget(t, 0x1234, 0x5678, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
|
|
|
cmd := NewKeyboardDefinitionsGenerateCmd()
|
|
cmd := NewKeyboardDefinitionsGenerateCmd()
|
|
|
var out, errOut strings.Builder
|
|
var out, errOut strings.Builder
|
|
@@ -146,9 +151,9 @@ func TestGenerateDoesNotReplaceAStoredDefinition(t *testing.T) {
|
|
|
t.Cleanup(definitionFlagRestore(t))
|
|
t.Cleanup(definitionFlagRestore(t))
|
|
|
t.Cleanup(forceDefinitionsDir(t, dir))
|
|
t.Cleanup(forceDefinitionsDir(t, dir))
|
|
|
t.Cleanup(forceGenerateRestore(t))
|
|
t.Cleanup(forceGenerateRestore(t))
|
|
|
- stubGenerateTarget(t, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
|
|
+ stubGenerateTarget(t, 0x1234, 0x5678, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
|
|
|
- written := `{"name":"Test Board","vendorId":"0x36B0","productId":"0x309F","menus":[],"note":"hand written"}`
|
|
|
|
|
|
|
+ written := `{"name":"Test Board","vendorId":"0x1234","productId":"0x5678","menus":[],"note":"hand written"}`
|
|
|
if err := os.WriteFile(filepath.Join(dir, "test_board.json"), []byte(written), 0o644); err != nil {
|
|
if err := os.WriteFile(filepath.Join(dir, "test_board.json"), []byte(written), 0o644); err != nil {
|
|
|
t.Fatal(err)
|
|
t.Fatal(err)
|
|
|
}
|
|
}
|
|
@@ -178,7 +183,7 @@ func TestGeneratedNoteCarriesTheSpellingsAndWhoWroteThem(t *testing.T) {
|
|
|
t.Cleanup(definitionFlagRestore(t))
|
|
t.Cleanup(definitionFlagRestore(t))
|
|
|
t.Cleanup(forceDefinitionsDir(t, dir))
|
|
t.Cleanup(forceDefinitionsDir(t, dir))
|
|
|
t.Cleanup(forceGenerateRestore(t))
|
|
t.Cleanup(forceGenerateRestore(t))
|
|
|
- stubGenerateTarget(t, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
|
|
+ stubGenerateTarget(t, 0x1234, 0x5678, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
|
|
|
cmd := NewKeyboardDefinitionsGenerateCmd()
|
|
cmd := NewKeyboardDefinitionsGenerateCmd()
|
|
|
var out, errOut strings.Builder
|
|
var out, errOut strings.Builder
|
|
@@ -230,3 +235,45 @@ func mustRead(t *testing.T, path string) string {
|
|
|
}
|
|
}
|
|
|
return string(data)
|
|
return string(data)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// A generated scaffold names no effect, so writing one for a board the binary
|
|
|
|
|
+// carries a definition for takes that board from 46 named effects to none — and
|
|
|
|
|
+// the file in the user directory is the one that is read. This is the whole
|
|
|
|
|
+// reason the built-in set is checked and not only the directory.
|
|
|
|
|
+func TestGenerateDoesNotShadowABuiltInDefinition(t *testing.T) {
|
|
|
|
|
+ dir := t.TempDir()
|
|
|
|
|
+ t.Cleanup(definitionFlagRestore(t))
|
|
|
|
|
+ t.Cleanup(forceDefinitionsDir(t, dir))
|
|
|
|
|
+ t.Cleanup(forceGenerateRestore(t))
|
|
|
|
|
+ // The Impact 80, whose definition is built into the binary.
|
|
|
|
|
+ stubGenerateTarget(t, 0x36B0, 0x309F, []intvia.Channel{intvia.ChannelRgbMatrix}, map[intvia.Channel]int{intvia.ChannelRgbMatrix: 45})
|
|
|
|
|
+
|
|
|
|
|
+ builtIn := 0
|
|
|
|
|
+ for _, def := range builtInDefinitions() {
|
|
|
|
|
+ if def.Matches(0x36B0, 0x309F) {
|
|
|
|
|
+ builtIn = namedEffectCount(def)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if builtIn == 0 {
|
|
|
|
|
+ t.Fatal("the binary carries no definition for 0x36B0/0x309F, so there is nothing to shadow")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ cmd := NewKeyboardDefinitionsGenerateCmd()
|
|
|
|
|
+ var out, errOut strings.Builder
|
|
|
|
|
+ cmd.SetOut(&out)
|
|
|
|
|
+ cmd.SetErr(&errOut)
|
|
|
|
|
+
|
|
|
|
|
+ err := cmd.Execute()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ t.Fatal("definitions generate = nil error, want a refusal to shadow a built-in definition")
|
|
|
|
|
+ }
|
|
|
|
|
+ if !strings.Contains(err.Error(), "carries a definition") {
|
|
|
|
|
+ t.Errorf("error = %q, want it to say the definition is one the binary carries", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if !strings.Contains(err.Error(), strconv.Itoa(builtIn)) {
|
|
|
|
|
+ t.Errorf("error = %q, want it to name how many effects would be lost (%d)", err, builtIn)
|
|
|
|
|
+ }
|
|
|
|
|
+ if entries, _ := filepath.Glob(filepath.Join(dir, "*.json")); len(entries) != 0 {
|
|
|
|
|
+ t.Errorf("definitions dir = %v, want nothing written", entries)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|