Files
杭州明婳科技 dcfd24b624 release: v1.0.3 bug fix release
v1.0.3 定位为 bug fix release,收口 v1.0.2 引入的破坏性清理并修复
4 个轻量 bug + 依赖复查 + 版本号治理 + 文档对齐。同时包含此前未提交
的 v1.0.2 全部工作。

v1.0.3 变更:

Fixed:
- generateJTI 忽略 rand.Read 错误(jwt)— 改为 (string, error) 并传播
- QueryBuilder.Page Count 受残留 Limit 截断(repository)— countDB 加 Limit(-1).Offset(-1)
- OSS/本地存储文件名冲突(storage)— 新增 uniqueFilename 加 8 字节随机后缀
- 数据库重试策略对不可恢复错误无效(database)— 新增 isTransientDBError

Dependencies:
- go mod tidy 补全 postgres 方言传递依赖;安全补丁升级
  x/crypto v0.49→v0.53、golang-jwt/jwt/v5 v5.2.1→v5.3.1、gorilla/websocket v1.5.1→v1.5.3

Removed:
- Breaking: 清理 v1.0.2 兼容别名(InitMySQL* / driverName)
- 死代码 database.DBResolver
- 代码中 292 行"评分/理由"自夸注释(#26,23 个文件)

Changed:
- Breaking: 错误码体系重构 CodeSuccess 1→0、CodeFail 0→1,删除 CodeInvalidParams,加编译期防撞码
- database/mysql.go → manager.go;Logger 拆分三独立 core 修复 Tee 重复写入
- 版本号常量化:app.go 新增 const Version 作为唯一来源,CLI/脚手架模板引用之,不再散落字面量

Security:
- CORS 中间件按 W3C 规范修复 Allow-Credentials / Vary: Origin / 非白名单不回显

Added:
- console 包显式 level 控制(SetLevel/WithLevel/LevelSilent,atomic.Int32 并发安全)
- 新增测试 jwt/repository/storage/database/router/middleware/app
- 文档:新增 CHANGELOG.md、Version_v1.0.2_report.md;更新 README/GUIDE 顶部更新日志
- 文档对齐:删除对不存在的 config.DefaultManager() getter 的描述(保持 API 与文档一致)

详见 CHANGELOG.md 与 README.md 更新日志。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:40:10 +08:00

153 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package console_test
import (
"bytes"
"strings"
"testing"
"github.com/EthanCodeCraft/xlgo-core/console"
)
func TestConsole(t *testing.T) {
// 使用默认控制台
console.Debug("这是一条调试信息")
console.Info("这是一条普通信息")
console.Success("这是一条成功信息")
console.Warn("这是一条警告信息")
console.Error("这是一条错误信息")
// 创建自定义控制台
c := console.New(
console.WithColor(true),
console.WithTime(true),
console.WithCaller(true, 2),
)
c.Debug("自定义控制台 - Debug")
c.Info("自定义控制台 - Info")
c.Success("自定义控制台 - Success")
c.Warn("自定义控制台 - Warn")
c.Error("自定义控制台 - Error")
}
// TestConsoleLevelFilter 验证显式 level 屏蔽:低于阈值的调用不输出。
// 这是方案 A 的核心契约——用户显式控制何时屏蔽,框架不做隐式行为。
func TestConsoleLevelFilter(t *testing.T) {
var buf bytes.Buffer
c := console.New(
console.WithOutput(&buf),
console.WithColor(false),
console.WithTime(false),
console.WithCaller(false),
console.WithLevel(console.LevelWarn),
)
c.Debug("DEBUG_MARK")
c.Info("INFO_MARK")
c.Success("SUCCESS_MARK")
c.Warn("WARN_MARK")
c.Error("ERROR_MARK")
out := buf.String()
// Warn / Error 必须输出
if !strings.Contains(out, "WARN_MARK") {
t.Errorf("Warn should be printed at LevelWarn, got: %q", out)
}
if !strings.Contains(out, "ERROR_MARK") {
t.Errorf("Error should be printed at LevelWarn, got: %q", out)
}
// Debug / Info / Success 必须被静默
for _, mark := range []string{"DEBUG_MARK", "INFO_MARK", "SUCCESS_MARK"} {
if strings.Contains(out, mark) {
t.Errorf("%s should be filtered at LevelWarn, but found in: %q", mark, out)
}
}
}
// TestConsoleLevelSilent 验证 LevelSilent 完全静默所有调用。
func TestConsoleLevelSilent(t *testing.T) {
var buf bytes.Buffer
c := console.New(
console.WithOutput(&buf),
console.WithColor(false),
console.WithLevel(console.LevelSilent),
)
c.Debug("D")
c.Info("I")
c.Success("S")
c.Warn("W")
c.Error("E")
if buf.Len() != 0 {
t.Errorf("LevelSilent should suppress all output, got %d bytes: %q", buf.Len(), buf.String())
}
}
// TestConsoleSetLevel 验证运行期热切换 level。
func TestConsoleSetLevel(t *testing.T) {
var buf bytes.Buffer
c := console.New(
console.WithOutput(&buf),
console.WithColor(false),
console.WithTime(false),
console.WithCaller(false),
)
// 默认 LevelDebugDebug 应输出
c.Debug("FIRST")
if !strings.Contains(buf.String(), "FIRST") {
t.Errorf("Debug should print at default LevelDebug, got: %q", buf.String())
}
buf.Reset()
// 切到 LevelError 后,Debug 应静默
c.SetLevel(console.LevelError)
if got := c.Level(); got != console.LevelError {
t.Errorf("Level() = %v, want LevelError", got)
}
c.Debug("SECOND")
if buf.Len() != 0 {
t.Errorf("Debug should be filtered after SetLevel(LevelError), got: %q", buf.String())
}
// Error 仍然输出
c.Error("THIRD")
if !strings.Contains(buf.String(), "THIRD") {
t.Errorf("Error should print at LevelError, got: %q", buf.String())
}
}
// TestConsolePackageLevelAPI 验证包级 SetLevel / GetLevel 操作的是 Default 实例。
func TestConsolePackageLevelAPI(t *testing.T) {
original := console.GetLevel()
t.Cleanup(func() { console.SetLevel(original) })
console.SetLevel(console.LevelWarn)
if got := console.GetLevel(); got != console.LevelWarn {
t.Errorf("GetLevel() = %v, want LevelWarn", got)
}
if got := console.Default.Level(); got != console.LevelWarn {
t.Errorf("Default.Level() = %v, want LevelWarn (package SetLevel must affect Default)", got)
}
}
// TestConsoleLevelString 验证 Level.String 输出可读名称(错误信息 / 日志会用到)。
func TestConsoleLevelString(t *testing.T) {
cases := map[console.Level]string{
console.LevelDebug: "Debug",
console.LevelInfo: "Info",
console.LevelSuccess: "Success",
console.LevelWarn: "Warn",
console.LevelError: "Error",
console.LevelSilent: "Silent",
}
for l, want := range cases {
if got := l.String(); got != want {
t.Errorf("Level(%d).String() = %q, want %q", l, got, want)
}
}
}