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

looplab / eventhorizon / 22671292316

04 Mar 2026 01:24PM UTC coverage: 52.974% (-0.1%) from 53.091%
22671292316

Pull #433

github

web-flow
Merge c45e35d3d into 0a9fd8211
Pull Request #433: Upgrade golangci-lint to v2 and fix all lint issues

120 of 233 new or added lines in 49 files covered. (51.5%)

5 existing lines in 3 files now uncovered.

4319 of 8153 relevant lines covered (52.97%)

58.94 hits per line

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

88.41
/command_check.go
1
// Copyright (c) 2014 - The Event Horizon authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package eventhorizon
16

17
import (
18
        "errors"
19
        "reflect"
20
        "time"
21

22
        "github.com/looplab/eventhorizon/uuid"
23
)
24

25
var (
26
        // ErrMissingCommand is when there is no command to be handled.
27
        ErrMissingCommand = errors.New("missing command")
28
        // ErrMissingAggregateID is when a command is missing an aggregate ID.
29
        ErrMissingAggregateID = errors.New("missing aggregate ID")
30
)
31

32
// IsZeroer is used to check if a type is zero-valued, and in that case
33
// is not allowed to be used in a command. See CheckCommand.
34
type IsZeroer interface {
35
        IsZero() bool
36
}
37

38
// CommandFieldError is returned by Dispatch when a field is incorrect.
39
type CommandFieldError struct {
40
        Field string
41
}
42

43
// Error implements the Error method of the error interface.
44
func (c *CommandFieldError) Error() string {
8✔
45
        return "missing field: " + c.Field
8✔
46
}
8✔
47

48
// CheckCommand checks a command for errors.
49
func CheckCommand(cmd Command) error {
19✔
50
        if cmd == nil {
20✔
51
                return ErrMissingCommand
1✔
52
        }
1✔
53

54
        if cmd.AggregateID() == uuid.Nil {
19✔
55
                return ErrMissingAggregateID
1✔
56
        }
1✔
57

58
        rv := reflect.Indirect(reflect.ValueOf(cmd))
17✔
59
        rt := rv.Type()
17✔
60

17✔
61
        for i := range rt.NumField() {
53✔
62
                field := rt.Field(i)
36✔
63
                if field.PkgPath != "" {
36✔
UNCOV
64
                        continue // Skip private field.
×
65
                }
66

67
                tag := field.Tag.Get("eh")
36✔
68
                if tag == "optional" {
37✔
69
                        continue // Optional field.
1✔
70
                }
71

72
                var zero bool
35✔
73
                switch foo := rv.Field(i).Interface().(type) {
35✔
74
                case IsZeroer:
3✔
75
                        zero = foo.IsZero()
3✔
76
                default:
32✔
77
                        zero = isZero(rv.Field(i))
32✔
78
                }
79

80
                if zero {
43✔
81
                        return &CommandFieldError{field.Name}
8✔
82
                }
8✔
83
        }
84

85
        return nil
9✔
86
}
87

88
func isZero(v reflect.Value) bool {
38✔
89
        switch v.Kind() {
38✔
90
        case reflect.Func, reflect.Chan, reflect.Ptr, reflect.UnsafePointer:
×
91
                // Types that are not allowed at all.
×
92
                // NOTE: Would be better with its own error for this.
×
93
                return true
×
94
        case reflect.Map, reflect.Slice:
2✔
95
                return v.IsNil()
2✔
96
        case reflect.Array:
22✔
97
                // Special case to check zero values of UUIDs.
22✔
98
                if obj, ok := v.Interface().(uuid.UUID); ok {
40✔
99
                        return obj == uuid.Nil
18✔
100
                }
18✔
101

102
                for i := range v.Len() {
8✔
103
                        if !isZero(v.Index(i)) {
7✔
104
                                return false
3✔
105
                        }
3✔
106
                }
107

108
                return true
1✔
109
        case reflect.Interface, reflect.String:
6✔
110
                z := reflect.Zero(v.Type())
6✔
111

6✔
112
                return v.Interface() == z.Interface()
6✔
113
        case reflect.Struct:
2✔
114
                // Special case to get zero values by method.
2✔
115
                if obj, ok := v.Interface().(time.Time); ok {
2✔
116
                        return obj.IsZero()
×
UNCOV
117
                }
×
118

119
                // Check public fields for zero values.
120
                z := true
2✔
121

2✔
122
                for i := range v.NumField() {
4✔
123
                        if v.Type().Field(i).PkgPath != "" {
2✔
124
                                continue // Skip private fields.
×
125
                        }
126

127
                        z = z && isZero(v.Field(i))
2✔
128
                }
129

130
                return z
2✔
131
        default:
6✔
132
                // Don't check for zero for value types:
6✔
133
                // Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32,
6✔
134
                // Uint64, Float32, Float64, Complex64, Complex128
6✔
135
                return false
6✔
136
        }
137
}
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