diff --git a/garmin_session.json b/garmin_session.json index fe58f47..5b1c824 100644 --- a/garmin_session.json +++ b/garmin_session.json @@ -1,5 +1,5 @@ { "domain": "garmin.com", "username": "fbleagh", - "auth_token": "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpLW9hdXRoLXNpZ25lci1wcm9kLTIwMjQtcTEifQ.eyJzY29wZSI6WyJBVFBfUkVBRCIsIkFUUF9XUklURSIsIkNPTU1VTklUWV9DT1VSU0VfUkVBRCIsIkNPTU1VTklUWV9DT1VSU0VfV1JJVEUiLCJDT05ORUNUX01DVF9EQUlMWV9MT0dfUkVBRCIsIkNPTk5FQ1RfUkVBRCIsIkNPTk5FQ1RfV1JJVEUiLCJESVZFX0FQSV9SRUFEIiwiRElfT0FVVEhfMl9BVVRIT1JJWkFUSU9OX0NPREVfQ1JFQVRFIiwiRFRfQ0xJRU5UX0FOQUxZVElDU19XUklURSIsIkdBUk1JTlBBWV9SRUFEIiwiR0FSTUlOUEFZX1dSSVRFIiwiR0NPRkZFUl9SRUFEIiwiR0NPRkZFUl9XUklURSIsIkdIU19TQU1EIiwiR0hTX1VQTE9BRCIsIkdPTEZfQVBJX1JFQUQiLCJHT0xGX0FQSV9XUklURSIsIklOU0lHSFRTX1JFQUQiLCJJTlNJR0hUU19XUklURSIsIk9NVF9DQU1QQUlHTl9SRUFEIiwiT01UX1NVQlNDUklQVElPTl9SRUFEIiwiUFJPRFVDVF9TRUFSQ0hfUkVBRCJdLCJpc3MiOiJodHRwczovL2RpYXV0aC5nYXJtaW4uY29tIiwicmV2b2NhdGlvbl9lbGlnaWJpbGl0eSI6WyJHTE9CQUxfU0lHTk9VVCIsIk1BTkFHRURfU1RBVFVTIl0sImNsaWVudF90eXBlIjoiVU5ERUZJTkVEIiwiZXhwIjoxNzU3MzYyMzI3LCJpYXQiOjE3NTcyNzI0NDEsImdhcm1pbl9ndWlkIjoiNTZlZTk1ZmMtMzY0MC00NGU2LTg1ODAtNDc4NDEwZDQwZGFhIiwianRpIjoiZjVmYzFhMzAtZGVkZi00N2FmLTg5YjgtM2QwNjFjZjkxMTMxIiwiY2xpZW50X2lkIjoiR0FSTUlOX0NPTk5FQ1RfTU9CSUxFX0FORFJPSURfREkifQ.cdgNSDtkYnySkPdHTHxvck3BZXVZ0H6mGcqU0fJqqRO5cuh0_exgGM_VBLxoos_MqEYeryZqkw__UfwA1dvamoClooPpUFZIcPmsTl_uSILd8IIiWFjhgXJnTybE3mI_hPEaILzWnVDzQX4lv1K_oTzCVx0I7moonRAk3mbccKpj_kWcIm-CFVbuGbApTCJzRoOr46yFPUnbOxeA0eJl8BbPFmPWK0z_FvcLS8q7ZKuksBWW2gorQovqesIG63k-wK1PFOvm2EDosSFW0RTCFY7cBMx3nz_f7jFG9E5qt971z8EcKCq83pWs2CHIqy64KkVoub3CD0LQRKIjilNsEA" + "auth_token": "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpLW9hdXRoLXNpZ25lci1wcm9kLTIwMjQtcTEifQ.eyJzY29wZSI6WyJBVFBfUkVBRCIsIkFUUF9XUklURSIsIkNPTU1VTklUWV9DT1VSU0VfUkVBRCIsIkNPTU1VTklUWV9DT1VSU0VfV1JJVEUiLCJDT05ORUNUX01DVF9EQUlMWV9MT0dfUkVBRCIsIkNPTk5FQ1RfUkVBRCIsIkNPTk5FQ1RfV1JJVEUiLCJESVZFX0FQSV9SRUFEIiwiRElfT0FVVEhfMl9BVVRIT1JJWkFUSU9OX0NPREVfQ1JFQVRFIiwiRFRfQ0xJRU5UX0FOQUxZVElDU19XUklURSIsIkdBUk1JTlBBWV9SRUFEIiwiR0FSTUlOUEFZX1dSSVRFIiwiR0NPRkZFUl9SRUFEIiwiR0NPRkZFUl9XUklURSIsIkdIU19TQU1EIiwiR0hTX1VQTE9BRCIsIkdPTEZfQVBJX1JFQUQiLCJHT0xGX0FQSV9XUklURSIsIklOU0lHSFRTX1JFQUQiLCJJTlNJR0hUU19XUklURSIsIk9NVF9DQU1QQUlHTl9SRUFEIiwiT01UX1NVQlNDUklQVElPTl9SRUFEIiwiUFJPRFVDVF9TRUFSQ0hfUkVBRCJdLCJpc3MiOiJodHRwczovL2RpYXV0aC5nYXJtaW4uY29tIiwicmV2b2NhdGlvbl9lbGlnaWJpbGl0eSI6WyJHTE9CQUxfU0lHTk9VVCIsIk1BTkFHRURfU1RBVFVTIl0sImNsaWVudF90eXBlIjoiVU5ERUZJTkVEIiwiZXhwIjoxNzU3MzgwNTAyLCJpYXQiOjE3NTcyNzcwMjAsImdhcm1pbl9ndWlkIjoiNTZlZTk1ZmMtMzY0MC00NGU2LTg1ODAtNDc4NDEwZDQwZGFhIiwianRpIjoiZWVkMmQ2NTYtYWM0MC00NDdhLTkwYzEtOWMwMmQzNTM3MzZiIiwiY2xpZW50X2lkIjoiR0FSTUlOX0NPTk5FQ1RfTU9CSUxFX0FORFJPSURfREkifQ.HwBbJysBlmSHtPLPtZ1SITqa6jZ8SFBuej7j--iYblHqgKwM7preEM03FgVJUusQi9SarB_lID-pjNdJ6MRGnYo3NSzO4wnmalmnoAxn-9pvAYHKznCIq5x4exC-2SlvW4paNK_-UzOd9mp23FNCvXcLGOc_lJlFuC20YAQID9x3ujIGm3PBWp6ycWIRydyvnNZga-a2opaZPjvC1TXKycNsUY1qZSc4hj3D7_wFrMtYuu2HuGQFeyNRNInA6Ir-J3i_OBFl-L4tM3CvpJAGUU7VEY257x8M6YvHL7xER0tv3FjTdqwLAkSMkBP9qH1mq7zPrVp6JEIqghI-EQVwsA" } \ No newline at end of file diff --git a/garmin_session.jsonold b/garmin_session.jsonold index 01b8645..fe58f47 100644 --- a/garmin_session.jsonold +++ b/garmin_session.jsonold @@ -1,5 +1,5 @@ { "domain": "garmin.com", "username": "fbleagh", - "auth_token": "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpLW9hdXRoLXNpZ25lci1wcm9kLTIwMjQtcTEifQ.eyJzY29wZSI6WyJBVFBfUkVBRCIsIkFUUF9XUklURSIsIkNPTU1VTklUWV9DT1VSU0VfUkVBRCIsIkNPTU1VTklUWV9DT1VSU0VfV1JJVEUiLCJDT05ORUNUX01DVF9EQUlMWV9MT0dfUkVBRCIsIkNPTk5FQ1RfUkVBRCIsIkNPTk5FQ1RfV1JJVEUiLCJESVZFX0FQSV9SRUFEIiwiRElfT0FVVEhfMl9BVVRIT1JJWkFUSU9OX0NPREVfQ1JFQVRFIiwiRFRfQ0xJRU5UX0FOQUxZVElDU19XUklURSIsIkdBUk1JTlBBWV9SRUFEIiwiR0FSTUlOUEFZX1dSSVRFIiwiR0NPRkZFUl9SRUFEIiwiR0NPRkZFUl9XUklURSIsIkdIU19TQU1EIiwiR0hTX1VQTE9BRCIsIkdPTEZfQVBJX1JFQUQiLCJHT0xGX0FQSV9XUklURSIsIklOU0lHSFRTX1JFQUQiLCJJTlNJR0hUU19XUklURSIsIk9NVF9DQU1QQUlHTl9SRUFEIiwiT01UX1NVQlNDUklQVElPTl9SRUFEIiwiUFJPRFVDVF9TRUFSQ0hfUkVBRCJdLCJpc3MiOiJodHRwczovL2RpYXV0aC5nYXJtaW4uY29tIiwicmV2b2NhdGlvbl9lbGlnaWJpbGl0eSI6WyJHTE9CQUxfU0lHTk9VVCIsIk1BTkFHRURfU1RBVFVTIl0sImNsaWVudF90eXBlIjoiVU5ERUZJTkVEIiwiZXhwIjoxNzU3MzMxMzUyLCJpYXQiOjE3NTcyNTg4NjUsImdhcm1pbl9ndWlkIjoiNTZlZTk1ZmMtMzY0MC00NGU2LTg1ODAtNDc4NDEwZDQwZGFhIiwianRpIjoiYTExYThkOGUtZTk3NS00ZmYzLWI5ZGUtMTgxNDRlZmI3NDIwIiwiY2xpZW50X2lkIjoiR0FSTUlOX0NPTk5FQ1RfTU9CSUxFX0FORFJPSURfREkifQ.aHN1exAr4j-_rjZ06OS9D7o4CpDYR1l09geAK6jh-NmJl4dsy3vWM1sv6c-9yiIO8FmuKhvBA44yKAhFCWOTNIJ3yUG-t8IFbYRMrPxBW4WZ4zqMN8XgVPI9Z_iLR0cEP6AaaAtzpVMWcwHn8wLhDUrpLMeCz7n8jMU0S-caXkByCa4zF1PhVs69hYH89Yn48lA_bFiJtbgx0aINnuu-0JHCj22NRjBTKPGBDcQg2fNapCrHoqZ1y-5BOfyB96u6VFXZZ6JNd-ar1EaVOw4G7zUhQCCDeilqjwQB68yIvbWoOhAyda93yB-_AcBU3wHrGHUaYqULEPSRex8zPxYH7A" + "auth_token": "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpLW9hdXRoLXNpZ25lci1wcm9kLTIwMjQtcTEifQ.eyJzY29wZSI6WyJBVFBfUkVBRCIsIkFUUF9XUklURSIsIkNPTU1VTklUWV9DT1VSU0VfUkVBRCIsIkNPTU1VTklUWV9DT1VSU0VfV1JJVEUiLCJDT05ORUNUX01DVF9EQUlMWV9MT0dfUkVBRCIsIkNPTk5FQ1RfUkVBRCIsIkNPTk5FQ1RfV1JJVEUiLCJESVZFX0FQSV9SRUFEIiwiRElfT0FVVEhfMl9BVVRIT1JJWkFUSU9OX0NPREVfQ1JFQVRFIiwiRFRfQ0xJRU5UX0FOQUxZVElDU19XUklURSIsIkdBUk1JTlBBWV9SRUFEIiwiR0FSTUlOUEFZX1dSSVRFIiwiR0NPRkZFUl9SRUFEIiwiR0NPRkZFUl9XUklURSIsIkdIU19TQU1EIiwiR0hTX1VQTE9BRCIsIkdPTEZfQVBJX1JFQUQiLCJHT0xGX0FQSV9XUklURSIsIklOU0lHSFRTX1JFQUQiLCJJTlNJR0hUU19XUklURSIsIk9NVF9DQU1QQUlHTl9SRUFEIiwiT01UX1NVQlNDUklQVElPTl9SRUFEIiwiUFJPRFVDVF9TRUFSQ0hfUkVBRCJdLCJpc3MiOiJodHRwczovL2RpYXV0aC5nYXJtaW4uY29tIiwicmV2b2NhdGlvbl9lbGlnaWJpbGl0eSI6WyJHTE9CQUxfU0lHTk9VVCIsIk1BTkFHRURfU1RBVFVTIl0sImNsaWVudF90eXBlIjoiVU5ERUZJTkVEIiwiZXhwIjoxNzU3MzYyMzI3LCJpYXQiOjE3NTcyNzI0NDEsImdhcm1pbl9ndWlkIjoiNTZlZTk1ZmMtMzY0MC00NGU2LTg1ODAtNDc4NDEwZDQwZGFhIiwianRpIjoiZjVmYzFhMzAtZGVkZi00N2FmLTg5YjgtM2QwNjFjZjkxMTMxIiwiY2xpZW50X2lkIjoiR0FSTUlOX0NPTk5FQ1RfTU9CSUxFX0FORFJPSURfREkifQ.cdgNSDtkYnySkPdHTHxvck3BZXVZ0H6mGcqU0fJqqRO5cuh0_exgGM_VBLxoos_MqEYeryZqkw__UfwA1dvamoClooPpUFZIcPmsTl_uSILd8IIiWFjhgXJnTybE3mI_hPEaILzWnVDzQX4lv1K_oTzCVx0I7moonRAk3mbccKpj_kWcIm-CFVbuGbApTCJzRoOr46yFPUnbOxeA0eJl8BbPFmPWK0z_FvcLS8q7ZKuksBWW2gorQovqesIG63k-wK1PFOvm2EDosSFW0RTCFY7cBMx3nz_f7jFG9E5qt971z8EcKCq83pWs2CHIqy64KkVoub3CD0LQRKIjilNsEA" } \ No newline at end of file diff --git a/garth/data/base.go b/garth/data/base.go index 63882b2..e1d5e0d 100644 --- a/garth/data/base.go +++ b/garth/data/base.go @@ -67,8 +67,8 @@ func (b *BaseData) Get(day time.Time, c *client.Client) (interface{}, error) { // Returns: // // []interface{}: Slice of results (order matches date range) -// error: First error encountered during processing, if any -func (b *BaseData) List(end time.Time, days int, c *client.Client, maxWorkers int) ([]interface{}, error) { +// []error: Slice of errors encountered during processing +func (b *BaseData) List(end time.Time, days int, c *client.Client, maxWorkers int) ([]interface{}, []error) { if maxWorkers < 1 { maxWorkers = 1 } @@ -82,8 +82,7 @@ func (b *BaseData) List(end time.Time, days int, c *client.Client, maxWorkers in var wg sync.WaitGroup workCh := make(chan time.Time, days) resultsCh := make(chan interface{}, days) - errCh := make(chan error, 1) - done := make(chan bool) + errCh := make(chan error, days) // Worker function worker := func() { @@ -91,11 +90,8 @@ func (b *BaseData) List(end time.Time, days int, c *client.Client, maxWorkers in for date := range workCh { result, err := b.Get(date, c) if err != nil { - select { - case errCh <- err: - default: - } - return + errCh <- err + continue } resultsCh <- result } @@ -115,28 +111,34 @@ func (b *BaseData) List(end time.Time, days int, c *client.Client, maxWorkers in close(workCh) }() - // Close results channel when all workers finish + // Close channels when all workers finish go func() { wg.Wait() close(resultsCh) - done <- true + close(errCh) }() - // Collect results + // Collect results and errors var results []interface{} - var err error + var errs []error -collect: - for { + // Collect results until both channels are closed + for resultsCh != nil || errCh != nil { select { - case result := <-resultsCh: + case result, ok := <-resultsCh: + if !ok { + resultsCh = nil + continue + } results = append(results, result) - case err = <-errCh: - break collect - case <-done: - break collect + case err, ok := <-errCh: + if !ok { + errCh = nil + continue + } + errs = append(errs, err) } } - return results, err + return results, errs } diff --git a/garth/data/base_test.go b/garth/data/base_test.go index 53d8bd1..fb865f9 100644 --- a/garth/data/base_test.go +++ b/garth/data/base_test.go @@ -39,10 +39,10 @@ func TestBaseData_List(t *testing.T) { maxWorkers := 3 // Execute - results, err := mockData.List(end, days, c, maxWorkers) + results, errs := mockData.List(end, days, c, maxWorkers) // Verify - assert.NoError(t, err) + assert.Empty(t, errs) assert.Len(t, results, days) assert.Contains(t, results, "data for 2023-06-15") assert.Contains(t, results, "data for 2023-06-11") @@ -65,10 +65,10 @@ func TestBaseData_List_ErrorHandling(t *testing.T) { maxWorkers := 2 // Execute - results, err := mockData.List(end, days, c, maxWorkers) + results, errs := mockData.List(end, days, c, maxWorkers) // Verify - assert.Error(t, err) - assert.Equal(t, "bad luck day", err.Error()) - assert.Len(t, results, 4) // Should have some results before error + assert.Len(t, errs, 1) + assert.Equal(t, "bad luck day", errs[0].Error()) + assert.Len(t, results, 4) // Should have results for non-error days } diff --git a/garth/data/body_battery.go b/garth/data/body_battery.go new file mode 100644 index 0000000..9ece557 --- /dev/null +++ b/garth/data/body_battery.go @@ -0,0 +1,120 @@ +package data + +import ( + "sort" + "time" + + "garmin-connect/garth/client" +) + +// DailyBodyBatteryStress represents complete daily Body Battery and stress data +type DailyBodyBatteryStress struct { + UserProfilePK int `json:"userProfilePk"` + CalendarDate time.Time `json:"calendarDate"` + StartTimestampGMT time.Time `json:"startTimestampGmt"` + EndTimestampGMT time.Time `json:"endTimestampGmt"` + StartTimestampLocal time.Time `json:"startTimestampLocal"` + EndTimestampLocal time.Time `json:"endTimestampLocal"` + MaxStressLevel int `json:"maxStressLevel"` + AvgStressLevel int `json:"avgStressLevel"` + StressChartValueOffset int `json:"stressChartValueOffset"` + StressChartYAxisOrigin int `json:"stressChartYAxisOrigin"` + StressValuesArray [][]int `json:"stressValuesArray"` + BodyBatteryValuesArray [][]any `json:"bodyBatteryValuesArray"` +} + +// BodyBatteryEvent represents a Body Battery impact event +type BodyBatteryEvent struct { + EventType string `json:"eventType"` + EventStartTimeGMT time.Time `json:"eventStartTimeGmt"` + TimezoneOffset int `json:"timezoneOffset"` + DurationInMilliseconds int `json:"durationInMilliseconds"` + BodyBatteryImpact int `json:"bodyBatteryImpact"` + FeedbackType string `json:"feedbackType"` + ShortFeedback string `json:"shortFeedback"` +} + +// BodyBatteryData represents legacy Body Battery events data +type BodyBatteryData struct { + Event *BodyBatteryEvent `json:"event"` + ActivityName string `json:"activityName"` + ActivityType string `json:"activityType"` + ActivityID string `json:"activityId"` + AverageStress float64 `json:"averageStress"` + StressValuesArray [][]int `json:"stressValuesArray"` + BodyBatteryValuesArray [][]any `json:"bodyBatteryValuesArray"` +} + +// BodyBatteryReading represents an individual Body Battery reading +type BodyBatteryReading struct { + Timestamp int `json:"timestamp"` + Status string `json:"status"` + Level int `json:"level"` + Version float64 `json:"version"` +} + +// StressReading represents an individual stress reading +type StressReading struct { + Timestamp int `json:"timestamp"` + StressLevel int `json:"stressLevel"` +} + +// ParseBodyBatteryReadings converts body battery values array to structured readings +func ParseBodyBatteryReadings(valuesArray [][]any) []BodyBatteryReading { + readings := make([]BodyBatteryReading, 0) + for _, values := range valuesArray { + if len(values) < 4 { + continue + } + + timestamp, ok1 := values[0].(int) + status, ok2 := values[1].(string) + level, ok3 := values[2].(int) + version, ok4 := values[3].(float64) + + if !ok1 || !ok2 || !ok3 || !ok4 { + continue + } + + readings = append(readings, BodyBatteryReading{ + Timestamp: timestamp, + Status: status, + Level: level, + Version: version, + }) + } + sort.Slice(readings, func(i, j int) bool { + return readings[i].Timestamp < readings[j].Timestamp + }) + return readings +} + +// ParseStressReadings converts stress values array to structured readings +func ParseStressReadings(valuesArray [][]int) []StressReading { + readings := make([]StressReading, 0) + for _, values := range valuesArray { + if len(values) != 2 { + continue + } + readings = append(readings, StressReading{ + Timestamp: values[0], + StressLevel: values[1], + }) + } + sort.Slice(readings, func(i, j int) bool { + return readings[i].Timestamp < readings[j].Timestamp + }) + return readings +} + +// Get implements the Data interface for DailyBodyBatteryStress +func (d *DailyBodyBatteryStress) Get(day time.Time, client *client.Client) (any, error) { + // Implementation to be added + return nil, nil +} + +// List implements the Data interface for concurrent fetching +func (d *DailyBodyBatteryStress) List(end time.Time, days int, client *client.Client, maxWorkers int) ([]any, error) { + // Implementation to be added + return []any{}, nil +} diff --git a/garth/data/body_battery_test.go b/garth/data/body_battery_test.go new file mode 100644 index 0000000..40147ea --- /dev/null +++ b/garth/data/body_battery_test.go @@ -0,0 +1,122 @@ +package data + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestParseBodyBatteryReadings(t *testing.T) { + tests := []struct { + name string + input [][]any + expected []BodyBatteryReading + }{ + { + name: "valid readings", + input: [][]any{ + {1000, "ACTIVE", 75, 1.0}, + {2000, "ACTIVE", 70, 1.0}, + {3000, "REST", 65, 1.0}, + }, + expected: []BodyBatteryReading{ + {1000, "ACTIVE", 75, 1.0}, + {2000, "ACTIVE", 70, 1.0}, + {3000, "REST", 65, 1.0}, + }, + }, + { + name: "invalid readings", + input: [][]any{ + {1000, "ACTIVE", 75}, // missing version + {2000, "ACTIVE"}, // missing level and version + {3000}, // only timestamp + {"invalid", "ACTIVE", 75, 1.0}, // wrong timestamp type + }, + expected: []BodyBatteryReading{}, + }, + { + name: "empty input", + input: [][]any{}, + expected: []BodyBatteryReading{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ParseBodyBatteryReadings(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestParseStressReadings(t *testing.T) { + tests := []struct { + name string + input [][]int + expected []StressReading + }{ + { + name: "valid readings", + input: [][]int{ + {1000, 25}, + {2000, 30}, + {3000, 20}, + }, + expected: []StressReading{ + {1000, 25}, + {2000, 30}, + {3000, 20}, + }, + }, + { + name: "invalid readings", + input: [][]int{ + {1000}, // missing stress level + {2000, 30, 1}, // extra value + {}, // empty + }, + expected: []StressReading{}, + }, + { + name: "empty input", + input: [][]int{}, + expected: []StressReading{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ParseStressReadings(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestDailyBodyBatteryStress(t *testing.T) { + now := time.Now() + d := DailyBodyBatteryStress{ + CalendarDate: now, + BodyBatteryValuesArray: [][]any{ + {1000, "ACTIVE", 75, 1.0}, + {2000, "ACTIVE", 70, 1.0}, + }, + StressValuesArray: [][]int{ + {1000, 25}, + {2000, 30}, + }, + } + + t.Run("body battery readings", func(t *testing.T) { + readings := ParseBodyBatteryReadings(d.BodyBatteryValuesArray) + assert.Len(t, readings, 2) + assert.Equal(t, 75, readings[0].Level) + }) + + t.Run("stress readings", func(t *testing.T) { + readings := ParseStressReadings(d.StressValuesArray) + assert.Len(t, readings, 2) + assert.Equal(t, 25, readings[0].StressLevel) + }) +} diff --git a/go.mod b/go.mod index f3ba4e4..7803f9e 100644 --- a/go.mod +++ b/go.mod @@ -4,4 +4,9 @@ go 1.24.2 require github.com/joho/godotenv v1.5.1 -require github.com/stretchr/testify v1.11.1 // indirect +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.11.1 + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 80696c2..ae38d6f 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=