commit 32b4c009427c4dc2ccf5caa0464f502eb8048732 Author: Marco Kittel Date: Sun Jun 22 19:33:30 2025 +0200 Erster Commit. diff --git a/logger/go.mod b/logger/go.mod new file mode 100644 index 0000000..a50491a --- /dev/null +++ b/logger/go.mod @@ -0,0 +1,3 @@ +module gittea.marcokittel.de/elio/eliotools/logger + +go 1.24.4 diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..c98421e --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,69 @@ +package logger + +import ( + "fmt" + "runtime/debug" + "strings" + "time" +) + +type Logger interface { + Info(message string) + Infof(format string, a ...any) + Warning(message string) + Critical(message string) + Fatal(message string) +} + +type ML struct { +} + +func (m *ML) sendMsg(message string) { + // Da die CSV Dateien RFC3339 nutzen, wechsel ich darauf im Log der + // Konsistenz wegen. + msg := "# " + time.Now().Format(time.RFC3339) + "\n* " + message + fmt.Println(msg) +} + +func (m *ML) sendMsgWithStack(message string) { + msg := message + stack := string(debug.Stack()) + msg += "\n\n### *** Stack ***\n\n\n >" + indentStacktrace(stack) + msg += "\n________" + m.sendMsg(msg) +} + +func (m *ML) Info(message string) { + m.sendMsgWithStack("Info: " + message) +} + +func (m *ML) Infof(format string, a ...any) { + msg := fmt.Sprintf(format, a) + m.sendMsgWithStack("Info: " + msg) +} + +func (m *ML) Warning(message string) { + m.sendMsgWithStack("Warning: " + message) +} + +func (m *ML) Critical(message string) { + stack := string(debug.Stack()) + m.sendMsgWithStack("Critical: " + message + indentStacktrace(stack)) +} + +func (m *ML) Fatal(message string) { + m.sendMsgWithStack("Fatal" + message) + panic(message) +} +func indentStacktrace(stack string) string { + lines := strings.Split(stack, "\n") + for i := 1; i < len(lines); i++ { + lines[i] = " " + lines[i] + } + return strings.Join(lines, "\n") +} + +func NewMarcoLogger() Logger { + log := ML{} + return &log +} diff --git a/tools/go.mod b/tools/go.mod new file mode 100644 index 0000000..fc0a64e --- /dev/null +++ b/tools/go.mod @@ -0,0 +1,3 @@ +module gittea.marcokittel.de/elio/eliotools/tools + +go 1.24.4 diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..ee88122 --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,41 @@ +package main + +import ( + "errors" + "os" + "regexp" + "time" +) + +func IsFilenameValid(filename string) bool { + pattern := `^20[2-9][0-9]-(0[1-9]|1[0-2])-(0[0-9]|1[0-9]|2[0-9]|3[0-1])T(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]:[0-5][0-9])((\+00:00)|(\-00:00)|(\-0[3,9]:30)|(\-1[0-2]:00)|(-0[0-9]:00)|(\+0[0-9]:00)|(\+0[09,03,04,05,06]:30)|(\+10:30)|(\+1[0-4]:00)|(\+0[5,8]:45)|(\+12:45))-(CH|DE|EU|AT)-(stock|delivery).csv$` + re := regexp.MustCompile(pattern) + return re.MatchString(filename) +} + +func CheckDir(path string) (bool, error) { + info, err := os.Stat(path) + if err == nil { + return info.IsDir(), nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +func RFC3339StringToTime(rfc3339str string) (time.Time, error) { + const MINUS12STUNDEN = -43200 + const PLUS24STUNDEN = 50400 + t, err := time.Parse("2006-01-02T15:04:05-07:00", rfc3339str) + if err != nil { + happybirthday := time.Date(1981, time.March, 1, 4, 15, 0, 0, time.UTC) + return happybirthday, err + } + + _, offset := t.Zone() + if offset < MINUS12STUNDEN || offset > PLUS24STUNDEN { + return time.Date(1981, time.March, 1, 4, 15, 0, 0, time.UTC), errors.New("timezone offset must be between -12:00 and +14:0") + } + return t, nil +} diff --git a/tools/tools_test.go b/tools/tools_test.go new file mode 100644 index 0000000..5deb658 --- /dev/null +++ b/tools/tools_test.go @@ -0,0 +1,149 @@ +package main + +import ( + "testing" +) + +func TestHello(t *testing.T) { + testcases := []struct { + testcase string + valid bool + }{ + {testcase: "2023-11-09T15:02:17+00:00-CH-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+00:00-DE-delivery.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+00:00-EU-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+00:00-AT-stock.csv", valid: true}, + } + + //"2023-11-09T15:02:17+00:00-CH-stock.csv" + + for i, tc := range testcases { + result := IsFilenameValid(tc.testcase) + if result != tc.valid { + t.Errorf("Testcase %d is not valid, but %s must be valid!", i, tc.testcase) + } + } +} +func TestValidTimeZonesWith30(t *testing.T) { + testcases := []struct { + testcase string + valid bool + }{ + {testcase: "2023-11-09T15:02:17+03:30-EU-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+04:30-DE-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+05:30-DE-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+06:30-CH-delivery.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+09:30-CH-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+10:30-AT-stock.csv", valid: true}, + } + + for i, tc := range testcases { + result := IsFilenameValid(tc.testcase) + if result != tc.valid { + t.Errorf("Testcase %d is not valid, but %s must be valid!", i, tc.testcase) + } + } +} + +func TestValidDateTime(t *testing.T) { + testcases := []struct { + testcase string + valid bool + }{ + {testcase: "2025-11-29T23:02:17+03:30-EU-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+04:30-DE-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+05:30-DE-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+06:30-CH-delivery.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+09:30-CH-stock.csv", valid: true}, + {testcase: "2023-11-09T15:02:17+10:30-AT-delivery.csv", valid: true}, + } + + for i, tc := range testcases { + result := IsFilenameValid(tc.testcase) + if result != tc.valid { + t.Errorf("Testcase %d is not valid, but %s must be valid!", i, tc.testcase) + } + } +} + +func TestInValidTimeZonesWith30(t *testing.T) { + testcases := []struct { + testcase string + valid bool + }{ + {testcase: "2023-11-09T15:02:17+02:30-EU-stock.csv", valid: false}, + {testcase: "2023-11-09T15:02:17+01:30-DE-stock.csv", valid: false}, + {testcase: "2023-11-09T15:02:17+23:30-DE-stock.csv", valid: false}, + {testcase: "2023-11-09T15:02:17+07:30-CH-stock.csv", valid: false}, + {testcase: "2023-11-09T15:02:17+08:30-CH-stock.csv", valid: false}, + {testcase: "2023-11-09T15:02:17+12:30-AT-stock.csv", valid: false}, + } + + for i, tc := range testcases { + result := IsFilenameValid(tc.testcase) + if result != tc.valid { + t.Errorf("Testcase %d is not valid, but %s must be valid!", i, tc.testcase) + } + } +} + +func TestInValidDateTimeWith(t *testing.T) { + testcases := []struct { + testcase string + valid bool + }{ + {testcase: "2000-11-03T15:02:17+00:00-EU-stock.csv", valid: false}, + {testcase: "2026-11-03T15:60:17+00:00-EU-stock.csv", valid: false}, + {testcase: "2025-00-03T15:20:17+00:00-EU-stock.csv", valid: false}, + {testcase: "2100-01-03T23:59:17+00:00-EU-stock.csv", valid: false}, + {testcase: "2027-2-03T15:20:17+00:00-EU-stock.csv", valid: false}, + {testcase: "2023-11-09T15:02:51+00:01-AT-stock.csv", valid: false}, + } + + for i, tc := range testcases { + result := IsFilenameValid(tc.testcase) + if result != tc.valid { + t.Errorf("Testcase %d is not valid, but %s must be valid!", i, tc.testcase) + } + } +} + +func TestValidRFC3339StringToTime(t *testing.T) { + testcases := []struct { + testcase string + valid bool + }{ + {testcase: "2000-11-03T15:02:17+00:00", valid: true}, + {testcase: "2026-11-03T15:02:17+03:30", valid: true}, + {testcase: "2026-12-03T23:02:17+05:30", valid: true}, + {testcase: "2026-11-03T15:02:17-12:00", valid: true}, + {testcase: "2026-11-03T23:59:17+14:00", valid: true}, + } + + for i, tc := range testcases { + result, err := RFC3339StringToTime(tc.testcase) + if err != nil || tc.valid == false { + t.Errorf("Testcase %d is not valid, but %s must be valid!", i, result) + } + } + +} +func TestInValidRFC3339StringToTime(t *testing.T) { + testcases := []struct { + testcase string + invalid bool + }{ + {testcase: "2026-13-03T23:02:17+05:30", invalid: true}, + {testcase: "2026-00-03T23:02:17+05:30", invalid: true}, + {testcase: "2026-03-03T23:02:17+99:30", invalid: true}, + {testcase: "2026-03-03T23:02:17+99:00", invalid: true}, + {testcase: "2026-03-03T23:02:17+16:00", invalid: true}, + } + + for i, tc := range testcases { + result, err := RFC3339StringToTime(tc.testcase) + if err == nil && tc.invalid { + t.Errorf("Testcase %d is valid, but %s must be invalid!", i, result.String()) + } + } +}