• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pace / bricks / 12827718001

17 Jan 2025 10:57AM UTC coverage: 56.909% (-0.3%) from 57.237%
12827718001

Pull #384

github

monstermunchkin
Satisfy linters
Pull Request #384: Extend linting

478 of 946 new or added lines in 109 files covered. (50.53%)

133 existing lines in 53 files now uncovered.

5667 of 9958 relevant lines covered (56.91%)

21.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.59
/http/jsonapi/runtime/parameters.go
1
// Copyright © 2018 by PACE Telematics GmbH. All rights reserved.
2

3
package runtime
4

5
import (
6
        "fmt"
7
        "net/http"
8
        "reflect"
9
        "strings"
10
        "time"
11

12
        "github.com/shopspring/decimal"
13

14
        "github.com/pace/bricks/pkg/isotime"
15
)
16

17
// ScanIn help to avoid missuse using iota for the possible values.
18
type ScanIn int
19

20
const (
21
        // ScanInPath hints the scanner to scan the input.
22
        ScanInPath ScanIn = iota
23
        // ScanInQuery hints the scanner to scan the request url query.
24
        ScanInQuery
25
        // ScanInHeader ints the scanner to scan the request header.
26
        ScanInHeader
27
)
28

29
// ScanParameter configured the ScanParameters function.
30
type ScanParameter struct {
31
        // Data contains the reference to the parameter, that should
32
        // be scanned to
33
        Data interface{}
34
        // Where the data can be found for scanning
35
        Location ScanIn
36
        // Input must contain the value data if location is in ScanInPath
37
        Input string
38
        // Name of the query variable
39
        Name string
40
}
41

42
// BuildInvalidValueError build a new error, using the passed type and data.
43
func (p *ScanParameter) BuildInvalidValueError(typ reflect.Type, data string) error {
2✔
44
        return &Error{
2✔
45
                Title:  fmt.Sprintf("invalid value for %s", p.Name),
2✔
46
                Detail: fmt.Sprintf("invalid value, expected %s got: %q", typ, data),
2✔
47
                Source: &map[string]interface{}{
2✔
48
                        "parameter": p.Name,
2✔
49
                },
2✔
50
        }
2✔
51
}
2✔
52

53
// ScanParameters scans the request using the given path parameter objects
54
// in case an error is encountered a 400 along with a jsonapi errors object
55
// is sent to the ResponseWriter and false is returned. Returns true if all
56
// values were scanned successfully. The used scanning function is fmt.Sscan.
57
func ScanParameters(w http.ResponseWriter, r *http.Request, parameters ...*ScanParameter) bool {
25✔
58
        for _, param := range parameters {
70✔
59
                var scanData string
45✔
60

45✔
61
                switch param.Location {
45✔
62
                case ScanInPath:
12✔
63
                        // input is filled with path data
12✔
64
                        scanData = param.Input
12✔
65
                case ScanInQuery:
32✔
66
                        // input may not be filled and needs to be parsed from the request
32✔
67
                        input := r.URL.Query()[param.Name]
32✔
68

32✔
69
                        // if parameter is a slice
32✔
70
                        reValue := reflect.ValueOf(param.Data).Elem()
32✔
71
                        if reValue.Kind() == reflect.Slice {
34✔
72
                                size := len(input)
2✔
73
                                array := reflect.MakeSlice(reValue.Type(), size, size)
2✔
74
                                invalid := 0
2✔
75

2✔
76
                                for i := 0; i < size; i++ {
7✔
77
                                        if input[i] == "" {
6✔
78
                                                invalid++
1✔
79
                                                continue
1✔
80
                                        }
81

82
                                        arrElem := array.Index(i - invalid)
4✔
83
                                        n, _ := Scan(input[i], arrElem.Addr().Interface())
4✔
84

4✔
85
                                        if n != 1 {
5✔
86
                                                WriteError(w, http.StatusBadRequest, param.BuildInvalidValueError(arrElem.Type(), input[i]))
1✔
87
                                                return false
1✔
88
                                        }
1✔
89
                                }
90
                                // some of the query parameters where empty, filter them out
91
                                if invalid > 0 {
2✔
92
                                        array = array.Slice(0, size-invalid)
1✔
93
                                }
1✔
94

95
                                reValue.Set(array)
1✔
96

1✔
97
                                // skip parsing at the bottom of the loop
1✔
98
                                continue
1✔
99
                        }
100

101
                        // single parameter scanning
102
                        scanData = strings.Join(input, " ")
30✔
103
                case ScanInHeader:
1✔
104
                        scanData = r.Header.Get(param.Name)
1✔
105
                default:
×
106
                        panic(fmt.Errorf("impossible scanning location: %d", param.Location))
×
107
                }
108

109
                n, _ := Scan(scanData, param.Data)
43✔
110
                // only report on non empty data, govalidator will handle the other cases
43✔
111
                if n != 1 && scanData != "" {
44✔
112
                        WriteError(w, http.StatusBadRequest, param.BuildInvalidValueError(reflect.ValueOf(param.Data).Type(), scanData))
1✔
113
                        return false
1✔
114
                }
1✔
115
        }
116

117
        return true
23✔
118
}
119

120
// Scan works like fmt.Sscan except for strings and decimals, they are directly assigned.
121
func Scan(str string, data interface{}) (int, error) {
47✔
122
        // handle decimal
47✔
123
        if d, ok := data.(*decimal.Decimal); ok {
47✔
124
                nd, err := decimal.NewFromString(str)
×
125
                if err != nil {
×
126
                        return 0, err
×
127
                }
×
128

129
                *d = nd
×
NEW
130

×
UNCOV
131
                return 1, nil
×
132
        }
133

134
        // handle time
135
        if t, ok := data.(*time.Time); ok {
53✔
136
                nt, err := isotime.ParseISO8601(str)
6✔
137
                if err != nil {
6✔
138
                        return 0, err
×
139
                }
×
140

141
                *t = nt
6✔
142

6✔
143
                return 1, nil
6✔
144
        }
145

146
        // Don't handle plain strings with sscan but directly assign the value
147
        strPtr, ok := data.(*string)
41✔
148
        if ok {
45✔
149
                *strPtr = str
4✔
150
                return 1, nil
4✔
151
        }
4✔
152

153
        return fmt.Sscan(str, data)
37✔
154
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc