diff --git a/go.mod b/go.mod index f21be64..dc9e36a 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( ) require ( + github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/hajimehoshi/oto v0.7.1 // indirect github.com/micmonay/keybd_event v1.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 3346abb..5927eae 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c= github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= @@ -15,6 +17,7 @@ github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos= github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk= github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= diff --git a/src/device/input/parse/v01/config.go b/src/device/input/parse/v01/config.go index 8ef4294..0f983cf 100644 --- a/src/device/input/parse/v01/config.go +++ b/src/device/input/parse/v01/config.go @@ -1,5 +1,11 @@ package v01 +import ( + "encoding/json" + + patch "github.com/evanphx/json-patch/v5" +) + type config struct { Feedback struct { Addr string @@ -14,3 +20,24 @@ type config struct { } Quiet bool } + +func (cfg config) WithJSONPatch(v interface{}) config { + originalData, _ := json.Marshal(cfg) + patchData, err := json.Marshal(v) + if err != nil { + return cfg + } + patcher, err := patch.DecodePatch(patchData) + if err != nil { + return cfg + } + patchedData, err := patcher.Apply(originalData) + if err != nil { + return cfg + } + var patched config + if err := json.Unmarshal(patchedData, &patched); err != nil { + return cfg + } + return patched +} diff --git a/src/device/input/parse/v01/config_test.go b/src/device/input/parse/v01/config_test.go new file mode 100644 index 0000000..365e44b --- /dev/null +++ b/src/device/input/parse/v01/config_test.go @@ -0,0 +1,79 @@ +package v01 + +import ( + "fmt" + "testing" +) + +func TestConfigPatch(t *testing.T) { + cases := map[string]struct { + cfg config + patch interface{} + want config + }{ + "nil patch": { + cfg: config{Quiet: true}, + patch: nil, + want: config{Quiet: true}, + }, + "[] patch": { + cfg: config{Quiet: true}, + patch: []interface{}{}, + want: config{Quiet: true}, + }, + "set fake field": { + cfg: config{Quiet: true}, + patch: []interface{}{ + map[string]interface{}{"op": "add", "path": "/Fake", "value": true}, + }, + want: config{Quiet: true}, + }, + "remove field": { + cfg: config{Quiet: true}, + patch: []interface{}{ + map[string]interface{}{"op": "remove", "path": "/Quiet"}, + }, + want: config{Quiet: false}, + }, + "replace field with valid": { + cfg: config{Quiet: true}, + patch: []interface{}{ + map[string]interface{}{"op": "replace", "path": "/Quiet", "value": false}, + }, + want: config{Quiet: false}, + }, + "replace field with invalid": { + cfg: config{Quiet: true}, + patch: []interface{}{ + map[string]interface{}{"op": "replace", "path": "/Quiet", "value": "teehee"}, + }, + want: config{Quiet: true}, + }, + "test and noop": { + cfg: config{Quiet: true}, + patch: []interface{}{ + map[string]interface{}{"op": "test", "path": "/Quiet", "value": false}, + map[string]interface{}{"op": "replace", "path": "/Quiet", "value": false}, + }, + want: config{Quiet: true}, + }, + "test and apply": { + cfg: config{Quiet: true}, + patch: []interface{}{ + map[string]interface{}{"op": "test", "path": "/Quiet", "value": true}, + map[string]interface{}{"op": "replace", "path": "/Quiet", "value": false}, + }, + want: config{Quiet: false}, + }, + } + + for name, d := range cases { + c := d + t.Run(name, func(t *testing.T) { + got := c.cfg.WithJSONPatch(c.patch) + if fmt.Sprintf("%+v", got) != fmt.Sprintf("%+v", c.want) { + t.Errorf("(%+v).Patch(%+v) want %+v, got %+v", c.cfg, c.patch, c.want, got) + } + }) + } +}