Browse Source

[GPT-98] Update go version & add verification/testing tools (#200)

<!--
For Work In Progress Pull Requests, please use the Draft PR feature,
see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for
further details.

     For a timely review/response, please avoid force-pushing additional
     commits if your PR already received reviews or comments.

     Before submitting a Pull Request, please ensure that you have:
- 📖 Read the Contributing guide:
https://github.com/gorilla/.github/blob/main/CONTRIBUTING.md
- 📖 Read the Code of Conduct:
https://github.com/gorilla/.github/blob/main/CODE_OF_CONDUCT.md

     - Provide tests for your changes.
     - Use descriptive commit messages.
	 - Comment your code where appropriate.
	 - Squash your commits
     - Update any related documentation.

     - Add gorilla/pull-request-reviewers as a Reviewer
-->

## What type of PR is this? (check all applicable)

- [ ] Refactor
- [ ] Feature
- [ ] Bug Fix
- [ ] Optimization
- [ ] Documentation Update

## Description

## Related Tickets & Documents

<!--
For pull requests that relate or close an issue, please include them
below. We like to follow [Github's guidance on linking issues to pull
requests](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).

For example having the text: "closes #1234" would connect the current
pull
request to issue 1234.  And when we merge the pull request, Github will
automatically close the issue.
-->

- Related Issue #
- Closes #

## Added/updated tests?

- [ ] Yes
- [ ] No, and this is why: _please replace this line with details on why
tests
      have not been included_
- [ ] I need help with writing tests

## Run verifications and test

- [ ] `make verify` is passing
- [ ] `make test` is passing

---------

Signed-off-by: Apoorva Jagtap <35304110+apoorvajagtap@users.noreply.github.com>
Co-authored-by: Corey Daley <cdaley@redhat.com>
coreydaley-patch-1^2
Apoorva Jagtap 1 year ago committed by GitHub
parent
commit
212775c4b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 70
      .circleci/config.yml
  2. 20
      .editorconfig
  3. 8
      .github/release-drafter.yml
  4. 12
      .github/stale.yml
  5. 20
      .github/workflows/issues.yml
  6. 55
      .github/workflows/test.yml
  7. 1
      .gitignore
  8. 2
      LICENSE
  9. 34
      Makefile
  10. 13
      README.md
  11. 12
      cache.go
  12. 2
      decoder.go
  13. 71
      decoder_test.go
  14. 11
      encoder.go
  15. 24
      encoder_test.go
  16. 2
      go.mod

70
.circleci/config.yml

@ -1,70 +0,0 @@
version: 2.1
jobs:
"test":
parameters:
version:
type: string
default: "latest"
golint:
type: boolean
default: true
modules:
type: boolean
default: true
goproxy:
type: string
default: ""
docker:
- image: "circleci/golang:<< parameters.version >>"
working_directory: /go/src/github.com/gorilla/schema
environment:
GO111MODULE: "on"
GOPROXY: "<< parameters.goproxy >>"
steps:
- checkout
- run:
name: "Print the Go version"
command: >
go version
- run:
name: "Fetch dependencies"
command: >
if [[ << parameters.modules >> = true ]]; then
go mod download
export GO111MODULE=on
else
go get -v ./...
fi
# Only run gofmt, vet & lint against the latest Go version
- run:
name: "Run golint"
command: >
if [ << parameters.version >> = "latest" ] && [ << parameters.golint >> = true ]; then
go get -u golang.org/x/lint/golint
golint ./...
fi
- run:
name: "Run gofmt"
command: >
if [[ << parameters.version >> = "latest" ]]; then
diff -u <(echo -n) <(gofmt -d -e .)
fi
- run:
name: "Run go vet"
command: >
if [[ << parameters.version >> = "latest" ]]; then
go vet -v ./...
fi
- run:
name: "Run go test (+ race detector)"
command: >
go test -v -race ./...
workflows:
tests:
jobs:
- test:
matrix:
parameters:
version: ["latest", "1.15", "1.14", "1.13", "1.12", "1.11"]

20
.editorconfig

@ -0,0 +1,20 @@
; https://editorconfig.org/
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
indent_style = tab
indent_size = 4
[*.md]
indent_size = 4
trim_trailing_whitespace = false
eclint_indent_style = unset

8
.github/release-drafter.yml

@ -1,8 +0,0 @@
# Config for https://github.com/apps/release-drafter
template: |
<summary of changes here>
## CHANGELOG
$CHANGES

12
.github/stale.yml

@ -1,12 +0,0 @@
daysUntilStale: 60
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- v2
- needs-review
- work-required
staleLabel: stale
markComment: >
This issue has been automatically marked as stale because it hasn't seen
a recent update. It'll be automatically closed in a few days.
closeComment: false

20
.github/workflows/issues.yml

@ -0,0 +1,20 @@
# Add issues or pull-requests created to the project.
name: Add issue or pull request to Project
on:
issues:
types:
- opened
pull_request:
types:
- opened
jobs:
add-to-project:
runs-on: ubuntu-latest
steps:
- name: Add issue to project
uses: actions/add-to-project@v0.5.0
with:
project-url: https://github.com/orgs/gorilla/projects/4
github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }}

55
.github/workflows/test.yml

@ -0,0 +1,55 @@
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
contents: read
jobs:
verify-and-test:
strategy:
matrix:
go: ['1.19','1.20']
os: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
cache: false
- name: Run GolangCI-Lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.53
args: --timeout=5m
- name: Run GoSec
if: matrix.os == 'ubuntu-latest'
uses: securego/gosec@master
with:
args: ./...
- name: Run GoVulnCheck
uses: golang/govulncheck-action@v1
with:
go-version-input: ${{ matrix.go }}
go-package: ./...
- name: Run Tests
run: go test -race -cover -coverprofile=coverage -covermode=atomic -v ./...
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage

1
.gitignore vendored

@ -0,0 +1 @@
coverage.coverprofile

2
LICENSE

@ -1,4 +1,4 @@
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
Copyright (c) 2023 The Gorilla Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are

34
Makefile

@ -0,0 +1,34 @@
GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '')
GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest
GO_SEC=$(shell which gosec 2> /dev/null || echo '')
GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest
GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '')
GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest
.PHONY: golangci-lint
golangci-lint:
$(if $(GO_LINT), ,go install $(GO_LINT_URI))
@echo "##### Running golangci-lint"
golangci-lint run -v
.PHONY: gosec
gosec:
$(if $(GO_SEC), ,go install $(GO_SEC_URI))
@echo "##### Running gosec"
gosec ./...
.PHONY: govulncheck
govulncheck:
$(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI))
@echo "##### Running govulncheck"
govulncheck ./...
.PHONY: verify
verify: golangci-lint gosec govulncheck
.PHONY: test
test:
@echo "##### Running tests"
go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./...

13
README.md

@ -1,9 +1,12 @@
schema
======
[![GoDoc](https://godoc.org/github.com/gorilla/schema?status.svg)](https://godoc.org/github.com/gorilla/schema)
[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/schema)
[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/schema/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/schema?badge)
# gorilla/schema
![testing](https://github.com/gorilla/schema/actions/workflows/test.yml/badge.svg)
[![codecov](https://codecov.io/github/gorilla/schema/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/schema)
[![godoc](https://godoc.org/github.com/gorilla/schema?status.svg)](https://godoc.org/github.com/gorilla/schema)
[![sourcegraph](https://sourcegraph.com/github.com/gorilla/schema/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/schema?badge)
![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5)
Package gorilla/schema converts structs to and from form values.

12
cache.go

@ -12,7 +12,7 @@ import (
"sync"
)
var invalidPath = errors.New("schema: invalid path")
var errInvalidPath = errors.New("schema: invalid path")
// newCache returns a new cache.
func newCache() *cache {
@ -53,13 +53,13 @@ func (c *cache) parsePath(p string, t reflect.Type) ([]pathPart, error) {
keys := strings.Split(p, ".")
for i := 0; i < len(keys); i++ {
if t.Kind() != reflect.Struct {
return nil, invalidPath
return nil, errInvalidPath
}
if struc = c.get(t); struc == nil {
return nil, invalidPath
return nil, errInvalidPath
}
if field = struc.get(keys[i]); field == nil {
return nil, invalidPath
return nil, errInvalidPath
}
// Valid field. Append index.
path = append(path, field.name)
@ -72,10 +72,10 @@ func (c *cache) parsePath(p string, t reflect.Type) ([]pathPart, error) {
// So checking i+2 is not necessary anymore.
i++
if i+1 > len(keys) {
return nil, invalidPath
return nil, errInvalidPath
}
if index64, err = strconv.ParseInt(keys[i], 10, 0); err != nil {
return nil, invalidPath
return nil, errInvalidPath
}
parts = append(parts, pathPart{
path: path,

2
decoder.go

@ -193,7 +193,7 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
if v.Type().Kind() == reflect.Struct {
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if field.Type().Kind() == reflect.Ptr && field.IsNil() && v.Type().Field(i).Anonymous == true {
if field.Type().Kind() == reflect.Ptr && field.IsNil() && v.Type().Field(i).Anonymous {
field.Set(reflect.New(field.Type().Elem()))
}
}

71
decoder_test.go

@ -69,9 +69,7 @@ func (id *S19) UnmarshalText(text []byte) error {
if len(buf) > len(*id) {
return errors.New("out of range")
}
for i := range buf {
(*id)[i] = buf[i]
}
copy((*id)[:], buf)
return nil
}
@ -673,7 +671,10 @@ func TestEmptyValue(t *testing.T) {
"F01": {"", "foo"},
}
s := &S5{}
NewDecoder().Decode(s, data)
err := NewDecoder().Decode(s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if len(s.F01) != 1 {
t.Errorf("Expected 1 values in F01")
}
@ -706,7 +707,10 @@ func TestUnexportedField(t *testing.T) {
"id": {"identifier"},
}
s := &S6{}
NewDecoder().Decode(s, data)
err := NewDecoder().Decode(s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s.id != "" {
t.Errorf("Unexported field expected to be ignored")
}
@ -724,7 +728,10 @@ func TestMultipleValues(t *testing.T) {
}
s := S7{}
NewDecoder().Decode(&s, data)
err := NewDecoder().Decode(&s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s.ID != "1" {
t.Errorf("Last defined value must be used when multiple values for same field are provided")
}
@ -742,7 +749,10 @@ func TestSetAliasTag(t *testing.T) {
s := S8{}
dec := NewDecoder()
dec.SetAliasTag("json")
dec.Decode(&s, data)
err := dec.Decode(&s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s.ID != "foo" {
t.Fatalf("Bad value: got %q, want %q", s.ID, "foo")
}
@ -813,7 +823,10 @@ func TestEmbeddedField(t *testing.T) {
"Id": {"identifier"},
}
s := &S10{}
NewDecoder().Decode(s, data)
err := NewDecoder().Decode(s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s.Id != "identifier" {
t.Errorf("Missing support for embedded fields")
}
@ -1148,7 +1161,10 @@ func TestCSVSlice(t *testing.T) {
}
s := S12A{}
NewDecoder().Decode(&s, data)
err := NewDecoder().Decode(&s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if len(s.ID) != 2 {
t.Errorf("Expected two values in the result list, got %+v", s.ID)
}
@ -1161,14 +1177,17 @@ type S12B struct {
ID []string
}
//Decode should not split on , into a slice for string only
// Decode should not split on , into a slice for string only
func TestCSVStringSlice(t *testing.T) {
data := map[string][]string{
"ID": {"0,1"},
}
s := S12B{}
NewDecoder().Decode(&s, data)
err := NewDecoder().Decode(&s, data)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if len(s.ID) != 1 {
t.Errorf("Expected one value in the result list, got %+v", s.ID)
}
@ -1177,7 +1196,7 @@ func TestCSVStringSlice(t *testing.T) {
}
}
//Invalid data provided by client should not panic (github issue 33)
// Invalid data provided by client should not panic (github issue 33)
func TestInvalidDataProvidedByClient(t *testing.T) {
defer func() {
if r := recover(); r != nil {
@ -1186,7 +1205,7 @@ func TestInvalidDataProvidedByClient(t *testing.T) {
}()
type S struct {
f string
f string // nolint:unused
}
data := map[string][]string{
@ -1202,7 +1221,7 @@ func TestInvalidDataProvidedByClient(t *testing.T) {
// underlying cause of error in issue 33
func TestInvalidPathInCacheParsePath(t *testing.T) {
type S struct {
f string
f string // nolint:unused
}
typ := reflect.ValueOf(new(S)).Elem().Type()
@ -1218,7 +1237,10 @@ func TestDecodeToTypedField(t *testing.T) {
type Aa bool
s1 := &struct{ Aa }{}
v1 := map[string][]string{"Aa": {"true"}}
NewDecoder().Decode(s1, v1)
err := NewDecoder().Decode(s1, v1)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s1.Aa != Aa(true) {
t.Errorf("s1: expected %v, got %v", true, s1.Aa)
}
@ -1238,7 +1260,10 @@ func TestRegisterConverter(t *testing.T) {
decoder.RegisterConverter(s1.Bb, func(s string) reflect.Value { return reflect.ValueOf(2) })
v1 := map[string][]string{"Aa": {"4"}, "Bb": {"5"}}
decoder.Decode(s1, v1)
err := decoder.Decode(s1, v1)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s1.Aa != Aa(1) {
t.Errorf("s1.Aa: expected %v, got %v", 1, s1.Aa)
@ -1260,9 +1285,12 @@ func TestRegisterConverterSlice(t *testing.T) {
}{}
expected := []string{"one", "two", "three"}
decoder.Decode(&result, map[string][]string{
err := decoder.Decode(&result, map[string][]string{
"multiple": []string{"one,two,three"},
})
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
for i := range expected {
if got, want := expected[i], result.Multiple[i]; got != want {
t.Errorf("%d: got %s, want %s", i, got, want)
@ -1868,8 +1896,11 @@ func TestRegisterConverterOverridesTextUnmarshaler(t *testing.T) {
ts := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
decoder.RegisterConverter(s1.MyTime, func(s string) reflect.Value { return reflect.ValueOf(ts) })
v1 := map[string][]string{"MyTime": {"4"}, "Bb": {"5"}}
decoder.Decode(s1, v1)
v1 := map[string][]string{"MyTime": {"4"}}
err := decoder.Decode(s1, v1)
if err != nil {
t.Fatalf("Failed to decode: %v", err)
}
if s1.MyTime != MyTime(ts) {
t.Errorf("s1.Aa: expected %v, got %v", ts, s1.MyTime)
@ -1951,7 +1982,7 @@ func TestTextUnmarshalerTypeSliceOfStructs(t *testing.T) {
sb := struct {
Value S21B
}{}
if err := decoder.Decode(&sb, data); err == invalidPath {
if err := decoder.Decode(&sb, data); err == errInvalidPath {
t.Fatal("Expecting invalid path error", err)
}
}

11
encoder.go

@ -3,6 +3,7 @@ package schema
import (
"errors"
"fmt"
"log"
"reflect"
"strconv"
)
@ -94,7 +95,10 @@ func (e *Encoder) encode(v reflect.Value, dst map[string][]string) error {
// Encode struct pointer types if the field is a valid pointer and a struct.
if isValidStructPointer(v.Field(i)) && !e.hasCustomEncoder(v.Field(i).Type()) {
e.encode(v.Field(i).Elem(), dst)
err := e.encode(v.Field(i).Elem(), dst)
if err != nil {
log.Fatal(err)
}
continue
}
@ -112,7 +116,10 @@ func (e *Encoder) encode(v reflect.Value, dst map[string][]string) error {
}
if v.Field(i).Type().Kind() == reflect.Struct {
e.encode(v.Field(i), dst)
err := e.encode(v.Field(i), dst)
if err != nil {
log.Fatal(err)
}
continue
}

24
encoder_test.go

@ -205,7 +205,7 @@ func TestCompatSlices(t *testing.T) {
t.Errorf("Dncoder has non-nil error: %v", err)
}
if len(src.Ints) != len(dst.Ints) || len(src.Ones) != len(src.Ones) {
if len(src.Ints) != len(dst.Ints) || len(src.Ones) != len(dst.Ones) {
t.Fatalf("Expected %v, got %v", src, dst)
}
@ -344,7 +344,10 @@ func TestEncoderSetAliasTag(t *testing.T) {
}
encoder := NewEncoder()
encoder.SetAliasTag("json")
encoder.Encode(&s, data)
err := encoder.Encode(&s, data)
if err != nil {
t.Fatalf("Failed to encode: %v", err)
}
valExists(t, "id", "foo", data)
}
@ -376,7 +379,10 @@ func TestEncoderWithOmitempty(t *testing.T) {
}
encoder := NewEncoder()
encoder.Encode(&s, vals)
err := encoder.Encode(&s, vals)
if err != nil {
t.Fatalf("Failed to encode: %v", err)
}
valNotExists(t, "f01", vals)
valExists(t, "f02", "test", vals)
@ -402,7 +408,10 @@ func TestStructPointer(t *testing.T) {
}
encoder := NewEncoder()
encoder.Encode(&s, vals)
err := encoder.Encode(&s, vals)
if err != nil {
t.Fatalf("Failed to encode: %v", err)
}
valExists(t, "F12", "2", vals)
valExists(t, "F02", "null", vals)
valNotExists(t, "F03", vals)
@ -428,7 +437,10 @@ func TestRegisterEncoderCustomArrayType(t *testing.T) {
return fmt.Sprint(value.Interface())
})
encoder.Encode(s, vals)
err := encoder.Encode(ss[s], vals)
if err != nil {
t.Fatalf("Failed to encode: %v", err)
}
}
}
@ -466,7 +478,7 @@ func TestRegisterEncoderStructIsZero(t *testing.T) {
t.Error("expected tim1 to be present")
}
if "2020-08-04T13:30:01Z" != ta[0] {
if ta[0] != "2020-08-04T13:30:01Z" {
t.Error("expected correct tim1 time")
}

2
go.mod

@ -1,3 +1,3 @@
module github.com/gorilla/schema
go 1.14
go 1.19

Loading…
Cancel
Save