refactor(config): extract DiffFormatter interface and clean up migration use case
- commit
- f0af95e44d1540f8cd0b8195c40cdd5a86bf0694
- author
- brice · · 2025-12-28 07:41 UTC
- parent
- 47613bd
- signature
- unsigned
8 files · +179 -124
M .mockery.yaml +1 -0
| @@ -10,6 +10,7 @@ packages: | |||
| 10 | 10 | interfaces: | |
| 11 | 11 | ConfigMigrator: {} | |
| 12 | 12 | DatabaseProvider: {} | |
| 13 | + | DiffFormatter: {} | |
| 13 | 14 | SessionLogger: {} | |
| 14 | 15 | SessionSpawner: {} | |
| 15 | 16 | TabListProvider: {} | |
| @@ -10,6 +10,7 @@ packages: | |||||
| 10 | interfaces: | 10 | interfaces: | ||
| 11 | ConfigMigrator: {} | 11 | ConfigMigrator: {} | ||
| 12 | DatabaseProvider: {} | 12 | DatabaseProvider: {} | ||
| 13 | + | DiffFormatter: {} | |||
| 13 | SessionLogger: {} | 14 | SessionLogger: {} | ||
| 14 | SessionSpawner: {} | 15 | SessionSpawner: {} | ||
| 15 | TabListProvider: {} | 16 | TabListProvider: {} | ||
M internal/application/port/config_migrator.go +6 -4
| @@ -28,8 +28,6 @@ const ( | |||
| 28 | 28 | KeyChangeRemoved | |
| 29 | 29 | // KeyChangeRenamed indicates a key was renamed (detected via similarity). | |
| 30 | 30 | KeyChangeRenamed | |
| 31 | - | // KeyChangeConsolidated indicates multiple keys were merged into one. | |
| 32 | - | KeyChangeConsolidated | |
| 33 | 31 | ) | |
| 34 | 32 | ||
| 35 | 33 | // String returns a display symbol for the change type. | |
| @@ -41,8 +39,6 @@ func (t KeyChangeType) String() string { | |||
| 41 | 39 | return "-" | |
| 42 | 40 | case KeyChangeRenamed: | |
| 43 | 41 | return "~" | |
| 44 | - | case KeyChangeConsolidated: | |
| 45 | - | return ">" | |
| 46 | 42 | default: | |
| 47 | 43 | return "?" | |
| 48 | 44 | } | |
| @@ -74,3 +70,9 @@ type ConfigMigrator interface { | |||
| 74 | 70 | // GetKeyInfo returns detailed information about a config key. | |
| 75 | 71 | GetKeyInfo(key string) KeyInfo | |
| 76 | 72 | } | |
| 73 | + | ||
| 74 | + | // DiffFormatter formats config changes for display. | |
| 75 | + | type DiffFormatter interface { | |
| 76 | + | // FormatChangesAsDiff returns changes formatted as a diff-like string for display. | |
| 77 | + | FormatChangesAsDiff(changes []KeyChange) string | |
| 78 | + | } | |
| @@ -28,8 +28,6 @@ const ( | |||||
| 28 | KeyChangeRemoved | 28 | KeyChangeRemoved | ||
| 29 | // KeyChangeRenamed indicates a key was renamed (detected via similarity). | 29 | // KeyChangeRenamed indicates a key was renamed (detected via similarity). | ||
| 30 | KeyChangeRenamed | 30 | KeyChangeRenamed | ||
| 31 | - | // KeyChangeConsolidated indicates multiple keys were merged into one. | |||
| 32 | - | KeyChangeConsolidated | |||
| 33 | ) | 31 | ) | ||
| 34 | 32 | ||||
| 35 | // String returns a display symbol for the change type. | 33 | // String returns a display symbol for the change type. | ||
| @@ -41,8 +39,6 @@ func (t KeyChangeType) String() string { | |||||
| 41 | return "-" | 39 | return "-" | ||
| 42 | case KeyChangeRenamed: | 40 | case KeyChangeRenamed: | ||
| 43 | return "~" | 41 | return "~" | ||
| 44 | - | case KeyChangeConsolidated: | |||
| 45 | - | return ">" | |||
| 46 | default: | 42 | default: | ||
| 47 | return "?" | 43 | return "?" | ||
| 48 | } | 44 | } | ||
| @@ -74,3 +70,9 @@ type ConfigMigrator interface { | |||||
| 74 | // GetKeyInfo returns detailed information about a config key. | 70 | // GetKeyInfo returns detailed information about a config key. | ||
| 75 | GetKeyInfo(key string) KeyInfo | 71 | GetKeyInfo(key string) KeyInfo | ||
| 76 | } | 72 | } | ||
| 73 | + | ||||
| 74 | + | // DiffFormatter formats config changes for display. | |||
| 75 | + | type DiffFormatter interface { | |||
| 76 | + | // FormatChangesAsDiff returns changes formatted as a diff-like string for display. | |||
| 77 | + | FormatChangesAsDiff(changes []KeyChange) string | |||
| 78 | + | } | |||
M internal/application/port/mocks/mocks.go +78 -0
| @@ -257,6 +257,84 @@ func (_c *MockConfigMigrator_Migrate_Call) RunAndReturn(run func() ([]string, er | |||
| 257 | 257 | return _c | |
| 258 | 258 | } | |
| 259 | 259 | ||
| 260 | + | // NewMockDiffFormatter creates a new instance of MockDiffFormatter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 261 | + | // The first argument is typically a *testing.T value. | |
| 262 | + | func NewMockDiffFormatter(t interface { | |
| 263 | + | mock.TestingT | |
| 264 | + | Cleanup(func()) | |
| 265 | + | }) *MockDiffFormatter { | |
| 266 | + | mock := &MockDiffFormatter{} | |
| 267 | + | mock.Mock.Test(t) | |
| 268 | + | ||
| 269 | + | t.Cleanup(func() { mock.AssertExpectations(t) }) | |
| 270 | + | ||
| 271 | + | return mock | |
| 272 | + | } | |
| 273 | + | ||
| 274 | + | // MockDiffFormatter is an autogenerated mock type for the DiffFormatter type | |
| 275 | + | type MockDiffFormatter struct { | |
| 276 | + | mock.Mock | |
| 277 | + | } | |
| 278 | + | ||
| 279 | + | type MockDiffFormatter_Expecter struct { | |
| 280 | + | mock *mock.Mock | |
| 281 | + | } | |
| 282 | + | ||
| 283 | + | func (_m *MockDiffFormatter) EXPECT() *MockDiffFormatter_Expecter { | |
| 284 | + | return &MockDiffFormatter_Expecter{mock: &_m.Mock} | |
| 285 | + | } | |
| 286 | + | ||
| 287 | + | // FormatChangesAsDiff provides a mock function for the type MockDiffFormatter | |
| 288 | + | func (_mock *MockDiffFormatter) FormatChangesAsDiff(changes []port.KeyChange) string { | |
| 289 | + | ret := _mock.Called(changes) | |
| 290 | + | ||
| 291 | + | if len(ret) == 0 { | |
| 292 | + | panic("no return value specified for FormatChangesAsDiff") | |
| 293 | + | } | |
| 294 | + | ||
| 295 | + | var r0 string | |
| 296 | + | if returnFunc, ok := ret.Get(0).(func([]port.KeyChange) string); ok { | |
| 297 | + | r0 = returnFunc(changes) | |
| 298 | + | } else { | |
| 299 | + | r0 = ret.Get(0).(string) | |
| 300 | + | } | |
| 301 | + | return r0 | |
| 302 | + | } | |
| 303 | + | ||
| 304 | + | // MockDiffFormatter_FormatChangesAsDiff_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FormatChangesAsDiff' | |
| 305 | + | type MockDiffFormatter_FormatChangesAsDiff_Call struct { | |
| 306 | + | *mock.Call | |
| 307 | + | } | |
| 308 | + | ||
| 309 | + | // FormatChangesAsDiff is a helper method to define mock.On call | |
| 310 | + | // - changes []port.KeyChange | |
| 311 | + | func (_e *MockDiffFormatter_Expecter) FormatChangesAsDiff(changes interface{}) *MockDiffFormatter_FormatChangesAsDiff_Call { | |
| 312 | + | return &MockDiffFormatter_FormatChangesAsDiff_Call{Call: _e.mock.On("FormatChangesAsDiff", changes)} | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | func (_c *MockDiffFormatter_FormatChangesAsDiff_Call) Run(run func(changes []port.KeyChange)) *MockDiffFormatter_FormatChangesAsDiff_Call { | |
| 316 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 317 | + | var arg0 []port.KeyChange | |
| 318 | + | if args[0] != nil { | |
| 319 | + | arg0 = args[0].([]port.KeyChange) | |
| 320 | + | } | |
| 321 | + | run( | |
| 322 | + | arg0, | |
| 323 | + | ) | |
| 324 | + | }) | |
| 325 | + | return _c | |
| 326 | + | } | |
| 327 | + | ||
| 328 | + | func (_c *MockDiffFormatter_FormatChangesAsDiff_Call) Return(s string) *MockDiffFormatter_FormatChangesAsDiff_Call { | |
| 329 | + | _c.Call.Return(s) | |
| 330 | + | return _c | |
| 331 | + | } | |
| 332 | + | ||
| 333 | + | func (_c *MockDiffFormatter_FormatChangesAsDiff_Call) RunAndReturn(run func(changes []port.KeyChange) string) *MockDiffFormatter_FormatChangesAsDiff_Call { | |
| 334 | + | _c.Call.Return(run) | |
| 335 | + | return _c | |
| 336 | + | } | |
| 337 | + | ||
| 260 | 338 | // NewMockDatabaseProvider creates a new instance of MockDatabaseProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 261 | 339 | // The first argument is typically a *testing.T value. | |
| 262 | 340 | func NewMockDatabaseProvider(t interface { | |
| @@ -257,6 +257,84 @@ func (_c *MockConfigMigrator_Migrate_Call) RunAndReturn(run func() ([]string, er | |||||
| 257 | return _c | 257 | return _c | ||
| 258 | } | 258 | } | ||
| 259 | 259 | ||||
| 260 | + | // NewMockDiffFormatter creates a new instance of MockDiffFormatter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |||
| 261 | + | // The first argument is typically a *testing.T value. | |||
| 262 | + | func NewMockDiffFormatter(t interface { | |||
| 263 | + | mock.TestingT | |||
| 264 | + | Cleanup(func()) | |||
| 265 | + | }) *MockDiffFormatter { | |||
| 266 | + | mock := &MockDiffFormatter{} | |||
| 267 | + | mock.Mock.Test(t) | |||
| 268 | + | ||||
| 269 | + | t.Cleanup(func() { mock.AssertExpectations(t) }) | |||
| 270 | + | ||||
| 271 | + | return mock | |||
| 272 | + | } | |||
| 273 | + | ||||
| 274 | + | // MockDiffFormatter is an autogenerated mock type for the DiffFormatter type | |||
| 275 | + | type MockDiffFormatter struct { | |||
| 276 | + | mock.Mock | |||
| 277 | + | } | |||
| 278 | + | ||||
| 279 | + | type MockDiffFormatter_Expecter struct { | |||
| 280 | + | mock *mock.Mock | |||
| 281 | + | } | |||
| 282 | + | ||||
| 283 | + | func (_m *MockDiffFormatter) EXPECT() *MockDiffFormatter_Expecter { | |||
| 284 | + | return &MockDiffFormatter_Expecter{mock: &_m.Mock} | |||
| 285 | + | } | |||
| 286 | + | ||||
| 287 | + | // FormatChangesAsDiff provides a mock function for the type MockDiffFormatter | |||
| 288 | + | func (_mock *MockDiffFormatter) FormatChangesAsDiff(changes []port.KeyChange) string { | |||
| 289 | + | ret := _mock.Called(changes) | |||
| 290 | + | ||||
| 291 | + | if len(ret) == 0 { | |||
| 292 | + | panic("no return value specified for FormatChangesAsDiff") | |||
| 293 | + | } | |||
| 294 | + | ||||
| 295 | + | var r0 string | |||
| 296 | + | if returnFunc, ok := ret.Get(0).(func([]port.KeyChange) string); ok { | |||
| 297 | + | r0 = returnFunc(changes) | |||
| 298 | + | } else { | |||
| 299 | + | r0 = ret.Get(0).(string) | |||
| 300 | + | } | |||
| 301 | + | return r0 | |||
| 302 | + | } | |||
| 303 | + | ||||
| 304 | + | // MockDiffFormatter_FormatChangesAsDiff_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FormatChangesAsDiff' | |||
| 305 | + | type MockDiffFormatter_FormatChangesAsDiff_Call struct { | |||
| 306 | + | *mock.Call | |||
| 307 | + | } | |||
| 308 | + | ||||
| 309 | + | // FormatChangesAsDiff is a helper method to define mock.On call | |||
| 310 | + | // - changes []port.KeyChange | |||
| 311 | + | func (_e *MockDiffFormatter_Expecter) FormatChangesAsDiff(changes interface{}) *MockDiffFormatter_FormatChangesAsDiff_Call { | |||
| 312 | + | return &MockDiffFormatter_FormatChangesAsDiff_Call{Call: _e.mock.On("FormatChangesAsDiff", changes)} | |||
| 313 | + | } | |||
| 314 | + | ||||
| 315 | + | func (_c *MockDiffFormatter_FormatChangesAsDiff_Call) Run(run func(changes []port.KeyChange)) *MockDiffFormatter_FormatChangesAsDiff_Call { | |||
| 316 | + | _c.Call.Run(func(args mock.Arguments) { | |||
| 317 | + | var arg0 []port.KeyChange | |||
| 318 | + | if args[0] != nil { | |||
| 319 | + | arg0 = args[0].([]port.KeyChange) | |||
| 320 | + | } | |||
| 321 | + | run( | |||
| 322 | + | arg0, | |||
| 323 | + | ) | |||
| 324 | + | }) | |||
| 325 | + | return _c | |||
| 326 | + | } | |||
| 327 | + | ||||
| 328 | + | func (_c *MockDiffFormatter_FormatChangesAsDiff_Call) Return(s string) *MockDiffFormatter_FormatChangesAsDiff_Call { | |||
| 329 | + | _c.Call.Return(s) | |||
| 330 | + | return _c | |||
| 331 | + | } | |||
| 332 | + | ||||
| 333 | + | func (_c *MockDiffFormatter_FormatChangesAsDiff_Call) RunAndReturn(run func(changes []port.KeyChange) string) *MockDiffFormatter_FormatChangesAsDiff_Call { | |||
| 334 | + | _c.Call.Return(run) | |||
| 335 | + | return _c | |||
| 336 | + | } | |||
| 337 | + | ||||
| 260 | // NewMockDatabaseProvider creates a new instance of MockDatabaseProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | 338 | // NewMockDatabaseProvider creates a new instance of MockDatabaseProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | ||
| 261 | // The first argument is typically a *testing.T value. | 339 | // The first argument is typically a *testing.T value. | ||
| 262 | func NewMockDatabaseProvider(t interface { | 340 | func NewMockDatabaseProvider(t interface { | ||
M internal/application/usecase/migrate_config.go +6 -32
| @@ -2,8 +2,6 @@ package usecase | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "context" | |
| 5 | - | "fmt" | |
| 6 | - | "strings" | |
| 7 | 5 | ||
| 8 | 6 | "github.com/bnema/dumber/internal/application/port" | |
| 9 | 7 | "github.com/bnema/dumber/internal/logging" | |
| @@ -48,13 +46,15 @@ type MigrateConfigOutput struct { | |||
| 48 | 46 | ||
| 49 | 47 | // MigrateConfigUseCase handles config migration operations. | |
| 50 | 48 | type MigrateConfigUseCase struct { | |
| 51 | - | migrator port.ConfigMigrator | |
| 49 | + | migrator port.ConfigMigrator | |
| 50 | + | diffFormatter port.DiffFormatter | |
| 52 | 51 | } | |
| 53 | 52 | ||
| 54 | 53 | // NewMigrateConfigUseCase creates a new migrate config use case. | |
| 55 | - | func NewMigrateConfigUseCase(migrator port.ConfigMigrator) *MigrateConfigUseCase { | |
| 54 | + | func NewMigrateConfigUseCase(migrator port.ConfigMigrator, diffFormatter port.DiffFormatter) *MigrateConfigUseCase { | |
| 56 | 55 | return &MigrateConfigUseCase{ | |
| 57 | - | migrator: migrator, | |
| 56 | + | migrator: migrator, | |
| 57 | + | diffFormatter: diffFormatter, | |
| 58 | 58 | } | |
| 59 | 59 | } | |
| 60 | 60 | ||
| @@ -122,7 +122,7 @@ func (uc *MigrateConfigUseCase) DetectChanges(ctx context.Context, _ DetectChang | |||
| 122 | 122 | return &DetectChangesOutput{ | |
| 123 | 123 | HasChanges: true, | |
| 124 | 124 | Changes: changes, | |
| 125 | - | DiffText: formatChangesAsDiff(changes), | |
| 125 | + | DiffText: uc.diffFormatter.FormatChangesAsDiff(changes), | |
| 126 | 126 | }, nil | |
| 127 | 127 | } | |
| 128 | 128 | ||
| @@ -161,29 +161,3 @@ func (uc *MigrateConfigUseCase) Execute(ctx context.Context, _ MigrateConfigInpu | |||
| 161 | 161 | ConfigFile: checkResult.ConfigFile, | |
| 162 | 162 | }, nil | |
| 163 | 163 | } | |
| 164 | - | ||
| 165 | - | // formatChangesAsDiff returns changes formatted as a diff for display. | |
| 166 | - | func formatChangesAsDiff(changes []port.KeyChange) string { | |
| 167 | - | if len(changes) == 0 { | |
| 168 | - | return "No changes detected." | |
| 169 | - | } | |
| 170 | - | ||
| 171 | - | var sb strings.Builder | |
| 172 | - | sb.WriteString("Config migration changes:\n\n") | |
| 173 | - | ||
| 174 | - | for _, change := range changes { | |
| 175 | - | switch change.Type { | |
| 176 | - | case port.KeyChangeAdded: | |
| 177 | - | sb.WriteString(fmt.Sprintf(" + %s = %s\n", change.NewKey, change.NewValue)) | |
| 178 | - | case port.KeyChangeRemoved: | |
| 179 | - | sb.WriteString(fmt.Sprintf(" - %s = %s (deprecated)\n", change.OldKey, change.OldValue)) | |
| 180 | - | case port.KeyChangeRenamed: | |
| 181 | - | sb.WriteString(fmt.Sprintf(" ~ %s -> %s\n", change.OldKey, change.NewKey)) | |
| 182 | - | sb.WriteString(fmt.Sprintf(" (value: %s)\n", change.OldValue)) | |
| 183 | - | case port.KeyChangeConsolidated: | |
| 184 | - | sb.WriteString(fmt.Sprintf(" > %s -> %s\n", change.OldKey, change.NewKey)) | |
| 185 | - | } | |
| 186 | - | } | |
| 187 | - | ||
| 188 | - | return sb.String() | |
| 189 | - | } | |
| @@ -2,8 +2,6 @@ package usecase | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "context" | 4 | "context" | ||
| 5 | - | "fmt" | |||
| 6 | - | "strings" | |||
| 7 | 5 | ||||
| 8 | "github.com/bnema/dumber/internal/application/port" | 6 | "github.com/bnema/dumber/internal/application/port" | ||
| 9 | "github.com/bnema/dumber/internal/logging" | 7 | "github.com/bnema/dumber/internal/logging" | ||
| @@ -48,13 +46,15 @@ type MigrateConfigOutput struct { | |||||
| 48 | 46 | ||||
| 49 | // MigrateConfigUseCase handles config migration operations. | 47 | // MigrateConfigUseCase handles config migration operations. | ||
| 50 | type MigrateConfigUseCase struct { | 48 | type MigrateConfigUseCase struct { | ||
| 51 | - | migrator port.ConfigMigrator | 49 | + | migrator port.ConfigMigrator |
| 50 | + | diffFormatter port.DiffFormatter | |||
| 52 | } | 51 | } | ||
| 53 | 52 | ||||
| 54 | // NewMigrateConfigUseCase creates a new migrate config use case. | 53 | // NewMigrateConfigUseCase creates a new migrate config use case. | ||
| 55 | - | func NewMigrateConfigUseCase(migrator port.ConfigMigrator) *MigrateConfigUseCase { | 54 | + | func NewMigrateConfigUseCase(migrator port.ConfigMigrator, diffFormatter port.DiffFormatter) *MigrateConfigUseCase { |
| 56 | return &MigrateConfigUseCase{ | 55 | return &MigrateConfigUseCase{ | ||
| 57 | - | migrator: migrator, | 56 | + | migrator: migrator, |
| 57 | + | diffFormatter: diffFormatter, | |||
| 58 | } | 58 | } | ||
| 59 | } | 59 | } | ||
| 60 | 60 | ||||
| @@ -122,7 +122,7 @@ func (uc *MigrateConfigUseCase) DetectChanges(ctx context.Context, _ DetectChang | |||||
| 122 | return &DetectChangesOutput{ | 122 | return &DetectChangesOutput{ | ||
| 123 | HasChanges: true, | 123 | HasChanges: true, | ||
| 124 | Changes: changes, | 124 | Changes: changes, | ||
| 125 | - | DiffText: formatChangesAsDiff(changes), | 125 | + | DiffText: uc.diffFormatter.FormatChangesAsDiff(changes), |
| 126 | }, nil | 126 | }, nil | ||
| 127 | } | 127 | } | ||
| 128 | 128 | ||||
| @@ -161,29 +161,3 @@ func (uc *MigrateConfigUseCase) Execute(ctx context.Context, _ MigrateConfigInpu | |||||
| 161 | ConfigFile: checkResult.ConfigFile, | 161 | ConfigFile: checkResult.ConfigFile, | ||
| 162 | }, nil | 162 | }, nil | ||
| 163 | } | 163 | } | ||
| 164 | - | ||||
| 165 | - | // formatChangesAsDiff returns changes formatted as a diff for display. | |||
| 166 | - | func formatChangesAsDiff(changes []port.KeyChange) string { | |||
| 167 | - | if len(changes) == 0 { | |||
| 168 | - | return "No changes detected." | |||
| 169 | - | } | |||
| 170 | - | ||||
| 171 | - | var sb strings.Builder | |||
| 172 | - | sb.WriteString("Config migration changes:\n\n") | |||
| 173 | - | ||||
| 174 | - | for _, change := range changes { | |||
| 175 | - | switch change.Type { | |||
| 176 | - | case port.KeyChangeAdded: | |||
| 177 | - | sb.WriteString(fmt.Sprintf(" + %s = %s\n", change.NewKey, change.NewValue)) | |||
| 178 | - | case port.KeyChangeRemoved: | |||
| 179 | - | sb.WriteString(fmt.Sprintf(" - %s = %s (deprecated)\n", change.OldKey, change.OldValue)) | |||
| 180 | - | case port.KeyChangeRenamed: | |||
| 181 | - | sb.WriteString(fmt.Sprintf(" ~ %s -> %s\n", change.OldKey, change.NewKey)) | |||
| 182 | - | sb.WriteString(fmt.Sprintf(" (value: %s)\n", change.OldValue)) | |||
| 183 | - | case port.KeyChangeConsolidated: | |||
| 184 | - | sb.WriteString(fmt.Sprintf(" > %s -> %s\n", change.OldKey, change.NewKey)) | |||
| 185 | - | } | |||
| 186 | - | } | |||
| 187 | - | ||||
| 188 | - | return sb.String() | |||
| 189 | - | } | |||
M internal/application/usecase/migrate_config_test.go +44 -60
| @@ -15,9 +15,10 @@ import ( | |||
| 15 | 15 | ||
| 16 | 16 | func TestMigrateConfigUseCase_Check_NoMigrationNeeded(t *testing.T) { | |
| 17 | 17 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 18 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 18 | 19 | mockMigrator.EXPECT().CheckMigration().Return(nil, nil) | |
| 19 | 20 | ||
| 20 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 21 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 21 | 22 | ctx := context.Background() | |
| 22 | 23 | ||
| 23 | 24 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | |
| @@ -29,6 +30,7 @@ func TestMigrateConfigUseCase_Check_NoMigrationNeeded(t *testing.T) { | |||
| 29 | 30 | ||
| 30 | 31 | func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | |
| 31 | 32 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 33 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 32 | 34 | ||
| 33 | 35 | migrationResult := &port.MigrationResult{ | |
| 34 | 36 | MissingKeys: []string{"key1", "key2"}, | |
| @@ -48,7 +50,7 @@ func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | |||
| 48 | 50 | DefaultValue: `"default"`, | |
| 49 | 51 | }) | |
| 50 | 52 | ||
| 51 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 53 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 52 | 54 | ctx := context.Background() | |
| 53 | 55 | ||
| 54 | 56 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | |
| @@ -67,10 +69,11 @@ func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | |||
| 67 | 69 | ||
| 68 | 70 | func TestMigrateConfigUseCase_Check_Error(t *testing.T) { | |
| 69 | 71 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 72 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 70 | 73 | expectedErr := errors.New("check failed") | |
| 71 | 74 | mockMigrator.EXPECT().CheckMigration().Return(nil, expectedErr) | |
| 72 | 75 | ||
| 73 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 76 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 74 | 77 | ctx := context.Background() | |
| 75 | 78 | ||
| 76 | 79 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | |
| @@ -82,9 +85,10 @@ func TestMigrateConfigUseCase_Check_Error(t *testing.T) { | |||
| 82 | 85 | ||
| 83 | 86 | func TestMigrateConfigUseCase_Execute_NoMigrationNeeded(t *testing.T) { | |
| 84 | 87 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 88 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 85 | 89 | mockMigrator.EXPECT().CheckMigration().Return(nil, nil) | |
| 86 | 90 | ||
| 87 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 91 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 88 | 92 | ctx := context.Background() | |
| 89 | 93 | ||
| 90 | 94 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | |
| @@ -95,6 +99,7 @@ func TestMigrateConfigUseCase_Execute_NoMigrationNeeded(t *testing.T) { | |||
| 95 | 99 | ||
| 96 | 100 | func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | |
| 97 | 101 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 102 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 98 | 103 | ||
| 99 | 104 | migrationResult := &port.MigrationResult{ | |
| 100 | 105 | MissingKeys: []string{"key1", "key2"}, | |
| @@ -103,7 +108,7 @@ func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | |||
| 103 | 108 | mockMigrator.EXPECT().CheckMigration().Return(migrationResult, nil) | |
| 104 | 109 | mockMigrator.EXPECT().Migrate().Return([]string{"key1", "key2"}, nil) | |
| 105 | 110 | ||
| 106 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 111 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 107 | 112 | ctx := context.Background() | |
| 108 | 113 | ||
| 109 | 114 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | |
| @@ -115,6 +120,7 @@ func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | |||
| 115 | 120 | ||
| 116 | 121 | func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | |
| 117 | 122 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 123 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 118 | 124 | ||
| 119 | 125 | migrationResult := &port.MigrationResult{ | |
| 120 | 126 | MissingKeys: []string{"key1"}, | |
| @@ -125,7 +131,7 @@ func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | |||
| 125 | 131 | expectedErr := errors.New("migrate failed") | |
| 126 | 132 | mockMigrator.EXPECT().Migrate().Return(nil, expectedErr) | |
| 127 | 133 | ||
| 128 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 134 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 129 | 135 | ctx := context.Background() | |
| 130 | 136 | ||
| 131 | 137 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | |
| @@ -137,11 +143,12 @@ func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | |||
| 137 | 143 | ||
| 138 | 144 | func TestMigrateConfigUseCase_Execute_CheckError(t *testing.T) { | |
| 139 | 145 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 146 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 140 | 147 | ||
| 141 | 148 | expectedErr := errors.New("check failed") | |
| 142 | 149 | mockMigrator.EXPECT().CheckMigration().Return(nil, expectedErr) | |
| 143 | 150 | ||
| 144 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 151 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 145 | 152 | ctx := context.Background() | |
| 146 | 153 | ||
| 147 | 154 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | |
| @@ -153,6 +160,7 @@ func TestMigrateConfigUseCase_Execute_CheckError(t *testing.T) { | |||
| 153 | 160 | ||
| 154 | 161 | func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | |
| 155 | 162 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 163 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 156 | 164 | ||
| 157 | 165 | // Return a result with empty missing keys | |
| 158 | 166 | migrationResult := &port.MigrationResult{ | |
| @@ -161,7 +169,7 @@ func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | |||
| 161 | 169 | } | |
| 162 | 170 | mockMigrator.EXPECT().CheckMigration().Return(migrationResult, nil) | |
| 163 | 171 | ||
| 164 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 172 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 165 | 173 | ctx := context.Background() | |
| 166 | 174 | ||
| 167 | 175 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | |
| @@ -173,15 +181,18 @@ func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | |||
| 173 | 181 | ||
| 174 | 182 | func TestNewMigrateConfigUseCase(t *testing.T) { | |
| 175 | 183 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 176 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 184 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 185 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 177 | 186 | ||
| 178 | 187 | assert.NotNil(t, uc) | |
| 179 | 188 | assert.Equal(t, mockMigrator, uc.migrator) | |
| 189 | + | assert.Equal(t, mockFormatter, uc.diffFormatter) | |
| 180 | 190 | } | |
| 181 | 191 | ||
| 182 | 192 | // Ensure mock expectations are set up correctly | |
| 183 | 193 | func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | |
| 184 | 194 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 195 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 185 | 196 | ||
| 186 | 197 | // Set up expectations with mock.Anything for flexibility | |
| 187 | 198 | mockMigrator.On("CheckMigration").Return(&port.MigrationResult{ | |
| @@ -195,7 +206,7 @@ func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | |||
| 195 | 206 | DefaultValue: `"test"`, | |
| 196 | 207 | }).Once() | |
| 197 | 208 | ||
| 198 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 209 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 199 | 210 | ctx := context.Background() | |
| 200 | 211 | ||
| 201 | 212 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | |
| @@ -207,9 +218,10 @@ func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | |||
| 207 | 218 | ||
| 208 | 219 | func TestMigrateConfigUseCase_DetectChanges_NoChanges(t *testing.T) { | |
| 209 | 220 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 221 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 210 | 222 | mockMigrator.EXPECT().DetectChanges().Return(nil, nil) | |
| 211 | 223 | ||
| 212 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 224 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 213 | 225 | ctx := context.Background() | |
| 214 | 226 | ||
| 215 | 227 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | |
| @@ -222,6 +234,7 @@ func TestMigrateConfigUseCase_DetectChanges_NoChanges(t *testing.T) { | |||
| 222 | 234 | ||
| 223 | 235 | func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | |
| 224 | 236 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 237 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 225 | 238 | ||
| 226 | 239 | changes := []port.KeyChange{ | |
| 227 | 240 | { | |
| @@ -231,8 +244,9 @@ func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | |||
| 231 | 244 | }, | |
| 232 | 245 | } | |
| 233 | 246 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | |
| 247 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return("Config migration changes:\n\n + workspace.styling.mode_indicator_toaster_enabled = true\n") | |
| 234 | 248 | ||
| 235 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 249 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 236 | 250 | ctx := context.Background() | |
| 237 | 251 | ||
| 238 | 252 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | |
| @@ -245,6 +259,7 @@ func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | |||
| 245 | 259 | ||
| 246 | 260 | func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | |
| 247 | 261 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 262 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 248 | 263 | ||
| 249 | 264 | changes := []port.KeyChange{ | |
| 250 | 265 | { | |
| @@ -255,8 +270,9 @@ func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | |||
| 255 | 270 | }, | |
| 256 | 271 | } | |
| 257 | 272 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | |
| 273 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return("Config migration changes:\n\n ~ workspace.styling.pane_mode_border_color -> workspace.styling.pane_mode_color\n (value: \"#4A90E2\")\n") | |
| 258 | 274 | ||
| 259 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 275 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 260 | 276 | ctx := context.Background() | |
| 261 | 277 | ||
| 262 | 278 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | |
| @@ -269,6 +285,7 @@ func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | |||
| 269 | 285 | ||
| 270 | 286 | func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | |
| 271 | 287 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 288 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 272 | 289 | ||
| 273 | 290 | changes := []port.KeyChange{ | |
| 274 | 291 | { | |
| @@ -278,8 +295,9 @@ func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | |||
| 278 | 295 | }, | |
| 279 | 296 | } | |
| 280 | 297 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | |
| 298 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return("Config migration changes:\n\n - workspace.styling.pane_mode_border_width = 4 (deprecated)\n") | |
| 281 | 299 | ||
| 282 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 300 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 283 | 301 | ctx := context.Background() | |
| 284 | 302 | ||
| 285 | 303 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | |
| @@ -293,10 +311,11 @@ func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | |||
| 293 | 311 | ||
| 294 | 312 | func TestMigrateConfigUseCase_DetectChanges_Error(t *testing.T) { | |
| 295 | 313 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 314 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 296 | 315 | expectedErr := errors.New("detect changes failed") | |
| 297 | 316 | mockMigrator.EXPECT().DetectChanges().Return(nil, expectedErr) | |
| 298 | 317 | ||
| 299 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 318 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 300 | 319 | ctx := context.Background() | |
| 301 | 320 | ||
| 302 | 321 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | |
| @@ -308,6 +327,7 @@ func TestMigrateConfigUseCase_DetectChanges_Error(t *testing.T) { | |||
| 308 | 327 | ||
| 309 | 328 | func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | |
| 310 | 329 | mockMigrator := mocks.NewMockConfigMigrator(t) | |
| 330 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |
| 311 | 331 | ||
| 312 | 332 | changes := []port.KeyChange{ | |
| 313 | 333 | { | |
| @@ -328,8 +348,15 @@ func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | |||
| 328 | 348 | }, | |
| 329 | 349 | } | |
| 330 | 350 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | |
| 331 | - | ||
| 332 | - | uc := NewMigrateConfigUseCase(mockMigrator) | |
| 351 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return( | |
| 352 | + | "Config migration changes:\n\n" + | |
| 353 | + | " + workspace.styling.mode_border_width = 4\n" + | |
| 354 | + | " ~ workspace.styling.pane_mode_border_color -> workspace.styling.pane_mode_color\n" + | |
| 355 | + | " (value: \"#4A90E2\")\n" + | |
| 356 | + | " - workspace.styling.pane_mode_border_width = 4 (deprecated)\n", | |
| 357 | + | ) | |
| 358 | + | ||
| 359 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |
| 333 | 360 | ctx := context.Background() | |
| 334 | 361 | ||
| 335 | 362 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | |
| @@ -343,46 +370,3 @@ func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | |||
| 343 | 370 | assert.Contains(t, result.DiffText, "~ workspace.styling.pane_mode_border_color") | |
| 344 | 371 | assert.Contains(t, result.DiffText, "- workspace.styling.pane_mode_border_width") | |
| 345 | 372 | } | |
| 346 | - | ||
| 347 | - | func TestFormatChangesAsDiff_EmptyChanges(t *testing.T) { | |
| 348 | - | result := formatChangesAsDiff(nil) | |
| 349 | - | assert.Equal(t, "No changes detected.", result) | |
| 350 | - | ||
| 351 | - | result = formatChangesAsDiff([]port.KeyChange{}) | |
| 352 | - | assert.Equal(t, "No changes detected.", result) | |
| 353 | - | } | |
| 354 | - | ||
| 355 | - | func TestFormatChangesAsDiff_AllChangeTypes(t *testing.T) { | |
| 356 | - | changes := []port.KeyChange{ | |
| 357 | - | { | |
| 358 | - | Type: port.KeyChangeAdded, | |
| 359 | - | NewKey: "new.key", | |
| 360 | - | NewValue: `"value"`, | |
| 361 | - | }, | |
| 362 | - | { | |
| 363 | - | Type: port.KeyChangeRemoved, | |
| 364 | - | OldKey: "old.key", | |
| 365 | - | OldValue: `"old_value"`, | |
| 366 | - | }, | |
| 367 | - | { | |
| 368 | - | Type: port.KeyChangeRenamed, | |
| 369 | - | OldKey: "renamed.old", | |
| 370 | - | NewKey: "renamed.new", | |
| 371 | - | OldValue: `"renamed_value"`, | |
| 372 | - | }, | |
| 373 | - | { | |
| 374 | - | Type: port.KeyChangeConsolidated, | |
| 375 | - | OldKey: "consolidated.old", | |
| 376 | - | NewKey: "consolidated.new", | |
| 377 | - | }, | |
| 378 | - | } | |
| 379 | - | ||
| 380 | - | result := formatChangesAsDiff(changes) | |
| 381 | - | ||
| 382 | - | assert.Contains(t, result, "Config migration changes:") | |
| 383 | - | assert.Contains(t, result, `+ new.key = "value"`) | |
| 384 | - | assert.Contains(t, result, `- old.key = "old_value" (deprecated)`) | |
| 385 | - | assert.Contains(t, result, "~ renamed.old -> renamed.new") | |
| 386 | - | assert.Contains(t, result, `(value: "renamed_value")`) | |
| 387 | - | assert.Contains(t, result, "> consolidated.old -> consolidated.new") | |
| 388 | - | } | |
| @@ -15,9 +15,10 @@ import ( | |||||
| 15 | 15 | ||||
| 16 | func TestMigrateConfigUseCase_Check_NoMigrationNeeded(t *testing.T) { | 16 | func TestMigrateConfigUseCase_Check_NoMigrationNeeded(t *testing.T) { | ||
| 17 | mockMigrator := mocks.NewMockConfigMigrator(t) | 17 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 18 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 18 | mockMigrator.EXPECT().CheckMigration().Return(nil, nil) | 19 | mockMigrator.EXPECT().CheckMigration().Return(nil, nil) | ||
| 19 | 20 | ||||
| 20 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 21 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 21 | ctx := context.Background() | 22 | ctx := context.Background() | ||
| 22 | 23 | ||||
| 23 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | 24 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | ||
| @@ -29,6 +30,7 @@ func TestMigrateConfigUseCase_Check_NoMigrationNeeded(t *testing.T) { | |||||
| 29 | 30 | ||||
| 30 | func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | 31 | func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | ||
| 31 | mockMigrator := mocks.NewMockConfigMigrator(t) | 32 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 33 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 32 | 34 | ||||
| 33 | migrationResult := &port.MigrationResult{ | 35 | migrationResult := &port.MigrationResult{ | ||
| 34 | MissingKeys: []string{"key1", "key2"}, | 36 | MissingKeys: []string{"key1", "key2"}, | ||
| @@ -48,7 +50,7 @@ func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | |||||
| 48 | DefaultValue: `"default"`, | 50 | DefaultValue: `"default"`, | ||
| 49 | }) | 51 | }) | ||
| 50 | 52 | ||||
| 51 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 53 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 52 | ctx := context.Background() | 54 | ctx := context.Background() | ||
| 53 | 55 | ||||
| 54 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | 56 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | ||
| @@ -67,10 +69,11 @@ func TestMigrateConfigUseCase_Check_MigrationNeeded(t *testing.T) { | |||||
| 67 | 69 | ||||
| 68 | func TestMigrateConfigUseCase_Check_Error(t *testing.T) { | 70 | func TestMigrateConfigUseCase_Check_Error(t *testing.T) { | ||
| 69 | mockMigrator := mocks.NewMockConfigMigrator(t) | 71 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 72 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 70 | expectedErr := errors.New("check failed") | 73 | expectedErr := errors.New("check failed") | ||
| 71 | mockMigrator.EXPECT().CheckMigration().Return(nil, expectedErr) | 74 | mockMigrator.EXPECT().CheckMigration().Return(nil, expectedErr) | ||
| 72 | 75 | ||||
| 73 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 76 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 74 | ctx := context.Background() | 77 | ctx := context.Background() | ||
| 75 | 78 | ||||
| 76 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | 79 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | ||
| @@ -82,9 +85,10 @@ func TestMigrateConfigUseCase_Check_Error(t *testing.T) { | |||||
| 82 | 85 | ||||
| 83 | func TestMigrateConfigUseCase_Execute_NoMigrationNeeded(t *testing.T) { | 86 | func TestMigrateConfigUseCase_Execute_NoMigrationNeeded(t *testing.T) { | ||
| 84 | mockMigrator := mocks.NewMockConfigMigrator(t) | 87 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 88 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 85 | mockMigrator.EXPECT().CheckMigration().Return(nil, nil) | 89 | mockMigrator.EXPECT().CheckMigration().Return(nil, nil) | ||
| 86 | 90 | ||||
| 87 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 91 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 88 | ctx := context.Background() | 92 | ctx := context.Background() | ||
| 89 | 93 | ||||
| 90 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | 94 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | ||
| @@ -95,6 +99,7 @@ func TestMigrateConfigUseCase_Execute_NoMigrationNeeded(t *testing.T) { | |||||
| 95 | 99 | ||||
| 96 | func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | 100 | func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | ||
| 97 | mockMigrator := mocks.NewMockConfigMigrator(t) | 101 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 102 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 98 | 103 | ||||
| 99 | migrationResult := &port.MigrationResult{ | 104 | migrationResult := &port.MigrationResult{ | ||
| 100 | MissingKeys: []string{"key1", "key2"}, | 105 | MissingKeys: []string{"key1", "key2"}, | ||
| @@ -103,7 +108,7 @@ func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | |||||
| 103 | mockMigrator.EXPECT().CheckMigration().Return(migrationResult, nil) | 108 | mockMigrator.EXPECT().CheckMigration().Return(migrationResult, nil) | ||
| 104 | mockMigrator.EXPECT().Migrate().Return([]string{"key1", "key2"}, nil) | 109 | mockMigrator.EXPECT().Migrate().Return([]string{"key1", "key2"}, nil) | ||
| 105 | 110 | ||||
| 106 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 111 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 107 | ctx := context.Background() | 112 | ctx := context.Background() | ||
| 108 | 113 | ||||
| 109 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | 114 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | ||
| @@ -115,6 +120,7 @@ func TestMigrateConfigUseCase_Execute_Success(t *testing.T) { | |||||
| 115 | 120 | ||||
| 116 | func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | 121 | func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | ||
| 117 | mockMigrator := mocks.NewMockConfigMigrator(t) | 122 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 123 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 118 | 124 | ||||
| 119 | migrationResult := &port.MigrationResult{ | 125 | migrationResult := &port.MigrationResult{ | ||
| 120 | MissingKeys: []string{"key1"}, | 126 | MissingKeys: []string{"key1"}, | ||
| @@ -125,7 +131,7 @@ func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | |||||
| 125 | expectedErr := errors.New("migrate failed") | 131 | expectedErr := errors.New("migrate failed") | ||
| 126 | mockMigrator.EXPECT().Migrate().Return(nil, expectedErr) | 132 | mockMigrator.EXPECT().Migrate().Return(nil, expectedErr) | ||
| 127 | 133 | ||||
| 128 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 134 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 129 | ctx := context.Background() | 135 | ctx := context.Background() | ||
| 130 | 136 | ||||
| 131 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | 137 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | ||
| @@ -137,11 +143,12 @@ func TestMigrateConfigUseCase_Execute_MigrateError(t *testing.T) { | |||||
| 137 | 143 | ||||
| 138 | func TestMigrateConfigUseCase_Execute_CheckError(t *testing.T) { | 144 | func TestMigrateConfigUseCase_Execute_CheckError(t *testing.T) { | ||
| 139 | mockMigrator := mocks.NewMockConfigMigrator(t) | 145 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 146 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 140 | 147 | ||||
| 141 | expectedErr := errors.New("check failed") | 148 | expectedErr := errors.New("check failed") | ||
| 142 | mockMigrator.EXPECT().CheckMigration().Return(nil, expectedErr) | 149 | mockMigrator.EXPECT().CheckMigration().Return(nil, expectedErr) | ||
| 143 | 150 | ||||
| 144 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 151 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 145 | ctx := context.Background() | 152 | ctx := context.Background() | ||
| 146 | 153 | ||||
| 147 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | 154 | result, err := uc.Execute(ctx, MigrateConfigInput{}) | ||
| @@ -153,6 +160,7 @@ func TestMigrateConfigUseCase_Execute_CheckError(t *testing.T) { | |||||
| 153 | 160 | ||||
| 154 | func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | 161 | func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | ||
| 155 | mockMigrator := mocks.NewMockConfigMigrator(t) | 162 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 163 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 156 | 164 | ||||
| 157 | // Return a result with empty missing keys | 165 | // Return a result with empty missing keys | ||
| 158 | migrationResult := &port.MigrationResult{ | 166 | migrationResult := &port.MigrationResult{ | ||
| @@ -161,7 +169,7 @@ func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | |||||
| 161 | } | 169 | } | ||
| 162 | mockMigrator.EXPECT().CheckMigration().Return(migrationResult, nil) | 170 | mockMigrator.EXPECT().CheckMigration().Return(migrationResult, nil) | ||
| 163 | 171 | ||||
| 164 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 172 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 165 | ctx := context.Background() | 173 | ctx := context.Background() | ||
| 166 | 174 | ||||
| 167 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | 175 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | ||
| @@ -173,15 +181,18 @@ func TestMigrateConfigUseCase_Check_EmptyMissingKeys(t *testing.T) { | |||||
| 173 | 181 | ||||
| 174 | func TestNewMigrateConfigUseCase(t *testing.T) { | 182 | func TestNewMigrateConfigUseCase(t *testing.T) { | ||
| 175 | mockMigrator := mocks.NewMockConfigMigrator(t) | 183 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 176 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 184 | + | mockFormatter := mocks.NewMockDiffFormatter(t) |
| 185 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |||
| 177 | 186 | ||||
| 178 | assert.NotNil(t, uc) | 187 | assert.NotNil(t, uc) | ||
| 179 | assert.Equal(t, mockMigrator, uc.migrator) | 188 | assert.Equal(t, mockMigrator, uc.migrator) | ||
| 189 | + | assert.Equal(t, mockFormatter, uc.diffFormatter) | |||
| 180 | } | 190 | } | ||
| 181 | 191 | ||||
| 182 | // Ensure mock expectations are set up correctly | 192 | // Ensure mock expectations are set up correctly | ||
| 183 | func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | 193 | func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | ||
| 184 | mockMigrator := mocks.NewMockConfigMigrator(t) | 194 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 195 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 185 | 196 | ||||
| 186 | // Set up expectations with mock.Anything for flexibility | 197 | // Set up expectations with mock.Anything for flexibility | ||
| 187 | mockMigrator.On("CheckMigration").Return(&port.MigrationResult{ | 198 | mockMigrator.On("CheckMigration").Return(&port.MigrationResult{ | ||
| @@ -195,7 +206,7 @@ func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | |||||
| 195 | DefaultValue: `"test"`, | 206 | DefaultValue: `"test"`, | ||
| 196 | }).Once() | 207 | }).Once() | ||
| 197 | 208 | ||||
| 198 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 209 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 199 | ctx := context.Background() | 210 | ctx := context.Background() | ||
| 200 | 211 | ||||
| 201 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | 212 | result, err := uc.Check(ctx, CheckConfigMigrationInput{}) | ||
| @@ -207,9 +218,10 @@ func TestMigrateConfigUseCase_MockExpectations(t *testing.T) { | |||||
| 207 | 218 | ||||
| 208 | func TestMigrateConfigUseCase_DetectChanges_NoChanges(t *testing.T) { | 219 | func TestMigrateConfigUseCase_DetectChanges_NoChanges(t *testing.T) { | ||
| 209 | mockMigrator := mocks.NewMockConfigMigrator(t) | 220 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 221 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 210 | mockMigrator.EXPECT().DetectChanges().Return(nil, nil) | 222 | mockMigrator.EXPECT().DetectChanges().Return(nil, nil) | ||
| 211 | 223 | ||||
| 212 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 224 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 213 | ctx := context.Background() | 225 | ctx := context.Background() | ||
| 214 | 226 | ||||
| 215 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | 227 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | ||
| @@ -222,6 +234,7 @@ func TestMigrateConfigUseCase_DetectChanges_NoChanges(t *testing.T) { | |||||
| 222 | 234 | ||||
| 223 | func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | 235 | func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | ||
| 224 | mockMigrator := mocks.NewMockConfigMigrator(t) | 236 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 237 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 225 | 238 | ||||
| 226 | changes := []port.KeyChange{ | 239 | changes := []port.KeyChange{ | ||
| 227 | { | 240 | { | ||
| @@ -231,8 +244,9 @@ func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | |||||
| 231 | }, | 244 | }, | ||
| 232 | } | 245 | } | ||
| 233 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | 246 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | ||
| 247 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return("Config migration changes:\n\n + workspace.styling.mode_indicator_toaster_enabled = true\n") | |||
| 234 | 248 | ||||
| 235 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 249 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 236 | ctx := context.Background() | 250 | ctx := context.Background() | ||
| 237 | 251 | ||||
| 238 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | 252 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | ||
| @@ -245,6 +259,7 @@ func TestMigrateConfigUseCase_DetectChanges_WithAddedKey(t *testing.T) { | |||||
| 245 | 259 | ||||
| 246 | func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | 260 | func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | ||
| 247 | mockMigrator := mocks.NewMockConfigMigrator(t) | 261 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 262 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 248 | 263 | ||||
| 249 | changes := []port.KeyChange{ | 264 | changes := []port.KeyChange{ | ||
| 250 | { | 265 | { | ||
| @@ -255,8 +270,9 @@ func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | |||||
| 255 | }, | 270 | }, | ||
| 256 | } | 271 | } | ||
| 257 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | 272 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | ||
| 273 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return("Config migration changes:\n\n ~ workspace.styling.pane_mode_border_color -> workspace.styling.pane_mode_color\n (value: \"#4A90E2\")\n") | |||
| 258 | 274 | ||||
| 259 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 275 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 260 | ctx := context.Background() | 276 | ctx := context.Background() | ||
| 261 | 277 | ||||
| 262 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | 278 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | ||
| @@ -269,6 +285,7 @@ func TestMigrateConfigUseCase_DetectChanges_WithRenamedKey(t *testing.T) { | |||||
| 269 | 285 | ||||
| 270 | func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | 286 | func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | ||
| 271 | mockMigrator := mocks.NewMockConfigMigrator(t) | 287 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 288 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 272 | 289 | ||||
| 273 | changes := []port.KeyChange{ | 290 | changes := []port.KeyChange{ | ||
| 274 | { | 291 | { | ||
| @@ -278,8 +295,9 @@ func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | |||||
| 278 | }, | 295 | }, | ||
| 279 | } | 296 | } | ||
| 280 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | 297 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | ||
| 298 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return("Config migration changes:\n\n - workspace.styling.pane_mode_border_width = 4 (deprecated)\n") | |||
| 281 | 299 | ||||
| 282 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 300 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 283 | ctx := context.Background() | 301 | ctx := context.Background() | ||
| 284 | 302 | ||||
| 285 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | 303 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | ||
| @@ -293,10 +311,11 @@ func TestMigrateConfigUseCase_DetectChanges_WithRemovedKey(t *testing.T) { | |||||
| 293 | 311 | ||||
| 294 | func TestMigrateConfigUseCase_DetectChanges_Error(t *testing.T) { | 312 | func TestMigrateConfigUseCase_DetectChanges_Error(t *testing.T) { | ||
| 295 | mockMigrator := mocks.NewMockConfigMigrator(t) | 313 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 314 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 296 | expectedErr := errors.New("detect changes failed") | 315 | expectedErr := errors.New("detect changes failed") | ||
| 297 | mockMigrator.EXPECT().DetectChanges().Return(nil, expectedErr) | 316 | mockMigrator.EXPECT().DetectChanges().Return(nil, expectedErr) | ||
| 298 | 317 | ||||
| 299 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 318 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) |
| 300 | ctx := context.Background() | 319 | ctx := context.Background() | ||
| 301 | 320 | ||||
| 302 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | 321 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | ||
| @@ -308,6 +327,7 @@ func TestMigrateConfigUseCase_DetectChanges_Error(t *testing.T) { | |||||
| 308 | 327 | ||||
| 309 | func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | 328 | func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | ||
| 310 | mockMigrator := mocks.NewMockConfigMigrator(t) | 329 | mockMigrator := mocks.NewMockConfigMigrator(t) | ||
| 330 | + | mockFormatter := mocks.NewMockDiffFormatter(t) | |||
| 311 | 331 | ||||
| 312 | changes := []port.KeyChange{ | 332 | changes := []port.KeyChange{ | ||
| 313 | { | 333 | { | ||
| @@ -328,8 +348,15 @@ func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | |||||
| 328 | }, | 348 | }, | ||
| 329 | } | 349 | } | ||
| 330 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | 350 | mockMigrator.EXPECT().DetectChanges().Return(changes, nil) | ||
| 331 | - | 351 | + | mockFormatter.EXPECT().FormatChangesAsDiff(changes).Return( | |
| 332 | - | uc := NewMigrateConfigUseCase(mockMigrator) | 352 | + | "Config migration changes:\n\n" + |
| 353 | + | " + workspace.styling.mode_border_width = 4\n" + | |||
| 354 | + | " ~ workspace.styling.pane_mode_border_color -> workspace.styling.pane_mode_color\n" + | |||
| 355 | + | " (value: \"#4A90E2\")\n" + | |||
| 356 | + | " - workspace.styling.pane_mode_border_width = 4 (deprecated)\n", | |||
| 357 | + | ) | |||
| 358 | + | ||||
| 359 | + | uc := NewMigrateConfigUseCase(mockMigrator, mockFormatter) | |||
| 333 | ctx := context.Background() | 360 | ctx := context.Background() | ||
| 334 | 361 | ||||
| 335 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | 362 | result, err := uc.DetectChanges(ctx, DetectChangesInput{}) | ||
| @@ -343,46 +370,3 @@ func TestMigrateConfigUseCase_DetectChanges_MultipleChanges(t *testing.T) { | |||||
| 343 | assert.Contains(t, result.DiffText, "~ workspace.styling.pane_mode_border_color") | 370 | assert.Contains(t, result.DiffText, "~ workspace.styling.pane_mode_border_color") | ||
| 344 | assert.Contains(t, result.DiffText, "- workspace.styling.pane_mode_border_width") | 371 | assert.Contains(t, result.DiffText, "- workspace.styling.pane_mode_border_width") | ||
| 345 | } | 372 | } | ||
| 346 | - | ||||
| 347 | - | func TestFormatChangesAsDiff_EmptyChanges(t *testing.T) { | |||
| 348 | - | result := formatChangesAsDiff(nil) | |||
| 349 | - | assert.Equal(t, "No changes detected.", result) | |||
| 350 | - | ||||
| 351 | - | result = formatChangesAsDiff([]port.KeyChange{}) | |||
| 352 | - | assert.Equal(t, "No changes detected.", result) | |||
| 353 | - | } | |||
| 354 | - | ||||
| 355 | - | func TestFormatChangesAsDiff_AllChangeTypes(t *testing.T) { | |||
| 356 | - | changes := []port.KeyChange{ | |||
| 357 | - | { | |||
| 358 | - | Type: port.KeyChangeAdded, | |||
| 359 | - | NewKey: "new.key", | |||
| 360 | - | NewValue: `"value"`, | |||
| 361 | - | }, | |||
| 362 | - | { | |||
| 363 | - | Type: port.KeyChangeRemoved, | |||
| 364 | - | OldKey: "old.key", | |||
| 365 | - | OldValue: `"old_value"`, | |||
| 366 | - | }, | |||
| 367 | - | { | |||
| 368 | - | Type: port.KeyChangeRenamed, | |||
| 369 | - | OldKey: "renamed.old", | |||
| 370 | - | NewKey: "renamed.new", | |||
| 371 | - | OldValue: `"renamed_value"`, | |||
| 372 | - | }, | |||
| 373 | - | { | |||
| 374 | - | Type: port.KeyChangeConsolidated, | |||
| 375 | - | OldKey: "consolidated.old", | |||
| 376 | - | NewKey: "consolidated.new", | |||
| 377 | - | }, | |||
| 378 | - | } | |||
| 379 | - | ||||
| 380 | - | result := formatChangesAsDiff(changes) | |||
| 381 | - | ||||
| 382 | - | assert.Contains(t, result, "Config migration changes:") | |||
| 383 | - | assert.Contains(t, result, `+ new.key = "value"`) | |||
| 384 | - | assert.Contains(t, result, `- old.key = "old_value" (deprecated)`) | |||
| 385 | - | assert.Contains(t, result, "~ renamed.old -> renamed.new") | |||
| 386 | - | assert.Contains(t, result, `(value: "renamed_value")`) | |||
| 387 | - | assert.Contains(t, result, "> consolidated.old -> consolidated.new") | |||
| 388 | - | } | |||
M internal/cli/cmd/config.go +4 -2
| @@ -56,7 +56,8 @@ func runConfigStatus(_ *cobra.Command, _ []string) error { | |||
| 56 | 56 | ||
| 57 | 57 | renderer := styles.NewConfigRenderer(app.Theme) | |
| 58 | 58 | migrator := config.NewMigrator() | |
| 59 | - | uc := usecase.NewMigrateConfigUseCase(migrator) | |
| 59 | + | diffFormatter := config.NewDiffFormatter() | |
| 60 | + | uc := usecase.NewMigrateConfigUseCase(migrator, diffFormatter) | |
| 60 | 61 | ||
| 61 | 62 | // Get config file path | |
| 62 | 63 | configFile, err := config.GetConfigFile() | |
| @@ -100,7 +101,8 @@ func runConfigMigrate(_ *cobra.Command, _ []string) error { | |||
| 100 | 101 | ||
| 101 | 102 | renderer := styles.NewConfigRenderer(app.Theme) | |
| 102 | 103 | migrator := config.NewMigrator() | |
| 103 | - | uc := usecase.NewMigrateConfigUseCase(migrator) | |
| 104 | + | diffFormatter := config.NewDiffFormatter() | |
| 105 | + | uc := usecase.NewMigrateConfigUseCase(migrator, diffFormatter) | |
| 104 | 106 | ||
| 105 | 107 | // Get config file path | |
| 106 | 108 | configFile, err := config.GetConfigFile() | |
| @@ -56,7 +56,8 @@ func runConfigStatus(_ *cobra.Command, _ []string) error { | |||||
| 56 | 56 | ||||
| 57 | renderer := styles.NewConfigRenderer(app.Theme) | 57 | renderer := styles.NewConfigRenderer(app.Theme) | ||
| 58 | migrator := config.NewMigrator() | 58 | migrator := config.NewMigrator() | ||
| 59 | - | uc := usecase.NewMigrateConfigUseCase(migrator) | 59 | + | diffFormatter := config.NewDiffFormatter() |
| 60 | + | uc := usecase.NewMigrateConfigUseCase(migrator, diffFormatter) | |||
| 60 | 61 | ||||
| 61 | // Get config file path | 62 | // Get config file path | ||
| 62 | configFile, err := config.GetConfigFile() | 63 | configFile, err := config.GetConfigFile() | ||
| @@ -100,7 +101,8 @@ func runConfigMigrate(_ *cobra.Command, _ []string) error { | |||||
| 100 | 101 | ||||
| 101 | renderer := styles.NewConfigRenderer(app.Theme) | 102 | renderer := styles.NewConfigRenderer(app.Theme) | ||
| 102 | migrator := config.NewMigrator() | 103 | migrator := config.NewMigrator() | ||
| 103 | - | uc := usecase.NewMigrateConfigUseCase(migrator) | 104 | + | diffFormatter := config.NewDiffFormatter() |
| 105 | + | uc := usecase.NewMigrateConfigUseCase(migrator, diffFormatter) | |||
| 104 | 106 | ||||
| 105 | // Get config file path | 107 | // Get config file path | ||
| 106 | configFile, err := config.GetConfigFile() | 108 | configFile, err := config.GetConfigFile() | ||
A internal/infrastructure/config/diff_formatter.go +40 -0
| @@ -0,0 +1,40 @@ | |||
| 1 | + | package config | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "fmt" | |
| 5 | + | "strings" | |
| 6 | + | ||
| 7 | + | "github.com/bnema/dumber/internal/application/port" | |
| 8 | + | ) | |
| 9 | + | ||
| 10 | + | // ConfigDiffFormatter implements port.DiffFormatter for formatting config changes. | |
| 11 | + | type ConfigDiffFormatter struct{} | |
| 12 | + | ||
| 13 | + | // NewDiffFormatter creates a new ConfigDiffFormatter. | |
| 14 | + | func NewDiffFormatter() *ConfigDiffFormatter { | |
| 15 | + | return &ConfigDiffFormatter{} | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | // FormatChangesAsDiff returns changes formatted as a diff for display. | |
| 19 | + | func (*ConfigDiffFormatter) FormatChangesAsDiff(changes []port.KeyChange) string { | |
| 20 | + | if len(changes) == 0 { | |
| 21 | + | return "No changes detected." | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | var sb strings.Builder | |
| 25 | + | sb.WriteString("Config migration changes:\n\n") | |
| 26 | + | ||
| 27 | + | for _, change := range changes { | |
| 28 | + | switch change.Type { | |
| 29 | + | case port.KeyChangeAdded: | |
| 30 | + | sb.WriteString(fmt.Sprintf(" + %s = %s\n", change.NewKey, change.NewValue)) | |
| 31 | + | case port.KeyChangeRemoved: | |
| 32 | + | sb.WriteString(fmt.Sprintf(" - %s = %s (deprecated)\n", change.OldKey, change.OldValue)) | |
| 33 | + | case port.KeyChangeRenamed: | |
| 34 | + | sb.WriteString(fmt.Sprintf(" ~ %s -> %s\n", change.OldKey, change.NewKey)) | |
| 35 | + | sb.WriteString(fmt.Sprintf(" (value: %s)\n", change.OldValue)) | |
| 36 | + | } | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | return sb.String() | |
| 40 | + | } | |
| @@ -0,0 +1,40 @@ | |||||
| 1 | + | package config | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "fmt" | |||
| 5 | + | "strings" | |||
| 6 | + | ||||
| 7 | + | "github.com/bnema/dumber/internal/application/port" | |||
| 8 | + | ) | |||
| 9 | + | ||||
| 10 | + | // ConfigDiffFormatter implements port.DiffFormatter for formatting config changes. | |||
| 11 | + | type ConfigDiffFormatter struct{} | |||
| 12 | + | ||||
| 13 | + | // NewDiffFormatter creates a new ConfigDiffFormatter. | |||
| 14 | + | func NewDiffFormatter() *ConfigDiffFormatter { | |||
| 15 | + | return &ConfigDiffFormatter{} | |||
| 16 | + | } | |||
| 17 | + | ||||
| 18 | + | // FormatChangesAsDiff returns changes formatted as a diff for display. | |||
| 19 | + | func (*ConfigDiffFormatter) FormatChangesAsDiff(changes []port.KeyChange) string { | |||
| 20 | + | if len(changes) == 0 { | |||
| 21 | + | return "No changes detected." | |||
| 22 | + | } | |||
| 23 | + | ||||
| 24 | + | var sb strings.Builder | |||
| 25 | + | sb.WriteString("Config migration changes:\n\n") | |||
| 26 | + | ||||
| 27 | + | for _, change := range changes { | |||
| 28 | + | switch change.Type { | |||
| 29 | + | case port.KeyChangeAdded: | |||
| 30 | + | sb.WriteString(fmt.Sprintf(" + %s = %s\n", change.NewKey, change.NewValue)) | |||
| 31 | + | case port.KeyChangeRemoved: | |||
| 32 | + | sb.WriteString(fmt.Sprintf(" - %s = %s (deprecated)\n", change.OldKey, change.OldValue)) | |||
| 33 | + | case port.KeyChangeRenamed: | |||
| 34 | + | sb.WriteString(fmt.Sprintf(" ~ %s -> %s\n", change.OldKey, change.NewKey)) | |||
| 35 | + | sb.WriteString(fmt.Sprintf(" (value: %s)\n", change.OldValue)) | |||
| 36 | + | } | |||
| 37 | + | } | |||
| 38 | + | ||||
| 39 | + | return sb.String() | |||
| 40 | + | } | |||
M internal/infrastructure/config/migrate.go +0 -26
| @@ -669,29 +669,3 @@ func (*Migrator) formatValue(value any) string { | |||
| 669 | 669 | return fmt.Sprintf("%v", v) | |
| 670 | 670 | } | |
| 671 | 671 | } | |
| 672 | - | ||
| 673 | - | // FormatChangesAsDiff returns changes formatted as a diff for display. | |
| 674 | - | func FormatChangesAsDiff(changes []port.KeyChange) string { | |
| 675 | - | if len(changes) == 0 { | |
| 676 | - | return "No changes detected." | |
| 677 | - | } | |
| 678 | - | ||
| 679 | - | var sb strings.Builder | |
| 680 | - | sb.WriteString("Config migration changes:\n\n") | |
| 681 | - | ||
| 682 | - | for _, change := range changes { | |
| 683 | - | switch change.Type { | |
| 684 | - | case port.KeyChangeAdded: | |
| 685 | - | sb.WriteString(fmt.Sprintf(" + %s = %s\n", change.NewKey, change.NewValue)) | |
| 686 | - | case port.KeyChangeRemoved: | |
| 687 | - | sb.WriteString(fmt.Sprintf(" - %s = %s (deprecated)\n", change.OldKey, change.OldValue)) | |
| 688 | - | case port.KeyChangeRenamed: | |
| 689 | - | sb.WriteString(fmt.Sprintf(" ~ %s -> %s\n", change.OldKey, change.NewKey)) | |
| 690 | - | sb.WriteString(fmt.Sprintf(" (value: %s)\n", change.OldValue)) | |
| 691 | - | case port.KeyChangeConsolidated: | |
| 692 | - | sb.WriteString(fmt.Sprintf(" > %s -> %s\n", change.OldKey, change.NewKey)) | |
| 693 | - | } | |
| 694 | - | } | |
| 695 | - | ||
| 696 | - | return sb.String() | |
| 697 | - | } | |
| @@ -669,29 +669,3 @@ func (*Migrator) formatValue(value any) string { | |||||
| 669 | return fmt.Sprintf("%v", v) | 669 | return fmt.Sprintf("%v", v) | ||
| 670 | } | 670 | } | ||
| 671 | } | 671 | } | ||
| 672 | - | ||||
| 673 | - | // FormatChangesAsDiff returns changes formatted as a diff for display. | |||
| 674 | - | func FormatChangesAsDiff(changes []port.KeyChange) string { | |||
| 675 | - | if len(changes) == 0 { | |||
| 676 | - | return "No changes detected." | |||
| 677 | - | } | |||
| 678 | - | ||||
| 679 | - | var sb strings.Builder | |||
| 680 | - | sb.WriteString("Config migration changes:\n\n") | |||
| 681 | - | ||||
| 682 | - | for _, change := range changes { | |||
| 683 | - | switch change.Type { | |||
| 684 | - | case port.KeyChangeAdded: | |||
| 685 | - | sb.WriteString(fmt.Sprintf(" + %s = %s\n", change.NewKey, change.NewValue)) | |||
| 686 | - | case port.KeyChangeRemoved: | |||
| 687 | - | sb.WriteString(fmt.Sprintf(" - %s = %s (deprecated)\n", change.OldKey, change.OldValue)) | |||
| 688 | - | case port.KeyChangeRenamed: | |||
| 689 | - | sb.WriteString(fmt.Sprintf(" ~ %s -> %s\n", change.OldKey, change.NewKey)) | |||
| 690 | - | sb.WriteString(fmt.Sprintf(" (value: %s)\n", change.OldValue)) | |||
| 691 | - | case port.KeyChangeConsolidated: | |||
| 692 | - | sb.WriteString(fmt.Sprintf(" > %s -> %s\n", change.OldKey, change.NewKey)) | |||
| 693 | - | } | |||
| 694 | - | } | |||
| 695 | - | ||||
| 696 | - | return sb.String() | |||
| 697 | - | } | |||