diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 823617e..7d9f201 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,20 +16,18 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '^1.21' - - - name: Get dependencies - run: go mod download + cache: false - name: Run golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: - version: v1.52.2 + version: v1.57.1 only-new-issues: true args: -c ./.golangci.yml --timeout 15m @@ -41,12 +39,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '^1.21' + cache: false - name: Get dependencies run: go mod download diff --git a/container/container.go b/container/container.go index 3f3292d..d30e961 100644 --- a/container/container.go +++ b/container/container.go @@ -4,7 +4,7 @@ import ( "errors" "io" - "github.com/safing/portbase/formats/varint" + "github.com/safing/structures/varint" ) // Container is []byte sclie on steroids, allowing for quick data appending, prepending and fetching. diff --git a/container/container_test.go b/container/container_test.go index 0c8e636..21c3745 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -3,8 +3,6 @@ package container import ( "bytes" "testing" - - "github.com/safing/portbase/utils" ) var ( @@ -25,7 +23,7 @@ var ( func TestContainerDataHandling(t *testing.T) { t.Parallel() - c1 := New(utils.DuplicateBytes(testData)) + c1 := New(duplicateBytes(testData)) c1c := c1.carbonCopy() c2 := New() @@ -87,7 +85,7 @@ func compareMany(t *testing.T, reference []byte, other ...[]byte) { func TestDataFetching(t *testing.T) { t.Parallel() - c1 := New(utils.DuplicateBytes(testData)) + c1 := New(duplicateBytes(testData)) data := c1.GetMax(1) if string(data[0]) != "T" { t.Errorf("failed to GetMax(1), got %s, expected %s", string(data), "T") @@ -107,7 +105,7 @@ func TestDataFetching(t *testing.T) { func TestBlocks(t *testing.T) { t.Parallel() - c1 := New(utils.DuplicateBytes(testData)) + c1 := New(duplicateBytes(testData)) c1.PrependLength() n, err := c1.GetNextN8() @@ -149,7 +147,7 @@ func TestBlocks(t *testing.T) { func TestContainerBlockHandling(t *testing.T) { t.Parallel() - c1 := New(utils.DuplicateBytes(testData)) + c1 := New(duplicateBytes(testData)) c1.PrependLength() c1.AppendAsBlock(testData) c1c := c1.carbonCopy() @@ -204,5 +202,12 @@ func TestContainerMisc(t *testing.T) { func TestDeprecated(t *testing.T) { t.Parallel() - NewContainer(utils.DuplicateBytes(testData)) + NewContainer(duplicateBytes(testData)) +} + +// duplicateBytes returns a new copy of the given byte slice. +func duplicateBytes(a []byte) []byte { + b := make([]byte, len(a)) + copy(b, a) + return b } diff --git a/dsd/compression.go b/dsd/compression.go index ebaa11c..0c699af 100644 --- a/dsd/compression.go +++ b/dsd/compression.go @@ -5,7 +5,7 @@ import ( "compress/gzip" "errors" - "github.com/safing/portbase/formats/varint" + "github.com/safing/structures/varint" ) // DumpAndCompress stores the interface as a dsd formatted data structure and compresses the resulting data. diff --git a/dsd/dsd.go b/dsd/dsd.go index 2664877..f04a7c9 100644 --- a/dsd/dsd.go +++ b/dsd/dsd.go @@ -13,8 +13,7 @@ import ( "github.com/ghodss/yaml" "github.com/vmihailenco/msgpack/v5" - "github.com/safing/portbase/formats/varint" - "github.com/safing/portbase/utils" + "github.com/safing/structures/varint" ) // Load loads an dsd structured data blob into the given interface. @@ -39,25 +38,25 @@ func LoadAsFormat(data []byte, format uint8, t interface{}) (err error) { case JSON: err = json.Unmarshal(data, t) if err != nil { - return fmt.Errorf("dsd: failed to unpack json: %w, data: %s", err, utils.SafeFirst16Bytes(data)) + return fmt.Errorf("dsd: failed to unpack json: %w, data: %s", err, safeFirst16Bytes(data)) } return nil case YAML: err = yaml.Unmarshal(data, t) if err != nil { - return fmt.Errorf("dsd: failed to unpack yaml: %w, data: %s", err, utils.SafeFirst16Bytes(data)) + return fmt.Errorf("dsd: failed to unpack yaml: %w, data: %s", err, safeFirst16Bytes(data)) } return nil case CBOR: err = cbor.Unmarshal(data, t) if err != nil { - return fmt.Errorf("dsd: failed to unpack cbor: %w, data: %s", err, utils.SafeFirst16Bytes(data)) + return fmt.Errorf("dsd: failed to unpack cbor: %w, data: %s", err, safeFirst16Bytes(data)) } return nil case MsgPack: err = msgpack.Unmarshal(data, t) if err != nil { - return fmt.Errorf("dsd: failed to unpack msgpack: %w, data: %s", err, utils.SafeFirst16Bytes(data)) + return fmt.Errorf("dsd: failed to unpack msgpack: %w, data: %s", err, safeFirst16Bytes(data)) } return nil case GenCode: @@ -67,7 +66,7 @@ func LoadAsFormat(data []byte, format uint8, t interface{}) (err error) { } _, err = genCodeStruct.GenCodeUnmarshal(data) if err != nil { - return fmt.Errorf("dsd: failed to unpack gencode: %w, data: %s", err, utils.SafeFirst16Bytes(data)) + return fmt.Errorf("dsd: failed to unpack gencode: %w, data: %s", err, safeFirst16Bytes(data)) } return nil default: diff --git a/dsd/http_test.go b/dsd/http_test.go index 32651ac..ed6f39b 100644 --- a/dsd/http_test.go +++ b/dsd/http_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestMimeTypes(t *testing.T) { @@ -13,12 +14,12 @@ func TestMimeTypes(t *testing.T) { // Test static maps. for _, mimeType := range FormatToMimeType { cleaned, _, err := mime.ParseMediaType(mimeType) - assert.NoError(t, err, "mime type must be parse-able") + require.NoError(t, err, "mime type must be parse-able") assert.Equal(t, mimeType, cleaned, "mime type should be clean in map already") } for mimeType := range MimeTypeToFormat { cleaned, _, err := mime.ParseMediaType(mimeType) - assert.NoError(t, err, "mime type must be parse-able") + require.NoError(t, err, "mime type must be parse-able") assert.Equal(t, mimeType, cleaned, "mime type should be clean in map already") } diff --git a/dsd/safe.go b/dsd/safe.go new file mode 100644 index 0000000..e4a47f9 --- /dev/null +++ b/dsd/safe.go @@ -0,0 +1,23 @@ +package dsd + +import ( + "encoding/hex" + "strings" +) + +// safeFirst16Bytes return the first 16 bytes of the given data in safe form. +func safeFirst16Bytes(data []byte) string { + if len(data) == 0 { + return "" + } + + return strings.TrimPrefix( + strings.SplitN(hex.Dump(data), "\n", 2)[0], + "00000000 ", + ) +} + +// safeFirst16Chars return the first 16 characters of the given data in safe form. +func safeFirst16Chars(s string) string { + return safeFirst16Bytes([]byte(s)) +} diff --git a/dsd/safe_test.go b/dsd/safe_test.go new file mode 100644 index 0000000..2fa0c33 --- /dev/null +++ b/dsd/safe_test.go @@ -0,0 +1,29 @@ +package dsd + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSafeFirst16(t *testing.T) { + t.Parallel() + + assert.Equal(t, + "47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|", + safeFirst16Bytes([]byte("Go is an open source programming language.")), + ) + assert.Equal(t, + "47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|", + safeFirst16Chars("Go is an open source programming language."), + ) + + assert.Equal(t, + "", + safeFirst16Bytes(nil), + ) + assert.Equal(t, + "", + safeFirst16Chars(""), + ) +} diff --git a/go.mod b/go.mod index 0f288f2..ff17c55 100644 --- a/go.mod +++ b/go.mod @@ -7,17 +7,14 @@ toolchain go1.21.2 require ( github.com/fxamacker/cbor/v2 v2.7.0 github.com/ghodss/yaml v1.0.0 - github.com/safing/portbase v0.19.5 github.com/stretchr/testify v1.8.4 github.com/vmihailenco/msgpack/v5 v5.4.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/kr/pretty v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/tevino/abool v1.2.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/go.sum b/go.sum index 1033679..fc4b73e 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -13,12 +11,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/safing/portbase v0.19.5 h1:3/8odzlvb629tHPwdj/sthSeJcwZHYrqA6YuvNUZzNc= -github.com/safing/portbase v0.19.5/go.mod h1:Qrh3ck+7VZloFmnozCs9Hj8godhJAi55cmiDiC7BwTc= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= -github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= diff --git a/test b/test new file mode 100755 index 0000000..82dd86b --- /dev/null +++ b/test @@ -0,0 +1,168 @@ +#!/bin/bash + +warnings=0 +errors=0 +scripted=0 +goUp="\\e[1A" +fullTestFlags="-short" +install=0 +testonly=0 + +function help { + echo "usage: $0 [command] [options]" + echo "" + echo "commands:" + echo " run baseline tests" + echo " full run full tests (ie. not short)" + echo " install install deps for running tests" + echo "" + echo "options:" + echo " --scripted don't jump console lines (still use colors)" + echo " --test-only run tests only, no linters" + echo " [package] run only on this package" +} + +function run { + if [[ $scripted -eq 0 ]]; then + echo "[......] $*" + fi + + # create tmpfile + tmpfile=$(mktemp) + # execute + $* >$tmpfile 2>&1 + rc=$? + output=$(cat $tmpfile) + + # check return code + if [[ $rc -eq 0 ]]; then + if [[ $output == *"[no test files]"* ]]; then + echo -e "${goUp}[\e[01;33mNOTEST\e[00m] $*" + warnings=$((warnings+1)) + else + echo -ne "${goUp}[\e[01;32m OK \e[00m] " + if [[ $2 == "test" ]]; then + echo -n $* + echo -n ": " + echo $output | cut -f "3-" -d " " + else + echo $* + fi + fi + else + if [[ $output == *"build constraints exclude all Go files"* ]]; then + echo -e "${goUp}[ !=OS ] $*" + else + echo -e "${goUp}[\e[01;31m FAIL \e[00m] $*" + cat $tmpfile + errors=$((errors+1)) + fi + fi + + rm -f $tmpfile +} + +# get and switch to script dir +baseDir="$( cd "$(dirname "$0")" && pwd )" +cd "$baseDir" + +# args +while true; do + case "$1" in + "-h"|"help"|"--help") + help + exit 0 + ;; + "--scripted") + scripted=1 + goUp="" + shift 1 + ;; + "--test-only") + testonly=1 + shift 1 + ;; + "install") + install=1 + shift 1 + ;; + "full") + fullTestFlags="" + shift 1 + ;; + *) + break + ;; + esac +done + +# check if $GOPATH/bin is in $PATH +if [[ $PATH != *"$GOPATH/bin"* ]]; then + export PATH=$GOPATH/bin:$PATH +fi + +# install +if [[ $install -eq 1 ]]; then + echo "installing dependencies..." + # TODO: update golangci-lint version regularly + echo "$ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0" + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0 + exit 0 +fi + +# check dependencies +if [[ $(which go) == "" ]]; then + echo "go command not found" + exit 1 +fi +if [[ $testonly -eq 0 ]]; then + if [[ $(which gofmt) == "" ]]; then + echo "gofmt command not found" + exit 1 + fi + if [[ $(which golangci-lint) == "" ]]; then + echo "golangci-lint command not found" + echo "install with: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin vX.Y.Z" + echo "don't forget to specify the version you want" + echo "or run: ./test install" + echo "" + echo "alternatively, install the current dev version with: go get -u github.com/golangci/golangci-lint/cmd/golangci-lint" + exit 1 + fi +fi + +# target selection +if [[ "$1" == "" ]]; then + # get all packages + packages=$(go list -e ./...) +else + # single package testing + packages=$(go list -e)/$1 + echo "note: only running tests for package $packages" +fi + +# platform info +platformInfo=$(go env GOOS GOARCH) +echo "running tests for ${platformInfo//$'\n'/ }:" + +# run vet/test on packages +for package in $packages; do + packagename=${package#github.com/safing/structures} #TODO: could be queried with `go list .` + packagename=${packagename#/} + echo "" + echo $package + if [[ $testonly -eq 0 ]]; then + run go vet $package + run golangci-lint run $packagename + fi + run go test -cover $fullTestFlags $package +done + +echo "" +if [[ $errors -gt 0 ]]; then + echo "failed with $errors errors and $warnings warnings" + exit 1 +else + echo "succeeded with $warnings warnings" + exit 0 +fi