From bb4b330fa0a3175cef110a3f1d30be9a0cdddd1b Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Fri, 22 Jul 2022 18:09:16 +0900 Subject: [PATCH 01/13] WIP support HCL encoding/decoding From a683b6f666b758848c2205548d051420e8b5ec64 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Fri, 22 Jul 2022 18:09:16 +0900 Subject: [PATCH 02/13] WIP support HCL encoding/decoding From 2c4e5cbaa28f25f93801114dc150a3eeec92711b Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Wed, 27 Jul 2022 01:58:27 +0900 Subject: [PATCH 03/13] bump up to 0.10.0 --- version.go | 2 +- version_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/version.go b/version.go index a82109a7..cac46c43 100644 --- a/version.go +++ b/version.go @@ -1,4 +1,4 @@ package structil // VERSION says my version number -const VERSION = "0.9.1" +const VERSION = "0.10.0" diff --git a/version_test.go b/version_test.go index 9e3b287f..3dbfb1ae 100644 --- a/version_test.go +++ b/version_test.go @@ -7,7 +7,7 @@ import ( ) func TestVersion(t *testing.T) { - exp := "0.9.1" + exp := "0.10.0" if VERSION != exp { t.Errorf("expected: %#v, but actual: %#v", exp, VERSION) From 6bbaf82bacdbddad319cfcaa85b9243195d20de0 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sun, 31 Jul 2022 11:12:19 +0900 Subject: [PATCH 04/13] WIP hcl --- cmd/strucmd/main.go | 24 ++++++- dynamicstruct/decoder/data_type.go | 20 ++---- dynamicstruct/decoder/decoder.go | 5 ++ dynamicstruct/decoder/decoder_test.go | 96 ++++++++++++++++++++++++++- go.mod | 5 ++ go.sum | 16 +++++ 6 files changed, 151 insertions(+), 15 deletions(-) diff --git a/cmd/strucmd/main.go b/cmd/strucmd/main.go index aa46a6d5..494a1d9d 100644 --- a/cmd/strucmd/main.go +++ b/cmd/strucmd/main.go @@ -2,8 +2,30 @@ package main import ( "fmt" + "log" + + "github.com/hashicorp/hcl/v2/hclsimple" ) func main() { - fmt.Println("NOT IMPLEMENTED YET") + const exampleConfig = ` +foo = "bar" +baz = "boop" +` + // type Config struct { + // Foo string `hcl:"foo"` + // Baz string `hcl:"baz"` + // } + // var config Config + + // var intf interface{} // PANIC + + var m map[string]interface{} + err := hclsimple.Decode("example.hcl", []byte(exampleConfig), nil, &m) + if err != nil { + log.Fatalf("Failed to load configuration: %s", err) + } + fmt.Printf("Configuration is %#v\n", m) + fmt.Printf("foo = %#v\n", m["foo"]) + fmt.Printf("baz = %#v\n", m["baz"]) } diff --git a/dynamicstruct/decoder/data_type.go b/dynamicstruct/decoder/data_type.go index 6f6ccb3b..9503cff8 100644 --- a/dynamicstruct/decoder/data_type.go +++ b/dynamicstruct/decoder/data_type.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" + "github.com/hashicorp/hcl/v2/hclsimple" "gopkg.in/yaml.v3" ) @@ -12,21 +13,13 @@ import ( type dataType int const ( - // TypeJSON is the type sign of JSON typeJSON dataType = iota - - // TypeYAML is the type sign of YAML typeYAML + typeHCL // FIXME: futures as follows - - // TypeXML is the type sign of XML // TypeXML - - // TypeTOML is the type sign of TOML // TypeTOML - - // TypeCSV is the type sign of CSV // TypeCSV end // end of iota @@ -35,6 +28,7 @@ const ( var formats = [...]string{ typeJSON: "json", typeYAML: "yaml", + typeHCL: "hcl", } func (dt dataType) string() string { @@ -55,11 +49,13 @@ func (dt dataType) unmarshalWithIPtr(data []byte, iptr interface{}) error { switch dt { case typeJSON: - // Note: iptr should be "map[string]interface{}" err = json.Unmarshal(data, iptr) case typeYAML: - // Note: iptr should be "map[interface{}]interface{}" using gopkg.in/yaml.v2 package err = yaml.Unmarshal(data, iptr) + case typeHCL: + var i map[string]interface{} + iptr = &i + err = hclsimple.Decode("example.hcl", data, nil, iptr) default: err = fmt.Errorf("invalid datatype for Unmarshal: %v", dt) } @@ -72,10 +68,8 @@ func (dt dataType) unmarshalWithIPtr(data []byte, iptr interface{}) error { func (dt dataType) marshal(m map[string]interface{}) (data []byte, err error) { switch dt { case typeJSON: - // Note: v is expected to be "map[string]interface{}" data, err = json.Marshal(m) case typeYAML: - // Note: v is expected to be converted from "map[interface{}]interface{}" to "map[string]interface{}" data, err = yaml.Marshal(m) default: err = fmt.Errorf("invalid datatype for Marshal: %v", dt) diff --git a/dynamicstruct/decoder/decoder.go b/dynamicstruct/decoder/decoder.go index 02b5b66b..398f0459 100644 --- a/dynamicstruct/decoder/decoder.go +++ b/dynamicstruct/decoder/decoder.go @@ -71,6 +71,11 @@ func FromYAML(data []byte) (*Decoder, error) { return newDecoder(data, typeYAML) } +// FromHCL returns a concrete Decoder for HCL. +func FromHCL(data []byte) (*Decoder, error) { + return newDecoder(data, typeHCL) +} + // FromXML returns a concrete Decoder for XML. // FIXME: This function is still a future candidate (returned error now) func FromXML(data []byte) (*Decoder, error) { diff --git a/dynamicstruct/decoder/decoder_test.go b/dynamicstruct/decoder/decoder_test.go index 6eefbfe1..9cb5136d 100644 --- a/dynamicstruct/decoder/decoder_test.go +++ b/dynamicstruct/decoder/decoder_test.go @@ -12,7 +12,8 @@ import ( const ( typeJSON int = iota typeYAML - typeXML + typeHCL + typeXML // FIXME ) var ( @@ -1078,6 +1079,99 @@ string_array_field: } } +func TestDynamicStructHCL(t *testing.T) { + t.Parallel() + + tests := []decoderTest{ + { + name: "HasOnlyPrimitive", + data: []byte(` +string_field = "かきくけこ" +int_field = 45678 +float32_field = 9.876 +bool_field = false +`), + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 4, + wantDefinition: `type DynamicStruct struct { + BoolField bool + Float32Field float64 + IntField float64 + StringField string +}`, + }, + { + name: "BracketOnly", + data: []byte(`{}`), + dt: typeJSON, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: `type DynamicStruct struct { +}`, + }, + { + name: "ArrayBracketOnly", + data: []byte(`[]`), + dt: typeJSON, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: `type DynamicStruct struct { +}`, + }, + { + name: "OnlyLiteral", + data: []byte(`aiueo`), + dt: typeJSON, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: ``, + wantErrorNew: true, + }, + { + name: "Empty", + data: []byte(``), + dt: typeJSON, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: ``, + wantErrorNew: true, + }, + { + name: "NullData", + data: nil, + dt: typeJSON, + nest: false, + useTag: false, + wantErrorNew: true, + }, + } + + for _, tt := range tests { + tt := tt // See: https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721 + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + dec, err := FromHCL(tt.data) + if err != nil { + if !tt.wantErrorNew { + t.Fatalf("unexpected error is returned from FromHCL: %v", err) + } + return + } else if tt.wantErrorNew { + t.Fatalf("error is expected but it does not occur from FromHCL. data: %q", string(tt.data)) + } + + testCorrectCase(t, tt, dec) + }) + } +} + func TestDynamicStructFixmeXml(t *testing.T) { t.Parallel() diff --git a/go.mod b/go.mod index cdd8982a..f305a754 100644 --- a/go.mod +++ b/go.mod @@ -4,15 +4,19 @@ go 1.19 require ( github.com/google/go-cmp v0.5.8 + github.com/hashicorp/hcl/v2 v2.13.0 github.com/iancoleman/strcase v0.2.0 github.com/spf13/viper v1.12.0 gopkg.in/yaml.v3 v3.0.1 ) require ( + github.com/agext/levenshtein v1.2.3 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/magiconair/properties v1.8.6 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.2 // indirect @@ -21,6 +25,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.0 // indirect + github.com/zclconf/go-cty v1.10.0 // indirect golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/text v0.3.8 // indirect gopkg.in/ini.v1 v1.66.6 // indirect diff --git a/go.sum b/go.sum index 14890866..a817de12 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,10 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -61,6 +65,7 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -121,6 +126,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc= +github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -134,8 +141,11 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= @@ -149,6 +159,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -168,10 +179,14 @@ github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -312,6 +327,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From ed7cdac57f9a9728ee68cce379c305c508b6c841 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Fri, 22 Jul 2022 18:09:16 +0900 Subject: [PATCH 05/13] WIP support HCL encoding/decoding From 36bd992e7c7f9e3174fafd96e2f97d567e154e09 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sat, 20 Aug 2022 14:16:59 +0900 Subject: [PATCH 06/13] refactoring unmarshal logic and temporary removing tests for hcl --- dynamicstruct/decoder/data_type.go | 8 +- dynamicstruct/decoder/decoder.go | 44 ++++--- dynamicstruct/decoder/decoder_test.go | 176 +++++++++++++------------- 3 files changed, 112 insertions(+), 116 deletions(-) diff --git a/dynamicstruct/decoder/data_type.go b/dynamicstruct/decoder/data_type.go index 9503cff8..98d0a0ff 100644 --- a/dynamicstruct/decoder/data_type.go +++ b/dynamicstruct/decoder/data_type.go @@ -38,13 +38,7 @@ func (dt dataType) string() string { return "" } -func (dt dataType) unmarshal(data []byte) (interface{}, error) { - var intf interface{} - err := dt.unmarshalWithIPtr(data, &intf) - return intf, err -} - -func (dt dataType) unmarshalWithIPtr(data []byte, iptr interface{}) error { +func (dt dataType) unmarshal(data []byte, iptr interface{}) error { var err error switch dt { diff --git a/dynamicstruct/decoder/decoder.go b/dynamicstruct/decoder/decoder.go index 398f0459..282e6d6e 100644 --- a/dynamicstruct/decoder/decoder.go +++ b/dynamicstruct/decoder/decoder.go @@ -20,36 +20,32 @@ type Decoder struct { } func newDecoder(data []byte, dt dataType) (*Decoder, error) { - unm, err := dt.unmarshal(data) + var intf interface{} + + err := dt.unmarshal(data, &intf) if err != nil { return nil, err } - dec := &Decoder{ - dt: dt, - orgData: data, - orgIntf: unm, - strKeyMap: make(map[string]interface{}), - } - - switch t := dec.orgIntf.(type) { + m := make(map[string]interface{}) + switch t := intf.(type) { case map[string]interface{}: // JSON - dec.strKeyMap = t + m = t // Note: this is dead case with gopkg.in/yaml.v3 (but alive with v2) // case map[interface{}]interface{}: // // YAML - // dec.strKeyMap = toStringKeyMap(t) + // m = toStringKeyMap(t) case []interface{}: if len(t) > 0 { // The items in the array must be same for all elements. // So the first element is used to process switch tt := t[0].(type) { case map[string]interface{}: - dec.strKeyMap = tt + m = tt // Note: this is dead case with gopkg.in/yaml.v3 (but alive with v2) // case map[interface{}]interface{}: - // dec.strKeyMap = toStringKeyMap(tt) + // m = toStringKeyMap(tt) default: return nil, fmt.Errorf("unexpected type of t[0] [%v]", tt) } @@ -58,7 +54,12 @@ func newDecoder(data []byte, dt dataType) (*Decoder, error) { return nil, fmt.Errorf("unexpected type of dec.orgIntf [%v]", t) } - return dec, nil + return &Decoder{ + dt: dt, + orgData: data, + orgIntf: intf, + strKeyMap: m, + }, nil } // FromJSON returns a concrete Decoder for JSON. @@ -117,22 +118,23 @@ func (d *Decoder) dsToGetter(nest bool) (*structil.Getter, error) { } func (d *Decoder) decodeToDynamicStruct(ds *dynamicstruct.DynamicStruct) (interface{}, error) { - // toDsFromStringMap() method uses "Build()" method and this means that ds is build by pointer-mode - // So ds.NewInterface() returns a struct *pointer* - d.dsi = ds.NewInterface() - // must use "d.strKeyMap" (not "d.orgIntf"). because key of "d.orgIntf" is not string but interface{} data, err := d.dt.marshal(d.strKeyMap) if err != nil { return nil, fmt.Errorf("fail to d.dt.marshal: %w", err) } - // must use "d.dsi" (not "&d.dsi"). because "d.dsi" is pointer - // if use "&.d.dsi", unmarshal result is not struct but map[interface{}]interface when dt is YAML - if err := d.dt.unmarshalWithIPtr(data, d.dsi); err != nil { + // toDsFromStringMap() method uses "Build()" method and this means that ds is build by pointer-mode + // So ds.NewInterface() returns a struct *pointer* + dsi := ds.NewInterface() + + // must use "dsi" (not "&dsi"). because "dsi" is pointer + // if use "&.dsi", unmarshal result is not struct but map[interface{}]interface when dt is YAML + if err := d.dt.unmarshal(data, dsi); err != nil { return nil, fmt.Errorf("fail to d.dt.unmarshalWithIPtr: %w", err) } + d.dsi = dsi return d.dsi, nil } diff --git a/dynamicstruct/decoder/decoder_test.go b/dynamicstruct/decoder/decoder_test.go index 9cb5136d..753ac211 100644 --- a/dynamicstruct/decoder/decoder_test.go +++ b/dynamicstruct/decoder/decoder_test.go @@ -1079,98 +1079,98 @@ string_array_field: } } -func TestDynamicStructHCL(t *testing.T) { - t.Parallel() +// func TestDynamicStructHCL(t *testing.T) { +// t.Parallel() - tests := []decoderTest{ - { - name: "HasOnlyPrimitive", - data: []byte(` -string_field = "かきくけこ" -int_field = 45678 -float32_field = 9.876 -bool_field = false -`), - dt: typeHCL, - nest: false, - useTag: false, - wantNumF: 4, - wantDefinition: `type DynamicStruct struct { - BoolField bool - Float32Field float64 - IntField float64 - StringField string -}`, - }, - { - name: "BracketOnly", - data: []byte(`{}`), - dt: typeJSON, - nest: false, - useTag: false, - wantNumF: 0, - wantDefinition: `type DynamicStruct struct { -}`, - }, - { - name: "ArrayBracketOnly", - data: []byte(`[]`), - dt: typeJSON, - nest: false, - useTag: false, - wantNumF: 0, - wantDefinition: `type DynamicStruct struct { -}`, - }, - { - name: "OnlyLiteral", - data: []byte(`aiueo`), - dt: typeJSON, - nest: false, - useTag: false, - wantNumF: 0, - wantDefinition: ``, - wantErrorNew: true, - }, - { - name: "Empty", - data: []byte(``), - dt: typeJSON, - nest: false, - useTag: false, - wantNumF: 0, - wantDefinition: ``, - wantErrorNew: true, - }, - { - name: "NullData", - data: nil, - dt: typeJSON, - nest: false, - useTag: false, - wantErrorNew: true, - }, - } +// tests := []decoderTest{ +// { +// name: "HasOnlyPrimitive", +// data: []byte(` +// string_field = "かきくけこ" +// int_field = 45678 +// float32_field = 9.876 +// bool_field = false +// `), +// dt: typeHCL, +// nest: false, +// useTag: false, +// wantNumF: 4, +// wantDefinition: `type DynamicStruct struct { +// BoolField bool +// Float32Field float64 +// IntField float64 +// StringField string +// }`, +// }, +// { +// name: "BracketOnly", +// data: []byte(`{}`), +// dt: typeJSON, +// nest: false, +// useTag: false, +// wantNumF: 0, +// wantDefinition: `type DynamicStruct struct { +// }`, +// }, +// { +// name: "ArrayBracketOnly", +// data: []byte(`[]`), +// dt: typeJSON, +// nest: false, +// useTag: false, +// wantNumF: 0, +// wantDefinition: `type DynamicStruct struct { +// }`, +// }, +// { +// name: "OnlyLiteral", +// data: []byte(`aiueo`), +// dt: typeJSON, +// nest: false, +// useTag: false, +// wantNumF: 0, +// wantDefinition: ``, +// wantErrorNew: true, +// }, +// { +// name: "Empty", +// data: []byte(``), +// dt: typeJSON, +// nest: false, +// useTag: false, +// wantNumF: 0, +// wantDefinition: ``, +// wantErrorNew: true, +// }, +// { +// name: "NullData", +// data: nil, +// dt: typeJSON, +// nest: false, +// useTag: false, +// wantErrorNew: true, +// }, +// } - for _, tt := range tests { - tt := tt // See: https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721 - t.Run(tt.name, func(t *testing.T) { - t.Parallel() +// for _, tt := range tests { +// tt := tt // See: https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721 +// t.Run(tt.name, func(t *testing.T) { +// t.Parallel() - dec, err := FromHCL(tt.data) - if err != nil { - if !tt.wantErrorNew { - t.Fatalf("unexpected error is returned from FromHCL: %v", err) - } - return - } else if tt.wantErrorNew { - t.Fatalf("error is expected but it does not occur from FromHCL. data: %q", string(tt.data)) - } +// dec, err := FromHCL(tt.data) +// if err != nil { +// if !tt.wantErrorNew { +// t.Fatalf("unexpected error is returned from FromHCL: %v", err) +// } +// return +// } else if tt.wantErrorNew { +// t.Fatalf("error is expected but it does not occur from FromHCL. data: %q", string(tt.data)) +// } - testCorrectCase(t, tt, dec) - }) - } -} +// testCorrectCase(t, tt, dec) +// }) +// } +// } func TestDynamicStructFixmeXml(t *testing.T) { t.Parallel() From 6fe19caecdbf7578e2c9724582f91a1233190386 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sat, 20 Aug 2022 14:22:03 +0900 Subject: [PATCH 07/13] remove unnecessary codes for yaml.v2 package --- dynamicstruct/decoder/decoder.go | 59 +------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/dynamicstruct/decoder/decoder.go b/dynamicstruct/decoder/decoder.go index 282e6d6e..0a032376 100644 --- a/dynamicstruct/decoder/decoder.go +++ b/dynamicstruct/decoder/decoder.go @@ -32,10 +32,6 @@ func newDecoder(data []byte, dt dataType) (*Decoder, error) { case map[string]interface{}: // JSON m = t - // Note: this is dead case with gopkg.in/yaml.v3 (but alive with v2) - // case map[interface{}]interface{}: - // // YAML - // m = toStringKeyMap(t) case []interface{}: if len(t) > 0 { // The items in the array must be same for all elements. @@ -43,9 +39,6 @@ func newDecoder(data []byte, dt dataType) (*Decoder, error) { switch tt := t[0].(type) { case map[string]interface{}: m = tt - // Note: this is dead case with gopkg.in/yaml.v3 (but alive with v2) - // case map[interface{}]interface{}: - // m = toStringKeyMap(tt) default: return nil, fmt.Errorf("unexpected type of t[0] [%v]", tt) } @@ -147,8 +140,7 @@ func (d *Decoder) OrgData() []byte { func (d *Decoder) DynamicStruct(nest bool, useTag bool) (*dynamicstruct.DynamicStruct, error) { var err error - // d.ds, err = d.toDs(d.orgIntf, nest, useTag) - d.ds, err = d.toDs(d.strKeyMap, nest, useTag) + d.ds, err = d.toDsFromStringMap(d.strKeyMap, nest, useTag) if err != nil { return nil, err } @@ -156,15 +148,6 @@ func (d *Decoder) DynamicStruct(nest bool, useTag bool) (*dynamicstruct.DynamicS return d.ds, err } -func (d *Decoder) toDs(i interface{}, nest bool, useTag bool) (*dynamicstruct.DynamicStruct, error) { - switch t := i.(type) { - case map[string]interface{}: - return d.toDsFromStringMap(t, nest, useTag) - } - - return nil, fmt.Errorf("unsupported type [%T] for toDs", i) -} - func (d *Decoder) toDsFromStringMap(m map[string]interface{}, nest bool, useTag bool) (*dynamicstruct.DynamicStruct, error) { var tag, name string var err error @@ -280,43 +263,3 @@ func (d *Decoder) addForStringMap( return b, nil } - -// Note: this is dead case with gopkg.in/yaml.v3 (but alive with v2) -// convert map[interface{}]interface{} to map[string]interface{} -// func toStringKeyMap(mapii map[interface{}]interface{}) map[string]interface{} { -// mapsi := make(map[string]interface{}) -// for k, v := range mapii { -// switch vt := v.(type) { -// case []interface{}: -// // for nest array -// mapsi[fmt.Sprintf("%v", k)] = fromArrayToMapValue(vt) -// case map[interface{}]interface{}: -// // for nest object -// mapsi[fmt.Sprintf("%v", k)] = toStringKeyMap(vt) -// default: -// mapsi[fmt.Sprintf("%v", k)] = v -// } -// } - -// return mapsi -// } - -// Note: this is dead case with gopkg.in/yaml.v3 (but alive with v2) -// func fromArrayToMapValue(ia []interface{}) interface{} { -// resIa := make([]interface{}, 0, len(ia)) -// for _, iv := range ia { -// switch ivt := iv.(type) { -// case []interface{}: -// // for nest array -// resIa = append(resIa, fromArrayToMapValue(ivt)) -// case map[interface{}]interface{}: -// // for nest object -// // !!! this is important process for map[interface{}]interface{} to map[string]interface{} for JSON unmarshaling -// resIa = append(resIa, toStringKeyMap(ivt)) -// default: -// resIa = append(resIa, ivt) -// } -// } - -// return resIa -// } From 193ce1e2cb9dbbefd0719886dbcc1c07d5cb4ba5 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sat, 20 Aug 2022 14:39:42 +0900 Subject: [PATCH 08/13] rename method --- getter.go | 112 +++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/getter.go b/getter.go index ba164fae..ac277a94 100644 --- a/getter.go +++ b/getter.go @@ -94,27 +94,27 @@ func (g *Getter) Names() []string { return g.names } -func (g *Getter) getSafely(name string) (*getterField, bool) { +func (g *Getter) getField(name string) (*getterField, bool) { gf, ok := g.fields[name] return gf, ok } // goroutine-safely and kind-safely access to a getterField by name -func (g *Getter) getSafelyKindly(name string, kind reflect.Kind) (*getterField, bool) { - gf, ok := g.getSafely(name) +func (g *Getter) getFieldKindly(name string, kind reflect.Kind) (*getterField, bool) { + gf, ok := g.getField(name) return gf, ok && gf.isKind(kind) } // Has tests whether the original struct has a field named "name". func (g *Getter) Has(name string) bool { - _, ok := g.getSafely(name) + _, ok := g.getField(name) return ok } // GetType returns the reflect.Type object of the original struct field named "name". // 2nd return value will be false if the original struct does not have a "name" field. func (g *Getter) GetType(name string) (reflect.Type, bool) { - gf, ok := g.getSafely(name) + gf, ok := g.getField(name) if ok { return gf.typ, true } @@ -125,7 +125,7 @@ func (g *Getter) GetType(name string) (reflect.Type, bool) { // GetValue returns the reflect.Value object of the original struct field named "name". // 2nd return value will be false if the original struct does not have a "name" field. func (g *Getter) GetValue(name string) (reflect.Value, bool) { - gf, ok := g.getSafely(name) + gf, ok := g.getField(name) if ok { return gf.indirect, true } @@ -136,7 +136,7 @@ func (g *Getter) GetValue(name string) (reflect.Value, bool) { // Get returns the interface of the original struct field named name. // 2nd return value will be false if the original struct does not have a "name" field. func (g *Getter) Get(name string) (interface{}, bool) { - gf, ok := g.getSafely(name) + gf, ok := g.getField(name) if ok { return gf.intf, true } @@ -156,7 +156,7 @@ func (g *Getter) ToMap() map[string]interface{} { // IsSlice reports whether type of the original struct field named name is slice. func (g *Getter) IsSlice(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Slice) + _, ok := g.getFieldKindly(name, reflect.Slice) return ok } @@ -164,7 +164,7 @@ func (g *Getter) IsSlice(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not slice of interface. func (g *Getter) Slice(name string) ([]interface{}, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Slice) + gf, ok := g.getFieldKindly(name, reflect.Slice) if !ok { return nil, false } @@ -181,7 +181,7 @@ func (g *Getter) Slice(name string) ([]interface{}, bool) { // IsBool reports whether type of the original struct field named name is bool. func (g *Getter) IsBool(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Bool) + _, ok := g.getFieldKindly(name, reflect.Bool) return ok } @@ -189,7 +189,7 @@ func (g *Getter) IsBool(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not bool. func (g *Getter) Bool(name string) (bool, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Bool) + gf, ok := g.getFieldKindly(name, reflect.Bool) if !ok { return false, false } @@ -200,7 +200,7 @@ func (g *Getter) Bool(name string) (bool, bool) { // IsByte reports whether type of the original struct field named name is byte. func (g *Getter) IsByte(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uint8) + _, ok := g.getFieldKindly(name, reflect.Uint8) return ok } @@ -208,7 +208,7 @@ func (g *Getter) IsByte(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not byte. func (g *Getter) Byte(name string) (byte, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uint8) + gf, ok := g.getFieldKindly(name, reflect.Uint8) if !ok { return 0, false } @@ -219,7 +219,7 @@ func (g *Getter) Byte(name string) (byte, bool) { // IsBytes reports whether type of the original struct field named name is []byte. func (g *Getter) IsBytes(name string) bool { - gf, ok := g.getSafelyKindly(name, reflect.Slice) + gf, ok := g.getFieldKindly(name, reflect.Slice) if !ok { return false } @@ -231,7 +231,7 @@ func (g *Getter) IsBytes(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not []byte. func (g *Getter) Bytes(name string) ([]byte, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Slice) + gf, ok := g.getFieldKindly(name, reflect.Slice) if !ok { return nil, false } @@ -242,7 +242,7 @@ func (g *Getter) Bytes(name string) ([]byte, bool) { // IsString reports whether type of the original struct field named name is string. func (g *Getter) IsString(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.String) + _, ok := g.getFieldKindly(name, reflect.String) return ok } @@ -250,7 +250,7 @@ func (g *Getter) IsString(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not string. func (g *Getter) String(name string) (string, bool) { - gf, ok := g.getSafelyKindly(name, reflect.String) + gf, ok := g.getFieldKindly(name, reflect.String) if !ok { return "", false } @@ -261,7 +261,7 @@ func (g *Getter) String(name string) (string, bool) { // IsInt reports whether type of the original struct field named name is int. func (g *Getter) IsInt(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Int) + _, ok := g.getFieldKindly(name, reflect.Int) return ok } @@ -269,7 +269,7 @@ func (g *Getter) IsInt(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not int. func (g *Getter) Int(name string) (int, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Int) + gf, ok := g.getFieldKindly(name, reflect.Int) if !ok { return 0, false } @@ -280,7 +280,7 @@ func (g *Getter) Int(name string) (int, bool) { // IsInt8 reports whether type of the original struct field named name is int8. func (g *Getter) IsInt8(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Int8) + _, ok := g.getFieldKindly(name, reflect.Int8) return ok } @@ -288,7 +288,7 @@ func (g *Getter) IsInt8(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not int8. func (g *Getter) Int8(name string) (int8, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Int8) + gf, ok := g.getFieldKindly(name, reflect.Int8) if !ok { return 0, false } @@ -299,7 +299,7 @@ func (g *Getter) Int8(name string) (int8, bool) { // IsInt16 reports whether type of the original struct field named name is int16. func (g *Getter) IsInt16(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Int16) + _, ok := g.getFieldKindly(name, reflect.Int16) return ok } @@ -307,7 +307,7 @@ func (g *Getter) IsInt16(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not int16. func (g *Getter) Int16(name string) (int16, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Int16) + gf, ok := g.getFieldKindly(name, reflect.Int16) if !ok { return 0, false } @@ -318,7 +318,7 @@ func (g *Getter) Int16(name string) (int16, bool) { // IsInt32 reports whether type of the original struct field named name is int32. func (g *Getter) IsInt32(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Int32) + _, ok := g.getFieldKindly(name, reflect.Int32) return ok } @@ -326,7 +326,7 @@ func (g *Getter) IsInt32(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not int32. func (g *Getter) Int32(name string) (int32, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Int32) + gf, ok := g.getFieldKindly(name, reflect.Int32) if !ok { return 0, false } @@ -337,7 +337,7 @@ func (g *Getter) Int32(name string) (int32, bool) { // IsInt64 reports whether type of the original struct field named name is int64. func (g *Getter) IsInt64(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Int64) + _, ok := g.getFieldKindly(name, reflect.Int64) return ok } @@ -345,7 +345,7 @@ func (g *Getter) IsInt64(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not int64. func (g *Getter) Int64(name string) (int64, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Int64) + gf, ok := g.getFieldKindly(name, reflect.Int64) if !ok { return 0, false } @@ -356,7 +356,7 @@ func (g *Getter) Int64(name string) (int64, bool) { // IsUint reports whether type of the original struct field named name is uint. func (g *Getter) IsUint(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uint) + _, ok := g.getFieldKindly(name, reflect.Uint) return ok } @@ -364,7 +364,7 @@ func (g *Getter) IsUint(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not uint. func (g *Getter) Uint(name string) (uint, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uint) + gf, ok := g.getFieldKindly(name, reflect.Uint) if !ok { return 0, false } @@ -375,7 +375,7 @@ func (g *Getter) Uint(name string) (uint, bool) { // IsUint8 reports whether type of the original struct field named name is uint8. func (g *Getter) IsUint8(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uint8) + _, ok := g.getFieldKindly(name, reflect.Uint8) return ok } @@ -383,7 +383,7 @@ func (g *Getter) IsUint8(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not uint8. func (g *Getter) Uint8(name string) (uint8, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uint8) + gf, ok := g.getFieldKindly(name, reflect.Uint8) if !ok { return 0, false } @@ -394,7 +394,7 @@ func (g *Getter) Uint8(name string) (uint8, bool) { // IsUint16 reports whether type of the original struct field named name is uint16. func (g *Getter) IsUint16(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uint16) + _, ok := g.getFieldKindly(name, reflect.Uint16) return ok } @@ -402,7 +402,7 @@ func (g *Getter) IsUint16(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not uint16. func (g *Getter) Uint16(name string) (uint16, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uint16) + gf, ok := g.getFieldKindly(name, reflect.Uint16) if !ok { return 0, false } @@ -413,7 +413,7 @@ func (g *Getter) Uint16(name string) (uint16, bool) { // IsUint32 reports whether type of the original struct field named name is uint32. func (g *Getter) IsUint32(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uint32) + _, ok := g.getFieldKindly(name, reflect.Uint32) return ok } @@ -421,7 +421,7 @@ func (g *Getter) IsUint32(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not uint32. func (g *Getter) Uint32(name string) (uint32, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uint32) + gf, ok := g.getFieldKindly(name, reflect.Uint32) if !ok { return 0, false } @@ -432,7 +432,7 @@ func (g *Getter) Uint32(name string) (uint32, bool) { // IsUint64 reports whether type of the original struct field named name is uint64. func (g *Getter) IsUint64(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uint64) + _, ok := g.getFieldKindly(name, reflect.Uint64) return ok } @@ -440,7 +440,7 @@ func (g *Getter) IsUint64(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not uint64. func (g *Getter) Uint64(name string) (uint64, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uint64) + gf, ok := g.getFieldKindly(name, reflect.Uint64) if !ok { return 0, false } @@ -451,7 +451,7 @@ func (g *Getter) Uint64(name string) (uint64, bool) { // IsUintptr reports whether type of the original struct field named name is uintptr. func (g *Getter) IsUintptr(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Uintptr) + _, ok := g.getFieldKindly(name, reflect.Uintptr) return ok } @@ -459,7 +459,7 @@ func (g *Getter) IsUintptr(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not uintptr. func (g *Getter) Uintptr(name string) (uintptr, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Uintptr) + gf, ok := g.getFieldKindly(name, reflect.Uintptr) if !ok { return 0, false } @@ -470,7 +470,7 @@ func (g *Getter) Uintptr(name string) (uintptr, bool) { // IsFloat32 reports whether type of the original struct field named name is float32. func (g *Getter) IsFloat32(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Float32) + _, ok := g.getFieldKindly(name, reflect.Float32) return ok } @@ -478,7 +478,7 @@ func (g *Getter) IsFloat32(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not float32. func (g *Getter) Float32(name string) (float32, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Float32) + gf, ok := g.getFieldKindly(name, reflect.Float32) if !ok { return 0, false } @@ -489,7 +489,7 @@ func (g *Getter) Float32(name string) (float32, bool) { // IsFloat64 reports whether type of the original struct field named name is float64. func (g *Getter) IsFloat64(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Float64) + _, ok := g.getFieldKindly(name, reflect.Float64) return ok } @@ -497,7 +497,7 @@ func (g *Getter) IsFloat64(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not float64. func (g *Getter) Float64(name string) (float64, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Float64) + gf, ok := g.getFieldKindly(name, reflect.Float64) if !ok { return 0, false } @@ -508,7 +508,7 @@ func (g *Getter) Float64(name string) (float64, bool) { // IsComplex64 reports whether type of the original struct field named name is []byte. func (g *Getter) IsComplex64(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Complex64) + _, ok := g.getFieldKindly(name, reflect.Complex64) return ok } @@ -516,7 +516,7 @@ func (g *Getter) IsComplex64(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not complex64. func (g *Getter) Complex64(name string) (complex64, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Complex64) + gf, ok := g.getFieldKindly(name, reflect.Complex64) if !ok { return 0, false } @@ -527,7 +527,7 @@ func (g *Getter) Complex64(name string) (complex64, bool) { // IsComplex128 reports whether type of the original struct field named name is []byte. func (g *Getter) IsComplex128(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Complex128) + _, ok := g.getFieldKindly(name, reflect.Complex128) return ok } @@ -535,7 +535,7 @@ func (g *Getter) IsComplex128(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not complex128. func (g *Getter) Complex128(name string) (complex128, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Complex128) + gf, ok := g.getFieldKindly(name, reflect.Complex128) if !ok { return 0, false } @@ -546,7 +546,7 @@ func (g *Getter) Complex128(name string) (complex128, bool) { // IsUnsafePointer reports whether type of the original struct field named name is []byte. func (g *Getter) IsUnsafePointer(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.UnsafePointer) + _, ok := g.getFieldKindly(name, reflect.UnsafePointer) return ok } @@ -554,7 +554,7 @@ func (g *Getter) IsUnsafePointer(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not unsafe.Pointer. func (g *Getter) UnsafePointer(name string) (unsafe.Pointer, bool) { - gf, ok := g.getSafelyKindly(name, reflect.UnsafePointer) + gf, ok := g.getFieldKindly(name, reflect.UnsafePointer) if !ok { return nil, false } @@ -565,31 +565,31 @@ func (g *Getter) UnsafePointer(name string) (unsafe.Pointer, bool) { // IsMap reports whether type of the original struct field named name is map. func (g *Getter) IsMap(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Map) + _, ok := g.getFieldKindly(name, reflect.Map) return ok } // IsFunc reports whether type of the original struct field named name is func. func (g *Getter) IsFunc(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Func) + _, ok := g.getFieldKindly(name, reflect.Func) return ok } // IsChan reports whether type of the original struct field named name is chan. func (g *Getter) IsChan(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Chan) + _, ok := g.getFieldKindly(name, reflect.Chan) return ok } // IsStruct reports whether type of the original struct field named name is struct. func (g *Getter) IsStruct(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Struct) + _, ok := g.getFieldKindly(name, reflect.Struct) return ok } // IsArray reports whether type of the original struct field named name is slice. func (g *Getter) IsArray(name string) bool { - _, ok := g.getSafelyKindly(name, reflect.Array) + _, ok := g.getFieldKindly(name, reflect.Array) return ok } @@ -597,7 +597,7 @@ func (g *Getter) IsArray(name string) bool { // 2nd return value will be false if the original struct does not have a "name" field. // 2nd return value will be false if type of the original struct "name" field is not struct or struct pointer. func (g *Getter) GetGetter(name string) (*Getter, bool) { - gf, ok := g.getSafelyKindly(name, reflect.Struct) + gf, ok := g.getFieldKindly(name, reflect.Struct) if !ok { return nil, false } @@ -608,7 +608,7 @@ func (g *Getter) GetGetter(name string) (*Getter, bool) { // MapGet returns the interface slice of mapped values of the original struct field named name. func (g *Getter) MapGet(name string, f func(int, *Getter) (interface{}, error)) ([]interface{}, error) { - gf, ok := g.getSafelyKindly(name, reflect.Slice) + gf, ok := g.getFieldKindly(name, reflect.Slice) if !ok { return nil, fmt.Errorf("field %s does not exist or is not slice type", name) } From a3c7ba83d52d6e32547b5f26e9eca00f40b0e89d Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sat, 20 Aug 2022 17:03:48 +0900 Subject: [PATCH 09/13] remove temporary cmd code --- cmd/strucmd/main.go | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 cmd/strucmd/main.go diff --git a/cmd/strucmd/main.go b/cmd/strucmd/main.go deleted file mode 100644 index 494a1d9d..00000000 --- a/cmd/strucmd/main.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2/hclsimple" -) - -func main() { - const exampleConfig = ` -foo = "bar" -baz = "boop" -` - // type Config struct { - // Foo string `hcl:"foo"` - // Baz string `hcl:"baz"` - // } - // var config Config - - // var intf interface{} // PANIC - - var m map[string]interface{} - err := hclsimple.Decode("example.hcl", []byte(exampleConfig), nil, &m) - if err != nil { - log.Fatalf("Failed to load configuration: %s", err) - } - fmt.Printf("Configuration is %#v\n", m) - fmt.Printf("foo = %#v\n", m["foo"]) - fmt.Printf("baz = %#v\n", m["baz"]) -} From 39884f400db82331b5be04d595ea08b8aeb4cd22 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sat, 20 Aug 2022 17:04:17 +0900 Subject: [PATCH 10/13] support HCL to DynamicStruct by FromHCL method --- dynamicstruct/decoder/data_type.go | 95 +++++++- dynamicstruct/decoder/decoder.go | 31 ++- dynamicstruct/decoder/decoder_test.go | 317 +++++++++++++++++--------- 3 files changed, 320 insertions(+), 123 deletions(-) diff --git a/dynamicstruct/decoder/data_type.go b/dynamicstruct/decoder/data_type.go index 98d0a0ff..b204a765 100644 --- a/dynamicstruct/decoder/data_type.go +++ b/dynamicstruct/decoder/data_type.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsimple" + "github.com/zclconf/go-cty/cty" "gopkg.in/yaml.v3" ) @@ -38,23 +40,38 @@ func (dt dataType) string() string { return "" } -func (dt dataType) unmarshal(data []byte, iptr interface{}) error { - var err error +func (dt dataType) unmarshal(data []byte) (ret interface{}, err error) { + switch dt { + case typeHCL: + // Note: hclsimple.Decode supports only pointer of map or struct. + var m map[string]interface{} + err = hclsimple.Decode("example.hcl", data, nil, &m) + if err != nil { + return nil, err + } + dec, err := decodeHCL(data) + if err != nil { + return nil, err + } + return interface{}(dec), nil + default: + err = dt.unmarshalWithPtr(data, &ret) + } + + return +} +func (dt dataType) unmarshalWithPtr(data []byte, iptr interface{}) (err error) { switch dt { case typeJSON: err = json.Unmarshal(data, iptr) case typeYAML: err = yaml.Unmarshal(data, iptr) - case typeHCL: - var i map[string]interface{} - iptr = &i - err = hclsimple.Decode("example.hcl", data, nil, iptr) default: err = fmt.Errorf("invalid datatype for Unmarshal: %v", dt) } - return err + return } // TODO: add tests and examples @@ -71,3 +88,67 @@ func (dt dataType) marshal(m map[string]interface{}) (data []byte, err error) { return } + +func decodeHCL(data []byte) (map[string]interface{}, error) { + // Note: hclsimple.Decode supports only pointer of map or struct. + var m map[string]interface{} + err := hclsimple.Decode("example.hcl", data, nil, &m) + if err != nil { + return m, err + } + + decoded := make(map[string]interface{}, len(m)) + for k, v := range m { + attr, ok := v.(*hcl.Attribute) + if !ok { + return decoded, fmt.Errorf("%q field can not cast to *hcl.Attribute. v = %v", k, v) + } + + ctyVal, _ := attr.Expr.Value(nil) + decoded[k], err = convCtyToGo(ctyVal) + if err != nil { + return decoded, err + } + } + + return decoded, nil +} + +func convCtyToGo(ctyVal cty.Value) (interface{}, error) { + var err error + + ctyType := ctyVal.Type() + if ctyType == cty.String { + return ctyVal.AsString(), nil + } else if ctyType == cty.Number { + return ctyVal.AsBigFloat(), nil + } else if ctyType == cty.Bool { + return ctyVal.True(), nil + } else if ctyType.IsTupleType() { + vals := ctyVal.AsValueSlice() + ret := make([]interface{}, len(vals)) + for i, v := range vals { + ret[i], err = convCtyToGo(v) + if err != nil { + return nil, err + } + } + return ret, nil + } else if ctyType.IsObjectType() { + valM := ctyVal.AsValueMap() + retM := make(map[string]interface{}, len(valM)) + for k, v := range valM { + retM[k], err = convCtyToGo(v) + if err != nil { + return nil, err + } + } + return retM, nil + } else if ctyType == cty.DynamicPseudoType { + // FIXME: just support only null? + return nil, nil + } else { + return nil, fmt.Errorf("unsupported ctyType: %v", ctyType) + } + +} diff --git a/dynamicstruct/decoder/decoder.go b/dynamicstruct/decoder/decoder.go index 0a032376..fda13d4c 100644 --- a/dynamicstruct/decoder/decoder.go +++ b/dynamicstruct/decoder/decoder.go @@ -2,6 +2,7 @@ package decoder import ( "fmt" + "math/big" "github.com/iancoleman/strcase" @@ -20,9 +21,7 @@ type Decoder struct { } func newDecoder(data []byte, dt dataType) (*Decoder, error) { - var intf interface{} - - err := dt.unmarshal(data, &intf) + intf, err := dt.unmarshal(data) if err != nil { return nil, err } @@ -96,6 +95,16 @@ func YAMLToGetter(data []byte, nest bool) (*structil.Getter, error) { return d.dsToGetter(nest) } +// FIXME: HCL decode method supports only struct pointer or map pointer +// func HCLToGetter(data []byte, nest bool) (*structil.Getter, error) { +// d, err := FromHCL(data) +// if err != nil { +// return nil, fmt.Errorf("fail to HCLToGetter: %w", err) +// } + +// return d.dsToGetter(nest) +// } + func (d *Decoder) dsToGetter(nest bool) (*structil.Getter, error) { ds, err := d.DynamicStruct(nest, true) if err != nil { @@ -117,14 +126,13 @@ func (d *Decoder) decodeToDynamicStruct(ds *dynamicstruct.DynamicStruct) (interf return nil, fmt.Errorf("fail to d.dt.marshal: %w", err) } - // toDsFromStringMap() method uses "Build()" method and this means that ds is build by pointer-mode - // So ds.NewInterface() returns a struct *pointer* - dsi := ds.NewInterface() - // must use "dsi" (not "&dsi"). because "dsi" is pointer - // if use "&.dsi", unmarshal result is not struct but map[interface{}]interface when dt is YAML - if err := d.dt.unmarshal(data, dsi); err != nil { - return nil, fmt.Errorf("fail to d.dt.unmarshalWithIPtr: %w", err) + // ds.NewInterface() returns a struct *pointer* + // FIXME: HCL decode method supports only struct pointer or map pointer + dsi := ds.NewInterface() + err = d.dt.unmarshalWithPtr(data, dsi) + if err != nil { + return nil, fmt.Errorf("fail to d.dt.unmarshalWithPtr: %w", err) } d.dsi = dsi @@ -225,6 +233,9 @@ func (d *Decoder) toDsFromStringMap(m map[string]interface{}, nest bool, useTag // YAML support case nil: b = b.AddInterfaceWithTag(name, false, tag) + // HCL support + case *big.Float: + b = b.AddFloat64WithTag(name, tag) default: return nil, fmt.Errorf("unsupported type of map-value. key = [%s] value = %#v", k, value) } diff --git a/dynamicstruct/decoder/decoder_test.go b/dynamicstruct/decoder/decoder_test.go index 753ac211..6e479eff 100644 --- a/dynamicstruct/decoder/decoder_test.go +++ b/dynamicstruct/decoder/decoder_test.go @@ -22,7 +22,7 @@ var ( "null_field":null, "string_field":"かきくけこ", "int_field":45678, - "float32_field":9.876, + "float64_field":9.876, "bool_field":false, "struct_ptr_field":{ "key":"hugakey", @@ -55,7 +55,7 @@ var ( "null_field":null, "string_field":"かきくけこ", "int_field":45678, - "float32_field":9.876, + "float64_field":9.876, "bool_field":false, "struct_ptr_field":{ "key":"hugakey", @@ -84,7 +84,7 @@ var ( "null_field":null, "string_field":"さしすせそ", "int_field":7890, - "float32_field":4.99, + "float64_field":4.99, "bool_field":true, "struct_ptr_field":{ "key":"hugakeyXXX", @@ -116,7 +116,7 @@ var ( null_field: null string_field: かきくけこ int_field: 45678 -float32_field: 9.876 +float64_field: 9.876 bool_field: false struct_ptr_field: key: hugakey @@ -137,7 +137,7 @@ array_struct_field: - null_field: null string_field: かきくけこ int_field: 45678 - float32_field: 9.876 + float64_field: 9.876 bool_field: false struct_ptr_field: key: hugakey @@ -155,7 +155,7 @@ array_struct_field: - null_field: null string_field: さしすせそ int_field: 7890 - float32_field: 4.99 + float64_field: 4.99 bool_field: true struct_ptr_field: key: hugakeyXXX @@ -176,7 +176,7 @@ array_struct_field: singleTOML = []byte(` string_field = "かきくけこ," int_field = 45678 -float32_field = "9.876," +float64_field = "9.876," bool_field = false array_string_field = ["array_str_1", "array_str_2"] @@ -204,7 +204,7 @@ array_string_field = ["array_str_1", "array_str_2"] かきくけこ 45678 - 9.876 + 9.876 false hugakey @@ -235,7 +235,7 @@ array_string_field = ["array_str_1", "array_str_2"] かきくけこ 45678 - 9.876 + 9.876 false hugakey @@ -260,7 +260,7 @@ array_string_field = ["array_str_1", "array_str_2"] さしすせそ 7890 - 4.99 + 4.99 true hugakeyXXX @@ -292,7 +292,7 @@ array_string_field = ["array_str_1", "array_str_2"] "int_field" = 45678 -"float32_field" = "9.876," +"float64_field" = "9.876," "bool_field" = false @@ -348,7 +348,7 @@ func TestDynamicStructJSON(t *testing.T) { "null_field":null, "string_field":"かきくけこ", "int_field":45678, - "float32_field":9.876, + "float64_field":9.876, "bool_field":false } `), @@ -358,14 +358,14 @@ func TestDynamicStructJSON(t *testing.T) { wantNumF: 5, wantDefinition: `type DynamicStruct struct { BoolField bool - Float32Field float64 + Float64Field float64 IntField float64 NullField interface {} StringField string }`, fieldAndNestFields: map[string][]string{ "BoolField": nil, - "Float32Field": nil, + "Float64Field": nil, "IntField": nil, "NullField": nil, "StringField": nil, @@ -785,7 +785,7 @@ func TestDynamicStructYAML(t *testing.T) { null_field: null string_field: かきくけこ int_field: 45678 -float32_field: 9.876 +float64_field: 9.876 bool_field: false `), dt: typeYAML, @@ -794,14 +794,14 @@ bool_field: false wantNumF: 5, wantDefinition: `type DynamicStruct struct { BoolField bool - Float32Field float64 + Float64Field float64 IntField int NullField interface {} StringField string }`, fieldAndNestFields: map[string][]string{ "BoolField": nil, - "Float32Field": nil, + "Float64Field": nil, "IntField": nil, "NullField": nil, "StringField": nil, @@ -1079,98 +1079,203 @@ string_array_field: } } -// func TestDynamicStructHCL(t *testing.T) { -// t.Parallel() +func TestDynamicStructHCL(t *testing.T) { + t.Parallel() -// tests := []decoderTest{ -// { -// name: "HasOnlyPrimitive", -// data: []byte(` -// string_field = "かきくけこ" -// int_field = 45678 -// float32_field = 9.876 -// bool_field = false -// `), -// dt: typeHCL, -// nest: false, -// useTag: false, -// wantNumF: 4, -// wantDefinition: `type DynamicStruct struct { -// BoolField bool -// Float32Field float64 -// IntField float64 -// StringField string -// }`, -// }, -// { -// name: "BracketOnly", -// data: []byte(`{}`), -// dt: typeJSON, -// nest: false, -// useTag: false, -// wantNumF: 0, -// wantDefinition: `type DynamicStruct struct { -// }`, -// }, -// { -// name: "ArrayBracketOnly", -// data: []byte(`[]`), -// dt: typeJSON, -// nest: false, -// useTag: false, -// wantNumF: 0, -// wantDefinition: `type DynamicStruct struct { -// }`, -// }, -// { -// name: "OnlyLiteral", -// data: []byte(`aiueo`), -// dt: typeJSON, -// nest: false, -// useTag: false, -// wantNumF: 0, -// wantDefinition: ``, -// wantErrorNew: true, -// }, -// { -// name: "Empty", -// data: []byte(``), -// dt: typeJSON, -// nest: false, -// useTag: false, -// wantNumF: 0, -// wantDefinition: ``, -// wantErrorNew: true, -// }, -// { -// name: "NullData", -// data: nil, -// dt: typeJSON, -// nest: false, -// useTag: false, -// wantErrorNew: true, -// }, -// } + tests := []decoderTest{ + { + name: "NoNestWithoutTag", + data: []byte(` +string_field = "かきくけこ" +int_field = 45678 +float64_field = 9.876 +bool_field = false +null_field = null +tuple_str_field = ["str1", "str2", "str3"] +tuple_mix_field = ["str1", 123, true] +object_str_field = { + key_a = "valA" + key_b = "valB" +} +object_mix_field = { + key_str = "strA" + key_num = 876.543 + key_bool = true +} +`), + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 9, + wantDefinition: `type DynamicStruct struct { + BoolField bool + Float64Field float64 + IntField float64 + NullField interface {} + ObjectMixField map[string]interface {} + ObjectStrField map[string]interface {} + StringField string + TupleMixField []string + TupleStrField []string +}`, + }, + { + name: "IsNestWithoutTag", + data: []byte(` +string_field = "かきくけこ" +int_field = 45678 +float64_field = 9.876 +bool_field = false +null_field = null +tuple_str_field = ["str1", "str2", "str3"] +tuple_mix_field = ["str1", 123, true] +object_str_field = { + key_a = "valA" + key_b = "valB" +} +object_mix_field = { + key_str = "strA" + key_num = 876.543 + key_bool = true +} +`), + dt: typeHCL, + nest: true, + useTag: false, + wantNumF: 9, + wantDefinition: `type DynamicStruct struct { + BoolField bool + Float64Field float64 + IntField float64 + NullField interface {} + ObjectMixField struct { + KeyBool bool + KeyNum float64 + KeyStr string + } + ObjectStrField struct { + KeyA string + KeyB string + } + StringField string + TupleMixField []string + TupleStrField []string +}`, + }, + { + name: "IsNestWithTag", + data: []byte(` +string_field = "かきくけこ" +int_field = 45678 +float64_field = 9.876 +bool_field = false +null_field = null +tuple_str_field = ["str1", "str2", "str3"] +tuple_mix_field = ["str1", 123, true] +object_str_field = { + key_a = "valA" + key_b = "valB" +} +object_mix_field = { + key_str = "strA" + key_num = 876.543 + key_bool = true +} +`), + dt: typeHCL, + nest: true, + useTag: true, + wantNumF: 9, + wantDefinition: `type DynamicStruct struct { + BoolField bool ` + "`hcl:\"bool_field\"`" + ` + Float64Field float64 ` + "`hcl:\"float64_field\"`" + ` + IntField float64 ` + "`hcl:\"int_field\"`" + ` + NullField interface {} ` + "`hcl:\"null_field\"`" + ` + ObjectMixField struct { + KeyBool bool ` + "`hcl:\"key_bool\"`" + ` + KeyNum float64 ` + "`hcl:\"key_num\"`" + ` + KeyStr string ` + "`hcl:\"key_str\"`" + ` + } ` + "`hcl:\"object_mix_field\"`" + ` + ObjectStrField struct { + KeyA string ` + "`hcl:\"key_a\"`" + ` + KeyB string ` + "`hcl:\"key_b\"`" + ` + } ` + "`hcl:\"object_str_field\"`" + ` + StringField string ` + "`hcl:\"string_field\"`" + ` + TupleMixField []string ` + "`hcl:\"tuple_mix_field\"`" + ` + TupleStrField []string ` + "`hcl:\"tuple_str_field\"`" + ` +}`, + }, + { + name: "BracketOnly", + data: []byte(`{}`), + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: ``, + wantErrorNew: true, + }, + { + name: "ArrayBracketOnly", + data: []byte(`[]`), + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: ``, + wantErrorNew: true, + }, + { + name: "OnlyLiteral", + data: []byte(`aiueo`), + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: ``, + wantErrorNew: true, + }, + { + name: "Empty", + data: []byte(``), + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: `type DynamicStruct struct { +}`, + }, + { + name: "NullData", + data: nil, + dt: typeHCL, + nest: false, + useTag: false, + wantNumF: 0, + wantDefinition: `type DynamicStruct struct { +}`, + }, + } -// for _, tt := range tests { -// tt := tt // See: https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721 -// t.Run(tt.name, func(t *testing.T) { -// t.Parallel() + for _, tt := range tests { + tt := tt // See: https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721 + t.Run(tt.name, func(t *testing.T) { + t.Parallel() -// dec, err := FromHCL(tt.data) -// if err != nil { -// if !tt.wantErrorNew { -// t.Fatalf("unexpected error is returned from FromHCL: %v", err) -// } -// return -// } else if tt.wantErrorNew { -// t.Fatalf("error is expected but it does not occur from FromHCL. data: %q", string(tt.data)) -// } + dec, err := FromHCL(tt.data) + if err != nil { + if !tt.wantErrorNew { + t.Fatalf("unexpected error is returned from FromHCL: %v", err) + } + return + } else if tt.wantErrorNew { + t.Fatalf("error is expected but it does not occur from FromHCL. data: %q", string(tt.data)) + } -// testCorrectCase(t, tt, dec) -// }) -// } -// } + testCorrectCase(t, tt, dec) + }) + } +} func TestDynamicStructFixmeXml(t *testing.T) { t.Parallel() @@ -1182,7 +1287,7 @@ func TestDynamicStructFixmeXml(t *testing.T) { null_field: null string_field: かきくけこ int_field: 45678 -float32_field: 9.876 +float64_field: 9.876 bool_field: false `), dt: typeXML, From 57a959a4a1573bb4956ccc051b31c413411fece2 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Sun, 21 Aug 2022 11:19:40 +0900 Subject: [PATCH 11/13] remove comment line --- dynamicstruct/decoder/data_type.go | 1 - 1 file changed, 1 deletion(-) diff --git a/dynamicstruct/decoder/data_type.go b/dynamicstruct/decoder/data_type.go index b204a765..854d3d86 100644 --- a/dynamicstruct/decoder/data_type.go +++ b/dynamicstruct/decoder/data_type.go @@ -150,5 +150,4 @@ func convCtyToGo(ctyVal cty.Value) (interface{}, error) { } else { return nil, fmt.Errorf("unsupported ctyType: %v", ctyType) } - } From 3fa99740d0988a09fe5aa2e0e87e182c4a3a9412 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Mon, 22 Aug 2022 19:07:33 +0900 Subject: [PATCH 12/13] fix --- dynamicstruct/decoder/benchmark_test.go | 360 ++++++++++++++++++++++-- dynamicstruct/decoder/data_type.go | 30 +- dynamicstruct/decoder/decoder.go | 113 ++++---- dynamicstruct/decoder/decoder_test.go | 312 -------------------- 4 files changed, 399 insertions(+), 416 deletions(-) diff --git a/dynamicstruct/decoder/benchmark_test.go b/dynamicstruct/decoder/benchmark_test.go index 18651cb8..cb2e6e2b 100644 --- a/dynamicstruct/decoder/benchmark_test.go +++ b/dynamicstruct/decoder/benchmark_test.go @@ -6,6 +6,310 @@ import ( . "github.com/goldeneggg/structil/dynamicstruct/decoder" ) +var ( + singleJSON = []byte(` +{ + "null_field":null, + "string_field":"かきくけこ", + "int_field":45678, + "float64_field":9.876, + "bool_field":false, + "struct_ptr_field":{ + "key":"hugakey", + "value":"hugavalue" + }, + "array_string_field":[ + "array_str_1", + "array_str_2" + ], + "array_struct_field":[ + { + "kkk":"kkk1", + "vvvv":"vvv1" + }, + { + "kkk":"kkk2", + "vvvv":"vvv2" + }, + { + "kkk":"kkk3", + "vvvv":"vvv3" + } + ] +} +`) + + arrayJSON = []byte(` +[ + { + "null_field":null, + "string_field":"かきくけこ", + "int_field":45678, + "float64_field":9.876, + "bool_field":false, + "struct_ptr_field":{ + "key":"hugakey", + "value":"hugavalue" + }, + "array_string_field":[ + "array_str_1", + "array_str_2" + ], + "array_struct_field":[ + { + "kkk":"kkk1", + "vvvv":"vvv1" + }, + { + "kkk":"kkk2", + "vvvv":"vvv2" + }, + { + "kkk":"kkk3", + "vvvv":"vvv3" + } + ] + }, + { + "null_field":null, + "string_field":"さしすせそ", + "int_field":7890, + "float64_field":4.99, + "bool_field":true, + "struct_ptr_field":{ + "key":"hugakeyXXX", + "value":"hugavalueXXX" + }, + "array_string_field":[ + "array_str_111", + "array_str_222" + ], + "array_struct_field":[ + { + "kkk":"kkk99", + "vvvv":"vvv99" + }, + { + "kkk":"kkk999", + "vvvv":"vvv999" + }, + { + "kkk":"kkk9999", + "vvvv":"vvv9999" + } + ] + } +] +`) + + singleYAML = []byte(` +null_field: null +string_field: かきくけこ +int_field: 45678 +float64_field: 9.876 +bool_field: false +struct_ptr_field: + key: hugakey + value: hugavalue +array_string_field: + - array_str_1 + - array_str_2 +array_struct_field: + - kkk: kkk1 + vvvv: vvv1 + - kkk: kkk2 + vvvv: vvv2 + - kkk: kkk3 + vvvv: vvv3 +`) + + arrayYAML = []byte(` +- null_field: null + string_field: かきくけこ + int_field: 45678 + float64_field: 9.876 + bool_field: false + struct_ptr_field: + key: hugakey + value: hugavalue + array_string_field: + - array_str_1 + - array_str_2 + array_struct_field: + - kkk: kkk1 + vvvv: vvv1 + - kkk: kkk2 + vvvv: vvv2 + - kkk: kkk3 + vvvv: vvv3 +- null_field: null + string_field: さしすせそ + int_field: 7890 + float64_field: 4.99 + bool_field: true + struct_ptr_field: + key: hugakeyXXX + value: hugavalueXXX + array_string_field: + - array_str_111 + - array_str_222 + array_struct_field: + - kkk: kkk99 + vvvv: vvv99 + - kkk: kkk999 + vvvv: vvv999 + - kkk: kkk9999 + vvvv: vvv9999 +`) + + //lint:ignore U1000 It's ok because this is for the future. + singleTOML = []byte(` +string_field = "かきくけこ," +int_field = 45678 +float64_field = "9.876," +bool_field = false +array_string_field = ["array_str_1", "array_str_2"] + +[struct_ptr_field] + key = "hugakey" + value = "hugavalue" + +[[array_struct_field]] + kkk = "kkk1" + vvvv = "vvv1" + +[[array_struct_field]] + kkk = "kkk2" + vvvv = "vvv2" + +[[array_struct_field]] + kkk = "kkk3" + vvvv = "vvv3" +`) + + //lint:ignore U1000 It's ok because this is for the future. + singleXML = []byte(` + + + + かきくけこ + 45678 + 9.876 + false + + hugakey + hugavalue + + array_str_1 + array_str_2 + + kkk1 + vvv1 + + + kkk2 + vvv2 + + + kkk3 + vvv3 + + +`) + + //lint:ignore U1000 It's ok because this is for the future. + arrayXML = []byte(` + + + <0> + + かきくけこ + 45678 + 9.876 + false + + hugakey + hugavalue + + array_str_1 + array_str_2 + + kkk1 + vvv1 + + + kkk2 + vvv2 + + + kkk3 + vvv3 + + + <1> + + さしすせそ + 7890 + 4.99 + true + + hugakeyXXX + hugavalueXXX + + array_str_111 + array_str_222 + + kkk99 + vvv99 + + + kkk999 + vvv999 + + + kkk9999 + vvv9999 + + + +`) + + //lint:ignore U1000 It's ok because this is for the future. + singleHCL = []byte(` +null_field = + +string_field = "かきくけこ," + +int_field = 45678 + +float64_field = "9.876," + +bool_field = false + +struct_ptr_field = { + key = "hugakey" + value = "hugavalue" +} + +array_string_field = ["array_str_1", "array_str_2"] + +array_struct_field = { + kkk = "kkk1" + vvvv = "vvv1" +} + +"array_struct_field" = { + kkk = "kkk2" + vvvv = "vvv2" +} + +array_struct_field = { + kkk = "kkk3" + vvvv = "vvv3" +} +`) +) + func BenchmarkFromJSON_singleJSON(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { @@ -74,6 +378,34 @@ func BenchmarkDynamicStruct_arrayJSON_nest_useTag(b *testing.B) { } } +func BenchmarkJSONToGetter_singleJSON_nonNest(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = JSONToGetter(singleJSON, false) + } +} + +func BenchmarkJSONToGetter_singleJSON_nest(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = JSONToGetter(singleJSON, true) + } +} + +func BenchmarkJSONToGetter_arrayJSON_nonNest(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = JSONToGetter(arrayJSON, false) + } +} + +func BenchmarkJSONToGetter_arrayJSON_nest(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = JSONToGetter(arrayJSON, true) + } +} + func BenchmarkFromYAML_singleYAML(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { @@ -142,34 +474,6 @@ func BenchmarkDynamicStruct_arrayYAML_nest_useTag(b *testing.B) { } } -func BenchmarkJSONToGetter_singleJSON_nonNest(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = JSONToGetter(singleJSON, false) - } -} - -func BenchmarkJSONToGetter_singleJSON_nest(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = JSONToGetter(singleJSON, true) - } -} - -func BenchmarkJSONToGetter_arrayJSON_nonNest(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = JSONToGetter(arrayJSON, false) - } -} - -func BenchmarkJSONToGetter_arrayJSON_nest(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = JSONToGetter(arrayJSON, true) - } -} - func BenchmarkYAMLToGetter_singleYAML_nonNest(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/dynamicstruct/decoder/data_type.go b/dynamicstruct/decoder/data_type.go index 854d3d86..3f637c98 100644 --- a/dynamicstruct/decoder/data_type.go +++ b/dynamicstruct/decoder/data_type.go @@ -74,21 +74,6 @@ func (dt dataType) unmarshalWithPtr(data []byte, iptr interface{}) (err error) { return } -// TODO: add tests and examples -// func (dt dataType) marshal(v interface{}) (data []byte, err error) { -func (dt dataType) marshal(m map[string]interface{}) (data []byte, err error) { - switch dt { - case typeJSON: - data, err = json.Marshal(m) - case typeYAML: - data, err = yaml.Marshal(m) - default: - err = fmt.Errorf("invalid datatype for Marshal: %v", dt) - } - - return -} - func decodeHCL(data []byte) (map[string]interface{}, error) { // Note: hclsimple.Decode supports only pointer of map or struct. var m map[string]interface{} @@ -151,3 +136,18 @@ func convCtyToGo(ctyVal cty.Value) (interface{}, error) { return nil, fmt.Errorf("unsupported ctyType: %v", ctyType) } } + +// TODO: add tests and examples +// func (dt dataType) marshal(v interface{}) (data []byte, err error) { +func (dt dataType) marshal(m map[string]interface{}) (data []byte, err error) { + switch dt { + case typeJSON: + data, err = json.Marshal(m) + case typeYAML: + data, err = yaml.Marshal(m) + default: + err = fmt.Errorf("invalid datatype for Marshal: %v", dt) + } + + return +} diff --git a/dynamicstruct/decoder/decoder.go b/dynamicstruct/decoder/decoder.go index fda13d4c..cdfd2881 100644 --- a/dynamicstruct/decoder/decoder.go +++ b/dynamicstruct/decoder/decoder.go @@ -12,16 +12,36 @@ import ( // Decoder is the struct that decodes some marshaled data like JSON and YAML. type Decoder struct { - dt dataType - orgData []byte // original data - orgIntf interface{} // unmarshaled interface from original data - strKeyMap map[string]interface{} // string key map for decoding to DymanicStruct - ds *dynamicstruct.DynamicStruct - dsi interface{} // unmarshaled result from data to DynamicStruct + typ dataType + data []byte + intf interface{} + m map[string]interface{} + ds *dynamicstruct.DynamicStruct } -func newDecoder(data []byte, dt dataType) (*Decoder, error) { - intf, err := dt.unmarshal(data) +// FromJSON returns a concrete Decoder for JSON. +func FromJSON(data []byte) (*Decoder, error) { + return newDecoder(data, typeJSON) +} + +// FromYAML returns a concrete Decoder for YAML. +func FromYAML(data []byte) (*Decoder, error) { + return newDecoder(data, typeYAML) +} + +// FromHCL returns a concrete Decoder for HCL. +func FromHCL(data []byte) (*Decoder, error) { + return newDecoder(data, typeHCL) +} + +// FromXML returns a concrete Decoder for XML. +// FIXME: This function is still a future candidate (returned error now) +func FromXML(data []byte) (*Decoder, error) { + return newDecoder(data, end) // FIXME: "end" is provisional type +} + +func newDecoder(data []byte, typ dataType) (*Decoder, error) { + intf, err := typ.unmarshal(data) if err != nil { return nil, err } @@ -43,38 +63,17 @@ func newDecoder(data []byte, dt dataType) (*Decoder, error) { } } default: - return nil, fmt.Errorf("unexpected type of dec.orgIntf [%v]", t) + return nil, fmt.Errorf("unexpected type of unmashalled interface [%v]", t) } return &Decoder{ - dt: dt, - orgData: data, - orgIntf: intf, - strKeyMap: m, + typ: typ, + data: data, + intf: intf, + m: m, }, nil } -// FromJSON returns a concrete Decoder for JSON. -func FromJSON(data []byte) (*Decoder, error) { - return newDecoder(data, typeJSON) -} - -// FromYAML returns a concrete Decoder for YAML. -func FromYAML(data []byte) (*Decoder, error) { - return newDecoder(data, typeYAML) -} - -// FromHCL returns a concrete Decoder for HCL. -func FromHCL(data []byte) (*Decoder, error) { - return newDecoder(data, typeHCL) -} - -// FromXML returns a concrete Decoder for XML. -// FIXME: This function is still a future candidate (returned error now) -func FromXML(data []byte) (*Decoder, error) { - return newDecoder(data, end) // FIXME: "end" is provisional type -} - // JSONToGetter returns a structil.Getter with a decoded JSON via DynamicStruct. func JSONToGetter(data []byte, nest bool) (*structil.Getter, error) { d, err := FromJSON(data) @@ -105,6 +104,18 @@ func YAMLToGetter(data []byte, nest bool) (*structil.Getter, error) { // return d.dsToGetter(nest) // } +// DynamicStruct returns a decoded DynamicStruct with unmarshaling data to DynamicStruct interface. +func (d *Decoder) DynamicStruct(nest bool, useTag bool) (*dynamicstruct.DynamicStruct, error) { + var err error + + d.ds, err = d.toDsFromStringMap(d.m, nest, useTag) + if err != nil { + return nil, err + } + + return d.ds, err +} + func (d *Decoder) dsToGetter(nest bool) (*structil.Getter, error) { ds, err := d.DynamicStruct(nest, true) if err != nil { @@ -120,40 +131,20 @@ func (d *Decoder) dsToGetter(nest bool) (*structil.Getter, error) { } func (d *Decoder) decodeToDynamicStruct(ds *dynamicstruct.DynamicStruct) (interface{}, error) { - // must use "d.strKeyMap" (not "d.orgIntf"). because key of "d.orgIntf" is not string but interface{} - data, err := d.dt.marshal(d.strKeyMap) + data, err := d.typ.marshal(d.m) if err != nil { - return nil, fmt.Errorf("fail to d.dt.marshal: %w", err) + return nil, fmt.Errorf("fail to d.typ.marshal: %w", err) } - // must use "dsi" (not "&dsi"). because "dsi" is pointer // ds.NewInterface() returns a struct *pointer* - // FIXME: HCL decode method supports only struct pointer or map pointer dsi := ds.NewInterface() - err = d.dt.unmarshalWithPtr(data, dsi) - if err != nil { - return nil, fmt.Errorf("fail to d.dt.unmarshalWithPtr: %w", err) - } - - d.dsi = dsi - return d.dsi, nil -} - -// OrgData returns an original data as []byte. -func (d *Decoder) OrgData() []byte { - return d.orgData -} - -// DynamicStruct returns a decoded DynamicStruct with unmarshaling data to DynamicStruct interface. -func (d *Decoder) DynamicStruct(nest bool, useTag bool) (*dynamicstruct.DynamicStruct, error) { - var err error - - d.ds, err = d.toDsFromStringMap(d.strKeyMap, nest, useTag) + // must use "dsi" (not "&dsi"). because "dsi" is pointer + err = d.typ.unmarshalWithPtr(data, dsi) if err != nil { - return nil, err + return nil, fmt.Errorf("fail to d.typ.unmarshalWithPtr: %w", err) } - return d.ds, err + return dsi, nil } func (d *Decoder) toDsFromStringMap(m map[string]interface{}, nest bool, useTag bool) (*dynamicstruct.DynamicStruct, error) { @@ -170,7 +161,7 @@ func (d *Decoder) toDsFromStringMap(m map[string]interface{}, nest bool, useTag // See: https://golang.org/pkg/encoding/json/#Marshal // See: https://m-zajac.github.io/json2go/ if useTag { - tag = fmt.Sprintf(`%s:"%s"`, d.dt.string(), k) + tag = fmt.Sprintf(`%s:"%s"`, d.typ.string(), k) } // FIXME: the first character of k should be only alpha-numeric diff --git a/dynamicstruct/decoder/decoder_test.go b/dynamicstruct/decoder/decoder_test.go index 6e479eff..78955f05 100644 --- a/dynamicstruct/decoder/decoder_test.go +++ b/dynamicstruct/decoder/decoder_test.go @@ -16,314 +16,6 @@ const ( typeXML // FIXME ) -var ( - singleJSON = []byte(` -{ - "null_field":null, - "string_field":"かきくけこ", - "int_field":45678, - "float64_field":9.876, - "bool_field":false, - "struct_ptr_field":{ - "key":"hugakey", - "value":"hugavalue" - }, - "array_string_field":[ - "array_str_1", - "array_str_2" - ], - "array_struct_field":[ - { - "kkk":"kkk1", - "vvvv":"vvv1" - }, - { - "kkk":"kkk2", - "vvvv":"vvv2" - }, - { - "kkk":"kkk3", - "vvvv":"vvv3" - } - ] -} -`) - - arrayJSON = []byte(` -[ - { - "null_field":null, - "string_field":"かきくけこ", - "int_field":45678, - "float64_field":9.876, - "bool_field":false, - "struct_ptr_field":{ - "key":"hugakey", - "value":"hugavalue" - }, - "array_string_field":[ - "array_str_1", - "array_str_2" - ], - "array_struct_field":[ - { - "kkk":"kkk1", - "vvvv":"vvv1" - }, - { - "kkk":"kkk2", - "vvvv":"vvv2" - }, - { - "kkk":"kkk3", - "vvvv":"vvv3" - } - ] - }, - { - "null_field":null, - "string_field":"さしすせそ", - "int_field":7890, - "float64_field":4.99, - "bool_field":true, - "struct_ptr_field":{ - "key":"hugakeyXXX", - "value":"hugavalueXXX" - }, - "array_string_field":[ - "array_str_111", - "array_str_222" - ], - "array_struct_field":[ - { - "kkk":"kkk99", - "vvvv":"vvv99" - }, - { - "kkk":"kkk999", - "vvvv":"vvv999" - }, - { - "kkk":"kkk9999", - "vvvv":"vvv9999" - } - ] - } -] -`) - - singleYAML = []byte(` -null_field: null -string_field: かきくけこ -int_field: 45678 -float64_field: 9.876 -bool_field: false -struct_ptr_field: - key: hugakey - value: hugavalue -array_string_field: - - array_str_1 - - array_str_2 -array_struct_field: - - kkk: kkk1 - vvvv: vvv1 - - kkk: kkk2 - vvvv: vvv2 - - kkk: kkk3 - vvvv: vvv3 -`) - - arrayYAML = []byte(` -- null_field: null - string_field: かきくけこ - int_field: 45678 - float64_field: 9.876 - bool_field: false - struct_ptr_field: - key: hugakey - value: hugavalue - array_string_field: - - array_str_1 - - array_str_2 - array_struct_field: - - kkk: kkk1 - vvvv: vvv1 - - kkk: kkk2 - vvvv: vvv2 - - kkk: kkk3 - vvvv: vvv3 -- null_field: null - string_field: さしすせそ - int_field: 7890 - float64_field: 4.99 - bool_field: true - struct_ptr_field: - key: hugakeyXXX - value: hugavalueXXX - array_string_field: - - array_str_111 - - array_str_222 - array_struct_field: - - kkk: kkk99 - vvvv: vvv99 - - kkk: kkk999 - vvvv: vvv999 - - kkk: kkk9999 - vvvv: vvv9999 -`) - - //lint:ignore U1000 It's ok because this is for the future. - singleTOML = []byte(` -string_field = "かきくけこ," -int_field = 45678 -float64_field = "9.876," -bool_field = false -array_string_field = ["array_str_1", "array_str_2"] - -[struct_ptr_field] - key = "hugakey" - value = "hugavalue" - -[[array_struct_field]] - kkk = "kkk1" - vvvv = "vvv1" - -[[array_struct_field]] - kkk = "kkk2" - vvvv = "vvv2" - -[[array_struct_field]] - kkk = "kkk3" - vvvv = "vvv3" -`) - - //lint:ignore U1000 It's ok because this is for the future. - singleXML = []byte(` - - - - かきくけこ - 45678 - 9.876 - false - - hugakey - hugavalue - - array_str_1 - array_str_2 - - kkk1 - vvv1 - - - kkk2 - vvv2 - - - kkk3 - vvv3 - - -`) - - //lint:ignore U1000 It's ok because this is for the future. - arrayXML = []byte(` - - - <0> - - かきくけこ - 45678 - 9.876 - false - - hugakey - hugavalue - - array_str_1 - array_str_2 - - kkk1 - vvv1 - - - kkk2 - vvv2 - - - kkk3 - vvv3 - - - <1> - - さしすせそ - 7890 - 4.99 - true - - hugakeyXXX - hugavalueXXX - - array_str_111 - array_str_222 - - kkk99 - vvv99 - - - kkk999 - vvv999 - - - kkk9999 - vvv9999 - - - -`) - - //lint:ignore U1000 It's ok because this is for the future. - singleHCL = []byte(` -"null_field" = - -"string_field" = "かきくけこ," - -"int_field" = 45678 - -"float64_field" = "9.876," - -"bool_field" = false - -"struct_ptr_field" = { - "key" = "hugakey" - - "value" = "hugavalue" -} - -"array_string_field" = ["array_str_1", "array_str_2"] - -"array_struct_field" = { - "kkk" = "kkk1" - - "vvvv" = "vvv1" -} - -"array_struct_field" = { - "kkk" = "kkk2" - - "vvvv" = "vvv2" -} - -"array_struct_field" = { - "kkk" = "kkk3" - - "vvvv" = "vvv3" -} -`) -) - type decoderTest struct { name string data []byte @@ -1336,10 +1028,6 @@ bool_field: false func testCorrectCase(t *testing.T, tt decoderTest, dec *Decoder) { t.Helper() - if d := cmp.Diff(dec.OrgData(), tt.data); d != "" { - t.Fatalf("mismatch OrgData: (-got +want)\n%s", d) - } - ds, err := dec.DynamicStruct(tt.nest, tt.useTag) if err != nil { if !tt.wantErrorDs { From 70c0d3d4b75fdeb68c7f11b424d5a260cd65c540 Mon Sep 17 00:00:00 2001 From: goldeneggg Date: Wed, 12 Apr 2023 00:17:42 +0900 Subject: [PATCH 13/13] fix go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f305a754..96bec9bf 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/hashicorp/hcl/v2 v2.13.0 github.com/iancoleman/strcase v0.2.0 github.com/spf13/viper v1.12.0 + github.com/zclconf/go-cty v1.10.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -25,7 +26,6 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.0 // indirect - github.com/zclconf/go-cty v1.10.0 // indirect golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/text v0.3.8 // indirect gopkg.in/ini.v1 v1.66.6 // indirect