meteologica/service_a/internal/domains/meteo/file_test.go

160 lines
4.9 KiB
Go

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, int(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 location")
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")
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 location")
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")
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)
}
})
}
}