|
1 | 1 | package updater |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "encoding/json" |
| 5 | + "os" |
| 6 | + "path/filepath" |
4 | 7 | "testing" |
| 8 | + "time" |
5 | 9 |
|
6 | 10 | "github.com/stretchr/testify/assert" |
| 11 | + "github.com/stretchr/testify/require" |
7 | 12 | ) |
8 | 13 |
|
9 | 14 | func TestIsNewerVersion(t *testing.T) { |
@@ -127,3 +132,182 @@ func TestTrimVersionPrefix(t *testing.T) { |
127 | 132 | }) |
128 | 133 | } |
129 | 134 | } |
| 135 | + |
| 136 | +func TestCompareSemver(t *testing.T) { |
| 137 | + tests := []struct { |
| 138 | + a, b string |
| 139 | + expected int |
| 140 | + }{ |
| 141 | + {"2.0.0", "1.0.0", 1}, |
| 142 | + {"1.0.0", "2.0.0", -1}, |
| 143 | + {"1.0.0", "1.0.0", 0}, |
| 144 | + {"1.2.3", "1.2.2", 1}, |
| 145 | + {"1.2.2", "1.2.3", -1}, |
| 146 | + {"1.10.0", "1.9.0", 1}, |
| 147 | + {"0.0.1", "0.0.0", 1}, |
| 148 | + } |
| 149 | + for _, tt := range tests { |
| 150 | + result := compareSemver(tt.a, tt.b) |
| 151 | + assert.Equal(t, tt.expected, result, "compareSemver(%q, %q)", tt.a, tt.b) |
| 152 | + } |
| 153 | +} |
| 154 | + |
| 155 | +func TestParseSemver(t *testing.T) { |
| 156 | + tests := []struct { |
| 157 | + input string |
| 158 | + expected [3]int |
| 159 | + }{ |
| 160 | + {"1.2.3", [3]int{1, 2, 3}}, |
| 161 | + {"10.20.30", [3]int{10, 20, 30}}, |
| 162 | + {"1.0.0", [3]int{1, 0, 0}}, |
| 163 | + {"", [3]int{0, 0, 0}}, |
| 164 | + {"abc", [3]int{0, 0, 0}}, |
| 165 | + {"1.abc.3", [3]int{1, 0, 3}}, |
| 166 | + } |
| 167 | + for _, tt := range tests { |
| 168 | + result := parseSemver(tt.input) |
| 169 | + assert.Equal(t, tt.expected, result, "parseSemver(%q)", tt.input) |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +func TestIsNewerVersion_DevBuild(t *testing.T) { |
| 174 | + assert.False(t, isNewerVersion("v99.0.0", "dev"), "dev builds should never trigger update") |
| 175 | +} |
| 176 | + |
| 177 | +func TestGetHTTPClient_Singleton(t *testing.T) { |
| 178 | + c1 := getHTTPClient() |
| 179 | + c2 := getHTTPClient() |
| 180 | + assert.Same(t, c1, c2, "getHTTPClient should return same instance") |
| 181 | + assert.NotNil(t, c1) |
| 182 | +} |
| 183 | + |
| 184 | +func TestGetCheckFilePath(t *testing.T) { |
| 185 | + t.Setenv("HOME", t.TempDir()) |
| 186 | + path, err := getCheckFilePath() |
| 187 | + require.NoError(t, err) |
| 188 | + assert.Contains(t, path, ".openboot") |
| 189 | + assert.Contains(t, path, "update_state.json") |
| 190 | +} |
| 191 | + |
| 192 | +func TestGetUserConfigPath(t *testing.T) { |
| 193 | + t.Setenv("HOME", t.TempDir()) |
| 194 | + path, err := getUserConfigPath() |
| 195 | + require.NoError(t, err) |
| 196 | + assert.Contains(t, path, ".openboot") |
| 197 | + assert.Contains(t, path, "config.json") |
| 198 | +} |
| 199 | + |
| 200 | +func TestLoadState_FileNotFound(t *testing.T) { |
| 201 | + t.Setenv("HOME", t.TempDir()) |
| 202 | + _, err := LoadState() |
| 203 | + assert.Error(t, err) |
| 204 | +} |
| 205 | + |
| 206 | +func TestSaveState_And_LoadState(t *testing.T) { |
| 207 | + t.Setenv("HOME", t.TempDir()) |
| 208 | + now := time.Now().Truncate(time.Second) |
| 209 | + state := &CheckState{ |
| 210 | + LastCheck: now, |
| 211 | + LatestVersion: "v1.2.3", |
| 212 | + UpdateAvailable: true, |
| 213 | + } |
| 214 | + require.NoError(t, SaveState(state)) |
| 215 | + |
| 216 | + loaded, err := LoadState() |
| 217 | + require.NoError(t, err) |
| 218 | + assert.Equal(t, "v1.2.3", loaded.LatestVersion) |
| 219 | + assert.True(t, loaded.UpdateAvailable) |
| 220 | + assert.Equal(t, now, loaded.LastCheck.Truncate(time.Second)) |
| 221 | +} |
| 222 | + |
| 223 | +func TestLoadUserConfig_Default_NoFile(t *testing.T) { |
| 224 | + t.Setenv("HOME", t.TempDir()) |
| 225 | + cfg := LoadUserConfig() |
| 226 | + assert.Equal(t, AutoUpdateEnabled, cfg.AutoUpdate) |
| 227 | +} |
| 228 | + |
| 229 | +func TestLoadUserConfig_FromFile(t *testing.T) { |
| 230 | + tmpDir := t.TempDir() |
| 231 | + t.Setenv("HOME", tmpDir) |
| 232 | + cfgDir := filepath.Join(tmpDir, ".openboot") |
| 233 | + require.NoError(t, os.MkdirAll(cfgDir, 0755)) |
| 234 | + data, err := json.Marshal(UserConfig{AutoUpdate: AutoUpdateNotify}) |
| 235 | + require.NoError(t, err) |
| 236 | + require.NoError(t, os.WriteFile(filepath.Join(cfgDir, "config.json"), data, 0644)) |
| 237 | + |
| 238 | + cfg := LoadUserConfig() |
| 239 | + assert.Equal(t, AutoUpdateNotify, cfg.AutoUpdate) |
| 240 | +} |
| 241 | + |
| 242 | +func TestLoadUserConfig_InvalidJSON(t *testing.T) { |
| 243 | + tmpDir := t.TempDir() |
| 244 | + t.Setenv("HOME", tmpDir) |
| 245 | + cfgDir := filepath.Join(tmpDir, ".openboot") |
| 246 | + require.NoError(t, os.MkdirAll(cfgDir, 0755)) |
| 247 | + require.NoError(t, os.WriteFile(filepath.Join(cfgDir, "config.json"), []byte("{bad json"), 0644)) |
| 248 | + |
| 249 | + cfg := LoadUserConfig() |
| 250 | + assert.Equal(t, AutoUpdateEnabled, cfg.AutoUpdate) |
| 251 | +} |
| 252 | + |
| 253 | +func TestLoadUserConfig_EmptyAutoUpdate(t *testing.T) { |
| 254 | + tmpDir := t.TempDir() |
| 255 | + t.Setenv("HOME", tmpDir) |
| 256 | + cfgDir := filepath.Join(tmpDir, ".openboot") |
| 257 | + require.NoError(t, os.MkdirAll(cfgDir, 0755)) |
| 258 | + require.NoError(t, os.WriteFile(filepath.Join(cfgDir, "config.json"), []byte(`{"autoupdate":""}`), 0644)) |
| 259 | + |
| 260 | + cfg := LoadUserConfig() |
| 261 | + assert.Equal(t, AutoUpdateEnabled, cfg.AutoUpdate) |
| 262 | +} |
| 263 | + |
| 264 | +func TestLoadUserConfig_DisabledMode(t *testing.T) { |
| 265 | + tmpDir := t.TempDir() |
| 266 | + t.Setenv("HOME", tmpDir) |
| 267 | + cfgDir := filepath.Join(tmpDir, ".openboot") |
| 268 | + require.NoError(t, os.MkdirAll(cfgDir, 0755)) |
| 269 | + data, err := json.Marshal(UserConfig{AutoUpdate: AutoUpdateDisabled}) |
| 270 | + require.NoError(t, err) |
| 271 | + require.NoError(t, os.WriteFile(filepath.Join(cfgDir, "config.json"), data, 0644)) |
| 272 | + |
| 273 | + cfg := LoadUserConfig() |
| 274 | + assert.Equal(t, AutoUpdateDisabled, cfg.AutoUpdate) |
| 275 | +} |
| 276 | + |
| 277 | +func TestAutoUpgrade_DisabledByEnv(t *testing.T) { |
| 278 | + t.Setenv("OPENBOOT_DISABLE_AUTOUPDATE", "1") |
| 279 | + AutoUpgrade("1.0.0") |
| 280 | +} |
| 281 | + |
| 282 | +func TestNotifyIfUpdateAvailable_NoStateFile(t *testing.T) { |
| 283 | + t.Setenv("HOME", t.TempDir()) |
| 284 | + NotifyIfUpdateAvailable("1.0.0") |
| 285 | +} |
| 286 | + |
| 287 | +func TestNotifyIfUpdateAvailable_UpdateAvailable(t *testing.T) { |
| 288 | + tmpDir := t.TempDir() |
| 289 | + t.Setenv("HOME", tmpDir) |
| 290 | + require.NoError(t, SaveState(&CheckState{ |
| 291 | + LastCheck: time.Now(), |
| 292 | + LatestVersion: "v2.0.0", |
| 293 | + UpdateAvailable: true, |
| 294 | + })) |
| 295 | + NotifyIfUpdateAvailable("1.0.0") |
| 296 | +} |
| 297 | + |
| 298 | +func TestNotifyIfUpdateAvailable_NoUpdate(t *testing.T) { |
| 299 | + tmpDir := t.TempDir() |
| 300 | + t.Setenv("HOME", tmpDir) |
| 301 | + require.NoError(t, SaveState(&CheckState{ |
| 302 | + LastCheck: time.Now(), |
| 303 | + LatestVersion: "v1.0.0", |
| 304 | + UpdateAvailable: false, |
| 305 | + })) |
| 306 | + NotifyIfUpdateAvailable("1.0.0") |
| 307 | +} |
| 308 | + |
| 309 | +func TestAutoUpdateModeConstants(t *testing.T) { |
| 310 | + assert.Equal(t, AutoUpdateMode("true"), AutoUpdateEnabled) |
| 311 | + assert.Equal(t, AutoUpdateMode("notify"), AutoUpdateNotify) |
| 312 | + assert.Equal(t, AutoUpdateMode("false"), AutoUpdateDisabled) |
| 313 | +} |
0 commit comments