Skip to content

Commit 8e4f5b3

Browse files
committed
test: add main-flow tests for uncovered functions, real impls only, per new strategy
1 parent 6180587 commit 8e4f5b3

58 files changed

Lines changed: 8167 additions & 424 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cursor/rules/TDD.mdc

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
description: Enforce Test-Driven Development (TDD) in this project — always write tests first
3+
globs: ["**/*.go"]
4+
alwaysApply: true
5+
---
6+
7+
# 🧪 Test-Driven Development (TDD) Guidelines for SaveMessage Bot
8+
9+
This rule enforces Test-Driven Development (TDD) as the standard workflow when developing new features.
10+
11+
---
12+
13+
## 🚦 What is TDD?
14+
15+
**Test-Driven Development (TDD)** means:
16+
17+
1. ✅ Write tests first (describe what the feature must do)
18+
2. 🛠 Write the minimal code to pass the test
19+
3. 🧹 Refactor with safety (the tests will catch regressions)
20+
21+
This ensures:
22+
- Cleaner architecture
23+
- Safer feature changes
24+
- Fewer bugs and regressions
25+
26+
---
27+
28+
## 📋 TDD Workflow
29+
30+
**For every new feature:**
31+
32+
### ✅ Step 1: Write Tests
33+
- Use Go’s `testing` package
34+
- Mock external dependencies (Telegram bot, OpenAI, DB)
35+
- Add edge case + failure tests
36+
- Prefer table-driven test format
37+
38+
### 🛠 Step 2: Implement the Code
39+
- Write just enough logic to make the tests pass
40+
- Keep functions focused and testable
41+
- Avoid unrelated logic during this phase
42+
43+
### 🧪 Step 3: Run Tests
44+
```bash
45+
go test ./... -cover
46+
```
47+
48+
Make sure:
49+
- All tests pass
50+
- Code coverage remains high (100% for new code ideally)
51+
52+
---
53+
54+
## 📂 Test Organization
55+
56+
| Location | Purpose |
57+
|-------------------------|----------------------------------|
58+
| `handlers/*_test.go` | Test user interaction flows |
59+
| `services/*_test.go` | Test logic and DB integration |
60+
| `internal/ai/*_test.go` | Test AI response formatting |
61+
| `internal/mocks/` | Mock interfaces and dependencies |
62+
63+
---
64+
65+
## 🔧 Use Interfaces for Service Layer
66+
67+
To enable mock-based testing:
68+
- Define service interfaces like `MessageService`, `TopicService`, `AIService`, etc.
69+
- Inject interfaces into handlers
70+
- Keep concrete logic in `services/`, mocks in `internal/mocks/`
71+
72+
### Example Interface:
73+
```go
74+
type MessageService interface {
75+
CopyMessage(...)
76+
DeleteMessage(...)
77+
EditMessage(...)
78+
}
79+
```
80+
81+
---
82+
83+
## 📝 Example Workflow
84+
85+
Suppose you're adding a feature like "Edit saved message":
86+
87+
1. ✅ Write the test:
88+
```go
89+
func TestHandleEditRequest_ShouldUpdateMessage(t *testing.T) {
90+
// mock message, bot, and services
91+
// simulate edit message payload
92+
// assert message was updated correctly
93+
}
94+
```
95+
96+
2. 🛠 Write the code:
97+
```go
98+
func (h *MessageHandler) HandleEditRequest(...) {
99+
...
100+
}
101+
```
102+
103+
3. 🧪 Run the test suite:
104+
```bash
105+
go test ./... -v -cover
106+
```
107+
108+
---
109+
110+
## ✅ Rule of Thumb
111+
112+
| Do this... | To ensure... |
113+
|----------------------------------|----------------------------------------|
114+
| 🧪 Write the test before the code | Feature is scoped and testable |
115+
| 🧩 Mock dependencies | Tests run fast and isolated |
116+
| 💯 Target 100% coverage for new code | Safer refactoring and future changes |
117+
| 🔁 Run tests before every commit | Avoid broken builds |
118+
119+
---
120+
121+
## 💬 Questions?
122+
123+
If you're unsure how to write tests, mock a service, or structure test cases, ask the team or refer to examples in:
124+
- `handlers/*_test.go`
125+
- `services/*_test.go`
126+
- `internal/mocks/`
127+
128+
---
129+
130+
Happy testing! 💪
131+
– SaveMessage Bot Team
Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,52 @@
1+
---
2+
description: Enforce modular architecture, clean separation, and reusable logic for AI Telegram bot
3+
globs: ["**/*.go"]
4+
alwaysApply: true
5+
---
6+
7+
# 🧱 Modular AI Telegram Bot Architecture Rules
18

2-
# Modular AI Telegram Bot Architecture Rules
9+
This rule enforces best practices for building scalable, testable, and clean modular architecture in the SaveMessage Telegram bot project.
10+
11+
---
312

413
## ✅ 1. Functional Isolation
514

6-
Each key behavior should be implemented as a **dedicated function** with a single purpose:
15+
Each core behavior must be a **dedicated function** with a single responsibility:
716

8-
- `DeleteMessage(chatID, messageID)`
9-
- `RequestTopicName(chatID, originalMessageID)`
10-
- `CreateNewTopic(chatID, topicName)`
11-
- `SuggestCategories(messageText) -> []string`
12-
- `MoveMessageToTopic(originalMsgID, targetTopicID)`
17+
- `DeleteMessage(chatID, messageID)`
18+
- `RequestTopicName(chatID, originalMessageID)`
19+
- `CreateNewTopic(chatID, topicName)`
20+
- `SuggestCategories(messageText) -> []string`
21+
- `MoveMessageToTopic(originalMsgID, targetTopicID)`
1322
- `SendEditPrompt(originalMsgID)`
1423

15-
All these functions should be reusable, predictable, and independently testable.
24+
These functions should be:
25+
- Predictable
26+
- Testable
27+
- Reusable
28+
- Free of side-effects outside their domain
1629

17-
## ✅ 2. Handler Separation by User Flow
18-
19-
Create **separate handlers** for user paths such as:
30+
---
2031

21-
- Selecting an existing folder from suggestions
22-
→ `HandleExistingTopicSelection()`
32+
## ✅ 2. Handler Separation by User Flow
2333

24-
- Choosing to create a new folder from AI suggestion
25-
→ `HandleNewTopicCreationRequest()`
34+
Each user journey must have its own **handler function**:
2635

27-
- Typing the topic name after being prompted
28-
→ `HandleNewTopicNameEntry()`
36+
| User Action | Handler Function |
37+
|------------------------------------------|------------------------------------|
38+
| Select an existing folder | `HandleExistingTopicSelection()` |
39+
| Create new folder from AI suggestion | `HandleNewTopicCreationRequest()` |
40+
| Enter name for new folder | `HandleNewTopicNameEntry()` |
41+
| Edit a saved message | `HandleEditRequest()` |
2942

30-
- Editing a message by sending `Edit:[ID] new text`
31-
→ `HandleEditRequest()`
43+
This ensures logic remains traceable and modular.
3244

33-
This keeps business logic traceable, debuggable, and scalable.
45+
---
3446

3547
## ✅ 3. Command/Event Routing
3648

37-
Set up a router or dispatcher to route incoming updates:
49+
Use a **central dispatcher** or router to route updates based on context:
3850

3951
```go
4052
func HandleUpdate(update tgbotapi.Update) {
@@ -53,21 +65,34 @@ func HandleUpdate(update tgbotapi.Update) {
5365
}
5466
```
5567

68+
This isolates behavior from parsing logic and avoids duplication.
69+
70+
---
71+
5672
## ✅ 4. Architecture Goals
5773

58-
- Respect clean architecture / separation of concerns
59-
- Use clear package boundaries: handlers/, services/, ai/, utils/
60-
- All messages, callbacks, and responses should go through a central dispatcher
61-
- All business logic should be inside small, focused services
62-
- No logic inside main.go except setup
74+
Maintain clean architectural principles:
75+
76+
- All logic should live in one of: `handlers/`, `services/`, `ai/`, or `utils/`
77+
- `main.go` should only handle setup, wiring, and server start
78+
- Keep message-handling logic out of `main.go`
79+
- Centralize all routing and command parsing
80+
81+
---
6382

6483
## 🧪 Additional Notes
6584

66-
- Always use logging for every handler entry and exit
67-
- Future-proof the code for new interaction types (search, tagging, etc.)
68-
- No hard-coded text: use constants or i18n struct
69-
- No message or user data should be saved in storage (privacy-first)
70-
description:
71-
globs:
72-
alwaysApply: false
85+
- Always log handler **entry and exit**
86+
- Prepare services to be **mocked** for testing
87+
- Future-proof for features like:
88+
- Search
89+
- Tagging
90+
- Reactions
91+
- Avoid hardcoded text — use constants or i18n
92+
- Respect user privacy:
93+
- Do not store message content or personal data
94+
- Only store minimal user metadata if needed (e.g., roles, pro status)
95+
7396
---
97+
98+
🏁 Following these rules will ensure a modular, scalable, and robust bot architecture that’s AI-ready and privacy-first.

Makefile

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
.PHONY: run test cover lint clean build help
2+
3+
# Default target
4+
help:
5+
@echo "Available commands:"
6+
@echo " run - Run the bot"
7+
@echo " test - Run all tests with verbose output"
8+
@echo " cover - Run tests with coverage report"
9+
@echo " lint - Run golangci-lint"
10+
@echo " clean - Clean build artifacts and coverage files"
11+
@echo " build - Build the bot binary"
12+
@echo " deps - Install dependencies"
13+
14+
# Run the bot
15+
run:
16+
go run main.go
17+
18+
# Run all tests with verbose output
19+
test:
20+
go test ./internal/... -v
21+
22+
# Run tests with coverage report
23+
cover:
24+
go test ./internal/... -coverprofile=coverage.out
25+
go tool cover -html=coverage.out -o coverage.html
26+
@echo "Coverage report generated: coverage.html"
27+
@echo "Coverage summary:"
28+
@go tool cover -func=coverage.out | tail -1
29+
30+
# Run golangci-lint
31+
lint:
32+
golangci-lint run
33+
34+
# Clean build artifacts and coverage files
35+
clean:
36+
rm -rf coverage.out coverage.html
37+
rm -rf main bot_modular
38+
rm -rf cmd/modular/modular
39+
40+
# Build the bot binary
41+
build:
42+
go build -o bot_modular main.go
43+
44+
# Build modular version
45+
build-modular:
46+
go build -o cmd/modular/modular cmd/modular/main.go
47+
48+
# Install dependencies
49+
deps:
50+
go mod tidy
51+
go mod download
52+
53+
# Install development tools
54+
dev-tools:
55+
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
56+
57+
# Run tests with race detection
58+
test-race:
59+
go test -race ./internal/...
60+
61+
# Run benchmarks
62+
bench:
63+
go test -bench=. ./internal/...
64+
65+
# Format code
66+
fmt:
67+
go fmt ./...
68+
69+
# Vet code
70+
vet:
71+
go vet ./...

0 commit comments

Comments
 (0)