From 049f287622936672b08985cbfc6f8fc6824fe077 Mon Sep 17 00:00:00 2001 From: Volker Schukai <volker.schukai@schukai.com> Date: Tue, 15 Aug 2023 22:59:30 +0200 Subject: [PATCH] fix: parse path values #2 #7 --- import.go | 91 ++++++++++++++++++++++++++++++++----------------- issue-7_test.go | 68 +++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 32 deletions(-) diff --git a/import.go b/import.go index 6234a0b..12bd306 100644 --- a/import.go +++ b/import.go @@ -94,8 +94,8 @@ func (s *Settings[C]) importStreams() { } } -//// replacePath replaces all pathInterface fields in the struct with the given path -//func replacePath(p string, c any) { +// // replacePath replaces all pathInterface fields in the struct with the given path +// func replacePath(p string, c any) { // // if reflect.TypeOf(c).Kind() != reflect.Ptr { // panic("c must be a pointer") @@ -152,21 +152,28 @@ func (s *Settings[C]) importStreams() { // // } // -//} - +// } func replacePath(p string, c interface{}) { cValue := reflect.ValueOf(c) - cType := cValue.Type() - if cType.Kind() != reflect.Ptr { - panic("c must be a pointer") + // If c is of type PathValue (which implements pathInterface), modify the path + if cValue.Type().ConvertibleTo(reflect.TypeOf(PathValue(""))) { + pathVal := cValue.Convert(reflect.TypeOf(PathValue(""))).Interface().(PathValue) + if !path.IsAbs(pathVal.String()) { + newPath := PathValue(path.Join(p, pathVal.String())) + if cValue.CanSet() { + cValue.Set(reflect.ValueOf(newPath)) + } + } + return } - if cType.Elem().Kind() != reflect.Struct { - panic("c must be a pointer to a struct") + // If c is not a struct, simply return + if cValue.Kind() != reflect.Ptr || cValue.Elem().Kind() != reflect.Struct { + return } - fields := reflect.VisibleFields(cType.Elem()) + fields := reflect.VisibleFields(cValue.Elem().Type()) for _, field := range fields { r := cValue.Elem().FieldByName(field.Name) handleField(p, r) @@ -179,12 +186,34 @@ func handleField(p string, r reflect.Value) { if r.CanAddr() { replacePath(p, r.Addr().Interface()) } - case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface: - forEachElem(r, func(e reflect.Value) { - if e.CanAddr() { - replacePath(p, e.Addr().Interface()) + case reflect.Slice: + for i := 0; i < r.Len(); i++ { + elem := r.Index(i) + if elem.Type().ConvertibleTo(reflect.TypeOf(PathValue(""))) { + pathVal := elem.Convert(reflect.TypeOf(PathValue(""))).Interface().(PathValue) + if !path.IsAbs(pathVal.String()) { + newPath := PathValue(path.Join(p, pathVal.String())) + if elem.CanSet() { + elem.Set(reflect.ValueOf(newPath)) + } + } + } else if elem.CanAddr() { + replacePath(p, elem.Addr().Interface()) } - }) + } + case reflect.Map: + for _, k := range r.MapKeys() { + elem := r.MapIndex(k) + if elem.Type().ConvertibleTo(reflect.TypeOf(PathValue(""))) { + pathVal := elem.Convert(reflect.TypeOf(PathValue(""))).Interface().(PathValue) + if !path.IsAbs(pathVal.String()) { + newPath := PathValue(path.Join(p, pathVal.String())) + r.SetMapIndex(k, reflect.ValueOf(newPath)) + } + } else if elem.CanAddr() { + replacePath(p, elem.Addr().Interface()) + } + } default: // Check for pathInterface if v, ok := r.Interface().(pathInterface); ok { @@ -196,22 +225,22 @@ func handleField(p string, r reflect.Value) { } } -func forEachElem(r reflect.Value, fn func(e reflect.Value)) { - switch r.Kind() { - case reflect.Slice: - for i := 0; i < r.Len(); i++ { - fn(r.Index(i)) - } - case reflect.Map: - for _, k := range r.MapKeys() { - fn(r.MapIndex(k)) - } - case reflect.Ptr, reflect.Interface: - if !r.IsNil() { - fn(r.Elem()) - } - } -} +//func forEachElem(r reflect.Value, fn func(e reflect.Value)) { +// switch r.Kind() { +// case reflect.Slice: +// for i := 0; i < r.Len(); i++ { +// fn(r.Index(i)) +// } +// case reflect.Map: +// for _, k := range r.MapKeys() { +// fn(r.MapIndex(k)) +// } +// case reflect.Ptr, reflect.Interface: +// if !r.IsNil() { +// fn(r.Elem()) +// } +// } +//} func (s *Settings[C]) importFiles() { diff --git a/issue-7_test.go b/issue-7_test.go index 887e714..781f678 100644 --- a/issue-7_test.go +++ b/issue-7_test.go @@ -14,6 +14,7 @@ import ( type Issue7Routing struct { P PathValue `json:"p" yaml:"p"` + X string `json:"x" yaml:"x"` } type Issue7Server struct { @@ -49,7 +50,8 @@ func TestPathRewrite(t *testing.T) { "server": { "routing": [ { - "p": "./test" + "p": "./test", + "x": "testX" } ] } @@ -69,5 +71,69 @@ func TestPathRewrite(t *testing.T) { expected := path.Join(filepath.Dir(n), "test") assert.Equal(t, expected, c.Config().Server.Routing[0].P.String()) + assert.Equal(t, "testX", c.Config().Server.Routing[0].X) } + +// Test data structs +type Issue7TestStruct1 struct { + A PathValue + B string + C int +} + +type Issue7TestStruct2 struct { + A PathValue + B Issue7TestStruct1 + C []PathValue + D map[string]PathValue +} + +func TestIssue7ReplacePath(t *testing.T) { + basePath := "/basepath" + + // Test case 1 + ts1 := Issue7TestStruct1{ + A: "relative/path", + B: "justastring", + C: 42, + } + + replacePath(basePath, &ts1) + + if ts1.A != PathValue(path.Join(basePath, "relative/path")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "relative/path"), ts1.A) + } + + // Test case 2 + ts2 := Issue7TestStruct2{ + A: "another/relative/path", + B: ts1, + C: []PathValue{"rel1", "rel2"}, + D: map[string]PathValue{ + "key1": "relkey1", + "key2": "relkey2", + }, + } + + replacePath(basePath, &ts2) + + if ts2.A != PathValue(path.Join(basePath, "another/relative/path")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "another/relative/path"), ts2.A) + } + if ts2.B.A != PathValue(path.Join(basePath, "relative/path")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "relative/path"), ts2.B.A) + } + if ts2.C[0] != PathValue(path.Join(basePath, "rel1")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "rel1"), ts2.C[0]) + } + if ts2.C[1] != PathValue(path.Join(basePath, "rel2")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "rel2"), ts2.C[1]) + } + if ts2.D["key1"] != PathValue(path.Join(basePath, "relkey1")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "relkey1"), ts2.D["key1"]) + } + if ts2.D["key2"] != PathValue(path.Join(basePath, "relkey2")) { + t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "relkey2"), ts2.D["key2"]) + } +} -- GitLab