turbo-editors/turbo-corepublic Fork 0
v0.9.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

version_test.go · 230 lines · 7.2 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 20h ago1package version
2
3import (
4 "runtime/debug"
5 "testing"
6)
7
8// buildInfo returns a *debug.BuildInfo describing a build, so that every case
9// can be exercised without linker flags — which is the whole point of keeping
10// resolve separate from Current.
11func buildInfo(mainVersion string, settings map[string]string) *debug.BuildInfo {
12 info := &debug.BuildInfo{}
13 info.Main.Version = mainVersion
14 for key, value := range settings {
15 info.Settings = append(info.Settings, debug.BuildSetting{Key: key, Value: value})
16 }
17 return info
18}
19
20func TestAStampedBuildReportsWhatTheLinkerGaveIt(t *testing.T) {
21 got := resolve("v0.2.0", "88a4c38ff11", "2026-08-31T18:04:05Z", buildInfo("(devel)", nil))
22
23 want := Info{Number: "0.2.0", Commit: "88a4c38", Built: "2026-08-31T18:04:05Z"}
24 if got != want {
25 t.Errorf("resolve() = %+v, want %+v", got, want)
26 }
27}
28
29func TestTheLinkerOutranksTheBuildSystem(t *testing.T) {
30 // A release binary is built from a checkout, so both sources have an
31 // answer; only the linker's knows the tag.
32 got := resolve("v0.2.0", "", "", buildInfo("(devel)", map[string]string{
33 "vcs.revision": "88a4c38ff11",
34 }))
35
36 if got.Number != "0.2.0" {
37 t.Errorf("Number = %q, want the stamped 0.2.0", got.Number)
38 }
39}
40
41func TestAnInstalledModuleReportsItsModuleVersion(t *testing.T) {
42 // `go install <module>@v0.2.0` records the version and no VCS information
43 // at all, because there was no repository to read.
44 got := resolve("", "", "", buildInfo("v0.2.0", nil))
45
46 want := Info{Number: "0.2.0"}
47 if got != want {
48 t.Errorf("resolve() = %+v, want %+v", got, want)
49 }
50}
51
52func TestAnUnstampedCheckoutBuildIsCalledDevel(t *testing.T) {
53 // The build system does not read tags, so no tag can be reported here.
54 got := resolve("", "", "", buildInfo("(devel)", map[string]string{
55 "vcs.revision": "88a4c38ff11",
56 "vcs.modified": "false",
57 }))
58
59 want := Info{Number: "devel", Commit: "88a4c38"}
60 if got != want {
61 t.Errorf("resolve() = %+v, want %+v", got, want)
62 }
63}
64
65func TestAnUnstampedDirtyCheckoutSaysSo(t *testing.T) {
66 got := resolve("", "", "", buildInfo("(devel)", map[string]string{
67 "vcs.revision": "88a4c38ff11",
68 "vcs.modified": "true",
69 }))
70
71 if got.Number != "devel-dirty" {
72 t.Errorf("Number = %q, want devel-dirty", got.Number)
73 }
74}
75
76func TestABuildWithNothingRecordedIsUnknown(t *testing.T) {
77 // Not "0.1.0": a stale number printed as fact is the defect this package
78 // exists to remove.
79 if got := resolve("", "", "", nil); got.Number != unknownNumber {
80 t.Errorf("Number = %q, want %q", got.Number, unknownNumber)
81 }
82 if got := resolve("", "", "", buildInfo("", nil)); got.Number != unknownNumber {
83 t.Errorf("with an empty build info, Number = %q, want %q", got.Number, unknownNumber)
84 }
85}
86
87func TestTheCommitDoesNotComeFromNowhere(t *testing.T) {
88 // An unstamped build with no revision must not invent one.
89 if got := resolve("", "", "", buildInfo("v0.2.0", nil)); got.Commit != "" {
90 t.Errorf("Commit = %q, want nothing", got.Commit)
91 }
92}
93
94func TestTheCommitDateIsNotUsedAsABuildDate(t *testing.T) {
95 // vcs.time is when the commit was made. Reporting it as "Built" would be
96 // wrong on every binary built later than its own commit, which is all of
97 // them.
98 got := resolve("", "", "", buildInfo("(devel)", map[string]string{
99 "vcs.revision": "88a4c38ff11",
100 "vcs.time": "2026-08-30T09:00:00Z",
101 }))
102
103 if got.Built != "" {
104 t.Errorf("Built = %q, want nothing", got.Built)
105 }
106}
107
108func TestOnlyAVersionsLeadingVIsDropped(t *testing.T) {
109 cases := map[string]string{
110 "v0.2.0": "0.2.0",
111 "v0.1.0-14-g88a4c38": "0.1.0-14-g88a4c38",
112 "0.2.0": "0.2.0",
113 "devel": "devel", // not "el"
114 "version": "version", // not "ersion"
115 "v": "v",
116 "": "",
117 }
118 for given, want := range cases {
119 if got := trimV(given); got != want {
120 t.Errorf("trimV(%q) = %q, want %q", given, got, want)
121 }
122 }
123}
124
125func TestARevisionIsAbbreviatedTheWayGitDoes(t *testing.T) {
126 if got := shorten("88a4c38ff1122334455"); got != "88a4c38" {
127 t.Errorf("shorten() = %q, want 88a4c38", got)
128 }
129 if got := shorten("88a4c3"); got != "88a4c3" {
130 t.Errorf("a revision shorter than the limit was changed: %q", got)
131 }
132 if got := shorten(""); got != "" {
133 t.Errorf("shorten(\"\") = %q, want nothing", got)
134 }
135}
136
137func TestStringShowsEveryPartThatIsKnown(t *testing.T) {
138 cases := []struct {
139 name string
140 info Info
141 want string
142 }{
143 {"everything", Info{"0.2.0", "88a4c38", "2026-08-31T18:04:05Z"}, "0.2.0 (88a4c38, built 2026-08-31T18:04:05Z)"},
144 {"commit only", Info{Number: "0.2.0", Commit: "88a4c38"}, "0.2.0 (88a4c38)"},
145 {"date only", Info{Number: "0.2.0", Built: "2026-08-31T18:04:05Z"}, "0.2.0 (built 2026-08-31T18:04:05Z)"},
146 {"number only", Info{Number: "0.2.0"}, "0.2.0"},
147 }
148 for _, one := range cases {
149 t.Run(one.name, func(t *testing.T) {
150 if got := one.info.String(); got != one.want {
151 t.Errorf("String() = %q, want %q", got, one.want)
152 }
153 })
154 }
155}
156
157func TestBuiltAtIsReadable(t *testing.T) {
158 if got := (Info{Built: "2026-08-31T18:04:05Z"}).BuiltAt(); got != "2026-08-31 18:04 UTC" {
159 t.Errorf("BuiltAt() = %q", got)
160 }
161}
162
163func TestBuiltAtNormalisesToUTC(t *testing.T) {
164 // The Makefile stamps UTC, but a hand-run build might not.
165 if got := (Info{Built: "2026-08-31T20:04:05+02:00"}).BuiltAt(); got != "2026-08-31 18:04 UTC" {
166 t.Errorf("BuiltAt() = %q, want the same moment in UTC", got)
167 }
168}
169
170func TestBuiltAtShowsAMalformedStampRatherThanHidingIt(t *testing.T) {
171 if got := (Info{Built: "last Tuesday"}).BuiltAt(); got != "last Tuesday" {
172 t.Errorf("BuiltAt() = %q, want the stamp as given", got)
173 }
174 if got := (Info{}).BuiltAt(); got != "" {
175 t.Errorf("BuiltAt() with no stamp = %q, want nothing", got)
176 }
177}
178
179func TestCurrentAnswersWithoutPanicking(t *testing.T) {
180 // A test binary is one of the builds resolve has to cope with, and its
181 // number is never empty whatever the build system recorded.
182 if got := Current(); got.Number == "" {
183 t.Error("Current() reported an empty version")
184 }
185}
186
187func TestEveryFormOfPseudoVersionIsRecognised(t *testing.T) {
188 // The three shapes the Go tool produces differ in what precedes the
189 // timestamp: a dash when there is no base tag, a dot when the base is a
190 // release or a pre-release.
191 pseudo := []string{
192 "0.0.0-20260831165958-88a4c3859bf3",
193 "0.1.1-0.20260831165958-88a4c3859bf3",
194 "0.1.1-0.20260831165958-88a4c3859bf3+dirty",
195 "0.2.0-pre.0.20260831165958-88a4c3859bf3",
196 }
197 for _, number := range pseudo {
198 if !isPseudoVersion(number) {
199 t.Errorf("isPseudoVersion(%q) = false, want true", number)
200 }
201 }
202
203 real := []string{
204 "0.2.0",
205 "0.2.0-rc.1",
206 "devel",
207 "0.1.0-14-g88a4c38",
208 "",
209 "0.0.0-20260831165958-88a4c3859bZ", // not hex
210 "0.0.0-2026083116595-88a4c3859bf3", // 13 digits
211 }
212 for _, number := range real {
213 if isPseudoVersion(number) {
214 t.Errorf("isPseudoVersion(%q) = true, want false", number)
215 }
216 }
217}
218
219func TestAPseudoVersionIsReportedAsDevel(t *testing.T) {
220 // "0.1.1" in a pseudo-version is a patch release that does not exist.
221 got := resolve("", "", "", buildInfo("v0.1.1-0.20260831165958-88a4c3859bf3+dirty", map[string]string{
222 "vcs.revision": "88a4c3859bf3e8cb",
223 "vcs.modified": "true",
224 }))
225
226 want := Info{Number: "devel-dirty", Commit: "88a4c38"}
227 if got != want {
228 t.Errorf("resolve() = %+v, want %+v", got, want)
229 }
230}