package meteo_test import ( "os" "servicea/internal/domains/meteo" "testing" "time" "github.com/stretchr/testify/assert" ) func Test_CSV_ParseFile(t *testing.T) { tests := []struct { name string filePath string expectedInserted int expectedRejected int expectError bool validateInserted func(t *testing.T, inserted []meteo.MeteoData) validateRejected func(t *testing.T, rejected []meteo.RejectedMeteoData) }{ { name: "valid record", filePath: "./../../../assets/test_1.csv", expectedInserted: 1, expectedRejected: 0, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Equal(t, 1, len(inserted)) record := inserted[0] assert.Equal(t, time.Date(2025, 10, 12, 0, 0, 0, 0, time.UTC), record.Timestamp) assert.Equal(t, "Madrid", record.Location) assert.Equal(t, float32(11.55), record.MaxTemp) assert.Equal(t, float32(6.25), record.MinTemp) assert.Equal(t, float32(0), record.Rainfall) assert.Equal(t, float32(10), record.Cloudiness) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Empty(t, rejected) }, }, { name: "record with leading spaces", filePath: "./../../../assets/test_2.csv", expectedInserted: 1, expectedRejected: 0, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Equal(t, 1, len(inserted)) assert.Equal(t, "Madrid", inserted[0].Location) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Empty(t, rejected) }, }, { name: "missing city column", filePath: "./../../../assets/test_3.csv", expectedInserted: 0, expectedRejected: 1, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Empty(t, inserted) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Equal(t, 1, len(rejected)) assert.Contains(t, rejected[0].Reason, "missing or invalid city field") assert.Equal(t, "2025/10/12;11,55;6,25;0;10", rejected[0].RowValue) }, }, { name: "empty file with only header", filePath: "./../../../assets/test_4.csv", expectedInserted: 0, expectedRejected: 0, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Empty(t, inserted) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Empty(t, rejected) }, }, { name: "missing max temp field value", filePath: "./../../../assets/test_5.csv", expectedInserted: 0, expectedRejected: 1, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Empty(t, inserted) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Equal(t, 1, len(rejected)) assert.Contains(t, rejected[0].Reason, "missing or invalid max temp field") assert.Equal(t, "2025/10/12;Madrid;;6,25;0;10", rejected[0].RowValue) }, }, { name: "missing city field value", filePath: "./../../../assets/test_6.csv", expectedInserted: 0, expectedRejected: 1, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Empty(t, inserted) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Equal(t, 1, len(rejected)) assert.Contains(t, rejected[0].Reason, "missing or invalid city field") assert.Equal(t, "2025/10/12;;11,55;6,25;0;10", rejected[0].RowValue) }, }, { name: "missing date field value", filePath: "./../../../assets/test_7.csv", expectedInserted: 0, expectedRejected: 1, expectError: false, validateInserted: func(t *testing.T, inserted []meteo.MeteoData) { assert.Empty(t, inserted) }, validateRejected: func(t *testing.T, rejected []meteo.RejectedMeteoData) { assert.Equal(t, 1, len(rejected)) assert.Contains(t, rejected[0].Reason, "missing or invalid date field") assert.Equal(t, ";Madrid;11,55;6,25;0;10", rejected[0].RowValue) }, }, { name: "invalid separator comma instead of semicolon", filePath: "./../../../assets/test_8.csv", expectedInserted: 0, expectedRejected: 0, expectError: true, validateInserted: nil, validateRejected: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { file, err := os.Open(tt.filePath) assert.NoError(t, err) defer file.Close() csvIngest := &meteo.CSV{} inserted, rejected, err := csvIngest.Parse(file) if tt.expectError { assert.Error(t, err) assert.ErrorIs(t, err, meteo.ErrCannotParseFile) return } assert.NoError(t, err) if tt.validateInserted != nil { tt.validateInserted(t, inserted) } if tt.validateRejected != nil { tt.validateRejected(t, rejected) } }) } }