From b027a69b56afc884e9c6536a3cca01b138f1ea58 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 00:10:20 -0400 Subject: [PATCH 01/32] git: ignore docs and samples --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index de84c8d..d258bac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ +### Testing +# Local samples +samples/ + +### Documentation +# Generated docs +docs/ +doc/ + ### JetBrains # User-specific stuff .idea/**/workspace.xml From 4e490da73439172f6ad1ed40e9bbf9c3672674e1 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 18:59:54 -0400 Subject: [PATCH 02/32] add: types/pseudo --- types/pseudo/int-bool.go | 37 +++++++++++++++++ types/pseudo/int-bool_test.go | 58 +++++++++++++++++++++++++++ types/pseudo/message-struct.go | 51 ++++++++++++++++++++++++ types/pseudo/message-struct_test.go | 62 +++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 types/pseudo/int-bool.go create mode 100644 types/pseudo/int-bool_test.go create mode 100644 types/pseudo/message-struct.go create mode 100644 types/pseudo/message-struct_test.go diff --git a/types/pseudo/int-bool.go b/types/pseudo/int-bool.go new file mode 100644 index 0000000..c0170cd --- /dev/null +++ b/types/pseudo/int-bool.go @@ -0,0 +1,37 @@ +package pseudo + +import "encoding/json" + +// IntBool is a custom type that represents a boolean value as an integer. +// It is used for JSON marshaling and unmarshaling purposes. +type IntBool bool + +// MarshalJSON is a method that serializes the IntBool value to JSON format. +// It converts the boolean value to an integer (1 or 0), then marshals the integer to JSON. +// The method returns the marshaled JSON bytes and an error, if any. +func (b IntBool) MarshalJSON() ([]byte, error) { + var v int + if b { + v = 1 + } else { + v = 0 + } + + return json.Marshal(v) +} + +// UnmarshalJSON is a method that deserializes the JSON data into the IntBool value. +// It unmarshals the received JSON data into an integer value, then assigns the IntBool +// value based on whether the integer is non-zero or zero. The IntBool value is set to +// true if the integer is non-zero, and false if the integer is zero. +// The method returns an error if the unmarshaling process fails. +func (b *IntBool) UnmarshalJSON(data []byte) error { + var v int + err := json.Unmarshal(data, &v) + if err != nil { + return err + } + + *b = v != 0 + return nil +} diff --git a/types/pseudo/int-bool_test.go b/types/pseudo/int-bool_test.go new file mode 100644 index 0000000..7077303 --- /dev/null +++ b/types/pseudo/int-bool_test.go @@ -0,0 +1,58 @@ +package pseudo + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestIntBool_MarshalJSON(t *testing.T) { + type TestCase struct { + name string + ib IntBool + want string + wantErr bool + } + + tests := []TestCase{ + {name: "true", ib: true, want: "1", wantErr: false}, + {name: "false", ib: false, want: "0", wantErr: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.ib.MarshalJSON() + assert.NoError(t, err, "it should not error") + assert.Equal(t, got, []byte(tt.want)) + }) + } +} + +func TestIntBool_UnmarshalJSON(t *testing.T) { + type TestCase struct { + name string + json string + want IntBool + wantErr bool + } + + tests := []TestCase{ + {name: "number 1", json: "1", want: true, wantErr: false}, + {name: "number 0", json: "0", want: false, wantErr: false}, + {name: "non-number", json: `"foo"`, want: false, wantErr: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var i IntBool + err := i.UnmarshalJSON([]byte(tt.json)) + + if tt.wantErr { + assert.Error(t, err, "it should error", tt.json) + } else { + assert.NoError(t, err, "it should not error", tt.json) + assert.Equal(t, tt.want, i) + } + + }) + } +} diff --git a/types/pseudo/message-struct.go b/types/pseudo/message-struct.go new file mode 100644 index 0000000..b838533 --- /dev/null +++ b/types/pseudo/message-struct.go @@ -0,0 +1,51 @@ +package pseudo + +import ( + "encoding/json" + "fmt" + "strings" +) + +// MessageStruct represents a generic message structure that may be overridden by a string in the JSON representation. +type MessageStruct[T any] struct { + Value *T + Message string +} + +// MarshalJSON serializes the MessageStruct type to JSON representation. +// If MessageStruct has a non-empty Message or HasMessage is true, +// it marshals only the Message field as a string. Otherwise, it marshals the Value field. +// It returns a byte slice and an error. +func (ms MessageStruct[T]) MarshalJSON() ([]byte, error) { + if strings.TrimSpace(ms.Message) != "" { + return json.Marshal(ms.Message) + } + + return json.Marshal(ms.Value) +} + +// UnmarshalJSON deserializes JSON data into a MessageStruct pointer. +// If the JSON is a string, it assigns the string to the Message field. +// If the JSON is T, it assigns the value to the Value field. +// In case the JSON data cannot be unmarshaled into a string or T, it returns an error. +func (ms *MessageStruct[T]) UnmarshalJSON(data []byte) error { + err := UnmarshalMessageOrStruct(data, &ms.Message, &ms.Value) + if err != nil { + return err + } + + return nil +} + +// UnmarshalMessageOrStruct will unmarshal JSON data into a target message or struct depending on the +// actual representation in the JSON data. +// This aids in conditions where the data overrides an anticipated structure with an error message. +func UnmarshalMessageOrStruct(data []byte, targetMessage *string, targetStruct interface{}) error { + if err := json.Unmarshal(data, targetMessage); err == nil { + return nil + } + if err := json.Unmarshal(data, targetStruct); err == nil { + return nil + } + return fmt.Errorf("unable to unmarshal data as string or struct") +} diff --git a/types/pseudo/message-struct_test.go b/types/pseudo/message-struct_test.go new file mode 100644 index 0000000..b2222f0 --- /dev/null +++ b/types/pseudo/message-struct_test.go @@ -0,0 +1,62 @@ +package pseudo + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMessageStruct_MarshalJSON(t *testing.T) { + type TestCase struct { + name string + ms MessageStruct[int] + want string + } + + value := 5 + + tests := []TestCase{ + {name: "has Value has Message", ms: MessageStruct[int]{Value: &value, Message: "Test"}, want: `"Test"`}, + {name: "has Value no Message", ms: MessageStruct[int]{Value: &value, Message: ""}, want: `5`}, + {name: "no Value and Message", ms: MessageStruct[int]{Value: nil, Message: ""}, want: `null`}, + {name: "no Value has Message", ms: MessageStruct[int]{Value: nil, Message: "Test"}, want: `"Test"`}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.ms.MarshalJSON() + assert.NoError(t, err, "it should not error") + assert.Equal(t, []byte(tt.want), got) + }) + } +} + +func TestMessageStruct_UnmarshalJSON(t *testing.T) { + type TestCase struct { + name string + json string + want MessageStruct[int] + wantErr bool + } + + value := 5 + + tests := []TestCase{ + {name: "string message", json: `"here is a message"`, want: MessageStruct[int]{Message: "here is a message"}, wantErr: false}, + {name: "expected value", json: `5`, want: MessageStruct[int]{Value: &value, Message: ""}, wantErr: false}, + {name: "unexpected value", json: `{"not an int": true}`, wantErr: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got MessageStruct[int] + err := got.UnmarshalJSON([]byte(tt.json)) + + if tt.wantErr { + assert.Error(t, err, "it should return an error") + } else { + assert.NoError(t, err, "it should not return an error") + assert.Equal(t, got, tt.want) + } + }) + } +} From 7a7bd4e40a6620f3f7bf077de3b8926ceac6adef Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:02:45 -0400 Subject: [PATCH 03/32] github: add dependabot --- .github/dependabot.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yaml diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..4ca67ad --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: gomod + directory: / + schedule: + interval: daily \ No newline at end of file From 2e3f0e122a855853cfba4f2348d2fdd45b9ad1aa Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:15:57 -0400 Subject: [PATCH 04/32] github: add ci workflow --- .github/workflows/ci.yaml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..b2f1f74 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,39 @@ +on: + pull_request: + branches: + - main + paths-ignore: + - "**/*.md" + - "**/*.py" + - "LICENSE" + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + matrix: + go-version: [ '1.22.5' ] + + steps: + - uses: actions/checkout@v2 + - name: Setup Go ${{ matrix.go-version }} + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + - name: Install dependencies + run: go get . + - name: Test + run: | + go install github.com/jstemmer/go-junit-report/v2@latest + go test -short -timeout 120s -race -count 1 -v ./... 2>&1 | go-junit-report -set-exit-code -iocopy -out "${{ github.workspace }}/report.xml" + - name: Test summary + uses: test-summary/action@v2 + with: + paths: | + ${{ github.workspace }}/report.xml + if: always() + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file From 70a68082ff4f469d73acce587a5b353f0b51eb0a Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:16:19 -0400 Subject: [PATCH 05/32] go: add modules --- go.mod | 28 ++++++++++++++++++++++++++++ go.sum | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f965687 --- /dev/null +++ b/go.mod @@ -0,0 +1,28 @@ +module github.com/johnlettman/oyster + +go 1.22.5 + +require ( + github.com/barweiss/go-tuple v1.1.2 + github.com/ungerik/go3d v0.0.0-20240502073936-1137f6adf7e9 + gonum.org/v1/gonum v0.15.0 +) + +require ( + github.com/brianvoe/gofakeit/v7 v7.0.4 + github.com/google/gopacket v1.1.19 + github.com/gookit/goutil v0.6.15 + github.com/johnlettman/buffergenerics v0.0.0-20240713034920-8ec5b0a7ac46 + github.com/stretchr/testify v1.9.0 + golang.org/x/exp v0.0.0-20240707233637-46b078467d37 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..359b4ec --- /dev/null +++ b/go.sum @@ -0,0 +1,49 @@ +github.com/barweiss/go-tuple v1.1.2 h1:ul9tIW0LZ5w+Vk/Hi3X9z3JyqkD0yaVGZp+nNTLW2YE= +github.com/barweiss/go-tuple v1.1.2/go.mod h1:SpoVilkI7ycNrIkQxcQfS1JG5A+R40sWwEUlPONlp3k= +github.com/brianvoe/gofakeit/v7 v7.0.4 h1:Mkxwz9jYg8Ad8NvT9HA27pCMZGFQo08MK6jD0QTKEww= +github.com/brianvoe/gofakeit/v7 v7.0.4/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/johnlettman/buffergenerics v0.0.0-20240709235154-6055f9d0ee47 h1:JI8pHEl80NHs6/34N0/Xnlgg/CvTf8Db2nowWI/DNFM= +github.com/johnlettman/buffergenerics v0.0.0-20240709235154-6055f9d0ee47/go.mod h1:+MfOwzy5m3FiRgGnUs1uE1I7EMzu5obrrJaRkRYqCWA= +github.com/johnlettman/buffergenerics v0.0.0-20240713034920-8ec5b0a7ac46 h1:wzEFdKuHGwzhKqyBAVZga3UBDTvVJhVMI2J9kmaITdY= +github.com/johnlettman/buffergenerics v0.0.0-20240713034920-8ec5b0a7ac46/go.mod h1:+MfOwzy5m3FiRgGnUs1uE1I7EMzu5obrrJaRkRYqCWA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/ungerik/go3d v0.0.0-20240502073936-1137f6adf7e9 h1:wMWP16Ijw+W+IXGcAzrwQDua1NBB4tP8iWECpg5DVRQ= +github.com/ungerik/go3d v0.0.0-20240502073936-1137f6adf7e9/go.mod h1:ipEjrk2uLK4xX8ivWBPIVOD0fMtKyPI0strluUfIlYQ= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= +gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 0f3adfb12d3343b6d282245d7ea74b26f9c96b13 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:18:37 -0400 Subject: [PATCH 06/32] github: update ci branches --- .github/workflows/ci.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b2f1f74..c1d5f4f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,7 +1,8 @@ on: + push: + branches: [ main, devel ] pull_request: - branches: - - main + branches: [ main ] paths-ignore: - "**/*.md" - "**/*.py" From f876b497774e8b59cc95cfa42b2be98ad12678a7 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:30:20 -0400 Subject: [PATCH 07/32] github: update ci testing process --- .github/workflows/ci.yaml | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c1d5f4f..8827ead 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,29 +11,18 @@ on: jobs: test: runs-on: ubuntu-latest - - strategy: - matrix: - go-version: [ '1.22.5' ] - steps: - uses: actions/checkout@v2 - name: Setup Go ${{ matrix.go-version }} uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go-version }} - - name: Install dependencies - run: go get . - - name: Test + go-version-file: go.mod + - name: Run Tests run: | - go install github.com/jstemmer/go-junit-report/v2@latest - go test -short -timeout 120s -race -count 1 -v ./... 2>&1 | go-junit-report -set-exit-code -iocopy -out "${{ github.workspace }}/report.xml" - - name: Test summary - uses: test-summary/action@v2 - with: - paths: | - ${{ github.workspace }}/report.xml - if: always() + go install github.com/jstemmer/go-junit-report@latest + go test -v ./... | go-junit-report -set-exit-code > report.xml + - name: Summarize Tests + uses: test-summary/action@v1 - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 with: From 3073ee91970792e23d287021b8f550f5e7f12a82 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:32:04 -0400 Subject: [PATCH 08/32] github: add test summary paths --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8827ead..0668a34 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,6 +23,8 @@ jobs: go test -v ./... | go-junit-report -set-exit-code > report.xml - name: Summarize Tests uses: test-summary/action@v1 + with: + paths: report.xml - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 with: From 11ce1933c003c8cb62898ffd1543e967da8603f6 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 19:36:49 -0400 Subject: [PATCH 09/32] github: switch testing method --- .github/workflows/ci.yaml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0668a34..8e3c837 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,14 +17,10 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: go.mod - - name: Run Tests - run: | - go install github.com/jstemmer/go-junit-report@latest - go test -v ./... | go-junit-report -set-exit-code > report.xml - - name: Summarize Tests - uses: test-summary/action@v1 + - name: Test + uses: robherley/go-test-action@v0 with: - paths: report.xml + testArguments: -covermode=atomic -coverprofile=coverage.out ./... - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 with: From caf7bdf5f0454b926f68d7fd8a2eba5098383bfc Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 20:39:04 -0400 Subject: [PATCH 10/32] types: add AutoStartFlag --- types/auto-start-flag.go | 97 +++++++++++++++++++++++++ types/auto-start-flag_test.go | 133 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 types/auto-start-flag.go create mode 100644 types/auto-start-flag_test.go diff --git a/types/auto-start-flag.go b/types/auto-start-flag.go new file mode 100644 index 0000000..62a0779 --- /dev/null +++ b/types/auto-start-flag.go @@ -0,0 +1,97 @@ +package types + +import ( + "github.com/johnlettman/oyster/types/pseudo" + "strings" +) + +// AutoStartFlag represents a boolean flag used for enabling or disabling auto-start functionality. +// +// For additional information, refer to [Ouster docs: Standby Operating Mode Examples]. +// +// Warning: +// +// AutoStartFlag has been deprecated with firmware v2.4 and later. +// Usage of AutoStartFlag in firmware prior to v2.0.0 has unexpected behavior. +// +// [Ouster docs: Standby Operating Mode Examples]: https://static.ouster.dev/sensor-docs/image_route1/image_route2/sensor_operations/sensor-operations.html#standby-operating-mode-examples +type AutoStartFlag pseudo.IntBool + +const ( + AutoStartOn AutoStartFlag = true // Equivalent to OperatingMode "NORMAL" + AutoStartOff AutoStartFlag = false // Equivalent to OperatingMode "STANDBY" +) + +// String returns the string representation of an AutoStartFlag. +func (a AutoStartFlag) String() string { + switch a { + default: + fallthrough + case AutoStartOn: + return "auto start on" + case AutoStartOff: + return "auto start off" + } +} + +// GoString returns the Go syntax representation of an AutoStartFlag. +func (a AutoStartFlag) GoString() string { + switch a { + default: + fallthrough + case AutoStartOn: + return "AutoStartOn" + case AutoStartOff: + return "AutoStartOff" + } +} + +// MarshalText returns the text representation of an AutoStartFlag. +// +// - If the AutoStartFlag is AutoStartOff, it returns "off". +// - Otherwise, it returns "on". +// +// It always returns nil, indicating no error occurred. +func (a AutoStartFlag) MarshalText() ([]byte, error) { + switch a { + default: + fallthrough + case AutoStartOn: + return []byte("on"), nil + case AutoStartOff: + return []byte("off"), nil + } +} + +// UnmarshalText parses the provided text and assigns the corresponding value to the receiver. +// The method converts the input text to lowercase. +// +// - If the text is 'off', it assigns AutoStartOff to the receiver. +// - For any other text, it assigns AutoStartOn to the receiver. +// +// It always returns nil, indicating no error occurred. +func (a *AutoStartFlag) UnmarshalText(text []byte) error { + switch strings.ToLower(string(text)) { + default: + fallthrough + case "on": + *a = AutoStartOn + case "off": + *a = AutoStartOff + } + + return nil +} + +// MarshalJSON converts AutoStartFlag to JSON format using pseudo.IntBool.MarshalJSON method. +// It returns the JSON bytes and any occurred error. +func (a AutoStartFlag) MarshalJSON() ([]byte, error) { + return (*pseudo.IntBool)(&a).MarshalJSON() +} + +// UnmarshalJSON converts the JSON data into the AutoStartFlag value. +// It leverages the pseudo.IntBool.UnmarshalJSON method to perform the actual unmarshaling. +// It returns any occurred error. +func (a *AutoStartFlag) UnmarshalJSON(data []byte) error { + return (*pseudo.IntBool)(a).UnmarshalJSON(data) +} diff --git a/types/auto-start-flag_test.go b/types/auto-start-flag_test.go new file mode 100644 index 0000000..c7f6488 --- /dev/null +++ b/types/auto-start-flag_test.go @@ -0,0 +1,133 @@ +package types + +import ( + "github.com/brianvoe/gofakeit/v7" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestAutoStartFlag_String(t *testing.T) { + type TestCase struct { + a AutoStartFlag + want string + } + + cases := []TestCase{ + {AutoStartOn, "auto start on"}, + {AutoStartOff, "auto start off"}, + } + + for _, c := range cases { + got := c.a.String() + assert.Equal(t, c.want, got, "it should return the correct representation") + } +} + +func TestAutoStartFlag_GoString(t *testing.T) { + type TestCase struct { + a AutoStartFlag + want string + } + + cases := []TestCase{ + {AutoStartOn, "AutoStartOn"}, + {AutoStartOff, "AutoStartOff"}, + } + + for _, c := range cases { + got := c.a.GoString() + assert.Equal(t, c.want, got, "it should return the correct representation") + } +} + +func TestAutoStartFlag_MarshalText(t *testing.T) { + type TestCase struct { + a AutoStartFlag + want string + } + + cases := []TestCase{ + {AutoStartOn, "on"}, + {AutoStartOff, "off"}, + } + + for _, c := range cases { + got, err := c.a.MarshalText() + assert.NoError(t, err, "it should not error") + assert.Equal(t, []byte(c.want), got, "it should return the correct representation") + } +} + +func TestAutoStartFlag_UnmarshalText(t *testing.T) { + type TestCase struct { + name string + text string + want AutoStartFlag + } + + cases := []TestCase{ + {"lowercase 'on'", "on", AutoStartOn}, + {"lowercase 'off'", "off", AutoStartOff}, + {"uppercase 'ON'", "ON", AutoStartOn}, + {"uppercase 'OFF'", "OFF", AutoStartOff}, + {"random text", gofakeit.LoremIpsumSentence(4), AutoStartOn}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var a AutoStartFlag + err := a.UnmarshalText([]byte(c.text)) + assert.NoError(t, err, "it should not error") + assert.Equal(t, c.want, a, "it should assign the correct value") + }) + } + +} + +func TestAutoStartFlag_MarshalJSON(t *testing.T) { + type TestCase struct { + a AutoStartFlag + want string + } + + cases := []TestCase{ + {AutoStartOn, "1"}, + {AutoStartOff, "0"}, + } + + for _, c := range cases { + got, err := c.a.MarshalJSON() + assert.NoError(t, err, "it should not error") + assert.Equal(t, got, []byte(c.want), "it should provide the correct JSON using IntBool") + } +} + +func TestIntBool_UnmarshalJSON(t *testing.T) { + type TestCase struct { + name string + json string + want AutoStartFlag + wantErr bool + } + + cases := []TestCase{ + {name: "number 1", json: "1", want: true, wantErr: false}, + {name: "number 0", json: "0", want: false, wantErr: false}, + {name: "non-number", json: `"foo"`, want: false, wantErr: true}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var a AutoStartFlag + err := a.UnmarshalJSON([]byte(c.json)) + + if c.wantErr { + assert.Error(t, err, "it should error") + } else { + assert.NoError(t, err, "it should not error") + assert.Equal(t, c.want, a, "it should assign the correct value using IntBool") + } + + }) + } +} From a3a27e157793d7b3f1af083e8659819ca10a69cf Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:00:14 -0400 Subject: [PATCH 11/32] dependabot: track workflows --- .github/dependabot.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 4ca67ad..3b82f57 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -3,4 +3,13 @@ updates: - package-ecosystem: gomod directory: / schedule: - interval: daily \ No newline at end of file + interval: daily + + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + labels: + - "CI/CD" + commit-message: + prefix: "ci: " \ No newline at end of file From 2bf45f9ae36528ba4819db03ed27908684708944 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:13:23 -0400 Subject: [PATCH 12/32] github: add docs workflow, touch-up --- .github/workflows/ci.yaml | 2 +- .github/workflows/docs.yaml | 40 +++++++++++++++++++++++++++++++++++++ .gitignore | 1 - 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/docs.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8e3c837..931d9fe 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup Go ${{ matrix.go-version }} + - name: Setup Go uses: actions/setup-go@v5 with: go-version-file: go.mod diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 0000000..cf21fed --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,40 @@ +on: + push: + branches: [main, devel] + pull_request: + branches: [main] + paths-ignore: + - "**/*.md" + - "**/*.py" + - "LICENSE" + +jobs: + docs: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Build documentation + run: | + go install go.abhg.dev/doc2go@latest + doc2go -out docs ./... + - name: Deploy documentation to GitHub pages + if: github.ref == 'refs/heads/main' + uses: peaceiris/actions-gh-pages@v2.3.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUBLISH_BRANCH: gh-pages + PUBLISH_DIR: docs + - name: Upload documentation + uses: actions/upload-artifact@v1 + with: + name: documentation + path: docs \ No newline at end of file diff --git a/.gitignore b/.gitignore index d258bac..8c0493d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ samples/ ### Documentation # Generated docs docs/ -doc/ ### JetBrains # User-specific stuff From e2360ea585e51146e799138e56eeb0798c558034 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:16:48 -0400 Subject: [PATCH 13/32] pages: set devel as ref --- .github/workflows/docs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index cf21fed..d5d964a 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -27,7 +27,7 @@ jobs: go install go.abhg.dev/doc2go@latest doc2go -out docs ./... - name: Deploy documentation to GitHub pages - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/devel' uses: peaceiris/actions-gh-pages@v2.3.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b89a626bc1749c53be90a18033255bea1d39895e Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:26:43 -0400 Subject: [PATCH 14/32] pages: tidy commit messages --- .github/workflows/docs.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index d5d964a..3407bfe 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -30,9 +30,10 @@ jobs: if: github.ref == 'refs/heads/devel' uses: peaceiris/actions-gh-pages@v2.3.1 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PUBLISH_BRANCH: gh-pages - PUBLISH_DIR: docs + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./docs + commit_message: "Pages: ${{ github.event.head_commit.message }}" - name: Upload documentation uses: actions/upload-artifact@v1 with: From 7ae9fd1fc80c27751047b1497b8d162ac63140f9 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:28:16 -0400 Subject: [PATCH 15/32] pages: fix env --- .github/workflows/docs.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 3407bfe..a959685 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -30,10 +30,10 @@ jobs: if: github.ref == 'refs/heads/devel' uses: peaceiris/actions-gh-pages@v2.3.1 env: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: ./docs - commit_message: "Pages: ${{ github.event.head_commit.message }}" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUBLISH_BRANCH: gh-pages + PUBLISH_DIR: ./docs + COMMIT_MESSAGE: "Pages: ${{ github.event.head_commit.message }}" - name: Upload documentation uses: actions/upload-artifact@v1 with: From d02b6e67f2a24309dd0802c3234d73236cba676e Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:29:42 -0400 Subject: [PATCH 16/32] types/auto-start-flag_test: fix text name --- types/auto-start-flag_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/auto-start-flag_test.go b/types/auto-start-flag_test.go index c7f6488..1cea64a 100644 --- a/types/auto-start-flag_test.go +++ b/types/auto-start-flag_test.go @@ -102,7 +102,7 @@ func TestAutoStartFlag_MarshalJSON(t *testing.T) { } } -func TestIntBool_UnmarshalJSON(t *testing.T) { +func TestAutoStartFlag_UnmarshalJSON(t *testing.T) { type TestCase struct { name string json string From 4448504ad80f4dbebc8a0230b303b378080b127e Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:43:57 -0400 Subject: [PATCH 17/32] pages: use official action --- .github/workflows/docs.yaml | 47 ++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index a959685..c3a60e4 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -7,9 +7,16 @@ on: - "**/*.md" - "**/*.py" - "LICENSE" + workflow_dispatch: + inputs: + head: + description: "Git commit to publish documentation for." + required: true + type: string jobs: - docs: + build: + name: Build documentation runs-on: ubuntu-latest permissions: contents: write @@ -22,20 +29,38 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: go.mod - - name: Build documentation + cache: true + - name: Generate documentation run: | go install go.abhg.dev/doc2go@latest doc2go -out docs ./... - - name: Deploy documentation to GitHub pages - if: github.ref == 'refs/heads/devel' - uses: peaceiris/actions-gh-pages@v2.3.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PUBLISH_BRANCH: gh-pages - PUBLISH_DIR: ./docs - COMMIT_MESSAGE: "Pages: ${{ github.event.head_commit.message }}" - name: Upload documentation uses: actions/upload-artifact@v1 with: name: documentation - path: docs \ No newline at end of file + path: docs + - name: Upload pages + if: github.ref == 'refs/heads/devel' + uses: actions/upload-pages-artifact@v1 + with: + path: docs + + publish: + name: Publish pages website + needs: build + + permissions: + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub pages + if: github.ref == 'refs/heads/devel' + id: deployment + uses: actions/deploy-pages@v1 + From 318585a702222bbe517c11102801a50fd7e486a0 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:52:29 -0400 Subject: [PATCH 18/32] pages: add pagefind support --- .github/workflows/docs.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index c3a60e4..f28de2e 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -30,10 +30,13 @@ jobs: with: go-version-file: go.mod cache: true + - name: Setup Node + uses: actions/setup-node@v4 - name: Generate documentation run: | + npm install pagefind go install go.abhg.dev/doc2go@latest - doc2go -out docs ./... + doc2go -out docs -pagefind ./... - name: Upload documentation uses: actions/upload-artifact@v1 with: From e2c8a0d5411b16f010ba510c6cde8f1bf62b47dc Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:55:13 -0400 Subject: [PATCH 19/32] pages: correct pagefind directory --- .github/workflows/docs.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index f28de2e..e82eea5 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -35,8 +35,10 @@ jobs: - name: Generate documentation run: | npm install pagefind + export PAGEFIND="${HOME}/node_modules/.bin/pagefind" + go install go.abhg.dev/doc2go@latest - doc2go -out docs -pagefind ./... + doc2go -out docs -pagefind="${PAGEFIND}" ./... - name: Upload documentation uses: actions/upload-artifact@v1 with: From 9446c625c210b4f1e89dce24362c8d7f84ba7b12 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 21:58:59 -0400 Subject: [PATCH 20/32] pages: correct pagefind directory v2 --- .github/workflows/docs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index e82eea5..85049e0 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -34,8 +34,8 @@ jobs: uses: actions/setup-node@v4 - name: Generate documentation run: | - npm install pagefind - export PAGEFIND="${HOME}/node_modules/.bin/pagefind" + npm install pagefind --prefix ./node_modules + export PAGEFIND="./node_modules/.bin/pagefind" go install go.abhg.dev/doc2go@latest doc2go -out docs -pagefind="${PAGEFIND}" ./... From 0b1f47f3afe8954ffdd92cade2ad6d63f16d0e67 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 22:02:20 -0400 Subject: [PATCH 21/32] pages: correct pagefind directory v3 --- .github/workflows/docs.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 85049e0..af29f76 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -32,9 +32,12 @@ jobs: cache: true - name: Setup Node uses: actions/setup-node@v4 + with: + cache: 'npm' + cache-dependency-path: package-lock.json - name: Generate documentation run: | - npm install pagefind --prefix ./node_modules + npm install pagefind --prefix . export PAGEFIND="./node_modules/.bin/pagefind" go install go.abhg.dev/doc2go@latest From 6498e29acd520ac65acfba0644f0fcf840ed51df Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 22:03:05 -0400 Subject: [PATCH 22/32] pages: correct pagefind directory v4 - remove cache --- .github/workflows/docs.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index af29f76..c7f214d 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -32,9 +32,6 @@ jobs: cache: true - name: Setup Node uses: actions/setup-node@v4 - with: - cache: 'npm' - cache-dependency-path: package-lock.json - name: Generate documentation run: | npm install pagefind --prefix . From c0f6cc32669180e7fa334dea234740fc44cf0e3e Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 22:25:05 -0400 Subject: [PATCH 23/32] types/pseudo: normalize names --- .../pseudo/{int-bool.go => int-bool-json.go} | 16 ++--- types/pseudo/int-bool-json_test.go | 60 ++++++++++++++++++ types/pseudo/int-bool_test.go | 58 ----------------- ...age-struct.go => message-override-json.go} | 22 +++---- types/pseudo/message-override-json_test.go | 62 +++++++++++++++++++ types/pseudo/message-struct_test.go | 62 ------------------- 6 files changed, 141 insertions(+), 139 deletions(-) rename types/pseudo/{int-bool.go => int-bool-json.go} (67%) create mode 100644 types/pseudo/int-bool-json_test.go delete mode 100644 types/pseudo/int-bool_test.go rename types/pseudo/{message-struct.go => message-override-json.go} (60%) create mode 100644 types/pseudo/message-override-json_test.go delete mode 100644 types/pseudo/message-struct_test.go diff --git a/types/pseudo/int-bool.go b/types/pseudo/int-bool-json.go similarity index 67% rename from types/pseudo/int-bool.go rename to types/pseudo/int-bool-json.go index c0170cd..f1b475f 100644 --- a/types/pseudo/int-bool.go +++ b/types/pseudo/int-bool-json.go @@ -2,14 +2,14 @@ package pseudo import "encoding/json" -// IntBool is a custom type that represents a boolean value as an integer. +// IntBoolJSON is a custom type that represents a boolean value as an integer. // It is used for JSON marshaling and unmarshaling purposes. -type IntBool bool +type IntBoolJSON bool -// MarshalJSON is a method that serializes the IntBool value to JSON format. +// MarshalJSON is a method that serializes the IntBoolJSON value to JSON format. // It converts the boolean value to an integer (1 or 0), then marshals the integer to JSON. // The method returns the marshaled JSON bytes and an error, if any. -func (b IntBool) MarshalJSON() ([]byte, error) { +func (b IntBoolJSON) MarshalJSON() ([]byte, error) { var v int if b { v = 1 @@ -20,12 +20,12 @@ func (b IntBool) MarshalJSON() ([]byte, error) { return json.Marshal(v) } -// UnmarshalJSON is a method that deserializes the JSON data into the IntBool value. -// It unmarshals the received JSON data into an integer value, then assigns the IntBool -// value based on whether the integer is non-zero or zero. The IntBool value is set to +// UnmarshalJSON is a method that deserializes the JSON data into the IntBoolJSON value. +// It unmarshals the received JSON data into an integer value, then assigns the IntBoolJSON +// value based on whether the integer is non-zero or zero. The IntBoolJSON value is set to // true if the integer is non-zero, and false if the integer is zero. // The method returns an error if the unmarshaling process fails. -func (b *IntBool) UnmarshalJSON(data []byte) error { +func (b *IntBoolJSON) UnmarshalJSON(data []byte) error { var v int err := json.Unmarshal(data, &v) if err != nil { diff --git a/types/pseudo/int-bool-json_test.go b/types/pseudo/int-bool-json_test.go new file mode 100644 index 0000000..9e82c30 --- /dev/null +++ b/types/pseudo/int-bool-json_test.go @@ -0,0 +1,60 @@ +package pseudo + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestIntBoolJSON_MarshalJSON(t *testing.T) { + type TestCase struct { + name string + i IntBoolJSON + want string + wantErr bool + } + + cases := []TestCase{ + {name: "true", i: IntBoolJSON(true), want: "1", wantErr: false}, + {name: "false", i: IntBoolJSON(false), want: "0", wantErr: false}, + {name: "native true", i: true, want: "1", wantErr: false}, + {name: "native false", i: false, want: "0", wantErr: false}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got, err := c.i.MarshalJSON() + assert.NoError(t, err, "it should not error") + assert.Equal(t, got, []byte(c.want)) + }) + } +} + +func TestIntBoolJSON_UnmarshalJSON(t *testing.T) { + type TestCase struct { + name string + json string + want IntBoolJSON + wantErr bool + } + + cases := []TestCase{ + {name: "number 1", json: "1", want: true, wantErr: false}, + {name: "number 0", json: "0", want: false, wantErr: false}, + {name: "non-number", json: `"foo"`, want: false, wantErr: true}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var i IntBoolJSON + err := i.UnmarshalJSON([]byte(c.json)) + + if c.wantErr { + assert.Error(t, err, "it should error", c.json) + } else { + assert.NoError(t, err, "it should not error", c.json) + assert.Equal(t, c.want, i) + } + + }) + } +} diff --git a/types/pseudo/int-bool_test.go b/types/pseudo/int-bool_test.go deleted file mode 100644 index 7077303..0000000 --- a/types/pseudo/int-bool_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package pseudo - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestIntBool_MarshalJSON(t *testing.T) { - type TestCase struct { - name string - ib IntBool - want string - wantErr bool - } - - tests := []TestCase{ - {name: "true", ib: true, want: "1", wantErr: false}, - {name: "false", ib: false, want: "0", wantErr: false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.ib.MarshalJSON() - assert.NoError(t, err, "it should not error") - assert.Equal(t, got, []byte(tt.want)) - }) - } -} - -func TestIntBool_UnmarshalJSON(t *testing.T) { - type TestCase struct { - name string - json string - want IntBool - wantErr bool - } - - tests := []TestCase{ - {name: "number 1", json: "1", want: true, wantErr: false}, - {name: "number 0", json: "0", want: false, wantErr: false}, - {name: "non-number", json: `"foo"`, want: false, wantErr: true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var i IntBool - err := i.UnmarshalJSON([]byte(tt.json)) - - if tt.wantErr { - assert.Error(t, err, "it should error", tt.json) - } else { - assert.NoError(t, err, "it should not error", tt.json) - assert.Equal(t, tt.want, i) - } - - }) - } -} diff --git a/types/pseudo/message-struct.go b/types/pseudo/message-override-json.go similarity index 60% rename from types/pseudo/message-struct.go rename to types/pseudo/message-override-json.go index b838533..94f1064 100644 --- a/types/pseudo/message-struct.go +++ b/types/pseudo/message-override-json.go @@ -6,30 +6,30 @@ import ( "strings" ) -// MessageStruct represents a generic message structure that may be overridden by a string in the JSON representation. -type MessageStruct[T any] struct { +// MessageOverrideJSON represents a generic message structure that may be overridden by a string in the JSON representation. +type MessageOverrideJSON[T any] struct { Value *T Message string } -// MarshalJSON serializes the MessageStruct type to JSON representation. -// If MessageStruct has a non-empty Message or HasMessage is true, +// MarshalJSON serializes the MessageOverrideJSON type to JSON representation. +// If MessageOverrideJSON has a non-empty Message or HasMessage is true, // it marshals only the Message field as a string. Otherwise, it marshals the Value field. // It returns a byte slice and an error. -func (ms MessageStruct[T]) MarshalJSON() ([]byte, error) { - if strings.TrimSpace(ms.Message) != "" { - return json.Marshal(ms.Message) +func (m MessageOverrideJSON[T]) MarshalJSON() ([]byte, error) { + if strings.TrimSpace(m.Message) != "" { + return json.Marshal(m.Message) } - return json.Marshal(ms.Value) + return json.Marshal(m.Value) } -// UnmarshalJSON deserializes JSON data into a MessageStruct pointer. +// UnmarshalJSON deserializes JSON data into a MessageOverrideJSON pointer. // If the JSON is a string, it assigns the string to the Message field. // If the JSON is T, it assigns the value to the Value field. // In case the JSON data cannot be unmarshaled into a string or T, it returns an error. -func (ms *MessageStruct[T]) UnmarshalJSON(data []byte) error { - err := UnmarshalMessageOrStruct(data, &ms.Message, &ms.Value) +func (m *MessageOverrideJSON[T]) UnmarshalJSON(data []byte) error { + err := UnmarshalMessageOrStruct(data, &m.Message, &m.Value) if err != nil { return err } diff --git a/types/pseudo/message-override-json_test.go b/types/pseudo/message-override-json_test.go new file mode 100644 index 0000000..4c70fe9 --- /dev/null +++ b/types/pseudo/message-override-json_test.go @@ -0,0 +1,62 @@ +package pseudo + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMessageOverrideJSON_MarshalJSON(t *testing.T) { + type TestCase struct { + name string + m MessageOverrideJSON[int] + want string + } + + value := 5 + + cases := []TestCase{ + {name: "has Value has Message", m: MessageOverrideJSON[int]{Value: &value, Message: "Test"}, want: `"Test"`}, + {name: "has Value no Message", m: MessageOverrideJSON[int]{Value: &value, Message: ""}, want: `5`}, + {name: "no Value and Message", m: MessageOverrideJSON[int]{Value: nil, Message: ""}, want: `null`}, + {name: "no Value has Message", m: MessageOverrideJSON[int]{Value: nil, Message: "Test"}, want: `"Test"`}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got, err := c.m.MarshalJSON() + assert.NoError(t, err, "it should not error") + assert.Equal(t, []byte(c.want), got) + }) + } +} + +func TestMessageOverrideJSON_UnmarshalJSON(t *testing.T) { + type TestCase struct { + name string + json string + want MessageOverrideJSON[int] + wantErr bool + } + + value := 5 + + cases := []TestCase{ + {name: "string message", json: `"here is a message"`, want: MessageOverrideJSON[int]{Message: "here is a message"}, wantErr: false}, + {name: "expected value", json: `5`, want: MessageOverrideJSON[int]{Value: &value, Message: ""}, wantErr: false}, + {name: "unexpected value", json: `{"not an int": true}`, wantErr: true}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var got MessageOverrideJSON[int] + err := got.UnmarshalJSON([]byte(c.json)) + + if c.wantErr { + assert.Error(t, err, "it should return an error") + } else { + assert.NoError(t, err, "it should not return an error") + assert.Equal(t, got, c.want) + } + }) + } +} diff --git a/types/pseudo/message-struct_test.go b/types/pseudo/message-struct_test.go deleted file mode 100644 index b2222f0..0000000 --- a/types/pseudo/message-struct_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package pseudo - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestMessageStruct_MarshalJSON(t *testing.T) { - type TestCase struct { - name string - ms MessageStruct[int] - want string - } - - value := 5 - - tests := []TestCase{ - {name: "has Value has Message", ms: MessageStruct[int]{Value: &value, Message: "Test"}, want: `"Test"`}, - {name: "has Value no Message", ms: MessageStruct[int]{Value: &value, Message: ""}, want: `5`}, - {name: "no Value and Message", ms: MessageStruct[int]{Value: nil, Message: ""}, want: `null`}, - {name: "no Value has Message", ms: MessageStruct[int]{Value: nil, Message: "Test"}, want: `"Test"`}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.ms.MarshalJSON() - assert.NoError(t, err, "it should not error") - assert.Equal(t, []byte(tt.want), got) - }) - } -} - -func TestMessageStruct_UnmarshalJSON(t *testing.T) { - type TestCase struct { - name string - json string - want MessageStruct[int] - wantErr bool - } - - value := 5 - - tests := []TestCase{ - {name: "string message", json: `"here is a message"`, want: MessageStruct[int]{Message: "here is a message"}, wantErr: false}, - {name: "expected value", json: `5`, want: MessageStruct[int]{Value: &value, Message: ""}, wantErr: false}, - {name: "unexpected value", json: `{"not an int": true}`, wantErr: true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var got MessageStruct[int] - err := got.UnmarshalJSON([]byte(tt.json)) - - if tt.wantErr { - assert.Error(t, err, "it should return an error") - } else { - assert.NoError(t, err, "it should not return an error") - assert.Equal(t, got, tt.want) - } - }) - } -} From 1243040301e362a86b05d680b2c5fee294c585b0 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 22:53:05 -0400 Subject: [PATCH 24/32] types: add full-scale-range --- types/full-scale-range.go | 78 +++++++++++++++++++++++++++ types/full-scale-range_test.go | 96 ++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 types/full-scale-range.go create mode 100644 types/full-scale-range_test.go diff --git a/types/full-scale-range.go b/types/full-scale-range.go new file mode 100644 index 0000000..b68a78d --- /dev/null +++ b/types/full-scale-range.go @@ -0,0 +1,78 @@ +package types + +import ( + "strings" +) + +// FullScaleRange represents whether modification of the onboard gyroscope or accelerometer +// has been enabled with an extended programmable scale. +// +// For additional information, refer to [Ouster docs: gyro_fsr] and [Ouster docs: accel_fsr]. +// +// [Ouster docs: gyro_fsr]: https://static.ouster.dev/sensor-docs/image_route1/image_route2/common_sections/API/sensor_configuration_description.html#gyro-fsr +// [Ouster docs: accel_fsr]: https://static.ouster.dev/sensor-docs/image_route1/image_route2/common_sections/API/sensor_configuration_description.html#accel-fsr +type FullScaleRange uint8 + +const ( + FullScaleRangeNormal FullScaleRange = iota // Normal range. + FullScaleRangeExtended // Extended programmable scale. +) + +// String returns the string representation of a FullScaleRange value. +func (r FullScaleRange) String() string { + switch r { + default: + fallthrough + case FullScaleRangeNormal: + return "normal" + case FullScaleRangeExtended: + return "extended" + } +} + +// GoString returns the Go syntax representation of a FullScaleRange value. +func (r FullScaleRange) GoString() string { + switch r { + default: + fallthrough + case FullScaleRangeNormal: + return "FullScaleRangeNormal" + case FullScaleRangeExtended: + return "FullScaleRangeExtended" + } +} + +// MarshalText returns the text representation of an FullScaleRange. +// - If the FullScaleRange is FullScaleRangeExtended, it returns "EXTENDED"; +// - otherwise, it returns "NORMAL". +// +// It always returns nil error, indicating no error occurred. +func (r FullScaleRange) MarshalText() ([]byte, error) { + switch r { + default: + fallthrough + case FullScaleRangeNormal: + return []byte("NORMAL"), nil + case FullScaleRangeExtended: + return []byte("EXTENDED"), nil + } +} + +// UnmarshalText parses the provided text and assigns the corresponding value to the receiver. +// The method converts the input text to uppercase. +// - If the text is 'EXTENDED', it assigns FullScaleRangeNormal to the receiver. +// - For any other text, it assigns AutoStartOn to the receiver. +// +// It always returns nil error, indicating no error occurred. +func (r *FullScaleRange) UnmarshalText(text []byte) error { + switch strings.ToUpper(string(text)) { + default: + fallthrough + case "NORMAL": + *r = FullScaleRangeNormal + case "EXTENDED": + *r = FullScaleRangeExtended + } + + return nil +} diff --git a/types/full-scale-range_test.go b/types/full-scale-range_test.go new file mode 100644 index 0000000..3f1b255 --- /dev/null +++ b/types/full-scale-range_test.go @@ -0,0 +1,96 @@ +package types + +import ( + "github.com/brianvoe/gofakeit/v7" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestFullScaleRange_String(t *testing.T) { + type TestCase struct { + name string + r FullScaleRange + want string + } + + cases := []TestCase{ + {"FullScaleRangeNormal", FullScaleRangeNormal, "normal"}, + {"FullScaleRangeExtended", FullScaleRangeExtended, "extended"}, + {"unknown value", FullScaleRangeExtended + 1, "normal"}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.r.String() + assert.Equal(t, c.want, got, "it should return the correct representation") + }) + } +} + +func TestFullScaleRange_GoString(t *testing.T) { + type TestCase struct { + name string + r FullScaleRange + want string + } + + cases := []TestCase{ + {"FullScaleRangeNormal", FullScaleRangeNormal, "FullScaleRangeNormal"}, + {"FullScaleRangeExtended", FullScaleRangeExtended, "FullScaleRangeExtended"}, + {"unknown value", FullScaleRangeExtended + 1, "FullScaleRangeNormal"}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.r.GoString() + assert.Equal(t, c.want, got, "it should return the correct representation") + }) + } +} + +func TestFullScaleRange_MarshalText(t *testing.T) { + type TestCase struct { + name string + r FullScaleRange + want string + } + + cases := []TestCase{ + {"FullScaleRangeNormal", FullScaleRangeNormal, "NORMAL"}, + {"FullScaleRangeExtended", FullScaleRangeExtended, "EXTENDED"}, + {"unknown value", FullScaleRangeExtended + 1, "NORMAL"}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got, err := c.r.MarshalText() + assert.NoError(t, err, "it should not error") + assert.Equal(t, []byte(c.want), got, "it should return the correct representation") + }) + } +} + +func TestFullScaleRange_UnmarshalText(t *testing.T) { + type TestCase struct { + name string + text string + want FullScaleRange + } + + cases := []TestCase{ + {"lowercase 'normal'", "normal", FullScaleRangeNormal}, + {"lowercase 'extended'", "extended", FullScaleRangeExtended}, + {"uppercase 'NORMAL'", "NORMAL", FullScaleRangeNormal}, + {"uppercase 'EXTENDED'", "EXTENDED", FullScaleRangeExtended}, + {"random text", gofakeit.LoremIpsumSentence(4), FullScaleRangeNormal}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var a FullScaleRange + err := a.UnmarshalText([]byte(c.text)) + assert.NoError(t, err, "it should not error") + assert.Equal(t, c.want, a, "it should assign the correct value") + }) + } +} From 4508497130e5a291c659bbac305ee45bf3ee08bd Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 23:25:48 -0400 Subject: [PATCH 25/32] types: lidar-mode --- types/lidar-mode.go | 138 ++++++++++++++++++++++++++++++++ types/lidar-mode_test.go | 166 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 types/lidar-mode.go create mode 100644 types/lidar-mode_test.go diff --git a/types/lidar-mode.go b/types/lidar-mode.go new file mode 100644 index 0000000..d49f42d --- /dev/null +++ b/types/lidar-mode.go @@ -0,0 +1,138 @@ +package types + +import ( + "github.com/johnlettman/oyster/util" +) + +// LIDARMode represents the horizontal resolution and rotation rate of the sensor. +// The effective range of the sensor is increased by 15-20% for every halving of the number of points gathered. +// For example, LidarMode512x10 has a 15-20% longer range than LidarMode512x20. +// +// LIDARMode implements encoding/json.Marshaller and encoding/json.Unmarshaller +// to simplify loading from ouster_meta.json +// +// For additional information, refer to [Ouster docs: lidar_mode]. +// +// [Ouster docs: lidar_mode]: https://static.ouster.dev/sensor-docs/image_route1/image_route2/common_sections/API/sensor_configuration_description.html?highlight=512x10#lidar-mode +type LIDARMode int + +const ( + LidarModeUnknown LIDARMode = iota // unspecified + LidarMode512x10 // 10 scans of 512 columns per second + LidarMode512x20 // 20 scans of 512 columns per second + LidarMode1024x10 // 10 scans of 1024 columns per second + LidarMode1024x20 // 20 scans of 1024 columns per second + LidarMode2048x10 // 10 scans of 2048 columns per second + LidarMode4096x5 // 5 scans of 4096 columns per second +) + +var lidarModeGoKV = map[LIDARMode]string{ + LidarModeUnknown: "LidarModeUnknown", + LidarMode512x10: "LidarMode512x10", + LidarMode512x20: "LidarMode512x20", + LidarMode1024x10: "LidarMode1024x10", + LidarMode1024x20: "LidarMode1024x20", + LidarMode2048x10: "LidarMode2048x10", + LidarMode4096x5: "LidarMode4096x5", +} + +// lidarModeKV maps LIDARMode values to their respective string representations. +var lidarModeKV = map[LIDARMode]string{ + LidarModeUnknown: "unknown", + LidarMode512x10: "512x10", + LidarMode512x20: "512x20", + LidarMode1024x10: "1024x10", + LidarMode1024x20: "1024x20", + LidarMode2048x10: "2048x10", + LidarMode4096x5: "4096x5", +} + +// lidarModeVK is a variable that stores the reverse mapping of the lidarModeKV map. +// It maps string representations of LIDARMode values to their respective LIDARMode values. +var lidarModeVK = util.ReverseMap(lidarModeKV) + +// String returns the string representation of a LIDARMode value. +// If no match is found, it returns "unknown" as the default string representation. +func (m LIDARMode) String() string { + if s, ok := lidarModeKV[m]; ok { + return s + } + + return lidarModeKV[LidarModeUnknown] +} + +// GoString returns the Go syntax representation of a LIDARMode value. +// If no match is found, it returns "LidarModeUnknown" as the default string representation. +func (m LIDARMode) GoString() string { + if s, ok := lidarModeGoKV[m]; ok { + return s + } + + return lidarModeGoKV[LidarModeUnknown] +} + +// MarshalText returns the text representation of a LIDARMode value. +// - If the LIDARMode has a matching string representation in the lidarModeKV map, +// it returns the byte slice of that string representation. +// - If no match is found, it returns nil. +// +// The error returned is always nil. +func (m LIDARMode) MarshalText() ([]byte, error) { + if s, ok := lidarModeKV[m]; ok { + return []byte(s), nil + } + + return []byte{}, nil +} + +// UnmarshalText unmarshals the given text into a LIDARMode value. +// - If the string representation of the text exists in the lidarModeVK map, +// it assigns the corresponding LIDARMode value to the receiver pointer. +// - Otherwise, it assigns LidarModeUnknown to the receiver pointer. +// +// The error returned is always nil. +func (m *LIDARMode) UnmarshalText(text []byte) error { + if mode, ok := lidarModeVK[string(text)]; ok { + *m = mode + } else { + *m = LidarModeUnknown + } + + return nil +} + +// Columns returns the number of columns for a given LIDARMode value. +// It returns 0 if the LIDARMode is unknown or not specified. +func (m LIDARMode) Columns() int { + switch m { + default: + fallthrough + case LidarModeUnknown: + return 0 + case LidarMode512x10, LidarMode512x20: + return 512 + case LidarMode1024x10, LidarMode1024x20: + return 1024 + case LidarMode2048x10: + return 2048 + case LidarMode4096x5: + return 4096 + } +} + +// Frequency returns the frequency (number of scans per second) for a given LIDARMode value. +// It returns 0 if the LIDARMode is unknown or not specified. +func (m LIDARMode) Frequency() int { + switch m { + default: + fallthrough + case LidarModeUnknown: + return 0 + case LidarMode512x20, LidarMode1024x20: + return 20 + case LidarMode512x10, LidarMode1024x10, LidarMode2048x10: + return 10 + case LidarMode4096x5: + return 5 + } +} diff --git a/types/lidar-mode_test.go b/types/lidar-mode_test.go new file mode 100644 index 0000000..2b93c30 --- /dev/null +++ b/types/lidar-mode_test.go @@ -0,0 +1,166 @@ +package types + +import ( + "github.com/brianvoe/gofakeit/v7" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLIDARMode_String(t *testing.T) { + type TestCase struct { + name string + m LIDARMode + want string + } + + cases := []TestCase{ + {"LIDARModeUnknown", LidarModeUnknown, "unknown"}, + {"LidarMode512x10", LidarMode512x10, "512x10"}, + {"LidarMode512x20", LidarMode512x20, "512x20"}, + {"LidarMode1024x10", LidarMode1024x10, "1024x10"}, + {"LidarMode1024x20", LidarMode1024x20, "1024x20"}, + {"LidarMode2048x10", LidarMode2048x10, "2048x10"}, + {"LidarMode4096x5", LidarMode4096x5, "4096x5"}, + {"unknown value", LidarMode4096x5 + 1, "unknown"}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.m.String() + assert.Equal(t, c.want, got, "it should return the correct representation") + }) + } +} + +func TestLIDARMode_GoString(t *testing.T) { + type TestCase struct { + name string + m LIDARMode + want string + } + + cases := []TestCase{ + {"LIDARModeUnknown", LidarModeUnknown, "LidarModeUnknown"}, + {"LidarMode512x10", LidarMode512x10, "LidarMode512x10"}, + {"LidarMode512x20", LidarMode512x20, "LidarMode512x20"}, + {"LidarMode1024x10", LidarMode1024x10, "LidarMode1024x10"}, + {"LidarMode1024x20", LidarMode1024x20, "LidarMode1024x20"}, + {"LidarMode2048x10", LidarMode2048x10, "LidarMode2048x10"}, + {"LidarMode4096x5", LidarMode4096x5, "LidarMode4096x5"}, + {"unknown value", LidarMode4096x5 + 1, "LidarModeUnknown"}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.m.GoString() + assert.Equal(t, c.want, got, "it should return the correct representation") + }) + } +} + +func TestLIDARMode_MarshalText(t *testing.T) { + type TestCase struct { + name string + m LIDARMode + want string + } + + cases := []TestCase{ + {"LIDARModeUnknown", LidarModeUnknown, "unknown"}, + {"LidarMode512x10", LidarMode512x10, "512x10"}, + {"LidarMode512x20", LidarMode512x20, "512x20"}, + {"LidarMode1024x10", LidarMode1024x10, "1024x10"}, + {"LidarMode1024x20", LidarMode1024x20, "1024x20"}, + {"LidarMode2048x10", LidarMode2048x10, "2048x10"}, + {"LidarMode4096x5", LidarMode4096x5, "4096x5"}, + {"unknown value", LidarMode4096x5 + 1, ""}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got, err := c.m.MarshalText() + assert.NoError(t, err, "it should not error") + assert.Equal(t, []byte(c.want), got, "it should return the correct representation") + }) + } +} + +func TestLIDARMode_UnmarshalText(t *testing.T) { + type TestCase struct { + name string + text string + want LIDARMode + } + + cases := []TestCase{ + {"LIDARModeUnknown", "unknown", LidarModeUnknown}, + {"LidarMode512x10", "512x10", LidarMode512x10}, + {"LidarMode512x20", "512x20", LidarMode512x20}, + {"LidarMode1024x10", "1024x10", LidarMode1024x10}, + {"LidarMode1024x20", "1024x20", LidarMode1024x20}, + {"LidarMode2048x10", "2048x10", LidarMode2048x10}, + {"LidarMode4096x5", "4096x5", LidarMode4096x5}, + {"random text", gofakeit.LoremIpsumSentence(4), LidarModeUnknown}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var m LIDARMode + err := m.UnmarshalText([]byte(c.text)) + assert.NoError(t, err, "it should not error") + assert.Equal(t, c.want, m, "it should assign the correct value") + }) + } +} + +func TestLIDARMode_Columns(t *testing.T) { + type TestCase struct { + name string + m LIDARMode + want int + } + + cases := []TestCase{ + {"LIDARModeUnknown", LidarModeUnknown, 0}, + {"LIDARMode512x10", LidarMode512x10, 512}, + {"LIDARMode512x20", LidarMode512x20, 512}, + {"LIDARMode1024x10", LidarMode1024x10, 1024}, + {"LIDARMode1024x20", LidarMode1024x20, 1024}, + {"LIDARMode2048x10", LidarMode2048x10, 2048}, + {"LIDARMode4096x5", LidarMode4096x5, 4096}, + {"unknown value", LidarMode4096x5 + 1, 0}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.m.Columns() + assert.Equal(t, c.want, got, "it should return the correct number of columns") + }) + } +} + +func TestLIDARMode_Frequency(t *testing.T) { + type TestCase struct { + name string + m LIDARMode + want int + } + + cases := []TestCase{ + {"LIDARModeUnknown", LidarModeUnknown, 0}, + {"LIDARMode512x10", LidarMode512x10, 10}, + {"LIDARMode512x20", LidarMode512x20, 20}, + {"LIDARMode1024x10", LidarMode1024x10, 10}, + {"LIDARMode1024x20", LidarMode1024x20, 20}, + {"LIDARMode2048x10", LidarMode2048x10, 10}, + {"LIDARMode4096x5", LidarMode4096x5, 5}, + {"unknown value", LidarMode4096x5 + 1, 0}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.m.Frequency() + assert.Equal(t, c.want, got, "it should return the correct number of columns") + }) + } +} From ff201725e5827809d48cb03074c69e7e4cb9ca91 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Mon, 15 Jul 2024 23:32:51 -0400 Subject: [PATCH 26/32] util: add maps --- util/maps.go | 10 ++++++++++ util/maps_test.go | 12 ++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 util/maps.go create mode 100644 util/maps_test.go diff --git a/util/maps.go b/util/maps.go new file mode 100644 index 0000000..9e6f9d6 --- /dev/null +++ b/util/maps.go @@ -0,0 +1,10 @@ +package util + +// ReverseMap reverses the key-value pairs of the input map and returns a new map. +func ReverseMap[K, V comparable](in map[K]V) map[V]K { + out := make(map[V]K, len(in)) + for k, v := range in { + out[v] = k + } + return out +} diff --git a/util/maps_test.go b/util/maps_test.go new file mode 100644 index 0000000..5c0da09 --- /dev/null +++ b/util/maps_test.go @@ -0,0 +1,12 @@ +package util + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestReverseMap(t *testing.T) { + input := map[string]string{"a": "z"} + got := ReverseMap(input) + assert.Equal(t, got["z"], "a", "it should reverse the map") +} From cf3f587e1dac6f5914ee3ab985aea0c33419b728 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Tue, 16 Jul 2024 00:37:01 -0400 Subject: [PATCH 27/32] util: add math --- util/math.go | 11 +++++++ util/math_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 util/math.go create mode 100644 util/math_test.go diff --git a/util/math.go b/util/math.go new file mode 100644 index 0000000..78b070d --- /dev/null +++ b/util/math.go @@ -0,0 +1,11 @@ +package util + +import "golang.org/x/exp/constraints" + +// Abs returns the absolute value of x. If x is negative, it returns -x. +func Abs[I constraints.Integer | constraints.Float](x I) I { + if x < 0 { + return -x + } + return x +} diff --git a/util/math_test.go b/util/math_test.go new file mode 100644 index 0000000..56eaffb --- /dev/null +++ b/util/math_test.go @@ -0,0 +1,73 @@ +package util + +import ( + "github.com/stretchr/testify/assert" + "golang.org/x/exp/constraints" + "testing" +) + +import "github.com/brianvoe/gofakeit/v7" + +type TestCaseAbs[T constraints.Integer | constraints.Float] struct { + Input T + Want T +} + +const CaseCountAbs = 10 + +var testAbsFakeFunctions = map[string]func() interface{}{ + "uint8": func() interface{} { return gofakeit.Uint8() }, + "uint16": func() interface{} { return gofakeit.Uint16() }, + "uint32": func() interface{} { return gofakeit.Uint32() }, + "uint64": func() interface{} { return gofakeit.Uint64() }, + "int8": func() interface{} { return gofakeit.Int8() }, + "int16": func() interface{} { return gofakeit.Int16() }, + "int32": func() interface{} { return gofakeit.Int32() }, + "int64": func() interface{} { return gofakeit.Int64() }, + "float32": func() interface{} { return gofakeit.Float32() }, + "float64": func() interface{} { return gofakeit.Float64() }, +} + +func testAbsCase[T constraints.Integer | constraints.Float](t *testing.T, c TestCaseAbs[T]) { + got := Abs(c.Input) + assert.Equalf(t, got, c.Want, "it should return %v for %v with generic of type %T", c.Want, got, *new(T)) +} + +func testAbsGeneric[T constraints.Integer | constraints.Float](t *testing.T) { + n := TypeName(*new(T)) + f, ok := testAbsFakeFunctions[n] + if !ok { + t.Fatalf("can not locate randomizer function for type %s", n) + return + } + + t.Run(n, func(t *testing.T) { + for i := 0; i < CaseCountAbs; i++ { + test := TestCaseAbs[T]{} + input := f().(T) + + test.Input = input + + if input < 0 { + test.Want = -input + } else { + test.Want = input + } + + testAbsCase(t, test) + } + }) +} + +func TestAbs(t *testing.T) { + testAbsGeneric[uint8](t) + testAbsGeneric[uint16](t) + testAbsGeneric[uint32](t) + testAbsGeneric[uint64](t) + testAbsGeneric[int8](t) + testAbsGeneric[int16](t) + testAbsGeneric[int32](t) + testAbsGeneric[int64](t) + testAbsGeneric[float32](t) + testAbsGeneric[float64](t) +} From 3ce454dfa8f7c8e84e21e1b4b08a8374342c1204 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Tue, 16 Jul 2024 01:09:07 -0400 Subject: [PATCH 28/32] util: add paths --- go.mod | 3 +- go.sum | 10 ++++- util/paths.go | 49 ++++++++++++++++++++ util/paths_test.go | 110 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 util/paths.go create mode 100644 util/paths_test.go diff --git a/go.mod b/go.mod index f965687..c6403d1 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( ) require ( + github.com/agiledragon/gomonkey/v2 v2.12.0 github.com/brianvoe/gofakeit/v7 v7.0.4 github.com/google/gopacket v1.1.19 github.com/gookit/goutil v0.6.15 @@ -19,9 +20,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gookit/color v1.5.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 359b4ec..99a02d5 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/agiledragon/gomonkey/v2 v2.12.0 h1:ek0dYu9K1rSV+TgkW5LvNNPRWyDZVIxGMCFI6Pz9o38= +github.com/agiledragon/gomonkey/v2 v2.12.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/barweiss/go-tuple v1.1.2 h1:ul9tIW0LZ5w+Vk/Hi3X9z3JyqkD0yaVGZp+nNTLW2YE= github.com/barweiss/go-tuple v1.1.2/go.mod h1:SpoVilkI7ycNrIkQxcQfS1JG5A+R40sWwEUlPONlp3k= github.com/brianvoe/gofakeit/v7 v7.0.4 h1:Mkxwz9jYg8Ad8NvT9HA27pCMZGFQo08MK6jD0QTKEww= @@ -10,12 +12,14 @@ github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= -github.com/johnlettman/buffergenerics v0.0.0-20240709235154-6055f9d0ee47 h1:JI8pHEl80NHs6/34N0/Xnlgg/CvTf8Db2nowWI/DNFM= -github.com/johnlettman/buffergenerics v0.0.0-20240709235154-6055f9d0ee47/go.mod h1:+MfOwzy5m3FiRgGnUs1uE1I7EMzu5obrrJaRkRYqCWA= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/johnlettman/buffergenerics v0.0.0-20240713034920-8ec5b0a7ac46 h1:wzEFdKuHGwzhKqyBAVZga3UBDTvVJhVMI2J9kmaITdY= github.com/johnlettman/buffergenerics v0.0.0-20240713034920-8ec5b0a7ac46/go.mod h1:+MfOwzy5m3FiRgGnUs1uE1I7EMzu5obrrJaRkRYqCWA= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ungerik/go3d v0.0.0-20240502073936-1137f6adf7e9 h1:wMWP16Ijw+W+IXGcAzrwQDua1NBB4tP8iWECpg5DVRQ= @@ -28,6 +32,7 @@ golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJI golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -39,6 +44,7 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= diff --git a/util/paths.go b/util/paths.go new file mode 100644 index 0000000..83d101c --- /dev/null +++ b/util/paths.go @@ -0,0 +1,49 @@ +package util + +import ( + "os" + "path/filepath" + "runtime" + "strings" +) + +// NormalizePath removes extraneous spaces, new lines, and carriage returns from the given path. +// - If the path starts with a tilde (~) character, +// it replaces the tilde with the user's home directory. +// - It then cleans the path to remove extra separators and dots. +// - Finally, it converts the path to its absolute form if possible. +// - If not, it returns the cleaned path. +func NormalizePath(path string) string { + // remove extraneous spaces + path = strings.TrimSpace(path) // extra space at start and end + path = strings.ReplaceAll(path, "\n", "") // new lines + path = strings.ReplaceAll(path, "\r", "") // carriage returns + + // replace instances of the tilde user home directory shorthand + if strings.HasPrefix(path, "~") { + home, err := os.UserHomeDir() + if err == nil { + path = strings.Replace(path, "~", home, 1) + } + } + + // clean the path to remove extra separators and dots + cleaned := filepath.Clean(path) + + // convert the path to its absolute form + if normalized, err := filepath.Abs(cleaned); err == nil { + return normalized + } + + // use the cleaned path if we can't get an absolute + return cleaned +} + +func ProjectRootDir() string { + _, caller, _, _ := runtime.Caller(0) + return NormalizePath(filepath.Join(filepath.Dir(caller), "..")) +} + +func ProjectDir(elem ...string) string { + return NormalizePath(filepath.Join(ProjectRootDir(), filepath.Join(elem...))) +} diff --git a/util/paths_test.go b/util/paths_test.go new file mode 100644 index 0000000..2e13200 --- /dev/null +++ b/util/paths_test.go @@ -0,0 +1,110 @@ +package util + +import ( + "github.com/agiledragon/gomonkey/v2" + "github.com/stretchr/testify/assert" + "os" + "os/exec" + "path/filepath" + "syscall" + "testing" +) + +func gitProjectDir() (string, error) { + cmd := exec.Command("git", "rev-parse", "--show-toplevel") + gitOutput, err := cmd.Output() + if err != nil { + return "", err + } + + return NormalizePath(string(gitOutput)), nil +} + +func TestProjectRootDir(t *testing.T) { + want, err := gitProjectDir() + if err != nil { + t.Fatalf("failed to determine git project dir: %v", err) + } + + got := ProjectRootDir() + assert.Equalf(t, got, want, "it should match the git project root %s", want) +} + +func TestProjectDir(t *testing.T) { + git, err := gitProjectDir() + if err != nil { + t.Fatalf("failed to determine git project dir: %v", err) + } + + sub := "util" + got := ProjectDir(sub) + want := filepath.Join(git, sub) + assert.Equalf(t, got, want, "it should match the git project directory for %s", sub) +} + +func TestNormalizePath(t *testing.T) { + type TestCase struct { + name string + path string + want string + } + + cases := []TestCase{ + { + name: "spaces around the path", + path: " /etc/os-release ", + want: "/etc/os-release", + }, + { + name: "new lines", + path: "/etc/\nlegal", + want: "/etc/legal", + }, + { + name: "carriage returns", + path: "/etc/\rlegal", + want: "/etc/legal", + }, + { + name: "tilde user home directory shorthand", + path: "~/Documents", + want: (func() string { + home, err := os.UserHomeDir() + if err != nil { + t.Fatalf("failed to determine user home: %v", err) + } + + return filepath.Join(home, "Documents") + })(), + }, + { + name: "dots", + path: "/root/../etc/../etc/././././os-release", + want: "/etc/os-release", + }, + { + name: "directory separators", + path: "///////etc/////os-release", + want: "/etc/os-release", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := NormalizePath(c.path) + assert.Equal(t, c.want, got, "it should normalize the path") + }) + } + + t.Run("filepath.Abs error", func(t *testing.T) { + assert.NotPanics(t, func() { + patches := gomonkey.ApplyFuncReturn(filepath.Abs, "", syscall.ENOTDIR) + defer patches.Reset() + + path := "/etc/os-release" + want := path + got := NormalizePath(path) + assert.Equal(t, want, got, "it should silently handle filepath.Abs error") + }, "it should not panic") + }) +} From 5c123ed24afe01d75a61b3243edb72610d99be3d Mon Sep 17 00:00:00 2001 From: John Lettman Date: Tue, 16 Jul 2024 01:10:26 -0400 Subject: [PATCH 29/32] util/math_test: use reflection for type name --- util/math_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/math_test.go b/util/math_test.go index 56eaffb..b04e3ae 100644 --- a/util/math_test.go +++ b/util/math_test.go @@ -3,6 +3,7 @@ package util import ( "github.com/stretchr/testify/assert" "golang.org/x/exp/constraints" + "reflect" "testing" ) @@ -34,7 +35,7 @@ func testAbsCase[T constraints.Integer | constraints.Float](t *testing.T, c Test } func testAbsGeneric[T constraints.Integer | constraints.Float](t *testing.T) { - n := TypeName(*new(T)) + n := reflect.TypeFor[T]().Name() f, ok := testAbsFakeFunctions[n] if !ok { t.Fatalf("can not locate randomizer function for type %s", n) From 42b169685258792ca901bd7df2cd0423348e7169 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Tue, 16 Jul 2024 01:18:17 -0400 Subject: [PATCH 30/32] util: add tuples --- util/tuples.go | 17 +++++++++++++++++ util/tuples_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 util/tuples.go create mode 100644 util/tuples_test.go diff --git a/util/tuples.go b/util/tuples.go new file mode 100644 index 0000000..5a1cae8 --- /dev/null +++ b/util/tuples.go @@ -0,0 +1,17 @@ +package util + +import "github.com/barweiss/go-tuple" + +// MapTuples creates a map from a slice of tuples.Pair. +// The keys are the values in V1 field of the pairs, +// and the values are the values in V2 field of the pairs. +// The function returns the created map. +func MapTuples[A comparable, B any](t []tuple.Pair[A, B]) map[A]B { + m := make(map[A]B) + + for _, pair := range t { + m[pair.V1] = pair.V2 + } + + return m +} diff --git a/util/tuples_test.go b/util/tuples_test.go new file mode 100644 index 0000000..ea3b99c --- /dev/null +++ b/util/tuples_test.go @@ -0,0 +1,32 @@ +package util + +import ( + "github.com/barweiss/go-tuple" + "github.com/brianvoe/gofakeit/v7" + "github.com/stretchr/testify/assert" + "testing" +) + +func createRandomTuple() tuple.Pair[string, string] { + return tuple.Pair[string, string]{ + V1: gofakeit.FirstName(), + V2: gofakeit.LastName(), + } +} + +func TestMapTuples(t *testing.T) { + var pair tuple.Pair[string, string] + + count := 10 + list := make([]tuple.Pair[string, string], count) + want := make(map[string]string, count) + + for i := 0; i < count; i++ { + pair = createRandomTuple() + list[i] = pair + want[pair.V1] = pair.V2 + } + + got := MapTuples[string, string](list) + assert.Equal(t, want, got, "it should map the tuple") +} From f49d34f93f92938096f12138045becf496d8dbe6 Mon Sep 17 00:00:00 2001 From: John Lettman Date: Tue, 16 Jul 2024 01:20:58 -0400 Subject: [PATCH 31/32] util/auto-start-flag: correct reference to IntBoolJSON --- types/auto-start-flag.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/types/auto-start-flag.go b/types/auto-start-flag.go index 62a0779..e6dce0a 100644 --- a/types/auto-start-flag.go +++ b/types/auto-start-flag.go @@ -15,7 +15,7 @@ import ( // Usage of AutoStartFlag in firmware prior to v2.0.0 has unexpected behavior. // // [Ouster docs: Standby Operating Mode Examples]: https://static.ouster.dev/sensor-docs/image_route1/image_route2/sensor_operations/sensor-operations.html#standby-operating-mode-examples -type AutoStartFlag pseudo.IntBool +type AutoStartFlag pseudo.IntBoolJSON const ( AutoStartOn AutoStartFlag = true // Equivalent to OperatingMode "NORMAL" @@ -47,9 +47,8 @@ func (a AutoStartFlag) GoString() string { } // MarshalText returns the text representation of an AutoStartFlag. -// -// - If the AutoStartFlag is AutoStartOff, it returns "off". -// - Otherwise, it returns "on". +// - If the AutoStartFlag is AutoStartOff, it returns "off"; +// - otherwise, it returns "on". // // It always returns nil, indicating no error occurred. func (a AutoStartFlag) MarshalText() ([]byte, error) { @@ -65,11 +64,10 @@ func (a AutoStartFlag) MarshalText() ([]byte, error) { // UnmarshalText parses the provided text and assigns the corresponding value to the receiver. // The method converts the input text to lowercase. -// // - If the text is 'off', it assigns AutoStartOff to the receiver. // - For any other text, it assigns AutoStartOn to the receiver. // -// It always returns nil, indicating no error occurred. +// It always returns nil error, indicating no error occurred. func (a *AutoStartFlag) UnmarshalText(text []byte) error { switch strings.ToLower(string(text)) { default: @@ -83,15 +81,15 @@ func (a *AutoStartFlag) UnmarshalText(text []byte) error { return nil } -// MarshalJSON converts AutoStartFlag to JSON format using pseudo.IntBool.MarshalJSON method. +// MarshalJSON converts AutoStartFlag to JSON format using pseudo.IntBoolJSON.MarshalJSON method. // It returns the JSON bytes and any occurred error. func (a AutoStartFlag) MarshalJSON() ([]byte, error) { - return (*pseudo.IntBool)(&a).MarshalJSON() + return (*pseudo.IntBoolJSON)(&a).MarshalJSON() } // UnmarshalJSON converts the JSON data into the AutoStartFlag value. -// It leverages the pseudo.IntBool.UnmarshalJSON method to perform the actual unmarshaling. +// It leverages the pseudo.IntBoolJSON.UnmarshalJSON method to perform the actual unmarshaling. // It returns any occurred error. func (a *AutoStartFlag) UnmarshalJSON(data []byte) error { - return (*pseudo.IntBool)(a).UnmarshalJSON(data) + return (*pseudo.IntBoolJSON)(a).UnmarshalJSON(data) } From 4f545daf0db2024f6023b86c8ebd511a48acbf2b Mon Sep 17 00:00:00 2001 From: John Lettman Date: Tue, 16 Jul 2024 01:21:35 -0400 Subject: [PATCH 32/32] .gitignore: add Node.js --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 8c0493d..2ccdfa9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,13 @@ samples/ # Generated docs docs/ +### Node.js +# Logs +npm-debug.log* + +# Dependency directories +node_modules/ + ### JetBrains # User-specific stuff .idea/**/workspace.xml