Files
knowledge-governance/internal/versionhistory/development_notes_plain_test.go
T
姚章浩 2a2e98bd8e
build / build (push) Successful in 1m41s
fix(version): 兼容开发快照版本标题
识别“## 开发快照 <version>(说明)”并保留旧 snapshot/v 格式。
版本号精确匹配、不跨二级标题、空正文不返回,archive 精确 SHA 绑定不变。
2026-11-04 15:57:53 +08:00

134 lines
4.9 KiB
Go
Raw 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 versionhistory
import (
"os"
"strings"
"testing"
"time"
"knowledge-governance/internal/governance"
)
const plainNotesFixture = `# Changelog
## 开发快照 0.1.351(索引预检使用目标映射 ID)
### Fixed
- 索引预检使用目标映射 ID
## 开发快照 0.1.35(前缀相似版本)
### Fixed
- 不应被 0.1.351 命中
## 开发快照 0.1.350(首次复用取消本库历史来源门槛)
### Changed
- 首次复用说明
`
func TestPlainDevelopmentHeadingExactVersion(t *testing.T) {
got := governance.ExtractDevelopmentNotes(plainNotesFixture, "0.1.351")
if got == "" || !strings.Contains(got, "索引预检使用目标映射 ID") || strings.Contains(got, "首次复用说明") {
t.Fatalf("plain 0.1.351 notes wrong: %q", got)
}
if other := governance.ExtractDevelopmentNotes(plainNotesFixture, "0.1.35"); strings.Contains(other, "索引预检") {
t.Fatalf("0.1.35 must not match 0.1.351 body: %q", other)
}
if other := governance.ExtractDevelopmentNotes(plainNotesFixture, "0.1.3"); other != "" {
t.Fatalf("0.1.3 must not prefix-match 0.1.35/0.1.351: %q", other)
}
if next := governance.ExtractDevelopmentNotes(plainNotesFixture, "0.1.350"); !strings.Contains(next, "首次复用说明") || strings.Contains(next, "索引预检") {
t.Fatalf("adjacent version bleed: %q", next)
}
}
func TestPlainDevelopmentHeadingEmptyBodyAndLegacyFormat(t *testing.T) {
if got := governance.ExtractDevelopmentNotes("## 开发快照 0.1.351(空)\n\n## 开发快照 0.1.350(下一版)\n\n- x\n", "0.1.351"); got != "" {
t.Fatalf("empty body must stay empty: %q", got)
}
legacy := "## 开发快照 snapshot/v0.1.1 - 2026-10-18\n\n### Fixed\n\n- legacy body\n"
if got := governance.ExtractDevelopmentNotes(legacy, "0.1.1"); !strings.Contains(got, "legacy body") {
t.Fatalf("legacy snapshot format regressed: %q", got)
}
}
func TestRealChangelogDevelopmentNotes(t *testing.T) {
body, err := os.ReadFile("../../CHANGELOG.md")
if err != nil {
t.Fatal(err)
}
changelog := string(body)
for _, tc := range []struct{ version, want string }{
{"0.1.351", "索引预检"},
{"0.1.350", "首次同步可复用"},
} {
notes := governance.ExtractDevelopmentNotes(changelog, tc.version)
if notes == "" || !strings.Contains(notes, tc.want) {
t.Fatalf("real CHANGELOG %s notes missing: %q", tc.version, notes)
}
if governance.ExtractDevelopmentNotes(changelog, "0.1.35") != "" {
t.Fatal("prefix version matched a longer version")
}
}
}
func TestDeriveVersionsPlainHeadingReleaseNotes(t *testing.T) {
text := "# Changelog\n\n## 开发快照 0.1.1(索引预检使用目标映射 ID)\n\n### Fixed\n\n- plain delivered notes\n\n## 开发快照 snapshot/v0.1.1 - 2026-10-18\n\n### Fixed\n\n- legacy duplicate heading\n\n## [0.1.0] - 2026-10-13\n\n### Added\n\n- baseline\n"
result := DeriveVersions(DeriveInput{
Commits: []RawCommit{{SHA: "a", CommittedAt: time.Now()}, {SHA: "b", Parents: []string{"a"}, CommittedAt: time.Now()}},
Tags: []RawTag{{Name: "v0.1.0", TargetSHA: "a", Annotated: true}},
Changelog: func(string) (string, error) {
return text, nil
},
})
for _, record := range result.Records {
if record.CommitSHA == "b" {
if record.RecordKind != governance.RecordKindDevelopment || !strings.Contains(record.ReleaseNotes, "plain delivered notes") ||
strings.Contains(record.ReleaseNotes, "legacy duplicate") {
t.Fatalf("DeriveVersions plain heading notes wrong: %q kind=%s label=%s", record.ReleaseNotes, record.RecordKind, record.VersionLabel)
}
return
}
}
t.Fatal("development record b missing")
}
func TestPlainDevelopmentArchiveBindsExactCommit(t *testing.T) {
sha := strings.Repeat("a", 40)
archive := "## 开发快照 0.1.351(索引预检使用目标映射 ID)\n\n目标提交:" + sha + "\n\n### Fixed\n\n- archived plain notes\n"
if got := governance.ExtractDevelopmentNotesForCommit(archive, "0.1.351", sha); !strings.Contains(got, "archived plain notes") {
t.Fatalf("plain archive notes missing for exact commit: %q", got)
}
if got := governance.ExtractDevelopmentNotesForCommit(archive, "0.1.351", strings.Repeat("b", 40)); got != "" {
t.Fatalf("plain archive notes leaked to wrong commit: %q", got)
}
}
func TestRealChangelogVersionInventory(t *testing.T) {
body, err := os.ReadFile("../../CHANGELOG.md")
if err != nil {
t.Fatal(err)
}
changelog := string(body)
for _, version := range []string{"0.1.351", "0.1.350", "0.1.349", "0.1.348"} {
notes := governance.ExtractDevelopmentNotes(changelog, version)
heading := ""
for _, line := range strings.Split(changelog, "\n") {
if strings.HasPrefix(line, "## 开发快照 "+version) || strings.HasPrefix(line, "## 开发快照 snapshot/v"+version) {
heading = line
break
}
}
t.Logf("version=%s heading=%q notes_bytes=%d", version, heading, len(notes))
if version == "0.1.351" || version == "0.1.350" {
if notes == "" {
t.Fatalf("%s has a CHANGELOG section but no extracted notes", version)
}
}
}
}