changelog generator & diff tool
stormlightlabs.github.io/git-storm/
changelog
changeset
markdown
golang
git
1package tty
2
3import (
4 "os"
5 "strings"
6 "testing"
7)
8
9func TestIsCI(t *testing.T) {
10 tests := []struct {
11 name string
12 envVars map[string]string
13 expected bool
14 }{
15 {
16 name: "no CI vars",
17 envVars: map[string]string{},
18 expected: false,
19 },
20 {
21 name: "generic CI var",
22 envVars: map[string]string{"CI": "true"},
23 expected: true,
24 },
25 {
26 name: "GitHub Actions",
27 envVars: map[string]string{"GITHUB_ACTIONS": "true"},
28 expected: true,
29 },
30 {
31 name: "GitLab CI",
32 envVars: map[string]string{"GITLAB_CI": "true"},
33 expected: true,
34 },
35 {
36 name: "CircleCI",
37 envVars: map[string]string{"CIRCLECI": "true"},
38 expected: true,
39 },
40 {
41 name: "multiple CI vars",
42 envVars: map[string]string{"CI": "true", "TRAVIS": "true"},
43 expected: true,
44 },
45 }
46
47 for _, tt := range tests {
48 t.Run(tt.name, func(t *testing.T) {
49 ciEnvVars := []string{
50 "CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS",
51 "GITLAB_CI", "CIRCLECI", "TRAVIS", "JENKINS_URL",
52 "BUILDKITE", "DRONE", "TEAMCITY_VERSION",
53 }
54 for _, v := range ciEnvVars {
55 os.Unsetenv(v)
56 }
57
58 for k, v := range tt.envVars {
59 os.Setenv(k, v)
60 }
61
62 defer func() {
63 for k := range tt.envVars {
64 os.Unsetenv(k)
65 }
66 }()
67
68 result := IsCI()
69 if result != tt.expected {
70 t.Errorf("IsCI() = %v, expected %v", result, tt.expected)
71 }
72 })
73 }
74}
75
76func TestGetCIName(t *testing.T) {
77 tests := []struct {
78 name string
79 envVar string
80 expected string
81 }{
82 {
83 name: "GitHub Actions",
84 envVar: "GITHUB_ACTIONS",
85 expected: "GitHub Actions",
86 },
87 {
88 name: "GitLab CI",
89 envVar: "GITLAB_CI",
90 expected: "GitLab CI",
91 },
92 {
93 name: "CircleCI",
94 envVar: "CIRCLECI",
95 expected: "CircleCI",
96 },
97 {
98 name: "Travis CI",
99 envVar: "TRAVIS",
100 expected: "Travis CI",
101 },
102 {
103 name: "Jenkins",
104 envVar: "JENKINS_URL",
105 expected: "Jenkins",
106 },
107 {
108 name: "Buildkite",
109 envVar: "BUILDKITE",
110 expected: "Buildkite",
111 },
112 {
113 name: "Drone CI",
114 envVar: "DRONE",
115 expected: "Drone CI",
116 },
117 {
118 name: "TeamCity",
119 envVar: "TEAMCITY_VERSION",
120 expected: "TeamCity",
121 },
122 {
123 name: "Generic CI",
124 envVar: "CI",
125 expected: "CI",
126 },
127 {
128 name: "No CI",
129 envVar: "",
130 expected: "",
131 },
132 }
133
134 for _, tt := range tests {
135 t.Run(tt.name, func(t *testing.T) {
136 ciEnvVars := []string{
137 "CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS",
138 "GITLAB_CI", "CIRCLECI", "TRAVIS", "JENKINS_URL",
139 "BUILDKITE", "DRONE", "TEAMCITY_VERSION",
140 }
141 for _, v := range ciEnvVars {
142 os.Unsetenv(v)
143 }
144
145 if tt.envVar != "" {
146 os.Setenv(tt.envVar, "true")
147 }
148
149 defer func() {
150 if tt.envVar != "" {
151 os.Unsetenv(tt.envVar)
152 }
153 }()
154
155 result := GetCIName()
156 if result != tt.expected {
157 t.Errorf("GetCIName() = %q, expected %q", result, tt.expected)
158 }
159 })
160 }
161}
162
163func TestErrorInteractiveRequired(t *testing.T) {
164 tests := []struct {
165 name string
166 commandName string
167 alternatives []string
168 ciEnv string
169 wantContains []string
170 }{
171 {
172 name: "basic error",
173 commandName: "review",
174 wantContains: []string{
175 "command 'review' requires an interactive terminal",
176 },
177 },
178 {
179 name: "with alternatives",
180 commandName: "review",
181 alternatives: []string{
182 "Use 'storm unreleased list' to view entries",
183 "Use 'storm unreleased list --json' for JSON output",
184 },
185 wantContains: []string{
186 "command 'review' requires an interactive terminal",
187 "Alternatives:",
188 "Use 'storm unreleased list' to view entries",
189 "Use 'storm unreleased list --json' for JSON output",
190 },
191 },
192 {
193 name: "CI environment",
194 commandName: "diff",
195 ciEnv: "GITHUB_ACTIONS",
196 wantContains: []string{
197 "command 'diff' requires an interactive terminal",
198 "detected GitHub Actions environment",
199 },
200 },
201 }
202
203 for _, tt := range tests {
204 t.Run(tt.name, func(t *testing.T) {
205 ciEnvVars := []string{
206 "CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS",
207 "GITLAB_CI", "CIRCLECI", "TRAVIS", "JENKINS_URL",
208 "BUILDKITE", "DRONE", "TEAMCITY_VERSION",
209 }
210 for _, v := range ciEnvVars {
211 os.Unsetenv(v)
212 }
213
214 if tt.ciEnv != "" {
215 os.Setenv(tt.ciEnv, "true")
216 defer os.Unsetenv(tt.ciEnv)
217 }
218
219 err := ErrorInteractiveRequired(tt.commandName, tt.alternatives)
220 if err == nil {
221 t.Fatal("ErrorInteractiveRequired() returned nil, expected error")
222 }
223
224 errMsg := err.Error()
225 for _, want := range tt.wantContains {
226 if !strings.Contains(errMsg, want) {
227 t.Errorf("ErrorInteractiveRequired() error message missing %q\nGot: %s", want, errMsg)
228 }
229 }
230 })
231 }
232}
233
234func TestErrorInteractiveFlag(t *testing.T) {
235 tests := []struct {
236 name string
237 flagName string
238 ciEnv string
239 wantContains []string
240 }{
241 {
242 name: "basic error",
243 flagName: "--interactive",
244 wantContains: []string{
245 "flag '--interactive' requires an interactive terminal",
246 },
247 },
248 {
249 name: "CI environment",
250 flagName: "--interactive",
251 ciEnv: "GITLAB_CI",
252 wantContains: []string{
253 "flag '--interactive' requires an interactive terminal",
254 "detected GitLab CI environment",
255 },
256 },
257 }
258
259 for _, tt := range tests {
260 t.Run(tt.name, func(t *testing.T) {
261 ciEnvVars := []string{
262 "CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS",
263 "GITLAB_CI", "CIRCLECI", "TRAVIS", "JENKINS_URL",
264 "BUILDKITE", "DRONE", "TEAMCITY_VERSION",
265 }
266 for _, v := range ciEnvVars {
267 os.Unsetenv(v)
268 }
269
270 if tt.ciEnv != "" {
271 os.Setenv(tt.ciEnv, "true")
272 defer os.Unsetenv(tt.ciEnv)
273 }
274
275 err := ErrorInteractiveFlag(tt.flagName)
276 if err == nil {
277 t.Fatal("ErrorInteractiveFlag() returned nil, expected error")
278 }
279
280 errMsg := err.Error()
281 for _, want := range tt.wantContains {
282 if !strings.Contains(errMsg, want) {
283 t.Errorf("ErrorInteractiveFlag() error message missing %q\nGot: %s", want, errMsg)
284 }
285 }
286 })
287 }
288}