@su-record/vibe 2.4.72 → 2.4.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +216 -215
- package/README.md +4 -4
- package/agents/research/best-practices-agent.md +13 -13
- package/agents/research/codebase-patterns-agent.md +33 -33
- package/agents/research/framework-docs-agent.md +23 -23
- package/agents/research/security-advisory-agent.md +29 -29
- package/agents/review/architecture-reviewer.md +31 -31
- package/agents/review/complexity-reviewer.md +21 -21
- package/agents/review/data-integrity-reviewer.md +29 -29
- package/agents/review/git-history-reviewer.md +24 -24
- package/agents/review/performance-reviewer.md +29 -29
- package/agents/review/python-reviewer.md +53 -53
- package/agents/review/rails-reviewer.md +40 -40
- package/agents/review/react-reviewer.md +40 -40
- package/agents/review/security-reviewer.md +29 -29
- package/agents/review/simplicity-reviewer.md +24 -24
- package/agents/review/test-coverage-reviewer.md +31 -31
- package/agents/review/typescript-reviewer.md +41 -41
- package/commands/vibe.analyze.md +103 -7
- package/commands/vibe.reason.md +106 -0
- package/commands/vibe.review.md +123 -38
- package/commands/vibe.run.md +286 -223
- package/commands/vibe.spec.md +425 -186
- package/commands/vibe.utils.md +104 -3
- package/commands/vibe.verify.md +179 -86
- package/dist/cli/detect.js +40 -40
- package/dist/cli/detect.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/llm.js +5 -5
- package/dist/cli/llm.js.map +1 -1
- package/dist/cli/setup.js +3 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/lib/ContextCompressor.js +1 -1
- package/dist/lib/ContextCompressor.js.map +1 -1
- package/dist/lib/MemoryManager.d.ts +13 -155
- package/dist/lib/MemoryManager.d.ts.map +1 -1
- package/dist/lib/MemoryManager.js +52 -617
- package/dist/lib/MemoryManager.js.map +1 -1
- package/dist/lib/gemini-api.js +12 -12
- package/dist/lib/gemini-api.js.map +1 -1
- package/dist/lib/gemini-oauth.js +22 -22
- package/dist/lib/gemini-oauth.js.map +1 -1
- package/dist/lib/gemini-storage.js +3 -3
- package/dist/lib/gemini-storage.js.map +1 -1
- package/dist/lib/gpt-api.js +11 -11
- package/dist/lib/gpt-api.js.map +1 -1
- package/dist/lib/gpt-oauth.js +28 -28
- package/dist/lib/gpt-oauth.js.map +1 -1
- package/dist/lib/gpt-storage.js +3 -3
- package/dist/lib/gpt-storage.js.map +1 -1
- package/dist/lib/memory/KnowledgeGraph.d.ts +34 -0
- package/dist/lib/memory/KnowledgeGraph.d.ts.map +1 -0
- package/dist/lib/memory/KnowledgeGraph.js +216 -0
- package/dist/lib/memory/KnowledgeGraph.js.map +1 -0
- package/dist/lib/memory/KnowledgeGraph.test.d.ts +2 -0
- package/dist/lib/memory/KnowledgeGraph.test.d.ts.map +1 -0
- package/dist/lib/memory/KnowledgeGraph.test.js +189 -0
- package/dist/lib/memory/KnowledgeGraph.test.js.map +1 -0
- package/dist/lib/memory/MemorySearch.d.ts +25 -0
- package/dist/lib/memory/MemorySearch.d.ts.map +1 -0
- package/dist/lib/memory/MemorySearch.js +85 -0
- package/dist/lib/memory/MemorySearch.js.map +1 -0
- package/dist/lib/memory/MemorySearch.test.d.ts +2 -0
- package/dist/lib/memory/MemorySearch.test.d.ts.map +1 -0
- package/dist/lib/memory/MemorySearch.test.js +149 -0
- package/dist/lib/memory/MemorySearch.test.js.map +1 -0
- package/dist/lib/memory/MemoryStorage.d.ts +77 -0
- package/dist/lib/memory/MemoryStorage.d.ts.map +1 -0
- package/dist/lib/memory/MemoryStorage.js +278 -0
- package/dist/lib/memory/MemoryStorage.js.map +1 -0
- package/dist/lib/memory/MemoryStorage.test.d.ts +2 -0
- package/dist/lib/memory/MemoryStorage.test.d.ts.map +1 -0
- package/dist/lib/memory/MemoryStorage.test.js +198 -0
- package/dist/lib/memory/MemoryStorage.test.js.map +1 -0
- package/dist/lib/memory/index.d.ts +4 -0
- package/dist/lib/memory/index.d.ts.map +1 -0
- package/dist/lib/memory/index.js +8 -0
- package/dist/lib/memory/index.js.map +1 -0
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +4 -6
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/tools/convention/analyzeComplexity.d.ts +3 -1
- package/dist/tools/convention/analyzeComplexity.d.ts.map +1 -1
- package/dist/tools/convention/analyzeComplexity.js +102 -4
- package/dist/tools/convention/analyzeComplexity.js.map +1 -1
- package/dist/tools/convention/analyzeComplexity.test.d.ts +2 -0
- package/dist/tools/convention/analyzeComplexity.test.d.ts.map +1 -0
- package/dist/tools/convention/analyzeComplexity.test.js +207 -0
- package/dist/tools/convention/analyzeComplexity.test.js.map +1 -0
- package/dist/tools/convention/applyQualityRules.js +1 -1
- package/dist/tools/convention/applyQualityRules.js.map +1 -1
- package/dist/tools/convention/checkCouplingCohesion.js +2 -2
- package/dist/tools/convention/checkCouplingCohesion.js.map +1 -1
- package/dist/tools/convention/suggestImprovements.js +1 -1
- package/dist/tools/convention/suggestImprovements.js.map +1 -1
- package/dist/tools/convention/validateCodeQuality.d.ts +3 -1
- package/dist/tools/convention/validateCodeQuality.d.ts.map +1 -1
- package/dist/tools/convention/validateCodeQuality.js +145 -2
- package/dist/tools/convention/validateCodeQuality.js.map +1 -1
- package/dist/tools/convention/validateCodeQuality.test.d.ts +2 -0
- package/dist/tools/convention/validateCodeQuality.test.d.ts.map +1 -0
- package/dist/tools/convention/validateCodeQuality.test.js +230 -0
- package/dist/tools/convention/validateCodeQuality.test.js.map +1 -0
- package/dist/tools/memory/autoSaveContext.js +1 -1
- package/dist/tools/memory/autoSaveContext.js.map +1 -1
- package/dist/tools/memory/createMemoryTimeline.js +27 -27
- package/dist/tools/memory/createMemoryTimeline.js.map +1 -1
- package/dist/tools/memory/deleteMemory.js +1 -1
- package/dist/tools/memory/deleteMemory.js.map +1 -1
- package/dist/tools/memory/getMemoryGraph.js +24 -24
- package/dist/tools/memory/getMemoryGraph.js.map +1 -1
- package/dist/tools/memory/getSessionContext.js +36 -36
- package/dist/tools/memory/getSessionContext.js.map +1 -1
- package/dist/tools/memory/linkMemories.js +21 -21
- package/dist/tools/memory/linkMemories.js.map +1 -1
- package/dist/tools/memory/prioritizeMemory.js +1 -1
- package/dist/tools/memory/prioritizeMemory.js.map +1 -1
- package/dist/tools/memory/restoreSessionContext.js +1 -1
- package/dist/tools/memory/restoreSessionContext.js.map +1 -1
- package/dist/tools/memory/searchMemories.js +1 -1
- package/dist/tools/memory/searchMemories.js.map +1 -1
- package/dist/tools/memory/searchMemoriesAdvanced.js +42 -42
- package/dist/tools/memory/searchMemoriesAdvanced.js.map +1 -1
- package/dist/tools/memory/startSession.js +2 -2
- package/dist/tools/memory/startSession.js.map +1 -1
- package/dist/tools/memory/updateMemory.js +1 -1
- package/dist/tools/memory/updateMemory.js.map +1 -1
- package/dist/tools/semantic/analyzeDependencyGraph.js +38 -38
- package/dist/tools/semantic/analyzeDependencyGraph.js.map +1 -1
- package/dist/tools/semantic/findReferences.js +1 -1
- package/dist/tools/semantic/findReferences.js.map +1 -1
- package/dist/tools/semantic/findSymbol.js +1 -1
- package/dist/tools/semantic/findSymbol.js.map +1 -1
- package/dist/tools/time/getCurrentTime.js +1 -1
- package/dist/tools/time/getCurrentTime.js.map +1 -1
- package/dist/tools/ui/previewUiAscii.js +2 -2
- package/dist/tools/ui/previewUiAscii.js.map +1 -1
- package/hooks/hooks.json +11 -2
- package/hooks/scripts/llm-orchestrate.js +1 -1
- package/hooks/scripts/utils.js +31 -6
- package/languages/csharp-unity.md +82 -83
- package/languages/dart-flutter.md +89 -88
- package/languages/go.md +76 -75
- package/languages/java-spring.md +85 -84
- package/languages/kotlin-android.md +64 -63
- package/languages/python-django.md +83 -82
- package/languages/python-fastapi.md +82 -81
- package/languages/rust.md +75 -74
- package/languages/swift-ios.md +73 -72
- package/languages/typescript-electron.md +70 -71
- package/languages/typescript-nextjs.md +93 -92
- package/languages/typescript-node.md +64 -63
- package/languages/typescript-nuxt.md +113 -112
- package/languages/typescript-react-native.md +82 -81
- package/languages/typescript-react.md +76 -75
- package/languages/typescript-tauri.md +74 -75
- package/languages/typescript-vue.md +73 -72
- package/package.json +1 -1
- package/skills/git-worktree.md +25 -25
- package/skills/multi-llm-orchestration.md +4 -6
- package/skills/priority-todos.md +39 -39
- package/skills/vibe-capabilities.md +2 -2
- package/vibe/config.json +2 -2
package/languages/go.md
CHANGED
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Go Quality Rules
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Core Principles (inherited from core)
|
|
4
4
|
|
|
5
5
|
```markdown
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
# Core Principles (inherited from core)
|
|
7
|
+
Single Responsibility (SRP)
|
|
8
|
+
No Duplication (DRY)
|
|
9
|
+
Reusability
|
|
10
|
+
Low Complexity
|
|
11
|
+
Function <= 30 lines
|
|
12
|
+
Nesting <= 3 levels
|
|
13
|
+
Cyclomatic complexity <= 10
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
## Go
|
|
16
|
+
## Go Specific Rules
|
|
16
17
|
|
|
17
|
-
### 1.
|
|
18
|
+
### 1. Error Handling
|
|
18
19
|
|
|
19
20
|
```go
|
|
20
|
-
//
|
|
21
|
+
// Bad: Ignoring error
|
|
21
22
|
data, _ := ioutil.ReadFile("config.json")
|
|
22
23
|
|
|
23
|
-
//
|
|
24
|
+
// Good: Always handle errors
|
|
24
25
|
data, err := ioutil.ReadFile("config.json")
|
|
25
26
|
if err != nil {
|
|
26
|
-
return fmt.Errorf("
|
|
27
|
+
return fmt.Errorf("failed to read config file: %w", err)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
//
|
|
30
|
+
// Good: Custom error type
|
|
30
31
|
type NotFoundError struct {
|
|
31
32
|
Resource string
|
|
32
33
|
ID string
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
func (e *NotFoundError) Error() string {
|
|
36
|
-
return fmt.Sprintf("%s (ID: %s)
|
|
37
|
+
return fmt.Sprintf("%s not found (ID: %s)", e.Resource, e.ID)
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
//
|
|
40
|
+
// Usage
|
|
40
41
|
func GetUser(id string) (*User, error) {
|
|
41
42
|
user, err := repo.FindByID(id)
|
|
42
43
|
if err != nil {
|
|
43
|
-
return nil, fmt.Errorf("
|
|
44
|
+
return nil, fmt.Errorf("failed to get user: %w", err)
|
|
44
45
|
}
|
|
45
46
|
if user == nil {
|
|
46
|
-
return nil, &NotFoundError{Resource: "
|
|
47
|
+
return nil, &NotFoundError{Resource: "User", ID: id}
|
|
47
48
|
}
|
|
48
49
|
return user, nil
|
|
49
50
|
}
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
### 2.
|
|
53
|
+
### 2. Structs and Interfaces
|
|
53
54
|
|
|
54
55
|
```go
|
|
55
|
-
//
|
|
56
|
+
// Good: Struct definition
|
|
56
57
|
type User struct {
|
|
57
58
|
ID string `json:"id"`
|
|
58
59
|
Email string `json:"email"`
|
|
@@ -61,7 +62,7 @@ type User struct {
|
|
|
61
62
|
UpdatedAt time.Time `json:"updated_at"`
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
//
|
|
65
|
+
// Good: Constructor function
|
|
65
66
|
func NewUser(email, name string) *User {
|
|
66
67
|
now := time.Now()
|
|
67
68
|
return &User{
|
|
@@ -73,7 +74,7 @@ func NewUser(email, name string) *User {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
//
|
|
77
|
+
// Good: Small interfaces (Go philosophy)
|
|
77
78
|
type Reader interface {
|
|
78
79
|
Read(p []byte) (n int, err error)
|
|
79
80
|
}
|
|
@@ -82,13 +83,13 @@ type Writer interface {
|
|
|
82
83
|
Write(p []byte) (n int, err error)
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
//
|
|
86
|
+
// Good: Interface composition
|
|
86
87
|
type ReadWriter interface {
|
|
87
88
|
Reader
|
|
88
89
|
Writer
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
//
|
|
92
|
+
// Good: Repository interface
|
|
92
93
|
type UserRepository interface {
|
|
93
94
|
FindByID(ctx context.Context, id string) (*User, error)
|
|
94
95
|
FindByEmail(ctx context.Context, email string) (*User, error)
|
|
@@ -98,12 +99,12 @@ type UserRepository interface {
|
|
|
98
99
|
}
|
|
99
100
|
```
|
|
100
101
|
|
|
101
|
-
### 3. Context
|
|
102
|
+
### 3. Context Usage
|
|
102
103
|
|
|
103
104
|
```go
|
|
104
|
-
//
|
|
105
|
+
// Good: Context propagation
|
|
105
106
|
func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
|
|
106
|
-
//
|
|
107
|
+
// Pass context to downstream functions
|
|
107
108
|
user, err := s.repo.FindByID(ctx, id)
|
|
108
109
|
if err != nil {
|
|
109
110
|
return nil, err
|
|
@@ -111,7 +112,7 @@ func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
|
|
|
111
112
|
return user, nil
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
//
|
|
115
|
+
// Good: Context timeout
|
|
115
116
|
func (h *Handler) HandleRequest(w http.ResponseWriter, r *http.Request) {
|
|
116
117
|
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
|
117
118
|
defer cancel()
|
|
@@ -119,7 +120,7 @@ func (h *Handler) HandleRequest(w http.ResponseWriter, r *http.Request) {
|
|
|
119
120
|
result, err := h.service.Process(ctx)
|
|
120
121
|
if err != nil {
|
|
121
122
|
if errors.Is(err, context.DeadlineExceeded) {
|
|
122
|
-
http.Error(w, "
|
|
123
|
+
http.Error(w, "Request timeout", http.StatusRequestTimeout)
|
|
123
124
|
return
|
|
124
125
|
}
|
|
125
126
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
@@ -130,10 +131,10 @@ func (h *Handler) HandleRequest(w http.ResponseWriter, r *http.Request) {
|
|
|
130
131
|
}
|
|
131
132
|
```
|
|
132
133
|
|
|
133
|
-
### 4. HTTP
|
|
134
|
+
### 4. HTTP Handlers (net/http, Gin, Echo)
|
|
134
135
|
|
|
135
136
|
```go
|
|
136
|
-
//
|
|
137
|
+
// Good: net/http handler
|
|
137
138
|
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
|
138
139
|
id := chi.URLParam(r, "id")
|
|
139
140
|
|
|
@@ -144,7 +145,7 @@ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
|
|
144
145
|
http.Error(w, err.Error(), http.StatusNotFound)
|
|
145
146
|
return
|
|
146
147
|
}
|
|
147
|
-
http.Error(w, "
|
|
148
|
+
http.Error(w, "Server error", http.StatusInternalServerError)
|
|
148
149
|
return
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -152,7 +153,7 @@ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
|
|
152
153
|
json.NewEncoder(w).Encode(user)
|
|
153
154
|
}
|
|
154
155
|
|
|
155
|
-
//
|
|
156
|
+
// Good: Gin handler
|
|
156
157
|
func (h *UserHandler) GetUser(c *gin.Context) {
|
|
157
158
|
id := c.Param("id")
|
|
158
159
|
|
|
@@ -163,14 +164,14 @@ func (h *UserHandler) GetUser(c *gin.Context) {
|
|
|
163
164
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
164
165
|
return
|
|
165
166
|
}
|
|
166
|
-
c.JSON(http.StatusInternalServerError, gin.H{"error": "
|
|
167
|
+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Server error"})
|
|
167
168
|
return
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
c.JSON(http.StatusOK, user)
|
|
171
172
|
}
|
|
172
173
|
|
|
173
|
-
//
|
|
174
|
+
// Good: Echo handler
|
|
174
175
|
func (h *UserHandler) GetUser(c echo.Context) error {
|
|
175
176
|
id := c.Param("id")
|
|
176
177
|
|
|
@@ -180,17 +181,17 @@ func (h *UserHandler) GetUser(c echo.Context) error {
|
|
|
180
181
|
if errors.As(err, ¬Found) {
|
|
181
182
|
return c.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
|
|
182
183
|
}
|
|
183
|
-
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "
|
|
184
|
+
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Server error"})
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
return c.JSON(http.StatusOK, user)
|
|
187
188
|
}
|
|
188
189
|
```
|
|
189
190
|
|
|
190
|
-
### 5.
|
|
191
|
+
### 5. Dependency Injection
|
|
191
192
|
|
|
192
193
|
```go
|
|
193
|
-
//
|
|
194
|
+
// Good: Inject dependencies into struct
|
|
194
195
|
type UserService struct {
|
|
195
196
|
repo UserRepository
|
|
196
197
|
cache CacheRepository
|
|
@@ -209,7 +210,7 @@ func NewUserService(
|
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
212
|
|
|
212
|
-
//
|
|
213
|
+
// Good: Options pattern
|
|
213
214
|
type ServerOption func(*Server)
|
|
214
215
|
|
|
215
216
|
func WithPort(port int) ServerOption {
|
|
@@ -226,7 +227,7 @@ func WithTimeout(timeout time.Duration) ServerOption {
|
|
|
226
227
|
|
|
227
228
|
func NewServer(opts ...ServerOption) *Server {
|
|
228
229
|
s := &Server{
|
|
229
|
-
port: 8080, //
|
|
230
|
+
port: 8080, // Default
|
|
230
231
|
timeout: 30 * time.Second,
|
|
231
232
|
}
|
|
232
233
|
for _, opt := range opts {
|
|
@@ -235,17 +236,17 @@ func NewServer(opts ...ServerOption) *Server {
|
|
|
235
236
|
return s
|
|
236
237
|
}
|
|
237
238
|
|
|
238
|
-
//
|
|
239
|
+
// Usage
|
|
239
240
|
server := NewServer(
|
|
240
241
|
WithPort(3000),
|
|
241
242
|
WithTimeout(60*time.Second),
|
|
242
243
|
)
|
|
243
244
|
```
|
|
244
245
|
|
|
245
|
-
### 6.
|
|
246
|
+
### 6. Concurrency
|
|
246
247
|
|
|
247
248
|
```go
|
|
248
|
-
//
|
|
249
|
+
// Good: Goroutine + Channel
|
|
249
250
|
func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
250
251
|
results := make(chan Result, len(items))
|
|
251
252
|
errs := make(chan error, len(items))
|
|
@@ -264,7 +265,7 @@ func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
|
264
265
|
}(item)
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
//
|
|
268
|
+
// Collect results
|
|
268
269
|
go func() {
|
|
269
270
|
wg.Wait()
|
|
270
271
|
close(results)
|
|
@@ -276,7 +277,7 @@ func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
|
276
277
|
finalResults = append(finalResults, result)
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
//
|
|
280
|
+
// Return first error
|
|
280
281
|
select {
|
|
281
282
|
case err := <-errs:
|
|
282
283
|
return nil, err
|
|
@@ -285,7 +286,7 @@ func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
//
|
|
289
|
+
// Good: Using errgroup (recommended)
|
|
289
290
|
import "golang.org/x/sync/errgroup"
|
|
290
291
|
|
|
291
292
|
func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
@@ -293,7 +294,7 @@ func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
|
293
294
|
results := make([]Result, len(items))
|
|
294
295
|
|
|
295
296
|
for i, item := range items {
|
|
296
|
-
i, item := i, item //
|
|
297
|
+
i, item := i, item // Closure capture
|
|
297
298
|
g.Go(func() error {
|
|
298
299
|
result, err := processItem(ctx, item)
|
|
299
300
|
if err != nil {
|
|
@@ -311,19 +312,19 @@ func ProcessItems(ctx context.Context, items []Item) ([]Result, error) {
|
|
|
311
312
|
}
|
|
312
313
|
```
|
|
313
314
|
|
|
314
|
-
### 7.
|
|
315
|
+
### 7. Testing
|
|
315
316
|
|
|
316
317
|
```go
|
|
317
|
-
//
|
|
318
|
+
// Good: Table-driven tests
|
|
318
319
|
func TestAdd(t *testing.T) {
|
|
319
320
|
tests := []struct {
|
|
320
321
|
name string
|
|
321
322
|
a, b int
|
|
322
323
|
expected int
|
|
323
324
|
}{
|
|
324
|
-
{"
|
|
325
|
-
{"
|
|
326
|
-
{"
|
|
325
|
+
{"positive addition", 2, 3, 5},
|
|
326
|
+
{"negative addition", -1, -2, -3},
|
|
327
|
+
{"addition with zero", 0, 5, 5},
|
|
327
328
|
}
|
|
328
329
|
|
|
329
330
|
for _, tt := range tests {
|
|
@@ -336,7 +337,7 @@ func TestAdd(t *testing.T) {
|
|
|
336
337
|
}
|
|
337
338
|
}
|
|
338
339
|
|
|
339
|
-
//
|
|
340
|
+
// Good: Using mock (testify)
|
|
340
341
|
type MockUserRepository struct {
|
|
341
342
|
mock.Mock
|
|
342
343
|
}
|
|
@@ -353,7 +354,7 @@ func TestUserService_GetUser(t *testing.T) {
|
|
|
353
354
|
mockRepo := new(MockUserRepository)
|
|
354
355
|
service := NewUserService(mockRepo, nil, slog.Default())
|
|
355
356
|
|
|
356
|
-
expectedUser := &User{ID: "123", Name: "
|
|
357
|
+
expectedUser := &User{ID: "123", Name: "Test"}
|
|
357
358
|
mockRepo.On("FindByID", mock.Anything, "123").Return(expectedUser, nil)
|
|
358
359
|
|
|
359
360
|
user, err := service.GetUser(context.Background(), "123")
|
|
@@ -364,33 +365,33 @@ func TestUserService_GetUser(t *testing.T) {
|
|
|
364
365
|
}
|
|
365
366
|
```
|
|
366
367
|
|
|
367
|
-
##
|
|
368
|
+
## File Structure
|
|
368
369
|
|
|
369
|
-
```
|
|
370
|
+
```text
|
|
370
371
|
project/
|
|
371
372
|
├── cmd/
|
|
372
373
|
│ └── server/
|
|
373
|
-
│ └── main.go #
|
|
374
|
+
│ └── main.go # Entry point
|
|
374
375
|
├── internal/
|
|
375
|
-
│ ├── domain/ #
|
|
376
|
-
│ ├── handler/ # HTTP
|
|
377
|
-
│ ├── service/ #
|
|
378
|
-
│ ├── repository/ #
|
|
379
|
-
│ └── middleware/ #
|
|
380
|
-
├── pkg/ #
|
|
381
|
-
├── config/ #
|
|
382
|
-
├── migrations/ # DB
|
|
376
|
+
│ ├── domain/ # Domain models
|
|
377
|
+
│ ├── handler/ # HTTP handlers
|
|
378
|
+
│ ├── service/ # Business logic
|
|
379
|
+
│ ├── repository/ # Data access
|
|
380
|
+
│ └── middleware/ # Middleware
|
|
381
|
+
├── pkg/ # Public packages
|
|
382
|
+
├── config/ # Configuration
|
|
383
|
+
├── migrations/ # DB migrations
|
|
383
384
|
├── go.mod
|
|
384
385
|
└── go.sum
|
|
385
386
|
```
|
|
386
387
|
|
|
387
|
-
##
|
|
388
|
+
## Checklist
|
|
388
389
|
|
|
389
|
-
- [ ]
|
|
390
|
-
- [ ] fmt.Errorf("%w", err)
|
|
391
|
-
- [ ] Context
|
|
392
|
-
- [ ]
|
|
393
|
-
- [ ]
|
|
394
|
-
- [ ]
|
|
395
|
-
- [ ] gofmt, golint, go vet
|
|
396
|
-
- [ ]
|
|
390
|
+
- [ ] Always handle errors (no _, err)
|
|
391
|
+
- [ ] Wrap errors with fmt.Errorf("%w", err)
|
|
392
|
+
- [ ] Pass Context as first argument
|
|
393
|
+
- [ ] Define small interfaces
|
|
394
|
+
- [ ] Use constructor functions (NewXxx)
|
|
395
|
+
- [ ] Table-driven tests
|
|
396
|
+
- [ ] Pass gofmt, golint, go vet
|
|
397
|
+
- [ ] Watch for race conditions in concurrency
|