diff --git a/.changes/unreleased/BUG FIXES-20231220-133159.yaml b/.changes/unreleased/BUG FIXES-20231220-133159.yaml new file mode 100644 index 00000000..353b686a --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20231220-133159.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: Fixed a bug where schema defaults were not detected for integer/int32 properties +time: 2023-12-20T13:31:59.436063-05:00 +custom: + Issue: "111" diff --git a/go.mod b/go.mod index fdc822bb..d6307c4b 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/hashicorp/cli v1.1.6 github.com/hashicorp/terraform-plugin-codegen-spec v0.1.0 github.com/mattn/go-colorable v0.1.13 - github.com/pb33f/libopenapi v0.13.22 + github.com/pb33f/libopenapi v0.14.4 gopkg.in/yaml.v3 v3.0.1 ) @@ -16,7 +16,9 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/armon/go-radix v1.0.0 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/fatih/color v1.16.0 // indirect github.com/google/uuid v1.3.0 // indirect @@ -24,6 +26,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.15 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -31,6 +34,7 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect diff --git a/go.sum b/go.sum index 82c03afa..a3c278e8 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,12 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= 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= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -62,6 +66,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -69,6 +74,8 @@ 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -95,8 +102,10 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/pb33f/libopenapi v0.13.22 h1:QivxHLf+ZaYl2mFivUFkKZ7315mtYMipaQP5zp0U1H4= -github.com/pb33f/libopenapi v0.13.22/go.mod h1:Lv2eEtsAtbRFlF8hjH82L8SIGoUNgemMVoKoB6A9THk= +github.com/pb33f/libopenapi v0.14.3 h1:GeUaHFre9WiI5jHAg283HvBNdxhSKfFkNQikNAj2gqY= +github.com/pb33f/libopenapi v0.14.3/go.mod h1:m+4Pwri31UvcnZjuP8M7TlbR906DXJmMvYsbis234xg= +github.com/pb33f/libopenapi v0.14.4 h1:NbcYaBbG/6pnJM8lw4F6b5e54HandyKF452HUl4+9j4= +github.com/pb33f/libopenapi v0.14.4/go.mod h1:m+4Pwri31UvcnZjuP8M7TlbR906DXJmMvYsbis234xg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= @@ -116,10 +125,12 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go index bd20d3b1..160c383f 100644 --- a/internal/cmd/generate.go +++ b/internal/cmd/generate.go @@ -160,7 +160,7 @@ func (cmd *GenerateCommand) runInternal(logger *slog.Logger) error { } // 7. Log a warning if the provider code spec is not valid based on the JSON schema - err = spec.Validate(context.Background(), bytes) + err = spec.Validate(context.TODO(), bytes) if err != nil { logger.Warn( "generated provider code spec failed validation", diff --git a/internal/cmd/testdata/kubernetes/provider_code_spec.json b/internal/cmd/testdata/kubernetes/provider_code_spec.json index b85fc8c8..e3226431 100644 --- a/internal/cmd/testdata/kubernetes/provider_code_spec.json +++ b/internal/cmd/testdata/kubernetes/provider_code_spec.json @@ -755,7 +755,10 @@ { "name": "weight", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100." } } @@ -1033,7 +1036,10 @@ { "name": "weight", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "weight associated with matching the corresponding podAffinityTerm, in the range 1-100." } } @@ -1360,7 +1366,10 @@ { "name": "weight", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "weight associated with matching the corresponding podAffinityTerm, in the range 1-100." } } @@ -2087,7 +2096,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -2254,7 +2266,10 @@ { "name": "container_port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 \u003c x \u003c 65536." } }, @@ -2333,7 +2348,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -2795,7 +2813,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -3699,7 +3720,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -3866,7 +3890,10 @@ { "name": "container_port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 \u003c x \u003c 65536." } }, @@ -3945,7 +3972,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -4407,7 +4437,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -5332,7 +5365,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -5499,7 +5535,10 @@ { "name": "container_port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 \u003c x \u003c 65536." } }, @@ -5578,7 +5617,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -6040,7 +6082,10 @@ { "name": "port", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." } }, @@ -6851,7 +6896,10 @@ { "name": "max_skew", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed." } }, @@ -8185,7 +8233,10 @@ { "name": "lun", "int64": { - "computed_optional_required": "required", + "computed_optional_required": "computed_optional", + "default": { + "static": 0 + }, "description": "lun represents iSCSI Target Lun number." } }, diff --git a/internal/explorer/config_explorer.go b/internal/explorer/config_explorer.go index 48c731a4..d80debee 100644 --- a/internal/explorer/config_explorer.go +++ b/internal/explorer/config_explorer.go @@ -117,27 +117,29 @@ func extractOp(paths *high.Paths, oasLocation *config.OpenApiSpecLocation) (*hig return nil, nil } - if paths == nil || paths.PathItems == nil || paths.PathItems[oasLocation.Path] == nil { + if paths == nil || paths.PathItems == nil || paths.PathItems.GetOrZero(oasLocation.Path) == nil { return nil, fmt.Errorf("path '%s' not found in OpenAPI spec", oasLocation.Path) } + pathItem, _ := paths.PathItems.Get(oasLocation.Path) + switch strings.ToLower(oasLocation.Method) { case low.PostLabel: - return paths.PathItems[oasLocation.Path].Post, nil + return pathItem.Post, nil case low.GetLabel: - return paths.PathItems[oasLocation.Path].Get, nil + return pathItem.Get, nil case low.PutLabel: - return paths.PathItems[oasLocation.Path].Put, nil + return pathItem.Put, nil case low.DeleteLabel: - return paths.PathItems[oasLocation.Path].Delete, nil + return pathItem.Delete, nil case low.PatchLabel: - return paths.PathItems[oasLocation.Path].Patch, nil + return pathItem.Patch, nil case low.OptionsLabel: - return paths.PathItems[oasLocation.Path].Options, nil + return pathItem.Options, nil case low.HeadLabel: - return paths.PathItems[oasLocation.Path].Head, nil + return pathItem.Head, nil case low.TraceLabel: - return paths.PathItems[oasLocation.Path].Trace, nil + return pathItem.Trace, nil default: return nil, fmt.Errorf("method '%s' not found at OpenAPI path '%s'", oasLocation.Method, oasLocation.Path) } @@ -158,7 +160,7 @@ func extractSchemaProxy(document high.Document, componentRef string) (*highbase. } // populate low-level schema, using root document.Index for resolving - err = lowSchema.Build(context.Background(), indexRef.Node, document.Index) + err = lowSchema.Build(context.TODO(), indexRef.Node, document.Index) if err != nil { return nil, fmt.Errorf("error populating low-level schema: %w", err) } diff --git a/internal/explorer/config_explorer_test.go b/internal/explorer/config_explorer_test.go index ae499319..36fa2cf1 100644 --- a/internal/explorer/config_explorer_test.go +++ b/internal/explorer/config_explorer_test.go @@ -10,19 +10,21 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/config" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer" + "gopkg.in/yaml.v3" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/pb33f/libopenapi" "github.com/pb33f/libopenapi/datamodel/high/base" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) func Test_ConfigExplorer_FindResources(t *testing.T) { t.Parallel() testCases := map[string]struct { - pathItems map[string]*high.PathItem + pathItems *orderedmap.Map[string, *high.PathItem] config config.Config want map[string]explorer.Resource expectedErr error @@ -50,7 +52,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Post: &high.Operation{ Description: "create op here", @@ -71,7 +73,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { OperationId: "delete_resource", }, }, - }, + }), want: map[string]explorer.Resource{ "test_resource": { CreateOp: &high.Operation{ @@ -121,7 +123,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/one": { Options: &high.Operation{ Description: "create op here", @@ -144,7 +146,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { OperationId: "update_resource", }, }, - }, + }), want: map[string]explorer.Resource{ "test_resource": { CreateOp: &high.Operation{ @@ -182,7 +184,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{}, + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{}), expectedErr: errors.New(`failed to extract 'test_resource.create': path '/fakepath' not found in OpenAPI spec`), }, "non-existent read path throws error": { @@ -196,7 +198,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{}, + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{}), expectedErr: errors.New(`failed to extract 'test_resource.read': path '/fakepath' not found in OpenAPI spec`), }, "non-existent update path throws error": { @@ -210,7 +212,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{}, + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{}), expectedErr: errors.New(`failed to extract 'test_resource.update': path '/fakepath' not found in OpenAPI spec`), }, "non-existent delete path throws error": { @@ -224,7 +226,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{}, + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{}), expectedErr: errors.New(`failed to extract 'test_resource.delete': path '/fakepath' not found in OpenAPI spec`), }, "non-existent method throws error": { @@ -238,14 +240,14 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/{resource_id}": { Put: &high.Operation{ Description: "update op here", OperationId: "update_resource", }, }, - }, + }), expectedErr: errors.New(`failed to extract 'test_resource.update': method 'FAKE' not found at OpenAPI path '/resources/{resource_id}'`), }, "schema options pass-through": { @@ -276,7 +278,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Post: &high.Operation{ Description: "create op here", @@ -289,7 +291,7 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { OperationId: "read_resource", }, }, - }, + }), want: map[string]explorer.Resource{ "test_resource": { CreateOp: &high.Operation{ @@ -350,7 +352,7 @@ func Test_ConfigExplorer_FindDataSources(t *testing.T) { t.Parallel() testCases := map[string]struct { - pathItems map[string]*high.PathItem + pathItems *orderedmap.Map[string, *high.PathItem] config config.Config want map[string]explorer.DataSource expectedErr error @@ -366,14 +368,14 @@ func Test_ConfigExplorer_FindDataSources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/{resource_id}": { Get: &high.Operation{ Description: "read op here", OperationId: "read_resource", }, }, - }, + }), want: map[string]explorer.DataSource{ "test_resource": { ReadOp: &high.Operation{ @@ -399,14 +401,14 @@ func Test_ConfigExplorer_FindDataSources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/two/{resource_id}": { Head: &high.Operation{ Description: "read op here", OperationId: "read_resource", }, }, - }, + }), want: map[string]explorer.DataSource{ "test_resource": { ReadOp: &high.Operation{ @@ -432,7 +434,7 @@ func Test_ConfigExplorer_FindDataSources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{}, + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{}), expectedErr: errors.New(`failed to extract 'test_resource.read': path '/fakepath' not found in OpenAPI spec`), }, "non-existent method throws error": { @@ -446,14 +448,14 @@ func Test_ConfigExplorer_FindDataSources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/{resource_id}": { Get: &high.Operation{ Description: "read op here", OperationId: "read_resource", }, }, - }, + }), expectedErr: errors.New(`failed to extract 'test_resource.read': method 'FAKE' not found at OpenAPI path '/resources/{resource_id}'`), }, "schema options pass-through": { @@ -480,14 +482,14 @@ func Test_ConfigExplorer_FindDataSources(t *testing.T) { }, }, }, - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/{resource_id}": { Get: &high.Operation{ Description: "read op here", OperationId: "read_resource", }, }, - }, + }), want: map[string]explorer.DataSource{ "test_resource": { ReadOp: &high.Operation{ @@ -568,7 +570,7 @@ func Test_ConfigExplorer_FindProvider(t *testing.T) { expectedSchema: &base.Schema{ Type: []string{"object"}, Description: "This is the provider schema", - Extensions: map[string]any{}, + Extensions: orderedmap.ToOrderedMap(map[string]*yaml.Node{}), }, }, } @@ -609,7 +611,7 @@ func Test_ConfigExplorer_FindProvider(t *testing.T) { t.Fatalf("error building returned schema proxy: %s", err) } - if diff := cmp.Diff(gotSchema, testCase.expectedSchema, cmpopts.IgnoreUnexported(base.Schema{})); diff != "" { + if diff := cmp.Diff(gotSchema, testCase.expectedSchema, cmpopts.IgnoreUnexported(base.Schema{}), cmpopts.IgnoreFields(base.Schema{}, "Extensions")); diff != "" { t.Errorf("unexpected difference: %s", diff) } } diff --git a/internal/explorer/guesstimator_explorer.go b/internal/explorer/guesstimator_explorer.go index 8f281d83..bc29f5db 100644 --- a/internal/explorer/guesstimator_explorer.go +++ b/internal/explorer/guesstimator_explorer.go @@ -4,12 +4,14 @@ package explorer import ( + "context" "fmt" "path" "regexp" "strings" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) var _ Explorer = guesstimatorExplorer{} @@ -128,8 +130,8 @@ func (e guesstimatorExplorer) FindDataSources() (map[string]DataSource, error) { func (e guesstimatorExplorer) groupPathItems() map[string]resourceOperations { groups := map[string]resourceOperations{} - for name, pathItem := range e.spec.Paths.PathItems { - resource, isIdentity := convertPathToResourceName(name) + for pair := range orderedmap.Iterate(context.TODO(), e.spec.Paths.PathItems) { + resource, isIdentity := convertPathToResourceName(pair.Key()) _, ok := groups[resource] if !ok { @@ -139,12 +141,12 @@ func (e guesstimatorExplorer) groupPathItems() map[string]resourceOperations { } } - ops := pathItem.GetOperations() - for opName, op := range ops { + ops := pair.Value().GetOperations() + for opPair := range orderedmap.Iterate(context.TODO(), ops) { if isIdentity { - groups[resource].IdentityOps[opName] = op + groups[resource].IdentityOps[opPair.Key()] = opPair.Value() } else { - groups[resource].CollectionOps[opName] = op + groups[resource].CollectionOps[opPair.Key()] = opPair.Value() } } } diff --git a/internal/explorer/guesstimator_explorer_test.go b/internal/explorer/guesstimator_explorer_test.go index 6980f622..0c42c7b7 100644 --- a/internal/explorer/guesstimator_explorer_test.go +++ b/internal/explorer/guesstimator_explorer_test.go @@ -9,17 +9,18 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) func Test_GuesstimatorExplorer_FindResources(t *testing.T) { t.Parallel() testCases := map[string]struct { - pathItems map[string]*high.PathItem + pathItems *orderedmap.Map[string, *high.PathItem] expectedResources []string }{ "valid flat resource combo": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Post: &high.Operation{}, }, @@ -27,11 +28,11 @@ func Test_GuesstimatorExplorer_FindResources(t *testing.T) { Get: &high.Operation{}, Delete: &high.Operation{}, }, - }, + }), expectedResources: []string{"resources"}, }, "valid nested resource combo": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/verycool/verynice/resources": { Post: &high.Operation{}, }, @@ -39,11 +40,11 @@ func Test_GuesstimatorExplorer_FindResources(t *testing.T) { Get: &high.Operation{}, Delete: &high.Operation{}, }, - }, + }), expectedResources: []string{"verycool_verynice_resources"}, }, "valid nested with id resource combo": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/verycool/{id}/verynice/resources": { Post: &high.Operation{}, }, @@ -51,45 +52,45 @@ func Test_GuesstimatorExplorer_FindResources(t *testing.T) { Get: &high.Operation{}, Delete: &high.Operation{}, }, - }, + }), expectedResources: []string{"verycool_verynice_resources"}, }, "invalid resource combo - POST,DELETEbyID": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Post: &high.Operation{}, }, "/resources/{resource_id}": { Delete: &high.Operation{}, }, - }, + }), expectedResources: []string{}, }, "invalid resource combo - GETbyID,DELETEbyID": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources/{resource_id}": { Get: &high.Operation{}, Delete: &high.Operation{}, }, - }, + }), expectedResources: []string{}, }, "invalid resource combo - GETbyID,POST": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Post: &high.Operation{}, }, "/resources/{resource_id}": { Get: &high.Operation{}, }, - }, + }), expectedResources: []string{}, }, "invalid resource combo - no ops": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": {}, "/resources/{resource_id}": {}, - }, + }), expectedResources: []string{}, }, } @@ -124,22 +125,22 @@ func Test_GuesstimatorExplorer_FindDataSources(t *testing.T) { t.Parallel() testCases := map[string]struct { - pathItems map[string]*high.PathItem + pathItems *orderedmap.Map[string, *high.PathItem] expectedDataSources []string }{ "valid flat data source combo": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Get: &high.Operation{}, }, "/resources/{resource_id}": { Get: &high.Operation{}, }, - }, + }), expectedDataSources: []string{"resources_collection", "resources_by_id"}, }, "valid nested data source combo": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/verycool/verynice/resources": { Post: &high.Operation{}, }, @@ -147,11 +148,11 @@ func Test_GuesstimatorExplorer_FindDataSources(t *testing.T) { Get: &high.Operation{}, Delete: &high.Operation{}, }, - }, + }), expectedDataSources: []string{"verycool_verynice_resources_by_id"}, }, "valid nested with id data source combo": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/verycool/{id}/verynice/resources": { Get: &high.Operation{}, Post: &high.Operation{}, @@ -159,11 +160,11 @@ func Test_GuesstimatorExplorer_FindDataSources(t *testing.T) { "/verycool/{id}/verynice/resources/{resource_id}": { Delete: &high.Operation{}, }, - }, + }), expectedDataSources: []string{"verycool_verynice_resources_collection"}, }, "invalid data source combo - no matching ops": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": { Put: &high.Operation{}, Post: &high.Operation{}, @@ -182,14 +183,14 @@ func Test_GuesstimatorExplorer_FindDataSources(t *testing.T) { Patch: &high.Operation{}, Trace: &high.Operation{}, }, - }, + }), expectedDataSources: []string{}, }, "invalid data source combo - no ops": { - pathItems: map[string]*high.PathItem{ + pathItems: orderedmap.ToOrderedMap(map[string]*high.PathItem{ "/resources": {}, "/resources/{resource_id}": {}, - }, + }), expectedDataSources: []string{}, }, } diff --git a/internal/mapper/datasource_mapper.go b/internal/mapper/datasource_mapper.go index 5956de18..591ae882 100644 --- a/internal/mapper/datasource_mapper.go +++ b/internal/mapper/datasource_mapper.go @@ -126,7 +126,7 @@ func generateDataSourceSchema(logger *slog.Logger, name string, dataSource explo } computability := schema.ComputedOptional - if param.Required { + if param.Required != nil && *param.Required { computability = schema.Required } diff --git a/internal/mapper/datasource_mapper_test.go b/internal/mapper/datasource_mapper_test.go index 76f14977..55c9a2df 100644 --- a/internal/mapper/datasource_mapper_test.go +++ b/internal/mapper/datasource_mapper_test.go @@ -17,6 +17,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) func TestDataSourceMapper_basic_merges(t *testing.T) { @@ -32,7 +33,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { readParams: []*high.Parameter{ { Name: "string_prop", - Required: true, + Required: pointer(true), In: "path", Description: "hey this is a string, required and overidden!", Schema: base.CreateSchemaProxy(&base.Schema{ @@ -43,7 +44,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, { Name: "bool_prop", - Required: true, + Required: pointer(true), In: "query", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, @@ -62,7 +63,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -71,7 +72,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), want: datasource.Attributes{ { @@ -110,17 +111,17 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { { Name: "nested_object_one", In: "query", - Required: true, + Required: pointer(true), Description: "hey this is an object, required + overidden!", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "you shouldn't see this because the description is overridden!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_object_two": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop"}, Description: "hey this is an object!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -129,19 +130,19 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is a integer!", }), - }, + }), }), - }, + }), }), }, }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_object_one": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "this one already exists, so you shouldn't see this description!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Format: util.OAS_format_password, @@ -150,7 +151,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { "nested_object_two": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "this one already exists, so you shouldn't see this description!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -159,11 +160,11 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), - }, + }), }), - }, + }), }), want: datasource.Attributes{ { @@ -220,7 +221,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { { Name: "array_prop", In: "query", - Required: true, + Required: pointer(true), Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array, required!", @@ -228,7 +229,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_array_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is a nested array, required!", @@ -236,7 +237,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"super_nested_bool_two"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "super_nested_bool_one": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a boolean!", @@ -249,7 +250,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is a integer!", }), - }, + }), }), }, }), @@ -257,7 +258,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), }, }), @@ -265,7 +266,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array!", @@ -273,7 +274,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_array_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -285,20 +286,20 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "super_nested_string": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Description: "hey this is a string!", }), - }, + }), }), }, }), - }, + }), }), }, }), - }, + }), }), want: datasource.Attributes{ { @@ -381,26 +382,26 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_list": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_object": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), - }, + }), }), - }, + }), }), }, }), - }, + }), }), }, }), @@ -410,7 +411,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array!", @@ -420,22 +421,22 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_list": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_object": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_string": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), - }, + }), }), }, }), @@ -445,13 +446,13 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { "deep_nested_int64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, }), - }, + }), }), }, }), }, }), - }, + }), }), want: datasource.Attributes{ { @@ -511,7 +512,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { readParams: []*high.Parameter{ { Name: "read_parameter_optional_read_parameter_only", - Required: false, + Required: pointer(false), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -519,7 +520,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, { Name: "read_parameter_optional_read_response", - Required: false, + Required: pointer(false), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -527,7 +528,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, { Name: "read_parameter_required_read_parameter_only", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -535,7 +536,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, { Name: "read_parameter_required_read_response", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -544,7 +545,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ // Simulate API returning parameter in response "read_parameter_optional_read_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -556,7 +557,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { "read_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), want: datasource.Attributes{ { @@ -595,7 +596,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { readParams: []*high.Parameter{ { Name: "read_path_parameter", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -603,7 +604,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, { Name: "read_query_parameter", - Required: false, + Required: pointer(false), In: "query", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, @@ -612,14 +613,14 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "attribute_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), "attribute_computed_optional": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), - }, + }), }), schemaOptions: explorer.SchemaOptions{ AttributeOptions: explorer.AttributeOptions{ @@ -656,7 +657,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { readParams: []*high.Parameter{ { Name: "bool_prop", - Required: true, + Required: pointer(true), In: "query", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, @@ -675,7 +676,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -686,7 +687,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { }), "nested_obj": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -695,7 +696,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"string"}, Description: "hey this is a string!", }), - }, + }), }), "nested_array": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, @@ -706,14 +707,14 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "deep_nested_int64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, }), - }, + }), }), }, }), @@ -725,7 +726,7 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), @@ -733,11 +734,11 @@ func TestDataSourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is an int64!", }), - }, + }), }), }, }), - }, + }), }), want: datasource.Attributes{ { @@ -851,7 +852,7 @@ func TestDataSourceMapper_collections(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -860,7 +861,7 @@ func TestDataSourceMapper_collections(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), }, }), @@ -898,7 +899,7 @@ func TestDataSourceMapper_collections(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -907,7 +908,7 @@ func TestDataSourceMapper_collections(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), }, }), diff --git a/internal/mapper/oas/attribute.go b/internal/mapper/oas/attribute.go index f3a01fac..d0464b60 100644 --- a/internal/mapper/oas/attribute.go +++ b/internal/mapper/oas/attribute.go @@ -4,25 +4,27 @@ package oas import ( + "context" "fmt" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/attrmapper" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" + "github.com/pb33f/libopenapi/orderedmap" ) func (s *OASSchema) BuildResourceAttributes() (attrmapper.ResourceAttributes, *SchemaError) { objectAttributes := attrmapper.ResourceAttributes{} - // Guarantee the order of processing - propertyNames := util.SortedKeys(s.Schema.Properties) - for _, name := range propertyNames { + sortedProperties := orderedmap.SortAlpha(s.Schema.Properties) + for pair := range orderedmap.Iterate(context.TODO(), sortedProperties) { + name := pair.Key() if s.IsPropertyIgnored(name) { continue } - pProxy := s.Schema.Properties[name] + pProxy := pair.Value() schemaOpts := SchemaOpts{ Ignores: s.GetIgnoresForNested(name), } @@ -72,15 +74,15 @@ func (s *OASSchema) BuildResourceAttribute(name string, computability schema.Com func (s *OASSchema) BuildDataSourceAttributes() (attrmapper.DataSourceAttributes, *SchemaError) { objectAttributes := attrmapper.DataSourceAttributes{} - // Guarantee the order of processing - propertyNames := util.SortedKeys(s.Schema.Properties) - for _, name := range propertyNames { + sortedProperties := orderedmap.SortAlpha(s.Schema.Properties) + for pair := range orderedmap.Iterate(context.TODO(), sortedProperties) { + name := pair.Key() if s.IsPropertyIgnored(name) { continue } - pProxy := s.Schema.Properties[name] + pProxy := pair.Value() schemaOpts := SchemaOpts{ Ignores: s.GetIgnoresForNested(name), } @@ -130,15 +132,15 @@ func (s *OASSchema) BuildDataSourceAttribute(name string, computability schema.C func (s *OASSchema) BuildProviderAttributes() (attrmapper.ProviderAttributes, *SchemaError) { objectAttributes := attrmapper.ProviderAttributes{} - // Guarantee the order of processing - propertyNames := util.SortedKeys(s.Schema.Properties) - for _, name := range propertyNames { + sortedProperties := orderedmap.SortAlpha(s.Schema.Properties) + for pair := range orderedmap.Iterate(context.TODO(), sortedProperties) { + name := pair.Key() if s.IsPropertyIgnored(name) { continue } - pProxy := s.Schema.Properties[name] + pProxy := pair.Value() schemaOpts := SchemaOpts{ Ignores: s.GetIgnoresForNested(name), } diff --git a/internal/mapper/oas/bool.go b/internal/mapper/oas/bool.go index c3a27a79..fe69e7fa 100644 --- a/internal/mapper/oas/bool.go +++ b/internal/mapper/oas/bool.go @@ -22,9 +22,8 @@ func (s *OASSchema) BuildBoolResource(name string, computability schema.Computed } if s.Schema.Default != nil { - staticDefault, ok := s.Schema.Default.(bool) - - if ok { + var staticDefault bool + if err := s.Schema.Default.Decode(&staticDefault); err == nil { if computability == schema.Required { result.ComputedOptionalRequired = schema.ComputedOptional } diff --git a/internal/mapper/oas/bool_test.go b/internal/mapper/oas/bool_test.go index 3412ad93..7904edcb 100644 --- a/internal/mapper/oas/bool_test.go +++ b/internal/mapper/oas/bool_test.go @@ -12,9 +12,11 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" + "gopkg.in/yaml.v3" "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) func TestBuildBoolResource(t *testing.T) { @@ -28,7 +30,7 @@ func TestBuildBoolResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey there! I'm a bool type.", @@ -37,7 +39,7 @@ func TestBuildBoolResource(t *testing.T) { Type: []string{"boolean"}, Description: "hey there! I'm a bool type, required.", }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceBoolAttribute{ @@ -60,20 +62,20 @@ func TestBuildBoolResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_prop_required_default_true"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop_default_false": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, - Default: false, + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "false"}, }), "bool_prop_default_true": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, - Default: true, + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "true"}, }), "bool_prop_required_default_true": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, - Default: true, + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "true"}, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceBoolAttribute{ @@ -109,12 +111,12 @@ func TestBuildBoolResource(t *testing.T) { "boolean attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceBoolAttribute{ @@ -130,7 +132,7 @@ func TestBuildBoolResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of bools.", @@ -149,7 +151,7 @@ func TestBuildBoolResource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -206,7 +208,7 @@ func TestBuildBoolDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey there! I'm a bool type.", @@ -215,7 +217,7 @@ func TestBuildBoolDataSource(t *testing.T) { Type: []string{"boolean"}, Description: "hey there! I'm a bool type, required.", }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceBoolAttribute{ @@ -237,12 +239,12 @@ func TestBuildBoolDataSource(t *testing.T) { "boolean attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceBoolAttribute{ @@ -258,7 +260,7 @@ func TestBuildBoolDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of bools.", @@ -277,7 +279,7 @@ func TestBuildBoolDataSource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -334,7 +336,7 @@ func TestBuildBoolProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey there! I'm a bool type.", @@ -343,7 +345,7 @@ func TestBuildBoolProvider(t *testing.T) { Type: []string{"boolean"}, Description: "hey there! I'm a bool type, required.", }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderBoolAttribute{ @@ -365,12 +367,12 @@ func TestBuildBoolProvider(t *testing.T) { "boolean attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderBoolAttribute{ @@ -386,7 +388,7 @@ func TestBuildBoolProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"bool_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of bools.", @@ -405,7 +407,7 @@ func TestBuildBoolProvider(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ diff --git a/internal/mapper/oas/build.go b/internal/mapper/oas/build.go index b5ae6401..bd763dfd 100644 --- a/internal/mapper/oas/build.go +++ b/internal/mapper/oas/build.go @@ -4,6 +4,7 @@ package oas import ( + "context" "errors" "fmt" "strconv" @@ -12,6 +13,7 @@ import ( "github.com/pb33f/libopenapi/datamodel/high/base" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) var ErrMultiTypeSchema = errors.New("unsupported multi-type, attribute cannot be created") @@ -20,7 +22,7 @@ var ErrSchemaNotFound = errors.New("no compatible schema found") // BuildSchemaFromRequest will extract and build the schema from the request body of an operation // - Media type will default to "application/json", then continue to the next available media type with a schema func BuildSchemaFromRequest(op *high.Operation, schemaOpts SchemaOpts, globalOpts GlobalSchemaOpts) (*OASSchema, error) { - if op == nil || op.RequestBody == nil || len(op.RequestBody.Content) == 0 { + if op == nil || op.RequestBody == nil || op.RequestBody.Content == nil || op.RequestBody.Content.Len() == 0 { return nil, ErrSchemaNotFound } @@ -31,25 +33,24 @@ func BuildSchemaFromRequest(op *high.Operation, schemaOpts SchemaOpts, globalOpt // - Response codes of 200 and then 201 will be prioritized, then will continue to the next available 2xx code // - Media type will default to "application/json", then continue to the next available media type with a schema func BuildSchemaFromResponse(op *high.Operation, schemaOpts SchemaOpts, globalOpts GlobalSchemaOpts) (*OASSchema, error) { - if op == nil || op.Responses == nil || len(op.Responses.Codes) == 0 { + if op == nil || op.Responses == nil || op.Responses.Codes == nil || op.Responses.Codes.Len() == 0 { return nil, ErrSchemaNotFound } - okResponse, ok := op.Responses.Codes[util.OAS_response_code_ok] + okResponse, ok := op.Responses.Codes.Get(util.OAS_response_code_ok) if ok { return getSchemaFromMediaType(okResponse.Content, schemaOpts, globalOpts) } - createdResponse, ok := op.Responses.Codes[util.OAS_response_code_created] + createdResponse, ok := op.Responses.Codes.Get(util.OAS_response_code_created) if ok { return getSchemaFromMediaType(createdResponse.Content, schemaOpts, globalOpts) } - // Guarantee the order of processing - codes := util.SortedKeys(op.Responses.Codes) - for _, code := range codes { - responseCode := op.Responses.Codes[code] - statusCode, err := strconv.Atoi(code) + sortedCodes := orderedmap.SortAlpha(op.Responses.Codes) + for pair := range orderedmap.Iterate(context.TODO(), sortedCodes) { + responseCode := pair.Value() + statusCode, err := strconv.Atoi(pair.Key()) if err != nil { continue } @@ -62,8 +63,12 @@ func BuildSchemaFromResponse(op *high.Operation, schemaOpts SchemaOpts, globalOp return nil, ErrSchemaNotFound } -func getSchemaFromMediaType(mediaTypes map[string]*high.MediaType, schemaOpts SchemaOpts, globalOpts GlobalSchemaOpts) (*OASSchema, error) { - jsonMediaType, ok := mediaTypes[util.OAS_mediatype_json] +func getSchemaFromMediaType(mediaTypes *orderedmap.Map[string, *high.MediaType], schemaOpts SchemaOpts, globalOpts GlobalSchemaOpts) (*OASSchema, error) { + if mediaTypes == nil { + return nil, ErrSchemaNotFound + } + + jsonMediaType, ok := mediaTypes.Get(util.OAS_mediatype_json) if ok && jsonMediaType.Schema != nil { s, err := BuildSchema(jsonMediaType.Schema, schemaOpts, globalOpts) if err != nil { @@ -72,10 +77,9 @@ func getSchemaFromMediaType(mediaTypes map[string]*high.MediaType, schemaOpts Sc return s, nil } - // Guarantee the order of processing - mediaTypeKeys := util.SortedKeys(mediaTypes) - for _, key := range mediaTypeKeys { - mediaType := mediaTypes[key] + sortedMediaTypes := orderedmap.SortAlpha(mediaTypes) + for pair := range orderedmap.Iterate(context.TODO(), sortedMediaTypes) { + mediaType := pair.Value() if mediaType.Schema != nil { s, err := BuildSchema(mediaType.Schema, schemaOpts, globalOpts) if err != nil { @@ -226,7 +230,7 @@ func retrieveType(schema *base.Schema) (string, *SchemaError) { case 0: // Properties are only valid applying to objects, it's possible tools might omit the type // https://github.com/hashicorp/terraform-plugin-codegen-openapi/issues/79 - if len(schema.Properties) > 0 { + if schema.Properties != nil && schema.Properties.Len() > 0 { return util.OAS_type_object, nil } diff --git a/internal/mapper/oas/build_test.go b/internal/mapper/oas/build_test.go index 19738ce7..7736170e 100644 --- a/internal/mapper/oas/build_test.go +++ b/internal/mapper/oas/build_test.go @@ -16,6 +16,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/pb33f/libopenapi/datamodel/high/base" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) func TestBuildSchemaFromRequest(t *testing.T) { @@ -28,7 +29,7 @@ func TestBuildSchemaFromRequest(t *testing.T) { "default to application/json": { op: &high.Operation{ RequestBody: &high.RequestBody{ - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/xml": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", @@ -41,7 +42,7 @@ func TestBuildSchemaFromRequest(t *testing.T) { Type: []string{"string"}, }), }, - }, + }), }, }, expectedSchema: &oas.OASSchema{ @@ -55,7 +56,7 @@ func TestBuildSchemaFromRequest(t *testing.T) { "utilizes other media types in sorted order": { op: &high.Operation{ RequestBody: &high.RequestBody{ - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/xml": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this won't be used because of sorting!", @@ -68,7 +69,7 @@ func TestBuildSchemaFromRequest(t *testing.T) { Type: []string{"string"}, }), }, - }, + }), }, }, expectedSchema: &oas.OASSchema{ @@ -82,7 +83,7 @@ func TestBuildSchemaFromRequest(t *testing.T) { "utilizes other media types when nil schemas in priority media types": { op: &high.Operation{ RequestBody: &high.RequestBody{ - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: nil, }, @@ -95,7 +96,7 @@ func TestBuildSchemaFromRequest(t *testing.T) { Type: []string{"string"}, }), }, - }, + }), }, }, expectedSchema: &oas.OASSchema{ @@ -152,14 +153,14 @@ func TestBuildSchemaFromRequest_Errors(t *testing.T) { "no media type schemas": { op: &high.Operation{ RequestBody: &high.RequestBody{ - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: nil, }, "application/xml": { Schema: nil, }, - }, + }), }, }, expectedErrRegex: oas.ErrSchemaNotFound.Error(), @@ -196,19 +197,19 @@ func TestBuildSchemaFromResponse(t *testing.T) { "default to 200 and application/json": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "201": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", Type: []string{"boolean"}, }), }, - }, + }), }, "200": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/xml": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", @@ -221,9 +222,9 @@ func TestBuildSchemaFromResponse(t *testing.T) { Type: []string{"string"}, }), }, - }, + }), }, - }, + }), }, }, expectedSchema: &oas.OASSchema{ @@ -237,19 +238,19 @@ func TestBuildSchemaFromResponse(t *testing.T) { "fallback to 201 and application/json": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "204": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", Type: []string{"boolean"}, }), }, - }, + }), }, "201": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/xml": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", @@ -262,9 +263,9 @@ func TestBuildSchemaFromResponse(t *testing.T) { Type: []string{"string"}, }), }, - }, + }), }, - }, + }), }, }, expectedSchema: &oas.OASSchema{ @@ -278,19 +279,19 @@ func TestBuildSchemaFromResponse(t *testing.T) { "fallback to success code and any media type in sorted order": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "304": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", Type: []string{"boolean"}, }), }, - }, + }), }, "204": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/xml": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this is the wrong one!", @@ -303,9 +304,9 @@ func TestBuildSchemaFromResponse(t *testing.T) { Type: []string{"string"}, }), }, - }, + }), }, - }, + }), }, }, expectedSchema: &oas.OASSchema{ @@ -362,38 +363,38 @@ func TestBuildSchemaFromResponse_Errors(t *testing.T) { "no success response code media type schemas": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "300": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this won't be used!", Type: []string{"string"}, }), }, - }, + }), }, "skip-me!": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this won't be used!", Type: []string{"string"}, }), }, - }, + }), }, "199": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: base.CreateSchemaProxy(&base.Schema{ Description: "this won't be used!", Type: []string{"string"}, }), }, - }, + }), }, - }, + }), }, }, expectedErrRegex: oas.ErrSchemaNotFound.Error(), @@ -401,15 +402,15 @@ func TestBuildSchemaFromResponse_Errors(t *testing.T) { "200 response code with no valid schema": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "200": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: nil, }, - }, + }), }, - }, + }), }, }, expectedErrRegex: oas.ErrSchemaNotFound.Error(), @@ -417,15 +418,15 @@ func TestBuildSchemaFromResponse_Errors(t *testing.T) { "201 response code with no valid schema": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "201": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: nil, }, - }, + }), }, - }, + }), }, }, expectedErrRegex: oas.ErrSchemaNotFound.Error(), @@ -433,15 +434,15 @@ func TestBuildSchemaFromResponse_Errors(t *testing.T) { "success response code with no valid schema": { op: &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "204": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: nil, }, - }, + }), }, - }, + }), }, }, expectedErrRegex: oas.ErrSchemaNotFound.Error(), @@ -478,7 +479,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nullable_string_two"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nullable_string_one": base.CreateSchemaProxy(&base.Schema{ Type: []string{"null", "string"}, Description: "hey there! I'm a nullable string type.", @@ -487,7 +488,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { Type: []string{"string", "null"}, Description: "hey there! I'm a nullable string type, required.", }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -510,7 +511,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"stringable_number", "stringable_bool"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "stringable_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string", "boolean"}, Description: "hey there! I'm a stringable bool type, required.", @@ -523,7 +524,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { Type: []string{"string", "number"}, Description: "hey there! I'm a stringable number type, required.", }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -553,7 +554,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nullable_string_two"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nullable_string_one": base.CreateSchemaProxy(&base.Schema{ AnyOf: []*base.SchemaProxy{ base.CreateSchemaProxy(&base.Schema{ @@ -576,7 +577,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -599,7 +600,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"stringable_number", "stringable_bool"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "stringable_bool": base.CreateSchemaProxy(&base.Schema{ AnyOf: []*base.SchemaProxy{ base.CreateSchemaProxy(&base.Schema{ @@ -633,7 +634,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -663,7 +664,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nullable_string_two"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nullable_string_one": base.CreateSchemaProxy(&base.Schema{ OneOf: []*base.SchemaProxy{ base.CreateSchemaProxy(&base.Schema{ @@ -686,7 +687,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -709,7 +710,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"stringable_number", "stringable_bool"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "stringable_bool": base.CreateSchemaProxy(&base.Schema{ OneOf: []*base.SchemaProxy{ base.CreateSchemaProxy(&base.Schema{ @@ -743,7 +744,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -773,7 +774,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"string_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of nullable strings.", @@ -792,7 +793,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -821,7 +822,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"string_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of nullable strings.", @@ -854,7 +855,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -883,7 +884,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"string_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of nullable strings.", @@ -916,7 +917,7 @@ func TestBuildSchema_MultiTypes(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -978,12 +979,12 @@ func TestBuildSchema_AllOfSchemaComposition(t *testing.T) { AllOf: []*base.SchemaProxy{ base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_object": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"string"}, Description: "hey there! I'm an object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey there! I'm a bool type.", @@ -992,9 +993,9 @@ func TestBuildSchema_AllOfSchemaComposition(t *testing.T) { Type: []string{"string"}, Description: "hey there! I'm a string type, required.", }), - }, + }), }), - }, + }), }), }, }), @@ -1028,7 +1029,7 @@ func TestBuildSchema_AllOfSchemaComposition(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"string_allof_override"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_allof_override": base.CreateSchemaProxy(&base.Schema{ Description: "Override the bool's description", AllOf: []*base.SchemaProxy{ @@ -1047,7 +1048,7 @@ func TestBuildSchema_AllOfSchemaComposition(t *testing.T) { }), }, }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceBoolAttribute{ @@ -1216,7 +1217,7 @@ func TestBuildSchema_EdgeCases(t *testing.T) { schemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{}, Required: []string{"string", "object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Description: "hey there! I'm a string type, required.", @@ -1225,14 +1226,14 @@ func TestBuildSchema_EdgeCases(t *testing.T) { Type: []string{}, Required: []string{"bool"}, Description: "hey there! I'm an object type, required.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey there! I'm a bool type, required.", }), - }, + }), }), - }, + }), }), expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSingleNestedAttribute{ diff --git a/internal/mapper/oas/collection_test.go b/internal/mapper/oas/collection_test.go index a5742c59..f30d2970 100644 --- a/internal/mapper/oas/collection_test.go +++ b/internal/mapper/oas/collection_test.go @@ -16,6 +16,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) // TODO: add error tests @@ -31,7 +32,7 @@ func TestBuildCollectionResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list nested array type, required.", @@ -39,7 +40,7 @@ func TestBuildCollectionResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -50,11 +51,11 @@ func TestBuildCollectionResource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListNestedAttribute{ @@ -87,7 +88,7 @@ func TestBuildCollectionResource(t *testing.T) { "list nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Deprecated: pointer(true), @@ -95,16 +96,16 @@ func TestBuildCollectionResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListNestedAttribute{ @@ -130,7 +131,7 @@ func TestBuildCollectionResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, MinItems: pointer(int64(1)), @@ -138,16 +139,16 @@ func TestBuildCollectionResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListNestedAttribute{ @@ -184,7 +185,7 @@ func TestBuildCollectionResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -193,7 +194,7 @@ func TestBuildCollectionResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -204,11 +205,11 @@ func TestBuildCollectionResource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSetNestedAttribute{ @@ -241,7 +242,7 @@ func TestBuildCollectionResource(t *testing.T) { "set nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -250,16 +251,16 @@ func TestBuildCollectionResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSetNestedAttribute{ @@ -285,7 +286,7 @@ func TestBuildCollectionResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -294,16 +295,16 @@ func TestBuildCollectionResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSetNestedAttribute{ @@ -340,7 +341,7 @@ func TestBuildCollectionResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of lists.", @@ -350,7 +351,7 @@ func TestBuildCollectionResource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -359,7 +360,7 @@ func TestBuildCollectionResource(t *testing.T) { Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), @@ -374,20 +375,20 @@ func TestBuildCollectionResource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -446,7 +447,7 @@ func TestBuildCollectionResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -458,7 +459,7 @@ func TestBuildCollectionResource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -467,7 +468,7 @@ func TestBuildCollectionResource(t *testing.T) { Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), @@ -484,20 +485,20 @@ func TestBuildCollectionResource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSetAttribute{ @@ -555,7 +556,7 @@ func TestBuildCollectionResource(t *testing.T) { "list and set attribute - nested map results in element type": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "list_with_map": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list with a nested map of objects.", @@ -565,7 +566,7 @@ func TestBuildCollectionResource(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_boolean": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "this won't be added, since it will map to element type", @@ -574,7 +575,7 @@ func TestBuildCollectionResource(t *testing.T) { Type: []string{"string"}, Description: "this won't be added, since it will map to element type", }), - }, + }), }), }, }), @@ -590,7 +591,7 @@ func TestBuildCollectionResource(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -601,13 +602,13 @@ func TestBuildCollectionResource(t *testing.T) { Format: "int64", Description: "this won't be added, since it will map to element type", }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -694,7 +695,7 @@ func TestBuildCollectionDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list nested array type, required.", @@ -702,7 +703,7 @@ func TestBuildCollectionDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -713,11 +714,11 @@ func TestBuildCollectionDataSource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListNestedAttribute{ @@ -750,7 +751,7 @@ func TestBuildCollectionDataSource(t *testing.T) { "list nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Deprecated: pointer(true), @@ -758,16 +759,16 @@ func TestBuildCollectionDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListNestedAttribute{ @@ -793,7 +794,7 @@ func TestBuildCollectionDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, MinItems: pointer(int64(1)), @@ -801,16 +802,16 @@ func TestBuildCollectionDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListNestedAttribute{ @@ -847,7 +848,7 @@ func TestBuildCollectionDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -856,7 +857,7 @@ func TestBuildCollectionDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -867,11 +868,11 @@ func TestBuildCollectionDataSource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceSetNestedAttribute{ @@ -904,7 +905,7 @@ func TestBuildCollectionDataSource(t *testing.T) { "set nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -913,16 +914,16 @@ func TestBuildCollectionDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceSetNestedAttribute{ @@ -948,7 +949,7 @@ func TestBuildCollectionDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -957,16 +958,16 @@ func TestBuildCollectionDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceSetNestedAttribute{ @@ -1003,7 +1004,7 @@ func TestBuildCollectionDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of lists.", @@ -1013,7 +1014,7 @@ func TestBuildCollectionDataSource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1022,7 +1023,7 @@ func TestBuildCollectionDataSource(t *testing.T) { Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), @@ -1037,20 +1038,20 @@ func TestBuildCollectionDataSource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -1109,7 +1110,7 @@ func TestBuildCollectionDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -1121,7 +1122,7 @@ func TestBuildCollectionDataSource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1130,7 +1131,7 @@ func TestBuildCollectionDataSource(t *testing.T) { Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), @@ -1147,20 +1148,20 @@ func TestBuildCollectionDataSource(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceSetAttribute{ @@ -1218,7 +1219,7 @@ func TestBuildCollectionDataSource(t *testing.T) { "list and set attribute - nested map results in element type": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "list_with_map": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list with a nested map of objects.", @@ -1228,7 +1229,7 @@ func TestBuildCollectionDataSource(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_boolean": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "this won't be added, since it will map to element type", @@ -1237,7 +1238,7 @@ func TestBuildCollectionDataSource(t *testing.T) { Type: []string{"string"}, Description: "this won't be added, since it will map to element type", }), - }, + }), }), }, }), @@ -1253,7 +1254,7 @@ func TestBuildCollectionDataSource(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1264,13 +1265,13 @@ func TestBuildCollectionDataSource(t *testing.T) { Format: "int64", Description: "this won't be added, since it will map to element type", }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -1357,7 +1358,7 @@ func TestBuildCollectionProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list nested array type, required.", @@ -1365,7 +1366,7 @@ func TestBuildCollectionProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1376,11 +1377,11 @@ func TestBuildCollectionProvider(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListNestedAttribute{ @@ -1413,7 +1414,7 @@ func TestBuildCollectionProvider(t *testing.T) { "list nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Deprecated: pointer(true), @@ -1421,16 +1422,16 @@ func TestBuildCollectionProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListNestedAttribute{ @@ -1456,7 +1457,7 @@ func TestBuildCollectionProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, MinItems: pointer(int64(1)), @@ -1464,16 +1465,16 @@ func TestBuildCollectionProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListNestedAttribute{ @@ -1510,7 +1511,7 @@ func TestBuildCollectionProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -1519,7 +1520,7 @@ func TestBuildCollectionProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1530,11 +1531,11 @@ func TestBuildCollectionProvider(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderSetNestedAttribute{ @@ -1567,7 +1568,7 @@ func TestBuildCollectionProvider(t *testing.T) { "set nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -1576,16 +1577,16 @@ func TestBuildCollectionProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderSetNestedAttribute{ @@ -1611,7 +1612,7 @@ func TestBuildCollectionProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -1620,16 +1621,16 @@ func TestBuildCollectionProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderSetNestedAttribute{ @@ -1666,7 +1667,7 @@ func TestBuildCollectionProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of lists.", @@ -1676,7 +1677,7 @@ func TestBuildCollectionProvider(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1685,7 +1686,7 @@ func TestBuildCollectionProvider(t *testing.T) { Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), @@ -1700,20 +1701,20 @@ func TestBuildCollectionProvider(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ @@ -1772,7 +1773,7 @@ func TestBuildCollectionProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_set_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Format: "set", @@ -1784,7 +1785,7 @@ func TestBuildCollectionProvider(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1793,7 +1794,7 @@ func TestBuildCollectionProvider(t *testing.T) { Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), @@ -1810,20 +1811,20 @@ func TestBuildCollectionProvider(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderSetAttribute{ @@ -1881,7 +1882,7 @@ func TestBuildCollectionProvider(t *testing.T) { "list and set attribute - nested map results in element type": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "list_with_map": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list with a nested map of objects.", @@ -1891,7 +1892,7 @@ func TestBuildCollectionProvider(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_boolean": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "this won't be added, since it will map to element type", @@ -1900,7 +1901,7 @@ func TestBuildCollectionProvider(t *testing.T) { Type: []string{"string"}, Description: "this won't be added, since it will map to element type", }), - }, + }), }), }, }), @@ -1916,7 +1917,7 @@ func TestBuildCollectionProvider(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -1927,13 +1928,13 @@ func TestBuildCollectionProvider(t *testing.T) { Format: "int64", Description: "this won't be added, since it will map to element type", }), - }, + }), }), }, }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ diff --git a/internal/mapper/oas/integer.go b/internal/mapper/oas/integer.go index 21ced376..c7544f8d 100644 --- a/internal/mapper/oas/integer.go +++ b/internal/mapper/oas/integer.go @@ -23,9 +23,8 @@ func (s *OASSchema) BuildIntegerResource(name string, computability schema.Compu } if s.Schema.Default != nil { - staticDefault, ok := s.Schema.Default.(int64) - - if ok { + var staticDefault int64 + if err := s.Schema.Default.Decode(&staticDefault); err == nil { if computability == schema.Required { result.ComputedOptionalRequired = schema.ComputedOptional } @@ -86,10 +85,9 @@ func (s *OASSchema) GetIntegerValidators() []schema.Int64Validator { if len(s.Schema.Enum) > 0 { var enum []int64 - for _, valueIface := range s.Schema.Enum { - value, ok := valueIface.(int64) - - if !ok { + for _, valueNode := range s.Schema.Enum { + var value int64 + if err := valueNode.Decode(&value); err != nil { // could consider error/panic here to notify developers continue } diff --git a/internal/mapper/oas/integer_test.go b/internal/mapper/oas/integer_test.go index 033fc0ac..4ed8df91 100644 --- a/internal/mapper/oas/integer_test.go +++ b/internal/mapper/oas/integer_test.go @@ -13,9 +13,11 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" + "gopkg.in/yaml.v3" "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) func TestBuildIntegerResource(t *testing.T) { @@ -29,7 +31,7 @@ func TestBuildIntegerResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Description: "hey there! I'm an int64 type.", @@ -38,7 +40,7 @@ func TestBuildIntegerResource(t *testing.T) { Type: []string{"integer"}, Description: "hey there! I'm an int64 type, required.", }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceInt64Attribute{ @@ -61,20 +63,20 @@ func TestBuildIntegerResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop_required_default_non_zero"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop_default_non_zero": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, - Default: int64(123), + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "123"}, }), "int64_prop_default_zero": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, - Default: int64(0), + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "0"}, }), "int64_prop_required_default_non_zero": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, - Default: int64(123), + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "123"}, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceInt64Attribute{ @@ -110,12 +112,12 @@ func TestBuildIntegerResource(t *testing.T) { "int64 attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceInt64Attribute{ @@ -131,7 +133,7 @@ func TestBuildIntegerResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of int64s.", @@ -150,7 +152,7 @@ func TestBuildIntegerResource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -179,12 +181,15 @@ func TestBuildIntegerResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, - Enum: []any{int64(1), int64(2)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1"}, + {Kind: yaml.ScalarNode, Value: "2"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceInt64Attribute{ @@ -239,7 +244,7 @@ func TestBuildIntegerDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Description: "hey there! I'm an int64 type.", @@ -248,7 +253,7 @@ func TestBuildIntegerDataSource(t *testing.T) { Type: []string{"integer"}, Description: "hey there! I'm an int64 type, required.", }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceInt64Attribute{ @@ -270,12 +275,12 @@ func TestBuildIntegerDataSource(t *testing.T) { "int64 attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceInt64Attribute{ @@ -291,7 +296,7 @@ func TestBuildIntegerDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of int64s.", @@ -310,7 +315,7 @@ func TestBuildIntegerDataSource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -339,12 +344,15 @@ func TestBuildIntegerDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, - Enum: []any{int64(1), int64(2)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1"}, + {Kind: yaml.ScalarNode, Value: "2"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceInt64Attribute{ @@ -399,7 +407,7 @@ func TestBuildIntegerProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Description: "hey there! I'm an int64 type.", @@ -408,7 +416,7 @@ func TestBuildIntegerProvider(t *testing.T) { Type: []string{"integer"}, Description: "hey there! I'm an int64 type, required.", }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderInt64Attribute{ @@ -430,12 +438,12 @@ func TestBuildIntegerProvider(t *testing.T) { "int64 attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderInt64Attribute{ @@ -451,7 +459,7 @@ func TestBuildIntegerProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of int64s.", @@ -470,7 +478,7 @@ func TestBuildIntegerProvider(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ @@ -499,12 +507,15 @@ func TestBuildIntegerProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, - Enum: []any{int64(1), int64(2)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1"}, + {Kind: yaml.ScalarNode, Value: "2"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderInt64Attribute{ @@ -567,7 +578,10 @@ func TestGetIntegerValidators(t *testing.T) { schema: oas.OASSchema{ Schema: &base.Schema{ Type: []string{"integer"}, - Enum: []any{int64(1), int64(2)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1"}, + {Kind: yaml.ScalarNode, Value: "2"}, + }, }, }, expected: []schema.Int64Validator{ diff --git a/internal/mapper/oas/map_test.go b/internal/mapper/oas/map_test.go index 357494bd..493ba0fa 100644 --- a/internal/mapper/oas/map_test.go +++ b/internal/mapper/oas/map_test.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/resource" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) // TODO: add error tests @@ -29,7 +30,7 @@ func TestBuildMapResource(t *testing.T) { "map nested attribute with props": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey there! I'm a map nested type.", @@ -37,12 +38,12 @@ func TestBuildMapResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_password_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, Description: "hey there! I'm a single nested object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -53,18 +54,18 @@ func TestBuildMapResource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), "nested_password_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Format: "password", Description: "hey there! I'm a nested string type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceMapNestedAttribute{ @@ -114,7 +115,7 @@ func TestBuildMapResource(t *testing.T) { "map nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Deprecated: pointer(true), @@ -122,16 +123,16 @@ func TestBuildMapResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceMapNestedAttribute{ @@ -157,7 +158,7 @@ func TestBuildMapResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_map_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, MinProperties: pointer(int64(1)), @@ -165,16 +166,16 @@ func TestBuildMapResource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceMapNestedAttribute{ @@ -211,7 +212,7 @@ func TestBuildMapResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"map_with_strings_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "map_with_floats": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey there! I'm a map type with floats.", @@ -231,7 +232,7 @@ func TestBuildMapResource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceMapAttribute{ @@ -288,7 +289,7 @@ func TestBuildMapDataSource(t *testing.T) { "map nested attribute with props": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey there! I'm a map nested type.", @@ -296,12 +297,12 @@ func TestBuildMapDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_password_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, Description: "hey there! I'm a single nested object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -312,18 +313,18 @@ func TestBuildMapDataSource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), "nested_password_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Format: "password", Description: "hey there! I'm a nested string type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceMapNestedAttribute{ @@ -373,7 +374,7 @@ func TestBuildMapDataSource(t *testing.T) { "map nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Deprecated: pointer(true), @@ -381,16 +382,16 @@ func TestBuildMapDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceMapNestedAttribute{ @@ -416,7 +417,7 @@ func TestBuildMapDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_map_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, MinProperties: pointer(int64(1)), @@ -424,16 +425,16 @@ func TestBuildMapDataSource(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceMapNestedAttribute{ @@ -470,7 +471,7 @@ func TestBuildMapDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"map_with_strings_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "map_with_floats": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey there! I'm a map type with floats.", @@ -490,7 +491,7 @@ func TestBuildMapDataSource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceMapAttribute{ @@ -547,7 +548,7 @@ func TestBuildMapProvider(t *testing.T) { "map nested attribute with props": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey there! I'm a map nested type.", @@ -555,12 +556,12 @@ func TestBuildMapProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_password_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, Description: "hey there! I'm a single nested object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -571,18 +572,18 @@ func TestBuildMapProvider(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), "nested_password_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Format: "password", Description: "hey there! I'm a nested string type, required.", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderMapNestedAttribute{ @@ -632,7 +633,7 @@ func TestBuildMapProvider(t *testing.T) { "map nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Deprecated: pointer(true), @@ -640,16 +641,16 @@ func TestBuildMapProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderMapNestedAttribute{ @@ -675,7 +676,7 @@ func TestBuildMapProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"nested_map_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_map_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, MinProperties: pointer(int64(1)), @@ -683,16 +684,16 @@ func TestBuildMapProvider(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderMapNestedAttribute{ @@ -729,7 +730,7 @@ func TestBuildMapProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"map_with_strings_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "map_with_floats": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey there! I'm a map type with floats.", @@ -749,7 +750,7 @@ func TestBuildMapProvider(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderMapAttribute{ diff --git a/internal/mapper/oas/number.go b/internal/mapper/oas/number.go index 694c7f2a..1feec3a4 100644 --- a/internal/mapper/oas/number.go +++ b/internal/mapper/oas/number.go @@ -25,9 +25,8 @@ func (s *OASSchema) BuildNumberResource(name string, computability schema.Comput } if s.Schema.Default != nil { - staticDefault, ok := s.Schema.Default.(float64) - - if ok { + var staticDefault float64 + if err := s.Schema.Default.Decode(&staticDefault); err == nil { if computability == schema.Required { result.ComputedOptionalRequired = schema.ComputedOptional } @@ -128,10 +127,9 @@ func (s *OASSchema) GetFloatValidators() []schema.Float64Validator { if len(s.Schema.Enum) > 0 { var enum []float64 - for _, valueIface := range s.Schema.Enum { - value, ok := valueIface.(float64) - - if !ok { + for _, valueNode := range s.Schema.Enum { + var value float64 + if err := valueNode.Decode(&value); err != nil { // could consider error/panic here to notify developers continue } diff --git a/internal/mapper/oas/number_test.go b/internal/mapper/oas/number_test.go index 93b72e3c..d3411769 100644 --- a/internal/mapper/oas/number_test.go +++ b/internal/mapper/oas/number_test.go @@ -13,9 +13,11 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" + "gopkg.in/yaml.v3" "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) func TestBuildNumberResource(t *testing.T) { @@ -29,7 +31,7 @@ func TestBuildNumberResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"double_float64_prop_required", "float_float64_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "double_float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -50,7 +52,7 @@ func TestBuildNumberResource(t *testing.T) { Format: "float", Description: "hey there! I'm a float64 type, from a float, required.", }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceFloat64Attribute{ @@ -87,23 +89,23 @@ func TestBuildNumberResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"float64_prop_required_default_non_zero"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop_default_non_zero": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", - Default: float64(123.45), + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "123.45"}, }), "float64_prop_default_zero": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", - Default: float64(0.0), + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "0.0"}, }), "float64_prop_required_default_non_zero": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", - Default: float64(123.45), + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "123.45"}, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceFloat64Attribute{ @@ -139,13 +141,13 @@ func TestBuildNumberResource(t *testing.T) { "float64 attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceFloat64Attribute{ @@ -161,13 +163,16 @@ func TestBuildNumberResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"float64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", - Enum: []any{float64(1.2), float64(2.3)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1.2"}, + {Kind: yaml.ScalarNode, Value: "2.3"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceFloat64Attribute{ @@ -194,7 +199,7 @@ func TestBuildNumberResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"number_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Description: "hey there! I'm a number type.", @@ -203,7 +208,7 @@ func TestBuildNumberResource(t *testing.T) { Type: []string{"number"}, Description: "hey there! I'm a number type, required.", }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceNumberAttribute{ @@ -225,12 +230,12 @@ func TestBuildNumberResource(t *testing.T) { "number attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceNumberAttribute{ @@ -246,7 +251,7 @@ func TestBuildNumberResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"double_float64_list_prop_required", "float_float64_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "double_float64_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of float64s.", @@ -287,7 +292,7 @@ func TestBuildNumberResource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -336,7 +341,7 @@ func TestBuildNumberResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"number_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of numbers.", @@ -355,7 +360,7 @@ func TestBuildNumberResource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -412,7 +417,7 @@ func TestBuildNumberDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"double_float64_prop_required", "float_float64_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "double_float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -433,7 +438,7 @@ func TestBuildNumberDataSource(t *testing.T) { Format: "float", Description: "hey there! I'm a float64 type, from a float, required.", }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceFloat64Attribute{ @@ -469,13 +474,13 @@ func TestBuildNumberDataSource(t *testing.T) { "float64 attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceFloat64Attribute{ @@ -491,13 +496,16 @@ func TestBuildNumberDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"float64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", - Enum: []any{float64(1.2), float64(2.3)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1.2"}, + {Kind: yaml.ScalarNode, Value: "2.3"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceFloat64Attribute{ @@ -524,7 +532,7 @@ func TestBuildNumberDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"number_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Description: "hey there! I'm a number type.", @@ -533,7 +541,7 @@ func TestBuildNumberDataSource(t *testing.T) { Type: []string{"number"}, Description: "hey there! I'm a number type, required.", }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceNumberAttribute{ @@ -555,12 +563,12 @@ func TestBuildNumberDataSource(t *testing.T) { "number attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceNumberAttribute{ @@ -576,7 +584,7 @@ func TestBuildNumberDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"double_float64_list_prop_required", "float_float64_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "double_float64_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of float64s.", @@ -617,7 +625,7 @@ func TestBuildNumberDataSource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -666,7 +674,7 @@ func TestBuildNumberDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"number_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of numbers.", @@ -685,7 +693,7 @@ func TestBuildNumberDataSource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -742,7 +750,7 @@ func TestBuildNumberProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"double_float64_prop_required", "float_float64_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "double_float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -763,7 +771,7 @@ func TestBuildNumberProvider(t *testing.T) { Format: "float", Description: "hey there! I'm a float64 type, from a float, required.", }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderFloat64Attribute{ @@ -799,13 +807,13 @@ func TestBuildNumberProvider(t *testing.T) { "float64 attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderFloat64Attribute{ @@ -821,13 +829,16 @@ func TestBuildNumberProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"float64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", - Enum: []any{float64(1.2), float64(2.3)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1.2"}, + {Kind: yaml.ScalarNode, Value: "2.3"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderFloat64Attribute{ @@ -854,7 +865,7 @@ func TestBuildNumberProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"number_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Description: "hey there! I'm a number type.", @@ -863,7 +874,7 @@ func TestBuildNumberProvider(t *testing.T) { Type: []string{"number"}, Description: "hey there! I'm a number type, required.", }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderNumberAttribute{ @@ -885,12 +896,12 @@ func TestBuildNumberProvider(t *testing.T) { "number attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderNumberAttribute{ @@ -906,7 +917,7 @@ func TestBuildNumberProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"double_float64_list_prop_required", "float_float64_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "double_float64_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of float64s.", @@ -947,7 +958,7 @@ func TestBuildNumberProvider(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ @@ -996,7 +1007,7 @@ func TestBuildNumberProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"number_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of numbers.", @@ -1015,7 +1026,7 @@ func TestBuildNumberProvider(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ @@ -1080,7 +1091,10 @@ func TestGetFloatValidators(t *testing.T) { schema: oas.OASSchema{ Schema: &base.Schema{ Type: []string{"integer"}, - Enum: []any{float64(1.2), float64(2.3)}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "1.2"}, + {Kind: yaml.ScalarNode, Value: "2.3"}, + }, }, }, expected: []schema.Float64Validator{ diff --git a/internal/mapper/oas/oas_schema.go b/internal/mapper/oas/oas_schema.go index 25d19206..29b4ec86 100644 --- a/internal/mapper/oas/oas_schema.go +++ b/internal/mapper/oas/oas_schema.go @@ -4,12 +4,14 @@ package oas import ( + "context" "strings" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) type OASSchema struct { @@ -73,9 +75,9 @@ func (s *OASSchema) getPropertyLineNumber(propName string) int { } // Check property nodes first for a line number - for k, v := range low.Properties.Value { - if k.Value == propName { - return v.NodeLineNumber() + for pair := range orderedmap.Iterate(context.TODO(), low.Properties.Value) { + if pair.Key().Value == propName { + return pair.Value().NodeLineNumber() } } diff --git a/internal/mapper/oas/object.go b/internal/mapper/oas/object.go index b070939b..48072675 100644 --- a/internal/mapper/oas/object.go +++ b/internal/mapper/oas/object.go @@ -4,22 +4,25 @@ package oas import ( + "context" + "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" + "github.com/pb33f/libopenapi/orderedmap" ) func (s *OASSchema) BuildObjectElementType() (schema.ElementType, *SchemaError) { objectElemTypes := []schema.ObjectAttributeType{} - // Guarantee the order of processing - propertyNames := util.SortedKeys(s.Schema.Properties) - for _, name := range propertyNames { + sortedProperties := orderedmap.SortAlpha(s.Schema.Properties) + for pair := range orderedmap.Iterate(context.TODO(), sortedProperties) { + name := pair.Key() if s.IsPropertyIgnored(name) { continue } - pProxy := s.Schema.Properties[name] + pProxy := pair.Value() schemaOpts := SchemaOpts{ Ignores: s.GetIgnoresForNested(name), } diff --git a/internal/mapper/oas/single_nested_test.go b/internal/mapper/oas/single_nested_test.go index 1bd84c47..8070b40c 100644 --- a/internal/mapper/oas/single_nested_test.go +++ b/internal/mapper/oas/single_nested_test.go @@ -15,6 +15,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) // TODO: add error test for nested objects @@ -29,17 +30,17 @@ func TestBuildSingleNestedResource(t *testing.T) { "single nested attributes": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_obj_prop_required"}, Description: "hey there! I'm a single nested object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, Description: "hey there! I'm a single nested object type, required.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -50,11 +51,11 @@ func TestBuildSingleNestedResource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), - }, + }), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSingleNestedAttribute{ @@ -94,19 +95,19 @@ func TestBuildSingleNestedResource(t *testing.T) { "single nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Deprecated: pointer(true), Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceSingleNestedAttribute{ @@ -157,17 +158,17 @@ func TestBuildSingleNestedDataSource(t *testing.T) { "single nested attributes": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_obj_prop_required"}, Description: "hey there! I'm a single nested object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, Description: "hey there! I'm a single nested object type, required.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -178,11 +179,11 @@ func TestBuildSingleNestedDataSource(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), - }, + }), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceSingleNestedAttribute{ @@ -222,19 +223,19 @@ func TestBuildSingleNestedDataSource(t *testing.T) { "single nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Deprecated: pointer(true), Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceSingleNestedAttribute{ @@ -285,17 +286,17 @@ func TestBuildSingleNestedProvider(t *testing.T) { "single nested attributes": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_obj_prop_required"}, Description: "hey there! I'm a single nested object type.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_int64_required"}, Description: "hey there! I'm a single nested object type, required.", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -306,11 +307,11 @@ func TestBuildSingleNestedProvider(t *testing.T) { Format: "int64", Description: "hey there! I'm a nested int64 type, required.", }), - }, + }), }), - }, + }), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderSingleNestedAttribute{ @@ -350,19 +351,19 @@ func TestBuildSingleNestedProvider(t *testing.T) { "single nested attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_obj_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Deprecated: pointer(true), Required: []string{"nested_int64_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Format: "int64", }), - }, + }), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderSingleNestedAttribute{ diff --git a/internal/mapper/oas/string.go b/internal/mapper/oas/string.go index 86f34d15..3cd96aac 100644 --- a/internal/mapper/oas/string.go +++ b/internal/mapper/oas/string.go @@ -24,9 +24,8 @@ func (s *OASSchema) BuildStringResource(name string, computability schema.Comput } if s.Schema.Default != nil { - staticDefault, ok := s.Schema.Default.(string) - - if ok { + var staticDefault string + if err := s.Schema.Default.Decode(&staticDefault); err == nil { if computability == schema.Required { result.ComputedOptionalRequired = schema.ComputedOptional } @@ -89,10 +88,9 @@ func (s *OASSchema) GetStringValidators() []schema.StringValidator { if len(s.Schema.Enum) > 0 { var enum []string - for _, valueIface := range s.Schema.Enum { - value, ok := valueIface.(string) - - if !ok { + for _, valueNode := range s.Schema.Enum { + var value string + if err := valueNode.Decode(&value); err != nil { // could consider error/panic here to notify developers continue } diff --git a/internal/mapper/oas/string_test.go b/internal/mapper/oas/string_test.go index 7556f002..7d72b975 100644 --- a/internal/mapper/oas/string_test.go +++ b/internal/mapper/oas/string_test.go @@ -13,9 +13,11 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" + "gopkg.in/yaml.v3" "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) func TestBuildStringResource(t *testing.T) { @@ -29,7 +31,7 @@ func TestBuildStringResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Description: "hey there! I'm a string type, not sensitive, required.", @@ -39,7 +41,7 @@ func TestBuildStringResource(t *testing.T) { Format: "password", Description: "hey there! I'm a string type, sensitive", }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -63,23 +65,20 @@ func TestBuildStringResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop_required_default_non_empty"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop_default_empty": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, - Format: "double", - Default: "", + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: ""}, }), "string_prop_default_non_empty": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, - Format: "double", - Default: "test value", + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "test value"}, }), "string_prop_required_default_non_empty": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, - Format: "double", - Default: "test value", + Default: &yaml.Node{Kind: yaml.ScalarNode, Value: "test value"}, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -115,12 +114,12 @@ func TestBuildStringResource(t *testing.T) { "string attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -136,7 +135,7 @@ func TestBuildStringResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of strings.", @@ -155,7 +154,7 @@ func TestBuildStringResource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceListAttribute{ @@ -184,12 +183,15 @@ func TestBuildStringResource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, - Enum: []any{"one", "two"}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "one"}, + {Kind: yaml.ScalarNode, Value: "two"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.ResourceAttributes{ &attrmapper.ResourceStringAttribute{ @@ -244,7 +246,7 @@ func TestBuildStringDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Description: "hey there! I'm a string type, not sensitive, required.", @@ -254,7 +256,7 @@ func TestBuildStringDataSource(t *testing.T) { Format: "password", Description: "hey there! I'm a string type, sensitive", }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceStringAttribute{ @@ -277,12 +279,12 @@ func TestBuildStringDataSource(t *testing.T) { "string attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceStringAttribute{ @@ -298,7 +300,7 @@ func TestBuildStringDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of strings.", @@ -317,7 +319,7 @@ func TestBuildStringDataSource(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceListAttribute{ @@ -346,12 +348,15 @@ func TestBuildStringDataSource(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, - Enum: []any{"one", "two"}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "one"}, + {Kind: yaml.ScalarNode, Value: "two"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceStringAttribute{ @@ -406,7 +411,7 @@ func TestBuildStringProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Description: "hey there! I'm a string type, not sensitive, required.", @@ -416,7 +421,7 @@ func TestBuildStringProvider(t *testing.T) { Format: "password", Description: "hey there! I'm a string type, sensitive", }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderStringAttribute{ @@ -439,12 +444,12 @@ func TestBuildStringProvider(t *testing.T) { "string attributes deprecated": { schema: &base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Deprecated: pointer(true), }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderStringAttribute{ @@ -460,7 +465,7 @@ func TestBuildStringProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_list_prop_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_list_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey there! I'm a list of strings.", @@ -479,7 +484,7 @@ func TestBuildStringProvider(t *testing.T) { }), }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderListAttribute{ @@ -508,12 +513,15 @@ func TestBuildStringProvider(t *testing.T) { schema: &base.Schema{ Type: []string{"object"}, Required: []string{"string_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, - Enum: []any{"one", "two"}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "one"}, + {Kind: yaml.ScalarNode, Value: "two"}, + }, }), - }, + }), }, expectedAttributes: attrmapper.ProviderAttributes{ &attrmapper.ProviderStringAttribute{ @@ -576,7 +584,10 @@ func TestGetStringValidators(t *testing.T) { schema: oas.OASSchema{ Schema: &base.Schema{ Type: []string{"string"}, - Enum: []any{"one", "two"}, + Enum: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "one"}, + {Kind: yaml.ScalarNode, Value: "two"}, + }, }, }, expected: []schema.StringValidator{ diff --git a/internal/mapper/provider_mapper_test.go b/internal/mapper/provider_mapper_test.go index b3d5635e..bd90c021 100644 --- a/internal/mapper/provider_mapper_test.go +++ b/internal/mapper/provider_mapper_test.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/schema" "github.com/pb33f/libopenapi/datamodel/high/base" + "github.com/pb33f/libopenapi/orderedmap" ) func TestProviderMapper_basic(t *testing.T) { @@ -38,7 +39,7 @@ func TestProviderMapper_basic(t *testing.T) { SchemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"string_prop", "bool_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool, required!", @@ -57,7 +58,7 @@ func TestProviderMapper_basic(t *testing.T) { Format: "float", Description: "hey this is a float64!", }), - }, + }), }), }, want: &provider.Provider{ @@ -108,7 +109,7 @@ func TestProviderMapper_basic(t *testing.T) { }, SchemaProxy: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -119,7 +120,7 @@ func TestProviderMapper_basic(t *testing.T) { }), "nested_obj": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -128,7 +129,7 @@ func TestProviderMapper_basic(t *testing.T) { Type: []string{"string"}, Description: "hey this is a string!", }), - }, + }), }), "nested_array": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, @@ -139,14 +140,14 @@ func TestProviderMapper_basic(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "deep_nested_int64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, }), - }, + }), }), }, }), @@ -158,7 +159,7 @@ func TestProviderMapper_basic(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), @@ -166,11 +167,11 @@ func TestProviderMapper_basic(t *testing.T) { Type: []string{"integer"}, Description: "hey this is an int64!", }), - }, + }), }), }, }), - }, + }), }), }, want: &provider.Provider{ diff --git a/internal/mapper/resource_mapper_test.go b/internal/mapper/resource_mapper_test.go index 851e919e..09cc42b2 100644 --- a/internal/mapper/resource_mapper_test.go +++ b/internal/mapper/resource_mapper_test.go @@ -17,6 +17,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/pb33f/libopenapi/datamodel/high/base" high "github.com/pb33f/libopenapi/datamodel/high/v3" + "github.com/pb33f/libopenapi/orderedmap" ) func TestResourceMapper_basic_merges(t *testing.T) { @@ -34,7 +35,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { createRequestSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"bool_prop", "int64_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool, required!", @@ -43,25 +44,25 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is an int64, required!", }), - }, + }), }), createResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "int64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, Description: "this one already exists, so you shouldn't see this description!", }), - }, + }), }), readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "number_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), readParams: []*high.Parameter{ { @@ -111,27 +112,27 @@ func TestResourceMapper_basic_merges(t *testing.T) { createRequestSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_object_one"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_object_one": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"bool_prop"}, Description: "hey this is an object, required!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool, required!", }), - }, + }), }), - }, + }), }), createResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_object_one": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "this one already exists, so you shouldn't see this description!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "string_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Format: util.OAS_format_password, @@ -140,7 +141,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { "nested_object_two": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "hey this is an object!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -149,11 +150,11 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), - }, + }), }), - }, + }), }), readParams: []*high.Parameter{ { @@ -162,12 +163,12 @@ func TestResourceMapper_basic_merges(t *testing.T) { Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Description: "this one already exists, so you shouldn't see this description!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_object_two": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"int64_prop"}, Description: "this one already exists, so you shouldn't see this description!", - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a bool!", @@ -176,9 +177,9 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is a integer, switched to computed optional!", }), - }, + }), }), - }, + }), }), }, }, @@ -243,7 +244,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { createRequestSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"array_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array, required!", @@ -251,7 +252,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_array_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "float64_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "double", @@ -263,25 +264,25 @@ func TestResourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "super_nested_string": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, Description: "hey this is a string!", }), - }, + }), }), }, }), - }, + }), }), }, }), - }, + }), }), readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"array_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array, required!", @@ -289,7 +290,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"nested_array_prop"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "nested_array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is a nested array, required!", @@ -297,7 +298,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"super_nested_bool_two"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "super_nested_bool_one": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "hey this is a boolean!", @@ -310,7 +311,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is a integer!", }), - }, + }), }), }, }), @@ -318,11 +319,11 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"number"}, Description: "hey this is a number!", }), - }, + }), }), }, }), - }, + }), }), want: resource.Attributes{ { @@ -394,7 +395,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { "deep merge list array with object element types": { createRequestSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array!", @@ -404,7 +405,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_float64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"number"}, Format: "float", @@ -412,17 +413,17 @@ func TestResourceMapper_basic_merges(t *testing.T) { "deep_nested_string": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), }, }), }, }), - }, + }), }), createResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array!", @@ -432,22 +433,22 @@ func TestResourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_list": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_object": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_string": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), - }, + }), }), }, }), @@ -457,17 +458,17 @@ func TestResourceMapper_basic_merges(t *testing.T) { "deep_nested_int64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, }), - }, + }), }), }, }), }, }), - }, + }), }), readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "array_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Description: "hey this is an array!", @@ -477,32 +478,32 @@ func TestResourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_list": base.CreateSchemaProxy(&base.Schema{ Type: []string{"array"}, Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_object": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), - }, + }), }), - }, + }), }), }, }), - }, + }), }), }, }), }, }), - }, + }), }), want: resource.Attributes{ { @@ -576,7 +577,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { "create_request_required_read_parameter_required", "create_request_required_read_response", }, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "create_request_optional_create_request_only": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), @@ -607,11 +608,11 @@ func TestResourceMapper_basic_merges(t *testing.T) { "create_request_required_read_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), createResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ // Simulate API returning parameter in response "create_request_optional_create_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -623,12 +624,12 @@ func TestResourceMapper_basic_merges(t *testing.T) { "create_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), readParams: []*high.Parameter{ { Name: "create_request_optional_read_parameter_optional", - Required: false, + Required: pointer(false), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -636,7 +637,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, { Name: "create_request_optional_read_parameter_required", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -644,7 +645,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, { Name: "create_request_required_read_parameter_optional", - Required: false, + Required: pointer(false), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -652,7 +653,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, { Name: "create_request_required_read_parameter_required", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -665,7 +666,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { // details to practitioners, which are conventionally hidden. { Name: "read_parameter_optional", - Required: false, + Required: pointer(false), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -673,7 +674,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, { Name: "read_parameter_required", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -682,7 +683,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ // Simulate API returning parameter in response "create_request_optional_read_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -694,7 +695,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { "read_response": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), want: resource.Attributes{ { @@ -787,16 +788,16 @@ func TestResourceMapper_basic_merges(t *testing.T) { createRequestSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, Required: []string{"attribute_required"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "attribute_required": base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, }), - }, + }), }), readParams: []*high.Parameter{ { Name: "read_path_parameter", - Required: true, + Required: pointer(true), In: "path", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"string"}, @@ -804,7 +805,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, { Name: "read_query_parameter", - Required: false, + Required: pointer(false), In: "query", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, @@ -813,11 +814,11 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "attribute_computed": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), - }, + }), }), schemaOptions: explorer.SchemaOptions{ AttributeOptions: explorer.AttributeOptions{ @@ -853,7 +854,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }, createRequestSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -868,7 +869,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { AdditionalProperties: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), @@ -876,15 +877,15 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"integer"}, Description: "hey this is an int64!", }), - }, + }), }), }, }), - }, + }), }), createResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -902,24 +903,24 @@ func TestResourceMapper_basic_merges(t *testing.T) { Items: &base.DynamicValue[*base.SchemaProxy, bool]{ A: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "deep_nested_bool": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, }), "deep_nested_int64": base.CreateSchemaProxy(&base.Schema{ Type: []string{"integer"}, }), - }, + }), }), }, }), }, }), - }, + }), }), readResponseSchema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -930,7 +931,7 @@ func TestResourceMapper_basic_merges(t *testing.T) { }), "nested_obj": base.CreateSchemaProxy(&base.Schema{ Type: []string{"object"}, - Properties: map[string]*base.SchemaProxy{ + Properties: orderedmap.ToOrderedMap(map[string]*base.SchemaProxy{ "bool_prop": base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, Description: "This boolean is going to be ignored!", @@ -939,14 +940,14 @@ func TestResourceMapper_basic_merges(t *testing.T) { Type: []string{"string"}, Description: "hey this is a string!", }), - }, + }), }), - }, + }), }), readParams: []*high.Parameter{ { Name: "bool_prop", - Required: true, + Required: pointer(true), In: "query", Schema: base.CreateSchemaProxy(&base.Schema{ Type: []string{"boolean"}, @@ -1066,22 +1067,22 @@ func TestResourceMapper_basic_merges(t *testing.T) { func createTestCreateOp(request *base.SchemaProxy, response *base.SchemaProxy) *high.Operation { return &high.Operation{ RequestBody: &high.RequestBody{ - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: request, }, - }, + }), }, Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "201": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: response, }, - }, + }), }, - }, + }), }, } } @@ -1089,15 +1090,15 @@ func createTestCreateOp(request *base.SchemaProxy, response *base.SchemaProxy) * func createTestReadOp(response *base.SchemaProxy, params []*high.Parameter) *high.Operation { return &high.Operation{ Responses: &high.Responses{ - Codes: map[string]*high.Response{ + Codes: orderedmap.ToOrderedMap(map[string]*high.Response{ "200": { - Content: map[string]*high.MediaType{ + Content: orderedmap.ToOrderedMap(map[string]*high.MediaType{ "application/json": { Schema: response, }, - }, + }), }, - }, + }), }, Parameters: params, }