Simple assertion utilities with panic-on-failure semantics designed to reduce boilerplate code in Go.
🎯 Panic-on-Failure Validation: Clean assertions with automatic panic on failure when conditions are violated ⚡ Type-Safe Generics: Comprehensive support with Go generics spanning assertion types 🔄 Stack Frame Adjustment: Precise panic location through intelligent skip configurations 🌍 Structured Logging: Deep integration with zap providing detailed panic context 📋 Domain-Specific Packages: Specialized utilities with numeric, string, slice, and map operations
go get github.com/yyle88/mustpackage main
import (
"fmt"
"github.com/yyle88/must"
)
func main() {
fmt.Println("=== Demo 1: Basic Assertions ===")
// Boolean assertion
must.True(checkCondition())
fmt.Println("✓ Boolean check passed")
// Validate no errors
must.Done(performOperation())
fmt.Println("✓ No error")
// Non-zero value
count := getCount()
must.Nice(count)
fmt.Printf("✓ Valid count: %d\n", count)
// Values match
must.Equals("success", getStatus())
fmt.Println("✓ Values match")
// Slice operations
items := getItems()
must.Have(items)
must.Length(items, 3)
must.In("banana", items)
fmt.Printf("✓ Slice validated: %v\n", items)
// Pointer check
account := getAccount()
must.Full(account)
fmt.Printf("✓ Pointer valid: %s\n", account.Name)
fmt.Println("\n=== All checks passed! ===")
}
type Account struct{ Name string }
func checkCondition() bool { return true }
func performOperation() error { return nil }
func getStatus() string { return "success" }
func getCount() int { return 42 }
func getItems() []string { return []string{"apple", "banana", "orange"} }
func getAccount() *Account { return &Account{Name: "test"} }⬆️ Source: Source
package main
import (
"fmt"
"github.com/yyle88/must"
)
func main() {
fmt.Println("=== Demo 2: Rese Package ===")
// V1 - single value validation
config := must.V1(readConfig())
fmt.Printf("✓ Config: %s\n", config)
// V2 - two-value validation
width, height := must.V2(getDimensions())
fmt.Printf("✓ Dimensions: %dx%d\n", width, height)
// P1 - non-nil data validation
admin := must.P1(findAdmin())
fmt.Printf("✓ Admin: %s\n", admin.Name)
// C1 - non-zero validation
num := must.C1(getNum())
fmt.Printf("✓ Num: %d\n", num)
// Combined validations
data := getData()
must.Full(data)
must.Nice(data.Score)
must.Same(data.Status, "active")
fmt.Printf("✓ Data: score=%d, status=%s\n", data.Score, data.Status)
fmt.Println("\n=== All checks passed! ===")
}
type Admin struct{ Name string }
type Data struct {
Score int
Status string
}
func readConfig() (string, error) { return "v1.0", nil }
func getDimensions() (int, int, error) { return 1920, 1080, nil }
func findAdmin() (*Admin, error) { return &Admin{"Alice"}, nil }
func getNum() (int, error) { return 123, nil }
func getData() *Data { return &Data{95, "active"} }⬆️ Source: Source
package main
import (
"fmt"
"github.com/yyle88/must"
"github.com/yyle88/must/mustmap"
"github.com/yyle88/must/mustnum"
"github.com/yyle88/must/mustslice"
"github.com/yyle88/must/muststrings"
)
func main() {
fmt.Println("=== Demo 3: Advanced Packages ===")
// Numeric validations
score := getScore()
mustnum.Positive(score)
mustnum.Gt(score, 60)
fmt.Printf("✓ Score: %d\n", score)
// Slice validations
tags := getTags()
mustslice.Have(tags)
mustslice.Contains(tags, "go")
fmt.Printf("✓ Tags: %v\n", tags)
// Map validations
config := getConfig()
mustmap.Have(config)
timeout := mustmap.Get(config, "timeout")
fmt.Printf("✓ Timeout: %d\n", timeout)
// String validations
filename := getFilename()
muststrings.HasSuffix(filename, ".pdf")
muststrings.Contains(filename, "report")
fmt.Printf("✓ Filename: %s\n", filename)
// Complex scenario
data := getAnalytics()
must.Full(data)
mustmap.Have(data.Metrics)
fmt.Printf("✓ Analytics: %d metrics\n", len(data.Metrics))
fmt.Println("\n=== All checks passed! ===")
}
type Analytics struct {
Metrics map[string]float64
}
func getScore() int { return 85 }
func getTags() []string { return []string{"go", "test"} }
func getConfig() map[string]int { return map[string]int{"timeout": 30} }
func getFilename() string { return "report.pdf" }
func getAnalytics() *Analytics {
return &Analytics{Metrics: map[string]float64{"score": 87.5}}
}⬆️ Source: Source
Here are the core assertions in must, summarized in a table:
| Function | Description | Example | Notes |
|---|---|---|---|
True(v bool) |
Panics if v is false. |
must.True(isValid) |
Validates if v is true. |
Done(err error) |
Panics if err is not nil. |
must.Done(err) |
Ensures no error occurred. |
Must(err error) |
Panics if err is not nil. |
must.Must(err) |
Same as Done. |
Nice(a V) |
Panics if a is zero. |
must.Nice(value) |
Ensures a is non-zero. |
Zero(a V) |
Panics if a is not zero. |
must.Zero(value) |
Ensures a is zero. |
None(a V) |
Panics if a is non-zero. |
must.None(value) |
Ensures a is zero. |
Null(v any) |
Panics if v is not nil. |
must.Null(ptr) |
Ensures v is nil. |
Full(v any) |
Panics if v is nil. |
must.Full(value) |
Ensures v is non-nil. |
Equals(a, b V) |
Panics if a and b are not the same. |
must.Equals(a, b) |
Checks if a equals b. |
Same(a, b V) |
Panics if a and b are not the same. |
must.Same(a, b) |
Alias of Equals. |
SameNice(a, b V) |
Panics if a and b are not the same, both non-zero. |
must.SameNice(a, b) |
Ensures same and non-zero. |
Sane(a, b V) |
Panics if a and b are not the same, both non-zero. |
must.Sane(a, b) |
Alias of SameNice. |
Diff(a, b V) |
Panics if a and b are the same. |
must.Diff(a, b) |
Ensures values mismatch. |
Different(a, b V) |
Panics if a and b are the same. |
must.Different(a, b) |
Alias of Diff. |
Is(a, b V) |
Panics if a and b are not the same. |
must.Is(a, b) |
Alias of Equals. |
Ise(err, target error) |
Panics if err does not match target using errors.Is. |
must.Ise(err, targetErr) |
Matching like errors.Is function. |
Ok(a V) |
Panics if a is zero. |
must.Ok(value) |
Ensures a is non-zero. |
OK(a V) |
Alias of Ok, checks non-zero value. |
must.OK(value) |
Same as Ok. |
TRUE(v bool) |
Panics if v is false. |
must.TRUE(isValid) |
Alias of True. |
FALSE(v bool) |
Panics if v is true. |
must.FALSE(isError) |
Ensures v is false. |
False(v bool) |
Panics if v is true. |
must.False(isError) |
Same as FALSE. |
Have(a []T) |
Panics if a has no elements. |
must.Have(slice) |
Ensures a is not vacant. |
Length(a []T, n int) |
Panics if a length is not n. |
must.Length(slice, 3) |
Ensures a length is n. |
Len(a []T, n int) |
Alias of Length, ensures a length is n. |
must.Len(slice, 3) |
Validates a length. |
In(v T, a []T) |
Panics if v is not in a. |
must.In(value, slice) |
Ensures v is in a. |
Contains(a []T, v T) |
Panics if a does not contain v. |
must.Contains(slice, value) |
Ensures a contains v. |
| Function | Description | Example | Notes |
|---|---|---|---|
True(v bool) |
Panics if v is false. |
mustboolean.True(isEnabled) |
Validates if v is true. |
Conflict(bs ...bool) |
Panics if multiple boolean values are true. | mustboolean.Conflict(a, b, c) |
Ensures at most one boolean is true. |
Assert non-zero value:
value := 42
must.Nice(value) // Panics if value is zeroValidate no error:
err := someFunction()
must.Done(err) // Panics if err is not nilCheck slice length:
arr := []int{1, 2, 3}
must.Length(arr, 3) // Panics if length is not 3Validate map operations:
config := map[string]int{"port": 8080}
port := mustmap.Get(config, "port")
mustnum.Positive(port)String validation:
filename := "data.json"
muststrings.HasSuffix(filename, ".json")
muststrings.Contains(filename, "data")Pointer validation:
account := findAccount(id)
must.Full(account) // Panics if account is nilExplore more error handling packages in this ecosystem:
- must - Must-style assertions with rich type support and detailed error context (this project)
- rese - Result extraction with panic, focused on safe value unwrapping
- done - Simple, focused error handling with method chaining
- sure - Generates code that creates custom validation methods
Each package targets different use cases, from quick prototyping to production systems with comprehensive error handling.
MIT License - see LICENSE.
Contributions are welcome! Report bugs, suggest features, and contribute code:
- 🐛 Mistake reports? Open an issue on GitHub with reproduction steps
- 💡 Fresh ideas? Create an issue to discuss
- 📖 Documentation confusing? Report it so we can improve
- 🚀 Need new features? Share the use cases to help us understand requirements
- ⚡ Performance issue? Help us optimize through reporting slow operations
- 🔧 Configuration problem? Ask questions about complex setups
- 📢 Follow project progress? Watch the repo to get new releases and features
- 🌟 Success stories? Share how this package improved the workflow
- 💬 Feedback? We welcome suggestions and comments
New code contributions, follow this process:
- Fork: Fork the repo on GitHub (using the webpage UI).
- Clone: Clone the forked project (
git clone https://github.com/yourname/repo-name.git). - Navigate: Navigate to the cloned project (
cd repo-name) - Branch: Create a feature branch (
git checkout -b feature/xxx). - Code: Implement the changes with comprehensive tests
- Testing: (Golang project) Ensure tests pass (
go test ./...) and follow Go code style conventions - Documentation: Update documentation to support client-facing changes
- Stage: Stage changes (
git add .) - Commit: Commit changes (
git commit -m "Add feature xxx") ensuring backward compatible code - Push: Push to the branch (
git push origin feature/xxx). - PR: Open a merge request on GitHub (on the GitHub webpage) with detailed description.
Please ensure tests pass and include relevant documentation updates.
Welcome to contribute to this project via submitting merge requests and reporting issues.
Project Support:
- ⭐ Give GitHub stars if this project helps you
- 🤝 Share with teammates and (golang) programming friends
- 📝 Write tech blogs about development tools and workflows - we provide content writing support
- 🌟 Join the ecosystem - committed to supporting open source and the (golang) development scene
Have Fun Coding with this package! 🎉🎉🎉