From 34cee4a42f9b8007e11379dd324659cb7e163667 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 15 Dec 2023 11:19:49 +0000 Subject: [PATCH 01/48] Add KnownValue interface and types (#243) --- knownvalue/bool.go | 41 ++++++++++++ knownvalue/bool_test.go | 57 ++++++++++++++++ knownvalue/doc.go | 5 ++ knownvalue/float64.go | 43 ++++++++++++ knownvalue/float64_test.go | 57 ++++++++++++++++ knownvalue/int64.go | 43 ++++++++++++ knownvalue/int64_test.go | 57 ++++++++++++++++ knownvalue/known_value.go | 10 +++ knownvalue/list.go | 55 ++++++++++++++++ knownvalue/list_partial.go | 76 ++++++++++++++++++++++ knownvalue/list_partial_test.go | 74 +++++++++++++++++++++ knownvalue/list_test.go | 89 +++++++++++++++++++++++++ knownvalue/map.go | 72 +++++++++++++++++++++ knownvalue/map_partial.go | 68 +++++++++++++++++++ knownvalue/map_partial_test.go | 80 +++++++++++++++++++++++ knownvalue/map_test.go | 82 +++++++++++++++++++++++ knownvalue/num_elements.go | 47 ++++++++++++++ knownvalue/num_elements_test.go | 77 ++++++++++++++++++++++ knownvalue/object.go | 72 +++++++++++++++++++++ knownvalue/object_partial.go | 68 +++++++++++++++++++ knownvalue/object_partial_test.go | 80 +++++++++++++++++++++++ knownvalue/object_test.go | 82 +++++++++++++++++++++++ knownvalue/set.go | 72 +++++++++++++++++++++ knownvalue/set_partial.go | 68 +++++++++++++++++++ knownvalue/set_partial_test.go | 75 +++++++++++++++++++++ knownvalue/set_test.go | 90 ++++++++++++++++++++++++++ knownvalue/string.go | 39 +++++++++++ knownvalue/string_test.go | 57 ++++++++++++++++ plancheck/expect_unknown_value_test.go | 56 +++++++++------- 29 files changed, 1769 insertions(+), 23 deletions(-) create mode 100644 knownvalue/bool.go create mode 100644 knownvalue/bool_test.go create mode 100644 knownvalue/doc.go create mode 100644 knownvalue/float64.go create mode 100644 knownvalue/float64_test.go create mode 100644 knownvalue/int64.go create mode 100644 knownvalue/int64_test.go create mode 100644 knownvalue/known_value.go create mode 100644 knownvalue/list.go create mode 100644 knownvalue/list_partial.go create mode 100644 knownvalue/list_partial_test.go create mode 100644 knownvalue/list_test.go create mode 100644 knownvalue/map.go create mode 100644 knownvalue/map_partial.go create mode 100644 knownvalue/map_partial_test.go create mode 100644 knownvalue/map_test.go create mode 100644 knownvalue/num_elements.go create mode 100644 knownvalue/num_elements_test.go create mode 100644 knownvalue/object.go create mode 100644 knownvalue/object_partial.go create mode 100644 knownvalue/object_partial_test.go create mode 100644 knownvalue/object_test.go create mode 100644 knownvalue/set.go create mode 100644 knownvalue/set_partial.go create mode 100644 knownvalue/set_partial_test.go create mode 100644 knownvalue/set_test.go create mode 100644 knownvalue/string.go create mode 100644 knownvalue/string_test.go diff --git a/knownvalue/bool.go b/knownvalue/bool.go new file mode 100644 index 000000000..3679ec132 --- /dev/null +++ b/knownvalue/bool.go @@ -0,0 +1,41 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import "strconv" + +var _ KnownValue = BoolValue{} + +type BoolValue struct { + value bool +} + +// Equal determines whether the passed value is of type bool, and +// contains a matching bool value. +func (v BoolValue) Equal(other any) bool { + otherVal, ok := other.(bool) + + if !ok { + return false + } + + if otherVal != v.value { + return false + } + + return true +} + +// String returns the string representation of the bool value. +func (v BoolValue) String() string { + return strconv.FormatBool(v.value) +} + +// NewBoolValue returns a KnownValue for asserting equality between the +// supplied bool and the value passed to the Equal method. +func NewBoolValue(value bool) BoolValue { + return BoolValue{ + value: value, + } +} diff --git a/knownvalue/bool_test.go b/knownvalue/bool_test.go new file mode 100644 index 000000000..5551e20eb --- /dev/null +++ b/knownvalue/bool_test.go @@ -0,0 +1,57 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestBoolValue_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "not-equal": { + other: false, + }, + "equal": { + other: true, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewBoolValue(true).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestBoolValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewBoolValue(true).String() + + if diff := cmp.Diff(got, "true"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/doc.go b/knownvalue/doc.go new file mode 100644 index 000000000..4041c3e93 --- /dev/null +++ b/knownvalue/doc.go @@ -0,0 +1,5 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package knownvalue contains the known value interface, and types implementing the known value interface. +package knownvalue diff --git a/knownvalue/float64.go b/knownvalue/float64.go new file mode 100644 index 000000000..a9727ee3c --- /dev/null +++ b/knownvalue/float64.go @@ -0,0 +1,43 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "strconv" +) + +var _ KnownValue = Float64Value{} + +type Float64Value struct { + value float64 +} + +// Equal determines whether the passed value is of type float64, and +// contains a matching float64 value. +func (v Float64Value) Equal(other any) bool { + otherVal, ok := other.(float64) + + if !ok { + return false + } + + if otherVal != v.value { + return false + } + + return true +} + +// String returns the string representation of the float64 value. +func (v Float64Value) String() string { + return strconv.FormatFloat(v.value, 'f', -1, 64) +} + +// NewFloat64Value returns a KnownValue for asserting equality between the +// supplied float64 and the value passed to the Equal method. +func NewFloat64Value(value float64) Float64Value { + return Float64Value{ + value: value, + } +} diff --git a/knownvalue/float64_test.go b/knownvalue/float64_test.go new file mode 100644 index 000000000..5ebd9c024 --- /dev/null +++ b/knownvalue/float64_test.go @@ -0,0 +1,57 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestFloat64Value_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 123, + }, + "not-equal": { + other: false, + }, + "equal": { + other: 1.23, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewFloat64Value(1.23).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestFloat64Value_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewFloat64Value(1.234567890123e+09).String() + + if diff := cmp.Diff(got, "1234567890.123"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/int64.go b/knownvalue/int64.go new file mode 100644 index 000000000..2ec7bfbcb --- /dev/null +++ b/knownvalue/int64.go @@ -0,0 +1,43 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "strconv" +) + +var _ KnownValue = Int64Value{} + +type Int64Value struct { + value int64 +} + +// Equal determines whether the passed value is of type int64, and +// contains a matching int64 value. +func (v Int64Value) Equal(other any) bool { + otherVal, ok := other.(int64) + + if !ok { + return false + } + + if otherVal != v.value { + return false + } + + return true +} + +// String returns the string representation of the int64 value. +func (v Int64Value) String() string { + return strconv.FormatInt(v.value, 10) +} + +// NewInt64Value returns a KnownValue for asserting equality between the +// supplied int64 and the value passed to the Equal method. +func NewInt64Value(value int64) Int64Value { + return Int64Value{ + value: value, + } +} diff --git a/knownvalue/int64_test.go b/knownvalue/int64_test.go new file mode 100644 index 000000000..3536d4748 --- /dev/null +++ b/knownvalue/int64_test.go @@ -0,0 +1,57 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestInt64Value_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "not-equal": { + other: false, + }, + "equal": { + other: int64(123), + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewInt64Value(123).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestInt64Value_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewInt64Value(1234567890123).String() + + if diff := cmp.Diff(got, "1234567890123"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/known_value.go b/knownvalue/known_value.go new file mode 100644 index 000000000..c4793bf39 --- /dev/null +++ b/knownvalue/known_value.go @@ -0,0 +1,10 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +// KnownValue defines an interface that is implemented to determine equality on the basis of type and value. +type KnownValue interface { + // Equal should perform equality testing. + Equal(other any) bool +} diff --git a/knownvalue/list.go b/knownvalue/list.go new file mode 100644 index 000000000..95e68ea9a --- /dev/null +++ b/knownvalue/list.go @@ -0,0 +1,55 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" +) + +var _ KnownValue = ListValue{} + +type ListValue struct { + value []KnownValue +} + +// Equal determines whether the passed value is of type []any, and +// contains matching slice entries in the same sequence. +func (v ListValue) Equal(other any) bool { + otherVal, ok := other.([]any) + + if !ok { + return false + } + + if len(otherVal) != len(v.value) { + return false + } + + for i := 0; i < len(v.value); i++ { + if !v.value[i].Equal(otherVal[i]) { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v ListValue) String() string { + var listVals []string + + for _, val := range v.value { + listVals = append(listVals, fmt.Sprintf("%s", val)) + } + + return fmt.Sprintf("%s", listVals) +} + +// NewListValue returns a KnownValue for asserting equality between the +// supplied []KnownValue and the value passed to the Equal method. +func NewListValue(value []KnownValue) ListValue { + return ListValue{ + value: value, + } +} diff --git a/knownvalue/list_partial.go b/knownvalue/list_partial.go new file mode 100644 index 000000000..184e7f96e --- /dev/null +++ b/knownvalue/list_partial.go @@ -0,0 +1,76 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "bytes" + "fmt" + "sort" + "strings" +) + +var _ KnownValue = ListValuePartial{} + +type ListValuePartial struct { + value map[int]KnownValue +} + +// Equal determines whether the passed value is of type []any, and +// contains matching slice entries in the same sequence. +func (v ListValuePartial) Equal(other any) bool { + otherVal, ok := other.([]any) + + if !ok { + return false + } + + for k, val := range v.value { + if len(otherVal) <= k { + return false + } + + if !val.Equal(otherVal[k]) { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v ListValuePartial) String() string { + var b bytes.Buffer + + b.WriteString("[") + + var keys []int + + var listVals []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + for _, k := range keys { + listVals = append(listVals, fmt.Sprintf("%d:%s", k, v.value[k])) + } + + b.WriteString(strings.Join(listVals, " ")) + + b.WriteString("]") + + return b.String() +} + +// NewListValuePartial returns a KnownValue for asserting equality between the +// supplied map[int]KnownValue and the value passed to the Equal method. +func NewListValuePartial(value map[int]KnownValue) ListValuePartial { + return ListValuePartial{ + value: value, + } +} diff --git a/knownvalue/list_partial_test.go b/knownvalue/list_partial_test.go new file mode 100644 index 000000000..2bb999155 --- /dev/null +++ b/knownvalue/list_partial_test.go @@ -0,0 +1,74 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestListValuePartial_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: []any{}, + }, + "different-len": { + other: []any{1.23, 4.56}, + }, + "not-equal": { + other: []any{1.23, 4.56, 6.54, 5.46}, + }, + "wrong-order": { + other: []any{1.23, 0.00, 7.89, 4.56}, + }, + "equal": { + other: []any{1.23, 0.00, 4.56, 7.89}, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewFloat64Value(1.23), + 2: knownvalue.NewFloat64Value(4.56), + 3: knownvalue.NewFloat64Value(7.89), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestListValuePartial_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewFloat64Value(1.23), + 2: knownvalue.NewFloat64Value(4.56), + 3: knownvalue.NewFloat64Value(7.89), + }).String() + + if diff := cmp.Diff(got, "[0:1.23 2:4.56 3:7.89]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/list_test.go b/knownvalue/list_test.go new file mode 100644 index 000000000..080003041 --- /dev/null +++ b/knownvalue/list_test.go @@ -0,0 +1,89 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestListValue_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: []any{}, + }, + "different-len": { + other: []any{ + int64(123), + int64(456), + }, + }, + "not-equal": { + other: []any{ + int64(123), + int64(456), + int64(654), + }, + }, + "wrong-order": { + other: []any{ + int64(789), + int64(456), + int64(123), + }, + }, + "equal": { + other: []any{ + int64(123), + int64(456), + int64(789), + }, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewInt64Value(123), + knownvalue.NewInt64Value(456), + knownvalue.NewInt64Value(789), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestListValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewInt64Value(123), + knownvalue.NewInt64Value(456), + knownvalue.NewInt64Value(789), + }).String() + + if diff := cmp.Diff(got, "[123 456 789]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/map.go b/knownvalue/map.go new file mode 100644 index 000000000..0f11558f4 --- /dev/null +++ b/knownvalue/map.go @@ -0,0 +1,72 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "sort" +) + +var _ KnownValue = MapValue{} + +type MapValue struct { + value map[string]KnownValue +} + +// Equal determines whether the passed value is of type map[string]any, and +// contains matching map entries. +func (v MapValue) Equal(other any) bool { + otherVal, ok := other.(map[string]any) + + if !ok { + return false + } + + if len(otherVal) != len(v.value) { + return false + } + + for k, v := range v.value { + otherValItem, ok := otherVal[k] + + if !ok { + return false + } + + if !v.Equal(otherValItem) { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v MapValue) String() string { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + mapVals := make(map[string]string, len(keys)) + + for _, k := range keys { + mapVals[k] = fmt.Sprintf("%s", v.value[k]) + } + + return fmt.Sprintf("%v", mapVals) +} + +// NewMapValue returns a KnownValue for asserting equality between the +// supplied map[string]KnownValue and the value passed to the Equal method. +func NewMapValue(value map[string]KnownValue) MapValue { + return MapValue{ + value: value, + } +} diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go new file mode 100644 index 000000000..9c9e776db --- /dev/null +++ b/knownvalue/map_partial.go @@ -0,0 +1,68 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "sort" +) + +var _ KnownValue = MapValuePartial{} + +type MapValuePartial struct { + value map[string]KnownValue +} + +// Equal determines whether the passed value is of type map[string]any, and +// contains matching map entries. +func (v MapValuePartial) Equal(other any) bool { + otherVal, ok := other.(map[string]any) + + if !ok { + return false + } + + for k, v := range v.value { + otherValItem, ok := otherVal[k] + + if !ok { + return false + } + + if !v.Equal(otherValItem) { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v MapValuePartial) String() string { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + mapVals := make(map[string]string, len(keys)) + + for _, k := range keys { + mapVals[k] = fmt.Sprintf("%s", v.value[k]) + } + + return fmt.Sprintf("%v", mapVals) +} + +// NewMapValuePartial returns a KnownValue for asserting partial equality between the +// supplied map[string]KnownValue and the value passed to the Equal method. +func NewMapValuePartial(value map[string]KnownValue) MapValuePartial { + return MapValuePartial{ + value: value, + } +} diff --git a/knownvalue/map_partial_test.go b/knownvalue/map_partial_test.go new file mode 100644 index 000000000..b2df1c79e --- /dev/null +++ b/knownvalue/map_partial_test.go @@ -0,0 +1,80 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestMapValuePartial_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: map[string]any{}, + }, + "not-equal-different-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + }, + }, + "not-equal-same-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 6.54, + }, + }, + "equal": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 7.89, + }, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "three": knownvalue.NewFloat64Value(7.89), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestMapValuePartial_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "three": knownvalue.NewFloat64Value(7.89), + }).String() + + if diff := cmp.Diff(got, "map[one:1.23 three:7.89]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/map_test.go b/knownvalue/map_test.go new file mode 100644 index 000000000..c669bf0ab --- /dev/null +++ b/knownvalue/map_test.go @@ -0,0 +1,82 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestMapValue_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: map[string]any{}, + }, + "different-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + }, + }, + "not-equal": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 6.54, + }, + }, + "equal": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 7.89, + }, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "two": knownvalue.NewFloat64Value(4.56), + "three": knownvalue.NewFloat64Value(7.89), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestMapValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "two": knownvalue.NewFloat64Value(4.56), + "three": knownvalue.NewFloat64Value(7.89), + }).String() + + if diff := cmp.Diff(got, "map[one:1.23 three:7.89 two:4.56]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/num_elements.go b/knownvalue/num_elements.go new file mode 100644 index 000000000..60712aee5 --- /dev/null +++ b/knownvalue/num_elements.go @@ -0,0 +1,47 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import "strconv" + +var _ KnownValue = NumElements{} + +type NumElements struct { + num int +} + +// Equal verifies that the passed value is a list, map, object, +// or set, and contains a matching number of elements. +func (v NumElements) Equal(other any) bool { + mapVal, mapOk := other.(map[string]any) + + sliceVal, sliceOk := other.([]any) + + if !mapOk && !sliceOk { + return false + } + + if mapOk && len(mapVal) != v.num { + return false + } + + if sliceOk && len(sliceVal) != v.num { + return false + } + + return true +} + +// String returns the string representation of the value. +func (v NumElements) String() string { + return strconv.FormatInt(int64(v.num), 10) +} + +// NewNumElements returns a KnownValue for asserting that +// a list, map, object, or set contains num elements. +func NewNumElements(num int) NumElements { + return NumElements{ + num: num, + } +} diff --git a/knownvalue/num_elements_test.go b/knownvalue/num_elements_test.go new file mode 100644 index 000000000..97b587ddc --- /dev/null +++ b/knownvalue/num_elements_test.go @@ -0,0 +1,77 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestNumElements_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty-map": { + other: map[string]any{}, + }, + "empty-slice": { + other: []any{}, + }, + "map-different-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + }, + }, + "slice-different-len": { + other: []any{1.23, 4.56}, + }, + "equal-map": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 7.89, + }, + expected: true, + }, + "equal-slice": { + other: []any{1.23, 4.56, 7.89}, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewNumElements(3).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestNumElements_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewNumElements(2).String() + + if diff := cmp.Diff(got, "2"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/object.go b/knownvalue/object.go new file mode 100644 index 000000000..418905685 --- /dev/null +++ b/knownvalue/object.go @@ -0,0 +1,72 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "sort" +) + +var _ KnownValue = ObjectValue{} + +type ObjectValue struct { + value map[string]KnownValue +} + +// Equal determines whether the passed value is of type map[string]any, and +// contains matching object entries. +func (v ObjectValue) Equal(other any) bool { + otherVal, ok := other.(map[string]any) + + if !ok { + return false + } + + if len(otherVal) != len(v.value) { + return false + } + + for k, v := range v.value { + otherValItem, ok := otherVal[k] + + if !ok { + return false + } + + if !v.Equal(otherValItem) { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v ObjectValue) String() string { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + mapVals := make(map[string]string, len(keys)) + + for _, k := range keys { + mapVals[k] = fmt.Sprintf("%s", v.value[k]) + } + + return fmt.Sprintf("%v", mapVals) +} + +// NewObjectValue returns a KnownValue for asserting equality between the +// supplied map[string]KnownValue and the value passed to the Equal method. +func NewObjectValue(value map[string]KnownValue) ObjectValue { + return ObjectValue{ + value: value, + } +} diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go new file mode 100644 index 000000000..721184b4f --- /dev/null +++ b/knownvalue/object_partial.go @@ -0,0 +1,68 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "sort" +) + +var _ KnownValue = ObjectValuePartial{} + +type ObjectValuePartial struct { + value map[string]KnownValue +} + +// Equal determines whether the passed value is of type map[string]any, and +// contains matching map entries. +func (v ObjectValuePartial) Equal(other any) bool { + otherVal, ok := other.(map[string]any) + + if !ok { + return false + } + + for k, v := range v.value { + otherValItem, ok := otherVal[k] + + if !ok { + return false + } + + if !v.Equal(otherValItem) { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v ObjectValuePartial) String() string { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + mapVals := make(map[string]string, len(keys)) + + for _, k := range keys { + mapVals[k] = fmt.Sprintf("%s", v.value[k]) + } + + return fmt.Sprintf("%v", mapVals) +} + +// NewObjectValuePartial returns a KnownValue for asserting partial equality between the +// supplied map[string]KnownValue and the value passed to the Equal method. +func NewObjectValuePartial(value map[string]KnownValue) ObjectValuePartial { + return ObjectValuePartial{ + value: value, + } +} diff --git a/knownvalue/object_partial_test.go b/knownvalue/object_partial_test.go new file mode 100644 index 000000000..0450006b7 --- /dev/null +++ b/knownvalue/object_partial_test.go @@ -0,0 +1,80 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestObjectValuePartial_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: map[string]any{}, + }, + "not-equal-different-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + }, + }, + "not-equal-same-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 6.54, + }, + }, + "equal": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 7.89, + }, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewObjectValuePartial(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "three": knownvalue.NewFloat64Value(7.89), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestObjectValuePartial_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewObjectValuePartial(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "three": knownvalue.NewFloat64Value(7.89), + }).String() + + if diff := cmp.Diff(got, "map[one:1.23 three:7.89]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/object_test.go b/knownvalue/object_test.go new file mode 100644 index 000000000..7b502d2a3 --- /dev/null +++ b/knownvalue/object_test.go @@ -0,0 +1,82 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestObjectValue_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: map[string]any{}, + }, + "different-len": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + }, + }, + "not-equal": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 6.54, + }, + }, + "equal": { + other: map[string]any{ + "one": 1.23, + "two": 4.56, + "three": 7.89, + }, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewObjectValue(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "two": knownvalue.NewFloat64Value(4.56), + "three": knownvalue.NewFloat64Value(7.89), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestObjectValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewObjectValue(map[string]knownvalue.KnownValue{ + "one": knownvalue.NewFloat64Value(1.23), + "two": knownvalue.NewFloat64Value(4.56), + "three": knownvalue.NewFloat64Value(7.89), + }).String() + + if diff := cmp.Diff(got, "map[one:1.23 three:7.89 two:4.56]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/set.go b/knownvalue/set.go new file mode 100644 index 000000000..605fe3cf3 --- /dev/null +++ b/knownvalue/set.go @@ -0,0 +1,72 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" +) + +var _ KnownValue = SetValue{} + +type SetValue struct { + value []KnownValue +} + +// Equal determines whether the passed value is of type []any, and +// contains matching slice entries independent of the sequence. +func (v SetValue) Equal(other any) bool { + otherVal, ok := other.([]any) + + if !ok { + return false + } + + if len(otherVal) != len(v.value) { + return false + } + + otherValCopy := make([]any, len(otherVal)) + + copy(otherValCopy, otherVal) + + for i := 0; i < len(v.value); i++ { + var equal bool + + for j := 0; j < len(otherValCopy); j++ { + equal = v.value[i].Equal(otherValCopy[j]) + + if equal { + otherValCopy[j] = otherValCopy[len(otherValCopy)-1] + otherValCopy = otherValCopy[:len(otherValCopy)-1] + + break + } + } + + if !equal { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v SetValue) String() string { + var setVals []string + + for _, val := range v.value { + setVals = append(setVals, fmt.Sprintf("%s", val)) + } + + return fmt.Sprintf("%s", setVals) +} + +// NewSetValue returns a KnownValue for asserting equality between the +// supplied []KnownValue and the value passed to the Equal method. +func NewSetValue(value []KnownValue) SetValue { + return SetValue{ + value: value, + } +} diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go new file mode 100644 index 000000000..d2dee6620 --- /dev/null +++ b/knownvalue/set_partial.go @@ -0,0 +1,68 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" +) + +var _ KnownValue = SetValuePartial{} + +type SetValuePartial struct { + value []KnownValue +} + +// Equal determines whether the passed value is of type []any, and +// contains matching slice entries in the same sequence. +func (v SetValuePartial) Equal(other any) bool { + otherVal, ok := other.([]any) + + if !ok { + return false + } + + otherValCopy := make([]any, len(otherVal)) + + copy(otherValCopy, otherVal) + + for i := 0; i < len(v.value); i++ { + var equal bool + + for j := 0; j < len(otherValCopy); j++ { + equal = v.value[i].Equal(otherValCopy[j]) + + if equal { + otherValCopy[j] = otherValCopy[len(otherValCopy)-1] + otherValCopy = otherValCopy[:len(otherValCopy)-1] + + break + } + } + + if !equal { + return false + } + } + + return true +} + +// String returns the string representation of the value. +func (v SetValuePartial) String() string { + var setVals []string + + for _, val := range v.value { + setVals = append(setVals, fmt.Sprintf("%s", val)) + } + + return fmt.Sprintf("%s", setVals) +} + +// NewSetValuePartial returns a KnownValue for asserting equality of the elements +// supplied in []KnownValue and the elements in the value passed to the Equal method. +func NewSetValuePartial(value []KnownValue) SetValuePartial { + return SetValuePartial{ + value: value, + } +} diff --git a/knownvalue/set_partial_test.go b/knownvalue/set_partial_test.go new file mode 100644 index 000000000..2f4f7fdd0 --- /dev/null +++ b/knownvalue/set_partial_test.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestSetValuePartial_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: []any{}, + }, + "different-len": { + other: []any{1.23, 4.56}, + }, + "not-equal": { + other: []any{1.23, 4.56, 6.54, 5.46}, + }, + "equal-different-order": { + other: []any{1.23, 0.00, 7.89, 4.56}, + expected: true, + }, + "equal-same-order": { + other: []any{1.23, 0.00, 4.56, 7.89}, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewFloat64Value(1.23), + knownvalue.NewFloat64Value(4.56), + knownvalue.NewFloat64Value(7.89), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestSetValuePartial_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewFloat64Value(1.23), + knownvalue.NewFloat64Value(4.56), + knownvalue.NewFloat64Value(7.89), + }).String() + + if diff := cmp.Diff(got, "[1.23 4.56 7.89]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/set_test.go b/knownvalue/set_test.go new file mode 100644 index 000000000..166b7dfe0 --- /dev/null +++ b/knownvalue/set_test.go @@ -0,0 +1,90 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestSetValue_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "empty": { + other: []any{}, + }, + "different-len": { + other: []any{ + int64(123), + int64(456), + }, + }, + "not-equal": { + other: []any{ + int64(123), + int64(456), + int64(654), + }, + }, + "equal-different-order": { + other: []any{ + int64(789), + int64(456), + int64(123), + }, + expected: true, + }, + "equal-same-order": { + other: []any{ + int64(123), + int64(456), + int64(789), + }, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewInt64Value(123), + knownvalue.NewInt64Value(456), + knownvalue.NewInt64Value(789), + }).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestSetValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewInt64Value(123), + knownvalue.NewInt64Value(456), + knownvalue.NewInt64Value(789), + }).String() + + if diff := cmp.Diff(got, "[123 456 789]"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/string.go b/knownvalue/string.go new file mode 100644 index 000000000..603363d5a --- /dev/null +++ b/knownvalue/string.go @@ -0,0 +1,39 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +var _ KnownValue = StringValue{} + +type StringValue struct { + value string +} + +// Equal determines whether the passed value is of type string, and +// contains a matching sequence of bytes. +func (v StringValue) Equal(other any) bool { + otherVal, ok := other.(string) + + if !ok { + return false + } + + if otherVal != v.value { + return false + } + + return true +} + +// String returns the string representation of the value. +func (v StringValue) String() string { + return v.value +} + +// NewStringValue returns a KnownValue for asserting equality between the +// supplied string and a value passed to the Equal method. +func NewStringValue(value string) StringValue { + return StringValue{ + value: value, + } +} diff --git a/knownvalue/string_test.go b/knownvalue/string_test.go new file mode 100644 index 000000000..7ec87c9e6 --- /dev/null +++ b/knownvalue/string_test.go @@ -0,0 +1,57 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestStringValue_Equal(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: 1.23, + }, + "not-equal": { + other: "other", + }, + "equal": { + other: "str", + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewStringValue("str").Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestStringValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NewStringValue("str").String() + + if diff := cmp.Diff(got, "str"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/plancheck/expect_unknown_value_test.go b/plancheck/expect_unknown_value_test.go index 31798b9d0..b2c94ad95 100644 --- a/plancheck/expect_unknown_value_test.go +++ b/plancheck/expect_unknown_value_test.go @@ -287,40 +287,25 @@ func testProvider() *schema.Provider { return nil }, Schema: map[string]*schema.Schema{ - "string_attribute": { + "bool_attribute": { Optional: true, - Type: schema.TypeString, + Type: schema.TypeBool, }, - - "list_attribute": { - Type: schema.TypeList, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, + "float_attribute": { Optional: true, + Type: schema.TypeFloat, }, - "set_attribute": { - Type: schema.TypeSet, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, + "int_attribute": { Optional: true, + Type: schema.TypeInt, }, - "map_attribute": { - Type: schema.TypeMap, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Optional: true, - }, - "root_map_attribute": { - Type: schema.TypeMap, + "list_attribute": { + Type: schema.TypeList, Elem: &schema.Schema{ Type: schema.TypeString, }, Optional: true, }, - "list_nested_block": { Type: schema.TypeList, Optional: true, @@ -333,6 +318,20 @@ func testProvider() *schema.Provider { }, }, }, + "map_attribute": { + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "set_attribute": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, "set_nested_block": { Type: schema.TypeSet, Optional: true, @@ -345,6 +344,17 @@ func testProvider() *schema.Provider { }, }, }, + "string_attribute": { + Optional: true, + Type: schema.TypeString, + }, + "root_map_attribute": { + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, }, }, }, From 6915f0eecdd61610cb21fefe4028b9904fee25e3 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 15 Dec 2023 11:20:11 +0000 Subject: [PATCH 02/48] Add ExpectKnownValue plan check (#243) --- plancheck/expect_known_value.go | 192 ++++++++ plancheck/expect_known_value_test.go | 703 +++++++++++++++++++++++++++ 2 files changed, 895 insertions(+) create mode 100644 plancheck/expect_known_value.go create mode 100644 plancheck/expect_known_value_test.go diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go new file mode 100644 index 000000000..f7ed92719 --- /dev/null +++ b/plancheck/expect_known_value.go @@ -0,0 +1,192 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plancheck + +import ( + "context" + "fmt" + "reflect" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +// Resource Plan Check +var _ PlanCheck = expectKnownValue{} + +type expectKnownValue struct { + resourceAddress string + attributePath tfjsonpath.Path + knownValue knownvalue.KnownValue +} + +// CheckPlan implements the plan check logic. +func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, resp *CheckPlanResponse) { + var rc *tfjson.ResourceChange + + for _, resourceChange := range req.Plan.ResourceChanges { + if e.resourceAddress == resourceChange.Address { + rc = resourceChange + + break + } + } + + if rc == nil { + resp.Error = fmt.Errorf("%s - resource not found in plan", e.resourceAddress) + + return + } + + result, err := tfjsonpath.Traverse(rc.Change.After, e.attributePath) + + if err != nil { + resp.Error = err + + return + } + + if result == nil { + resp.Error = fmt.Errorf("attribute value is null") + + return + } + + switch reflect.TypeOf(result).Kind() { + case reflect.Bool: + v, ok := e.knownValue.(knownvalue.BoolValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: attribute value is bool, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(reflect.ValueOf(result).Interface()) { + resp.Error = fmt.Errorf("attribute value does not equal expected value: %v != %v", result, v) + } + // Float64 is the default type for all numerical values. + case reflect.Float64: + switch t := e.knownValue.(type) { + case + knownvalue.Float64Value: + if !t.Equal(result) { + resp.Error = fmt.Errorf("attribute value %v is not equal to %s", result, t) + + return + } + case knownvalue.Int64Value: + // nolint:forcetypeassert // result is reflect.Float64 Kind + f := result.(float64) + + if !t.Equal(int64(f)) { + resp.Error = fmt.Errorf("attribute value %v is not equal to %s", result, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: attribute type is %T, known value type is %T", result, t) + } + case reflect.Map: + switch t := e.knownValue.(type) { + case knownvalue.MapValue, + knownvalue.MapValuePartial, + knownvalue.NumElements, + knownvalue.ObjectValue, + knownvalue.ObjectValuePartial: + + elems := make(map[string]any) + + val := reflect.ValueOf(result) + + for _, key := range val.MapKeys() { + elems[key.String()] = val.MapIndex(key).Interface() + } + + if !t.Equal(elems) { + resp.Error = fmt.Errorf("attribute %v is not equal to expected value %v", elems, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: attribute type is list, or set, known value type is %T", t) + + return + } + case reflect.Slice: + switch t := e.knownValue.(type) { + case knownvalue.ListValue, + knownvalue.ListValuePartial, + knownvalue.NumElements, + knownvalue.SetValue, + knownvalue.SetValuePartial: + + var elems []any + + var elemsWithIndex []string + + val := reflect.ValueOf(result) + + for i := 0; i < val.Len(); i++ { + elems = append(elems, val.Index(i).Interface()) + elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) + } + + if !t.Equal(elems) { + switch e.knownValue.(type) { + case knownvalue.ListValuePartial: + resp.Error = fmt.Errorf("attribute %v does not contain elements at the specified indices %v", elemsWithIndex, t) + + return + case knownvalue.NumElements: + resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) + + return + case knownvalue.SetValuePartial: + resp.Error = fmt.Errorf("attribute %v does not contain %v", elems, t) + + return + } + + resp.Error = fmt.Errorf("attribute %v is not equal to expected value %v", elems, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: attribute type is list, or set, known value type is %T", t) + + return + } + // String will need to handle json.Number if tfjson.Plan is modified to use json.Number for numerical values. + case reflect.String: + v, ok := e.knownValue.(knownvalue.StringValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: attribute value is string, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(reflect.ValueOf(result).Interface()) { + resp.Error = fmt.Errorf("attribute value does not equal expected value: %v != %v", result, v) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: attribute type is %T, known value type is %T", result, e.knownValue) + + return + } +} + +// ExpectKnownValue returns a plan check that asserts that the specified attribute at the given resource has a known type, and value. +func ExpectKnownValue(resourceAddress string, attributePath tfjsonpath.Path, knownValue knownvalue.KnownValue) PlanCheck { + return expectKnownValue{ + resourceAddress: resourceAddress, + attributePath: attributePath, + knownValue: knownValue, + } +} diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go new file mode 100644 index 000000000..41bba2b9c --- /dev/null +++ b/plancheck/expect_known_value_test.go @@ -0,0 +1,703 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plancheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +//func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { +// t.Parallel() +// +// testCases := map[string]struct { +// knownValue knownvalue.KnownValue +// req plancheck.CheckPlanRequest +// expected plancheck.CheckPlanResponse +// }{ +// "equal": { +// knownValue: knownvalue.NewInt64Value(123), +// req: plancheck.CheckPlanRequest{ +// Plan: &tfjson.Plan{ +// ResourceChanges: []*tfjson.ResourceChange{ +// { +// Address: "example_resource.test", +// Change: &tfjson.Change{ +// After: map[string]any{ +// "attribute": float64(123), // tfjson.Plan handles all numerical values as float64. +// }, +// }, +// }, +// }, +// }, +// }, +// expected: plancheck.CheckPlanResponse{}, +// }, +// } +// +// for name, testCase := range testCases { +// name, testCase := name, testCase +// +// t.Run(name, func(t *testing.T) { +// t.Parallel() +// +// e := plancheck.ExpectKnownValue("example_resource.test", tfjsonpath.New("attribute"), testCase.knownValue) +// +// resp := plancheck.CheckPlanResponse{} +// +// e.CheckPlan(context.Background(), testCase.req, &resp) +// +// if diff := cmp.Diff(resp, testCase.expected); diff != "" { +// t.Errorf("unexpected difference: %s", diff) +// } +// }) +// } +//} + +func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewInt64Value(123), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_nested_block"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_nested_block"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_nested_block"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_SetNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_SetNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_nested_block"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_nested_block"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_nested_block"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), knownvalue.NewStringValue("str")), + }, + }, + }, + }, + }) +} From f5035948dec36346d16786086bb4f3c578858af0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 15 Dec 2023 15:43:45 +0000 Subject: [PATCH 03/48] Handling different permutations for equality checking of interface type and value, and known value type and value (#243) --- plancheck/expect_known_value.go | 104 ++-- plancheck/expect_known_value_test.go | 885 ++++++++++++++++++++++----- 2 files changed, 801 insertions(+), 188 deletions(-) diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index f7ed92719..dfdba55f6 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -66,15 +66,15 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } if !v.Equal(reflect.ValueOf(result).Interface()) { - resp.Error = fmt.Errorf("attribute value does not equal expected value: %v != %v", result, v) + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, v) } - // Float64 is the default type for all numerical values. + // Float64 is the default type for all numerical values in tfjson.Plan. case reflect.Float64: switch t := e.knownValue.(type) { case knownvalue.Float64Value: if !t.Equal(result) { - resp.Error = fmt.Errorf("attribute value %v is not equal to %s", result, t) + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, t) return } @@ -83,75 +83,83 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r f := result.(float64) if !t.Equal(int64(f)) { - resp.Error = fmt.Errorf("attribute value %v is not equal to %s", result, t) + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, t) return } default: - resp.Error = fmt.Errorf("wrong type: attribute type is %T, known value type is %T", result, t) + resp.Error = fmt.Errorf("wrong type: attribute type is float64 or int64, known value type is %T", t) } case reflect.Map: - switch t := e.knownValue.(type) { - case knownvalue.MapValue, - knownvalue.MapValuePartial, - knownvalue.NumElements, - knownvalue.ObjectValue, - knownvalue.ObjectValuePartial: + elems := make(map[string]any) + + val := reflect.ValueOf(result) - elems := make(map[string]any) + for _, key := range val.MapKeys() { + elems[key.String()] = val.MapIndex(key).Interface() + } - val := reflect.ValueOf(result) + switch t := e.knownValue.(type) { + case knownvalue.MapValue, + knownvalue.ObjectValue: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", elems, t) - for _, key := range val.MapKeys() { - elems[key.String()] = val.MapIndex(key).Interface() + return } + case knownvalue.MapValuePartial, + knownvalue.ObjectValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("attribute value: %v does not contain: %v", elems, t) + return + } + case knownvalue.NumElements: if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute %v is not equal to expected value %v", elems, t) + resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) return } default: - resp.Error = fmt.Errorf("wrong type: attribute type is list, or set, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: attribute type is map, or object, known value type is %T", t) return } case reflect.Slice: - switch t := e.knownValue.(type) { - case knownvalue.ListValue, - knownvalue.ListValuePartial, - knownvalue.NumElements, - knownvalue.SetValue, - knownvalue.SetValuePartial: + var elems []any - var elems []any + var elemsWithIndex []string - var elemsWithIndex []string + val := reflect.ValueOf(result) - val := reflect.ValueOf(result) - - for i := 0; i < val.Len(); i++ { - elems = append(elems, val.Index(i).Interface()) - elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) - } + for i := 0; i < val.Len(); i++ { + elems = append(elems, val.Index(i).Interface()) + elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) + } + switch t := e.knownValue.(type) { + case knownvalue.ListValue, + knownvalue.SetValue: if !t.Equal(elems) { - switch e.knownValue.(type) { - case knownvalue.ListValuePartial: - resp.Error = fmt.Errorf("attribute %v does not contain elements at the specified indices %v", elemsWithIndex, t) - - return - case knownvalue.NumElements: - resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", elems, t) - return - case knownvalue.SetValuePartial: - resp.Error = fmt.Errorf("attribute %v does not contain %v", elems, t) + return + } + case knownvalue.ListValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("attribute value: %v does not contain elements at the specified indices: %v", elemsWithIndex, t) - return - } + return + } + case knownvalue.NumElements: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) - resp.Error = fmt.Errorf("attribute %v is not equal to expected value %v", elems, t) + return + } + case knownvalue.SetValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("attribute value: %v does not contain: %v", elems, t) return } @@ -160,7 +168,6 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - // String will need to handle json.Number if tfjson.Plan is modified to use json.Number for numerical values. case reflect.String: v, ok := e.knownValue.(knownvalue.StringValue) @@ -171,12 +178,15 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } if !v.Equal(reflect.ValueOf(result).Interface()) { - resp.Error = fmt.Errorf("attribute value does not equal expected value: %v != %v", result, v) + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, v) return } default: - resp.Error = fmt.Errorf("wrong type: attribute type is %T, known value type is %T", result, e.knownValue) + errorStr := fmt.Sprintf("unrecognised attribute type: %T, known value type is %T", result, e.knownValue) + errorStr += "\n\nThis is an error in plancheck.ExpectKnownValue.\nPlease report this to the maintainers." + + resp.Error = fmt.Errorf(errorStr) return } diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 41bba2b9c..1d3d55eba 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -4,8 +4,13 @@ package plancheck_test import ( + "context" + "fmt" + "regexp" "testing" + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" r "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -14,53 +19,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) -//func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { -// t.Parallel() -// -// testCases := map[string]struct { -// knownValue knownvalue.KnownValue -// req plancheck.CheckPlanRequest -// expected plancheck.CheckPlanResponse -// }{ -// "equal": { -// knownValue: knownvalue.NewInt64Value(123), -// req: plancheck.CheckPlanRequest{ -// Plan: &tfjson.Plan{ -// ResourceChanges: []*tfjson.ResourceChange{ -// { -// Address: "example_resource.test", -// Change: &tfjson.Change{ -// After: map[string]any{ -// "attribute": float64(123), // tfjson.Plan handles all numerical values as float64. -// }, -// }, -// }, -// }, -// }, -// }, -// expected: plancheck.CheckPlanResponse{}, -// }, -// } -// -// for name, testCase := range testCases { -// name, testCase := name, testCase -// -// t.Run(name, func(t *testing.T) { -// t.Parallel() -// -// e := plancheck.ExpectKnownValue("example_resource.test", tfjsonpath.New("attribute"), testCase.knownValue) -// -// resp := plancheck.CheckPlanResponse{} -// -// e.CheckPlan(context.Background(), testCase.req, &resp) -// -// if diff := cmp.Diff(resp, testCase.expected); diff != "" { -// t.Errorf("unexpected difference: %s", diff) -// } -// }) -// } -//} - func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { t.Parallel() @@ -73,15 +31,536 @@ func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - bool_attribute = true + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: attribute value is bool, known value type is knownvalue.Float64Value"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(false), + ), + }, + }, + ExpectError: regexp.MustCompile("attribute value: true does not equal expected value: false"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.NewStringValue("str"), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: attribute type is float64 or int64, known value type is knownvalue.StringValue"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.NewFloat64Value(3.21), + ), + }, + }, + ExpectError: regexp.MustCompile("attribute value: 1.23 does not equal expected value: 3.21"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewInt64Value(123), + ), + }, + }, + }, + }, + }) +} + +// TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongType highlights a limitation of tfjson.Plan in that all numerical +// values are represented as float64. +func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewStringValue("str"), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: attribute type is float64 or int64, known value type is knownvalue.StringValue"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewInt64Value(321), + ), + }, + }, + ExpectError: regexp.MustCompile("attribute value: 123 does not equal expected value: 321"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{}), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: attribute type is list, or set, known value type is knownvalue.MapValue"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value3"), + knownvalue.NewStringValue("value4"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`attribute value: \[value1 value2\] does not equal expected value: \[value3 value4\]`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +// No need to check KnownValueWrongType for ListPartial as all lists, and sets are []any in +// tfjson.Plan. +func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`attribute value: \[0:value1 1:value2\] does not contain elements at the specified indices: \[0:value3\]`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElements(3), + ), + }, + }, + ExpectError: regexp.MustCompile("attribute contains 2 elements, expected 3"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + tfjsonpath.New("list_nested_block"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), ), }, }, @@ -90,7 +569,7 @@ func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -102,15 +581,24 @@ func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - float_attribute = 1.23 + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("float_attribute"), - knownvalue.NewFloat64Value(1.23), + tfjsonpath.New("list_nested_block"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), ), }, }, @@ -119,7 +607,7 @@ func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -131,15 +619,20 @@ func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - int_attribute = 123 + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("int_attribute"), - knownvalue.NewInt64Value(123), + tfjsonpath.New("list_nested_block"), + knownvalue.NewNumElements(2), ), }, }, @@ -148,7 +641,7 @@ func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_List(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -160,20 +653,20 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] + map_attribute = { + key1 = "value1" + key2 = "value2" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), }), ), }, @@ -183,7 +676,7 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -195,29 +688,28 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] + map_attribute = { + key1 = "value1" + key2 = "value2" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value1"), - }), + tfjsonpath.New("map_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{}), ), }, }, + ExpectError: regexp.MustCompile("wrong type: attribute type is map, or object, known value type is knownvalue.ListValue"), }, }, }) } -func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -229,27 +721,31 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] + map_attribute = { + key1 = "value1" + key2 = "value2" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewNumElements(2), + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key3": knownvalue.NewStringValue("value3"), + "key4": knownvalue.NewStringValue("value4"), + }), ), }, }, + ExpectError: regexp.MustCompile(`attribute value: map\[key1:value1 key2:value2\] does not equal expected value: map\[key3:value3 key4:value4\]`), }, }, }) } -func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -261,11 +757,9 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_nested_block { - list_nested_block_attribute = "str" - } - list_nested_block { - list_nested_block_attribute = "rts" + map_attribute = { + key1 = "value1" + key2 = "value2" } } `, @@ -273,14 +767,9 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_nested_block"), - knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("str"), - }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), - }), + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), }), ), }, @@ -290,7 +779,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -302,11 +791,9 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_nested_block { - list_nested_block_attribute = "str" - } - list_nested_block { - list_nested_block_attribute = "rts" + map_attribute = { + key1 = "value1" + key2 = "value2" } } `, @@ -314,21 +801,20 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_nested_block"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), - }), + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key3": knownvalue.NewStringValue("value1"), }), ), }, }, + ExpectError: regexp.MustCompile(`attribute value: map\[key1:value1 key2:value2\] does not contain: map\[key3:value1\]`), }, }, }) } -func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -340,11 +826,9 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_nested_block { - list_nested_block_attribute = "str" - } - list_nested_block { - list_nested_block_attribute = "rts" + map_attribute = { + key1 = "value1" + key2 = "value2" } } `, @@ -352,7 +836,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_nested_block"), + tfjsonpath.New("map_attribute"), knownvalue.NewNumElements(2), ), }, @@ -362,7 +846,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -385,19 +869,17 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), - }), + knownvalue.NewNumElements(3), ), }, }, + ExpectError: regexp.MustCompile("attribute contains 2 elements, expected 3"), }, }, }) } -func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -409,19 +891,20 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - map_attribute = { - key1 = "value1" - key2 = "value2" - } + set_attribute = [ + "value1", + "value2" + ] } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), }), ), }, @@ -431,7 +914,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -443,27 +926,31 @@ func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - map_attribute = { - key1 = "value1" - key2 = "value2" - } + set_attribute = [ + "value1", + "value2" + ] } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("map_attribute"), - knownvalue.NewNumElements(2), + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value3"), + }), ), }, }, + ExpectError: regexp.MustCompile(`attribute value: \[value1 value2\] does not equal expected value: \[value1 value3\]`), }, }, }) } -func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { +func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -486,8 +973,7 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ knownvalue.NewStringValue("value2"), }), ), @@ -498,7 +984,7 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -522,11 +1008,12 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { "test_resource.one", tfjsonpath.New("set_attribute"), knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value2"), + knownvalue.NewStringValue("value3"), }), ), }, }, + ExpectError: regexp.MustCompile(`attribute value: \[value1 value2\] does not contain: \[value3\]`), }, }, }) @@ -694,10 +1181,126 @@ func TestExpectKnownValue_CheckPlan_String(t *testing.T) { `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), knownvalue.NewStringValue("str")), + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.NewStringValue("str")), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.NewBoolValue(true)), + }, + }, + ExpectError: regexp.MustCompile("wrong type: attribute value is string, known value type is knownvalue.BoolValue"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.NewStringValue("rts")), }, }, + ExpectError: regexp.MustCompile("attribute value: str does not equal expected value: rts"), }, }, }) } + +func TestExpectKnownValue_CheckPlan_UnknownAttributeType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + knownValue knownvalue.KnownValue + req plancheck.CheckPlanRequest + expectedErr error + }{ + "equal": { + knownValue: knownvalue.NewInt64Value(123), + req: plancheck.CheckPlanRequest{ + Plan: &tfjson.Plan{ + ResourceChanges: []*tfjson.ResourceChange{ + { + Address: "example_resource.test", + Change: &tfjson.Change{ + After: map[string]any{ + "attribute": float32(123), + }, + }, + }, + }, + }, + }, + expectedErr: fmt.Errorf("unrecognised attribute type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in plancheck.ExpectKnownValue.\nPlease report this to the maintainers."), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + e := plancheck.ExpectKnownValue("example_resource.test", tfjsonpath.New("attribute"), testCase.knownValue) + + resp := plancheck.CheckPlanResponse{} + + e.CheckPlan(context.Background(), testCase.req, &resp) + + if diff := cmp.Diff(resp.Error, testCase.expectedErr, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +var equateErrorMessage = cmp.Comparer(func(x, y error) bool { + if x == nil || y == nil { + return x == nil && y == nil + } + + return x.Error() == y.Error() +}) From 4f8eed97207fa530149d2c860bd465366da93d3b Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 15 Dec 2023 15:58:45 +0000 Subject: [PATCH 04/48] Adding tests for missing resource, and attribute value null (#243) --- plancheck/expect_known_value.go | 2 +- plancheck/expect_known_value_test.go | 57 ++++++++++++++++++++++++++ plancheck/expect_unknown_value_test.go | 7 ---- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index dfdba55f6..e597dd539 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -36,7 +36,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } if rc == nil { - resp.Error = fmt.Errorf("%s - resource not found in plan", e.resourceAddress) + resp.Error = fmt.Errorf("%s - Resource not found in plan ResourceChanges", e.resourceAddress) return } diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 1d3d55eba..003226a19 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -19,6 +19,63 @@ import ( "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) +func TestExpectKnownValue_CheckPlan_ResourceNotFound(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.two", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + ExpectError: regexp.MustCompile("test_resource.two - Resource not found in plan ResourceChanges"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {}`, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + ExpectError: regexp.MustCompile("attribute value is null"), + }, + }, + }) +} + func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { t.Parallel() diff --git a/plancheck/expect_unknown_value_test.go b/plancheck/expect_unknown_value_test.go index b2c94ad95..4a46387d2 100644 --- a/plancheck/expect_unknown_value_test.go +++ b/plancheck/expect_unknown_value_test.go @@ -348,13 +348,6 @@ func testProvider() *schema.Provider { Optional: true, Type: schema.TypeString, }, - "root_map_attribute": { - Type: schema.TypeMap, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Optional: true, - }, }, }, }, From a1f35f63e418a3a63658add9b21973529122ec39 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 18 Dec 2023 08:57:41 +0000 Subject: [PATCH 05/48] Adding plan checks for known output value and known output value at path (#243) --- plancheck/expect_known_output_value.go | 201 +++ .../expect_known_output_value_at_path.go | 203 +++ .../expect_known_output_value_at_path_test.go | 1507 +++++++++++++++++ plancheck/expect_known_output_value_test.go | 1466 ++++++++++++++++ plancheck/expect_known_value.go | 9 +- plancheck/expect_known_value_test.go | 10 +- 6 files changed, 3387 insertions(+), 9 deletions(-) create mode 100644 plancheck/expect_known_output_value.go create mode 100644 plancheck/expect_known_output_value_at_path.go create mode 100644 plancheck/expect_known_output_value_at_path_test.go create mode 100644 plancheck/expect_known_output_value_test.go diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go new file mode 100644 index 000000000..ddb93b713 --- /dev/null +++ b/plancheck/expect_known_output_value.go @@ -0,0 +1,201 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plancheck + +import ( + "context" + "fmt" + "reflect" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +// Resource Plan Check +var _ PlanCheck = expectKnownOutputValue{} + +type expectKnownOutputValue struct { + outputAddress string + knownValue knownvalue.KnownValue +} + +// CheckPlan implements the plan check logic. +func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequest, resp *CheckPlanResponse) { + var change *tfjson.Change + + for address, oc := range req.Plan.OutputChanges { + if e.outputAddress == address { + change = oc + + break + } + } + + if change == nil { + resp.Error = fmt.Errorf("%s - Output not found in plan OutputChanges", e.outputAddress) + + return + } + + result, err := tfjsonpath.Traverse(change.After, tfjsonpath.Path{}) + + if err != nil { + resp.Error = err + + return + } + + if result == nil { + resp.Error = fmt.Errorf("output value is null") + + return + } + + switch reflect.TypeOf(result).Kind() { + case reflect.Bool: + v, ok := e.knownValue.(knownvalue.BoolValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: output value is bool, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(reflect.ValueOf(result).Interface()) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + } + // Float64 is the default type for all numerical values in tfjson.Plan. + case reflect.Float64: + switch t := e.knownValue.(type) { + case + knownvalue.Float64Value: + if !t.Equal(result) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) + + return + } + case knownvalue.Int64Value: + // nolint:forcetypeassert // result is reflect.Float64 Kind + f := result.(float64) + + if !t.Equal(int64(f)) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: output value is float64 or int64, known value type is %T", t) + } + case reflect.Map: + elems := make(map[string]any) + + val := reflect.ValueOf(result) + + for _, key := range val.MapKeys() { + elems[key.String()] = val.MapIndex(key).Interface() + } + + switch t := e.knownValue.(type) { + case knownvalue.MapValue, + knownvalue.ObjectValue: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) + + return + } + case knownvalue.MapValuePartial, + knownvalue.ObjectValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) + + return + } + case knownvalue.NumElements: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: output type is map, or object, known value type is %T", t) + + return + } + case reflect.Slice: + var elems []any + + var elemsWithIndex []string + + val := reflect.ValueOf(result) + + for i := 0; i < val.Len(); i++ { + elems = append(elems, val.Index(i).Interface()) + elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) + } + + switch t := e.knownValue.(type) { + case knownvalue.ListValue, + knownvalue.SetValue: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) + + return + } + case knownvalue.ListValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not contain elements at the specified indices: %v", elemsWithIndex, t) + + return + } + case knownvalue.NumElements: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) + + return + } + case knownvalue.SetValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: output type is list, or set, known value type is %T", t) + + return + } + case reflect.String: + v, ok := e.knownValue.(knownvalue.StringValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(reflect.ValueOf(result).Interface()) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + + return + } + default: + errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) + errorStr += "\n\nThis is an error in plancheck.ExpectKnownOutputValue.\nPlease report this to the maintainers." + + resp.Error = fmt.Errorf(errorStr) + + return + } +} + +// ExpectKnownOutputValue returns a plan check that asserts that the specified output value +// has a known type, and value. +func ExpectKnownOutputValue(outputAddress string, knownValue knownvalue.KnownValue) PlanCheck { + return expectKnownOutputValue{ + outputAddress: outputAddress, + knownValue: knownValue, + } +} diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go new file mode 100644 index 000000000..ecc4240cc --- /dev/null +++ b/plancheck/expect_known_output_value_at_path.go @@ -0,0 +1,203 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plancheck + +import ( + "context" + "fmt" + "reflect" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +// Resource Plan Check +var _ PlanCheck = expectKnownOutputValueAtPath{} + +type expectKnownOutputValueAtPath struct { + outputAddress string + outputPath tfjsonpath.Path + knownValue knownvalue.KnownValue +} + +// CheckPlan implements the plan check logic. +func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPlanRequest, resp *CheckPlanResponse) { + var change *tfjson.Change + + for address, oc := range req.Plan.OutputChanges { + if e.outputAddress == address { + change = oc + + break + } + } + + if change == nil { + resp.Error = fmt.Errorf("%s - Output not found in plan OutputChanges", e.outputAddress) + + return + } + + result, err := tfjsonpath.Traverse(change.After, e.outputPath) + + if err != nil { + resp.Error = err + + return + } + + if result == nil { + resp.Error = fmt.Errorf("output value is null") + + return + } + + switch reflect.TypeOf(result).Kind() { + case reflect.Bool: + v, ok := e.knownValue.(knownvalue.BoolValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: output value is bool, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(reflect.ValueOf(result).Interface()) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + } + // Float64 is the default type for all numerical values in tfjson.Plan. + case reflect.Float64: + switch t := e.knownValue.(type) { + case + knownvalue.Float64Value: + if !t.Equal(result) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) + + return + } + case knownvalue.Int64Value: + // nolint:forcetypeassert // result is reflect.Float64 Kind + f := result.(float64) + + if !t.Equal(int64(f)) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: output value is float64 or int64, known value type is %T", t) + } + case reflect.Map: + elems := make(map[string]any) + + val := reflect.ValueOf(result) + + for _, key := range val.MapKeys() { + elems[key.String()] = val.MapIndex(key).Interface() + } + + switch t := e.knownValue.(type) { + case knownvalue.MapValue, + knownvalue.ObjectValue: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) + + return + } + case knownvalue.MapValuePartial, + knownvalue.ObjectValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) + + return + } + case knownvalue.NumElements: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: output value is map, or object, known value type is %T", t) + + return + } + case reflect.Slice: + var elems []any + + var elemsWithIndex []string + + val := reflect.ValueOf(result) + + for i := 0; i < val.Len(); i++ { + elems = append(elems, val.Index(i).Interface()) + elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) + } + + switch t := e.knownValue.(type) { + case knownvalue.ListValue, + knownvalue.SetValue: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) + + return + } + case knownvalue.ListValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not contain elements at the specified indices: %v", elemsWithIndex, t) + + return + } + case knownvalue.NumElements: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) + + return + } + case knownvalue.SetValuePartial: + if !t.Equal(elems) { + resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) + + return + } + default: + resp.Error = fmt.Errorf("wrong type: output value is list, or set, known value type is %T", t) + + return + } + case reflect.String: + v, ok := e.knownValue.(knownvalue.StringValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(reflect.ValueOf(result).Interface()) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + + return + } + default: + errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) + errorStr += "\n\nThis is an error in plancheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers." + + resp.Error = fmt.Errorf(errorStr) + + return + } +} + +// ExpectKnownOutputValueAtPath returns a plan check that asserts that the specified output at the given path +// has a known type and value. +func ExpectKnownOutputValueAtPath(outputAddress string, outputPath tfjsonpath.Path, knownValue knownvalue.KnownValue) PlanCheck { + return expectKnownOutputValueAtPath{ + outputAddress: outputAddress, + outputPath: outputPath, + knownValue: knownValue, + } +} diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go new file mode 100644 index 000000000..4f2cd7c67 --- /dev/null +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -0,0 +1,1507 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plancheck_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +func TestExpectKnownOutputValueAtPath_CheckPlan_ResourceNotFound(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_two_output", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + ExpectError: regexp.MustCompile("test_resource_two_output - Output not found in plan OutputChanges"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {} + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + ExpectError: regexp.MustCompile("output value is null"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is bool, known value type is knownvalue.Float64Value"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(false), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: true does not equal expected value: false"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("float_attribute"), + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("float_attribute"), + knownvalue.NewStringValue("str"), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("float_attribute"), + knownvalue.NewFloat64Value(3.21), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: 1.23 does not equal expected value: 3.21"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NewInt64Value(123), + ), + }, + }, + }, + }, + }) +} + +// TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongType highlights a limitation of tfjson.Plan in that all numerical +// values are represented as float64. +func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NewStringValue("str"), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NewInt64Value(321), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{}), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is list, or set, known value type is knownvalue.MapValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value3"), + knownvalue.NewStringValue("value4"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value3 value4\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +// No need to check KnownValueWrongType for ListPartial as all lists, and sets are []any in +// tfjson.Plan. +func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[0:value1 1:value2\] does not contain elements at the specified indices: \[0:value3\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElements(3), + ), + }, + }, + ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_nested_block"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_nested_block"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_nested_block"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{}), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is map, or object, known value type is knownvalue.ListValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key3": knownvalue.NewStringValue("value3"), + "key4": knownvalue.NewStringValue("value4"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not equal expected value: map\[key3:value3 key4:value4\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key3": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not contain: map\[key3:value1\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.NewNumElements(3), + ), + }, + }, + ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value1 value3\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not contain: \[value3\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_SetNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_nested_block"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_nested_block"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_nested_block"), + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("string_attribute"), + knownvalue.NewStringValue("str")), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("string_attribute"), + knownvalue.NewBoolValue(true)), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is string, known value type is knownvalue.BoolValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("string_attribute"), + knownvalue.NewStringValue("rts")), + }, + }, + ExpectError: regexp.MustCompile("output value: str does not equal expected value: rts"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_UnknownAttributeType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + knownValue knownvalue.KnownValue + req plancheck.CheckPlanRequest + expectedErr error + }{ + "unrecognised-type": { + knownValue: knownvalue.NewInt64Value(123), + req: plancheck.CheckPlanRequest{ + Plan: &tfjson.Plan{ + OutputChanges: map[string]*tfjson.Change{ + "float32_output": { + After: float32(123), + }, + }, + }, + }, + expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in plancheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers."), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + e := plancheck.ExpectKnownOutputValueAtPath("float32_output", tfjsonpath.Path{}, testCase.knownValue) + + resp := plancheck.CheckPlanResponse{} + + e.CheckPlan(context.Background(), testCase.req, &resp) + + if diff := cmp.Diff(resp.Error, testCase.expectedErr, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go new file mode 100644 index 000000000..01388e5c4 --- /dev/null +++ b/plancheck/expect_known_output_value_test.go @@ -0,0 +1,1466 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plancheck_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" +) + +func TestExpectKnownOutputValue_CheckPlan_OutputNotFound(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_not_found", + knownvalue.NewBoolValue(true), + ), + }, + }, + ExpectError: regexp.MustCompile("bool_not_found - Output not found in plan OutputChanges"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {} + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.NewBoolValue(true), + ), + }, + }, + ExpectError: regexp.MustCompile("output value is null"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is bool, known value type is knownvalue.Float64Value"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.NewBoolValue(false), + ), + }, + }, + ExpectError: regexp.MustCompile("value: true does not equal expected value: false"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output float64_output { + value = test_resource.one.float_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "float64_output", + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output float64_output { + value = test_resource.one.float_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "float64_output", + knownvalue.NewStringValue("str"), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output float64_output { + value = test_resource.one.float_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "float64_output", + knownvalue.NewFloat64Value(3.21), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: 1.23 does not equal expected value: 3.21"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NewInt64Value(123), + ), + }, + }, + }, + }, + }) +} + +// TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongType highlights a limitation of tfjson.Plan in that all numerical +// values are represented as float64. +func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NewStringValue("str"), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NewInt64Value(321), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{}), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output type is list, or set, known value type is knownvalue.MapValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value3"), + knownvalue.NewStringValue("value4"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value3 value4\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +// No need to check KnownValueWrongType for ListPartial as all lists, and sets are []any in +// tfjson.Plan. +func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[0:value1 1:value2\] does not contain elements at the specified indices: \[0:value3\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_ListNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_output", + knownvalue.NewNumElements(3), + ), + }, + }, + ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output list_nested_block_output { + value = test_resource.one.list_nested_block + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_nested_block_output", + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output list_nested_block_output { + value = test_resource.one.list_nested_block + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_nested_block_output", + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output list_nested_block_output { + value = test_resource.one.list_nested_block + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "list_nested_block_output", + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewListValue([]knownvalue.KnownValue{}), + ), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output type is map, or object, known value type is knownvalue.ListValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key3": knownvalue.NewStringValue("value3"), + "key4": knownvalue.NewStringValue("value4"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not equal expected value: map\[key3:value3 key4:value4\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key3": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not contain: map\[key3:value1\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_MapNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "map_output", + knownvalue.NewNumElements(3), + ), + }, + }, + ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_output", + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_output", + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value1 value3\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_output", + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_output", + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value3"), + }), + ), + }, + }, + ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not contain: \[value3\]`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_SetNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_output", + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_SetNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output set_nested_block_output { + value = test_resource.one.set_nested_block + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_nested_block_output", + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("str"), + }), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output set_nested_block_output { + value = test_resource.one.set_nested_block + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_nested_block_output", + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + }), + }), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output set_nested_block_output { + value = test_resource.one.set_nested_block + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "set_nested_block_output", + knownvalue.NewNumElements(2), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output string_output { + value = test_resource.one.string_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "string_output", + knownvalue.NewStringValue("str")), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output string_output { + value = test_resource.one.string_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "string_output", + knownvalue.NewBoolValue(true)), + }, + }, + ExpectError: regexp.MustCompile("wrong type: output value is string, known value type is knownvalue.BoolValue"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output string_output { + value = test_resource.one.string_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "string_output", + knownvalue.NewStringValue("rts")), + }, + }, + ExpectError: regexp.MustCompile("output value: str does not equal expected value: rts"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_UnknownAttributeType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + knownValue knownvalue.KnownValue + req plancheck.CheckPlanRequest + expectedErr error + }{ + "unrecognised-type": { + knownValue: knownvalue.NewInt64Value(123), + req: plancheck.CheckPlanRequest{ + Plan: &tfjson.Plan{ + OutputChanges: map[string]*tfjson.Change{ + "float32_output": { + After: float32(123), + }, + }, + }, + }, + expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in plancheck.ExpectKnownOutputValue.\nPlease report this to the maintainers."), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + e := plancheck.ExpectKnownOutputValue("float32_output", testCase.knownValue) + + resp := plancheck.CheckPlanResponse{} + + e.CheckPlan(context.Background(), testCase.req, &resp) + + if diff := cmp.Diff(resp.Error, testCase.expectedErr, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index e597dd539..3b814678e 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -88,7 +88,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } default: - resp.Error = fmt.Errorf("wrong type: attribute type is float64 or int64, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: attribute value is float64 or int64, known value type is %T", t) } case reflect.Map: elems := make(map[string]any) @@ -121,7 +121,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } default: - resp.Error = fmt.Errorf("wrong type: attribute type is map, or object, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: attribute value is map, or object, known value type is %T", t) return } @@ -164,7 +164,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } default: - resp.Error = fmt.Errorf("wrong type: attribute type is list, or set, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: attribute value is list, or set, known value type is %T", t) return } @@ -192,7 +192,8 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } } -// ExpectKnownValue returns a plan check that asserts that the specified attribute at the given resource has a known type, and value. +// ExpectKnownValue returns a plan check that asserts that the specified attribute at the given resource +// has a known type and value. func ExpectKnownValue(resourceAddress string, attributePath tfjsonpath.Path, knownValue knownvalue.KnownValue) PlanCheck { return expectKnownValue{ resourceAddress: resourceAddress, diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 003226a19..0ba7a5b35 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -218,7 +218,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute type is float64 or int64, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: attribute value is float64 or int64, known value type is knownvalue.StringValue"), }, }, }) @@ -309,7 +309,7 @@ func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute type is float64 or int64, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: attribute value is float64 or int64, known value type is knownvalue.StringValue"), }, }, }) @@ -407,7 +407,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute type is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile("wrong type: attribute value is list, or set, known value type is knownvalue.MapValue"), }, }, }) @@ -760,7 +760,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute type is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile("wrong type: attribute value is map, or object, known value type is knownvalue.ListValue"), }, }, }) @@ -1315,7 +1315,7 @@ func TestExpectKnownValue_CheckPlan_UnknownAttributeType(t *testing.T) { req plancheck.CheckPlanRequest expectedErr error }{ - "equal": { + "unrecognised-type": { knownValue: knownvalue.NewInt64Value(123), req: plancheck.CheckPlanRequest{ Plan: &tfjson.Plan{ From 853a3e423d8ec9a972786c32e5f71fd88b5924a8 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 18 Dec 2023 11:26:00 +0000 Subject: [PATCH 06/48] Adding documentation (#243) --- knownvalue/bool.go | 2 + knownvalue/float64.go | 2 + knownvalue/int64.go | 2 + knownvalue/list.go | 2 + knownvalue/list_partial.go | 6 +- knownvalue/map.go | 2 + knownvalue/map_partial.go | 2 + knownvalue/num_elements.go | 16 +- knownvalue/num_elements_test.go | 4 +- knownvalue/object.go | 2 + knownvalue/object_partial.go | 2 + knownvalue/set.go | 2 + knownvalue/set_partial.go | 2 + knownvalue/string.go | 2 + plancheck/expect_known_output_value.go | 4 +- .../expect_known_output_value_at_path.go | 4 +- .../expect_known_output_value_at_path_test.go | 14 +- plancheck/expect_known_output_value_test.go | 14 +- plancheck/expect_known_value.go | 4 +- plancheck/expect_known_value_test.go | 14 +- website/data/plugin-testing-nav-data.json | 4 + .../testing/acceptance-tests/known-values.mdx | 517 ++++++++++++++++++ .../acceptance-tests/plan-checks/output.mdx | 86 ++- .../acceptance-tests/plan-checks/resource.mdx | 43 +- 24 files changed, 704 insertions(+), 48 deletions(-) create mode 100644 website/docs/plugin/testing/acceptance-tests/known-values.mdx diff --git a/knownvalue/bool.go b/knownvalue/bool.go index 3679ec132..2bb912a58 100644 --- a/knownvalue/bool.go +++ b/knownvalue/bool.go @@ -7,6 +7,8 @@ import "strconv" var _ KnownValue = BoolValue{} +// BoolValue is a KnownValue for asserting equality between the value +// supplied to NewBoolValue and the value passed to the Equal method. type BoolValue struct { value bool } diff --git a/knownvalue/float64.go b/knownvalue/float64.go index a9727ee3c..88081ea45 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -9,6 +9,8 @@ import ( var _ KnownValue = Float64Value{} +// Float64Value is a KnownValue for asserting equality between the value +// supplied to NewFloat64Value and the value passed to the Equal method. type Float64Value struct { value float64 } diff --git a/knownvalue/int64.go b/knownvalue/int64.go index 2ec7bfbcb..6c9a04126 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -9,6 +9,8 @@ import ( var _ KnownValue = Int64Value{} +// Int64Value is a KnownValue for asserting equality between the value +// supplied to NewInt64Value and the value passed to the Equal method. type Int64Value struct { value int64 } diff --git a/knownvalue/list.go b/knownvalue/list.go index 95e68ea9a..b68121ea0 100644 --- a/knownvalue/list.go +++ b/knownvalue/list.go @@ -9,6 +9,8 @@ import ( var _ KnownValue = ListValue{} +// ListValue is a KnownValue for asserting equality between the value +// supplied to NewListValue and the value passed to the Equal method. type ListValue struct { value []KnownValue } diff --git a/knownvalue/list_partial.go b/knownvalue/list_partial.go index 184e7f96e..7fe6a0de2 100644 --- a/knownvalue/list_partial.go +++ b/knownvalue/list_partial.go @@ -12,6 +12,8 @@ import ( var _ KnownValue = ListValuePartial{} +// ListValuePartial is a KnownValue for asserting equality between the value +// supplied to NewListValuePartial and the value passed to the Equal method. type ListValuePartial struct { value map[int]KnownValue } @@ -68,7 +70,9 @@ func (v ListValuePartial) String() string { } // NewListValuePartial returns a KnownValue for asserting equality between the -// supplied map[int]KnownValue and the value passed to the Equal method. +// supplied map[int]KnownValue and the value passed to the Equal method. The +// map keys correspond to the position of the zero-ordered element within the +// list that is being checked. func NewListValuePartial(value map[int]KnownValue) ListValuePartial { return ListValuePartial{ value: value, diff --git a/knownvalue/map.go b/knownvalue/map.go index 0f11558f4..ae243ff97 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -10,6 +10,8 @@ import ( var _ KnownValue = MapValue{} +// MapValue is a KnownValue for asserting equality between the value +// supplied to NewMapValue and the value passed to the Equal method. type MapValue struct { value map[string]KnownValue } diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index 9c9e776db..cd6f16047 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -10,6 +10,8 @@ import ( var _ KnownValue = MapValuePartial{} +// MapValuePartial is a KnownValue for asserting equality between the value +// supplied to NewMapValuePartial and the value passed to the Equal method. type MapValuePartial struct { value map[string]KnownValue } diff --git a/knownvalue/num_elements.go b/knownvalue/num_elements.go index 60712aee5..ceb1a084c 100644 --- a/knownvalue/num_elements.go +++ b/knownvalue/num_elements.go @@ -5,15 +5,17 @@ package knownvalue import "strconv" -var _ KnownValue = NumElements{} +var _ KnownValue = NumElementsValue{} -type NumElements struct { +// NumElementsValue is a KnownValue for asserting equality between the value +// supplied to NewNumElementsValue and the value passed to the Equal method. +type NumElementsValue struct { num int } // Equal verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. -func (v NumElements) Equal(other any) bool { +func (v NumElementsValue) Equal(other any) bool { mapVal, mapOk := other.(map[string]any) sliceVal, sliceOk := other.([]any) @@ -34,14 +36,14 @@ func (v NumElements) Equal(other any) bool { } // String returns the string representation of the value. -func (v NumElements) String() string { +func (v NumElementsValue) String() string { return strconv.FormatInt(int64(v.num), 10) } -// NewNumElements returns a KnownValue for asserting that +// NewNumElementsValue returns a KnownValue for asserting that // a list, map, object, or set contains num elements. -func NewNumElements(num int) NumElements { - return NumElements{ +func NewNumElementsValue(num int) NumElementsValue { + return NumElementsValue{ num: num, } } diff --git a/knownvalue/num_elements_test.go b/knownvalue/num_elements_test.go index 97b587ddc..2dcae603f 100644 --- a/knownvalue/num_elements_test.go +++ b/knownvalue/num_elements_test.go @@ -57,7 +57,7 @@ func TestNumElements_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewNumElements(3).Equal(testCase.other) + got := knownvalue.NewNumElementsValue(3).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -69,7 +69,7 @@ func TestNumElements_Equal(t *testing.T) { func TestNumElements_String(t *testing.T) { t.Parallel() - got := knownvalue.NewNumElements(2).String() + got := knownvalue.NewNumElementsValue(2).String() if diff := cmp.Diff(got, "2"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/knownvalue/object.go b/knownvalue/object.go index 418905685..9e114b398 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -10,6 +10,8 @@ import ( var _ KnownValue = ObjectValue{} +// ObjectValue is a KnownValue for asserting equality between the value +// supplied to NewObjectValue and the value passed to the Equal method. type ObjectValue struct { value map[string]KnownValue } diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index 721184b4f..5e99990db 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -10,6 +10,8 @@ import ( var _ KnownValue = ObjectValuePartial{} +// ObjectValuePartial is a KnownValue for asserting equality between the value +// supplied to NewObjectValuePartial and the value passed to the Equal method. type ObjectValuePartial struct { value map[string]KnownValue } diff --git a/knownvalue/set.go b/knownvalue/set.go index 605fe3cf3..3114d763c 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -9,6 +9,8 @@ import ( var _ KnownValue = SetValue{} +// SetValue is a KnownValue for asserting equality between the value +// supplied to NewSetValue and the value passed to the Equal method. type SetValue struct { value []KnownValue } diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index d2dee6620..56bf11fce 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -9,6 +9,8 @@ import ( var _ KnownValue = SetValuePartial{} +// SetValuePartial is a KnownValue for asserting equality between the value +// supplied to NewSetValuePartial and the value passed to the Equal method. type SetValuePartial struct { value []KnownValue } diff --git a/knownvalue/string.go b/knownvalue/string.go index 603363d5a..f8a5194e4 100644 --- a/knownvalue/string.go +++ b/knownvalue/string.go @@ -5,6 +5,8 @@ package knownvalue var _ KnownValue = StringValue{} +// StringValue is a KnownValue for asserting equality between the value +// supplied to NewStringValue and the value passed to the Equal method. type StringValue struct { value string } diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go index ddb93b713..7131cc7da 100644 --- a/plancheck/expect_known_output_value.go +++ b/plancheck/expect_known_output_value.go @@ -113,7 +113,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } - case knownvalue.NumElements: + case knownvalue.NumElementsValue: if !t.Equal(elems) { resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) @@ -150,7 +150,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } - case knownvalue.NumElements: + case knownvalue.NumElementsValue: if !t.Equal(elems) { resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go index ecc4240cc..c5859e915 100644 --- a/plancheck/expect_known_output_value_at_path.go +++ b/plancheck/expect_known_output_value_at_path.go @@ -114,7 +114,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } - case knownvalue.NumElements: + case knownvalue.NumElementsValue: if !t.Equal(elems) { resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) @@ -151,7 +151,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } - case knownvalue.NumElements: + case knownvalue.NumElementsValue: if !t.Equal(elems) { resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index 4f2cd7c67..e605fa20d 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -612,7 +612,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -648,7 +648,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElements(3), + knownvalue.NewNumElementsValue(3), ), }, }, @@ -774,7 +774,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockNumElements(t *te plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -1003,7 +1003,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -1039,7 +1039,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testi plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElements(3), + knownvalue.NewNumElementsValue(3), ), }, }, @@ -1232,7 +1232,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -1357,7 +1357,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockNumElements(t *tes plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 01388e5c4..19e3445f8 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -593,7 +593,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -628,7 +628,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewNumElements(3), + knownvalue.NewNumElementsValue(3), ), }, }, @@ -751,7 +751,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockNumElements(t *testing. PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -974,7 +974,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -1009,7 +1009,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewNumElements(3), + knownvalue.NewNumElementsValue(3), ), }, }, @@ -1197,7 +1197,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -1319,7 +1319,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockNumElements(t *testing.T PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index 3b814678e..04305463c 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -114,7 +114,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - case knownvalue.NumElements: + case knownvalue.NumElementsValue: if !t.Equal(elems) { resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) @@ -151,7 +151,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - case knownvalue.NumElements: + case knownvalue.NumElementsValue: if !t.Equal(elems) { resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 0ba7a5b35..f866575f5 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -543,7 +543,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -575,7 +575,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElements(3), + knownvalue.NewNumElementsValue(3), ), }, }, @@ -689,7 +689,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -894,7 +894,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -926,7 +926,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElements(3), + knownvalue.NewNumElementsValue(3), ), }, }, @@ -1099,7 +1099,7 @@ func TestExpectKnownValue_CheckPlan_SetNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, @@ -1212,7 +1212,7 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.NewNumElements(2), + knownvalue.NewNumElementsValue(2), ), }, }, diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index 72d37fdcb..054f09a21 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -50,6 +50,10 @@ } ] }, + { + "title": "Known Values", + "path": "acceptance-tests/known-values" + }, { "title": "Sweepers", "path": "acceptance-tests/sweepers" diff --git a/website/docs/plugin/testing/acceptance-tests/known-values.mdx b/website/docs/plugin/testing/acceptance-tests/known-values.mdx new file mode 100644 index 000000000..83bef84f8 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-values.mdx @@ -0,0 +1,517 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + How to use known values in the testing module. + Known values define an expected type, and value for a resource attribute, or output value in a Terraform plan or in Terraform state. +--- + +# Known Values + +Specify types, and values for use with plan checks and state checks. + +## Usage + +Example uses in the testing module include: + +- The [`ExpectknownValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/resource), [`ExpectKnownOutputValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output) and [`ExpectKnownOutputValueAtPath()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output) [built-in plan checks](/terraform/plugin/testing/acceptance-tests/plan-checks) use known values for asserting whether a specific resource attribute, or output value has a particular type, and value. + +## Concepts + +Known Values are for use in conjunction with plan checks and state checks, both of which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan, or Terraform state. The known value types that are defined (e.g., `BoolValue`), have been named to match the types defined within [Terraform Plugin Framework](https://developer.hashicorp.com/terraform/plugin/framework/handling-data/types). + +## Using a Known Value + +The known value types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known values are instantiated by calling the `New` constructor function. + +```go +knownvalue.NewBoolValue(true) +``` + +For known values that represents collections, or objects, nesting of known values can be used to define a "composite" known value for use in asserting against a resource attribute, or output value that contains other values. + +```go +knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), +}) +``` + +## Known Value Types + +The following table describes the correspondence between attributes, and [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types. Output value correspond to the known value types in same way on the basis of the attribute to which the output value refers. + +| Framework Attribute Type | SDKv2 Attribute Type | Known Value Type | +|---------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------| +| `schema.BoolAttribute` | `schema.TypeBool` | [knownvalue.BoolValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValue) | +| `schema.Float64Attribute` | `schema.TypeFloat` | [knownvalue.Float64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Value) | +| `schema.Int64Attribute` | `schema.TypeInt` | [knownvalue.Int64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Value) | +| `schema.ListAttribute` | `schema.TypeList` | [knownvalue.ListValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValue) | +| `schema.MapAttribute` | `schema.TypeMap` | [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) | +| `schema.ObjectAttribute` | N/A | [knownvalue.ObjectValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValue) | +| `schema.SetAttribute` | `schema.TypeSet` | [knownvalue.SetValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValue) | +| `schema.StringAttribute` | `schema.TypeString` | [knownvalue.StringValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValue) | + +Additionally, there are known values for use in plan checks, and state checks, in which only a part, or subset of a collection or object needs to be asserted. + +| Framework Attribute Type | SDKv2 Attribute Type | Known Value Type | +|--------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------| +| `schema.ListAttribute` | `schema.TypeList` | [knownvalue.ListValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartial) | +| `schema.MapAttribute` | `schema.TypeMap` | [knownvalue.MapValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartial) | +| `schema.ObjectAttribute` | N/A | [knownvalue.ObjectValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartial) | +| `schema.SetAttribute` | `schema.TypeSet` | [knownvalue.SetValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartial) | + +There are also general purpose known value types for use, for example, in asserting the number of elements in a collection or object: + +* [knownvalue.NumElements](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumElements) + + +### Bool Known Value + +Example usage of [knownvalue.BoolValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} +``` + +### Float64 Known Value + +Example usage of [knownvalue.Float64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Value) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.NewFloat64Value(1.23), + ), + }, + }, + }, + }, + }) +} +``` + +### Int64 Known Value + +Example usage of [knownvalue.Int64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Value) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewInt64Value(123), + ), + }, + }, + }, + }, + }) +} +``` + +### List Known Value + +Example usage of [knownvalue.ListValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### List Partial Known Value + +Example usage of [knownvalue.ListValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +In this example, only the first element within the list is checked. + +```go +func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + 0: knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### Num Elements Known Value + +Example usage of [knownvalue.NumElements](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumElements) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElementsValue(2), + ), + }, + }, + }, + }, + }) +} +``` + +### Map Known Value + +Example usage of [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### Map Partial Known Value + +Example usage of [knownvalue.MapValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### Object Known Value + +Example usage of [knownvalue.ObjectValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + object_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("object_attribute"), + knownvalue.NewObjectValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### Object Partial Known Value + +Example usage of [knownvalue.ObjectValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + object_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("object_attribute"), + knownvalue.NewObjectValuePartial(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### Set Known Value + +Example usage of [knownvalue.SetValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value1"), + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### Set Partial Known Value + +Example usage of [knownvalue.SetValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewStringValue("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +### String Known Value + +Example usage of [knownvalue.StringValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.NewStringValue("str")), + }, + }, + }, + }, + }) +} +``` \ No newline at end of file diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx index 8e8edd1bd..a3410de9a 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx @@ -9,12 +9,86 @@ description: >- The `terraform-plugin-testing` module provides a package [`plancheck`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck) with built-in output value plan checks for common use-cases: -| Check | Description | -|------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------| -| [`plancheck.ExpectNullOutputValue(address)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectNullOutputValue) | Asserts the output at the specified address has a null value. | -| [`plancheck.ExpectNullOutputValueAtPath(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectNullOutputValueAtPath) | Asserts the output at the specified address, and path has a null value. | -| [`plancheck.ExpectUnknownOutputValue(address)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectUnknownOutputValue) | Asserts the output at the specified address has an unknown value. | -| [`plancheck.ExpectUnknownOutputValueAtPath(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectUnknownOutputValueAtPath) | Asserts the output at the specified address, and path has an unknown value. | +| Check | Description | +|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------| +| [`plancheck.ExpectKnownOutputValue(address, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownOutputValue) | Asserts the output at the specified address has the specified type, and value. | +| [`plancheck.ExpectKnownOutputValueAtPath(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownOutputValueAtPath) | Asserts the output at the specified address, and path has the specified type, and value. | +| [`plancheck.ExpectNullOutputValue(address)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectNullOutputValue) | Asserts the output at the specified address has a null value. | +| [`plancheck.ExpectNullOutputValueAtPath(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectNullOutputValueAtPath) | Asserts the output at the specified address, and path has a null value. | +| [`plancheck.ExpectUnknownOutputValue(address)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectUnknownOutputValue) | Asserts the output at the specified address has an unknown value. | +| [`plancheck.ExpectUnknownOutputValueAtPath(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectUnknownOutputValueAtPath) | Asserts the output at the specified address, and path has an unknown value. | + +## Example using `plancheck.ExpectKnownOutputValue` + +The [`plancheck.ExpectKnownOutputValue(address, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownOutputValue) plan check verifies that a specific output value has a known type, and value. + +Refer to [Known Values](/terraform/plugin/testing/acceptance-tests/known-values) for details, and examples of the available [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types that can be used with the `ExpectKnownOutputValue` plan check. + +```go +func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} +``` + +## Example using `plancheck.ExpectKnownOutputValueAtPath` + +The [`plancheck.ExpectKnownOutputValueAtPath(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownOutputValueAtPath) plan check verifies that a specific output value at a defined path has a known type, and value. + +Refer to [Known Values](/terraform/plugin/testing/acceptance-tests/known-values) for details, and examples of the available [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types that can be used with the `ExpectKnownOutputValueAtPath` plan check. + +```go +func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.NewBoolValue(true), + ), + }, + }, + }, + }, + }) +} +``` ## Example using `plancheck.ExpectUnknownOutputValue` diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx index 6e197e043..968f3cb6e 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx @@ -9,11 +9,44 @@ description: >- The `terraform-plugin-testing` module provides a package [`plancheck`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck) with built-in managed resource, and data source plan checks for common use-cases: -| Check | Description | -|---------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------| -| [`plancheck.ExpectResourceAction(address, operation)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectResourceAction) | Asserts the given managed resource, or data source, has the specified operation for apply. | -| [`plancheck.ExpectUnknownValue(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectUnknownValue) | Asserts the specified attribute at the given managed resource, or data source, has an unknown value. | -| [`plancheck.ExpectSensitiveValue(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectSensitiveValue) | Asserts the specified attribute at the given managed resource, or data source, has a sensitive value. | +| Check | Description | +|---------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| +| [`plancheck.ExpectKnownValue(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownValue) | Asserts the specified attribute at the given managed resource, or data source, has the specified type, and value. | +| [`plancheck.ExpectResourceAction(address, operation)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectResourceAction) | Asserts the given managed resource, or data source, has the specified operation for apply. | +| [`plancheck.ExpectSensitiveValue(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectSensitiveValue) | Asserts the specified attribute at the given managed resource, or data source, has a sensitive value. | +| [`plancheck.ExpectUnknownValue(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectUnknownValue) | Asserts the specified attribute at the given managed resource, or data source, has an unknown value. | + +## Example using `plancheck.ExpectKnownValue` + +The [`plancheck.ExpectKnownValue(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownValue) plan check provides a basis for asserting that a specific resource attribute has a known type, and value. + +Refer to [Known Values](/terraform/plugin/testing/acceptance-tests/known-values) for details, and examples of the available [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types that can be used with the `ExpectKnownValue` plan check. + +```go +func TestExpectKnownValue_CheckPlan_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.NewStringValue("str")), + }, + }, + }, + }, + }) +} +``` ## Examples using `plancheck.ExpectResourceAction` From 0ccf758f9f9e4d1d45c9a21e38a0284e149d61be Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 18 Dec 2023 11:48:20 +0000 Subject: [PATCH 07/48] Adding changelog entries (#243) --- .changes/unreleased/FEATURES-20231218-114539.yaml | 6 ++++++ .changes/unreleased/FEATURES-20231218-114553.yaml | 6 ++++++ .changes/unreleased/FEATURES-20231218-114611.yaml | 6 ++++++ .changes/unreleased/FEATURES-20231218-114739.yaml | 6 ++++++ 4 files changed, 24 insertions(+) create mode 100644 .changes/unreleased/FEATURES-20231218-114539.yaml create mode 100644 .changes/unreleased/FEATURES-20231218-114553.yaml create mode 100644 .changes/unreleased/FEATURES-20231218-114611.yaml create mode 100644 .changes/unreleased/FEATURES-20231218-114739.yaml diff --git a/.changes/unreleased/FEATURES-20231218-114539.yaml b/.changes/unreleased/FEATURES-20231218-114539.yaml new file mode 100644 index 000000000..97567a488 --- /dev/null +++ b/.changes/unreleased/FEATURES-20231218-114539.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'plancheck: Added `ExpectKnownValue` plan check, which asserts that a given + resource attribute has a defined type, and value' +time: 2023-12-18T11:45:39.181954Z +custom: + Issue: "248" diff --git a/.changes/unreleased/FEATURES-20231218-114553.yaml b/.changes/unreleased/FEATURES-20231218-114553.yaml new file mode 100644 index 000000000..3627c9eee --- /dev/null +++ b/.changes/unreleased/FEATURES-20231218-114553.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'plancheck: Added `ExpectKnownOutputValue` plan check, which asserts that a + given output value has a defined type, and value' +time: 2023-12-18T11:45:53.272412Z +custom: + Issue: "248" diff --git a/.changes/unreleased/FEATURES-20231218-114611.yaml b/.changes/unreleased/FEATURES-20231218-114611.yaml new file mode 100644 index 000000000..09fe1d9dc --- /dev/null +++ b/.changes/unreleased/FEATURES-20231218-114611.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'plancheck: Added `ExpectKnownOutputValueAtPath` plan check, which asserts that + a given output value at a specified path has a defined type, and value' +time: 2023-12-18T11:46:11.58053Z +custom: + Issue: "248" diff --git a/.changes/unreleased/FEATURES-20231218-114739.yaml b/.changes/unreleased/FEATURES-20231218-114739.yaml new file mode 100644 index 000000000..85498d64a --- /dev/null +++ b/.changes/unreleased/FEATURES-20231218-114739.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'knownvalue: Introduced new `knownvalue` package which contains types for working + with plan checks and state checks' +time: 2023-12-18T11:47:39.059813Z +custom: + Issue: "248" From f161203df46ebc7546cf0dbd173d180d81dff6b0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 18 Dec 2023 12:16:02 +0000 Subject: [PATCH 08/48] Adding TerraformVersionChecks (#243) --- .../expect_known_output_value_at_path_test.go | 274 ++++++++++++++++++ 1 file changed, 274 insertions(+) diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index e605fa20d..16b1e7459 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" ) func TestExpectKnownOutputValueAtPath_CheckPlan_ResourceNotFound(t *testing.T) { @@ -28,6 +29,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ResourceNotFound(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -62,6 +70,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_AttributeValueNull(t *testing.T) return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" {} @@ -94,6 +109,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -127,6 +149,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *test return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -161,6 +190,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *tes return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -195,6 +231,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -228,6 +271,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -262,6 +312,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t * return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -296,6 +353,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -331,6 +395,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongType(t *tes return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -365,6 +436,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *te return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -399,6 +477,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -438,6 +523,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *test return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -475,6 +567,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *tes return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -515,6 +614,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -555,6 +661,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -594,6 +707,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -630,6 +750,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *test return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -667,6 +794,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlock(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -712,6 +846,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockPartial(t *testin return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -754,6 +895,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockNumElements(t *te return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -792,6 +940,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -831,6 +986,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongType(t *testi return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -868,6 +1030,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *test return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -908,6 +1077,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -946,6 +1122,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -985,6 +1168,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1021,6 +1211,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testi return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1058,6 +1255,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1097,6 +1301,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *test return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1137,6 +1348,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1175,6 +1393,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1214,6 +1439,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNumElements(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1250,6 +1482,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlock(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1295,6 +1534,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockPartial(t *testing return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1337,6 +1583,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockNumElements(t *tes return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1375,6 +1628,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String(t *testing.T) { return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1407,6 +1667,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *te return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1440,6 +1707,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *t return testProvider(), nil }, }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { From e13bdaad5b36d4b7733116e371f5c1a5ca515074 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 20 Dec 2023 14:16:36 +0000 Subject: [PATCH 09/48] Modifying to handle numerical values returned as json.Number for tfjson.Plan (#243) --- go.mod | 6 +- go.sum | 12 +- internal/plugintest/working_dir.go | 2 +- knownvalue/number.go | 45 ++++++ knownvalue/number_test.go | 76 ++++++++++ plancheck/expect_known_output_value.go | 105 +++++++++---- .../expect_known_output_value_at_path.go | 101 +++++++++---- .../expect_known_output_value_at_path_test.go | 140 ++++++++++++------ plancheck/expect_known_output_value_test.go | 120 ++++++++++----- plancheck/expect_known_value.go | 101 +++++++++---- plancheck/expect_known_value_test.go | 107 ++++++++----- .../testing/acceptance-tests/known-values.mdx | 88 +++++++---- 12 files changed, 661 insertions(+), 242 deletions(-) create mode 100644 knownvalue/number.go create mode 100644 knownvalue/number_test.go diff --git a/go.mod b/go.mod index c4cd717cb..1af653dfb 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/hashicorp/hc-install v0.6.2 github.com/hashicorp/hcl/v2 v2.19.1 github.com/hashicorp/logutils v1.0.0 - github.com/hashicorp/terraform-exec v0.19.0 - github.com/hashicorp/terraform-json v0.18.0 + github.com/hashicorp/terraform-exec v0.20.0 + github.com/hashicorp/terraform-json v0.19.0 github.com/hashicorp/terraform-plugin-go v0.20.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0 @@ -20,7 +20,7 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 github.com/mitchellh/reflectwalk v1.0.2 github.com/zclconf/go-cty v1.14.1 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 ) diff --git a/go.sum b/go.sum index 091dbfa97..84ca6ffa2 100644 --- a/go.sum +++ b/go.sum @@ -58,10 +58,10 @@ github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5R github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81SpgVtZNNtFSM= -github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg= -github.com/hashicorp/terraform-json v0.18.0 h1:pCjgJEqqDESv4y0Tzdqfxr/edOIGkjs8keY42xfNBwU= -github.com/hashicorp/terraform-json v0.18.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= +github.com/hashicorp/terraform-exec v0.20.0 h1:DIZnPsqzPGuUnq6cH8jWcPunBfY+C+M8JyYF3vpnuEo= +github.com/hashicorp/terraform-exec v0.20.0/go.mod h1:ckKGkJWbsNqFKV1itgMnE0hY9IYf1HoiekpuN0eWoDw= +github.com/hashicorp/terraform-json v0.19.0 h1:e9DBKC5sxDfiJT7Zoi+yRIwqLVtFur/fwK/FuE6AWsA= +github.com/hashicorp/terraform-json v0.19.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= github.com/hashicorp/terraform-plugin-go v0.20.0 h1:oqvoUlL+2EUbKNsJbIt3zqqZ7wi6lzn4ufkn/UA51xQ= github.com/hashicorp/terraform-plugin-go v0.20.0/go.mod h1:Rr8LBdMlY53a3Z/HpP+ZU3/xCDqtKNCkeI9qOyT10QE= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= @@ -124,8 +124,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U= golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= diff --git a/internal/plugintest/working_dir.go b/internal/plugintest/working_dir.go index 95d6b1af8..2c8888d72 100644 --- a/internal/plugintest/working_dir.go +++ b/internal/plugintest/working_dir.go @@ -305,7 +305,7 @@ func (wd *WorkingDir) SavedPlan(ctx context.Context) (*tfjson.Plan, error) { logging.HelperResourceTrace(ctx, "Calling Terraform CLI show command for JSON plan") - plan, err := wd.tf.ShowPlanFile(context.Background(), wd.planFilename(), tfexec.Reattach(wd.reattachInfo)) + plan, err := wd.tf.ShowPlanFile(context.Background(), wd.planFilename(), tfexec.Reattach(wd.reattachInfo), tfexec.JSONNumber(true)) logging.HelperResourceTrace(ctx, "Calling Terraform CLI show command for JSON plan") diff --git a/knownvalue/number.go b/knownvalue/number.go new file mode 100644 index 000000000..3e7ddacca --- /dev/null +++ b/knownvalue/number.go @@ -0,0 +1,45 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "math/big" +) + +var _ KnownValue = NumberValue{} + +// NumberValue is a KnownValue for asserting equality between the value +// supplied to NewNumberValue and the value passed to the Equal method. +type NumberValue struct { + value *big.Float +} + +// Equal determines whether the passed value is of type *big.Float, and +// contains a matching *big.Float value. +func (v NumberValue) Equal(other any) bool { + otherVal, ok := other.(*big.Float) + + if !ok { + return false + } + + if v.value.Cmp(otherVal) != 0 { + return false + } + + return true +} + +// String returns the string representation of the *big.Float value. +func (v NumberValue) String() string { + return v.value.Text('f', -1) +} + +// NewNumberValue returns a KnownValue for asserting equality between the +// supplied *big.Float and the value passed to the Equal method. +func NewNumberValue(value *big.Float) NumberValue { + return NumberValue{ + value: value, + } +} diff --git a/knownvalue/number_test.go b/knownvalue/number_test.go new file mode 100644 index 000000000..f6adb0784 --- /dev/null +++ b/knownvalue/number_test.go @@ -0,0 +1,76 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "math/big" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestNumberValue_Equal(t *testing.T) { + t.Parallel() + + bigFloat, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862315", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + otherBigFloat, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862314", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + testCases := map[string]struct { + other any + expected bool + }{ + "nil": {}, + "wrong-type": { + other: "str", + }, + "not-equal": { + other: otherBigFloat, + }, + "equal": { + other: bigFloat, + expected: true, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := knownvalue.NewNumberValue(bigFloat).Equal(testCase.other) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestNumberValue_String(t *testing.T) { + t.Parallel() + + bigFloat, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862315", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + got := knownvalue.NewNumberValue(bigFloat).String() + + if diff := cmp.Diff(got, "1.797693134862315797693134862315797693134862315"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go index 7131cc7da..27314ee53 100644 --- a/plancheck/expect_known_output_value.go +++ b/plancheck/expect_known_output_value.go @@ -5,7 +5,9 @@ package plancheck import ( "context" + "encoding/json" "fmt" + "math/big" "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -64,30 +66,10 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } - if !v.Equal(reflect.ValueOf(result).Interface()) { + if !v.Equal(result) { resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) - } - // Float64 is the default type for all numerical values in tfjson.Plan. - case reflect.Float64: - switch t := e.knownValue.(type) { - case - knownvalue.Float64Value: - if !t.Equal(result) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) - - return - } - case knownvalue.Int64Value: - // nolint:forcetypeassert // result is reflect.Float64 Kind - f := result.(float64) - if !t.Equal(int64(f)) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) - - return - } - default: - resp.Error = fmt.Errorf("wrong type: output value is float64 or int64, known value type is %T", t) + return } case reflect.Map: elems := make(map[string]any) @@ -120,7 +102,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } default: - resp.Error = fmt.Errorf("wrong type: output type is map, or object, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: output value is map, or object, known value type is %T", t) return } @@ -163,23 +145,82 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } default: - resp.Error = fmt.Errorf("wrong type: output type is list, or set, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: output value is list, or set, known value type is %T", t) return } case reflect.String: - v, ok := e.knownValue.(knownvalue.StringValue) + jsonNum, jsonNumOk := result.(json.Number) - if !ok { - resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + if jsonNumOk { + float64Val, float64ValOk := e.knownValue.(knownvalue.Float64Value) - return - } + int64Val, int64ValOk := e.knownValue.(knownvalue.Int64Value) - if !v.Equal(reflect.ValueOf(result).Interface()) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) - return + if !float64ValOk && !int64ValOk && !numberValOk { + resp.Error = fmt.Errorf("wrong type: output value is number, known value type is %T", e.knownValue) + } + + switch { + case float64ValOk: + f, err := jsonNum.Float64() + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as float64", jsonNum.String()) + + return + } + + if !float64Val.Equal(f) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, float64Val) + + return + } + case int64ValOk: + i, err := jsonNum.Int64() + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as int64", jsonNum.String()) + + return + } + + if !int64Val.Equal(i) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, int64Val) + + return + } + case numberValOk: + f, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as big.Float", jsonNum.String()) + + return + } + + if !numberValue.Equal(f) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, numberValue) + + return + } + } + } else { + v, ok := e.knownValue.(knownvalue.StringValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(result) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, v) + + return + } } default: errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go index c5859e915..00d75eabc 100644 --- a/plancheck/expect_known_output_value_at_path.go +++ b/plancheck/expect_known_output_value_at_path.go @@ -5,7 +5,9 @@ package plancheck import ( "context" + "encoding/json" "fmt" + "math/big" "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -65,30 +67,10 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } - if !v.Equal(reflect.ValueOf(result).Interface()) { + if !v.Equal(result) { resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) - } - // Float64 is the default type for all numerical values in tfjson.Plan. - case reflect.Float64: - switch t := e.knownValue.(type) { - case - knownvalue.Float64Value: - if !t.Equal(result) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) - - return - } - case knownvalue.Int64Value: - // nolint:forcetypeassert // result is reflect.Float64 Kind - f := result.(float64) - if !t.Equal(int64(f)) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, t) - - return - } - default: - resp.Error = fmt.Errorf("wrong type: output value is float64 or int64, known value type is %T", t) + return } case reflect.Map: elems := make(map[string]any) @@ -169,18 +151,77 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } case reflect.String: - v, ok := e.knownValue.(knownvalue.StringValue) + jsonNum, jsonNumOk := result.(json.Number) - if !ok { - resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + if jsonNumOk { + float64Val, float64ValOk := e.knownValue.(knownvalue.Float64Value) - return - } + int64Val, int64ValOk := e.knownValue.(knownvalue.Int64Value) - if !v.Equal(reflect.ValueOf(result).Interface()) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) - return + if !float64ValOk && !int64ValOk && !numberValOk { + resp.Error = fmt.Errorf("wrong type: output value is number, known value type is %T", e.knownValue) + } + + switch { + case float64ValOk: + f, err := jsonNum.Float64() + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as float64", jsonNum.String()) + + return + } + + if !float64Val.Equal(f) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, float64Val) + + return + } + case int64ValOk: + i, err := jsonNum.Int64() + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as int64", jsonNum.String()) + + return + } + + if !int64Val.Equal(i) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, int64Val) + + return + } + case numberValOk: + f, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as big.Float", jsonNum.String()) + + return + } + + if !numberValue.Equal(f) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, numberValue) + + return + } + } + } else { + v, ok := e.knownValue.(knownvalue.StringValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(result) { + resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, v) + + return + } } default: errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index 16b1e7459..2566f1873 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -6,6 +6,7 @@ package plancheck_test import ( "context" "fmt" + "math/big" "regexp" "testing" @@ -262,6 +263,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64(t *testing.T) { }) } +// We do not need equivalent tests for Int64 and Number as they all test the same logic. func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { t.Parallel() @@ -297,7 +299,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: output value is number, known value type is knownvalue.StringValue"), }, }, }) @@ -384,49 +386,6 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64(t *testing.T) { }) } -// TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongType highlights a limitation of tfjson.Plan in that all numerical -// values are represented as float64. -func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "test": func() (*schema.Provider, error) { //nolint:unparam // required signature - return testProvider(), nil - }, - }, - // Prior to Terraform v1.3.0 a planned output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - int_attribute = 123 - } - - output test_resource_one_output { - value = test_resource.one - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownOutputValueAtPath( - "test_resource_one_output", - tfjsonpath.New("int_attribute"), - knownvalue.NewStringValue("str"), - ), - }, - }, - ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), - }, - }, - }) -} - func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { t.Parallel() @@ -1246,6 +1205,99 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testi }) } +func TestExpectKnownOutputValueAtPath_CheckPlan_Number(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("123", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NewNumberValue(f), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("321", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a planned output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NewNumberValue(f), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + }, + }, + }) +} + func TestExpectKnownOutputValueAtPath_CheckPlan_Set(t *testing.T) { t.Parallel() diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 19e3445f8..4ee7e8cac 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -6,6 +6,7 @@ package plancheck_test import ( "context" "fmt" + "math/big" "regexp" "testing" @@ -211,6 +212,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64(t *testing.T) { }) } +// We do not need equivalent tests for Int64 and Number as they all test the same logic. func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { t.Parallel() @@ -238,7 +240,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: output value is number, known value type is knownvalue.StringValue"), }, }, }) @@ -309,41 +311,6 @@ func TestExpectKnownOutputValue_CheckPlan_Int64(t *testing.T) { }) } -// TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongType highlights a limitation of tfjson.Plan in that all numerical -// values are represented as float64. -func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "test": func() (*schema.Provider, error) { //nolint:unparam // required signature - return testProvider(), nil - }, - }, - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - int_attribute = 123 - } - - output int64_output { - value = test_resource.one.int_attribute - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownOutputValue( - "int64_output", - knownvalue.NewStringValue("str"), - ), - }, - }, - ExpectError: regexp.MustCompile("wrong type: output value is float64 or int64, known value type is knownvalue.StringValue"), - }, - }, - }) -} - func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { t.Parallel() @@ -445,7 +412,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong type: output type is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile("wrong type: output value is list, or set, known value type is knownvalue.MapValue"), }, }, }) @@ -828,7 +795,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong type: output type is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile("wrong type: output value is map, or object, known value type is knownvalue.ListValue"), }, }, }) @@ -1019,6 +986,83 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) }) } +func TestExpectKnownOutputValue_CheckPlan_Number(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("123", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NewNumberValue(f), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("321", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NewNumberValue(f), + ), + }, + }, + ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + }, + }, + }) +} + func TestExpectKnownOutputValue_CheckPlan_Set(t *testing.T) { t.Parallel() diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index 04305463c..b0543e3ab 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -5,7 +5,9 @@ package plancheck import ( "context" + "encoding/json" "fmt" + "math/big" "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -65,30 +67,10 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - if !v.Equal(reflect.ValueOf(result).Interface()) { + if !v.Equal(result) { resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, v) - } - // Float64 is the default type for all numerical values in tfjson.Plan. - case reflect.Float64: - switch t := e.knownValue.(type) { - case - knownvalue.Float64Value: - if !t.Equal(result) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, t) - - return - } - case knownvalue.Int64Value: - // nolint:forcetypeassert // result is reflect.Float64 Kind - f := result.(float64) - if !t.Equal(int64(f)) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, t) - - return - } - default: - resp.Error = fmt.Errorf("wrong type: attribute value is float64 or int64, known value type is %T", t) + return } case reflect.Map: elems := make(map[string]any) @@ -169,18 +151,77 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } case reflect.String: - v, ok := e.knownValue.(knownvalue.StringValue) + jsonNum, jsonNumOk := result.(json.Number) - if !ok { - resp.Error = fmt.Errorf("wrong type: attribute value is string, known value type is %T", e.knownValue) + if jsonNumOk { + float64Val, float64ValOk := e.knownValue.(knownvalue.Float64Value) - return - } + int64Val, int64ValOk := e.knownValue.(knownvalue.Int64Value) - if !v.Equal(reflect.ValueOf(result).Interface()) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, v) + numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) - return + if !float64ValOk && !int64ValOk && !numberValOk { + resp.Error = fmt.Errorf("wrong type: attribute value is number, known value type is %T", e.knownValue) + } + + switch { + case float64ValOk: + f, err := jsonNum.Float64() + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as float64", jsonNum.String()) + + return + } + + if !float64Val.Equal(f) { + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, float64Val) + + return + } + case int64ValOk: + i, err := jsonNum.Int64() + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as int64", jsonNum.String()) + + return + } + + if !int64Val.Equal(i) { + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, int64Val) + + return + } + case numberValOk: + f, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) + + if err != nil { + resp.Error = fmt.Errorf("%q could not be parsed as big.Float", jsonNum.String()) + + return + } + + if !numberValue.Equal(f) { + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, numberValue) + + return + } + } + } else { + v, ok := e.knownValue.(knownvalue.StringValue) + + if !ok { + resp.Error = fmt.Errorf("wrong type: attribute value is string, known value type is %T", e.knownValue) + + return + } + + if !v.Equal(result) { + resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, v) + + return + } } default: errorStr := fmt.Sprintf("unrecognised attribute type: %T, known value type is %T", result, e.knownValue) diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index f866575f5..812bcb470 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -6,6 +6,7 @@ package plancheck_test import ( "context" "fmt" + "math/big" "regexp" "testing" @@ -194,6 +195,7 @@ func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { }) } +// We do not need equivalent tests for Int64 and Number as they all test the same logic. func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { t.Parallel() @@ -218,7 +220,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute value is float64 or int64, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: attribute value is number, known value type is knownvalue.StringValue"), }, }, }) @@ -283,38 +285,6 @@ func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { }) } -// TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongType highlights a limitation of tfjson.Plan in that all numerical -// values are represented as float64. -func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongType(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "test": func() (*schema.Provider, error) { //nolint:unparam // required signature - return testProvider(), nil - }, - }, - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - int_attribute = 123 - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("int_attribute"), - knownvalue.NewStringValue("str"), - ), - }, - }, - ExpectError: regexp.MustCompile("wrong type: attribute value is float64 or int64, known value type is knownvalue.StringValue"), - }, - }, - }) -} - func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { t.Parallel() @@ -936,6 +906,77 @@ func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { }) } +func TestExpectKnownValue_CheckPlan_Number(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("123", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewNumberValue(f), + ), + }, + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("321", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NewNumberValue(f), + ), + }, + }, + ExpectError: regexp.MustCompile("attribute value: 123 does not equal expected value: 321"), + }, + }, + }) +} + func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { t.Parallel() diff --git a/website/docs/plugin/testing/acceptance-tests/known-values.mdx b/website/docs/plugin/testing/acceptance-tests/known-values.mdx index 83bef84f8..7e175cbbd 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-values.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-values.mdx @@ -47,6 +47,7 @@ The following table describes the correspondence between attributes, and [knownv | `schema.Int64Attribute` | `schema.TypeInt` | [knownvalue.Int64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Value) | | `schema.ListAttribute` | `schema.TypeList` | [knownvalue.ListValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValue) | | `schema.MapAttribute` | `schema.TypeMap` | [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) | +| `schema.NumberAttribute` | N/A | [knownvalue.NumberValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValue) | | `schema.ObjectAttribute` | N/A | [knownvalue.ObjectValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValue) | | `schema.SetAttribute` | `schema.TypeSet` | [knownvalue.SetValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValue) | | `schema.StringAttribute` | `schema.TypeString` | [knownvalue.StringValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValue) | @@ -233,12 +234,12 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { } ``` -### Num Elements Known Value +### Map Known Value -Example usage of [knownvalue.NumElements](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumElements) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -246,18 +247,21 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] + map_attribute = { + key1 = "value1" + key2 = "value2" + } } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewNumElementsValue(2), + tfjsonpath.New("map_attribute"), + knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + "key1": knownvalue.NewStringValue("value1"), + "key2": knownvalue.NewStringValue("value2"), + }), ), }, }, @@ -267,12 +271,12 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { } ``` -### Map Known Value +### Map Partial Known Value -Example usage of [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [knownvalue.MapValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -291,9 +295,8 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), }), ), }, @@ -304,12 +307,12 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { } ``` -### Map Partial Known Value +### Num Elements Known Value -Example usage of [knownvalue.MapValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [knownvalue.NumElements](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumElements) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -317,20 +320,55 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { - map_attribute = { - key1 = "value1" - key2 = "value2" - } + list_attribute = [ + "value1", + "value2" + ] } `, ConfigPlanChecks: r.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", - tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), - }), + tfjsonpath.New("list_attribute"), + knownvalue.NewNumElementsValue(2), + ), + }, + }, + }, + }, + }) +} +``` + +### Number Known Value + +Example usage of [knownvalue.NumberValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862315", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + number_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("number_attribute"), + knownvalue.NewNumberValue(f), ), }, }, From 450339db48bd9b6d7f5931c785096025d93f2ca0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Jan 2024 11:20:59 +0000 Subject: [PATCH 10/48] Renaming known value constructors (#243) --- knownvalue/bool.go | 6 +- knownvalue/bool_test.go | 4 +- knownvalue/float64.go | 6 +- knownvalue/float64_test.go | 4 +- knownvalue/int64.go | 6 +- knownvalue/int64_test.go | 4 +- knownvalue/list_partial_test.go | 12 +- knownvalue/list_test.go | 12 +- knownvalue/map.go | 6 +- knownvalue/map_partial.go | 6 +- knownvalue/map_partial_test.go | 12 +- knownvalue/map_test.go | 16 +-- knownvalue/num_elements.go | 6 +- knownvalue/num_elements_test.go | 4 +- knownvalue/number.go | 6 +- knownvalue/number_test.go | 4 +- knownvalue/object.go | 6 +- knownvalue/object_partial.go | 6 +- knownvalue/object_partial_test.go | 12 +- knownvalue/object_test.go | 16 +-- knownvalue/set.go | 6 +- knownvalue/set_partial.go | 6 +- knownvalue/set_partial_test.go | 16 +-- knownvalue/set_test.go | 14 +- knownvalue/string.go | 6 +- knownvalue/string_test.go | 4 +- .../expect_known_output_value_at_path_test.go | 128 +++++++++--------- plancheck/expect_known_output_value_test.go | 128 +++++++++--------- plancheck/expect_known_value_test.go | 128 +++++++++--------- 29 files changed, 295 insertions(+), 295 deletions(-) diff --git a/knownvalue/bool.go b/knownvalue/bool.go index 2bb912a58..2a8e1a839 100644 --- a/knownvalue/bool.go +++ b/knownvalue/bool.go @@ -8,7 +8,7 @@ import "strconv" var _ KnownValue = BoolValue{} // BoolValue is a KnownValue for asserting equality between the value -// supplied to NewBoolValue and the value passed to the Equal method. +// supplied to BoolValueExact and the value passed to the Equal method. type BoolValue struct { value bool } @@ -34,9 +34,9 @@ func (v BoolValue) String() string { return strconv.FormatBool(v.value) } -// NewBoolValue returns a KnownValue for asserting equality between the +// BoolValueExact returns a KnownValue for asserting equality between the // supplied bool and the value passed to the Equal method. -func NewBoolValue(value bool) BoolValue { +func BoolValueExact(value bool) BoolValue { return BoolValue{ value: value, } diff --git a/knownvalue/bool_test.go b/knownvalue/bool_test.go index 5551e20eb..d8d442f1f 100644 --- a/knownvalue/bool_test.go +++ b/knownvalue/bool_test.go @@ -37,7 +37,7 @@ func TestBoolValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewBoolValue(true).Equal(testCase.other) + got := knownvalue.BoolValueExact(true).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -49,7 +49,7 @@ func TestBoolValue_Equal(t *testing.T) { func TestBoolValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NewBoolValue(true).String() + got := knownvalue.BoolValueExact(true).String() if diff := cmp.Diff(got, "true"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/knownvalue/float64.go b/knownvalue/float64.go index 88081ea45..51ada6897 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -10,7 +10,7 @@ import ( var _ KnownValue = Float64Value{} // Float64Value is a KnownValue for asserting equality between the value -// supplied to NewFloat64Value and the value passed to the Equal method. +// supplied to Float64ValueExact and the value passed to the Equal method. type Float64Value struct { value float64 } @@ -36,9 +36,9 @@ func (v Float64Value) String() string { return strconv.FormatFloat(v.value, 'f', -1, 64) } -// NewFloat64Value returns a KnownValue for asserting equality between the +// Float64ValueExact returns a KnownValue for asserting equality between the // supplied float64 and the value passed to the Equal method. -func NewFloat64Value(value float64) Float64Value { +func Float64ValueExact(value float64) Float64Value { return Float64Value{ value: value, } diff --git a/knownvalue/float64_test.go b/knownvalue/float64_test.go index 5ebd9c024..c706a877f 100644 --- a/knownvalue/float64_test.go +++ b/knownvalue/float64_test.go @@ -37,7 +37,7 @@ func TestFloat64Value_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewFloat64Value(1.23).Equal(testCase.other) + got := knownvalue.Float64ValueExact(1.23).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -49,7 +49,7 @@ func TestFloat64Value_Equal(t *testing.T) { func TestFloat64Value_String(t *testing.T) { t.Parallel() - got := knownvalue.NewFloat64Value(1.234567890123e+09).String() + got := knownvalue.Float64ValueExact(1.234567890123e+09).String() if diff := cmp.Diff(got, "1234567890.123"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/knownvalue/int64.go b/knownvalue/int64.go index 6c9a04126..bf81328b4 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -10,7 +10,7 @@ import ( var _ KnownValue = Int64Value{} // Int64Value is a KnownValue for asserting equality between the value -// supplied to NewInt64Value and the value passed to the Equal method. +// supplied to Int64ValueExact and the value passed to the Equal method. type Int64Value struct { value int64 } @@ -36,9 +36,9 @@ func (v Int64Value) String() string { return strconv.FormatInt(v.value, 10) } -// NewInt64Value returns a KnownValue for asserting equality between the +// Int64ValueExact returns a KnownValue for asserting equality between the // supplied int64 and the value passed to the Equal method. -func NewInt64Value(value int64) Int64Value { +func Int64ValueExact(value int64) Int64Value { return Int64Value{ value: value, } diff --git a/knownvalue/int64_test.go b/knownvalue/int64_test.go index 3536d4748..c71fabbce 100644 --- a/knownvalue/int64_test.go +++ b/knownvalue/int64_test.go @@ -37,7 +37,7 @@ func TestInt64Value_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewInt64Value(123).Equal(testCase.other) + got := knownvalue.Int64ValueExact(123).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -49,7 +49,7 @@ func TestInt64Value_Equal(t *testing.T) { func TestInt64Value_String(t *testing.T) { t.Parallel() - got := knownvalue.NewInt64Value(1234567890123).String() + got := knownvalue.Int64ValueExact(1234567890123).String() if diff := cmp.Diff(got, "1234567890123"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/knownvalue/list_partial_test.go b/knownvalue/list_partial_test.go index 2bb999155..66d52abe3 100644 --- a/knownvalue/list_partial_test.go +++ b/knownvalue/list_partial_test.go @@ -47,9 +47,9 @@ func TestListValuePartial_Equal(t *testing.T) { t.Parallel() got := knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewFloat64Value(1.23), - 2: knownvalue.NewFloat64Value(4.56), - 3: knownvalue.NewFloat64Value(7.89), + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -63,9 +63,9 @@ func TestListValuePartial_String(t *testing.T) { t.Parallel() got := knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewFloat64Value(1.23), - 2: knownvalue.NewFloat64Value(4.56), - 3: knownvalue.NewFloat64Value(7.89), + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), }).String() if diff := cmp.Diff(got, "[0:1.23 2:4.56 3:7.89]"); diff != "" { diff --git a/knownvalue/list_test.go b/knownvalue/list_test.go index 080003041..26d1e9762 100644 --- a/knownvalue/list_test.go +++ b/knownvalue/list_test.go @@ -62,9 +62,9 @@ func TestListValue_Equal(t *testing.T) { t.Parallel() got := knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewInt64Value(123), - knownvalue.NewInt64Value(456), - knownvalue.NewInt64Value(789), + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -78,9 +78,9 @@ func TestListValue_String(t *testing.T) { t.Parallel() got := knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewInt64Value(123), - knownvalue.NewInt64Value(456), - knownvalue.NewInt64Value(789), + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), }).String() if diff := cmp.Diff(got, "[123 456 789]"); diff != "" { diff --git a/knownvalue/map.go b/knownvalue/map.go index ae243ff97..0be97b6ba 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -11,7 +11,7 @@ import ( var _ KnownValue = MapValue{} // MapValue is a KnownValue for asserting equality between the value -// supplied to NewMapValue and the value passed to the Equal method. +// supplied to MapValueExact and the value passed to the Equal method. type MapValue struct { value map[string]KnownValue } @@ -65,9 +65,9 @@ func (v MapValue) String() string { return fmt.Sprintf("%v", mapVals) } -// NewMapValue returns a KnownValue for asserting equality between the +// MapValueExact returns a KnownValue for asserting equality between the // supplied map[string]KnownValue and the value passed to the Equal method. -func NewMapValue(value map[string]KnownValue) MapValue { +func MapValueExact(value map[string]KnownValue) MapValue { return MapValue{ value: value, } diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index cd6f16047..d274e12ef 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -11,7 +11,7 @@ import ( var _ KnownValue = MapValuePartial{} // MapValuePartial is a KnownValue for asserting equality between the value -// supplied to NewMapValuePartial and the value passed to the Equal method. +// supplied to MapValuePartialMatch and the value passed to the Equal method. type MapValuePartial struct { value map[string]KnownValue } @@ -61,9 +61,9 @@ func (v MapValuePartial) String() string { return fmt.Sprintf("%v", mapVals) } -// NewMapValuePartial returns a KnownValue for asserting partial equality between the +// MapValuePartialMatch returns a KnownValue for asserting partial equality between the // supplied map[string]KnownValue and the value passed to the Equal method. -func NewMapValuePartial(value map[string]KnownValue) MapValuePartial { +func MapValuePartialMatch(value map[string]KnownValue) MapValuePartial { return MapValuePartial{ value: value, } diff --git a/knownvalue/map_partial_test.go b/knownvalue/map_partial_test.go index b2df1c79e..c21e824f5 100644 --- a/knownvalue/map_partial_test.go +++ b/knownvalue/map_partial_test.go @@ -54,9 +54,9 @@ func TestMapValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -69,9 +69,9 @@ func TestMapValuePartial_Equal(t *testing.T) { func TestMapValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), }).String() if diff := cmp.Diff(got, "map[one:1.23 three:7.89]"); diff != "" { diff --git a/knownvalue/map_test.go b/knownvalue/map_test.go index c669bf0ab..a7f1ca169 100644 --- a/knownvalue/map_test.go +++ b/knownvalue/map_test.go @@ -54,10 +54,10 @@ func TestMapValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "two": knownvalue.NewFloat64Value(4.56), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -70,10 +70,10 @@ func TestMapValue_Equal(t *testing.T) { func TestMapValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "two": knownvalue.NewFloat64Value(4.56), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), }).String() if diff := cmp.Diff(got, "map[one:1.23 three:7.89 two:4.56]"); diff != "" { diff --git a/knownvalue/num_elements.go b/knownvalue/num_elements.go index ceb1a084c..a31e36905 100644 --- a/knownvalue/num_elements.go +++ b/knownvalue/num_elements.go @@ -8,7 +8,7 @@ import "strconv" var _ KnownValue = NumElementsValue{} // NumElementsValue is a KnownValue for asserting equality between the value -// supplied to NewNumElementsValue and the value passed to the Equal method. +// supplied to NumElementsExact and the value passed to the Equal method. type NumElementsValue struct { num int } @@ -40,9 +40,9 @@ func (v NumElementsValue) String() string { return strconv.FormatInt(int64(v.num), 10) } -// NewNumElementsValue returns a KnownValue for asserting that +// NumElementsExact returns a KnownValue for asserting that // a list, map, object, or set contains num elements. -func NewNumElementsValue(num int) NumElementsValue { +func NumElementsExact(num int) NumElementsValue { return NumElementsValue{ num: num, } diff --git a/knownvalue/num_elements_test.go b/knownvalue/num_elements_test.go index 2dcae603f..d13c4d5c2 100644 --- a/knownvalue/num_elements_test.go +++ b/knownvalue/num_elements_test.go @@ -57,7 +57,7 @@ func TestNumElements_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewNumElementsValue(3).Equal(testCase.other) + got := knownvalue.NumElementsExact(3).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -69,7 +69,7 @@ func TestNumElements_Equal(t *testing.T) { func TestNumElements_String(t *testing.T) { t.Parallel() - got := knownvalue.NewNumElementsValue(2).String() + got := knownvalue.NumElementsExact(2).String() if diff := cmp.Diff(got, "2"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/knownvalue/number.go b/knownvalue/number.go index 3e7ddacca..4cc773ff6 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -10,7 +10,7 @@ import ( var _ KnownValue = NumberValue{} // NumberValue is a KnownValue for asserting equality between the value -// supplied to NewNumberValue and the value passed to the Equal method. +// supplied to NumberValueExact and the value passed to the Equal method. type NumberValue struct { value *big.Float } @@ -36,9 +36,9 @@ func (v NumberValue) String() string { return v.value.Text('f', -1) } -// NewNumberValue returns a KnownValue for asserting equality between the +// NumberValueExact returns a KnownValue for asserting equality between the // supplied *big.Float and the value passed to the Equal method. -func NewNumberValue(value *big.Float) NumberValue { +func NumberValueExact(value *big.Float) NumberValue { return NumberValue{ value: value, } diff --git a/knownvalue/number_test.go b/knownvalue/number_test.go index f6adb0784..1fed6adcc 100644 --- a/knownvalue/number_test.go +++ b/knownvalue/number_test.go @@ -50,7 +50,7 @@ func TestNumberValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewNumberValue(bigFloat).Equal(testCase.other) + got := knownvalue.NumberValueExact(bigFloat).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -68,7 +68,7 @@ func TestNumberValue_String(t *testing.T) { t.Errorf("%s", err) } - got := knownvalue.NewNumberValue(bigFloat).String() + got := knownvalue.NumberValueExact(bigFloat).String() if diff := cmp.Diff(got, "1.797693134862315797693134862315797693134862315"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/knownvalue/object.go b/knownvalue/object.go index 9e114b398..ca19e032d 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -11,7 +11,7 @@ import ( var _ KnownValue = ObjectValue{} // ObjectValue is a KnownValue for asserting equality between the value -// supplied to NewObjectValue and the value passed to the Equal method. +// supplied to ObjectValueExact and the value passed to the Equal method. type ObjectValue struct { value map[string]KnownValue } @@ -65,9 +65,9 @@ func (v ObjectValue) String() string { return fmt.Sprintf("%v", mapVals) } -// NewObjectValue returns a KnownValue for asserting equality between the +// ObjectValueExact returns a KnownValue for asserting equality between the // supplied map[string]KnownValue and the value passed to the Equal method. -func NewObjectValue(value map[string]KnownValue) ObjectValue { +func ObjectValueExact(value map[string]KnownValue) ObjectValue { return ObjectValue{ value: value, } diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index 5e99990db..30c936251 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -11,7 +11,7 @@ import ( var _ KnownValue = ObjectValuePartial{} // ObjectValuePartial is a KnownValue for asserting equality between the value -// supplied to NewObjectValuePartial and the value passed to the Equal method. +// supplied to ObjectValuePartialMatch and the value passed to the Equal method. type ObjectValuePartial struct { value map[string]KnownValue } @@ -61,9 +61,9 @@ func (v ObjectValuePartial) String() string { return fmt.Sprintf("%v", mapVals) } -// NewObjectValuePartial returns a KnownValue for asserting partial equality between the +// ObjectValuePartialMatch returns a KnownValue for asserting partial equality between the // supplied map[string]KnownValue and the value passed to the Equal method. -func NewObjectValuePartial(value map[string]KnownValue) ObjectValuePartial { +func ObjectValuePartialMatch(value map[string]KnownValue) ObjectValuePartial { return ObjectValuePartial{ value: value, } diff --git a/knownvalue/object_partial_test.go b/knownvalue/object_partial_test.go index 0450006b7..ec8b6033f 100644 --- a/knownvalue/object_partial_test.go +++ b/knownvalue/object_partial_test.go @@ -54,9 +54,9 @@ func TestObjectValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewObjectValuePartial(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.ObjectValuePartialMatch(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -69,9 +69,9 @@ func TestObjectValuePartial_Equal(t *testing.T) { func TestObjectValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.NewObjectValuePartial(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.ObjectValuePartialMatch(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), }).String() if diff := cmp.Diff(got, "map[one:1.23 three:7.89]"); diff != "" { diff --git a/knownvalue/object_test.go b/knownvalue/object_test.go index 7b502d2a3..1a87a04da 100644 --- a/knownvalue/object_test.go +++ b/knownvalue/object_test.go @@ -54,10 +54,10 @@ func TestObjectValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewObjectValue(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "two": knownvalue.NewFloat64Value(4.56), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.ObjectValueExact(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -70,10 +70,10 @@ func TestObjectValue_Equal(t *testing.T) { func TestObjectValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NewObjectValue(map[string]knownvalue.KnownValue{ - "one": knownvalue.NewFloat64Value(1.23), - "two": knownvalue.NewFloat64Value(4.56), - "three": knownvalue.NewFloat64Value(7.89), + got := knownvalue.ObjectValueExact(map[string]knownvalue.KnownValue{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), }).String() if diff := cmp.Diff(got, "map[one:1.23 three:7.89 two:4.56]"); diff != "" { diff --git a/knownvalue/set.go b/knownvalue/set.go index 3114d763c..b3a524076 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -10,7 +10,7 @@ import ( var _ KnownValue = SetValue{} // SetValue is a KnownValue for asserting equality between the value -// supplied to NewSetValue and the value passed to the Equal method. +// supplied to SetValueExact and the value passed to the Equal method. type SetValue struct { value []KnownValue } @@ -65,9 +65,9 @@ func (v SetValue) String() string { return fmt.Sprintf("%s", setVals) } -// NewSetValue returns a KnownValue for asserting equality between the +// SetValueExact returns a KnownValue for asserting equality between the // supplied []KnownValue and the value passed to the Equal method. -func NewSetValue(value []KnownValue) SetValue { +func SetValueExact(value []KnownValue) SetValue { return SetValue{ value: value, } diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index 56bf11fce..7ec2d67f1 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -10,7 +10,7 @@ import ( var _ KnownValue = SetValuePartial{} // SetValuePartial is a KnownValue for asserting equality between the value -// supplied to NewSetValuePartial and the value passed to the Equal method. +// supplied to SetValuePartialMatch and the value passed to the Equal method. type SetValuePartial struct { value []KnownValue } @@ -61,9 +61,9 @@ func (v SetValuePartial) String() string { return fmt.Sprintf("%s", setVals) } -// NewSetValuePartial returns a KnownValue for asserting equality of the elements +// SetValuePartialMatch returns a KnownValue for asserting equality of the elements // supplied in []KnownValue and the elements in the value passed to the Equal method. -func NewSetValuePartial(value []KnownValue) SetValuePartial { +func SetValuePartialMatch(value []KnownValue) SetValuePartial { return SetValuePartial{ value: value, } diff --git a/knownvalue/set_partial_test.go b/knownvalue/set_partial_test.go index 2f4f7fdd0..62cd36770 100644 --- a/knownvalue/set_partial_test.go +++ b/knownvalue/set_partial_test.go @@ -47,10 +47,10 @@ func TestSetValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewFloat64Value(1.23), - knownvalue.NewFloat64Value(4.56), - knownvalue.NewFloat64Value(7.89), + got := knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -63,10 +63,10 @@ func TestSetValuePartial_Equal(t *testing.T) { func TestSetValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewFloat64Value(1.23), - knownvalue.NewFloat64Value(4.56), - knownvalue.NewFloat64Value(7.89), + got := knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), }).String() if diff := cmp.Diff(got, "[1.23 4.56 7.89]"); diff != "" { diff --git a/knownvalue/set_test.go b/knownvalue/set_test.go index 166b7dfe0..9de1a724a 100644 --- a/knownvalue/set_test.go +++ b/knownvalue/set_test.go @@ -62,10 +62,10 @@ func TestSetValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewInt64Value(123), - knownvalue.NewInt64Value(456), - knownvalue.NewInt64Value(789), + got := knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), }).Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { @@ -79,9 +79,9 @@ func TestSetValue_String(t *testing.T) { t.Parallel() got := knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewInt64Value(123), - knownvalue.NewInt64Value(456), - knownvalue.NewInt64Value(789), + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), }).String() if diff := cmp.Diff(got, "[123 456 789]"); diff != "" { diff --git a/knownvalue/string.go b/knownvalue/string.go index f8a5194e4..d924568fd 100644 --- a/knownvalue/string.go +++ b/knownvalue/string.go @@ -6,7 +6,7 @@ package knownvalue var _ KnownValue = StringValue{} // StringValue is a KnownValue for asserting equality between the value -// supplied to NewStringValue and the value passed to the Equal method. +// supplied to StringValueExact and the value passed to the Equal method. type StringValue struct { value string } @@ -32,9 +32,9 @@ func (v StringValue) String() string { return v.value } -// NewStringValue returns a KnownValue for asserting equality between the +// StringValueExact returns a KnownValue for asserting equality between the // supplied string and a value passed to the Equal method. -func NewStringValue(value string) StringValue { +func StringValueExact(value string) StringValue { return StringValue{ value: value, } diff --git a/knownvalue/string_test.go b/knownvalue/string_test.go index 7ec87c9e6..21ee97447 100644 --- a/knownvalue/string_test.go +++ b/knownvalue/string_test.go @@ -37,7 +37,7 @@ func TestStringValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewStringValue("str").Equal(testCase.other) + got := knownvalue.StringValueExact("str").Equal(testCase.other) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -49,7 +49,7 @@ func TestStringValue_Equal(t *testing.T) { func TestStringValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NewStringValue("str").String() + got := knownvalue.StringValueExact("str").String() if diff := cmp.Diff(got, "str"); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index 2566f1873..c8442f1ba 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -52,7 +52,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ResourceNotFound(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_two_output", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -91,7 +91,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_AttributeValueNull(t *testing.T) plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -132,7 +132,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -172,7 +172,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.NewFloat64Value(1.23), + knownvalue.Float64ValueExact(1.23), ), }, }, @@ -213,7 +213,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *tes plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(false), + knownvalue.BoolValueExact(false), ), }, }, @@ -254,7 +254,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("float_attribute"), - knownvalue.NewFloat64Value(1.23), + knownvalue.Float64ValueExact(1.23), ), }, }, @@ -295,7 +295,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("float_attribute"), - knownvalue.NewStringValue("str"), + knownvalue.StringValueExact("str"), ), }, }, @@ -336,7 +336,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t * plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("float_attribute"), - knownvalue.NewFloat64Value(3.21), + knownvalue.Float64ValueExact(3.21), ), }, }, @@ -377,7 +377,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.NewInt64Value(123), + knownvalue.Int64ValueExact(123), ), }, }, @@ -417,7 +417,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *te plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.NewInt64Value(321), + knownvalue.Int64ValueExact(321), ), }, }, @@ -462,8 +462,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List(t *testing.T) { "test_resource_one_output", tfjsonpath.New("list_attribute"), knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }), ), }, @@ -507,7 +507,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{}), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{}), ), }, }, @@ -552,8 +552,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *tes "test_resource_one_output", tfjsonpath.New("list_attribute"), knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value3"), - knownvalue.NewStringValue("value4"), + knownvalue.StringValueExact("value3"), + knownvalue.StringValueExact("value4"), }), ), }, @@ -599,7 +599,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial(t *testing.T) { "test_resource_one_output", tfjsonpath.New("list_attribute"), knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value1"), + 0: knownvalue.StringValueExact("value1"), }), ), }, @@ -646,7 +646,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue "test_resource_one_output", tfjsonpath.New("list_attribute"), knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value3"), + 0: knownvalue.StringValueExact("value3"), }), ), }, @@ -691,7 +691,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -734,7 +734,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElementsValue(3), + knownvalue.NumElementsExact(3), ), }, }, @@ -781,11 +781,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlock(t *testing.T) { "test_resource_one_output", tfjsonpath.New("list_nested_block"), knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("str"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -833,8 +833,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockPartial(t *testin "test_resource_one_output", tfjsonpath.New("list_nested_block"), knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + 1: knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -881,7 +881,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockNumElements(t *te plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -924,9 +924,9 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), }), ), }, @@ -1014,9 +1014,9 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key3": knownvalue.NewStringValue("value3"), - "key4": knownvalue.NewStringValue("value4"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "key3": knownvalue.StringValueExact("value3"), + "key4": knownvalue.StringValueExact("value4"), }), ), }, @@ -1061,8 +1061,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "key1": knownvalue.StringValueExact("value1"), }), ), }, @@ -1106,8 +1106,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key3": knownvalue.NewStringValue("value1"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "key3": knownvalue.StringValueExact("value1"), }), ), }, @@ -1152,7 +1152,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1195,7 +1195,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testi plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElementsValue(3), + knownvalue.NumElementsExact(3), ), }, }, @@ -1242,7 +1242,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Number(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.NewNumberValue(f), + knownvalue.NumberValueExact(f), ), }, }, @@ -1288,7 +1288,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Number_KnownValueWrongValue(t *t plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.NewNumberValue(f), + knownvalue.NumberValueExact(f), ), }, }, @@ -1332,9 +1332,9 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }), ), }, @@ -1378,9 +1378,9 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value3"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value3"), }), ), }, @@ -1425,8 +1425,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value2"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value2"), }), ), }, @@ -1470,8 +1470,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value3"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value3"), }), ), }, @@ -1516,7 +1516,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1561,12 +1561,12 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlock(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("str"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -1613,9 +1613,9 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockPartial(t *testing plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -1662,7 +1662,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockNumElements(t *tes plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1702,7 +1702,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("string_attribute"), - knownvalue.NewStringValue("str")), + knownvalue.StringValueExact("str")), }, }, }, @@ -1741,7 +1741,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *te plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("string_attribute"), - knownvalue.NewBoolValue(true)), + knownvalue.BoolValueExact(true)), }, }, ExpectError: regexp.MustCompile("wrong type: output value is string, known value type is knownvalue.BoolValue"), @@ -1781,7 +1781,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *t plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("string_attribute"), - knownvalue.NewStringValue("rts")), + knownvalue.StringValueExact("rts")), }, }, ExpectError: regexp.MustCompile("output value: str does not equal expected value: rts"), @@ -1799,7 +1799,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_UnknownAttributeType(t *testing. expectedErr error }{ "unrecognised-type": { - knownValue: knownvalue.NewInt64Value(123), + knownValue: knownvalue.Int64ValueExact(123), req: plancheck.CheckPlanRequest{ Plan: &tfjson.Plan{ OutputChanges: map[string]*tfjson.Change{ diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 4ee7e8cac..17c63a725 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -42,7 +42,7 @@ func TestExpectKnownOutputValue_CheckPlan_OutputNotFound(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_not_found", - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -72,7 +72,7 @@ func TestExpectKnownOutputValue_CheckPlan_AttributeValueNull(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -105,7 +105,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -137,7 +137,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.NewFloat64Value(1.23), + knownvalue.Float64ValueExact(1.23), ), }, }, @@ -170,7 +170,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.NewBoolValue(false), + knownvalue.BoolValueExact(false), ), }, }, @@ -203,7 +203,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "float64_output", - knownvalue.NewFloat64Value(1.23), + knownvalue.Float64ValueExact(1.23), ), }, }, @@ -236,7 +236,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "float64_output", - knownvalue.NewStringValue("str"), + knownvalue.StringValueExact("str"), ), }, }, @@ -269,7 +269,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongValue(t *testin PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "float64_output", - knownvalue.NewFloat64Value(3.21), + knownvalue.Float64ValueExact(3.21), ), }, }, @@ -302,7 +302,7 @@ func TestExpectKnownOutputValue_CheckPlan_Int64(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "int64_output", - knownvalue.NewInt64Value(123), + knownvalue.Int64ValueExact(123), ), }, }, @@ -334,7 +334,7 @@ func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing. PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "int64_output", - knownvalue.NewInt64Value(321), + knownvalue.Int64ValueExact(321), ), }, }, @@ -371,8 +371,8 @@ func TestExpectKnownOutputValue_CheckPlan_List(t *testing.T) { plancheck.ExpectKnownOutputValue( "list_output", knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }), ), }, @@ -408,7 +408,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{}), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{}), ), }, }, @@ -445,8 +445,8 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownOutputValue( "list_output", knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value3"), - knownvalue.NewStringValue("value4"), + knownvalue.StringValueExact("value3"), + knownvalue.StringValueExact("value4"), }), ), }, @@ -484,7 +484,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownOutputValue( "list_output", knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value1"), + 0: knownvalue.StringValueExact("value1"), }), ), }, @@ -523,7 +523,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *te plancheck.ExpectKnownOutputValue( "list_output", knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value3"), + 0: knownvalue.StringValueExact("value3"), }), ), }, @@ -560,7 +560,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -595,7 +595,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewNumElementsValue(3), + knownvalue.NumElementsExact(3), ), }, }, @@ -634,11 +634,11 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlock(t *testing.T) { plancheck.ExpectKnownOutputValue( "list_nested_block_output", knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("str"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -678,8 +678,8 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { plancheck.ExpectKnownOutputValue( "list_nested_block_output", knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + 1: knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -718,7 +718,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockNumElements(t *testing. PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -753,9 +753,9 @@ func TestExpectKnownOutputValue_CheckPlan_Map(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), }), ), }, @@ -827,9 +827,9 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key3": knownvalue.NewStringValue("value3"), - "key4": knownvalue.NewStringValue("value4"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "key3": knownvalue.StringValueExact("value3"), + "key4": knownvalue.StringValueExact("value4"), }), ), }, @@ -866,8 +866,8 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "key1": knownvalue.StringValueExact("value1"), }), ), }, @@ -903,8 +903,8 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *tes PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key3": knownvalue.NewStringValue("value1"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "key3": knownvalue.StringValueExact("value1"), }), ), }, @@ -941,7 +941,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -976,7 +976,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewNumElementsValue(3), + knownvalue.NumElementsExact(3), ), }, }, @@ -1015,7 +1015,7 @@ func TestExpectKnownOutputValue_CheckPlan_Number(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "int64_output", - knownvalue.NewNumberValue(f), + knownvalue.NumberValueExact(f), ), }, }, @@ -1053,7 +1053,7 @@ func TestExpectKnownOutputValue_CheckPlan_Number_KnownValueWrongValue(t *testing PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "int64_output", - knownvalue.NewNumberValue(f), + knownvalue.NumberValueExact(f), ), }, }, @@ -1089,9 +1089,9 @@ func TestExpectKnownOutputValue_CheckPlan_Set(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }), ), }, @@ -1127,9 +1127,9 @@ func TestExpectKnownOutputValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value3"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value3"), }), ), }, @@ -1166,8 +1166,8 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value2"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value2"), }), ), }, @@ -1203,8 +1203,8 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *tes PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value3"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value3"), }), ), }, @@ -1241,7 +1241,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1278,12 +1278,12 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlock(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("str"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -1322,9 +1322,9 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -1363,7 +1363,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockNumElements(t *testing.T PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1395,7 +1395,7 @@ func TestExpectKnownOutputValue_CheckPlan_String(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "string_output", - knownvalue.NewStringValue("str")), + knownvalue.StringValueExact("str")), }, }, }, @@ -1426,7 +1426,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongType(t *testing. PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "string_output", - knownvalue.NewBoolValue(true)), + knownvalue.BoolValueExact(true)), }, }, ExpectError: regexp.MustCompile("wrong type: output value is string, known value type is knownvalue.BoolValue"), @@ -1458,7 +1458,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongValue(t *testing PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "string_output", - knownvalue.NewStringValue("rts")), + knownvalue.StringValueExact("rts")), }, }, ExpectError: regexp.MustCompile("output value: str does not equal expected value: rts"), @@ -1476,7 +1476,7 @@ func TestExpectKnownOutputValue_CheckPlan_UnknownAttributeType(t *testing.T) { expectedErr error }{ "unrecognised-type": { - knownValue: knownvalue.NewInt64Value(123), + knownValue: knownvalue.Int64ValueExact(123), req: plancheck.CheckPlanRequest{ Plan: &tfjson.Plan{ OutputChanges: map[string]*tfjson.Change{ diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 812bcb470..d5a9a07b7 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -40,7 +40,7 @@ func TestExpectKnownValue_CheckPlan_ResourceNotFound(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.two", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -67,7 +67,7 @@ func TestExpectKnownValue_CheckPlan_AttributeValueNull(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -97,7 +97,7 @@ func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -126,7 +126,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.NewFloat64Value(1.23), + knownvalue.Float64ValueExact(1.23), ), }, }, @@ -156,7 +156,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(false), + knownvalue.BoolValueExact(false), ), }, }, @@ -186,7 +186,7 @@ func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.NewFloat64Value(1.23), + knownvalue.Float64ValueExact(1.23), ), }, }, @@ -216,7 +216,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.NewStringValue("str"), + knownvalue.StringValueExact("str"), ), }, }, @@ -246,7 +246,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.NewFloat64Value(3.21), + knownvalue.Float64ValueExact(3.21), ), }, }, @@ -276,7 +276,7 @@ func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.NewInt64Value(123), + knownvalue.Int64ValueExact(123), ), }, }, @@ -305,7 +305,7 @@ func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.NewInt64Value(321), + knownvalue.Int64ValueExact(321), ), }, }, @@ -339,8 +339,8 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { "test_resource.one", tfjsonpath.New("list_attribute"), knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }), ), }, @@ -373,7 +373,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{}), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{}), ), }, }, @@ -407,8 +407,8 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { "test_resource.one", tfjsonpath.New("list_attribute"), knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value3"), - knownvalue.NewStringValue("value4"), + knownvalue.StringValueExact("value3"), + knownvalue.StringValueExact("value4"), }), ), }, @@ -443,7 +443,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { "test_resource.one", tfjsonpath.New("list_attribute"), knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value1"), + 0: knownvalue.StringValueExact("value1"), }), ), }, @@ -479,7 +479,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing. "test_resource.one", tfjsonpath.New("list_attribute"), knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.NewStringValue("value3"), + 0: knownvalue.StringValueExact("value3"), }), ), }, @@ -513,7 +513,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -545,7 +545,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewNumElementsValue(3), + knownvalue.NumElementsExact(3), ), }, }, @@ -581,11 +581,11 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { "test_resource.one", tfjsonpath.New("list_nested_block"), knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("str"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -622,8 +622,8 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { "test_resource.one", tfjsonpath.New("list_nested_block"), knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "list_nested_block_attribute": knownvalue.NewStringValue("rts"), + 1: knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -659,7 +659,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -691,9 +691,9 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), }), ), }, @@ -759,9 +759,9 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "key3": knownvalue.NewStringValue("value3"), - "key4": knownvalue.NewStringValue("value4"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "key3": knownvalue.StringValueExact("value3"), + "key4": knownvalue.StringValueExact("value4"), }), ), }, @@ -795,8 +795,8 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key1": knownvalue.NewStringValue("value1"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "key1": knownvalue.StringValueExact("value1"), }), ), }, @@ -829,8 +829,8 @@ func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ - "key3": knownvalue.NewStringValue("value1"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + "key3": knownvalue.StringValueExact("value1"), }), ), }, @@ -864,7 +864,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -896,7 +896,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewNumElementsValue(3), + knownvalue.NumElementsExact(3), ), }, }, @@ -932,7 +932,7 @@ func TestExpectKnownValue_CheckPlan_Number(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.NewNumberValue(f), + knownvalue.NumberValueExact(f), ), }, }, @@ -967,7 +967,7 @@ func TestExpectKnownValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.NewNumberValue(f), + knownvalue.NumberValueExact(f), ), }, }, @@ -1000,9 +1000,9 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }), ), }, @@ -1035,9 +1035,9 @@ func TestExpectKnownValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value3"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value3"), }), ), }, @@ -1071,8 +1071,8 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value2"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value2"), }), ), }, @@ -1105,8 +1105,8 @@ func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value3"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.StringValueExact("value3"), }), ), }, @@ -1140,7 +1140,7 @@ func TestExpectKnownValue_CheckPlan_SetNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1174,12 +1174,12 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlock(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("str"), + knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -1215,9 +1215,9 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ - "set_nested_block_attribute": knownvalue.NewStringValue("rts"), + knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), ), @@ -1253,7 +1253,7 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.NewNumElementsValue(2), + knownvalue.NumElementsExact(2), ), }, }, @@ -1282,7 +1282,7 @@ func TestExpectKnownValue_CheckPlan_String(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.NewStringValue("str")), + knownvalue.StringValueExact("str")), }, }, }, @@ -1310,7 +1310,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.NewBoolValue(true)), + knownvalue.BoolValueExact(true)), }, }, ExpectError: regexp.MustCompile("wrong type: attribute value is string, known value type is knownvalue.BoolValue"), @@ -1339,7 +1339,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.NewStringValue("rts")), + knownvalue.StringValueExact("rts")), }, }, ExpectError: regexp.MustCompile("attribute value: str does not equal expected value: rts"), @@ -1357,7 +1357,7 @@ func TestExpectKnownValue_CheckPlan_UnknownAttributeType(t *testing.T) { expectedErr error }{ "unrecognised-type": { - knownValue: knownvalue.NewInt64Value(123), + knownValue: knownvalue.Int64ValueExact(123), req: plancheck.CheckPlanRequest{ Plan: &tfjson.Plan{ ResourceChanges: []*tfjson.ResourceChange{ From 31cbf097ae17257306780a02f2e07097717096b8 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Jan 2024 10:51:55 +0000 Subject: [PATCH 11/48] Refactoring to Check interface (#243) --- knownvalue/bool.go | 25 +++-- knownvalue/bool_test.go | 44 ++++++-- knownvalue/float64.go | 21 ++-- knownvalue/float64_test.go | 35 ++++-- knownvalue/int64.go | 21 ++-- knownvalue/int64_test.go | 35 ++++-- knownvalue/known_value.go | 11 +- knownvalue/list.go | 28 ++--- knownvalue/list_elements.go | 46 ++++++++ knownvalue/list_elements_test.go | 84 +++++++++++++++ knownvalue/list_partial.go | 40 ++++--- knownvalue/list_partial_test.go | 85 +++++++++++---- knownvalue/list_test.go | 77 ++++++++++--- knownvalue/map.go | 42 +++++--- knownvalue/map_elements.go | 46 ++++++++ knownvalue/map_elements_test.go | 84 +++++++++++++++ knownvalue/map_partial.go | 40 ++++--- knownvalue/map_partial_test.go | 89 ++++++++++++--- knownvalue/map_test.go | 95 +++++++++++++--- knownvalue/num_elements.go | 49 --------- knownvalue/num_elements_test.go | 77 ------------- knownvalue/number.go | 25 +++-- knownvalue/number_test.go | 34 ++++-- knownvalue/object.go | 42 +++++--- knownvalue/object_attributes.go | 46 ++++++++ knownvalue/object_attributes_test.go | 84 +++++++++++++++ knownvalue/object_partial.go | 40 ++++--- knownvalue/object_partial_test.go | 89 ++++++++++++--- knownvalue/object_test.go | 95 +++++++++++++--- knownvalue/set.go | 36 ++++--- knownvalue/set_elements.go | 46 ++++++++ knownvalue/set_elements_test.go | 84 +++++++++++++++ knownvalue/set_partial.go | 36 ++++--- knownvalue/set_partial_test.go | 78 ++++++++++---- knownvalue/set_test.go | 77 ++++++++++--- knownvalue/string.go | 20 ++-- knownvalue/string_test.go | 35 ++++-- plancheck/expect_known_output_value.go | 91 ++++++---------- .../expect_known_output_value_at_path.go | 89 ++++++--------- .../expect_known_output_value_at_path_test.go | 102 +++++++++--------- plancheck/expect_known_output_value_test.go | 100 ++++++++--------- plancheck/expect_known_value.go | 89 ++++++--------- plancheck/expect_known_value_test.go | 102 +++++++++--------- 43 files changed, 1704 insertions(+), 810 deletions(-) create mode 100644 knownvalue/list_elements.go create mode 100644 knownvalue/list_elements_test.go create mode 100644 knownvalue/map_elements.go create mode 100644 knownvalue/map_elements_test.go delete mode 100644 knownvalue/num_elements.go delete mode 100644 knownvalue/num_elements_test.go create mode 100644 knownvalue/object_attributes.go create mode 100644 knownvalue/object_attributes_test.go create mode 100644 knownvalue/set_elements.go create mode 100644 knownvalue/set_elements_test.go diff --git a/knownvalue/bool.go b/knownvalue/bool.go index 2a8e1a839..e4293ae70 100644 --- a/knownvalue/bool.go +++ b/knownvalue/bool.go @@ -3,30 +3,33 @@ package knownvalue -import "strconv" +import ( + "fmt" + "strconv" +) -var _ KnownValue = BoolValue{} +var _ Check = BoolValue{} -// BoolValue is a KnownValue for asserting equality between the value -// supplied to BoolValueExact and the value passed to the Equal method. +// BoolValue is a KnownValue for asserting equality between the value supplied +// to BoolValueExact and the value passed to the CheckValue method. type BoolValue struct { value bool } -// Equal determines whether the passed value is of type bool, and +// CheckValue determines whether the passed value is of type bool, and // contains a matching bool value. -func (v BoolValue) Equal(other any) bool { +func (v BoolValue) CheckValue(other any) error { otherVal, ok := other.(bool) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is bool", other) } if otherVal != v.value { - return false + return fmt.Errorf("value: %t does not equal expected value: %t", otherVal, v.value) } - return true + return nil } // String returns the string representation of the bool value. @@ -34,8 +37,8 @@ func (v BoolValue) String() string { return strconv.FormatBool(v.value) } -// BoolValueExact returns a KnownValue for asserting equality between the -// supplied bool and the value passed to the Equal method. +// BoolValueExact returns a Check for asserting equality between the +// supplied bool and the value passed to the CheckValue method. func BoolValueExact(value bool) BoolValue { return BoolValue{ value: value, diff --git a/knownvalue/bool_test.go b/knownvalue/bool_test.go index d8d442f1f..d7820c891 100644 --- a/knownvalue/bool_test.go +++ b/knownvalue/bool_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,23 +12,37 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestBoolValue_Equal(t *testing.T) { +func TestBoolValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.BoolValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is bool"), + }, + "zero-other": { + other: false, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.BoolValueExact(false), + expectedError: fmt.Errorf("wrong type: , known value type is bool"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.BoolValueExact(true), + other: 1.23, + expectedError: fmt.Errorf("wrong type: float64, known value type is bool"), }, "not-equal": { - other: false, + self: knownvalue.BoolValueExact(true), + other: false, + expectedError: fmt.Errorf("value: false does not equal expected value: true"), }, "equal": { - other: true, - expected: true, + self: knownvalue.BoolValueExact(true), + other: true, }, } @@ -37,9 +52,9 @@ func TestBoolValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.BoolValueExact(true).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -55,3 +70,12 @@ func TestBoolValue_String(t *testing.T) { t.Errorf("unexpected difference: %s", diff) } } + +// equateErrorMessage reports errors to be equal if both are nil +// or both have the same message. +var equateErrorMessage = cmp.Comparer(func(x, y error) bool { + if x == nil || y == nil { + return x == nil && y == nil + } + return x.Error() == y.Error() +}) diff --git a/knownvalue/float64.go b/knownvalue/float64.go index 51ada6897..e9455554b 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -4,31 +4,32 @@ package knownvalue import ( + "fmt" "strconv" ) -var _ KnownValue = Float64Value{} +var _ Check = Float64Value{} -// Float64Value is a KnownValue for asserting equality between the value -// supplied to Float64ValueExact and the value passed to the Equal method. +// Float64Value is a KnownValue for asserting equality between the value supplied +// to Float64ValueExact and the value passed to the CheckValue method. type Float64Value struct { value float64 } -// Equal determines whether the passed value is of type float64, and +// CheckValue determines whether the passed value is of type float64, and // contains a matching float64 value. -func (v Float64Value) Equal(other any) bool { +func (v Float64Value) CheckValue(other any) error { otherVal, ok := other.(float64) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is float64", other) } if otherVal != v.value { - return false + return fmt.Errorf("value: %v does not equal expected value: %s", strconv.FormatFloat(otherVal, 'f', -1, 64), v.String()) } - return true + return nil } // String returns the string representation of the float64 value. @@ -36,8 +37,8 @@ func (v Float64Value) String() string { return strconv.FormatFloat(v.value, 'f', -1, 64) } -// Float64ValueExact returns a KnownValue for asserting equality between the -// supplied float64 and the value passed to the Equal method. +// Float64ValueExact returns a Check for asserting equality between the +// supplied float64 and the value passed to the CheckValue method. func Float64ValueExact(value float64) Float64Value { return Float64Value{ value: value, diff --git a/knownvalue/float64_test.go b/knownvalue/float64_test.go index c706a877f..bfde22b5a 100644 --- a/knownvalue/float64_test.go +++ b/knownvalue/float64_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,23 +12,37 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestFloat64Value_Equal(t *testing.T) { +func TestFloat64Value_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.Float64Value + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is float64"), + }, + "zero-other": { + other: 0.0, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.Float64ValueExact(1.234), + expectedError: fmt.Errorf("wrong type: , known value type is float64"), + }, "wrong-type": { - other: 123, + self: knownvalue.Float64ValueExact(1.234), + other: int64(1234), + expectedError: fmt.Errorf("wrong type: int64, known value type is float64"), }, "not-equal": { - other: false, + self: knownvalue.Float64ValueExact(1.234), + other: 4.321, + expectedError: fmt.Errorf("value: 4.321 does not equal expected value: 1.234"), }, "equal": { - other: 1.23, - expected: true, + self: knownvalue.Float64ValueExact(1.234), + other: 1.234, }, } @@ -37,9 +52,9 @@ func TestFloat64Value_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.Float64ValueExact(1.23).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) diff --git a/knownvalue/int64.go b/knownvalue/int64.go index bf81328b4..9e2abf528 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -4,31 +4,32 @@ package knownvalue import ( + "fmt" "strconv" ) -var _ KnownValue = Int64Value{} +var _ Check = Int64Value{} -// Int64Value is a KnownValue for asserting equality between the value -// supplied to Int64ValueExact and the value passed to the Equal method. +// Int64Value is a KnownValue for asserting equality between the value supplied +// to Int64ValueExact and the value passed to the CheckValue method. type Int64Value struct { value int64 } -// Equal determines whether the passed value is of type int64, and +// CheckValue determines whether the passed value is of type int64, and // contains a matching int64 value. -func (v Int64Value) Equal(other any) bool { +func (v Int64Value) CheckValue(other any) error { otherVal, ok := other.(int64) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is int64", other) } if otherVal != v.value { - return false + return fmt.Errorf("value: %d does not equal expected value: %d", otherVal, v.value) } - return true + return nil } // String returns the string representation of the int64 value. @@ -36,8 +37,8 @@ func (v Int64Value) String() string { return strconv.FormatInt(v.value, 10) } -// Int64ValueExact returns a KnownValue for asserting equality between the -// supplied int64 and the value passed to the Equal method. +// Int64ValueExact returns a Check for asserting equality between the +// supplied int64 and the value passed to the CheckValue method. func Int64ValueExact(value int64) Int64Value { return Int64Value{ value: value, diff --git a/knownvalue/int64_test.go b/knownvalue/int64_test.go index c71fabbce..5b5d82b59 100644 --- a/knownvalue/int64_test.go +++ b/knownvalue/int64_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,23 +12,37 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestInt64Value_Equal(t *testing.T) { +func TestInt64Value_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.Int64Value + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is int64"), + }, + "zero-other": { + other: int64(0), // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.Int64ValueExact(1234), + expectedError: fmt.Errorf("wrong type: , known value type is int64"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.Int64ValueExact(1234), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is int64"), }, "not-equal": { - other: false, + self: knownvalue.Int64ValueExact(1234), + other: int64(4321), + expectedError: fmt.Errorf("value: 4321 does not equal expected value: 1234"), }, "equal": { - other: int64(123), - expected: true, + self: knownvalue.Int64ValueExact(1234), + other: int64(1234), }, } @@ -37,9 +52,9 @@ func TestInt64Value_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.Int64ValueExact(123).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) diff --git a/knownvalue/known_value.go b/knownvalue/known_value.go index c4793bf39..0c54bda20 100644 --- a/knownvalue/known_value.go +++ b/knownvalue/known_value.go @@ -3,8 +3,11 @@ package knownvalue -// KnownValue defines an interface that is implemented to determine equality on the basis of type and value. -type KnownValue interface { - // Equal should perform equality testing. - Equal(other any) bool +// Check defines an interface that is implemented to determine whether type and value match. Individual +// implementations determine how the match is performed (e.g., exact match, partial match). +type Check interface { + // CheckValue should perform match testing. + CheckValue(value any) error + // String should return a string representation of the type and value. + String() string } diff --git a/knownvalue/list.go b/knownvalue/list.go index b68121ea0..b94b572ba 100644 --- a/knownvalue/list.go +++ b/knownvalue/list.go @@ -7,34 +7,34 @@ import ( "fmt" ) -var _ KnownValue = ListValue{} +var _ Check = ListValue{} -// ListValue is a KnownValue for asserting equality between the value -// supplied to NewListValue and the value passed to the Equal method. +// ListValue is a KnownValue for asserting equality between the value supplied +// to ListValueExact and the value passed to the CheckValue method. type ListValue struct { - value []KnownValue + value []Check } -// Equal determines whether the passed value is of type []any, and +// CheckValue determines whether the passed value is of type []any, and // contains matching slice entries in the same sequence. -func (v ListValue) Equal(other any) bool { +func (v ListValue) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is []Check", other) } if len(otherVal) != len(v.value) { - return false + return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) } for i := 0; i < len(v.value); i++ { - if !v.value[i].Equal(otherVal[i]) { - return false + if err := v.value[i].CheckValue(otherVal[i]); err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -48,9 +48,9 @@ func (v ListValue) String() string { return fmt.Sprintf("%s", listVals) } -// NewListValue returns a KnownValue for asserting equality between the -// supplied []KnownValue and the value passed to the Equal method. -func NewListValue(value []KnownValue) ListValue { +// ListValueExact returns a Check for asserting equality between the +// supplied []KnownValue and the value passed to the CheckValue method. +func ListValueExact(value []Check) ListValue { return ListValue{ value: value, } diff --git a/knownvalue/list_elements.go b/knownvalue/list_elements.go new file mode 100644 index 000000000..2295d5912 --- /dev/null +++ b/knownvalue/list_elements.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "strconv" +) + +var _ Check = ListElements{} + +// ListElements is a Check for asserting equality between the value supplied +// to ListElementsExact and the value passed to the CheckValue method. +type ListElements struct { + num int +} + +// CheckValue verifies that the passed value is a list, map, object, +// or set, and contains a matching number of elements. +func (v ListElements) CheckValue(other any) error { + val, ok := other.([]any) + + if !ok { + return fmt.Errorf("wrong type: %T, expected []any", other) + } + + if len(val) != v.num { + return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + } + + return nil +} + +// String returns the string representation of the value. +func (v ListElements) String() string { + return strconv.FormatInt(int64(v.num), 10) +} + +// ListElementsExact returns a Check for asserting that +// a list num elements. +func ListElementsExact(num int) ListElements { + return ListElements{ + num: num, + } +} diff --git a/knownvalue/list_elements_test.go b/knownvalue/list_elements_test.go new file mode 100644 index 000000000..f057ccf8f --- /dev/null +++ b/knownvalue/list_elements_test.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestListElements_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.ListElements + other any + expectedError error + }{ + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , expected []any"), + }, + "zero-other": { + other: []any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.ListElementsExact(3), + expectedError: fmt.Errorf("wrong type: , expected []any"), + }, + "wrong-type": { + self: knownvalue.ListElementsExact(3), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, expected []any"), + }, + "empty": { + self: knownvalue.ListElementsExact(3), + other: []any{}, + expectedError: fmt.Errorf("wrong length: 0, expected 3"), + }, + "wrong-length": { + self: knownvalue.ListElementsExact(3), + other: []any{ + int64(123), + int64(456), + }, + expectedError: fmt.Errorf("wrong length: 2, expected 3"), + }, + "equal": { + self: knownvalue.ListElementsExact(3), + other: []any{ + int64(123), + int64(456), + int64(789), + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestListElements_String(t *testing.T) { + t.Parallel() + + got := knownvalue.ListElementsExact(2).String() + + if diff := cmp.Diff(got, "2"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/list_partial.go b/knownvalue/list_partial.go index 7fe6a0de2..767c50d6b 100644 --- a/knownvalue/list_partial.go +++ b/knownvalue/list_partial.go @@ -10,34 +10,44 @@ import ( "strings" ) -var _ KnownValue = ListValuePartial{} +var _ Check = ListValuePartial{} -// ListValuePartial is a KnownValue for asserting equality between the value -// supplied to NewListValuePartial and the value passed to the Equal method. +// ListValuePartial is a KnownValue for asserting equality between the value supplied +// to ListValuePartialMatch and the value passed to the CheckValue method. type ListValuePartial struct { - value map[int]KnownValue + value map[int]Check } -// Equal determines whether the passed value is of type []any, and +// CheckValue determines whether the passed value is of type []any, and // contains matching slice entries in the same sequence. -func (v ListValuePartial) Equal(other any) bool { +func (v ListValuePartial) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is map[int]Check", other) } - for k, val := range v.value { + var keys []int + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + for _, k := range keys { if len(otherVal) <= k { - return false + return fmt.Errorf("index out of bounds: %d", k) } - if !val.Equal(otherVal[k]) { - return false + if err := v.value[k].CheckValue(otherVal[k]); err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -69,11 +79,11 @@ func (v ListValuePartial) String() string { return b.String() } -// NewListValuePartial returns a KnownValue for asserting equality between the -// supplied map[int]KnownValue and the value passed to the Equal method. The +// ListValuePartialMatch returns a Check for asserting equality between the +// supplied map[int]KnownValue and the value passed to the CheckValue method. The // map keys correspond to the position of the zero-ordered element within the // list that is being checked. -func NewListValuePartial(value map[int]KnownValue) ListValuePartial { +func ListValuePartialMatch(value map[int]Check) ListValuePartial { return ListValuePartial{ value: value, } diff --git a/knownvalue/list_partial_test.go b/knownvalue/list_partial_test.go index 66d52abe3..0e6551a96 100644 --- a/knownvalue/list_partial_test.go +++ b/knownvalue/list_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,32 +12,80 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestListValuePartial_Equal(t *testing.T) { +func TestListValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.ListValuePartial + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is map[int]Check"), + }, + "zero-other": { + other: []any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + expectedError: fmt.Errorf("wrong type: , known value type is map[int]Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is map[int]Check"), }, "empty": { - other: []any{}, + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + other: []any{}, + expectedError: fmt.Errorf("index out of bounds: 0"), }, - "different-len": { - other: []any{1.23, 4.56}, + "wrong-length": { + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 4.56}, + expectedError: fmt.Errorf("index out of bounds: 2"), }, "not-equal": { - other: []any{1.23, 4.56, 6.54, 5.46}, + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 4.56, 6.54, 5.46}, + expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 4.56"), }, "wrong-order": { - other: []any{1.23, 0.00, 7.89, 4.56}, + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 0.00, 7.89, 4.56}, + expectedError: fmt.Errorf("value: 7.89 does not equal expected value: 4.56"), }, "equal": { - other: []any{1.23, 0.00, 4.56, 7.89}, - expected: true, + self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.Float64ValueExact(1.23), + 2: knownvalue.Float64ValueExact(4.56), + 3: knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 0.00, 4.56, 7.89}, }, } @@ -46,23 +95,19 @@ func TestListValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 0: knownvalue.Float64ValueExact(1.23), - 2: knownvalue.Float64ValueExact(4.56), - 3: knownvalue.Float64ValueExact(7.89), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) } } -func TestListValuePartial_String(t *testing.T) { +func TestListValuePartialPartial_String(t *testing.T) { t.Parallel() - got := knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + got := knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), diff --git a/knownvalue/list_test.go b/knownvalue/list_test.go index 26d1e9762..8a4760801 100644 --- a/knownvalue/list_test.go +++ b/knownvalue/list_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,47 +12,95 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestListValue_Equal(t *testing.T) { +func TestListValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.ListValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + }, + "zero-other": { + other: []any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), + expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is []Check"), }, "empty": { - other: []any{}, + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), + other: []any{}, + expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), }, - "different-len": { + "wrong-length": { + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ int64(123), int64(456), }, + expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), }, "not-equal": { + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ int64(123), int64(456), int64(654), }, + expectedError: fmt.Errorf("value: 654 does not equal expected value: 789"), }, "wrong-order": { + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ + int64(123), int64(789), int64(456), - int64(123), }, + expectedError: fmt.Errorf("value: 789 does not equal expected value: 456"), }, "equal": { + self: knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ int64(123), int64(456), int64(789), }, - expected: true, }, } @@ -61,13 +110,9 @@ func TestListValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.Int64ValueExact(123), - knownvalue.Int64ValueExact(456), - knownvalue.Int64ValueExact(789), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -77,7 +122,7 @@ func TestListValue_Equal(t *testing.T) { func TestListValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NewListValue([]knownvalue.KnownValue{ + got := knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.Int64ValueExact(123), knownvalue.Int64ValueExact(456), knownvalue.Int64ValueExact(789), diff --git a/knownvalue/map.go b/knownvalue/map.go index 0be97b6ba..d3f086cf2 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -8,40 +8,50 @@ import ( "sort" ) -var _ KnownValue = MapValue{} +var _ Check = MapValue{} -// MapValue is a KnownValue for asserting equality between the value -// supplied to MapValueExact and the value passed to the Equal method. +// MapValue is a KnownValue for asserting equality between the value supplied +// to MapValueExact and the value passed to the CheckValue method. type MapValue struct { - value map[string]KnownValue + value map[string]Check } -// Equal determines whether the passed value is of type map[string]any, and +// CheckValue determines whether the passed value is of type map[string]any, and // contains matching map entries. -func (v MapValue) Equal(other any) bool { +func (v MapValue) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) } if len(otherVal) != len(v.value) { - return false + return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) } - for k, v := range v.value { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + for _, k := range keys { otherValItem, ok := otherVal[k] if !ok { - return false + return fmt.Errorf("missing key: %s", k) } - if !v.Equal(otherValItem) { - return false + if err := v.value[k].CheckValue(otherValItem); err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -65,9 +75,9 @@ func (v MapValue) String() string { return fmt.Sprintf("%v", mapVals) } -// MapValueExact returns a KnownValue for asserting equality between the -// supplied map[string]KnownValue and the value passed to the Equal method. -func MapValueExact(value map[string]KnownValue) MapValue { +// MapValueExact returns a Check for asserting equality between the +// supplied map[string]KnownValue and the value passed to the CheckValue method. +func MapValueExact(value map[string]Check) MapValue { return MapValue{ value: value, } diff --git a/knownvalue/map_elements.go b/knownvalue/map_elements.go new file mode 100644 index 000000000..bc7547afc --- /dev/null +++ b/knownvalue/map_elements.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "strconv" +) + +var _ Check = MapElements{} + +// MapElements is a Check for asserting equality between the value supplied +// to MapElementsExact and the value passed to the CheckValue method. +type MapElements struct { + num int +} + +// CheckValue verifies that the passed value is a list, map, object, +// or set, and contains a matching number of elements. +func (v MapElements) CheckValue(other any) error { + val, ok := other.(map[string]any) + + if !ok { + return fmt.Errorf("wrong type: %T, expected map[string]any", other) + } + + if len(val) != v.num { + return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + } + + return nil +} + +// String returns the string representation of the value. +func (v MapElements) String() string { + return strconv.FormatInt(int64(v.num), 10) +} + +// MapElementsExact returns a Check for asserting that +// a list num elements. +func MapElementsExact(num int) MapElements { + return MapElements{ + num: num, + } +} diff --git a/knownvalue/map_elements_test.go b/knownvalue/map_elements_test.go new file mode 100644 index 000000000..79f3804bd --- /dev/null +++ b/knownvalue/map_elements_test.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestMapElements_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.MapElements + other any + expectedError error + }{ + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + }, + "zero-other": { + other: map[string]any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.MapElementsExact(3), + expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + }, + "wrong-type": { + self: knownvalue.MapElementsExact(3), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, expected map[string]any"), + }, + "empty": { + self: knownvalue.MapElementsExact(3), + other: map[string]any{}, + expectedError: fmt.Errorf("wrong length: 0, expected 3"), + }, + "wrong-length": { + self: knownvalue.MapElementsExact(3), + other: map[string]any{ + "one": int64(123), + "two": int64(456), + }, + expectedError: fmt.Errorf("wrong length: 2, expected 3"), + }, + "equal": { + self: knownvalue.MapElementsExact(3), + other: map[string]any{ + "one": int64(123), + "two": int64(456), + "three": int64(789), + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestMapElements_String(t *testing.T) { + t.Parallel() + + got := knownvalue.MapElementsExact(2).String() + + if diff := cmp.Diff(got, "2"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index d274e12ef..2074ae006 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -8,36 +8,46 @@ import ( "sort" ) -var _ KnownValue = MapValuePartial{} +var _ Check = MapValuePartial{} -// MapValuePartial is a KnownValue for asserting equality between the value -// supplied to MapValuePartialMatch and the value passed to the Equal method. +// MapValuePartial is a KnownValue for asserting equality between the value supplied +// to MapValuePartialMatch and the value passed to the CheckValue method. type MapValuePartial struct { - value map[string]KnownValue + value map[string]Check } -// Equal determines whether the passed value is of type map[string]any, and +// CheckValue determines whether the passed value is of type map[string]any, and // contains matching map entries. -func (v MapValuePartial) Equal(other any) bool { +func (v MapValuePartial) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) } - for k, v := range v.value { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + for _, k := range keys { otherValItem, ok := otherVal[k] if !ok { - return false + return fmt.Errorf("missing key: %s", k) } - if !v.Equal(otherValItem) { - return false + if err := v.value[k].CheckValue(otherValItem); err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -61,9 +71,9 @@ func (v MapValuePartial) String() string { return fmt.Sprintf("%v", mapVals) } -// MapValuePartialMatch returns a KnownValue for asserting partial equality between the -// supplied map[string]KnownValue and the value passed to the Equal method. -func MapValuePartialMatch(value map[string]KnownValue) MapValuePartial { +// MapValuePartialMatch returns a Check for asserting partial equality between the +// supplied map[string]Check and the value passed to the CheckValue method. +func MapValuePartialMatch(value map[string]Check) MapValuePartial { return MapValuePartial{ value: value, } diff --git a/knownvalue/map_partial_test.go b/knownvalue/map_partial_test.go index c21e824f5..ffb6c2e21 100644 --- a/knownvalue/map_partial_test.go +++ b/knownvalue/map_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,40 +12,101 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestMapValuePartial_Equal(t *testing.T) { +func TestMapValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.MapValuePartial + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, + "zero-other": { + other: map[string]any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), }, "empty": { - other: map[string]any{}, + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{}, + expectedError: fmt.Errorf("missing key: one"), }, - "not-equal-different-len": { + "wrong-length": { + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, }, + expectedError: fmt.Errorf("missing key: three"), }, - "not-equal-same-len": { + "not-equal": { + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 6.54, }, + expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + }, + "wrong-order": { + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "one": 1.23, + "two": 7.89, + "three": 4.56, + }, + expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + }, + "key-not-found": { + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "four": 1.23, + "five": 7.89, + "six": 4.56, + }, + expectedError: fmt.Errorf("missing key: one"), }, "equal": { + self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 7.89, }, - expected: true, }, } @@ -54,12 +116,9 @@ func TestMapValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ - "one": knownvalue.Float64ValueExact(1.23), - "three": knownvalue.Float64ValueExact(7.89), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -69,7 +128,7 @@ func TestMapValuePartial_Equal(t *testing.T) { func TestMapValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + got := knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }).String() diff --git a/knownvalue/map_test.go b/knownvalue/map_test.go index a7f1ca169..c6ba1c65e 100644 --- a/knownvalue/map_test.go +++ b/knownvalue/map_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,40 +12,108 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestMapValue_Equal(t *testing.T) { +func TestMapValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.MapValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, + "zero-other": { + other: map[string]any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), }, "empty": { - other: map[string]any{}, + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{}, + expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), }, - "different-len": { + "wrong-length": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, }, + expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), }, "not-equal": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 6.54, }, + expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + }, + "wrong-order": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "one": 1.23, + "two": 7.89, + "three": 4.56, + }, + expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + }, + "key-not-found": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "four": 1.23, + "five": 7.89, + "six": 4.56, + }, + expectedError: fmt.Errorf("missing key: one"), }, "equal": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 7.89, }, - expected: true, }, } @@ -54,13 +123,9 @@ func TestMapValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ - "one": knownvalue.Float64ValueExact(1.23), - "two": knownvalue.Float64ValueExact(4.56), - "three": knownvalue.Float64ValueExact(7.89), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -70,7 +135,7 @@ func TestMapValue_Equal(t *testing.T) { func TestMapValue_String(t *testing.T) { t.Parallel() - got := knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + got := knownvalue.MapValueExact(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), diff --git a/knownvalue/num_elements.go b/knownvalue/num_elements.go deleted file mode 100644 index a31e36905..000000000 --- a/knownvalue/num_elements.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue - -import "strconv" - -var _ KnownValue = NumElementsValue{} - -// NumElementsValue is a KnownValue for asserting equality between the value -// supplied to NumElementsExact and the value passed to the Equal method. -type NumElementsValue struct { - num int -} - -// Equal verifies that the passed value is a list, map, object, -// or set, and contains a matching number of elements. -func (v NumElementsValue) Equal(other any) bool { - mapVal, mapOk := other.(map[string]any) - - sliceVal, sliceOk := other.([]any) - - if !mapOk && !sliceOk { - return false - } - - if mapOk && len(mapVal) != v.num { - return false - } - - if sliceOk && len(sliceVal) != v.num { - return false - } - - return true -} - -// String returns the string representation of the value. -func (v NumElementsValue) String() string { - return strconv.FormatInt(int64(v.num), 10) -} - -// NumElementsExact returns a KnownValue for asserting that -// a list, map, object, or set contains num elements. -func NumElementsExact(num int) NumElementsValue { - return NumElementsValue{ - num: num, - } -} diff --git a/knownvalue/num_elements_test.go b/knownvalue/num_elements_test.go deleted file mode 100644 index d13c4d5c2..000000000 --- a/knownvalue/num_elements_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue_test - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/hashicorp/terraform-plugin-testing/knownvalue" -) - -func TestNumElements_Equal(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - other any - expected bool - }{ - "nil": {}, - "wrong-type": { - other: 1.23, - }, - "empty-map": { - other: map[string]any{}, - }, - "empty-slice": { - other: []any{}, - }, - "map-different-len": { - other: map[string]any{ - "one": 1.23, - "two": 4.56, - }, - }, - "slice-different-len": { - other: []any{1.23, 4.56}, - }, - "equal-map": { - other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 7.89, - }, - expected: true, - }, - "equal-slice": { - other: []any{1.23, 4.56, 7.89}, - expected: true, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := knownvalue.NumElementsExact(3).Equal(testCase.other) - - if diff := cmp.Diff(got, testCase.expected); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} - -func TestNumElements_String(t *testing.T) { - t.Parallel() - - got := knownvalue.NumElementsExact(2).String() - - if diff := cmp.Diff(got, "2"); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } -} diff --git a/knownvalue/number.go b/knownvalue/number.go index 4cc773ff6..a0ee720f8 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -4,31 +4,36 @@ package knownvalue import ( + "fmt" "math/big" ) -var _ KnownValue = NumberValue{} +var _ Check = NumberValue{} -// NumberValue is a KnownValue for asserting equality between the value -// supplied to NumberValueExact and the value passed to the Equal method. +// NumberValue is a KnownValue for asserting equality between the value supplied +// to NumberValueExact and the value passed to the CheckValue method. type NumberValue struct { value *big.Float } -// Equal determines whether the passed value is of type *big.Float, and +// CheckValue determines whether the passed value is of type *big.Float, and // contains a matching *big.Float value. -func (v NumberValue) Equal(other any) bool { +func (v NumberValue) CheckValue(other any) error { + if v.value == nil { + return fmt.Errorf("known value type is nil") + } + otherVal, ok := other.(*big.Float) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is *big.Float", other) } if v.value.Cmp(otherVal) != 0 { - return false + return fmt.Errorf("value: %s does not equal expected value: %s", otherVal.Text('f', -1), v.String()) } - return true + return nil } // String returns the string representation of the *big.Float value. @@ -36,8 +41,8 @@ func (v NumberValue) String() string { return v.value.Text('f', -1) } -// NumberValueExact returns a KnownValue for asserting equality between the -// supplied *big.Float and the value passed to the Equal method. +// NumberValueExact returns a Check for asserting equality between the +// supplied *big.Float and the value passed to the CheckValue method. func NumberValueExact(value *big.Float) NumberValue { return NumberValue{ value: value, diff --git a/knownvalue/number_test.go b/knownvalue/number_test.go index 1fed6adcc..9aa30a101 100644 --- a/knownvalue/number_test.go +++ b/knownvalue/number_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "math/big" "testing" @@ -28,19 +29,34 @@ func TestNumberValue_Equal(t *testing.T) { } testCases := map[string]struct { - other any - expected bool + self knownvalue.NumberValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("known value type is nil"), + }, + "zero-other": { + other: otherBigFloat, // checking against the underlying value field zero-value + expectedError: fmt.Errorf("known value type is nil"), + }, + "nil": { + self: knownvalue.NumberValueExact(bigFloat), + expectedError: fmt.Errorf("wrong type: , known value type is *big.Float"), + }, "wrong-type": { - other: "str", + self: knownvalue.NumberValueExact(bigFloat), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is *big.Float"), }, "not-equal": { - other: otherBigFloat, + self: knownvalue.NumberValueExact(bigFloat), + other: otherBigFloat, + expectedError: fmt.Errorf("value: 1.797693134862315797693134862315797693134862314 does not equal expected value: 1.797693134862315797693134862315797693134862315"), }, "equal": { - other: bigFloat, - expected: true, + self: knownvalue.NumberValueExact(bigFloat), + other: bigFloat, }, } @@ -50,9 +66,9 @@ func TestNumberValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.NumberValueExact(bigFloat).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) diff --git a/knownvalue/object.go b/knownvalue/object.go index ca19e032d..5ae4b489b 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -8,40 +8,50 @@ import ( "sort" ) -var _ KnownValue = ObjectValue{} +var _ Check = ObjectValue{} -// ObjectValue is a KnownValue for asserting equality between the value -// supplied to ObjectValueExact and the value passed to the Equal method. +// ObjectValue is a KnownValue for asserting equality between the value supplied +// to ObjectValueExact and the value passed to the CheckValue method. type ObjectValue struct { - value map[string]KnownValue + value map[string]Check } -// Equal determines whether the passed value is of type map[string]any, and +// CheckValue determines whether the passed value is of type map[string]any, and // contains matching object entries. -func (v ObjectValue) Equal(other any) bool { +func (v ObjectValue) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) } if len(otherVal) != len(v.value) { - return false + return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) } - for k, v := range v.value { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + for _, k := range keys { otherValItem, ok := otherVal[k] if !ok { - return false + return fmt.Errorf("missing key: %s", k) } - if !v.Equal(otherValItem) { - return false + if err := v.value[k].CheckValue(otherValItem); err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -65,9 +75,9 @@ func (v ObjectValue) String() string { return fmt.Sprintf("%v", mapVals) } -// ObjectValueExact returns a KnownValue for asserting equality between the -// supplied map[string]KnownValue and the value passed to the Equal method. -func ObjectValueExact(value map[string]KnownValue) ObjectValue { +// ObjectValueExact returns a Check for asserting equality between the +// supplied map[string]KnownValue and the value passed to the CheckValue method. +func ObjectValueExact(value map[string]Check) ObjectValue { return ObjectValue{ value: value, } diff --git a/knownvalue/object_attributes.go b/knownvalue/object_attributes.go new file mode 100644 index 000000000..575bd9f4c --- /dev/null +++ b/knownvalue/object_attributes.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "strconv" +) + +var _ Check = ObjectAttributes{} + +// ObjectAttributes is a Check for asserting equality between the value supplied +// to ObjectAttributesExact and the value passed to the CheckValue method. +type ObjectAttributes struct { + num int +} + +// CheckValue verifies that the passed value is a list, map, object, +// or set, and contains a matching number of elements. +func (v ObjectAttributes) CheckValue(other any) error { + val, ok := other.(map[string]any) + + if !ok { + return fmt.Errorf("wrong type: %T, expected map[string]any", other) + } + + if len(val) != v.num { + return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + } + + return nil +} + +// String returns the string representation of the value. +func (v ObjectAttributes) String() string { + return strconv.FormatInt(int64(v.num), 10) +} + +// ObjectAttributesExact returns a Check for asserting that +// a list num elements. +func ObjectAttributesExact(num int) ObjectAttributes { + return ObjectAttributes{ + num: num, + } +} diff --git a/knownvalue/object_attributes_test.go b/knownvalue/object_attributes_test.go new file mode 100644 index 000000000..bea0fb1c9 --- /dev/null +++ b/knownvalue/object_attributes_test.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestObjectAttributes_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.ObjectAttributes + other any + expectedError error + }{ + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + }, + "zero-other": { + other: map[string]any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.ObjectAttributesExact(3), + expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + }, + "wrong-type": { + self: knownvalue.ObjectAttributesExact(3), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, expected map[string]any"), + }, + "empty": { + self: knownvalue.ObjectAttributesExact(3), + other: map[string]any{}, + expectedError: fmt.Errorf("wrong length: 0, expected 3"), + }, + "wrong-length": { + self: knownvalue.ObjectAttributesExact(3), + other: map[string]any{ + "one": int64(123), + "two": int64(456), + }, + expectedError: fmt.Errorf("wrong length: 2, expected 3"), + }, + "equal": { + self: knownvalue.ObjectAttributesExact(3), + other: map[string]any{ + "one": int64(123), + "two": int64(456), + "three": int64(789), + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestObjectAttributes_String(t *testing.T) { + t.Parallel() + + got := knownvalue.ObjectAttributesExact(2).String() + + if diff := cmp.Diff(got, "2"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index 30c936251..5209808ef 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -8,36 +8,46 @@ import ( "sort" ) -var _ KnownValue = ObjectValuePartial{} +var _ Check = ObjectValuePartial{} -// ObjectValuePartial is a KnownValue for asserting equality between the value -// supplied to ObjectValuePartialMatch and the value passed to the Equal method. +// ObjectValuePartial is a KnownValue for asserting equality between the value supplied +// to ObjectValuePartialMatch and the value passed to the CheckValue method. type ObjectValuePartial struct { - value map[string]KnownValue + value map[string]Check } -// Equal determines whether the passed value is of type map[string]any, and +// CheckValue determines whether the passed value is of type map[string]any, and // contains matching map entries. -func (v ObjectValuePartial) Equal(other any) bool { +func (v ObjectValuePartial) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) } - for k, v := range v.value { + var keys []string + + for k := range v.value { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + for _, k := range keys { otherValItem, ok := otherVal[k] if !ok { - return false + return fmt.Errorf("missing key: %s", k) } - if !v.Equal(otherValItem) { - return false + if err := v.value[k].CheckValue(otherValItem); err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -61,9 +71,9 @@ func (v ObjectValuePartial) String() string { return fmt.Sprintf("%v", mapVals) } -// ObjectValuePartialMatch returns a KnownValue for asserting partial equality between the -// supplied map[string]KnownValue and the value passed to the Equal method. -func ObjectValuePartialMatch(value map[string]KnownValue) ObjectValuePartial { +// ObjectValuePartialMatch returns a Check for asserting partial equality between the +// supplied map[string]KnownValue and the value passed to the CheckValue method. +func ObjectValuePartialMatch(value map[string]Check) ObjectValuePartial { return ObjectValuePartial{ value: value, } diff --git a/knownvalue/object_partial_test.go b/knownvalue/object_partial_test.go index ec8b6033f..3d249cf0f 100644 --- a/knownvalue/object_partial_test.go +++ b/knownvalue/object_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,40 +12,101 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestObjectValuePartial_Equal(t *testing.T) { +func TestObjectValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.ObjectValuePartial + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, + "zero-other": { + other: map[string]any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), }, "empty": { - other: map[string]any{}, + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{}, + expectedError: fmt.Errorf("missing key: one"), }, - "not-equal-different-len": { + "wrong-length": { + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, }, + expectedError: fmt.Errorf("missing key: three"), }, - "not-equal-same-len": { + "not-equal": { + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 6.54, }, + expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + }, + "wrong-order": { + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "one": 1.23, + "two": 7.89, + "three": 4.56, + }, + expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + }, + "key-not-found": { + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "four": 1.23, + "five": 7.89, + "six": 4.56, + }, + expectedError: fmt.Errorf("missing key: one"), }, "equal": { + self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 7.89, }, - expected: true, }, } @@ -54,12 +116,9 @@ func TestObjectValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.ObjectValuePartialMatch(map[string]knownvalue.KnownValue{ - "one": knownvalue.Float64ValueExact(1.23), - "three": knownvalue.Float64ValueExact(7.89), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -69,7 +128,7 @@ func TestObjectValuePartial_Equal(t *testing.T) { func TestObjectValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.ObjectValuePartialMatch(map[string]knownvalue.KnownValue{ + got := knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }).String() diff --git a/knownvalue/object_test.go b/knownvalue/object_test.go index 1a87a04da..9fd6f9d77 100644 --- a/knownvalue/object_test.go +++ b/knownvalue/object_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,40 +12,108 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestObjectValue_Equal(t *testing.T) { +func TestObjectValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.ObjectValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, + "zero-other": { + other: map[string]any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), }, "empty": { - other: map[string]any{}, + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{}, + expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), }, - "different-len": { + "wrong-length": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, }, + expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), }, "not-equal": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 6.54, }, + expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + }, + "wrong-order": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "one": 1.23, + "two": 7.89, + "three": 4.56, + }, + expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + }, + "key-not-found": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), + other: map[string]any{ + "four": 1.23, + "five": 7.89, + "six": 4.56, + }, + expectedError: fmt.Errorf("missing key: one"), }, "equal": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "one": knownvalue.Float64ValueExact(1.23), + "two": knownvalue.Float64ValueExact(4.56), + "three": knownvalue.Float64ValueExact(7.89), + }), other: map[string]any{ "one": 1.23, "two": 4.56, "three": 7.89, }, - expected: true, }, } @@ -54,13 +123,9 @@ func TestObjectValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.ObjectValueExact(map[string]knownvalue.KnownValue{ - "one": knownvalue.Float64ValueExact(1.23), - "two": knownvalue.Float64ValueExact(4.56), - "three": knownvalue.Float64ValueExact(7.89), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -70,7 +135,7 @@ func TestObjectValue_Equal(t *testing.T) { func TestObjectValue_String(t *testing.T) { t.Parallel() - got := knownvalue.ObjectValueExact(map[string]knownvalue.KnownValue{ + got := knownvalue.ObjectValueExact(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), diff --git a/knownvalue/set.go b/knownvalue/set.go index b3a524076..9d2600b10 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -7,25 +7,25 @@ import ( "fmt" ) -var _ KnownValue = SetValue{} +var _ Check = SetValue{} -// SetValue is a KnownValue for asserting equality between the value -// supplied to SetValueExact and the value passed to the Equal method. +// SetValue is a KnownValue for asserting equality between the value supplied +// to SetValueExact and the value passed to the CheckValue method. type SetValue struct { - value []KnownValue + value []Check } -// Equal determines whether the passed value is of type []any, and +// CheckValue determines whether the passed value is of type []any, and // contains matching slice entries independent of the sequence. -func (v SetValue) Equal(other any) bool { +func (v SetValue) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is []Check", other) } if len(otherVal) != len(v.value) { - return false + return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) } otherValCopy := make([]any, len(otherVal)) @@ -33,25 +33,27 @@ func (v SetValue) Equal(other any) bool { copy(otherValCopy, otherVal) for i := 0; i < len(v.value); i++ { - var equal bool + err := fmt.Errorf("expected value not found: %s", v.value[i].String()) for j := 0; j < len(otherValCopy); j++ { - equal = v.value[i].Equal(otherValCopy[j]) + checkValueErr := v.value[i].CheckValue(otherValCopy[j]) - if equal { + if checkValueErr == nil { otherValCopy[j] = otherValCopy[len(otherValCopy)-1] otherValCopy = otherValCopy[:len(otherValCopy)-1] + err = nil + break } } - if !equal { - return false + if err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -65,9 +67,9 @@ func (v SetValue) String() string { return fmt.Sprintf("%s", setVals) } -// SetValueExact returns a KnownValue for asserting equality between the -// supplied []KnownValue and the value passed to the Equal method. -func SetValueExact(value []KnownValue) SetValue { +// SetValueExact returns a Check for asserting equality between the +// supplied []Check and the value passed to the CheckValue method. +func SetValueExact(value []Check) SetValue { return SetValue{ value: value, } diff --git a/knownvalue/set_elements.go b/knownvalue/set_elements.go new file mode 100644 index 000000000..d01fa8445 --- /dev/null +++ b/knownvalue/set_elements.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" + "strconv" +) + +var _ Check = SetElements{} + +// SetElements is a Check for asserting equality between the value supplied +// to SetElementsExact and the value passed to the CheckValue method. +type SetElements struct { + num int +} + +// CheckValue verifies that the passed value is a list, map, object, +// or set, and contains a matching number of elements. +func (v SetElements) CheckValue(other any) error { + val, ok := other.([]any) + + if !ok { + return fmt.Errorf("wrong type: %T, expected []any", other) + } + + if len(val) != v.num { + return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + } + + return nil +} + +// String returns the string representation of the value. +func (v SetElements) String() string { + return strconv.FormatInt(int64(v.num), 10) +} + +// SetElementsExact returns a Check for asserting that +// a list num elements. +func SetElementsExact(num int) SetElements { + return SetElements{ + num: num, + } +} diff --git a/knownvalue/set_elements_test.go b/knownvalue/set_elements_test.go new file mode 100644 index 000000000..e38d58956 --- /dev/null +++ b/knownvalue/set_elements_test.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestSetElements_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.SetElements + other any + expectedError error + }{ + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , expected []any"), + }, + "zero-other": { + other: []any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.SetElementsExact(3), + expectedError: fmt.Errorf("wrong type: , expected []any"), + }, + "wrong-type": { + self: knownvalue.SetElementsExact(3), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, expected []any"), + }, + "empty": { + self: knownvalue.SetElementsExact(3), + other: []any{}, + expectedError: fmt.Errorf("wrong length: 0, expected 3"), + }, + "wrong-length": { + self: knownvalue.SetElementsExact(3), + other: []any{ + int64(123), + int64(456), + }, + expectedError: fmt.Errorf("wrong length: 2, expected 3"), + }, + "equal": { + self: knownvalue.SetElementsExact(3), + other: []any{ + int64(123), + int64(456), + int64(789), + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestSetElements_String(t *testing.T) { + t.Parallel() + + got := knownvalue.SetElementsExact(2).String() + + if diff := cmp.Diff(got, "2"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index 7ec2d67f1..b8c149b05 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -7,21 +7,21 @@ import ( "fmt" ) -var _ KnownValue = SetValuePartial{} +var _ Check = SetValuePartial{} -// SetValuePartial is a KnownValue for asserting equality between the value -// supplied to SetValuePartialMatch and the value passed to the Equal method. +// SetValuePartial is a KnownValue for asserting equality between the value supplied +// to SetValuePartialMatch and the value passed to the CheckValue method. type SetValuePartial struct { - value []KnownValue + value []Check } -// Equal determines whether the passed value is of type []any, and -// contains matching slice entries in the same sequence. -func (v SetValuePartial) Equal(other any) bool { +// CheckValue determines whether the passed value is of type []any, and +// contains matching slice entries in any sequence. +func (v SetValuePartial) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is []Check", other) } otherValCopy := make([]any, len(otherVal)) @@ -29,25 +29,27 @@ func (v SetValuePartial) Equal(other any) bool { copy(otherValCopy, otherVal) for i := 0; i < len(v.value); i++ { - var equal bool + err := fmt.Errorf("expected value not found: %s", v.value[i].String()) for j := 0; j < len(otherValCopy); j++ { - equal = v.value[i].Equal(otherValCopy[j]) + checkValueErr := v.value[i].CheckValue(otherValCopy[j]) - if equal { + if checkValueErr == nil { otherValCopy[j] = otherValCopy[len(otherValCopy)-1] otherValCopy = otherValCopy[:len(otherValCopy)-1] + err = nil + break } } - if !equal { - return false + if err != nil { + return err } } - return true + return nil } // String returns the string representation of the value. @@ -61,9 +63,9 @@ func (v SetValuePartial) String() string { return fmt.Sprintf("%s", setVals) } -// SetValuePartialMatch returns a KnownValue for asserting equality of the elements -// supplied in []KnownValue and the elements in the value passed to the Equal method. -func SetValuePartialMatch(value []KnownValue) SetValuePartial { +// SetValuePartialMatch returns a Check for asserting equality of the elements +// supplied in []Check and the elements in the value passed to the CheckValue method. +func SetValuePartialMatch(value []Check) SetValuePartial { return SetValuePartial{ value: value, } diff --git a/knownvalue/set_partial_test.go b/knownvalue/set_partial_test.go index 62cd36770..789e892ed 100644 --- a/knownvalue/set_partial_test.go +++ b/knownvalue/set_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,33 +12,70 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestSetValuePartial_Equal(t *testing.T) { +func TestSetValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.SetValuePartial + other any + expectedError error }{ - "nil": {}, - "wrong-type": { - other: 1.23, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is []Check"), }, - "empty": { - other: []any{}, + "zero-other": { + other: []any{}, // checking against the underlying value field zero-value }, - "different-len": { - other: []any{1.23, 4.56}, + "nil": { + self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), + }), + expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + }, + "wrong-type": { + self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is []Check"), + }, + "equal-empty": { + self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), + }), + other: []any{}, + expectedError: fmt.Errorf("expected value not found: 1.23"), }, "not-equal": { - other: []any{1.23, 4.56, 6.54, 5.46}, + self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 4.56, 6.54, 5.46}, + expectedError: fmt.Errorf("expected value not found: 7.89"), }, "equal-different-order": { - other: []any{1.23, 0.00, 7.89, 4.56}, - expected: true, + self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 0.00, 7.89, 4.56}, }, "equal-same-order": { - other: []any{1.23, 0.00, 4.56, 7.89}, - expected: true, + self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.Float64ValueExact(1.23), + knownvalue.Float64ValueExact(4.56), + knownvalue.Float64ValueExact(7.89), + }), + other: []any{1.23, 0.00, 4.56, 7.89}, }, } @@ -47,13 +85,9 @@ func TestSetValuePartial_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ - knownvalue.Float64ValueExact(1.23), - knownvalue.Float64ValueExact(4.56), - knownvalue.Float64ValueExact(7.89), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -63,7 +97,7 @@ func TestSetValuePartial_Equal(t *testing.T) { func TestSetValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + got := knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), diff --git a/knownvalue/set_test.go b/knownvalue/set_test.go index 9de1a724a..6b46da69d 100644 --- a/knownvalue/set_test.go +++ b/knownvalue/set_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,48 +12,94 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestSetValue_Equal(t *testing.T) { +func TestSetValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.SetValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + }, + "zero-other": { + other: []any{}, // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), + expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is []Check"), }, "empty": { - other: []any{}, + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), + other: []any{}, + expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), }, - "different-len": { + "wrong-length": { + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ int64(123), int64(456), }, + expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), }, "not-equal": { + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ int64(123), int64(456), int64(654), }, + expectedError: fmt.Errorf("expected value not found: 789"), }, "equal-different-order": { + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ + int64(123), int64(789), int64(456), - int64(123), }, - expected: true, }, "equal-same-order": { + self: knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.Int64ValueExact(123), + knownvalue.Int64ValueExact(456), + knownvalue.Int64ValueExact(789), + }), other: []any{ int64(123), int64(456), int64(789), }, - expected: true, }, } @@ -62,13 +109,9 @@ func TestSetValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.SetValueExact([]knownvalue.KnownValue{ - knownvalue.Int64ValueExact(123), - knownvalue.Int64ValueExact(456), - knownvalue.Int64ValueExact(789), - }).Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -78,7 +121,7 @@ func TestSetValue_Equal(t *testing.T) { func TestSetValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NewListValue([]knownvalue.KnownValue{ + got := knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.Int64ValueExact(123), knownvalue.Int64ValueExact(456), knownvalue.Int64ValueExact(789), diff --git a/knownvalue/string.go b/knownvalue/string.go index d924568fd..59609cde7 100644 --- a/knownvalue/string.go +++ b/knownvalue/string.go @@ -3,28 +3,30 @@ package knownvalue -var _ KnownValue = StringValue{} +import "fmt" + +var _ Check = StringValue{} // StringValue is a KnownValue for asserting equality between the value -// supplied to StringValueExact and the value passed to the Equal method. +// supplied to StringValueExact and the value passed to the CheckValue method. type StringValue struct { value string } -// Equal determines whether the passed value is of type string, and +// CheckValue determines whether the passed value is of type string, and // contains a matching sequence of bytes. -func (v StringValue) Equal(other any) bool { +func (v StringValue) CheckValue(other any) error { otherVal, ok := other.(string) if !ok { - return false + return fmt.Errorf("wrong type: %T, known value type is string", other) } if otherVal != v.value { - return false + return fmt.Errorf("value: %s does not equal expected value: %s", otherVal, v.value) } - return true + return nil } // String returns the string representation of the value. @@ -32,8 +34,8 @@ func (v StringValue) String() string { return v.value } -// StringValueExact returns a KnownValue for asserting equality between the -// supplied string and a value passed to the Equal method. +// StringValueExact returns a Check for asserting equality between the +// supplied string and a value passed to the CheckValue method. func StringValueExact(value string) StringValue { return StringValue{ value: value, diff --git a/knownvalue/string_test.go b/knownvalue/string_test.go index 21ee97447..3576d2ee3 100644 --- a/knownvalue/string_test.go +++ b/knownvalue/string_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,23 +12,37 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" ) -func TestStringValue_Equal(t *testing.T) { +func TestStringValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - other any - expected bool + self knownvalue.StringValue + other any + expectedError error }{ - "nil": {}, + "zero-nil": { + expectedError: fmt.Errorf("wrong type: , known value type is string"), + }, + "zero-other": { + other: "", // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.StringValueExact("str"), + expectedError: fmt.Errorf("wrong type: , known value type is string"), + }, "wrong-type": { - other: 1.23, + self: knownvalue.StringValueExact("str"), + other: 1.234, + expectedError: fmt.Errorf("wrong type: float64, known value type is string"), }, "not-equal": { - other: "other", + self: knownvalue.StringValueExact("str"), + other: "rts", + expectedError: fmt.Errorf("value: rts does not equal expected value: str"), }, "equal": { - other: "str", - expected: true, + self: knownvalue.StringValueExact("str"), + other: "str", }, } @@ -37,9 +52,9 @@ func TestStringValue_Equal(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := knownvalue.StringValueExact("str").Equal(testCase.other) + got := testCase.self.CheckValue(testCase.other) - if diff := cmp.Diff(got, testCase.expected); diff != "" { + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go index 27314ee53..b1fa053c5 100644 --- a/plancheck/expect_known_output_value.go +++ b/plancheck/expect_known_output_value.go @@ -21,7 +21,7 @@ var _ PlanCheck = expectKnownOutputValue{} type expectKnownOutputValue struct { outputAddress string - knownValue knownvalue.KnownValue + knownValue knownvalue.Check } // CheckPlan implements the plan check logic. @@ -51,7 +51,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ } if result == nil { - resp.Error = fmt.Errorf("output value is null") + resp.Error = fmt.Errorf("value is null") return } @@ -61,13 +61,13 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ v, ok := e.knownValue.(knownvalue.BoolValue) if !ok { - resp.Error = fmt.Errorf("wrong type: output value is bool, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is bool, known value type is %T", e.knownValue) return } - if !v.Equal(result) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + if err := v.CheckValue(result); err != nil { + resp.Error = err return } @@ -81,28 +81,19 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ } switch t := e.knownValue.(type) { - case knownvalue.MapValue, - knownvalue.ObjectValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) - - return - } - case knownvalue.MapValuePartial, + case knownvalue.MapElements, + knownvalue.MapValue, + knownvalue.MapValuePartial, + knownvalue.ObjectAttributes, + knownvalue.ObjectValue, knownvalue.ObjectValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) - - return - } - case knownvalue.NumElementsValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) + if err := t.CheckValue(elems); err != nil { + resp.Error = err return } default: - resp.Error = fmt.Errorf("wrong type: output value is map, or object, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: value is map, or object, known value type is %T", t) return } @@ -119,33 +110,19 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ } switch t := e.knownValue.(type) { - case knownvalue.ListValue, - knownvalue.SetValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) - - return - } - case knownvalue.ListValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not contain elements at the specified indices: %v", elemsWithIndex, t) - - return - } - case knownvalue.NumElementsValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) - - return - } - case knownvalue.SetValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) + case knownvalue.ListElements, + knownvalue.ListValue, + knownvalue.ListValuePartial, + knownvalue.SetElements, + knownvalue.SetValue, + knownvalue.SetValuePartial: + if err := t.CheckValue(elems); err != nil { + resp.Error = err return } default: - resp.Error = fmt.Errorf("wrong type: output value is list, or set, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: value is list, or set, known value type is %T", t) return } @@ -160,7 +137,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) if !float64ValOk && !int64ValOk && !numberValOk { - resp.Error = fmt.Errorf("wrong type: output value is number, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is number, known value type is %T", e.knownValue) } switch { @@ -173,8 +150,8 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } - if !float64Val.Equal(f) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, float64Val) + if err := float64Val.CheckValue(f); err != nil { + resp.Error = err return } @@ -187,8 +164,8 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } - if !int64Val.Equal(i) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, int64Val) + if err := int64Val.CheckValue(i); err != nil { + resp.Error = err return } @@ -201,8 +178,8 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ return } - if !numberValue.Equal(f) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, numberValue) + if err := numberValue.CheckValue(f); err != nil { + resp.Error = err return } @@ -211,13 +188,13 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ v, ok := e.knownValue.(knownvalue.StringValue) if !ok { - resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is string, known value type is %T", e.knownValue) return } - if !v.Equal(result) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, v) + if err := v.CheckValue(result); err != nil { + resp.Error = err return } @@ -232,9 +209,9 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ } } -// ExpectKnownOutputValue returns a plan check that asserts that the specified output value +// ExpectKnownOutputValue returns a plan check that asserts that the specified value // has a known type, and value. -func ExpectKnownOutputValue(outputAddress string, knownValue knownvalue.KnownValue) PlanCheck { +func ExpectKnownOutputValue(outputAddress string, knownValue knownvalue.Check) PlanCheck { return expectKnownOutputValue{ outputAddress: outputAddress, knownValue: knownValue, diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go index 00d75eabc..b66bca6d7 100644 --- a/plancheck/expect_known_output_value_at_path.go +++ b/plancheck/expect_known_output_value_at_path.go @@ -22,7 +22,7 @@ var _ PlanCheck = expectKnownOutputValueAtPath{} type expectKnownOutputValueAtPath struct { outputAddress string outputPath tfjsonpath.Path - knownValue knownvalue.KnownValue + knownValue knownvalue.Check } // CheckPlan implements the plan check logic. @@ -52,7 +52,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl } if result == nil { - resp.Error = fmt.Errorf("output value is null") + resp.Error = fmt.Errorf("value is null") return } @@ -62,13 +62,13 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl v, ok := e.knownValue.(knownvalue.BoolValue) if !ok { - resp.Error = fmt.Errorf("wrong type: output value is bool, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is bool, known value type is %T", e.knownValue) return } - if !v.Equal(result) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", result, v) + if err := v.CheckValue(result); err != nil { + resp.Error = err return } @@ -82,28 +82,19 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl } switch t := e.knownValue.(type) { - case knownvalue.MapValue, - knownvalue.ObjectValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) - - return - } - case knownvalue.MapValuePartial, + case knownvalue.MapElements, + knownvalue.MapValue, + knownvalue.MapValuePartial, + knownvalue.ObjectAttributes, + knownvalue.ObjectValue, knownvalue.ObjectValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) - - return - } - case knownvalue.NumElementsValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) + if err := t.CheckValue(elems); err != nil { + resp.Error = err return } default: - resp.Error = fmt.Errorf("wrong type: output value is map, or object, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: value is map, or object, known value type is %T", t) return } @@ -120,33 +111,19 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl } switch t := e.knownValue.(type) { - case knownvalue.ListValue, - knownvalue.SetValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %s", elems, t) - - return - } - case knownvalue.ListValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not contain elements at the specified indices: %v", elemsWithIndex, t) - - return - } - case knownvalue.NumElementsValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output contains %d elements, expected %v", len(elems), t) - - return - } - case knownvalue.SetValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("output value: %v does not contain: %v", elems, t) + case knownvalue.ListElements, + knownvalue.ListValue, + knownvalue.ListValuePartial, + knownvalue.SetElements, + knownvalue.SetValue, + knownvalue.SetValuePartial: + if err := t.CheckValue(elems); err != nil { + resp.Error = err return } default: - resp.Error = fmt.Errorf("wrong type: output value is list, or set, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: value is list, or set, known value type is %T", t) return } @@ -161,7 +138,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) if !float64ValOk && !int64ValOk && !numberValOk { - resp.Error = fmt.Errorf("wrong type: output value is number, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is number, known value type is %T", e.knownValue) } switch { @@ -174,8 +151,8 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } - if !float64Val.Equal(f) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, float64Val) + if err := float64Val.CheckValue(f); err != nil { + resp.Error = err return } @@ -188,8 +165,8 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } - if !int64Val.Equal(i) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, int64Val) + if err := int64Val.CheckValue(i); err != nil { + resp.Error = err return } @@ -202,8 +179,8 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl return } - if !numberValue.Equal(f) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, numberValue) + if err := numberValue.CheckValue(f); err != nil { + resp.Error = err return } @@ -212,13 +189,13 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl v, ok := e.knownValue.(knownvalue.StringValue) if !ok { - resp.Error = fmt.Errorf("wrong type: output value is string, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is string, known value type is %T", e.knownValue) return } - if !v.Equal(result) { - resp.Error = fmt.Errorf("output value: %v does not equal expected value: %v", result, v) + if err := v.CheckValue(result); err != nil { + resp.Error = err return } @@ -235,7 +212,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl // ExpectKnownOutputValueAtPath returns a plan check that asserts that the specified output at the given path // has a known type and value. -func ExpectKnownOutputValueAtPath(outputAddress string, outputPath tfjsonpath.Path, knownValue knownvalue.KnownValue) PlanCheck { +func ExpectKnownOutputValueAtPath(outputAddress string, outputPath tfjsonpath.Path, knownValue knownvalue.Check) PlanCheck { return expectKnownOutputValueAtPath{ outputAddress: outputAddress, outputPath: outputPath, diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index c8442f1ba..2cb8cc07a 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -95,7 +95,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_AttributeValueNull(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("output value is null"), + ExpectError: regexp.MustCompile("value is null"), }, }, }) @@ -176,7 +176,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is bool, known value type is knownvalue.Float64Value"), + ExpectError: regexp.MustCompile("wrong type: value is bool, known value type is knownvalue.Float64Value"), }, }, }) @@ -217,7 +217,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile("output value: true does not equal expected value: false"), + ExpectError: regexp.MustCompile("value: true does not equal expected value: false"), }, }, }) @@ -299,7 +299,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is number, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: value is number, known value type is knownvalue.StringValue"), }, }, }) @@ -340,7 +340,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t * ), }, }, - ExpectError: regexp.MustCompile("output value: 1.23 does not equal expected value: 3.21"), + ExpectError: regexp.MustCompile("value: 1.23 does not equal expected value: 3.21"), }, }, }) @@ -421,7 +421,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *te ), }, }, - ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), }, }, }) @@ -461,7 +461,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), }), @@ -507,11 +507,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{}), + knownvalue.MapValueExact(map[string]knownvalue.Check{}), ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile("wrong type: value is list, or set, known value type is knownvalue.MapValue"), }, }, }) @@ -551,14 +551,14 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *tes plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value3"), knownvalue.StringValueExact("value4"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value3 value4\]`), + ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), }, }, }) @@ -598,7 +598,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -645,13 +645,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[0:value1 1:value2\] does not contain elements at the specified indices: \[0:value3\]`), + ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), }, }, }) @@ -691,7 +691,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NumElementsExact(2), + knownvalue.ListElementsExact(2), ), }, }, @@ -734,11 +734,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.NumElementsExact(3), + knownvalue.ListElementsExact(3), ), }, }, - ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), }, }, }) @@ -780,11 +780,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlock(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -832,8 +832,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockPartial(t *testin plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -881,7 +881,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockNumElements(t *te plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.NumElementsExact(2), + knownvalue.ListElementsExact(2), ), }, }, @@ -924,7 +924,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), "key2": knownvalue.StringValueExact("value2"), }), @@ -970,11 +970,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongType(t *testi plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{}), + knownvalue.ListValueExact([]knownvalue.Check{}), ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile("wrong type: value is map, or object, known value type is knownvalue.ListValue"), }, }, }) @@ -1014,14 +1014,14 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value3"), "key4": knownvalue.StringValueExact("value4"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not equal expected value: map\[key3:value3 key4:value4\]`), + ExpectError: regexp.MustCompile(`missing key: key3`), }, }, }) @@ -1061,7 +1061,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -1106,13 +1106,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not contain: map\[key3:value1\]`), + ExpectError: regexp.MustCompile(`missing key: key3`), }, }, }) @@ -1152,7 +1152,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NumElementsExact(2), + knownvalue.MapElementsExact(2), ), }, }, @@ -1195,11 +1195,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testi plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.NumElementsExact(3), + knownvalue.MapElementsExact(3), ), }, }, - ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), }, }, }) @@ -1292,7 +1292,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Number_KnownValueWrongValue(t *t ), }, }, - ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), }, }, }) @@ -1332,7 +1332,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), }), @@ -1378,14 +1378,14 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *test plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value1 value3\]`), + ExpectError: regexp.MustCompile(`expected value not found: value3`), }, }, }) @@ -1425,7 +1425,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1470,13 +1470,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not contain: \[value3\]`), + ExpectError: regexp.MustCompile(`expected value not found: value3`), }, }, }) @@ -1516,7 +1516,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNumElements(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.NumElementsExact(2), + knownvalue.SetElementsExact(2), ), }, }, @@ -1561,11 +1561,11 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlock(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetValueExact([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -1613,8 +1613,8 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockPartial(t *testing plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -1662,7 +1662,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockNumElements(t *tes plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.NumElementsExact(2), + knownvalue.SetElementsExact(2), ), }, }, @@ -1744,7 +1744,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *te knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is string, known value type is knownvalue.BoolValue"), + ExpectError: regexp.MustCompile("wrong type: value is string, known value type is knownvalue.BoolValue"), }, }, }) @@ -1784,7 +1784,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *t knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("output value: str does not equal expected value: rts"), + ExpectError: regexp.MustCompile("value: str does not equal expected value: rts"), }, }, }) @@ -1794,7 +1794,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_UnknownAttributeType(t *testing. t.Parallel() testCases := map[string]struct { - knownValue knownvalue.KnownValue + knownValue knownvalue.Check req plancheck.CheckPlanRequest expectedErr error }{ diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 17c63a725..2c5f2ae9c 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -76,7 +76,7 @@ func TestExpectKnownOutputValue_CheckPlan_AttributeValueNull(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("output value is null"), + ExpectError: regexp.MustCompile("value is null"), }, }, }) @@ -141,7 +141,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is bool, known value type is knownvalue.Float64Value"), + ExpectError: regexp.MustCompile("wrong type: value is bool, known value type is knownvalue.Float64Value"), }, }, }) @@ -240,7 +240,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is number, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: value is number, known value type is knownvalue.StringValue"), }, }, }) @@ -273,7 +273,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongValue(t *testin ), }, }, - ExpectError: regexp.MustCompile("output value: 1.23 does not equal expected value: 3.21"), + ExpectError: regexp.MustCompile("value: 1.23 does not equal expected value: 3.21"), }, }, }) @@ -338,7 +338,7 @@ func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing. ), }, }, - ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), }, }, }) @@ -370,7 +370,7 @@ func TestExpectKnownOutputValue_CheckPlan_List(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), }), @@ -408,11 +408,11 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{}), + knownvalue.MapValueExact(map[string]knownvalue.Check{}), ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile("wrong type: value is list, or set, known value type is knownvalue.MapValue"), }, }, }) @@ -444,14 +444,14 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongValue(t *testing.T PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value3"), knownvalue.StringValueExact("value4"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value3 value4\]`), + ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), }, }, }) @@ -483,7 +483,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -522,13 +522,13 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *te PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[0:value1 1:value2\] does not contain elements at the specified indices: \[0:value3\]`), + ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), }, }, }) @@ -560,7 +560,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NumElementsExact(2), + knownvalue.ListElementsExact(2), ), }, }, @@ -595,11 +595,11 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.NumElementsExact(3), + knownvalue.ListElementsExact(3), ), }, }, - ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), }, }, }) @@ -633,11 +633,11 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlock(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -677,8 +677,8 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -718,7 +718,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockNumElements(t *testing. PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.NumElementsExact(2), + knownvalue.ListElementsExact(2), ), }, }, @@ -753,7 +753,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), "key2": knownvalue.StringValueExact("value2"), }), @@ -791,11 +791,11 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NewListValue([]knownvalue.KnownValue{}), + knownvalue.ListValueExact([]knownvalue.Check{}), ), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile("wrong type: value is map, or object, known value type is knownvalue.ListValue"), }, }, }) @@ -827,14 +827,14 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value3"), "key4": knownvalue.StringValueExact("value4"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not equal expected value: map\[key3:value3 key4:value4\]`), + ExpectError: regexp.MustCompile(`missing key: key3`), }, }, }) @@ -866,7 +866,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -903,13 +903,13 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *tes PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: map\[key1:value1 key2:value2\] does not contain: map\[key3:value1\]`), + ExpectError: regexp.MustCompile(`missing key: key3`), }, }, }) @@ -941,7 +941,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NumElementsExact(2), + knownvalue.MapElementsExact(2), ), }, }, @@ -976,11 +976,11 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.NumElementsExact(3), + knownvalue.MapElementsExact(3), ), }, }, - ExpectError: regexp.MustCompile("output contains 2 elements, expected 3"), + ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), }, }, }) @@ -1057,7 +1057,7 @@ func TestExpectKnownOutputValue_CheckPlan_Number_KnownValueWrongValue(t *testing ), }, }, - ExpectError: regexp.MustCompile("output value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), }, }, }) @@ -1089,7 +1089,7 @@ func TestExpectKnownOutputValue_CheckPlan_Set(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), }), @@ -1127,14 +1127,14 @@ func TestExpectKnownOutputValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not equal expected value: \[value1 value3\]`), + ExpectError: regexp.MustCompile(`expected value not found: value3`), }, }, }) @@ -1166,7 +1166,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1203,13 +1203,13 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *tes PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`output value: \[value1 value2\] does not contain: \[value3\]`), + ExpectError: regexp.MustCompile(`expected value not found: value3`), }, }, }) @@ -1241,7 +1241,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNumElements(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.NumElementsExact(2), + knownvalue.SetElementsExact(2), ), }, }, @@ -1278,11 +1278,11 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlock(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetValueExact([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -1322,8 +1322,8 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -1363,7 +1363,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockNumElements(t *testing.T PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.NumElementsExact(2), + knownvalue.SetElementsExact(2), ), }, }, @@ -1429,7 +1429,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongType(t *testing. knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("wrong type: output value is string, known value type is knownvalue.BoolValue"), + ExpectError: regexp.MustCompile("wrong type: value is string, known value type is knownvalue.BoolValue"), }, }, }) @@ -1461,7 +1461,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongValue(t *testing knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("output value: str does not equal expected value: rts"), + ExpectError: regexp.MustCompile("value: str does not equal expected value: rts"), }, }, }) @@ -1471,7 +1471,7 @@ func TestExpectKnownOutputValue_CheckPlan_UnknownAttributeType(t *testing.T) { t.Parallel() testCases := map[string]struct { - knownValue knownvalue.KnownValue + knownValue knownvalue.Check req plancheck.CheckPlanRequest expectedErr error }{ diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index b0543e3ab..05d5c1b83 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -22,7 +22,7 @@ var _ PlanCheck = expectKnownValue{} type expectKnownValue struct { resourceAddress string attributePath tfjsonpath.Path - knownValue knownvalue.KnownValue + knownValue knownvalue.Check } // CheckPlan implements the plan check logic. @@ -52,7 +52,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } if result == nil { - resp.Error = fmt.Errorf("attribute value is null") + resp.Error = fmt.Errorf("value is null") return } @@ -62,13 +62,13 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r v, ok := e.knownValue.(knownvalue.BoolValue) if !ok { - resp.Error = fmt.Errorf("wrong type: attribute value is bool, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is bool, known value type is %T", e.knownValue) return } - if !v.Equal(result) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", result, v) + if err := v.CheckValue(result); err != nil { + resp.Error = err return } @@ -82,28 +82,19 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } switch t := e.knownValue.(type) { - case knownvalue.MapValue, - knownvalue.ObjectValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", elems, t) - - return - } - case knownvalue.MapValuePartial, + case knownvalue.MapElements, + knownvalue.MapValue, + knownvalue.MapValuePartial, + knownvalue.ObjectAttributes, + knownvalue.ObjectValue, knownvalue.ObjectValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute value: %v does not contain: %v", elems, t) - - return - } - case knownvalue.NumElementsValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) + if err := t.CheckValue(elems); err != nil { + resp.Error = err return } default: - resp.Error = fmt.Errorf("wrong type: attribute value is map, or object, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: value is map, or object, known value type is %T", t) return } @@ -120,33 +111,19 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } switch t := e.knownValue.(type) { - case knownvalue.ListValue, - knownvalue.SetValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %s", elems, t) - - return - } - case knownvalue.ListValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute value: %v does not contain elements at the specified indices: %v", elemsWithIndex, t) - - return - } - case knownvalue.NumElementsValue: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute contains %d elements, expected %v", len(elems), t) - - return - } - case knownvalue.SetValuePartial: - if !t.Equal(elems) { - resp.Error = fmt.Errorf("attribute value: %v does not contain: %v", elems, t) + case knownvalue.ListElements, + knownvalue.ListValue, + knownvalue.ListValuePartial, + knownvalue.SetElements, + knownvalue.SetValue, + knownvalue.SetValuePartial: + if err := t.CheckValue(elems); err != nil { + resp.Error = err return } default: - resp.Error = fmt.Errorf("wrong type: attribute value is list, or set, known value type is %T", t) + resp.Error = fmt.Errorf("wrong type: value is list, or set, known value type is %T", t) return } @@ -161,7 +138,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) if !float64ValOk && !int64ValOk && !numberValOk { - resp.Error = fmt.Errorf("wrong type: attribute value is number, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is number, known value type is %T", e.knownValue) } switch { @@ -174,8 +151,8 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - if !float64Val.Equal(f) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, float64Val) + if err := float64Val.CheckValue(f); err != nil { + resp.Error = err return } @@ -188,8 +165,8 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - if !int64Val.Equal(i) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, int64Val) + if err := int64Val.CheckValue(i); err != nil { + resp.Error = err return } @@ -202,8 +179,8 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r return } - if !numberValue.Equal(f) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, numberValue) + if err := numberValue.CheckValue(f); err != nil { + resp.Error = err return } @@ -212,13 +189,13 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r v, ok := e.knownValue.(knownvalue.StringValue) if !ok { - resp.Error = fmt.Errorf("wrong type: attribute value is string, known value type is %T", e.knownValue) + resp.Error = fmt.Errorf("wrong type: value is string, known value type is %T", e.knownValue) return } - if !v.Equal(result) { - resp.Error = fmt.Errorf("attribute value: %v does not equal expected value: %v", result, v) + if err := v.CheckValue(result); err != nil { + resp.Error = err return } @@ -235,7 +212,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r // ExpectKnownValue returns a plan check that asserts that the specified attribute at the given resource // has a known type and value. -func ExpectKnownValue(resourceAddress string, attributePath tfjsonpath.Path, knownValue knownvalue.KnownValue) PlanCheck { +func ExpectKnownValue(resourceAddress string, attributePath tfjsonpath.Path, knownValue knownvalue.Check) PlanCheck { return expectKnownValue{ resourceAddress: resourceAddress, attributePath: attributePath, diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index d5a9a07b7..afafe20b8 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -71,7 +71,7 @@ func TestExpectKnownValue_CheckPlan_AttributeValueNull(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("attribute value is null"), + ExpectError: regexp.MustCompile("value is null"), }, }, }) @@ -130,7 +130,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute value is bool, known value type is knownvalue.Float64Value"), + ExpectError: regexp.MustCompile("wrong type: value is bool, known value type is knownvalue.Float64Value"), }, }, }) @@ -160,7 +160,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("attribute value: true does not equal expected value: false"), + ExpectError: regexp.MustCompile("value: true does not equal expected value: false"), }, }, }) @@ -220,7 +220,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute value is number, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile("wrong type: value is number, known value type is knownvalue.StringValue"), }, }, }) @@ -250,7 +250,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("attribute value: 1.23 does not equal expected value: 3.21"), + ExpectError: regexp.MustCompile("value: 1.23 does not equal expected value: 3.21"), }, }, }) @@ -309,7 +309,7 @@ func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("attribute value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), }, }, }) @@ -338,7 +338,7 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), }), @@ -373,11 +373,11 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{}), + knownvalue.MapValueExact(map[string]knownvalue.Check{}), ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute value is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile("wrong type: value is list, or set, known value type is knownvalue.MapValue"), }, }, }) @@ -406,14 +406,14 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value3"), knownvalue.StringValueExact("value4"), }), ), }, }, - ExpectError: regexp.MustCompile(`attribute value: \[value1 value2\] does not equal expected value: \[value3 value4\]`), + ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), }, }, }) @@ -442,7 +442,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -478,13 +478,13 @@ func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing. plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`attribute value: \[0:value1 1:value2\] does not contain elements at the specified indices: \[0:value3\]`), + ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), }, }, }) @@ -513,7 +513,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NumElementsExact(2), + knownvalue.ListElementsExact(2), ), }, }, @@ -545,11 +545,11 @@ func TestExpectKnownValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NumElementsExact(3), + knownvalue.ListElementsExact(3), ), }, }, - ExpectError: regexp.MustCompile("attribute contains 2 elements, expected 3"), + ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), }, }, }) @@ -580,11 +580,11 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlock(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -621,8 +621,8 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ - 1: knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -659,7 +659,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.NumElementsExact(2), + knownvalue.ListElementsExact(2), ), }, }, @@ -691,7 +691,7 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), "key2": knownvalue.StringValueExact("value2"), }), @@ -726,11 +726,11 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{}), + knownvalue.ListValueExact([]knownvalue.Check{}), ), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute value is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile("wrong type: value is map, or object, known value type is knownvalue.ListValue"), }, }, }) @@ -759,14 +759,14 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value3"), "key4": knownvalue.StringValueExact("value4"), }), ), }, }, - ExpectError: regexp.MustCompile(`attribute value: map\[key1:value1 key2:value2\] does not equal expected value: map\[key3:value3 key4:value4\]`), + ExpectError: regexp.MustCompile(`missing key: key3`), }, }, }) @@ -795,7 +795,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -829,13 +829,13 @@ func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.KnownValue{ + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), }, }, - ExpectError: regexp.MustCompile(`attribute value: map\[key1:value1 key2:value2\] does not contain: map\[key3:value1\]`), + ExpectError: regexp.MustCompile(`missing key: key3`), }, }, }) @@ -864,7 +864,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NumElementsExact(2), + knownvalue.MapElementsExact(2), ), }, }, @@ -896,11 +896,11 @@ func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NumElementsExact(3), + knownvalue.MapElementsExact(3), ), }, }, - ExpectError: regexp.MustCompile("attribute contains 2 elements, expected 3"), + ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), }, }, }) @@ -971,7 +971,7 @@ func TestExpectKnownValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("attribute value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), }, }, }) @@ -1000,7 +1000,7 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), }), @@ -1035,14 +1035,14 @@ func TestExpectKnownValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`attribute value: \[value1 value2\] does not equal expected value: \[value1 value3\]`), + ExpectError: regexp.MustCompile(`expected value not found: value3`), }, }, }) @@ -1071,7 +1071,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1105,13 +1105,13 @@ func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`attribute value: \[value1 value2\] does not contain: \[value3\]`), + ExpectError: regexp.MustCompile(`expected value not found: value3`), }, }, }) @@ -1140,7 +1140,7 @@ func TestExpectKnownValue_CheckPlan_SetNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NumElementsExact(2), + knownvalue.SetElementsExact(2), ), }, }, @@ -1174,11 +1174,11 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlock(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetValueExact([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -1215,8 +1215,8 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartialMatch([]knownvalue.KnownValue{ - knownvalue.MapValueExact(map[string]knownvalue.KnownValue{ + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), }), @@ -1253,7 +1253,7 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.NumElementsExact(2), + knownvalue.SetElementsExact(2), ), }, }, @@ -1313,7 +1313,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("wrong type: attribute value is string, known value type is knownvalue.BoolValue"), + ExpectError: regexp.MustCompile("wrong type: value is string, known value type is knownvalue.BoolValue"), }, }, }) @@ -1342,7 +1342,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("attribute value: str does not equal expected value: rts"), + ExpectError: regexp.MustCompile("value: str does not equal expected value: rts"), }, }, }) @@ -1352,7 +1352,7 @@ func TestExpectKnownValue_CheckPlan_UnknownAttributeType(t *testing.T) { t.Parallel() testCases := map[string]struct { - knownValue knownvalue.KnownValue + knownValue knownvalue.Check req plancheck.CheckPlanRequest expectedErr error }{ From 3f14259328eb357b6ac9b750c0f2998c07265962 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Jan 2024 11:06:14 +0000 Subject: [PATCH 12/48] Linting (#243) --- knownvalue/list.go | 2 +- knownvalue/map.go | 2 +- knownvalue/map_partial.go | 2 +- knownvalue/object.go | 2 +- knownvalue/object_partial.go | 2 +- knownvalue/set.go | 2 +- knownvalue/set_partial.go | 2 +- plancheck/expect_known_output_value.go | 3 --- plancheck/expect_known_output_value_at_path.go | 3 --- plancheck/expect_known_value.go | 3 --- 10 files changed, 7 insertions(+), 16 deletions(-) diff --git a/knownvalue/list.go b/knownvalue/list.go index b94b572ba..24b25d828 100644 --- a/knownvalue/list.go +++ b/knownvalue/list.go @@ -42,7 +42,7 @@ func (v ListValue) String() string { var listVals []string for _, val := range v.value { - listVals = append(listVals, fmt.Sprintf("%s", val)) + listVals = append(listVals, val.String()) } return fmt.Sprintf("%s", listVals) diff --git a/knownvalue/map.go b/knownvalue/map.go index d3f086cf2..192e70dcc 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -69,7 +69,7 @@ func (v MapValue) String() string { mapVals := make(map[string]string, len(keys)) for _, k := range keys { - mapVals[k] = fmt.Sprintf("%s", v.value[k]) + mapVals[k] = v.value[k].String() } return fmt.Sprintf("%v", mapVals) diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index 2074ae006..bd55b19c8 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -65,7 +65,7 @@ func (v MapValuePartial) String() string { mapVals := make(map[string]string, len(keys)) for _, k := range keys { - mapVals[k] = fmt.Sprintf("%s", v.value[k]) + mapVals[k] = v.value[k].String() } return fmt.Sprintf("%v", mapVals) diff --git a/knownvalue/object.go b/knownvalue/object.go index 5ae4b489b..8a2c3c78c 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -69,7 +69,7 @@ func (v ObjectValue) String() string { mapVals := make(map[string]string, len(keys)) for _, k := range keys { - mapVals[k] = fmt.Sprintf("%s", v.value[k]) + mapVals[k] = v.value[k].String() } return fmt.Sprintf("%v", mapVals) diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index 5209808ef..a84bbedff 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -65,7 +65,7 @@ func (v ObjectValuePartial) String() string { mapVals := make(map[string]string, len(keys)) for _, k := range keys { - mapVals[k] = fmt.Sprintf("%s", v.value[k]) + mapVals[k] = v.value[k].String() } return fmt.Sprintf("%v", mapVals) diff --git a/knownvalue/set.go b/knownvalue/set.go index 9d2600b10..7399e1d14 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -61,7 +61,7 @@ func (v SetValue) String() string { var setVals []string for _, val := range v.value { - setVals = append(setVals, fmt.Sprintf("%s", val)) + setVals = append(setVals, val.String()) } return fmt.Sprintf("%s", setVals) diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index b8c149b05..b9e4b204b 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -57,7 +57,7 @@ func (v SetValuePartial) String() string { var setVals []string for _, val := range v.value { - setVals = append(setVals, fmt.Sprintf("%s", val)) + setVals = append(setVals, val.String()) } return fmt.Sprintf("%s", setVals) diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go index b1fa053c5..f310fe06b 100644 --- a/plancheck/expect_known_output_value.go +++ b/plancheck/expect_known_output_value.go @@ -100,13 +100,10 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ case reflect.Slice: var elems []any - var elemsWithIndex []string - val := reflect.ValueOf(result) for i := 0; i < val.Len(); i++ { elems = append(elems, val.Index(i).Interface()) - elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) } switch t := e.knownValue.(type) { diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go index b66bca6d7..0fadbd01d 100644 --- a/plancheck/expect_known_output_value_at_path.go +++ b/plancheck/expect_known_output_value_at_path.go @@ -101,13 +101,10 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl case reflect.Slice: var elems []any - var elemsWithIndex []string - val := reflect.ValueOf(result) for i := 0; i < val.Len(); i++ { elems = append(elems, val.Index(i).Interface()) - elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) } switch t := e.knownValue.(type) { diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index 05d5c1b83..2f7e12c05 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -101,13 +101,10 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r case reflect.Slice: var elems []any - var elemsWithIndex []string - val := reflect.ValueOf(result) for i := 0; i < val.Len(); i++ { elems = append(elems, val.Index(i).Interface()) - elemsWithIndex = append(elemsWithIndex, fmt.Sprintf("%d:%v", i, val.Index(i).Interface())) } switch t := e.knownValue.(type) { From 5e615244e37ba2459d2f5346c96695a50ecfc9b7 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Jan 2024 14:53:20 +0000 Subject: [PATCH 13/48] Modifying known value check error messages and tests (#243) --- knownvalue/bool.go | 4 ++-- knownvalue/bool_test.go | 8 ++++---- knownvalue/float64.go | 4 ++-- knownvalue/float64_test.go | 8 ++++---- knownvalue/int64.go | 4 ++-- knownvalue/int64_test.go | 8 ++++---- knownvalue/list.go | 17 ++++++++++++++--- knownvalue/list_elements.go | 19 +++++++++++++++---- knownvalue/list_elements_test.go | 10 +++++----- knownvalue/list_partial.go | 6 +++--- knownvalue/list_partial_test.go | 14 +++++++------- knownvalue/list_test.go | 14 +++++++------- knownvalue/map.go | 19 +++++++++++++++---- knownvalue/map_elements.go | 19 +++++++++++++++---- knownvalue/map_elements_test.go | 10 +++++----- knownvalue/map_partial.go | 6 +++--- knownvalue/map_partial_test.go | 16 ++++++++-------- knownvalue/map_test.go | 16 ++++++++-------- knownvalue/number.go | 4 ++-- knownvalue/number_test.go | 6 +++--- knownvalue/object.go | 19 +++++++++++++++---- knownvalue/object_attributes.go | 19 +++++++++++++++---- knownvalue/object_attributes_test.go | 10 +++++----- knownvalue/object_partial.go | 6 +++--- knownvalue/object_partial_test.go | 16 ++++++++-------- knownvalue/object_test.go | 16 ++++++++-------- knownvalue/set.go | 17 ++++++++++++++--- knownvalue/set_elements.go | 19 +++++++++++++++---- knownvalue/set_elements_test.go | 10 +++++----- knownvalue/set_partial.go | 4 ++-- knownvalue/set_partial_test.go | 10 +++++----- knownvalue/set_test.go | 12 ++++++------ knownvalue/string.go | 4 ++-- knownvalue/string_test.go | 8 ++++---- 34 files changed, 235 insertions(+), 147 deletions(-) diff --git a/knownvalue/bool.go b/knownvalue/bool.go index e4293ae70..12006a7f1 100644 --- a/knownvalue/bool.go +++ b/knownvalue/bool.go @@ -22,11 +22,11 @@ func (v BoolValue) CheckValue(other any) error { otherVal, ok := other.(bool) if !ok { - return fmt.Errorf("wrong type: %T, known value type is bool", other) + return fmt.Errorf("expected bool value for BoolValue check, got: %T", other) } if otherVal != v.value { - return fmt.Errorf("value: %t does not equal expected value: %t", otherVal, v.value) + return fmt.Errorf("expected value %t for BoolValue check, got: %t", v.value, otherVal) } return nil diff --git a/knownvalue/bool_test.go b/knownvalue/bool_test.go index d7820c891..21e9bee7e 100644 --- a/knownvalue/bool_test.go +++ b/knownvalue/bool_test.go @@ -21,24 +21,24 @@ func TestBoolValue_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is bool"), + expectedError: fmt.Errorf("expected bool value for BoolValue check, got: "), }, "zero-other": { other: false, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.BoolValueExact(false), - expectedError: fmt.Errorf("wrong type: , known value type is bool"), + expectedError: fmt.Errorf("expected bool value for BoolValue check, got: "), }, "wrong-type": { self: knownvalue.BoolValueExact(true), other: 1.23, - expectedError: fmt.Errorf("wrong type: float64, known value type is bool"), + expectedError: fmt.Errorf("expected bool value for BoolValue check, got: float64"), }, "not-equal": { self: knownvalue.BoolValueExact(true), other: false, - expectedError: fmt.Errorf("value: false does not equal expected value: true"), + expectedError: fmt.Errorf("expected value true for BoolValue check, got: false"), }, "equal": { self: knownvalue.BoolValueExact(true), diff --git a/knownvalue/float64.go b/knownvalue/float64.go index e9455554b..4514db9ff 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -22,11 +22,11 @@ func (v Float64Value) CheckValue(other any) error { otherVal, ok := other.(float64) if !ok { - return fmt.Errorf("wrong type: %T, known value type is float64", other) + return fmt.Errorf("expected float64 value for Float64Value check, got: %T", other) } if otherVal != v.value { - return fmt.Errorf("value: %v does not equal expected value: %s", strconv.FormatFloat(otherVal, 'f', -1, 64), v.String()) + return fmt.Errorf("expected value %s for Float64Value check, got: %s", v.String(), strconv.FormatFloat(otherVal, 'f', -1, 64)) } return nil diff --git a/knownvalue/float64_test.go b/knownvalue/float64_test.go index bfde22b5a..5a4d67d81 100644 --- a/knownvalue/float64_test.go +++ b/knownvalue/float64_test.go @@ -21,24 +21,24 @@ func TestFloat64Value_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is float64"), + expectedError: fmt.Errorf("expected float64 value for Float64Value check, got: "), }, "zero-other": { other: 0.0, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.Float64ValueExact(1.234), - expectedError: fmt.Errorf("wrong type: , known value type is float64"), + expectedError: fmt.Errorf("expected float64 value for Float64Value check, got: "), }, "wrong-type": { self: knownvalue.Float64ValueExact(1.234), other: int64(1234), - expectedError: fmt.Errorf("wrong type: int64, known value type is float64"), + expectedError: fmt.Errorf("expected float64 value for Float64Value check, got: int64"), }, "not-equal": { self: knownvalue.Float64ValueExact(1.234), other: 4.321, - expectedError: fmt.Errorf("value: 4.321 does not equal expected value: 1.234"), + expectedError: fmt.Errorf("expected value 1.234 for Float64Value check, got: 4.321"), }, "equal": { self: knownvalue.Float64ValueExact(1.234), diff --git a/knownvalue/int64.go b/knownvalue/int64.go index 9e2abf528..bf4f9eadf 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -22,11 +22,11 @@ func (v Int64Value) CheckValue(other any) error { otherVal, ok := other.(int64) if !ok { - return fmt.Errorf("wrong type: %T, known value type is int64", other) + return fmt.Errorf("expected int64 value for Int64Value check, got: %T", other) } if otherVal != v.value { - return fmt.Errorf("value: %d does not equal expected value: %d", otherVal, v.value) + return fmt.Errorf("expected value %d for Int64Value check, got: %d", v.value, otherVal) } return nil diff --git a/knownvalue/int64_test.go b/knownvalue/int64_test.go index 5b5d82b59..d2b0de770 100644 --- a/knownvalue/int64_test.go +++ b/knownvalue/int64_test.go @@ -21,24 +21,24 @@ func TestInt64Value_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is int64"), + expectedError: fmt.Errorf("expected int64 value for Int64Value check, got: "), }, "zero-other": { other: int64(0), // checking against the underlying value field zero-value }, "nil": { self: knownvalue.Int64ValueExact(1234), - expectedError: fmt.Errorf("wrong type: , known value type is int64"), + expectedError: fmt.Errorf("expected int64 value for Int64Value check, got: "), }, "wrong-type": { self: knownvalue.Int64ValueExact(1234), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is int64"), + expectedError: fmt.Errorf("expected int64 value for Int64Value check, got: float64"), }, "not-equal": { self: knownvalue.Int64ValueExact(1234), other: int64(4321), - expectedError: fmt.Errorf("value: 4321 does not equal expected value: 1234"), + expectedError: fmt.Errorf("expected value 1234 for Int64Value check, got: 4321"), }, "equal": { self: knownvalue.Int64ValueExact(1234), diff --git a/knownvalue/list.go b/knownvalue/list.go index 24b25d828..a39a0504e 100644 --- a/knownvalue/list.go +++ b/knownvalue/list.go @@ -21,16 +21,27 @@ func (v ListValue) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is []Check", other) + return fmt.Errorf("expected []any value for ListValue check, got: %T", other) } if len(otherVal) != len(v.value) { - return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) + expectedElements := "elements" + actualElements := "elements" + + if len(v.value) == 1 { + expectedElements = "element" + } + + if len(otherVal) == 1 { + actualElements = "element" + } + + return fmt.Errorf("expected %d %s for ListValue check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) } for i := 0; i < len(v.value); i++ { if err := v.value[i].CheckValue(otherVal[i]); err != nil { - return err + return fmt.Errorf("list element index %d: %s", i, err) } } diff --git a/knownvalue/list_elements.go b/knownvalue/list_elements.go index 2295d5912..ffb4b1eea 100644 --- a/knownvalue/list_elements.go +++ b/knownvalue/list_elements.go @@ -19,14 +19,25 @@ type ListElements struct { // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. func (v ListElements) CheckValue(other any) error { - val, ok := other.([]any) + otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("wrong type: %T, expected []any", other) + return fmt.Errorf("expected []any value for ListElements check, got: %T", other) } - if len(val) != v.num { - return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + if len(otherVal) != v.num { + expectedElements := "elements" + actualElements := "elements" + + if v.num == 1 { + expectedElements = "element" + } + + if len(otherVal) == 1 { + actualElements = "element" + } + + return fmt.Errorf("expected %d %s for ListElements check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) } return nil diff --git a/knownvalue/list_elements_test.go b/knownvalue/list_elements_test.go index f057ccf8f..242b13f61 100644 --- a/knownvalue/list_elements_test.go +++ b/knownvalue/list_elements_test.go @@ -21,24 +21,24 @@ func TestListElements_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , expected []any"), + expectedError: fmt.Errorf("expected []any value for ListElements check, got: "), }, "zero-other": { other: []any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.ListElementsExact(3), - expectedError: fmt.Errorf("wrong type: , expected []any"), + expectedError: fmt.Errorf("expected []any value for ListElements check, got: "), }, "wrong-type": { self: knownvalue.ListElementsExact(3), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, expected []any"), + expectedError: fmt.Errorf("expected []any value for ListElements check, got: float64"), }, "empty": { self: knownvalue.ListElementsExact(3), other: []any{}, - expectedError: fmt.Errorf("wrong length: 0, expected 3"), + expectedError: fmt.Errorf("expected 3 elements for ListElements check, got 0 elements"), }, "wrong-length": { self: knownvalue.ListElementsExact(3), @@ -46,7 +46,7 @@ func TestListElements_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("wrong length: 2, expected 3"), + expectedError: fmt.Errorf("expected 3 elements for ListElements check, got 2 elements"), }, "equal": { self: knownvalue.ListElementsExact(3), diff --git a/knownvalue/list_partial.go b/knownvalue/list_partial.go index 767c50d6b..9ac85fc5a 100644 --- a/knownvalue/list_partial.go +++ b/knownvalue/list_partial.go @@ -24,7 +24,7 @@ func (v ListValuePartial) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is map[int]Check", other) + return fmt.Errorf("expected []any value for ListValuePartial check, got: %T", other) } var keys []int @@ -39,11 +39,11 @@ func (v ListValuePartial) CheckValue(other any) error { for _, k := range keys { if len(otherVal) <= k { - return fmt.Errorf("index out of bounds: %d", k) + return fmt.Errorf("missing element index %d for ListValuePartial check", k) } if err := v.value[k].CheckValue(otherVal[k]); err != nil { - return err + return fmt.Errorf("list element %d: %s", k, err) } } diff --git a/knownvalue/list_partial_test.go b/knownvalue/list_partial_test.go index 0e6551a96..1585c4f03 100644 --- a/knownvalue/list_partial_test.go +++ b/knownvalue/list_partial_test.go @@ -21,7 +21,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is map[int]Check"), + expectedError: fmt.Errorf("expected []any value for ListValuePartial check, got: "), }, "zero-other": { other: []any{}, // checking against the underlying value field zero-value @@ -32,7 +32,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("wrong type: , known value type is map[int]Check"), + expectedError: fmt.Errorf("expected []any value for ListValuePartial check, got: "), }, "wrong-type": { self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ @@ -41,7 +41,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { 3: knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is map[int]Check"), + expectedError: fmt.Errorf("expected []any value for ListValuePartial check, got: float64"), }, "empty": { self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ @@ -50,7 +50,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { 3: knownvalue.Float64ValueExact(7.89), }), other: []any{}, - expectedError: fmt.Errorf("index out of bounds: 0"), + expectedError: fmt.Errorf("missing element index 0 for ListValuePartial check"), }, "wrong-length": { self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ @@ -59,7 +59,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { 3: knownvalue.Float64ValueExact(7.89), }), other: []any{1.23, 4.56}, - expectedError: fmt.Errorf("index out of bounds: 2"), + expectedError: fmt.Errorf("missing element index 2 for ListValuePartial check"), }, "not-equal": { self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ @@ -68,7 +68,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { 3: knownvalue.Float64ValueExact(7.89), }), other: []any{1.23, 4.56, 6.54, 5.46}, - expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 4.56"), + expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64Value check, got: 6.54"), }, "wrong-order": { self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ @@ -77,7 +77,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { 3: knownvalue.Float64ValueExact(7.89), }), other: []any{1.23, 0.00, 7.89, 4.56}, - expectedError: fmt.Errorf("value: 7.89 does not equal expected value: 4.56"), + expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64Value check, got: 7.89"), }, "equal": { self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ diff --git a/knownvalue/list_test.go b/knownvalue/list_test.go index 8a4760801..cd964f84c 100644 --- a/knownvalue/list_test.go +++ b/knownvalue/list_test.go @@ -21,7 +21,7 @@ func TestListValue_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for ListValue check, got: "), }, "zero-other": { other: []any{}, // checking against the underlying value field zero-value @@ -32,7 +32,7 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(456), knownvalue.Int64ValueExact(789), }), - expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for ListValue check, got: "), }, "wrong-type": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -41,7 +41,7 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for ListValue check, got: float64"), }, "empty": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -50,7 +50,7 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{}, - expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), + expectedError: fmt.Errorf("expected 3 elements for ListValue check, got 0 elements"), }, "wrong-length": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -62,7 +62,7 @@ func TestListValue_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), + expectedError: fmt.Errorf("expected 3 elements for ListValue check, got 2 elements"), }, "not-equal": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -75,7 +75,7 @@ func TestListValue_CheckValue(t *testing.T) { int64(456), int64(654), }, - expectedError: fmt.Errorf("value: 654 does not equal expected value: 789"), + expectedError: fmt.Errorf("list element index 2: expected value 789 for Int64Value check, got: 654"), }, "wrong-order": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -88,7 +88,7 @@ func TestListValue_CheckValue(t *testing.T) { int64(789), int64(456), }, - expectedError: fmt.Errorf("value: 789 does not equal expected value: 456"), + expectedError: fmt.Errorf("list element index 1: expected value 456 for Int64Value check, got: 789"), }, "equal": { self: knownvalue.ListValueExact([]knownvalue.Check{ diff --git a/knownvalue/map.go b/knownvalue/map.go index 192e70dcc..f2e171d44 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -22,11 +22,22 @@ func (v MapValue) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) + return fmt.Errorf("expected map[string]any value for MapValue check, got: %T", other) } if len(otherVal) != len(v.value) { - return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) + expectedElements := "elements" + actualElements := "elements" + + if len(v.value) == 1 { + expectedElements = "element" + } + + if len(otherVal) == 1 { + actualElements = "element" + } + + return fmt.Errorf("expected %d %s for MapValue check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) } var keys []string @@ -43,11 +54,11 @@ func (v MapValue) CheckValue(other any) error { otherValItem, ok := otherVal[k] if !ok { - return fmt.Errorf("missing key: %s", k) + return fmt.Errorf("missing element %s for MapValue check", k) } if err := v.value[k].CheckValue(otherValItem); err != nil { - return err + return fmt.Errorf("%s map element: %s", k, err) } } diff --git a/knownvalue/map_elements.go b/knownvalue/map_elements.go index bc7547afc..79b617206 100644 --- a/knownvalue/map_elements.go +++ b/knownvalue/map_elements.go @@ -19,14 +19,25 @@ type MapElements struct { // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. func (v MapElements) CheckValue(other any) error { - val, ok := other.(map[string]any) + otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("wrong type: %T, expected map[string]any", other) + return fmt.Errorf("expected map[string]any value for MapElements check, got: %T", other) } - if len(val) != v.num { - return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + if len(otherVal) != v.num { + expectedElements := "elements" + actualElements := "elements" + + if v.num == 1 { + expectedElements = "element" + } + + if len(otherVal) == 1 { + actualElements = "element" + } + + return fmt.Errorf("expected %d %s for MapElements check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) } return nil diff --git a/knownvalue/map_elements_test.go b/knownvalue/map_elements_test.go index 79f3804bd..82297f623 100644 --- a/knownvalue/map_elements_test.go +++ b/knownvalue/map_elements_test.go @@ -21,24 +21,24 @@ func TestMapElements_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + expectedError: fmt.Errorf("expected map[string]any value for MapElements check, got: "), }, "zero-other": { other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.MapElementsExact(3), - expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + expectedError: fmt.Errorf("expected map[string]any value for MapElements check, got: "), }, "wrong-type": { self: knownvalue.MapElementsExact(3), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, expected map[string]any"), + expectedError: fmt.Errorf("expected map[string]any value for MapElements check, got: float64"), }, "empty": { self: knownvalue.MapElementsExact(3), other: map[string]any{}, - expectedError: fmt.Errorf("wrong length: 0, expected 3"), + expectedError: fmt.Errorf("expected 3 elements for MapElements check, got 0 elements"), }, "wrong-length": { self: knownvalue.MapElementsExact(3), @@ -46,7 +46,7 @@ func TestMapElements_CheckValue(t *testing.T) { "one": int64(123), "two": int64(456), }, - expectedError: fmt.Errorf("wrong length: 2, expected 3"), + expectedError: fmt.Errorf("expected 3 elements for MapElements check, got 2 elements"), }, "equal": { self: knownvalue.MapElementsExact(3), diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index bd55b19c8..ce044712b 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -22,7 +22,7 @@ func (v MapValuePartial) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) + return fmt.Errorf("expected map[string]any value for MapValuePartial check, got: %T", other) } var keys []string @@ -39,11 +39,11 @@ func (v MapValuePartial) CheckValue(other any) error { otherValItem, ok := otherVal[k] if !ok { - return fmt.Errorf("missing key: %s", k) + return fmt.Errorf("missing element %s for MapValuePartial check", k) } if err := v.value[k].CheckValue(otherValItem); err != nil { - return err + return fmt.Errorf("%s map element: %s", k, err) } } diff --git a/knownvalue/map_partial_test.go b/knownvalue/map_partial_test.go index ffb6c2e21..745b0e362 100644 --- a/knownvalue/map_partial_test.go +++ b/knownvalue/map_partial_test.go @@ -21,7 +21,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for MapValuePartial check, got: "), }, "zero-other": { other: map[string]any{}, // checking against the underlying value field zero-value @@ -31,7 +31,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for MapValuePartial check, got: "), }, "wrong-type": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ @@ -39,7 +39,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for MapValuePartial check, got: float64"), }, "empty": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ @@ -47,7 +47,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{}, - expectedError: fmt.Errorf("missing key: one"), + expectedError: fmt.Errorf("missing element one for MapValuePartial check"), }, "wrong-length": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ @@ -58,7 +58,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "one": 1.23, "two": 4.56, }, - expectedError: fmt.Errorf("missing key: three"), + expectedError: fmt.Errorf("missing element three for MapValuePartial check"), }, "not-equal": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ @@ -70,7 +70,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "two": 4.56, "three": 6.54, }, - expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 6.54"), }, "wrong-order": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ @@ -82,7 +82,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "two": 7.89, "three": 4.56, }, - expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 4.56"), }, "key-not-found": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ @@ -95,7 +95,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "five": 7.89, "six": 4.56, }, - expectedError: fmt.Errorf("missing key: one"), + expectedError: fmt.Errorf("missing element one for MapValuePartial check"), }, "equal": { self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ diff --git a/knownvalue/map_test.go b/knownvalue/map_test.go index c6ba1c65e..056351f92 100644 --- a/knownvalue/map_test.go +++ b/knownvalue/map_test.go @@ -21,7 +21,7 @@ func TestMapValue_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for MapValue check, got: "), }, "zero-other": { other: map[string]any{}, // checking against the underlying value field zero-value @@ -32,7 +32,7 @@ func TestMapValue_CheckValue(t *testing.T) { "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for MapValue check, got: "), }, "wrong-type": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -41,7 +41,7 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for MapValue check, got: float64"), }, "empty": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -50,7 +50,7 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{}, - expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), + expectedError: fmt.Errorf("expected 3 elements for MapValue check, got 0 elements"), }, "wrong-length": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -62,7 +62,7 @@ func TestMapValue_CheckValue(t *testing.T) { "one": 1.23, "two": 4.56, }, - expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), + expectedError: fmt.Errorf("expected 3 elements for MapValue check, got 2 elements"), }, "not-equal": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -75,7 +75,7 @@ func TestMapValue_CheckValue(t *testing.T) { "two": 4.56, "three": 6.54, }, - expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 6.54"), }, "wrong-order": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -88,7 +88,7 @@ func TestMapValue_CheckValue(t *testing.T) { "two": 7.89, "three": 4.56, }, - expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 4.56"), }, "key-not-found": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -101,7 +101,7 @@ func TestMapValue_CheckValue(t *testing.T) { "five": 7.89, "six": 4.56, }, - expectedError: fmt.Errorf("missing key: one"), + expectedError: fmt.Errorf("missing element one for MapValue check"), }, "equal": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ diff --git a/knownvalue/number.go b/knownvalue/number.go index a0ee720f8..d1601eaf2 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -26,11 +26,11 @@ func (v NumberValue) CheckValue(other any) error { otherVal, ok := other.(*big.Float) if !ok { - return fmt.Errorf("wrong type: %T, known value type is *big.Float", other) + return fmt.Errorf("expected *big.Float value for NumberValue check, got: %T", other) } if v.value.Cmp(otherVal) != 0 { - return fmt.Errorf("value: %s does not equal expected value: %s", otherVal.Text('f', -1), v.String()) + return fmt.Errorf("expected value %s for NumberValue check, got: %s", v.String(), otherVal.Text('f', -1)) } return nil diff --git a/knownvalue/number_test.go b/knownvalue/number_test.go index 9aa30a101..bc1793187 100644 --- a/knownvalue/number_test.go +++ b/knownvalue/number_test.go @@ -42,17 +42,17 @@ func TestNumberValue_Equal(t *testing.T) { }, "nil": { self: knownvalue.NumberValueExact(bigFloat), - expectedError: fmt.Errorf("wrong type: , known value type is *big.Float"), + expectedError: fmt.Errorf("expected *big.Float value for NumberValue check, got: "), }, "wrong-type": { self: knownvalue.NumberValueExact(bigFloat), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is *big.Float"), + expectedError: fmt.Errorf("expected *big.Float value for NumberValue check, got: float64"), }, "not-equal": { self: knownvalue.NumberValueExact(bigFloat), other: otherBigFloat, - expectedError: fmt.Errorf("value: 1.797693134862315797693134862315797693134862314 does not equal expected value: 1.797693134862315797693134862315797693134862315"), + expectedError: fmt.Errorf("expected value 1.797693134862315797693134862315797693134862315 for NumberValue check, got: 1.797693134862315797693134862315797693134862314"), }, "equal": { self: knownvalue.NumberValueExact(bigFloat), diff --git a/knownvalue/object.go b/knownvalue/object.go index 8a2c3c78c..0221ee5e2 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -22,11 +22,22 @@ func (v ObjectValue) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) + return fmt.Errorf("expected map[string]any value for ObjectValue check, got: %T", other) } if len(otherVal) != len(v.value) { - return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) + expectedAttributes := "attributes" + actualAttributes := "attributes" + + if len(v.value) == 1 { + expectedAttributes = "attribute" + } + + if len(otherVal) == 1 { + actualAttributes = "attribute" + } + + return fmt.Errorf("expected %d %s for ObjectValue check, got %d %s", len(v.value), expectedAttributes, len(otherVal), actualAttributes) } var keys []string @@ -43,11 +54,11 @@ func (v ObjectValue) CheckValue(other any) error { otherValItem, ok := otherVal[k] if !ok { - return fmt.Errorf("missing key: %s", k) + return fmt.Errorf("missing attribute %s for ObjectValue check", k) } if err := v.value[k].CheckValue(otherValItem); err != nil { - return err + return fmt.Errorf("%s object attribute: %s", k, err) } } diff --git a/knownvalue/object_attributes.go b/knownvalue/object_attributes.go index 575bd9f4c..80de51aa5 100644 --- a/knownvalue/object_attributes.go +++ b/knownvalue/object_attributes.go @@ -19,14 +19,25 @@ type ObjectAttributes struct { // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. func (v ObjectAttributes) CheckValue(other any) error { - val, ok := other.(map[string]any) + otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("wrong type: %T, expected map[string]any", other) + return fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: %T", other) } - if len(val) != v.num { - return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + if len(otherVal) != v.num { + expectedAttributes := "attributes" + actualAttributes := "attributes" + + if v.num == 1 { + expectedAttributes = "attribute" + } + + if len(otherVal) == 1 { + actualAttributes = "attribute" + } + + return fmt.Errorf("expected %d %s for ObjectAttributes check, got %d %s", v.num, expectedAttributes, len(otherVal), actualAttributes) } return nil diff --git a/knownvalue/object_attributes_test.go b/knownvalue/object_attributes_test.go index bea0fb1c9..7de835c51 100644 --- a/knownvalue/object_attributes_test.go +++ b/knownvalue/object_attributes_test.go @@ -21,24 +21,24 @@ func TestObjectAttributes_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: "), }, "zero-other": { other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.ObjectAttributesExact(3), - expectedError: fmt.Errorf("wrong type: , expected map[string]any"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: "), }, "wrong-type": { self: knownvalue.ObjectAttributesExact(3), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, expected map[string]any"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: float64"), }, "empty": { self: knownvalue.ObjectAttributesExact(3), other: map[string]any{}, - expectedError: fmt.Errorf("wrong length: 0, expected 3"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributes check, got 0 attributes"), }, "wrong-length": { self: knownvalue.ObjectAttributesExact(3), @@ -46,7 +46,7 @@ func TestObjectAttributes_CheckValue(t *testing.T) { "one": int64(123), "two": int64(456), }, - expectedError: fmt.Errorf("wrong length: 2, expected 3"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributes check, got 2 attributes"), }, "equal": { self: knownvalue.ObjectAttributesExact(3), diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index a84bbedff..4edf51d2a 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -22,7 +22,7 @@ func (v ObjectValuePartial) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is map[string]Check", other) + return fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: %T", other) } var keys []string @@ -39,11 +39,11 @@ func (v ObjectValuePartial) CheckValue(other any) error { otherValItem, ok := otherVal[k] if !ok { - return fmt.Errorf("missing key: %s", k) + return fmt.Errorf("missing attribute %s for ObjectValuePartial check", k) } if err := v.value[k].CheckValue(otherValItem); err != nil { - return err + return fmt.Errorf("%s object attribute: %s", k, err) } } diff --git a/knownvalue/object_partial_test.go b/knownvalue/object_partial_test.go index 3d249cf0f..3bf6d9208 100644 --- a/knownvalue/object_partial_test.go +++ b/knownvalue/object_partial_test.go @@ -21,7 +21,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: "), }, "zero-other": { other: map[string]any{}, // checking against the underlying value field zero-value @@ -31,7 +31,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: "), }, "wrong-type": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ @@ -39,7 +39,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: float64"), }, "empty": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ @@ -47,7 +47,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{}, - expectedError: fmt.Errorf("missing key: one"), + expectedError: fmt.Errorf("missing attribute one for ObjectValuePartial check"), }, "wrong-length": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ @@ -58,7 +58,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "one": 1.23, "two": 4.56, }, - expectedError: fmt.Errorf("missing key: three"), + expectedError: fmt.Errorf("missing attribute three for ObjectValuePartial check"), }, "not-equal": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ @@ -70,7 +70,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "two": 4.56, "three": 6.54, }, - expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 6.54"), }, "wrong-order": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ @@ -82,7 +82,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "two": 7.89, "three": 4.56, }, - expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 4.56"), }, "key-not-found": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ @@ -95,7 +95,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "five": 7.89, "six": 4.56, }, - expectedError: fmt.Errorf("missing key: one"), + expectedError: fmt.Errorf("missing attribute one for ObjectValuePartial check"), }, "equal": { self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ diff --git a/knownvalue/object_test.go b/knownvalue/object_test.go index 9fd6f9d77..0e3224bb1 100644 --- a/knownvalue/object_test.go +++ b/knownvalue/object_test.go @@ -21,7 +21,7 @@ func TestObjectValue_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValue check, got: "), }, "zero-other": { other: map[string]any{}, // checking against the underlying value field zero-value @@ -32,7 +32,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("wrong type: , known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValue check, got: "), }, "wrong-type": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -41,7 +41,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is map[string]Check"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValue check, got: float64"), }, "empty": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -50,7 +50,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{}, - expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectValue check, got 0 attributes"), }, "wrong-length": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -62,7 +62,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "one": 1.23, "two": 4.56, }, - expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectValue check, got 2 attributes"), }, "not-equal": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -75,7 +75,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "two": 4.56, "three": 6.54, }, - expectedError: fmt.Errorf("value: 6.54 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 6.54"), }, "wrong-order": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -88,7 +88,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "two": 7.89, "three": 4.56, }, - expectedError: fmt.Errorf("value: 4.56 does not equal expected value: 7.89"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 4.56"), }, "key-not-found": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -101,7 +101,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "five": 7.89, "six": 4.56, }, - expectedError: fmt.Errorf("missing key: one"), + expectedError: fmt.Errorf("missing attribute one for ObjectValue check"), }, "equal": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ diff --git a/knownvalue/set.go b/knownvalue/set.go index 7399e1d14..c80bbd8c4 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -21,11 +21,22 @@ func (v SetValue) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is []Check", other) + return fmt.Errorf("expected []any value for SetValue check, got: %T", other) } if len(otherVal) != len(v.value) { - return fmt.Errorf("wrong length: %d, known value length is %d", len(otherVal), len(v.value)) + expectedElements := "elements" + actualElements := "elements" + + if len(v.value) == 1 { + expectedElements = "element" + } + + if len(otherVal) == 1 { + actualElements = "element" + } + + return fmt.Errorf("expected %d %s for SetValue check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) } otherValCopy := make([]any, len(otherVal)) @@ -33,7 +44,7 @@ func (v SetValue) CheckValue(other any) error { copy(otherValCopy, otherVal) for i := 0; i < len(v.value); i++ { - err := fmt.Errorf("expected value not found: %s", v.value[i].String()) + err := fmt.Errorf("missing value %s for SetValue check", v.value[i].String()) for j := 0; j < len(otherValCopy); j++ { checkValueErr := v.value[i].CheckValue(otherValCopy[j]) diff --git a/knownvalue/set_elements.go b/knownvalue/set_elements.go index d01fa8445..25312b163 100644 --- a/knownvalue/set_elements.go +++ b/knownvalue/set_elements.go @@ -19,14 +19,25 @@ type SetElements struct { // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. func (v SetElements) CheckValue(other any) error { - val, ok := other.([]any) + otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("wrong type: %T, expected []any", other) + return fmt.Errorf("expected []any value for SetElements check, got: %T", other) } - if len(val) != v.num { - return fmt.Errorf("wrong length: %d, expected %d", len(val), v.num) + if len(otherVal) != v.num { + expectedElements := "elements" + actualElements := "elements" + + if v.num == 1 { + expectedElements = "element" + } + + if len(otherVal) == 1 { + actualElements = "element" + } + + return fmt.Errorf("expected %d %s for SetElements check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) } return nil diff --git a/knownvalue/set_elements_test.go b/knownvalue/set_elements_test.go index e38d58956..522287dc3 100644 --- a/knownvalue/set_elements_test.go +++ b/knownvalue/set_elements_test.go @@ -21,24 +21,24 @@ func TestSetElements_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , expected []any"), + expectedError: fmt.Errorf("expected []any value for SetElements check, got: "), }, "zero-other": { other: []any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.SetElementsExact(3), - expectedError: fmt.Errorf("wrong type: , expected []any"), + expectedError: fmt.Errorf("expected []any value for SetElements check, got: "), }, "wrong-type": { self: knownvalue.SetElementsExact(3), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, expected []any"), + expectedError: fmt.Errorf("expected []any value for SetElements check, got: float64"), }, "empty": { self: knownvalue.SetElementsExact(3), other: []any{}, - expectedError: fmt.Errorf("wrong length: 0, expected 3"), + expectedError: fmt.Errorf("expected 3 elements for SetElements check, got 0 elements"), }, "wrong-length": { self: knownvalue.SetElementsExact(3), @@ -46,7 +46,7 @@ func TestSetElements_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("wrong length: 2, expected 3"), + expectedError: fmt.Errorf("expected 3 elements for SetElements check, got 2 elements"), }, "equal": { self: knownvalue.SetElementsExact(3), diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index b9e4b204b..ea12ed215 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -21,7 +21,7 @@ func (v SetValuePartial) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("wrong type: %T, known value type is []Check", other) + return fmt.Errorf("expected []any value for SetValuePartial check, got: %T", other) } otherValCopy := make([]any, len(otherVal)) @@ -29,7 +29,7 @@ func (v SetValuePartial) CheckValue(other any) error { copy(otherValCopy, otherVal) for i := 0; i < len(v.value); i++ { - err := fmt.Errorf("expected value not found: %s", v.value[i].String()) + err := fmt.Errorf("missing value %s for SetValuePartial check", v.value[i].String()) for j := 0; j < len(otherValCopy); j++ { checkValueErr := v.value[i].CheckValue(otherValCopy[j]) diff --git a/knownvalue/set_partial_test.go b/knownvalue/set_partial_test.go index 789e892ed..2d29b3019 100644 --- a/knownvalue/set_partial_test.go +++ b/knownvalue/set_partial_test.go @@ -21,7 +21,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for SetValuePartial check, got: "), }, "zero-other": { other: []any{}, // checking against the underlying value field zero-value @@ -32,7 +32,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for SetValuePartial check, got: "), }, "wrong-type": { self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ @@ -41,7 +41,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for SetValuePartial check, got: float64"), }, "equal-empty": { self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ @@ -50,7 +50,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(7.89), }), other: []any{}, - expectedError: fmt.Errorf("expected value not found: 1.23"), + expectedError: fmt.Errorf("missing value 1.23 for SetValuePartial check"), }, "not-equal": { self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ @@ -59,7 +59,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(7.89), }), other: []any{1.23, 4.56, 6.54, 5.46}, - expectedError: fmt.Errorf("expected value not found: 7.89"), + expectedError: fmt.Errorf("missing value 7.89 for SetValuePartial check"), }, "equal-different-order": { self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ diff --git a/knownvalue/set_test.go b/knownvalue/set_test.go index 6b46da69d..4df59505c 100644 --- a/knownvalue/set_test.go +++ b/knownvalue/set_test.go @@ -21,7 +21,7 @@ func TestSetValue_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for SetValue check, got: "), }, "zero-other": { other: []any{}, // checking against the underlying value field zero-value @@ -32,7 +32,7 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(456), knownvalue.Int64ValueExact(789), }), - expectedError: fmt.Errorf("wrong type: , known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for SetValue check, got: "), }, "wrong-type": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -41,7 +41,7 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is []Check"), + expectedError: fmt.Errorf("expected []any value for SetValue check, got: float64"), }, "empty": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -50,7 +50,7 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{}, - expectedError: fmt.Errorf("wrong length: 0, known value length is 3"), + expectedError: fmt.Errorf("expected 3 elements for SetValue check, got 0 elements"), }, "wrong-length": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -62,7 +62,7 @@ func TestSetValue_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("wrong length: 2, known value length is 3"), + expectedError: fmt.Errorf("expected 3 elements for SetValue check, got 2 elements"), }, "not-equal": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -75,7 +75,7 @@ func TestSetValue_CheckValue(t *testing.T) { int64(456), int64(654), }, - expectedError: fmt.Errorf("expected value not found: 789"), + expectedError: fmt.Errorf("missing value 789 for SetValue check"), }, "equal-different-order": { self: knownvalue.SetValueExact([]knownvalue.Check{ diff --git a/knownvalue/string.go b/knownvalue/string.go index 59609cde7..6b98ba0c5 100644 --- a/knownvalue/string.go +++ b/knownvalue/string.go @@ -19,11 +19,11 @@ func (v StringValue) CheckValue(other any) error { otherVal, ok := other.(string) if !ok { - return fmt.Errorf("wrong type: %T, known value type is string", other) + return fmt.Errorf("expected string value for StringValue check, got: %T", other) } if otherVal != v.value { - return fmt.Errorf("value: %s does not equal expected value: %s", otherVal, v.value) + return fmt.Errorf("expected value %s for StringValue check, got: %s", v.value, otherVal) } return nil diff --git a/knownvalue/string_test.go b/knownvalue/string_test.go index 3576d2ee3..a08a53ee6 100644 --- a/knownvalue/string_test.go +++ b/knownvalue/string_test.go @@ -21,24 +21,24 @@ func TestStringValue_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("wrong type: , known value type is string"), + expectedError: fmt.Errorf("expected string value for StringValue check, got: "), }, "zero-other": { other: "", // checking against the underlying value field zero-value }, "nil": { self: knownvalue.StringValueExact("str"), - expectedError: fmt.Errorf("wrong type: , known value type is string"), + expectedError: fmt.Errorf("expected string value for StringValue check, got: "), }, "wrong-type": { self: knownvalue.StringValueExact("str"), other: 1.234, - expectedError: fmt.Errorf("wrong type: float64, known value type is string"), + expectedError: fmt.Errorf("expected string value for StringValue check, got: float64"), }, "not-equal": { self: knownvalue.StringValueExact("str"), other: "rts", - expectedError: fmt.Errorf("value: rts does not equal expected value: str"), + expectedError: fmt.Errorf("expected value str for StringValue check, got: rts"), }, "equal": { self: knownvalue.StringValueExact("str"), From 41eb4debb4d274d0af00106fcdfbf68249281600 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Jan 2024 15:40:12 +0000 Subject: [PATCH 14/48] Updating tests for ExpectKnownValue, ExpectKnownOutputValue and ExpectKnownOutputValueAtPaath (#243) --- .../expect_known_output_value_at_path_test.go | 26 +++++++++---------- plancheck/expect_known_output_value_test.go | 26 +++++++++---------- plancheck/expect_known_value_test.go | 26 +++++++++---------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index 2cb8cc07a..fcd83b14d 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -217,7 +217,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile("value: true does not equal expected value: false"), + ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), }, }, }) @@ -340,7 +340,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t * ), }, }, - ExpectError: regexp.MustCompile("value: 1.23 does not equal expected value: 3.21"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), }, }, }) @@ -421,7 +421,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *te ), }, }, - ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), }, }, }) @@ -558,7 +558,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), }, }, }) @@ -651,7 +651,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue ), }, }, - ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), }, }, }) @@ -738,7 +738,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *test ), }, }, - ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), }, }, }) @@ -1021,7 +1021,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *test ), }, }, - ExpectError: regexp.MustCompile(`missing key: key3`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), }, }, }) @@ -1112,7 +1112,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( ), }, }, - ExpectError: regexp.MustCompile(`missing key: key3`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), }, }, }) @@ -1199,7 +1199,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testi ), }, }, - ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), }, }, }) @@ -1292,7 +1292,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Number_KnownValueWrongValue(t *t ), }, }, - ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), }, }, }) @@ -1385,7 +1385,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *test ), }, }, - ExpectError: regexp.MustCompile(`expected value not found: value3`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), }, }, }) @@ -1476,7 +1476,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( ), }, }, - ExpectError: regexp.MustCompile(`expected value not found: value3`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), }, }, }) @@ -1784,7 +1784,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *t knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("value: str does not equal expected value: rts"), + ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), }, }, }) diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 2c5f2ae9c..489c2a570 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -174,7 +174,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile("value: true does not equal expected value: false"), + ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), }, }, }) @@ -273,7 +273,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongValue(t *testin ), }, }, - ExpectError: regexp.MustCompile("value: 1.23 does not equal expected value: 3.21"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), }, }, }) @@ -338,7 +338,7 @@ func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing. ), }, }, - ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), }, }, }) @@ -451,7 +451,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), }, }, }) @@ -528,7 +528,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *te ), }, }, - ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), }, }, }) @@ -599,7 +599,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), }, }, }) @@ -834,7 +834,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`missing key: key3`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), }, }, }) @@ -909,7 +909,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`missing key: key3`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), }, }, }) @@ -980,7 +980,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), }, }, }) @@ -1057,7 +1057,7 @@ func TestExpectKnownOutputValue_CheckPlan_Number_KnownValueWrongValue(t *testing ), }, }, - ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), }, }, }) @@ -1134,7 +1134,7 @@ func TestExpectKnownOutputValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected value not found: value3`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), }, }, }) @@ -1209,7 +1209,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`expected value not found: value3`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), }, }, }) @@ -1461,7 +1461,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongValue(t *testing knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("value: str does not equal expected value: rts"), + ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), }, }, }) diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index afafe20b8..1d9c86741 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -160,7 +160,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("value: true does not equal expected value: false"), + ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), }, }, }) @@ -250,7 +250,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("value: 1.23 does not equal expected value: 3.21"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), }, }, }) @@ -309,7 +309,7 @@ func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), }, }, }) @@ -413,7 +413,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), }, }, }) @@ -484,7 +484,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing. ), }, }, - ExpectError: regexp.MustCompile(`value: value1 does not equal expected value: value3`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), }, }, }) @@ -549,7 +549,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), }, }, }) @@ -766,7 +766,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`missing key: key3`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), }, }, }) @@ -835,7 +835,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`missing key: key3`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), }, }, }) @@ -900,7 +900,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong length: 2, expected 3"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), }, }, }) @@ -971,7 +971,7 @@ func TestExpectKnownValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("value: 123 does not equal expected value: 321"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), }, }, }) @@ -1042,7 +1042,7 @@ func TestExpectKnownValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected value not found: value3`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), }, }, }) @@ -1111,7 +1111,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`expected value not found: value3`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), }, }, }) @@ -1342,7 +1342,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("value: str does not equal expected value: rts"), + ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), }, }, }) From 94bdfa705b15bb5fe000ed5b1a5c91dcea32779e Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 08:39:36 +0000 Subject: [PATCH 15/48] Adding changelog entry to note the switch to using json.Number for numerical value representation in the plan (#243) --- .changes/unreleased/NOTES-20240104-083841.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/unreleased/NOTES-20240104-083841.yaml diff --git a/.changes/unreleased/NOTES-20240104-083841.yaml b/.changes/unreleased/NOTES-20240104-083841.yaml new file mode 100644 index 000000000..e281b21b6 --- /dev/null +++ b/.changes/unreleased/NOTES-20240104-083841.yaml @@ -0,0 +1,6 @@ +kind: NOTES +body: Numerical values in the plan are now represented as json.Number, not float64. + Custom plan checks relying upon float64 representation may need altering +time: 2024-01-04T08:38:41.645745Z +custom: + Issue: "248" From f09f7e931fc128d1a7e9e871a47eccc446dc7274 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 08:42:32 +0000 Subject: [PATCH 16/48] Remove reference to state checks (#243) --- website/docs/plugin/testing/acceptance-tests/known-values.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/plugin/testing/acceptance-tests/known-values.mdx b/website/docs/plugin/testing/acceptance-tests/known-values.mdx index 7e175cbbd..87966a3f6 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-values.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-values.mdx @@ -7,7 +7,7 @@ description: >- # Known Values -Specify types, and values for use with plan checks and state checks. +Specify types, and values for use with plan checks. ## Usage From 7c5c177aa008a1872d5855a525bc975c4262bd8c Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 08:48:45 +0000 Subject: [PATCH 17/48] Moving concepts under title and removing reference to Framework types (#243) --- .../docs/plugin/testing/acceptance-tests/known-values.mdx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/website/docs/plugin/testing/acceptance-tests/known-values.mdx b/website/docs/plugin/testing/acceptance-tests/known-values.mdx index 87966a3f6..6fbca13c6 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-values.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-values.mdx @@ -7,7 +7,7 @@ description: >- # Known Values -Specify types, and values for use with plan checks. +Known Values are for use in conjunction with [Plan Checks](/terraform/plugin/testing/acceptance-tests/plan-checks), which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan, or Terraform state. ## Usage @@ -15,10 +15,6 @@ Example uses in the testing module include: - The [`ExpectknownValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/resource), [`ExpectKnownOutputValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output) and [`ExpectKnownOutputValueAtPath()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output) [built-in plan checks](/terraform/plugin/testing/acceptance-tests/plan-checks) use known values for asserting whether a specific resource attribute, or output value has a particular type, and value. -## Concepts - -Known Values are for use in conjunction with plan checks and state checks, both of which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan, or Terraform state. The known value types that are defined (e.g., `BoolValue`), have been named to match the types defined within [Terraform Plugin Framework](https://developer.hashicorp.com/terraform/plugin/framework/handling-data/types). - ## Using a Known Value The known value types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known values are instantiated by calling the `New` constructor function. From 16388088fc5a6916ae635c8949d09948fb58b8c0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 09:23:13 +0000 Subject: [PATCH 18/48] Updating Go doc comments to clarify usage of partial equality and remove references to KnownValue interface (#243) --- knownvalue/bool.go | 2 +- knownvalue/float64.go | 2 +- knownvalue/int64.go | 2 +- knownvalue/list.go | 5 +++-- knownvalue/list_partial.go | 14 ++++++++------ knownvalue/map.go | 4 ++-- knownvalue/map_partial.go | 9 ++++++--- knownvalue/number.go | 2 +- knownvalue/object.go | 7 ++++--- knownvalue/object_partial.go | 9 ++++++--- knownvalue/set.go | 3 ++- knownvalue/set_partial.go | 11 +++++++---- knownvalue/string.go | 2 +- 13 files changed, 43 insertions(+), 29 deletions(-) diff --git a/knownvalue/bool.go b/knownvalue/bool.go index 12006a7f1..f0e3a1f7b 100644 --- a/knownvalue/bool.go +++ b/knownvalue/bool.go @@ -10,7 +10,7 @@ import ( var _ Check = BoolValue{} -// BoolValue is a KnownValue for asserting equality between the value supplied +// BoolValue is a Check for asserting equality between the value supplied // to BoolValueExact and the value passed to the CheckValue method. type BoolValue struct { value bool diff --git a/knownvalue/float64.go b/knownvalue/float64.go index 4514db9ff..6b993e290 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -10,7 +10,7 @@ import ( var _ Check = Float64Value{} -// Float64Value is a KnownValue for asserting equality between the value supplied +// Float64Value is a Check for asserting equality between the value supplied // to Float64ValueExact and the value passed to the CheckValue method. type Float64Value struct { value float64 diff --git a/knownvalue/int64.go b/knownvalue/int64.go index bf4f9eadf..c2e005613 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -10,7 +10,7 @@ import ( var _ Check = Int64Value{} -// Int64Value is a KnownValue for asserting equality between the value supplied +// Int64Value is a Check for asserting equality between the value supplied // to Int64ValueExact and the value passed to the CheckValue method. type Int64Value struct { value int64 diff --git a/knownvalue/list.go b/knownvalue/list.go index a39a0504e..a14967b72 100644 --- a/knownvalue/list.go +++ b/knownvalue/list.go @@ -9,7 +9,7 @@ import ( var _ Check = ListValue{} -// ListValue is a KnownValue for asserting equality between the value supplied +// ListValue is a Check for asserting equality between the value supplied // to ListValueExact and the value passed to the CheckValue method. type ListValue struct { value []Check @@ -60,7 +60,8 @@ func (v ListValue) String() string { } // ListValueExact returns a Check for asserting equality between the -// supplied []KnownValue and the value passed to the CheckValue method. +// supplied []Check and the value passed to the CheckValue method. +// This is an order-dependent check. func ListValueExact(value []Check) ListValue { return ListValue{ value: value, diff --git a/knownvalue/list_partial.go b/knownvalue/list_partial.go index 9ac85fc5a..0c6c075ea 100644 --- a/knownvalue/list_partial.go +++ b/knownvalue/list_partial.go @@ -12,8 +12,9 @@ import ( var _ Check = ListValuePartial{} -// ListValuePartial is a KnownValue for asserting equality between the value supplied -// to ListValuePartialMatch and the value passed to the CheckValue method. +// ListValuePartial is a Check for asserting partial equality between the +// value supplied to ListValuePartialMatch and the value passed to the +// CheckValue method. type ListValuePartial struct { value map[int]Check } @@ -79,10 +80,11 @@ func (v ListValuePartial) String() string { return b.String() } -// ListValuePartialMatch returns a Check for asserting equality between the -// supplied map[int]KnownValue and the value passed to the CheckValue method. The -// map keys correspond to the position of the zero-ordered element within the -// list that is being checked. +// ListValuePartialMatch returns a Check for asserting partial equality between the +// supplied map[int]Check and the value passed to the CheckValue method. The +// map keys represent the zero-ordered element indices within the list that is +// being checked. Only the elements at the indices defined within the +// supplied map[int]Check are checked. func ListValuePartialMatch(value map[int]Check) ListValuePartial { return ListValuePartial{ value: value, diff --git a/knownvalue/map.go b/knownvalue/map.go index f2e171d44..b86a8c50f 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -10,7 +10,7 @@ import ( var _ Check = MapValue{} -// MapValue is a KnownValue for asserting equality between the value supplied +// MapValue is a Check for asserting equality between the value supplied // to MapValueExact and the value passed to the CheckValue method. type MapValue struct { value map[string]Check @@ -87,7 +87,7 @@ func (v MapValue) String() string { } // MapValueExact returns a Check for asserting equality between the -// supplied map[string]KnownValue and the value passed to the CheckValue method. +// supplied map[string]Check and the value passed to the CheckValue method. func MapValueExact(value map[string]Check) MapValue { return MapValue{ value: value, diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index ce044712b..da620c5b1 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -10,8 +10,9 @@ import ( var _ Check = MapValuePartial{} -// MapValuePartial is a KnownValue for asserting equality between the value supplied -// to MapValuePartialMatch and the value passed to the CheckValue method. +// MapValuePartial is a Check for asserting partial equality between the +// value supplied to MapValuePartialMatch and the value passed to the +// CheckValue method. type MapValuePartial struct { value map[string]Check } @@ -72,7 +73,9 @@ func (v MapValuePartial) String() string { } // MapValuePartialMatch returns a Check for asserting partial equality between the -// supplied map[string]Check and the value passed to the CheckValue method. +// supplied map[string]Check and the value passed to the CheckValue method. Only +// the elements at the map keys defined within the supplied map[string]Check are +// checked. func MapValuePartialMatch(value map[string]Check) MapValuePartial { return MapValuePartial{ value: value, diff --git a/knownvalue/number.go b/knownvalue/number.go index d1601eaf2..fff3b829e 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -10,7 +10,7 @@ import ( var _ Check = NumberValue{} -// NumberValue is a KnownValue for asserting equality between the value supplied +// NumberValue is a Check for asserting equality between the value supplied // to NumberValueExact and the value passed to the CheckValue method. type NumberValue struct { value *big.Float diff --git a/knownvalue/object.go b/knownvalue/object.go index 0221ee5e2..e8b74a4b5 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -10,7 +10,7 @@ import ( var _ Check = ObjectValue{} -// ObjectValue is a KnownValue for asserting equality between the value supplied +// ObjectValue is a Check for asserting equality between the value supplied // to ObjectValueExact and the value passed to the CheckValue method. type ObjectValue struct { value map[string]Check @@ -86,8 +86,9 @@ func (v ObjectValue) String() string { return fmt.Sprintf("%v", mapVals) } -// ObjectValueExact returns a Check for asserting equality between the -// supplied map[string]KnownValue and the value passed to the CheckValue method. +// ObjectValueExact returns a Check for asserting equality between the supplied +// map[string]Check and the value passed to the CheckValue method. The map +// keys represent object attribute names. func ObjectValueExact(value map[string]Check) ObjectValue { return ObjectValue{ value: value, diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index 4edf51d2a..f024982b9 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -10,8 +10,9 @@ import ( var _ Check = ObjectValuePartial{} -// ObjectValuePartial is a KnownValue for asserting equality between the value supplied -// to ObjectValuePartialMatch and the value passed to the CheckValue method. +// ObjectValuePartial is a Check for asserting partial equality between the +// value supplied to ObjectValuePartialMatch and the value passed to the +// CheckValue method. type ObjectValuePartial struct { value map[string]Check } @@ -72,7 +73,9 @@ func (v ObjectValuePartial) String() string { } // ObjectValuePartialMatch returns a Check for asserting partial equality between the -// supplied map[string]KnownValue and the value passed to the CheckValue method. +// supplied map[string]Check and the value passed to the CheckValue method. The map +// keys represent object attribute names. Only the object attributes defined by the +// map keys within the supplied map[string]Check are checked. func ObjectValuePartialMatch(value map[string]Check) ObjectValuePartial { return ObjectValuePartial{ value: value, diff --git a/knownvalue/set.go b/knownvalue/set.go index c80bbd8c4..54996f164 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -9,7 +9,7 @@ import ( var _ Check = SetValue{} -// SetValue is a KnownValue for asserting equality between the value supplied +// SetValue is a Check for asserting equality between the value supplied // to SetValueExact and the value passed to the CheckValue method. type SetValue struct { value []Check @@ -80,6 +80,7 @@ func (v SetValue) String() string { // SetValueExact returns a Check for asserting equality between the // supplied []Check and the value passed to the CheckValue method. +// This is an order-independent check. func SetValueExact(value []Check) SetValue { return SetValue{ value: value, diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index ea12ed215..89da7510b 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -9,8 +9,9 @@ import ( var _ Check = SetValuePartial{} -// SetValuePartial is a KnownValue for asserting equality between the value supplied -// to SetValuePartialMatch and the value passed to the CheckValue method. +// SetValuePartial is a Check for asserting partial equality between the +// value supplied to SetValuePartialMatch and the value passed to the +// CheckValue method. type SetValuePartial struct { value []Check } @@ -63,8 +64,10 @@ func (v SetValuePartial) String() string { return fmt.Sprintf("%s", setVals) } -// SetValuePartialMatch returns a Check for asserting equality of the elements -// supplied in []Check and the elements in the value passed to the CheckValue method. +// SetValuePartialMatch returns a Check for asserting partial equality between the +// supplied []Check and the value passed to the CheckValue method. Only the +// elements defined within the supplied []Check are checked. This is an +// order-independent check. func SetValuePartialMatch(value []Check) SetValuePartial { return SetValuePartial{ value: value, diff --git a/knownvalue/string.go b/knownvalue/string.go index 6b98ba0c5..7ccc58aca 100644 --- a/knownvalue/string.go +++ b/knownvalue/string.go @@ -7,7 +7,7 @@ import "fmt" var _ Check = StringValue{} -// StringValue is a KnownValue for asserting equality between the value +// StringValue is a Check for asserting equality between the value // supplied to StringValueExact and the value passed to the CheckValue method. type StringValue struct { value string From 213b81a9e2ab00de354ada9297cee187a594e216 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 09:24:59 +0000 Subject: [PATCH 19/48] Modifying known-values.mdx page description (#243) --- website/docs/plugin/testing/acceptance-tests/known-values.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/plugin/testing/acceptance-tests/known-values.mdx b/website/docs/plugin/testing/acceptance-tests/known-values.mdx index 6fbca13c6..b87bb6624 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-values.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-values.mdx @@ -2,7 +2,7 @@ page_title: 'Plugin Development - Acceptance Testing: Known Values' description: >- How to use known values in the testing module. - Known values define an expected type, and value for a resource attribute, or output value in a Terraform plan or in Terraform state. + Known values define an expected type, and value for a resource attribute, or output value in a Terraform plan or in Terraform state for use in Plan Checks. --- # Known Values From fa8f125c8a1a4ab923ba4537c0be1da02b5a75eb Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 09:49:47 +0000 Subject: [PATCH 20/48] Restructuring and updating references to knownvalue.Check (#243) --- website/data/plugin-testing-nav-data.json | 9 ++++-- .../index.mdx} | 28 +++++++++---------- .../acceptance-tests/plan-checks/output.mdx | 4 +-- .../acceptance-tests/plan-checks/resource.mdx | 4 +-- 4 files changed, 25 insertions(+), 20 deletions(-) rename website/docs/plugin/testing/acceptance-tests/{known-values.mdx => known-value-checks/index.mdx} (94%) diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index 054f09a21..3a9617dc5 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -51,8 +51,13 @@ ] }, { - "title": "Known Values", - "path": "acceptance-tests/known-values" + "title": "Known Value Checks", + "routes": [ + { + "title": "Overview", + "path": "acceptance-tests/known-value-checks" + } + ] }, { "title": "Sweepers", diff --git a/website/docs/plugin/testing/acceptance-tests/known-values.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx similarity index 94% rename from website/docs/plugin/testing/acceptance-tests/known-values.mdx rename to website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx index b87bb6624..5a8f102a3 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-values.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx @@ -17,24 +17,24 @@ Example uses in the testing module include: ## Using a Known Value -The known value types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known values are instantiated by calling the `New` constructor function. +The known value types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known values are instantiated by calling the relevant constructor function. For example ```go -knownvalue.NewBoolValue(true) +knownvalue.BoolValueExact(true) ``` For known values that represents collections, or objects, nesting of known values can be used to define a "composite" known value for use in asserting against a resource attribute, or output value that contains other values. ```go -knownvalue.NewListValue([]knownvalue.KnownValue{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), +knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), }) ``` ## Known Value Types -The following table describes the correspondence between attributes, and [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types. Output value correspond to the known value types in same way on the basis of the attribute to which the output value refers. +The following table describes the correspondence between attributes, and [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types. Output value correspond to the known value types in same way on the basis of the attribute to which the output value refers. | Framework Attribute Type | SDKv2 Attribute Type | Known Value Type | |---------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------| @@ -179,7 +179,7 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.KnownValue{ + knownvalue.NewListValue([]knownvalue.Check{ knownvalue.NewStringValue("value1"), knownvalue.NewStringValue("value2"), }), @@ -218,7 +218,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.KnownValue{ + knownvalue.NewListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.NewStringValue("value1"), }), ), @@ -254,7 +254,7 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.KnownValue{ + knownvalue.NewMapValue(map[string]knownvalue.Check{ "key1": knownvalue.NewStringValue("value1"), "key2": knownvalue.NewStringValue("value2"), }), @@ -291,7 +291,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.KnownValue{ + knownvalue.NewMapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.NewStringValue("value1"), }), ), @@ -398,7 +398,7 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("object_attribute"), - knownvalue.NewObjectValue(map[string]knownvalue.KnownValue{ + knownvalue.NewObjectValue(map[string]knownvalue.Check{ "key1": knownvalue.NewStringValue("value1"), "key2": knownvalue.NewStringValue("value2"), }), @@ -435,7 +435,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("object_attribute"), - knownvalue.NewObjectValuePartial(map[string]knownvalue.KnownValue{ + knownvalue.NewObjectValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.NewStringValue("value1"), }), ), @@ -471,7 +471,7 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.KnownValue{ + knownvalue.NewSetValue([]knownvalue.Check{ knownvalue.NewStringValue("value1"), knownvalue.NewStringValue("value2"), }), @@ -508,7 +508,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.NewSetValuePartial([]knownvalue.KnownValue{ + knownvalue.NewSetValuePartial([]knownvalue.Check{ knownvalue.NewStringValue("value2"), }), ), diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx index a3410de9a..bdada1867 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx @@ -22,7 +22,7 @@ The `terraform-plugin-testing` module provides a package [`plancheck`](https://p The [`plancheck.ExpectKnownOutputValue(address, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownOutputValue) plan check verifies that a specific output value has a known type, and value. -Refer to [Known Values](/terraform/plugin/testing/acceptance-tests/known-values) for details, and examples of the available [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types that can be used with the `ExpectKnownOutputValue` plan check. +Refer to [Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks) for details, and examples of the available [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types that can be used with the `ExpectKnownOutputValue` plan check. ```go func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { @@ -58,7 +58,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { The [`plancheck.ExpectKnownOutputValueAtPath(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownOutputValueAtPath) plan check verifies that a specific output value at a defined path has a known type, and value. -Refer to [Known Values](/terraform/plugin/testing/acceptance-tests/known-values) for details, and examples of the available [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types that can be used with the `ExpectKnownOutputValueAtPath` plan check. +Refer to [Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks) for details, and examples of the available [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types that can be used with the `ExpectKnownOutputValueAtPath` plan check. ```go func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx index 968f3cb6e..c0f93b6e7 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx @@ -20,7 +20,7 @@ The `terraform-plugin-testing` module provides a package [`plancheck`](https://p The [`plancheck.ExpectKnownValue(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck#ExpectKnownValue) plan check provides a basis for asserting that a specific resource attribute has a known type, and value. -Refer to [Known Values](/terraform/plugin/testing/acceptance-tests/known-values) for details, and examples of the available [knownvalue.KnownValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#KnownValue) types that can be used with the `ExpectKnownValue` plan check. +Refer to [Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks) for details, and examples of the available [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types that can be used with the `ExpectKnownValue` plan check. ```go func TestExpectKnownValue_CheckPlan_String(t *testing.T) { @@ -39,7 +39,7 @@ func TestExpectKnownValue_CheckPlan_String(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.NewStringValue("str")), + knownvalue.StringValueExact("str")), }, }, }, From 91417e1b6340b383a3c8cb338c303a6fd7d6be6b Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 12:17:39 +0000 Subject: [PATCH 21/48] Adding individual docs pages for each type of known value check (#243) --- website/data/plugin-testing-nav-data.json | 36 ++ .../known-value-checks/bool.mdx | 44 ++ .../known-value-checks/float64.mdx | 44 ++ .../known-value-checks/index.mdx | 539 +----------------- .../known-value-checks/int64.mdx | 44 ++ .../known-value-checks/list.mdx | 126 ++++ .../known-value-checks/map.mdx | 128 +++++ .../known-value-checks/number.mdx | 50 ++ .../known-value-checks/object.mdx | 128 +++++ .../known-value-checks/set.mdx | 126 ++++ .../known-value-checks/string.mdx | 43 ++ .../acceptance-tests/plan-checks/output.mdx | 4 +- 12 files changed, 790 insertions(+), 522 deletions(-) create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index 3a9617dc5..d12334aa5 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -56,6 +56,42 @@ { "title": "Overview", "path": "acceptance-tests/known-value-checks" + }, + { + "title": "Bool", + "path": "acceptance-tests/known-value-checks/bool" + }, + { + "title": "Float64", + "path": "acceptance-tests/known-value-checks/float64" + }, + { + "title": "Int64", + "path": "acceptance-tests/known-value-checks/int64" + }, + { + "title": "List", + "path": "acceptance-tests/known-value-checks/list" + }, + { + "title": "Map", + "path": "acceptance-tests/known-value-checks/map" + }, + { + "title": "Number", + "path": "acceptance-tests/known-value-checks/number" + }, + { + "title": "Object", + "path": "acceptance-tests/known-value-checks/object" + }, + { + "title": "Set", + "path": "acceptance-tests/known-value-checks/set" + }, + { + "title": "String", + "path": "acceptance-tests/known-value-checks/string" } ] }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx new file mode 100644 index 000000000..9d5b345c6 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx @@ -0,0 +1,44 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Bool Value Checks for use with Plan Checks. +--- + +# Bool Known Value Checks + +The known value checks that are available for bool values are: + +* [BoolValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/bool#boolvalueexact-check) + +## `BoolValueExact` Check + +The [BoolValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValueExact) check tests that a resource attribute, or output value has an exactly matching bool value. + +Example usage of [BoolValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx new file mode 100644 index 000000000..6509178e1 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx @@ -0,0 +1,44 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Float64 Value Checks for use with Plan Checks. +--- + +# Float64 Known Value Checks + +The known value checks that are available for float64 values are: + +* [Float64ValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#float64valueexact-check) + +## `Float64ValueExact` Check + +The [Float64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64ValueExact) check tests that a resource attribute, or output value has an exactly matching float64 value. + +Example usage of [Float64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64ValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.Float64ValueExact(1.23), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx index 5a8f102a3..8d449b974 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx @@ -5,25 +5,25 @@ description: >- Known values define an expected type, and value for a resource attribute, or output value in a Terraform plan or in Terraform state for use in Plan Checks. --- -# Known Values +# Known Value Checks -Known Values are for use in conjunction with [Plan Checks](/terraform/plugin/testing/acceptance-tests/plan-checks), which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan, or Terraform state. +Known Value Checks are for use in conjunction with [Plan Checks](/terraform/plugin/testing/acceptance-tests/plan-checks), which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan, or Terraform state. ## Usage Example uses in the testing module include: -- The [`ExpectknownValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/resource), [`ExpectKnownOutputValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output) and [`ExpectKnownOutputValueAtPath()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output) [built-in plan checks](/terraform/plugin/testing/acceptance-tests/plan-checks) use known values for asserting whether a specific resource attribute, or output value has a particular type, and value. +- The [`ExpectknownValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/resource#example-using-plancheck-expectknownvalue), [`ExpectKnownOutputValue()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output#example-using-plancheck-expectknownoutputvalue) and [`ExpectKnownOutputValueAtPath()`](/terraform/plugin/testing/acceptance-tests/plan-checks/output#example-using-plancheck-expectknownoutputvalueatpath) [built-in plan checks](/terraform/plugin/testing/acceptance-tests/plan-checks) use known value checks for asserting whether a specific resource attribute, or output value has a particular type, and value. -## Using a Known Value +## Using a Known Value Check -The known value types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known values are instantiated by calling the relevant constructor function. For example +The known value check types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known value checks are instantiated by calling the relevant constructor function. ```go knownvalue.BoolValueExact(true) ``` -For known values that represents collections, or objects, nesting of known values can be used to define a "composite" known value for use in asserting against a resource attribute, or output value that contains other values. +For known value checks that represent collections, or objects, nesting of known value checks can be used to define a "composite" known value check for use in asserting against a resource attribute, or output value that contains other values. ```go knownvalue.ListValueExact([]knownvalue.Check{ @@ -32,520 +32,19 @@ knownvalue.ListValueExact([]knownvalue.Check{ }) ``` -## Known Value Types +## Known Value Check Types -The following table describes the correspondence between attributes, and [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types. Output value correspond to the known value types in same way on the basis of the attribute to which the output value refers. +The following table shows the correspondence between [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types, and attributes. -| Framework Attribute Type | SDKv2 Attribute Type | Known Value Type | -|---------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------| -| `schema.BoolAttribute` | `schema.TypeBool` | [knownvalue.BoolValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValue) | -| `schema.Float64Attribute` | `schema.TypeFloat` | [knownvalue.Float64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Value) | -| `schema.Int64Attribute` | `schema.TypeInt` | [knownvalue.Int64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Value) | -| `schema.ListAttribute` | `schema.TypeList` | [knownvalue.ListValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValue) | -| `schema.MapAttribute` | `schema.TypeMap` | [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) | -| `schema.NumberAttribute` | N/A | [knownvalue.NumberValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValue) | -| `schema.ObjectAttribute` | N/A | [knownvalue.ObjectValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValue) | -| `schema.SetAttribute` | `schema.TypeSet` | [knownvalue.SetValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValue) | -| `schema.StringAttribute` | `schema.TypeString` | [knownvalue.StringValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValue) | +| Known Value Check Type | Framework Attribute Type | SDKv2 Attribute Type | +|-----------------------------------------------------------------------------------------------------|---------------------------|----------------------| +| [Bool Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/bool) | `schema.BoolAttribute` | `schema.TypeBool` | +| [Float64 Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64) | `schema.Float64Attribute` | `schema.TypeFloat` | +| [Int64 Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/int64) | `schema.Int64Attribute` | `schema.TypeInt` | +| [List Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/list) | `schema.ListAttribute` | `schema.TypeList` | +| [Map Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/map) | `schema.MapAttribute` | `schema.TypeMap` | +| [Number Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/number) | `schema.NumberAttribute` | N/A | +| [Object Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/object) | `schema.ObjectAttribute` | N/A | +| [Set Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/set) | `schema.SetAttribute` | `schema.TypeSet` | +| [String Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/string) | `schema.StringAttribute` | `schema.TypeString` | -Additionally, there are known values for use in plan checks, and state checks, in which only a part, or subset of a collection or object needs to be asserted. - -| Framework Attribute Type | SDKv2 Attribute Type | Known Value Type | -|--------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------| -| `schema.ListAttribute` | `schema.TypeList` | [knownvalue.ListValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartial) | -| `schema.MapAttribute` | `schema.TypeMap` | [knownvalue.MapValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartial) | -| `schema.ObjectAttribute` | N/A | [knownvalue.ObjectValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartial) | -| `schema.SetAttribute` | `schema.TypeSet` | [knownvalue.SetValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartial) | - -There are also general purpose known value types for use, for example, in asserting the number of elements in a collection or object: - -* [knownvalue.NumElements](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumElements) - - -### Bool Known Value - -Example usage of [knownvalue.BoolValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - bool_attribute = true - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("bool_attribute"), - knownvalue.NewBoolValue(true), - ), - }, - }, - }, - }, - }) -} -``` - -### Float64 Known Value - -Example usage of [knownvalue.Float64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Value) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - float_attribute = 1.23 - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("float_attribute"), - knownvalue.NewFloat64Value(1.23), - ), - }, - }, - }, - }, - }) -} -``` - -### Int64 Known Value - -Example usage of [knownvalue.Int64Value](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Value) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - int_attribute = 123 - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("int_attribute"), - knownvalue.NewInt64Value(123), - ), - }, - }, - }, - }, - }) -} -``` - -### List Known Value - -Example usage of [knownvalue.ListValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_List(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewListValue([]knownvalue.Check{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### List Partial Known Value - -Example usage of [knownvalue.ListValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -In this example, only the first element within the list is checked. - -```go -func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.NewStringValue("value1"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### Map Known Value - -Example usage of [knownvalue.MapValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - map_attribute = { - key1 = "value1" - key2 = "value2" - } - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("map_attribute"), - knownvalue.NewMapValue(map[string]knownvalue.Check{ - "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### Map Partial Known Value - -Example usage of [knownvalue.MapValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - map_attribute = { - key1 = "value1" - key2 = "value2" - } - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("map_attribute"), - knownvalue.NewMapValuePartial(map[string]knownvalue.Check{ - "key1": knownvalue.NewStringValue("value1"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### Num Elements Known Value - -Example usage of [knownvalue.NumElements](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumElements) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - list_attribute = [ - "value1", - "value2" - ] - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("list_attribute"), - knownvalue.NewNumElementsValue(2), - ), - }, - }, - }, - }, - }) -} -``` - -### Number Known Value - -Example usage of [knownvalue.NumberValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { - t.Parallel() - - f, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862315", 10, 512, big.ToNearestEven) - - if err != nil { - t.Errorf("%s", err) - } - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - number_attribute = 123 - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("number_attribute"), - knownvalue.NewNumberValue(f), - ), - }, - }, - }, - }, - }) -} -``` - -### Object Known Value - -Example usage of [knownvalue.ObjectValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - object_attribute = { - key1 = "value1" - key2 = "value2" - } - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("object_attribute"), - knownvalue.NewObjectValue(map[string]knownvalue.Check{ - "key1": knownvalue.NewStringValue("value1"), - "key2": knownvalue.NewStringValue("value2"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### Object Partial Known Value - -Example usage of [knownvalue.ObjectValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - object_attribute = { - key1 = "value1" - key2 = "value2" - } - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("object_attribute"), - knownvalue.NewObjectValuePartial(map[string]knownvalue.Check{ - "key1": knownvalue.NewStringValue("value1"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### Set Known Value - -Example usage of [knownvalue.SetValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - set_attribute = [ - "value1", - "value2" - ] - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("set_attribute"), - knownvalue.NewSetValue([]knownvalue.Check{ - knownvalue.NewStringValue("value1"), - knownvalue.NewStringValue("value2"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### Set Partial Known Value - -Example usage of [knownvalue.SetValuePartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - set_attribute = [ - "value1", - "value2" - ] - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("set_attribute"), - knownvalue.NewSetValuePartial([]knownvalue.Check{ - knownvalue.NewStringValue("value2"), - }), - ), - }, - }, - }, - }, - }) -} -``` - -### String Known Value - -Example usage of [knownvalue.StringValue](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValue) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_String(t *testing.T) { - t.Parallel() - - r.Test(t, r.TestCase{ - // Provider definition omitted. - Steps: []r.TestStep{ - { - Config: `resource "test_resource" "one" { - string_attribute = "str" - } - `, - ConfigPlanChecks: r.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("string_attribute"), - knownvalue.NewStringValue("str")), - }, - }, - }, - }, - }) -} -``` \ No newline at end of file diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx new file mode 100644 index 000000000..0584c8cfc --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx @@ -0,0 +1,44 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Int64 Value Checks for use with Plan Checks. +--- + +# Int64 Known Value Checks + +The known value checks that are available for int64 values are: + +* [Int64ValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#int64valueexact-check) + +## `Int64ValueExact` Check + +The [Int64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64ValueExact) check tests that a resource attribute, or output value has an exactly matching int64 value. + +Example usage of [Int64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64ValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.Int64ValueExact(123), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx new file mode 100644 index 000000000..03d74d170 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx @@ -0,0 +1,126 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + List Value Checks for use with Plan Checks. +--- + +# List Known Value Checks + +The known value checks that are available for list values are: + +* [ListElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listelementsexact-check) +* [ListValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listvalueexact-check) +* [ListValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listvaluepartialmatch-check) + +## `ListElementsExact` Check + +The [ListElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListElementsExact) check tests that a resource attribute, or output value contains the specified number of elements. + +Example usage of [ListElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }, + }) +} +``` + +## `ListValueExact` Check + +The [ListValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValueExact) check tests that a resource attribute, or output value has an order-dependent, matching collection of element values. + +Example usage of [ListValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +## `ListValuePartialMatch` Check + +The [ListValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartialMatch) check tests that a resource attribute, or output value has matching element values for the specified collection indices. + +Example usage of [ListValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the first element within the list, the element defined at index `0`, is checked. + +```go +func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx new file mode 100644 index 000000000..9b66acd21 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx @@ -0,0 +1,128 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Map Value Checks for use with Plan Checks. +--- + +# Map Known Value Checks + +The known value checks that are available for map values are: + +* [MapElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapelementsexact-check) +* [MapValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapvalueexact-check) +* [MapValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapvaluepartialmatch-check) + +## `MapElementsExact` Check + +The [MapElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapElementsExact) check tests that a resource attribute, or output value contains the specified number of elements. + +Example usage of [MapElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapElementsExact(2), + ), + }, + }, + }, + }, + }) +} +``` + +## `MapValueExact` Check + +The [MapValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValueExact) check tests that a resource attribute, or output value has a key-specified, matching collection of element values. + +Example usage of [MapValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +## `MapValuePartialMatch` Check + +The [MapValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartialMatch) check tests that a resource attribute, or output value has matching element values for the specified keys. + +Example usage of [MapValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +In this example, only the element associated with `key1` within the map is checked. + +```go +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx new file mode 100644 index 000000000..c069eaa9b --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx @@ -0,0 +1,50 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Number Value Checks for use with Plan Checks. +--- + +# Number Known Value Checks + +The known value checks that are available for number values are: + +* [NumberValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/number#numbervalueexact-check) + +## `NumberValueExact` Check + +The [NumberValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValueExact) check tests that a resource attribute, or output value has an exactly matching number value. + +Example usage of [NumberValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Number(t *testing.T) { + t.Parallel() + + num, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862315", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + number_attribute = 123 + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("number_attribute"), + knownvalue.NumberValueExact(num), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx new file mode 100644 index 000000000..5f0f237a2 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx @@ -0,0 +1,128 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Object Value Checks for use with Plan Checks. +--- + +# Object Known Value Checks + +The known value checks that are available for object values are: + +* [ObjectElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectelementsexact-check) +* [ObjectValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectvalueexact-check) +* [ObjectValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectvaluepartialmatch-check) + +## `ObjectElementsExact` Check + +The [ObjectElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectElementsExact) check tests that a resource attribute, or output value contains the specified number of attributes. + +Example usage of [ObjectElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_ObjectElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + object_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("object_attribute"), + knownvalue.ObjectElementsExact(2), + ), + }, + }, + }, + }, + }) +} +``` + +## `ObjectValueExact` Check + +The [ObjectValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValueExact) check tests that a resource attribute, or output value has a matching collection of attribute name, and attribute values. + +Example usage of [ObjectValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Object(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + object_attribute = { + attr1 = "value1" + attr2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("object_attribute"), + knownvalue.ObjectValueExact(map[string]knownvalue.Check{ + "attr1": knownvalue.StringValueExact("value1"), + "attr2": knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +## `ObjectValuePartialMatch` Check + +The [ObjectValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartialMatch) check tests that a resource attribute, or output value has matching attribute values for the specified attribute names. + +Example usage of [ObjectValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +In this example, only the attribute value associated with the attribute name `attr1` within the object is checked. + +```go +func TestExpectKnownValue_CheckPlan_ObjectPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + object_attribute = { + attr1 = "value1" + attr2 = "value2" + } + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("object_attribute"), + knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + "attr1": knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx new file mode 100644 index 000000000..41d1e1319 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx @@ -0,0 +1,126 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Set Value Checks for use with Plan Checks. +--- + +# Set Known Value Checks + +The known value checks that are available for set values are: + +* [SetElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setelementsexact-check) +* [SetValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setvalueexact-check) +* [SetValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setvaluepartialmatch-check) + +## `SetElementsExact` Check + +The [SetElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetElementsExact) check tests that a resource attribute, or output value contains the specified number of elements. + +Example usage of [SetElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }, + }) +} +``` + +## `SetValueExact` Check + +The [SetValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValueExact) check tests that a resource attribute, or output value has an order-independent, matching collection of element values. + +Example usage of [SetValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value2"), + knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }, + }) +} +``` + +## `SetValuePartialMatch` Check + +The [SetValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartialMatch) check tests that a resource attribute, or output value contains matching element values. + +Example usage of [SetValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the one element within the set is checked. + +```go +func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx new file mode 100644 index 000000000..9b8dead06 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx @@ -0,0 +1,43 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + String Value Checks for use with Plan Checks. +--- + +# String Known Value Checks + +The known value checks that are available for string values are: + +* [StringValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/string#stringvalueexact-check) + +## `StringValueExact` Check + +The [StringValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValueExact) check tests that a resource attribute, or output value has an exactly matching string value. + +Example usage of [StringValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigPlanChecks: r.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.StringValueExact("str")), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx index bdada1867..146ea2de7 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx @@ -44,7 +44,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, @@ -80,7 +80,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.NewBoolValue(true), + knownvalue.BoolValueExact(true), ), }, }, From 463c0e3b0eb5a9147600ec1cd980334d686c09b9 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 12:22:09 +0000 Subject: [PATCH 22/48] Removing references to num elements (#243) --- .../expect_known_output_value_at_path_test.go | 14 +++++++------- plancheck/expect_known_output_value_test.go | 14 +++++++------- plancheck/expect_known_value_test.go | 16 ++++++++-------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index fcd83b14d..a86d8ae68 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -657,7 +657,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_ListElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -700,7 +700,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements(t *testing.T) { }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_ListNumElements_WrongNum(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_ListElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -845,7 +845,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockPartial(t *testin }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockNumElements(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1118,7 +1118,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_MapElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1161,7 +1161,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements(t *testing.T) { }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_MapNumElements_WrongNum(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_MapElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1482,7 +1482,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_SetNumElements(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_SetElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1626,7 +1626,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockPartial(t *testing }) } -func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockNumElements(t *testing.T) { +func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 489c2a570..affa301e4 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -534,7 +534,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *te }) } -func TestExpectKnownOutputValue_CheckPlan_ListNumElements(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_ListElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -569,7 +569,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNumElements(t *testing.T) { }) } -func TestExpectKnownOutputValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_ListElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -690,7 +690,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { }) } -func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -915,7 +915,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *tes }) } -func TestExpectKnownOutputValue_CheckPlan_MapNumElements(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_MapElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -950,7 +950,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapNumElements(t *testing.T) { }) } -func TestExpectKnownOutputValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_MapElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1215,7 +1215,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *tes }) } -func TestExpectKnownOutputValue_CheckPlan_SetNumElements(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_SetElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1335,7 +1335,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { }) } -func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { +func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 1d9c86741..9957cc325 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -490,7 +490,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing. }) } -func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -522,7 +522,7 @@ func TestExpectKnownValue_CheckPlan_ListNumElements(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_ListNumElements_WrongNum(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -634,7 +634,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_ListNestedBlockNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListNestedBlockElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -841,7 +841,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T }) } -func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -873,7 +873,7 @@ func TestExpectKnownValue_CheckPlan_MapNumElements(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_MapNumElements_WrongNum(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapElements_WrongNum(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1001,8 +1001,8 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { "test_resource.one", tfjsonpath.New("set_attribute"), knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), knownvalue.StringValueExact("value2"), + knownvalue.StringValueExact("value1"), }), ), }, @@ -1117,7 +1117,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T }) } -func TestExpectKnownValue_CheckPlan_SetNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ @@ -1228,7 +1228,7 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { }) } -func TestExpectKnownValue_CheckPlan_SetNestedBlockNumElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_SetNestedBlockElements(t *testing.T) { t.Parallel() r.Test(t, r.TestCase{ From a6614906e60986fc50bdd439589932b2056f950d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 12:25:26 +0000 Subject: [PATCH 23/48] Removing references to state (#243) --- .../testing/acceptance-tests/known-value-checks/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx index 8d449b974..dae04a89d 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx @@ -2,12 +2,12 @@ page_title: 'Plugin Development - Acceptance Testing: Known Values' description: >- How to use known values in the testing module. - Known values define an expected type, and value for a resource attribute, or output value in a Terraform plan or in Terraform state for use in Plan Checks. + Known values define an expected type, and value for a resource attribute, or output value in a Terraform plan for use in Plan Checks. --- # Known Value Checks -Known Value Checks are for use in conjunction with [Plan Checks](/terraform/plugin/testing/acceptance-tests/plan-checks), which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan, or Terraform state. +Known Value Checks are for use in conjunction with [Plan Checks](/terraform/plugin/testing/acceptance-tests/plan-checks), which leverage the [terraform-json](https://pkg.go.dev/github.com/hashicorp/terraform-json) representation of a Terraform plan. ## Usage From 6b626f4cf1b50c470ad190ce61fe085c4b090aa0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Jan 2024 14:09:22 +0000 Subject: [PATCH 24/48] Adding docs page for custom known value checks (#243) --- website/data/plugin-testing-nav-data.json | 4 ++ .../known-value-checks/custom.mdx | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index d12334aa5..7e581b6c3 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -61,6 +61,10 @@ "title": "Bool", "path": "acceptance-tests/known-value-checks/bool" }, + { + "title": "Custom", + "path": "acceptance-tests/known-value-checks/custom" + }, { "title": "Float64", "path": "acceptance-tests/known-value-checks/float64" diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx new file mode 100644 index 000000000..15e989936 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx @@ -0,0 +1,50 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Custom Value Checks for use with Plan Checks. +--- + +# Custom Known Value Checks + +Custom known value checks can be created by implementing the [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) interface. + +```go +type Check interface { + CheckValue(value any) error + String() string +} +``` + +For example, a `StringValueContains` implementation could look as follows: + +```go +var _ Check = StringValueContains{} + +type StringValueContains struct { + value string +} + +func (v StringValueContains) CheckValue(other any) error { + otherVal, ok := other.(string) + + if !ok { + return fmt.Errorf("expected string value for StringValueContains check, got: %T", other) + } + + if !strings.Contains(v.value, otherVal) { + return fmt.Errorf("expected string %q to contain %q for StringValueContains check", v.value, otherVal) + } + + return nil +} + +func (v StringValueContains) String() string { + return v.value +} + +func StringValueMatch(value string) StringValue { + return StringValueContains{ + value: value, + } +} +``` From ad071ae4cf7f918f0606a5a30045742eb51df8f5 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 5 Jan 2024 06:41:50 +0000 Subject: [PATCH 25/48] Fixing error message (#243) --- .../testing/acceptance-tests/known-value-checks/custom.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx index 15e989936..ee48caa62 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx @@ -32,7 +32,7 @@ func (v StringValueContains) CheckValue(other any) error { } if !strings.Contains(v.value, otherVal) { - return fmt.Errorf("expected string %q to contain %q for StringValueContains check", v.value, otherVal) + return fmt.Errorf("expected string %q to contain %q for StringValueContains check", otherVal, v.value) } return nil From efb0b98b5c180e966435108efa3704bc731bbe3c Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 5 Jan 2024 11:05:47 +0000 Subject: [PATCH 26/48] Refactoring to accomodate custom known value checks in ExpectKnownValue, ExpectKnownOutputValue and ExpectKnownOutputValueAtPath (#243) --- knownvalue/float64.go | 11 +- knownvalue/float64_test.go | 15 +- knownvalue/int64.go | 11 +- knownvalue/int64_test.go | 15 +- knownvalue/list_partial_test.go | 27 +++- knownvalue/list_test.go | 19 +-- knownvalue/map_partial_test.go | 29 ++-- knownvalue/map_test.go | 29 ++-- knownvalue/number.go | 13 +- knownvalue/number_test.go | 23 ++- knownvalue/object_partial_test.go | 29 ++-- knownvalue/object_test.go | 29 ++-- knownvalue/set_partial_test.go | 22 ++- knownvalue/set_test.go | 23 +-- plancheck/expect_known_output_value.go | 142 +----------------- .../expect_known_output_value_at_path.go | 142 +----------------- .../expect_known_output_value_at_path_test.go | 10 +- plancheck/expect_known_output_value_test.go | 10 +- plancheck/expect_known_value.go | 142 +----------------- plancheck/expect_known_value_test.go | 10 +- 20 files changed, 207 insertions(+), 544 deletions(-) diff --git a/knownvalue/float64.go b/knownvalue/float64.go index 6b993e290..195ae8c30 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -4,6 +4,7 @@ package knownvalue import ( + "encoding/json" "fmt" "strconv" ) @@ -19,10 +20,16 @@ type Float64Value struct { // CheckValue determines whether the passed value is of type float64, and // contains a matching float64 value. func (v Float64Value) CheckValue(other any) error { - otherVal, ok := other.(float64) + jsonNum, ok := other.(json.Number) if !ok { - return fmt.Errorf("expected float64 value for Float64Value check, got: %T", other) + return fmt.Errorf("expected json.Number value for Float64Value check, got: %T", other) + } + + otherVal, err := jsonNum.Float64() + + if err != nil { + return fmt.Errorf("expected json.Number to be parseable as float64 value for Float64Value check: %s", err) } if otherVal != v.value { diff --git a/knownvalue/float64_test.go b/knownvalue/float64_test.go index 5a4d67d81..7ddbde24f 100644 --- a/knownvalue/float64_test.go +++ b/knownvalue/float64_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -21,28 +22,28 @@ func TestFloat64Value_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected float64 value for Float64Value check, got: "), + expectedError: fmt.Errorf("expected json.Number value for Float64Value check, got: "), }, "zero-other": { - other: 0.0, // checking against the underlying value field zero-value + other: json.Number("0.0"), // checking against the underlying value field zero-value }, "nil": { self: knownvalue.Float64ValueExact(1.234), - expectedError: fmt.Errorf("expected float64 value for Float64Value check, got: "), + expectedError: fmt.Errorf("expected json.Number value for Float64Value check, got: "), }, "wrong-type": { self: knownvalue.Float64ValueExact(1.234), - other: int64(1234), - expectedError: fmt.Errorf("expected float64 value for Float64Value check, got: int64"), + other: json.Number("str"), + expectedError: fmt.Errorf("expected json.Number to be parseable as float64 value for Float64Value check: strconv.ParseFloat: parsing \"str\": invalid syntax"), }, "not-equal": { self: knownvalue.Float64ValueExact(1.234), - other: 4.321, + other: json.Number("4.321"), expectedError: fmt.Errorf("expected value 1.234 for Float64Value check, got: 4.321"), }, "equal": { self: knownvalue.Float64ValueExact(1.234), - other: 1.234, + other: json.Number("1.234"), }, } diff --git a/knownvalue/int64.go b/knownvalue/int64.go index c2e005613..bf3b5ad48 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -4,6 +4,7 @@ package knownvalue import ( + "encoding/json" "fmt" "strconv" ) @@ -19,10 +20,16 @@ type Int64Value struct { // CheckValue determines whether the passed value is of type int64, and // contains a matching int64 value. func (v Int64Value) CheckValue(other any) error { - otherVal, ok := other.(int64) + jsonNum, ok := other.(json.Number) if !ok { - return fmt.Errorf("expected int64 value for Int64Value check, got: %T", other) + return fmt.Errorf("expected json.Number value for Int64Value check, got: %T", other) + } + + otherVal, err := jsonNum.Int64() + + if err != nil { + return fmt.Errorf("expected json.Number to be parseable as int64 value for Int64Value check: %s", err) } if otherVal != v.value { diff --git a/knownvalue/int64_test.go b/knownvalue/int64_test.go index d2b0de770..0aba7a21e 100644 --- a/knownvalue/int64_test.go +++ b/knownvalue/int64_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -21,28 +22,28 @@ func TestInt64Value_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected int64 value for Int64Value check, got: "), + expectedError: fmt.Errorf("expected json.Number value for Int64Value check, got: "), }, "zero-other": { - other: int64(0), // checking against the underlying value field zero-value + other: json.Number("0"), // checking against the underlying value field zero-value }, "nil": { self: knownvalue.Int64ValueExact(1234), - expectedError: fmt.Errorf("expected int64 value for Int64Value check, got: "), + expectedError: fmt.Errorf("expected json.Number value for Int64Value check, got: "), }, "wrong-type": { self: knownvalue.Int64ValueExact(1234), - other: 1.234, - expectedError: fmt.Errorf("expected int64 value for Int64Value check, got: float64"), + other: json.Number("str"), + expectedError: fmt.Errorf("expected json.Number to be parseable as int64 value for Int64Value check: strconv.ParseInt: parsing \"str\": invalid syntax"), }, "not-equal": { self: knownvalue.Int64ValueExact(1234), - other: int64(4321), + other: json.Number("4321"), expectedError: fmt.Errorf("expected value 1234 for Int64Value check, got: 4321"), }, "equal": { self: knownvalue.Int64ValueExact(1234), - other: int64(1234), + other: json.Number("1234"), }, } diff --git a/knownvalue/list_partial_test.go b/knownvalue/list_partial_test.go index 1585c4f03..d2f640b1c 100644 --- a/knownvalue/list_partial_test.go +++ b/knownvalue/list_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -58,7 +59,10 @@ func TestListValuePartial_CheckValue(t *testing.T) { 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 4.56}, + other: []any{ + json.Number("1.23"), + json.Number("4.56"), + }, expectedError: fmt.Errorf("missing element index 2 for ListValuePartial check"), }, "not-equal": { @@ -67,7 +71,12 @@ func TestListValuePartial_CheckValue(t *testing.T) { 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 4.56, 6.54, 5.46}, + other: []any{ + json.Number("1.23"), + json.Number("4.56"), + json.Number("6.54"), + json.Number("5.46"), + }, expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64Value check, got: 6.54"), }, "wrong-order": { @@ -76,7 +85,12 @@ func TestListValuePartial_CheckValue(t *testing.T) { 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 0.00, 7.89, 4.56}, + other: []any{ + json.Number("1.23"), + json.Number("0.00"), + json.Number("7.89"), + json.Number("4.56"), + }, expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64Value check, got: 7.89"), }, "equal": { @@ -85,7 +99,12 @@ func TestListValuePartial_CheckValue(t *testing.T) { 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 0.00, 4.56, 7.89}, + other: []any{ + json.Number("1.23"), + json.Number("0.00"), + json.Number("4.56"), + json.Number("7.89"), + }, }, } diff --git a/knownvalue/list_test.go b/knownvalue/list_test.go index cd964f84c..34c74752b 100644 --- a/knownvalue/list_test.go +++ b/knownvalue/list_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -71,9 +72,9 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(456), - int64(654), + json.Number("123"), + json.Number("456"), + json.Number("654"), }, expectedError: fmt.Errorf("list element index 2: expected value 789 for Int64Value check, got: 654"), }, @@ -84,9 +85,9 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(789), - int64(456), + json.Number("123"), + json.Number("789"), + json.Number("456"), }, expectedError: fmt.Errorf("list element index 1: expected value 456 for Int64Value check, got: 789"), }, @@ -97,9 +98,9 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(456), - int64(789), + json.Number("123"), + json.Number("456"), + json.Number("789"), }, }, } diff --git a/knownvalue/map_partial_test.go b/knownvalue/map_partial_test.go index 745b0e362..04a19cfd1 100644 --- a/knownvalue/map_partial_test.go +++ b/knownvalue/map_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -55,8 +56,8 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, + "one": json.Number("1.23"), + "two": json.Number("4.56"), }, expectedError: fmt.Errorf("missing element three for MapValuePartial check"), }, @@ -66,9 +67,9 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 6.54, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("6.54"), }, expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 6.54"), }, @@ -78,9 +79,9 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 7.89, - "three": 4.56, + "one": json.Number("1.23"), + "two": json.Number("7.89"), + "three": json.Number("4.56"), }, expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 4.56"), }, @@ -91,9 +92,9 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "four": 1.23, - "five": 7.89, - "six": 4.56, + "four": json.Number("1.23"), + "five": json.Number("7.89"), + "six": json.Number("4.56"), }, expectedError: fmt.Errorf("missing element one for MapValuePartial check"), }, @@ -103,9 +104,9 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 7.89, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("7.89"), }, }, } diff --git a/knownvalue/map_test.go b/knownvalue/map_test.go index 056351f92..c022f7eed 100644 --- a/knownvalue/map_test.go +++ b/knownvalue/map_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -59,8 +60,8 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, + "one": json.Number("1.23"), + "two": json.Number("4.56"), }, expectedError: fmt.Errorf("expected 3 elements for MapValue check, got 2 elements"), }, @@ -71,9 +72,9 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 6.54, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("6.54"), }, expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 6.54"), }, @@ -84,9 +85,9 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 7.89, - "three": 4.56, + "one": json.Number("1.23"), + "two": json.Number("7.89"), + "three": json.Number("4.56"), }, expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 4.56"), }, @@ -97,9 +98,9 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "four": 1.23, - "five": 7.89, - "six": 4.56, + "four": json.Number("1.23"), + "five": json.Number("7.89"), + "six": json.Number("4.56"), }, expectedError: fmt.Errorf("missing element one for MapValue check"), }, @@ -110,9 +111,9 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 7.89, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("7.89"), }, }, } diff --git a/knownvalue/number.go b/knownvalue/number.go index fff3b829e..5f8700e70 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -4,6 +4,7 @@ package knownvalue import ( + "encoding/json" "fmt" "math/big" ) @@ -20,13 +21,19 @@ type NumberValue struct { // contains a matching *big.Float value. func (v NumberValue) CheckValue(other any) error { if v.value == nil { - return fmt.Errorf("known value type is nil") + return fmt.Errorf("value in NumberValue check is nil") } - otherVal, ok := other.(*big.Float) + jsonNum, ok := other.(json.Number) if !ok { - return fmt.Errorf("expected *big.Float value for NumberValue check, got: %T", other) + return fmt.Errorf("expected json.Number value for NumberValue check, got: %T", other) + } + + otherVal, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) + + if err != nil { + return fmt.Errorf("expected json.Number to be parseable as big.Float value for NumberValue check: %s", err) } if v.value.Cmp(otherVal) != 0 { diff --git a/knownvalue/number_test.go b/knownvalue/number_test.go index bc1793187..4d3e7b8a9 100644 --- a/knownvalue/number_test.go +++ b/knownvalue/number_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "math/big" "testing" @@ -22,41 +23,35 @@ func TestNumberValue_Equal(t *testing.T) { t.Errorf("%s", err) } - otherBigFloat, _, err := big.ParseFloat("1.797693134862315797693134862315797693134862314", 10, 512, big.ToNearestEven) - - if err != nil { - t.Errorf("%s", err) - } - testCases := map[string]struct { self knownvalue.NumberValue other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("known value type is nil"), + expectedError: fmt.Errorf("value in NumberValue check is nil"), }, "zero-other": { - other: otherBigFloat, // checking against the underlying value field zero-value - expectedError: fmt.Errorf("known value type is nil"), + other: json.Number("1.797693134862315797693134862315797693134862314"), // checking against the underlying value field zero-value + expectedError: fmt.Errorf("value in NumberValue check is nil"), }, "nil": { self: knownvalue.NumberValueExact(bigFloat), - expectedError: fmt.Errorf("expected *big.Float value for NumberValue check, got: "), + expectedError: fmt.Errorf("expected json.Number value for NumberValue check, got: "), }, "wrong-type": { self: knownvalue.NumberValueExact(bigFloat), - other: 1.234, - expectedError: fmt.Errorf("expected *big.Float value for NumberValue check, got: float64"), + other: json.Number("str"), + expectedError: fmt.Errorf("expected json.Number to be parseable as big.Float value for NumberValue check: number has no digits"), }, "not-equal": { self: knownvalue.NumberValueExact(bigFloat), - other: otherBigFloat, + other: json.Number("1.797693134862315797693134862315797693134862314"), expectedError: fmt.Errorf("expected value 1.797693134862315797693134862315797693134862315 for NumberValue check, got: 1.797693134862315797693134862315797693134862314"), }, "equal": { self: knownvalue.NumberValueExact(bigFloat), - other: bigFloat, + other: json.Number("1.797693134862315797693134862315797693134862315"), }, } diff --git a/knownvalue/object_partial_test.go b/knownvalue/object_partial_test.go index 3bf6d9208..150487c82 100644 --- a/knownvalue/object_partial_test.go +++ b/knownvalue/object_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -55,8 +56,8 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, + "one": json.Number("1.23"), + "two": json.Number("4.56"), }, expectedError: fmt.Errorf("missing attribute three for ObjectValuePartial check"), }, @@ -66,9 +67,9 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 6.54, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("6.54"), }, expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 6.54"), }, @@ -78,9 +79,9 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 7.89, - "three": 4.56, + "one": json.Number("1.23"), + "two": json.Number("7.89"), + "three": json.Number("4.56"), }, expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 4.56"), }, @@ -91,9 +92,9 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "four": 1.23, - "five": 7.89, - "six": 4.56, + "four": json.Number("1.23"), + "five": json.Number("7.89"), + "six": json.Number("4.56"), }, expectedError: fmt.Errorf("missing attribute one for ObjectValuePartial check"), }, @@ -103,9 +104,9 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 7.89, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("7.89"), }, }, } diff --git a/knownvalue/object_test.go b/knownvalue/object_test.go index 0e3224bb1..f281e3d6a 100644 --- a/knownvalue/object_test.go +++ b/knownvalue/object_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -59,8 +60,8 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, + "one": json.Number("1.23"), + "two": json.Number("4.56"), }, expectedError: fmt.Errorf("expected 3 attributes for ObjectValue check, got 2 attributes"), }, @@ -71,9 +72,9 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 6.54, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("6.54"), }, expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 6.54"), }, @@ -84,9 +85,9 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 7.89, - "three": 4.56, + "one": json.Number("1.23"), + "two": json.Number("7.89"), + "three": json.Number("4.56"), }, expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 4.56"), }, @@ -97,9 +98,9 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "four": 1.23, - "five": 7.89, - "six": 4.56, + "four": json.Number("1.23"), + "five": json.Number("7.89"), + "six": json.Number("4.56"), }, expectedError: fmt.Errorf("missing attribute one for ObjectValue check"), }, @@ -110,9 +111,9 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{ - "one": 1.23, - "two": 4.56, - "three": 7.89, + "one": json.Number("1.23"), + "two": json.Number("4.56"), + "three": json.Number("7.89"), }, }, } diff --git a/knownvalue/set_partial_test.go b/knownvalue/set_partial_test.go index 2d29b3019..63d02d404 100644 --- a/knownvalue/set_partial_test.go +++ b/knownvalue/set_partial_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -58,7 +59,12 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 4.56, 6.54, 5.46}, + other: []any{ + json.Number("1.23"), + json.Number("4.56"), + json.Number("6.54"), + json.Number("5.46"), + }, expectedError: fmt.Errorf("missing value 7.89 for SetValuePartial check"), }, "equal-different-order": { @@ -67,7 +73,12 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 0.00, 7.89, 4.56}, + other: []any{ + json.Number("1.23"), + json.Number("0.00"), + json.Number("7.89"), + json.Number("4.56"), + }, }, "equal-same-order": { self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ @@ -75,7 +86,12 @@ func TestSetValuePartial_CheckValue(t *testing.T) { knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), }), - other: []any{1.23, 0.00, 4.56, 7.89}, + other: []any{ + json.Number("1.23"), + json.Number("0.00"), + json.Number("4.56"), + json.Number("7.89"), + }, }, } diff --git a/knownvalue/set_test.go b/knownvalue/set_test.go index 4df59505c..e89c89386 100644 --- a/knownvalue/set_test.go +++ b/knownvalue/set_test.go @@ -4,6 +4,7 @@ package knownvalue_test import ( + "encoding/json" "fmt" "testing" @@ -59,8 +60,8 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(456), + json.Number("123"), + json.Number("456"), }, expectedError: fmt.Errorf("expected 3 elements for SetValue check, got 2 elements"), }, @@ -71,9 +72,9 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(456), - int64(654), + json.Number("123"), + json.Number("456"), + json.Number("654"), }, expectedError: fmt.Errorf("missing value 789 for SetValue check"), }, @@ -84,9 +85,9 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(789), - int64(456), + json.Number("123"), + json.Number("789"), + json.Number("456"), }, }, "equal-same-order": { @@ -96,9 +97,9 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{ - int64(123), - int64(456), - int64(789), + json.Number("123"), + json.Number("456"), + json.Number("789"), }, }, } diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go index f310fe06b..8004f8764 100644 --- a/plancheck/expect_known_output_value.go +++ b/plancheck/expect_known_output_value.go @@ -5,9 +5,7 @@ package plancheck import ( "context" - "encoding/json" "fmt" - "math/big" "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -57,145 +55,15 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ } switch reflect.TypeOf(result).Kind() { - case reflect.Bool: - v, ok := e.knownValue.(knownvalue.BoolValue) - - if !ok { - resp.Error = fmt.Errorf("wrong type: value is bool, known value type is %T", e.knownValue) - - return - } - - if err := v.CheckValue(result); err != nil { + case reflect.Bool, + reflect.Map, + reflect.Slice, + reflect.String: + if err := e.knownValue.CheckValue(result); err != nil { resp.Error = err return } - case reflect.Map: - elems := make(map[string]any) - - val := reflect.ValueOf(result) - - for _, key := range val.MapKeys() { - elems[key.String()] = val.MapIndex(key).Interface() - } - - switch t := e.knownValue.(type) { - case knownvalue.MapElements, - knownvalue.MapValue, - knownvalue.MapValuePartial, - knownvalue.ObjectAttributes, - knownvalue.ObjectValue, - knownvalue.ObjectValuePartial: - if err := t.CheckValue(elems); err != nil { - resp.Error = err - - return - } - default: - resp.Error = fmt.Errorf("wrong type: value is map, or object, known value type is %T", t) - - return - } - case reflect.Slice: - var elems []any - - val := reflect.ValueOf(result) - - for i := 0; i < val.Len(); i++ { - elems = append(elems, val.Index(i).Interface()) - } - - switch t := e.knownValue.(type) { - case knownvalue.ListElements, - knownvalue.ListValue, - knownvalue.ListValuePartial, - knownvalue.SetElements, - knownvalue.SetValue, - knownvalue.SetValuePartial: - if err := t.CheckValue(elems); err != nil { - resp.Error = err - - return - } - default: - resp.Error = fmt.Errorf("wrong type: value is list, or set, known value type is %T", t) - - return - } - case reflect.String: - jsonNum, jsonNumOk := result.(json.Number) - - if jsonNumOk { - float64Val, float64ValOk := e.knownValue.(knownvalue.Float64Value) - - int64Val, int64ValOk := e.knownValue.(knownvalue.Int64Value) - - numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) - - if !float64ValOk && !int64ValOk && !numberValOk { - resp.Error = fmt.Errorf("wrong type: value is number, known value type is %T", e.knownValue) - } - - switch { - case float64ValOk: - f, err := jsonNum.Float64() - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as float64", jsonNum.String()) - - return - } - - if err := float64Val.CheckValue(f); err != nil { - resp.Error = err - - return - } - case int64ValOk: - i, err := jsonNum.Int64() - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as int64", jsonNum.String()) - - return - } - - if err := int64Val.CheckValue(i); err != nil { - resp.Error = err - - return - } - case numberValOk: - f, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as big.Float", jsonNum.String()) - - return - } - - if err := numberValue.CheckValue(f); err != nil { - resp.Error = err - - return - } - } - } else { - v, ok := e.knownValue.(knownvalue.StringValue) - - if !ok { - resp.Error = fmt.Errorf("wrong type: value is string, known value type is %T", e.knownValue) - - return - } - - if err := v.CheckValue(result); err != nil { - resp.Error = err - - return - } - } default: errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) errorStr += "\n\nThis is an error in plancheck.ExpectKnownOutputValue.\nPlease report this to the maintainers." diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go index 0fadbd01d..131cd86a5 100644 --- a/plancheck/expect_known_output_value_at_path.go +++ b/plancheck/expect_known_output_value_at_path.go @@ -5,9 +5,7 @@ package plancheck import ( "context" - "encoding/json" "fmt" - "math/big" "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -58,145 +56,15 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl } switch reflect.TypeOf(result).Kind() { - case reflect.Bool: - v, ok := e.knownValue.(knownvalue.BoolValue) - - if !ok { - resp.Error = fmt.Errorf("wrong type: value is bool, known value type is %T", e.knownValue) - - return - } - - if err := v.CheckValue(result); err != nil { + case reflect.Bool, + reflect.Map, + reflect.Slice, + reflect.String: + if err := e.knownValue.CheckValue(result); err != nil { resp.Error = err return } - case reflect.Map: - elems := make(map[string]any) - - val := reflect.ValueOf(result) - - for _, key := range val.MapKeys() { - elems[key.String()] = val.MapIndex(key).Interface() - } - - switch t := e.knownValue.(type) { - case knownvalue.MapElements, - knownvalue.MapValue, - knownvalue.MapValuePartial, - knownvalue.ObjectAttributes, - knownvalue.ObjectValue, - knownvalue.ObjectValuePartial: - if err := t.CheckValue(elems); err != nil { - resp.Error = err - - return - } - default: - resp.Error = fmt.Errorf("wrong type: value is map, or object, known value type is %T", t) - - return - } - case reflect.Slice: - var elems []any - - val := reflect.ValueOf(result) - - for i := 0; i < val.Len(); i++ { - elems = append(elems, val.Index(i).Interface()) - } - - switch t := e.knownValue.(type) { - case knownvalue.ListElements, - knownvalue.ListValue, - knownvalue.ListValuePartial, - knownvalue.SetElements, - knownvalue.SetValue, - knownvalue.SetValuePartial: - if err := t.CheckValue(elems); err != nil { - resp.Error = err - - return - } - default: - resp.Error = fmt.Errorf("wrong type: value is list, or set, known value type is %T", t) - - return - } - case reflect.String: - jsonNum, jsonNumOk := result.(json.Number) - - if jsonNumOk { - float64Val, float64ValOk := e.knownValue.(knownvalue.Float64Value) - - int64Val, int64ValOk := e.knownValue.(knownvalue.Int64Value) - - numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) - - if !float64ValOk && !int64ValOk && !numberValOk { - resp.Error = fmt.Errorf("wrong type: value is number, known value type is %T", e.knownValue) - } - - switch { - case float64ValOk: - f, err := jsonNum.Float64() - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as float64", jsonNum.String()) - - return - } - - if err := float64Val.CheckValue(f); err != nil { - resp.Error = err - - return - } - case int64ValOk: - i, err := jsonNum.Int64() - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as int64", jsonNum.String()) - - return - } - - if err := int64Val.CheckValue(i); err != nil { - resp.Error = err - - return - } - case numberValOk: - f, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as big.Float", jsonNum.String()) - - return - } - - if err := numberValue.CheckValue(f); err != nil { - resp.Error = err - - return - } - } - } else { - v, ok := e.knownValue.(knownvalue.StringValue) - - if !ok { - resp.Error = fmt.Errorf("wrong type: value is string, known value type is %T", e.knownValue) - - return - } - - if err := v.CheckValue(result); err != nil { - resp.Error = err - - return - } - } default: errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) errorStr += "\n\nThis is an error in plancheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers." diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index a86d8ae68..ba3f2070f 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -176,7 +176,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is bool, known value type is knownvalue.Float64Value"), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), }, }, }) @@ -299,7 +299,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is number, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), }, }, }) @@ -511,7 +511,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), }, }, }) @@ -974,7 +974,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongType(t *testi ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), }, }, }) @@ -1744,7 +1744,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *te knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("wrong type: value is string, known value type is knownvalue.BoolValue"), + ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), }, }, }) diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index affa301e4..6e6363ffd 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -141,7 +141,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is bool, known value type is knownvalue.Float64Value"), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), }, }, }) @@ -240,7 +240,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is number, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), }, }, }) @@ -412,7 +412,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), }, }, }) @@ -795,7 +795,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), }, }, }) @@ -1429,7 +1429,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongType(t *testing. knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("wrong type: value is string, known value type is knownvalue.BoolValue"), + ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), }, }, }) diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index 2f7e12c05..dc8829c97 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -5,9 +5,7 @@ package plancheck import ( "context" - "encoding/json" "fmt" - "math/big" "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -58,145 +56,15 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } switch reflect.TypeOf(result).Kind() { - case reflect.Bool: - v, ok := e.knownValue.(knownvalue.BoolValue) - - if !ok { - resp.Error = fmt.Errorf("wrong type: value is bool, known value type is %T", e.knownValue) - - return - } - - if err := v.CheckValue(result); err != nil { + case reflect.Bool, + reflect.Map, + reflect.Slice, + reflect.String: + if err := e.knownValue.CheckValue(result); err != nil { resp.Error = err return } - case reflect.Map: - elems := make(map[string]any) - - val := reflect.ValueOf(result) - - for _, key := range val.MapKeys() { - elems[key.String()] = val.MapIndex(key).Interface() - } - - switch t := e.knownValue.(type) { - case knownvalue.MapElements, - knownvalue.MapValue, - knownvalue.MapValuePartial, - knownvalue.ObjectAttributes, - knownvalue.ObjectValue, - knownvalue.ObjectValuePartial: - if err := t.CheckValue(elems); err != nil { - resp.Error = err - - return - } - default: - resp.Error = fmt.Errorf("wrong type: value is map, or object, known value type is %T", t) - - return - } - case reflect.Slice: - var elems []any - - val := reflect.ValueOf(result) - - for i := 0; i < val.Len(); i++ { - elems = append(elems, val.Index(i).Interface()) - } - - switch t := e.knownValue.(type) { - case knownvalue.ListElements, - knownvalue.ListValue, - knownvalue.ListValuePartial, - knownvalue.SetElements, - knownvalue.SetValue, - knownvalue.SetValuePartial: - if err := t.CheckValue(elems); err != nil { - resp.Error = err - - return - } - default: - resp.Error = fmt.Errorf("wrong type: value is list, or set, known value type is %T", t) - - return - } - case reflect.String: - jsonNum, jsonNumOk := result.(json.Number) - - if jsonNumOk { - float64Val, float64ValOk := e.knownValue.(knownvalue.Float64Value) - - int64Val, int64ValOk := e.knownValue.(knownvalue.Int64Value) - - numberValue, numberValOk := e.knownValue.(knownvalue.NumberValue) - - if !float64ValOk && !int64ValOk && !numberValOk { - resp.Error = fmt.Errorf("wrong type: value is number, known value type is %T", e.knownValue) - } - - switch { - case float64ValOk: - f, err := jsonNum.Float64() - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as float64", jsonNum.String()) - - return - } - - if err := float64Val.CheckValue(f); err != nil { - resp.Error = err - - return - } - case int64ValOk: - i, err := jsonNum.Int64() - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as int64", jsonNum.String()) - - return - } - - if err := int64Val.CheckValue(i); err != nil { - resp.Error = err - - return - } - case numberValOk: - f, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) - - if err != nil { - resp.Error = fmt.Errorf("%q could not be parsed as big.Float", jsonNum.String()) - - return - } - - if err := numberValue.CheckValue(f); err != nil { - resp.Error = err - - return - } - } - } else { - v, ok := e.knownValue.(knownvalue.StringValue) - - if !ok { - resp.Error = fmt.Errorf("wrong type: value is string, known value type is %T", e.knownValue) - - return - } - - if err := v.CheckValue(result); err != nil { - resp.Error = err - - return - } - } default: errorStr := fmt.Sprintf("unrecognised attribute type: %T, known value type is %T", result, e.knownValue) errorStr += "\n\nThis is an error in plancheck.ExpectKnownValue.\nPlease report this to the maintainers." diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 9957cc325..e4499bc01 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -130,7 +130,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is bool, known value type is knownvalue.Float64Value"), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), }, }, }) @@ -220,7 +220,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is number, known value type is knownvalue.StringValue"), + ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), }, }, }) @@ -377,7 +377,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is list, or set, known value type is knownvalue.MapValue"), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), }, }, }) @@ -730,7 +730,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("wrong type: value is map, or object, known value type is knownvalue.ListValue"), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), }, }, }) @@ -1313,7 +1313,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("wrong type: value is string, known value type is knownvalue.BoolValue"), + ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), }, }, }) From 6accadc9b5c1326412c8490bbf119c6ec06513d5 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Jan 2024 11:19:37 +0000 Subject: [PATCH 27/48] Adding StateCheck interface (#266) * Configuring when state checks are executed. * Testing that state checks are executed. --- helper/resource/state_checks.go | 29 +++++ helper/resource/state_checks_test.go | 22 ++++ helper/resource/testing.go | 12 ++ helper/resource/testing_new_config.go | 20 ++++ helper/resource/testing_new_config_test.go | 124 +++++++++++++++++++++ statecheck/doc.go | 5 + statecheck/state_check.go | 30 +++++ 7 files changed, 242 insertions(+) create mode 100644 helper/resource/state_checks.go create mode 100644 helper/resource/state_checks_test.go create mode 100644 statecheck/doc.go create mode 100644 statecheck/state_check.go diff --git a/helper/resource/state_checks.go b/helper/resource/state_checks.go new file mode 100644 index 000000000..66c850eae --- /dev/null +++ b/helper/resource/state_checks.go @@ -0,0 +1,29 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "errors" + + tfjson "github.com/hashicorp/terraform-json" + "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/terraform-plugin-testing/statecheck" +) + +func runStateChecks(ctx context.Context, t testing.T, state *tfjson.State, stateChecks []statecheck.StateCheck) error { + t.Helper() + + var result []error + + for _, stateCheck := range stateChecks { + resp := statecheck.CheckStateResponse{} + stateCheck.CheckState(ctx, statecheck.CheckStateRequest{State: state}, &resp) + + result = append(result, resp.Error) + } + + return errors.Join(result...) +} diff --git a/helper/resource/state_checks_test.go b/helper/resource/state_checks_test.go new file mode 100644 index 000000000..e8ab33753 --- /dev/null +++ b/helper/resource/state_checks_test.go @@ -0,0 +1,22 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-testing/statecheck" +) + +var _ statecheck.StateCheck = &stateCheckSpy{} + +type stateCheckSpy struct { + err error + called bool +} + +func (s *stateCheckSpy) CheckState(ctx context.Context, req statecheck.CheckStateRequest, resp *statecheck.CheckStateResponse) { + s.called = true + resp.Error = s.err +} diff --git a/helper/resource/testing.go b/helper/resource/testing.go index 581152f72..5abda4eaa 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/tfversion" @@ -590,6 +591,13 @@ type TestStep struct { // [plancheck]: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/plancheck RefreshPlanChecks RefreshPlanChecks + // ConfigStateChecks allow assertions to be made against the state file at different points of a Config (apply) test using a state check. + // Custom state checks can be created by implementing the [StateCheck] interface, or by using a StateCheck implementation from the provided [statecheck] package + // + // [StateCheck]: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#StateCheck + // [statecheck]: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck + ConfigStateChecks ConfigStateChecks + // PlanOnly can be set to only run `plan` with this configuration, and not // actually apply it. This is useful for ensuring config changes result in // no-op plans @@ -795,6 +803,10 @@ type RefreshPlanChecks struct { PostRefresh []plancheck.PlanCheck } +// ConfigStateChecks runs all state checks in the slice. This occurs after the apply and refresh of a Config test are run. +// All errors by state checks in this slice are aggregated, reported, and will result in a test failure. +type ConfigStateChecks []statecheck.StateCheck + // ParallelTest performs an acceptance test on a resource, allowing concurrency // with other ParallelTest. The number of concurrent tests is controlled by the // "go test" command -parallel flag. diff --git a/helper/resource/testing_new_config.go b/helper/resource/testing_new_config.go index 35e605c1d..17d3745fa 100644 --- a/helper/resource/testing_new_config.go +++ b/helper/resource/testing_new_config.go @@ -313,6 +313,26 @@ func testStepNewConfig(ctx context.Context, t testing.T, c TestCase, wd *plugint } } + // Run post-apply, post-refresh state checks + if len(step.ConfigStateChecks) > 0 { + var state *tfjson.State + + err = runProviderCommand(ctx, t, func() error { + var err error + state, err = wd.State(ctx) + return err + }, wd, providers) + + if err != nil { + return fmt.Errorf("Error retrieving post-apply, post-refresh state: %w", err) + } + + err = runStateChecks(ctx, t, state, step.ConfigStateChecks) + if err != nil { + return fmt.Errorf("Post-apply refresh state check(s) failed:\n%w", err) + } + } + // check if plan is empty if !planIsEmpty(plan, helper.TerraformVersion()) && !step.ExpectNonEmptyPlan { var stdout string diff --git a/helper/resource/testing_new_config_test.go b/helper/resource/testing_new_config_test.go index b54eb4282..fe0eb707e 100644 --- a/helper/resource/testing_new_config_test.go +++ b/helper/resource/testing_new_config_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider" "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver" "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource" @@ -717,3 +718,126 @@ func Test_ConfigPlanChecks_PostApplyPostRefresh_Errors(t *testing.T) { }, }) } + +func Test_ConfigStateChecks_Called(t *testing.T) { + t.Parallel() + + spy1 := &stateCheckSpy{} + spy2 := &stateCheckSpy{} + UnitTest(t, TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_0_0), // ProtoV6ProviderFactories + }, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), + }, + Steps: []TestStep{ + { + Config: `resource "test_resource" "test" {}`, + ConfigStateChecks: ConfigStateChecks{ + spy1, + spy2, + }, + }, + }, + }) + + if !spy1.called { + t.Error("expected ConfigStateChecks spy1 to be called at least once") + } + + if !spy2.called { + t.Error("expected ConfigStateChecks spy2 to be called at least once") + } +} + +func Test_ConfigStateChecks_Errors(t *testing.T) { + t.Parallel() + + spy1 := &stateCheckSpy{} + spy2 := &stateCheckSpy{ + err: errors.New("spy2 check failed"), + } + spy3 := &stateCheckSpy{ + err: errors.New("spy3 check failed"), + } + UnitTest(t, TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_0_0), // ProtoV6ProviderFactories + }, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), + }, + Steps: []TestStep{ + { + Config: `resource "test_resource" "test" {}`, + ConfigStateChecks: ConfigStateChecks{ + spy1, + spy2, + spy3, + }, + ExpectError: regexp.MustCompile(`.*?(spy2 check failed)\n.*?(spy3 check failed)`), + }, + }, + }) +} diff --git a/statecheck/doc.go b/statecheck/doc.go new file mode 100644 index 000000000..eba32447d --- /dev/null +++ b/statecheck/doc.go @@ -0,0 +1,5 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package statecheck contains the state check interface, request/response structs, and common state check implementations. +package statecheck diff --git a/statecheck/state_check.go b/statecheck/state_check.go new file mode 100644 index 000000000..cfd2da6b1 --- /dev/null +++ b/statecheck/state_check.go @@ -0,0 +1,30 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck + +import ( + "context" + + tfjson "github.com/hashicorp/terraform-json" +) + +// StateCheck defines an interface for implementing test logic that checks a state file and then returns an error +// if the state file does not match what is expected. +type StateCheck interface { + // CheckState should perform the state check. + CheckState(context.Context, CheckStateRequest, *CheckStateResponse) +} + +// CheckStateRequest is a request for an invoke of the CheckState function. +type CheckStateRequest struct { + // State represents a parsed state file, retrieved via the `terraform show -json` command. + State *tfjson.State +} + +// CheckStateResponse is a response to an invoke of the CheckState function. +type CheckStateResponse struct { + // Error is used to report the failure of a state check assertion and is combined with other StateCheck errors + // to be reported as a test failure. + Error error +} From 50b202fbd327aae6b8f8ec372e6cbbedf0b77d56 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Jan 2024 11:29:11 +0000 Subject: [PATCH 28/48] Adding validation to ensure state checks are only defined for config (apply) tests (#266) --- helper/resource/teststep_validate.go | 8 +++++++- helper/resource/teststep_validate_test.go | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/helper/resource/teststep_validate.go b/helper/resource/teststep_validate.go index d63db4dc8..8590ca466 100644 --- a/helper/resource/teststep_validate.go +++ b/helper/resource/teststep_validate.go @@ -15,7 +15,7 @@ import ( // testStepValidateRequest contains data for the (TestStep).validate() method. type testStepValidateRequest struct { // StepConfiguration contains the TestStep configuration derived from - // TestStep.Config or TestStep.ConfigDirectory. + // TestStep.Config, TestStep.ConfigDirectory, or TestStep.ConfigFile. StepConfiguration teststep.Config // StepNumber is the index of the TestStep in the TestCase.Steps. @@ -235,5 +235,11 @@ func (s TestStep) validate(ctx context.Context, req testStepValidateRequest) err return err } + if len(s.ConfigStateChecks) > 0 && req.StepConfiguration == nil { + err := fmt.Errorf("TestStep ConfigStateChecks must only be specified with Config, ConfigDirectory or ConfigFile") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + return nil } diff --git a/helper/resource/teststep_validate_test.go b/helper/resource/teststep_validate_test.go index c5f19a60e..6a326e003 100644 --- a/helper/resource/teststep_validate_test.go +++ b/helper/resource/teststep_validate_test.go @@ -466,6 +466,16 @@ func TestTestStepValidate(t *testing.T) { testStepValidateRequest: testStepValidateRequest{TestCaseHasProviders: true}, expectedError: errors.New("TestStep ConfigPlanChecks.PostApplyPostRefresh must only be specified with Config"), }, + "configstatechecks-not-config-mode": { + testStep: TestStep{ + ConfigStateChecks: ConfigStateChecks{ + &stateCheckSpy{}, + }, + RefreshState: true, + }, + testStepValidateRequest: testStepValidateRequest{TestCaseHasProviders: true}, + expectedError: errors.New("TestStep ConfigStateChecks must only be specified with Config"), + }, "refreshplanchecks-postrefresh-not-refresh-mode": { testStep: TestStep{ RefreshPlanChecks: RefreshPlanChecks{ From 64d470d45ebe542eaf542284d0f2a97d1e207fd0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Jan 2024 11:58:57 +0000 Subject: [PATCH 29/48] Adding ExpectKnownValue state check (#266) --- statecheck/expect_known_value.go | 94 ++ statecheck/expect_known_value_test.go | 1412 +++++++++++++++++++++++++ 2 files changed, 1506 insertions(+) create mode 100644 statecheck/expect_known_value.go create mode 100644 statecheck/expect_known_value_test.go diff --git a/statecheck/expect_known_value.go b/statecheck/expect_known_value.go new file mode 100644 index 000000000..2f073f15c --- /dev/null +++ b/statecheck/expect_known_value.go @@ -0,0 +1,94 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck + +import ( + "context" + "fmt" + "reflect" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +// Resource State Check +var _ StateCheck = expectKnownValue{} + +type expectKnownValue struct { + resourceAddress string + attributePath tfjsonpath.Path + knownValue knownvalue.Check +} + +// CheckState implements the state check logic. +func (e expectKnownValue) CheckState(ctx context.Context, req CheckStateRequest, resp *CheckStateResponse) { + var rc *tfjson.StateResource + + if req.State.Values == nil { + resp.Error = fmt.Errorf("state does not contain any state values") + } + + if req.State.Values.RootModule == nil { + resp.Error = fmt.Errorf("state does not contain a root module") + } + + for _, resourceChange := range req.State.Values.RootModule.Resources { + if e.resourceAddress == resourceChange.Address { + rc = resourceChange + + break + } + } + + if rc == nil { + resp.Error = fmt.Errorf("%s - Resource not found in state", e.resourceAddress) + + return + } + + result, err := tfjsonpath.Traverse(rc.AttributeValues, e.attributePath) + + if err != nil { + resp.Error = err + + return + } + + if result == nil { + resp.Error = fmt.Errorf("value is null") + + return + } + + switch reflect.TypeOf(result).Kind() { + case reflect.Bool, + reflect.Map, + reflect.Slice, + reflect.String: + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err + + return + } + default: + errorStr := fmt.Sprintf("unrecognised attribute type: %T, known value type is %T", result, e.knownValue) + errorStr += "\n\nThis is an error in statecheck.ExpectKnownValue.\nPlease report this to the maintainers." + + resp.Error = fmt.Errorf(errorStr) + + return + } +} + +// ExpectKnownValue returns a state check that asserts that the specified attribute at the given resource +// has a known type and value. +func ExpectKnownValue(resourceAddress string, attributePath tfjsonpath.Path, knownValue knownvalue.Check) StateCheck { + return expectKnownValue{ + resourceAddress: resourceAddress, + attributePath: attributePath, + knownValue: knownValue, + } +} diff --git a/statecheck/expect_known_value_test.go b/statecheck/expect_known_value_test.go new file mode 100644 index 000000000..bd1024891 --- /dev/null +++ b/statecheck/expect_known_value_test.go @@ -0,0 +1,1412 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck_test + +import ( + "context" + "fmt" + "math/big" + "regexp" + "testing" + + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +func TestExpectKnownValue_CheckState_ResourceNotFound(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.two", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + ExpectError: regexp.MustCompile("test_resource.two - Resource not found in state"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {}`, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + ExpectError: regexp.MustCompile("value is null"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Bool_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.Float64ValueExact(1.23), + ), + }, + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Bool_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(false), + ), + }, + ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.Float64ValueExact(1.23), + ), + }, + }, + }, + }) +} + +// We do not need equivalent tests for Int64 and Number as they all test the same logic. +func TestExpectKnownValue_CheckState_Float64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.StringValueExact("str"), + ), + }, + ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Float64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("float_attribute"), + knownvalue.Float64ValueExact(3.21), + ), + }, + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.Int64ValueExact(123), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Int64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.Int64ValueExact(321), + ), + }, + ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_List_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{}), + ), + }, + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_List_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value3"), + knownvalue.StringValueExact("value4"), + }), + ), + }, + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +// No need to check KnownValueWrongType for ListPartial as all lists, and sets are []any in +// tfjson.State. +func TestExpectKnownValue_CheckState_ListPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_ListElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_ListElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_attribute"), + knownvalue.ListElementsExact(3), + ), + }, + ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_nested_block"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("str"), + }), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_ListNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_nested_block"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_ListNestedBlockElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("list_nested_block"), + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Map_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{}), + ), + }, + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Map_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key3": knownvalue.StringValueExact("value3"), + "key4": knownvalue.StringValueExact("value4"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_MapPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key3": knownvalue.StringValueExact("value1"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_MapElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_MapElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("map_attribute"), + knownvalue.MapElementsExact(3), + ), + }, + ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Number(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("123", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NumberValueExact(f), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Number_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("321", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("int_attribute"), + knownvalue.NumberValueExact(f), + ), + }, + ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value2"), + knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_Set_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_SetPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_SetElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_attribute"), + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_SetNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_nested_block"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("str"), + }), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_SetNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_nested_block"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_SetNestedBlockElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("set_nested_block"), + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.StringValueExact("str")), + }, + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_String_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.BoolValueExact(true)), + }, + ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_String_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("string_attribute"), + knownvalue.StringValueExact("rts")), + }, + ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + }, + }, + }) +} + +func TestExpectKnownValue_CheckState_UnknownAttributeType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + knownValue knownvalue.Check + req statecheck.CheckStateRequest + expectedErr error + }{ + "unrecognised-type": { + knownValue: knownvalue.Int64ValueExact(123), + req: statecheck.CheckStateRequest{ + State: &tfjson.State{ + Values: &tfjson.StateValues{ + RootModule: &tfjson.StateModule{ + Resources: []*tfjson.StateResource{ + { + Address: "example_resource.test", + AttributeValues: map[string]any{ + "attribute": float32(123), + }, + }, + }, + }, + }, + }, + }, + expectedErr: fmt.Errorf("unrecognised attribute type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in statecheck.ExpectKnownValue.\nPlease report this to the maintainers."), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + e := statecheck.ExpectKnownValue("example_resource.test", tfjsonpath.New("attribute"), testCase.knownValue) + + resp := statecheck.CheckStateResponse{} + + e.CheckState(context.Background(), testCase.req, &resp) + + if diff := cmp.Diff(resp.Error, testCase.expectedErr, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +var equateErrorMessage = cmp.Comparer(func(x, y error) bool { + if x == nil || y == nil { + return x == nil && y == nil + } + + return x.Error() == y.Error() +}) + +func testProvider() *schema.Provider { + return &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test_resource": { + CreateContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { + d.SetId("test") + return nil + }, + UpdateContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil + }, + DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil + }, + ReadContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil + }, + Schema: map[string]*schema.Schema{ + "bool_attribute": { + Optional: true, + Type: schema.TypeBool, + }, + "float_attribute": { + Optional: true, + Type: schema.TypeFloat, + }, + "int_attribute": { + Optional: true, + Type: schema.TypeInt, + }, + "list_attribute": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "list_nested_block": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "list_nested_block_attribute": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "map_attribute": { + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "set_attribute": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "set_nested_block": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "set_nested_block_attribute": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "string_attribute": { + Optional: true, + Type: schema.TypeString, + }, + }, + }, + }, + } +} From 8f6fe6dba8a4288cdc2282e8656b13f2bebc5c03 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Jan 2024 13:34:14 +0000 Subject: [PATCH 30/48] Adding ExpectKnownOutputValue state check (#266) --- statecheck/expect_known_output_value.go | 92 ++ statecheck/expect_known_output_value_test.go | 1432 ++++++++++++++++++ statecheck/expect_known_value.go | 4 + 3 files changed, 1528 insertions(+) create mode 100644 statecheck/expect_known_output_value.go create mode 100644 statecheck/expect_known_output_value_test.go diff --git a/statecheck/expect_known_output_value.go b/statecheck/expect_known_output_value.go new file mode 100644 index 000000000..2809dff46 --- /dev/null +++ b/statecheck/expect_known_output_value.go @@ -0,0 +1,92 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck + +import ( + "context" + "fmt" + "reflect" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +// Resource State Check +var _ StateCheck = expectKnownOutputValue{} + +type expectKnownOutputValue struct { + outputAddress string + knownValue knownvalue.Check +} + +// CheckState implements the state check logic. +func (e expectKnownOutputValue) CheckState(ctx context.Context, req CheckStateRequest, resp *CheckStateResponse) { + var output *tfjson.StateOutput + + if req.State == nil { + resp.Error = fmt.Errorf("state is nil") + } + + if req.State.Values == nil { + resp.Error = fmt.Errorf("state does not contain any state values") + } + + for address, oc := range req.State.Values.Outputs { + if e.outputAddress == address { + output = oc + + break + } + } + + if output == nil { + resp.Error = fmt.Errorf("%s - Output not found in state", e.outputAddress) + + return + } + + result, err := tfjsonpath.Traverse(output.Value, tfjsonpath.Path{}) + + if err != nil { + resp.Error = err + + return + } + + if result == nil { + resp.Error = fmt.Errorf("value is null") + + return + } + + switch reflect.TypeOf(result).Kind() { + case reflect.Bool, + reflect.Map, + reflect.Slice, + reflect.String: + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err + + return + } + default: + errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) + errorStr += "\n\nThis is an error in statecheck.ExpectKnownOutputValue.\nPlease report this to the maintainers." + + resp.Error = fmt.Errorf(errorStr) + + return + } +} + +// ExpectKnownOutputValue returns a state check that asserts that the specified value +// has a known type, and value. +func ExpectKnownOutputValue(outputAddress string, knownValue knownvalue.Check) StateCheck { + return expectKnownOutputValue{ + outputAddress: outputAddress, + knownValue: knownValue, + } +} diff --git a/statecheck/expect_known_output_value_test.go b/statecheck/expect_known_output_value_test.go new file mode 100644 index 000000000..1c1cfcaa7 --- /dev/null +++ b/statecheck/expect_known_output_value_test.go @@ -0,0 +1,1432 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck_test + +import ( + "context" + "fmt" + "math/big" + "regexp" + "testing" + + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" +) + +func TestExpectKnownOutputValue_CheckState_OutputNotFound(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "bool_not_found", + knownvalue.BoolValueExact(true), + ), + }, + ExpectError: regexp.MustCompile("bool_not_found - Output not found in state"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {} + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.BoolValueExact(true), + ), + }, + ExpectError: regexp.MustCompile("bool_output - Output not found in state"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Bool_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.Float64ValueExact(1.23), + ), + }, + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Bool_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.BoolValueExact(false), + ), + }, + ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output float64_output { + value = test_resource.one.float_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "float64_output", + knownvalue.Float64ValueExact(1.23), + ), + }, + }, + }, + }) +} + +// We do not need equivalent tests for Int64 and Number as they all test the same logic. +func TestExpectKnownOutputValue_CheckState_Float64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output float64_output { + value = test_resource.one.float_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "float64_output", + knownvalue.StringValueExact("str"), + ), + }, + ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Float64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output float64_output { + value = test_resource.one.float_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "float64_output", + knownvalue.Float64ValueExact(3.21), + ), + }, + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.Int64ValueExact(123), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Int64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.Int64ValueExact(321), + ), + }, + ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_List_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.MapValueExact(map[string]knownvalue.Check{}), + ), + }, + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_List_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value3"), + knownvalue.StringValueExact("value4"), + }), + ), + }, + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +// No need to check KnownValueWrongType for ListPartial as all lists, and sets are []any in +// tfjson.State. +func TestExpectKnownOutputValue_CheckState_ListPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_ListElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_ListElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output list_output { + value = test_resource.one.list_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_output", + knownvalue.ListElementsExact(3), + ), + }, + ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output list_nested_block_output { + value = test_resource.one.list_nested_block + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_nested_block_output", + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("str"), + }), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_ListNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output list_nested_block_output { + value = test_resource.one.list_nested_block + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_nested_block_output", + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_ListNestedBlockElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output list_nested_block_output { + value = test_resource.one.list_nested_block + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "list_nested_block_output", + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Map_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.ListValueExact([]knownvalue.Check{}), + ), + }, + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Map_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key3": knownvalue.StringValueExact("value3"), + "key4": knownvalue.StringValueExact("value4"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_MapPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key3": knownvalue.StringValueExact("value1"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_MapElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.MapElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_MapElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output map_output { + value = test_resource.one.map_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "map_output", + knownvalue.MapElementsExact(3), + ), + }, + ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Number(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("123", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NumberValueExact(f), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Number_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("321", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output int64_output { + value = test_resource.one.int_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "int64_output", + knownvalue.NumberValueExact(f), + ), + }, + ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_output", + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_Set_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_output", + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_output", + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_SetPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_output", + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_SetElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output set_output { + value = test_resource.one.set_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_output", + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_SetNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output set_nested_block_output { + value = test_resource.one.set_nested_block + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_nested_block_output", + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("str"), + }), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_SetNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output set_nested_block_output { + value = test_resource.one.set_nested_block + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_nested_block_output", + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_SetNestedBlockElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output set_nested_block_output { + value = test_resource.one.set_nested_block + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "set_nested_block_output", + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output string_output { + value = test_resource.one.string_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "string_output", + knownvalue.StringValueExact("str")), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_String_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output string_output { + value = test_resource.one.string_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "string_output", + knownvalue.BoolValueExact(true)), + }, + ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_String_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output string_output { + value = test_resource.one.string_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "string_output", + knownvalue.StringValueExact("rts")), + }, + ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + }, + }, + }) +} + +func TestExpectKnownOutputValue_CheckState_UnknownAttributeType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + knownValue knownvalue.Check + req statecheck.CheckStateRequest + expectedErr error + }{ + "unrecognised-type": { + knownValue: knownvalue.Int64ValueExact(123), + req: statecheck.CheckStateRequest{ + State: &tfjson.State{ + Values: &tfjson.StateValues{ + Outputs: map[string]*tfjson.StateOutput{ + "float32_output": { + Value: float32(123), + }, + }, + }, + }, + }, + expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in statecheck.ExpectKnownOutputValue.\nPlease report this to the maintainers."), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + e := statecheck.ExpectKnownOutputValue("float32_output", testCase.knownValue) + + resp := statecheck.CheckStateResponse{} + + e.CheckState(context.Background(), testCase.req, &resp) + + if diff := cmp.Diff(resp.Error, testCase.expectedErr, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/statecheck/expect_known_value.go b/statecheck/expect_known_value.go index 2f073f15c..b8d5a6157 100644 --- a/statecheck/expect_known_value.go +++ b/statecheck/expect_known_value.go @@ -27,6 +27,10 @@ type expectKnownValue struct { func (e expectKnownValue) CheckState(ctx context.Context, req CheckStateRequest, resp *CheckStateResponse) { var rc *tfjson.StateResource + if req.State == nil { + resp.Error = fmt.Errorf("state is nil") + } + if req.State.Values == nil { resp.Error = fmt.Errorf("state does not contain any state values") } From a90b4d9276cabb45f1516375425034d0f7034465 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Jan 2024 13:48:21 +0000 Subject: [PATCH 31/48] Adding ExpectKnownOutputValueAtPath state check (#266) --- .../expect_known_output_value_at_path.go | 94 + .../expect_known_output_value_at_path_test.go | 1755 +++++++++++++++++ 2 files changed, 1849 insertions(+) create mode 100644 statecheck/expect_known_output_value_at_path.go create mode 100644 statecheck/expect_known_output_value_at_path_test.go diff --git a/statecheck/expect_known_output_value_at_path.go b/statecheck/expect_known_output_value_at_path.go new file mode 100644 index 000000000..31d4516b1 --- /dev/null +++ b/statecheck/expect_known_output_value_at_path.go @@ -0,0 +1,94 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck + +import ( + "context" + "fmt" + "reflect" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +// Resource State Check +var _ StateCheck = expectKnownOutputValueAtPath{} + +type expectKnownOutputValueAtPath struct { + outputAddress string + outputPath tfjsonpath.Path + knownValue knownvalue.Check +} + +// CheckState implements the state check logic. +func (e expectKnownOutputValueAtPath) CheckState(ctx context.Context, req CheckStateRequest, resp *CheckStateResponse) { + var output *tfjson.StateOutput + + if req.State == nil { + resp.Error = fmt.Errorf("state is nil") + } + + if req.State.Values == nil { + resp.Error = fmt.Errorf("state does not contain any state values") + } + + for address, oc := range req.State.Values.Outputs { + if e.outputAddress == address { + output = oc + + break + } + } + + if output == nil { + resp.Error = fmt.Errorf("%s - Output not found in state", e.outputAddress) + + return + } + + result, err := tfjsonpath.Traverse(output.Value, e.outputPath) + + if err != nil { + resp.Error = err + + return + } + + if result == nil { + resp.Error = fmt.Errorf("value is null") + + return + } + + switch reflect.TypeOf(result).Kind() { + case reflect.Bool, + reflect.Map, + reflect.Slice, + reflect.String: + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err + + return + } + default: + errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) + errorStr += "\n\nThis is an error in statecheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers." + + resp.Error = fmt.Errorf(errorStr) + + return + } +} + +// ExpectKnownOutputValueAtPath returns a state check that asserts that the specified output at the given path +// has a known type and value. +func ExpectKnownOutputValueAtPath(outputAddress string, outputPath tfjsonpath.Path, knownValue knownvalue.Check) StateCheck { + return expectKnownOutputValueAtPath{ + outputAddress: outputAddress, + outputPath: outputPath, + knownValue: knownValue, + } +} diff --git a/statecheck/expect_known_output_value_at_path_test.go b/statecheck/expect_known_output_value_at_path_test.go new file mode 100644 index 000000000..6b9795f90 --- /dev/null +++ b/statecheck/expect_known_output_value_at_path_test.go @@ -0,0 +1,1755 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck_test + +import ( + "context" + "fmt" + "math/big" + "regexp" + "testing" + + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestExpectKnownOutputValueAtPath_CheckState_ResourceNotFound(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_two_output", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + ExpectError: regexp.MustCompile("test_resource_two_output - Output not found in state"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {} + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + ExpectError: regexp.MustCompile("value is null"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.Float64ValueExact(1.23), + ), + }, + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(false), + ), + }, + ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Float64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("float_attribute"), + knownvalue.Float64ValueExact(1.23), + ), + }, + }, + }, + }) +} + +// We do not need equivalent tests for Int64 and Number as they all test the same logic. +func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("float_attribute"), + knownvalue.StringValueExact("str"), + ), + }, + ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + float_attribute = 1.23 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("float_attribute"), + knownvalue.Float64ValueExact(3.21), + ), + }, + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Int64(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.Int64ValueExact(123), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Int64_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.Int64ValueExact(321), + ), + }, + ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_List(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{}), + ), + }, + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value3"), + knownvalue.StringValueExact("value4"), + }), + ), + }, + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_ListPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +// No need to check KnownValueWrongType for ListPartial as all lists, and sets are []any in +// tfjson.State. +func TestExpectKnownOutputValueAtPath_CheckState_ListPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 0: knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_ListElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_ListElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_attribute"), + knownvalue.ListElementsExact(3), + ), + }, + ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_nested_block"), + knownvalue.ListValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("str"), + }), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_nested_block"), + knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + list_nested_block { + list_nested_block_attribute = "str" + } + list_nested_block { + list_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("list_nested_block"), + knownvalue.ListElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Map(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + "key2": knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.ListValueExact([]knownvalue.Check{}), + ), + }, + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "key3": knownvalue.StringValueExact("value3"), + "key4": knownvalue.StringValueExact("value4"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_MapPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key1": knownvalue.StringValueExact("value1"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_MapPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + "key3": knownvalue.StringValueExact("value1"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_MapElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.MapElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_MapElements_WrongNum(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + map_attribute = { + key1 = "value1" + key2 = "value2" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("map_attribute"), + knownvalue.MapElementsExact(3), + ), + }, + ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Number(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("123", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NumberValueExact(f), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Number_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + f, _, err := big.ParseFloat("321", 10, 512, big.ToNearestEven) + + if err != nil { + t.Errorf("%s", err) + } + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + int_attribute = 123 + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("int_attribute"), + knownvalue.NumberValueExact(f), + ), + }, + ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Set(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_Set_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.StringValueExact("value1"), + knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_SetPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value2"), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_SetPartial_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.StringValueExact("value3"), + }), + ), + }, + ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_SetElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_attribute = [ + "value1", + "value2" + ] + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_attribute"), + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlock(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_nested_block"), + knownvalue.SetValueExact([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("str"), + }), + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockPartial(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_nested_block"), + knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.MapValueExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + }), + }), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockElements(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + set_nested_block { + set_nested_block_attribute = "str" + } + set_nested_block { + set_nested_block_attribute = "rts" + } + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("set_nested_block"), + knownvalue.SetElementsExact(2), + ), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_String(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("string_attribute"), + knownvalue.StringValueExact("str")), + }, + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongType(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("string_attribute"), + knownvalue.BoolValueExact(true)), + }, + ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongValue(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProvider(), nil + }, + }, + // Prior to Terraform v1.3.0 a statened output is marked as fully unknown + // if any attribute is unknown. The id attribute within the test provider + // is unknown. + // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_3_0), + }, + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + string_attribute = "str" + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("string_attribute"), + knownvalue.StringValueExact("rts")), + }, + ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + }, + }, + }) +} + +func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + knownValue knownvalue.Check + req statecheck.CheckStateRequest + expectedErr error + }{ + "unrecognised-type": { + knownValue: knownvalue.Int64ValueExact(123), + req: statecheck.CheckStateRequest{ + State: &tfjson.State{ + Values: &tfjson.StateValues{ + Outputs: map[string]*tfjson.StateOutput{ + "float32_output": { + Value: float32(123), + }, + }, + }, + }, + }, + expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in statecheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers."), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + e := statecheck.ExpectKnownOutputValueAtPath("float32_output", tfjsonpath.Path{}, testCase.knownValue) + + resp := statecheck.CheckStateResponse{} + + e.CheckState(context.Background(), testCase.req, &resp) + + if diff := cmp.Diff(resp.Error, testCase.expectedErr, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} From 26efbb82cf737b31efaea6274d7f80ff90e5c2ce Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 10 Jan 2024 10:45:42 +0000 Subject: [PATCH 32/48] Modifying ExpectKnown to allow for checking of null values (#266) --- knownvalue/null.go | 34 +++ knownvalue/null_test.go | 61 ++++ statecheck/expect_known_output_value.go | 24 +- .../expect_known_output_value_at_path.go | 24 +- .../expect_known_output_value_at_path_test.go | 286 +----------------- statecheck/expect_known_output_value_test.go | 6 +- statecheck/expect_known_value.go | 26 +- statecheck/expect_known_value_test.go | 5 +- 8 files changed, 110 insertions(+), 356 deletions(-) create mode 100644 knownvalue/null.go create mode 100644 knownvalue/null_test.go diff --git a/knownvalue/null.go b/knownvalue/null.go new file mode 100644 index 000000000..93e773cb0 --- /dev/null +++ b/knownvalue/null.go @@ -0,0 +1,34 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "fmt" +) + +var _ Check = NullValue{} + +// NullValue is a Check for asserting equality between the value supplied +// to NullValueExact and the value passed to the CheckValue method. +type NullValue struct{} + +// CheckValue determines whether the passed value is of nil. +func (v NullValue) CheckValue(other any) error { + if other != nil { + return fmt.Errorf("expected value nil for NullValue check, got: %T", other) + } + + return nil +} + +// String returns the string representation of nil. +func (v NullValue) String() string { + return "nil" +} + +// NullValueExact returns a Check for asserting equality nil +// and the value passed to the CheckValue method. +func NullValueExact() NullValue { + return NullValue{} +} diff --git a/knownvalue/null_test.go b/knownvalue/null_test.go new file mode 100644 index 000000000..b185ca220 --- /dev/null +++ b/knownvalue/null_test.go @@ -0,0 +1,61 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestNullValue_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.NullValue + other any + expectedError error + }{ + "zero-nil": {}, + "zero-other": { + other: nil, // checking against the underlying value field zero-value + }, + "not-nil": { + self: knownvalue.NullValueExact(), + other: false, + expectedError: fmt.Errorf("expected value nil for NullValue check, got: bool"), + }, + "equal": { + self: knownvalue.NullValueExact(), + other: nil, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestNullValue_String(t *testing.T) { + t.Parallel() + + got := knownvalue.NullValueExact().String() + + if diff := cmp.Diff(got, "nil"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/statecheck/expect_known_output_value.go b/statecheck/expect_known_output_value.go index 2809dff46..1cf6b69e8 100644 --- a/statecheck/expect_known_output_value.go +++ b/statecheck/expect_known_output_value.go @@ -6,7 +6,6 @@ package statecheck import ( "context" "fmt" - "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -56,27 +55,8 @@ func (e expectKnownOutputValue) CheckState(ctx context.Context, req CheckStateRe return } - if result == nil { - resp.Error = fmt.Errorf("value is null") - - return - } - - switch reflect.TypeOf(result).Kind() { - case reflect.Bool, - reflect.Map, - reflect.Slice, - reflect.String: - if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err - - return - } - default: - errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) - errorStr += "\n\nThis is an error in statecheck.ExpectKnownOutputValue.\nPlease report this to the maintainers." - - resp.Error = fmt.Errorf(errorStr) + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err return } diff --git a/statecheck/expect_known_output_value_at_path.go b/statecheck/expect_known_output_value_at_path.go index 31d4516b1..7ff704b06 100644 --- a/statecheck/expect_known_output_value_at_path.go +++ b/statecheck/expect_known_output_value_at_path.go @@ -6,7 +6,6 @@ package statecheck import ( "context" "fmt" - "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -57,27 +56,8 @@ func (e expectKnownOutputValueAtPath) CheckState(ctx context.Context, req CheckS return } - if result == nil { - resp.Error = fmt.Errorf("value is null") - - return - } - - switch reflect.TypeOf(result).Kind() { - case reflect.Bool, - reflect.Map, - reflect.Slice, - reflect.String: - if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err - - return - } - default: - errorStr := fmt.Sprintf("unrecognised output type: %T, known value type is %T", result, e.knownValue) - errorStr += "\n\nThis is an error in statecheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers." - - resp.Error = fmt.Errorf(errorStr) + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err return } diff --git a/statecheck/expect_known_output_value_at_path_test.go b/statecheck/expect_known_output_value_at_path_test.go index 6b9795f90..371847b69 100644 --- a/statecheck/expect_known_output_value_at_path_test.go +++ b/statecheck/expect_known_output_value_at_path_test.go @@ -18,7 +18,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" - "github.com/hashicorp/terraform-plugin-testing/tfversion" ) func TestExpectKnownOutputValueAtPath_CheckState_ResourceNotFound(t *testing.T) { @@ -30,13 +29,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ResourceNotFound(t *testing.T) return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -69,13 +61,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_AttributeValueNull(t *testing.T return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" {} @@ -88,10 +73,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_AttributeValueNull(t *testing.T statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.NullValueExact(), ), }, - ExpectError: regexp.MustCompile("value is null"), }, }, }) @@ -106,13 +90,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -144,13 +121,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongType(t *tes return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -183,13 +153,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongValue(t *te return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -222,13 +185,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -261,13 +217,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongType(t * return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -300,13 +249,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongValue(t return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -339,13 +281,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Int64(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -377,13 +312,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Int64_KnownValueWrongValue(t *t return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -416,13 +344,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_List(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -460,13 +381,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongType(t *tes return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -502,13 +416,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongValue(t *te return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -547,13 +454,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListPartial(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -592,13 +492,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListPartial_KnownValueWrongValu return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -636,13 +529,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListElements(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -677,13 +563,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListElements_WrongNum(t *testin return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -719,13 +598,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlock(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -769,13 +641,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockPartial(t *testi return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -816,13 +681,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockElements(t *test return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -859,13 +717,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -903,13 +754,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongType(t *test return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -945,13 +789,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongValue(t *tes return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -990,13 +827,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapPartial(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1033,13 +863,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapPartial_KnownValueWrongValue return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1077,13 +900,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapElements(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1118,13 +934,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapElements_WrongNum(t *testing return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1166,13 +975,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Number(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1210,13 +1012,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Number_KnownValueWrongValue(t * return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1249,13 +1044,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Set(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1293,13 +1081,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_Set_KnownValueWrongValue(t *tes return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1338,13 +1119,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetPartial(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1381,13 +1155,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetPartial_KnownValueWrongValue return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1425,13 +1192,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetElements(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1466,13 +1226,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlock(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1516,13 +1269,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockPartial(t *testin return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1563,13 +1309,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockElements(t *testi return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1606,13 +1345,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_String(t *testing.T) { return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1643,13 +1375,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongType(t *t return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1681,13 +1406,6 @@ func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongValue(t * return testProvider(), nil }, }, - // Prior to Terraform v1.3.0 a statened output is marked as fully unknown - // if any attribute is unknown. The id attribute within the test provider - // is unknown. - // Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022 - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_3_0), - }, Steps: []r.TestStep{ { Config: `resource "test_resource" "one" { @@ -1731,7 +1449,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing }, }, }, - expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in statecheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers."), + expectedErr: fmt.Errorf("expected json.Number value for Int64Value check, got: float32"), }, } diff --git a/statecheck/expect_known_output_value_test.go b/statecheck/expect_known_output_value_test.go index 1c1cfcaa7..e081b0716 100644 --- a/statecheck/expect_known_output_value_test.go +++ b/statecheck/expect_known_output_value_test.go @@ -50,6 +50,10 @@ func TestExpectKnownOutputValue_CheckState_OutputNotFound(t *testing.T) { }) } +// TestExpectKnownOutputValue_CheckState_AttributeValueNull shows that outputs that reference +// null values do not appear in state. Indicating that there is no way to discriminate +// between null outputs and non-existent outputs. +// Reference: https://github.com/hashicorp/terraform/issues/34080 func TestExpectKnownOutputValue_CheckState_AttributeValueNull(t *testing.T) { t.Parallel() @@ -1408,7 +1412,7 @@ func TestExpectKnownOutputValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in statecheck.ExpectKnownOutputValue.\nPlease report this to the maintainers."), + expectedErr: fmt.Errorf("expected json.Number value for Int64Value check, got: float32"), }, } diff --git a/statecheck/expect_known_value.go b/statecheck/expect_known_value.go index b8d5a6157..096699cba 100644 --- a/statecheck/expect_known_value.go +++ b/statecheck/expect_known_value.go @@ -6,7 +6,6 @@ package statecheck import ( "context" "fmt" - "reflect" tfjson "github.com/hashicorp/terraform-json" @@ -61,29 +60,8 @@ func (e expectKnownValue) CheckState(ctx context.Context, req CheckStateRequest, return } - if result == nil { - resp.Error = fmt.Errorf("value is null") - - return - } - - switch reflect.TypeOf(result).Kind() { - case reflect.Bool, - reflect.Map, - reflect.Slice, - reflect.String: - if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err - - return - } - default: - errorStr := fmt.Sprintf("unrecognised attribute type: %T, known value type is %T", result, e.knownValue) - errorStr += "\n\nThis is an error in statecheck.ExpectKnownValue.\nPlease report this to the maintainers." - - resp.Error = fmt.Errorf(errorStr) - - return + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err } } diff --git a/statecheck/expect_known_value_test.go b/statecheck/expect_known_value_test.go index bd1024891..ce2d0a5c9 100644 --- a/statecheck/expect_known_value_test.go +++ b/statecheck/expect_known_value_test.go @@ -65,10 +65,9 @@ func TestExpectKnownValue_CheckState_AttributeValueNull(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.NullValueExact(), ), }, - ExpectError: regexp.MustCompile("value is null"), }, }, }) @@ -1295,7 +1294,7 @@ func TestExpectKnownValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("unrecognised attribute type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in statecheck.ExpectKnownValue.\nPlease report this to the maintainers."), + expectedErr: fmt.Errorf("expected json.Number value for Int64Value check, got: float32"), }, } From 7bc660cfab2675e4c635de6edbdbd4559a86dd42 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 10 Jan 2024 12:07:10 +0000 Subject: [PATCH 33/48] Adding ExpectSensitiveValue state check (#266) --- statecheck/expect_sensitive_value.go | 95 +++++++ statecheck/expect_sensitive_value_test.go | 308 ++++++++++++++++++++++ tfversion/versions.go | 1 + 3 files changed, 404 insertions(+) create mode 100644 statecheck/expect_sensitive_value.go create mode 100644 statecheck/expect_sensitive_value_test.go diff --git a/statecheck/expect_sensitive_value.go b/statecheck/expect_sensitive_value.go new file mode 100644 index 000000000..7e8ec7325 --- /dev/null +++ b/statecheck/expect_sensitive_value.go @@ -0,0 +1,95 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck + +import ( + "context" + "encoding/json" + "fmt" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +var _ StateCheck = expectSensitiveValue{} + +type expectSensitiveValue struct { + resourceAddress string + attributePath tfjsonpath.Path +} + +// CheckState implements the state check logic. +func (e expectSensitiveValue) CheckState(ctx context.Context, req CheckStateRequest, resp *CheckStateResponse) { + var rc *tfjson.StateResource + + if req.State == nil { + resp.Error = fmt.Errorf("state is nil") + } + + if req.State.Values == nil { + resp.Error = fmt.Errorf("state does not contain any state values") + } + + if req.State.Values.RootModule == nil { + resp.Error = fmt.Errorf("state does not contain a root module") + } + + for _, resourceChange := range req.State.Values.RootModule.Resources { + if e.resourceAddress == resourceChange.Address { + rc = resourceChange + + break + } + } + + if rc == nil { + resp.Error = fmt.Errorf("%s - Resource not found in state", e.resourceAddress) + + return + } + + var data map[string]any + + err := json.Unmarshal(rc.SensitiveValues, &data) + + if err != nil { + resp.Error = fmt.Errorf("could not unmarshal SensitiveValues: %s", err) + + return + } + + result, err := tfjsonpath.Traverse(data, e.attributePath) + + if err != nil { + resp.Error = err + + return + } + + isSensitive, ok := result.(bool) + if !ok { + resp.Error = fmt.Errorf("invalid path: the path value cannot be asserted as bool") + return + } + + if !isSensitive { + resp.Error = fmt.Errorf("attribute at path is not sensitive") + return + } + + return +} + +// ExpectSensitiveValue returns a state check that asserts that the specified attribute at the given resource has a sensitive value. +// +// Due to implementation differences between the terraform-plugin-sdk and the terraform-plugin-framework, representation of sensitive +// values may differ. For example, terraform-plugin-sdk based providers may have less precise representations of sensitive values, such +// as marking whole maps as sensitive rather than individual element values. +func ExpectSensitiveValue(resourceAddress string, attributePath tfjsonpath.Path) StateCheck { + return expectSensitiveValue{ + resourceAddress: resourceAddress, + attributePath: attributePath, + } +} diff --git a/statecheck/expect_sensitive_value_test.go b/statecheck/expect_sensitive_value_test.go new file mode 100644 index 000000000..5723d73b4 --- /dev/null +++ b/statecheck/expect_sensitive_value_test.go @@ -0,0 +1,308 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package statecheck_test + +import ( + "context" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func Test_ExpectSensitiveValue_SensitiveStringAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + sensitive_string_attribute = "test" + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("sensitive_string_attribute")), + }, + }, + }, + }) +} + +func Test_ExpectSensitiveValue_SensitiveListAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + sensitive_list_attribute = ["value1"] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("sensitive_list_attribute")), + }, + }, + }, + }) +} + +func Test_ExpectSensitiveValue_SensitiveSetAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + sensitive_set_attribute = ["value1"] + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("sensitive_set_attribute")), + }, + }, + }, + }) +} + +func Test_ExpectSensitiveValue_SensitiveMapAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + sensitive_map_attribute = { + key1 = "value1", + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("sensitive_map_attribute")), + }, + }, + }, + }) +} + +func Test_ExpectSensitiveValue_ListNestedBlock_SensitiveAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + list_nested_block_sensitive_attribute { + sensitive_list_nested_block_attribute = "sensitive-test" + list_nested_block_attribute = "test" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("list_nested_block_sensitive_attribute").AtSliceIndex(0). + AtMapKey("sensitive_list_nested_block_attribute")), + }, + }, + }, + }) +} + +func Test_ExpectSensitiveValue_SetNestedBlock_SensitiveAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + set_nested_block_sensitive_attribute { + sensitive_set_nested_block_attribute = "sensitive-test" + set_nested_block_attribute = "test" + } + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("set_nested_block_sensitive_attribute")), + }, + }, + }, + }) +} + +func Test_ExpectSensitiveValue_ExpectError_ResourceNotFound(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "test": func() (*schema.Provider, error) { //nolint:unparam // required signature + return testProviderSensitive(), nil + }, + }, + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" {} + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.two", tfjsonpath.New("set_attribute")), + }, + ExpectError: regexp.MustCompile(`test_resource.two - Resource not found in state`), + }, + }, + }) +} + +func testProviderSensitive() *schema.Provider { + return &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test_resource": { + CreateContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { + d.SetId("test") + return nil + }, + UpdateContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil + }, + DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil + }, + ReadContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil + }, + Schema: map[string]*schema.Schema{ + "sensitive_string_attribute": { + Sensitive: true, + Optional: true, + Type: schema.TypeString, + }, + "sensitive_list_attribute": { + Sensitive: true, + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "sensitive_set_attribute": { + Sensitive: true, + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "sensitive_map_attribute": { + Sensitive: true, + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "list_nested_block_sensitive_attribute": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "list_nested_block_attribute": { + Type: schema.TypeString, + Optional: true, + }, + "sensitive_list_nested_block_attribute": { + Sensitive: true, + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "set_nested_block_sensitive_attribute": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "set_nested_block_attribute": { + Type: schema.TypeString, + Optional: true, + }, + "sensitive_set_nested_block_attribute": { + Sensitive: true, + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/tfversion/versions.go b/tfversion/versions.go index 77f384b5e..f405bd766 100644 --- a/tfversion/versions.go +++ b/tfversion/versions.go @@ -28,6 +28,7 @@ var ( Version1_2_0 *version.Version = version.Must(version.NewVersion("1.2.0")) Version1_3_0 *version.Version = version.Must(version.NewVersion("1.3.0")) Version1_4_0 *version.Version = version.Must(version.NewVersion("1.4.0")) + Version1_4_6 *version.Version = version.Must(version.NewVersion("1.4.6")) Version1_5_0 *version.Version = version.Must(version.NewVersion("1.5.0")) Version1_6_0 *version.Version = version.Must(version.NewVersion("1.6.0")) Version1_7_0 *version.Version = version.Must(version.NewVersion("1.7.0")) From 483b364127a3f642435f944eb5e452ddb3d03120 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 10 Jan 2024 17:03:54 +0000 Subject: [PATCH 34/48] Adding documentation for state checks and null known value check type (#266) --- website/data/plugin-testing-nav-data.json | 25 ++++ .../known-value-checks/null.mdx | 39 ++++++ .../acceptance-tests/state-checks/custom.mdx | 119 ++++++++++++++++++ .../acceptance-tests/state-checks/index.mdx | 20 +++ .../acceptance-tests/state-checks/output.mdx | 84 +++++++++++++ .../state-checks/resource.mdx | 78 ++++++++++++ 6 files changed, 365 insertions(+) create mode 100644 website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/state-checks/index.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx create mode 100644 website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index 7e581b6c3..40fc85629 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -50,6 +50,27 @@ } ] }, + { + "title": "State Checks", + "routes": [ + { + "title": "Overview", + "path": "acceptance-tests/state-checks" + }, + { + "title": "Resource State Checks", + "path": "acceptance-tests/state-checks/resource" + }, + { + "title": "Output State Checks", + "path": "acceptance-tests/state-checks/output" + }, + { + "title": "Custom State Checks", + "path": "acceptance-tests/state-checks/custom" + } + ] + }, { "title": "Known Value Checks", "routes": [ @@ -85,6 +106,10 @@ "title": "Number", "path": "acceptance-tests/known-value-checks/number" }, + { + "title": "Null ", + "path": "acceptance-tests/known-value-checks/null" + }, { "title": "Object", "path": "acceptance-tests/known-value-checks/object" diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx new file mode 100644 index 000000000..9d50ee65e --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx @@ -0,0 +1,39 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Null Value Checks for use with Plan Checks or State Checks. +--- + +# Null Known Value Checks + +The known value checks that are available for null values are: + +* [NullValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/null#nullvalueexact-check) + +## `NullValueExact` Check + +The [NullValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NullValueExact) check tests that a resource attribute, or output value has an exactly matching null value. + +Example usage of [NullValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NullValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/state-checks/resource) state check. + +```go +func TestExpectKnownValue_CheckState_AttributeValueNull(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" {}`, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.NullValueExact(), + ), + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx new file mode 100644 index 000000000..f3b3461b0 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx @@ -0,0 +1,119 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: State Checks' +description: >- + State Checks are test assertions that can inspect state during a TestStep. Custom State Checks can be implemented. +--- + +# Custom State Checks + +The package [`statecheck`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck) also provides the [`StateCheck`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#StateCheck) interface, which can be implemented for a custom state check. + +The [`statecheck.CheckStateRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#CheckStateRequest) contains the current state file, parsed by the [terraform-json package](https://pkg.go.dev/github.com/hashicorp/terraform-json#State). + +Here is an example implementation of a state check that asserts that a specific resource attribute has a known type and value: + +```go +package example_test + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-testing/statecheck" +) + +var _ StateCheck = expectKnownValue{} + +type expectKnownValue struct { + resourceAddress string + attributePath tfjsonpath.Path + knownValue knownvalue.Check +} + +func (e expectKnownValue) CheckState(ctx context.Context, req CheckStateRequest, resp *CheckStateResponse) { + var rc *tfjson.StateResource + + if req.State == nil { + resp.Error = fmt.Errorf("state is nil") + } + + if req.State.Values == nil { + resp.Error = fmt.Errorf("state does not contain any state values") + } + + if req.State.Values.RootModule == nil { + resp.Error = fmt.Errorf("state does not contain a root module") + } + + for _, resourceChange := range req.State.Values.RootModule.Resources { + if e.resourceAddress == resourceChange.Address { + rc = resourceChange + + break + } + } + + if rc == nil { + resp.Error = fmt.Errorf("%s - Resource not found in state", e.resourceAddress) + + return + } + + result, err := tfjsonpath.Traverse(rc.AttributeValues, e.attributePath) + + if err != nil { + resp.Error = err + + return + } + + if err := e.knownValue.CheckValue(result); err != nil { + resp.Error = err + } +} + +func ExpectKnownValue(resourceAddress string, attributePath tfjsonpath.Path, knownValue knownvalue.Check) StateCheck { + return expectKnownValue{ + resourceAddress: resourceAddress, + attributePath: attributePath, + knownValue: knownValue, + } +} +``` + +And example usage: +```go +package example_test + +import ( + "testing" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +func TestExpectKnownValue_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/index.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/index.mdx new file mode 100644 index 000000000..36304e388 --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/index.mdx @@ -0,0 +1,20 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: State Checks' +description: >- + State Checks are test assertions that can inspect state during a TestStep. The testing module + provides built-in State Checks for common use-cases, and custom State Checks can also be implemented. +--- + +# State Checks + +During the **Lifecycle (config)** [mode](/terraform/plugin/testing/acceptance-tests/teststep#test-modes) of a `TestStep`, the testing framework will run `terraform apply`. + +The execution of `terraform apply` results in a [state file](/terraform/language/state), and can be represented by this [JSON format](/terraform/internals/json-format#state-representation). + +A **state check** is a test assertion that inspects the state file. Multiple state checks can be run, all assertion errors returned are aggregated, reported as a test failure, and all test cleanup logic is executed. + +Refer to: + +- [Resource State Checks](/terraform/plugin/testing/acceptance-tests/state-checks/resource) for built-in managed resource and data source state checks. +- [Output State Checks](/terraform/plugin/testing/acceptance-tests/state-checks/output) for built-in output-related state checks. +- [Custom State Checks](/terraform/plugin/testing/acceptance-tests/state-checks/custom) for defining bespoke state checks. diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx new file mode 100644 index 000000000..01caccdae --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx @@ -0,0 +1,84 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: State Checks' +description: >- + State Checks are test assertions that can inspect state during a TestStep. The testing module + provides built-in Output Value State Checks for common use-cases. +--- + +# Output State Checks + +The `terraform-plugin-testing` module provides a package [`statecheck`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck) with built-in output value state checks for common use-cases: + +| Check | Description | +|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------| +| [`statecheck.ExpectKnownOutputValue(address, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectKnownOutputValue) | Asserts the output at the specified address has the specified type, and value. | +| [`statecheck.ExpectKnownOutputValueAtPath(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectKnownOutputValueAtPath) | Asserts the output at the specified address, and path has the specified type, and value. | + +## Example using `statecheck.ExpectKnownOutputValue` + +The [`statecheck.ExpectKnownOutputValue(address, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectKnownOutputValue) state check verifies that a specific output value has a known type, and value. + +Refer to [Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks) for details, and examples of the available [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types that can be used with the `ExpectKnownOutputValue` state check. + +```go +func TestExpectKnownOutputValue_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output bool_output { + value = test_resource.one.bool_attribute + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValue( + "bool_output", + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} +``` + +## Example using `statecheck.ExpectKnownOutputValueAtPath` + +The [`statecheck.ExpectKnownOutputValueAtPath(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectKnownOutputValueAtPath) state check verifies that a specific output value at a defined path has a known type, and value. + +Refer to [Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks) for details, and examples of the available [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types that can be used with the `ExpectKnownOutputValueAtPath` state check. + +```go +func TestExpectKnownOutputValueAtPath_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + + output test_resource_one_output { + value = test_resource.one + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownOutputValueAtPath( + "test_resource_one_output", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} +``` \ No newline at end of file diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx new file mode 100644 index 000000000..990fd828b --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx @@ -0,0 +1,78 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: State Checks' +description: >- + State Checks are test assertions that can inspect state during a TestStep. The testing module + provides built-in Managed Resource and Data Source State Checks for common use-cases. +--- + +# Resource State Checks + +The `terraform-plugin-testing` module provides a package [`statecheck`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck) with built-in managed resource, and data source state checks for common use-cases: + +| Check | Description | +|------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| +| [`statecheck.ExpectKnownValue(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectKnownValue) | Asserts the specified attribute at the given managed resource, or data source, has the specified type, and value. | +| [`statecheck.ExpectSensitiveValue(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectSensitiveValue) | Asserts the specified attribute at the given managed resource, or data source, has a sensitive value. | + +## Example using `statecheck.ExpectKnownValue` + +The [`statecheck.ExpectKnownValue(address, path, value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectKnownValue) state check provides a basis for asserting that a specific resource attribute has a known type, and value. + +Refer to [Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks) for details, and examples of the available [knownvalue.Check](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Check) types that can be used with the `ExpectKnownValue` state check. + +```go +func TestExpectKnownValue_CheckState_Bool(t *testing.T) { + t.Parallel() + + r.Test(t, r.TestCase{ + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: `resource "test_resource" "one" { + bool_attribute = true + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("bool_attribute"), + knownvalue.BoolValueExact(true), + ), + }, + }, + }, + }) +} +``` + +## Example using `statecheck.ExpectSensitiveValue` + +The [`statecheck.ExpectSensitiveValue(address, path)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/statecheck#ExpectSensitiveValue) state check provides a basis for asserting that a specific resource attribute is marked as sensitive. + +-> **Note:** In this example, a [TerraformVersionCheck](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/tfversion#TerraformVersionCheck) is being used to prevent execution of this test prior to Terraform version `1.4.6` (refer to the release notes for Terraform [v1.4.6](https://github.com/hashicorp/terraform/releases/tag/v1.4.6)). + +```go +func Test_ExpectSensitiveValue_SensitiveStringAttribute(t *testing.T) { + t.Parallel() + + r.UnitTest(t, r.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_4_6), // StateResource.SensitiveValues + }, + // Provider definition omitted. + Steps: []r.TestStep{ + { + Config: ` + resource "test_resource" "one" { + sensitive_string_attribute = "test" + } + `, + ConfigStateChecks: r.ConfigStateChecks{ + statecheck.ExpectSensitiveValue("test_resource.one", + tfjsonpath.New("sensitive_string_attribute")), + }, + }, + }, + }) +} +``` From 388051681ec3526685dab064ff5719b3eee168f3 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 08:11:23 +0000 Subject: [PATCH 35/48] Adding to the documentation for the custom known value check (#266) --- .../known-value-checks/custom.mdx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx index ee48caa62..b9f69de1e 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx @@ -48,3 +48,26 @@ func StringValueMatch(value string) StringValue { } } ``` + +## `CheckValue` Method Implementation + +The `other` parameter passed to the `CheckValue` method is one of the following types: + +* bool +* map[string]any +* []any +* string + +-> **Note:** Numerical values will be of type `json.Number`, with an underlying type of `string`. + +Refer to the following built-in known value checks for implementations that handle the different types that can be passed to the `CheckValue` method in the `other` parameter: + +* [BoolValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValueExact) +* [Float64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64ValueExact) +* [Int64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64ValueExact) +* [ListValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValueExact) +* [MapValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValueExact) +* [NumberValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValueExact) +* [ObjectValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValueExact) +* [SetValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValueExact) +* [StringValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValueExact) From 9e5cde18187b044887e4c55ca14a781cbbeca3c4 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 10:09:18 +0000 Subject: [PATCH 36/48] Apply suggestions from code review Co-authored-by: Brian Flad --- knownvalue/known_value.go | 3 ++- knownvalue/map_elements.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/knownvalue/known_value.go b/knownvalue/known_value.go index 0c54bda20..cef532c94 100644 --- a/knownvalue/known_value.go +++ b/knownvalue/known_value.go @@ -6,7 +6,8 @@ package knownvalue // Check defines an interface that is implemented to determine whether type and value match. Individual // implementations determine how the match is performed (e.g., exact match, partial match). type Check interface { - // CheckValue should perform match testing. + // CheckValue should assert the given known value against any expectations. Use the error + // return to signal unexpected values or implementation errors. CheckValue(value any) error // String should return a string representation of the type and value. String() string diff --git a/knownvalue/map_elements.go b/knownvalue/map_elements.go index 79b617206..1aca668cc 100644 --- a/knownvalue/map_elements.go +++ b/knownvalue/map_elements.go @@ -45,7 +45,7 @@ func (v MapElements) CheckValue(other any) error { // String returns the string representation of the value. func (v MapElements) String() string { - return strconv.FormatInt(int64(v.num), 10) + return strconv.Itoa(v.num) } // MapElementsExact returns a Check for asserting that From d14429e01fc876ee7ffcdc344c8213591209145f Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 10:21:31 +0000 Subject: [PATCH 37/48] Unexporting types that implement known value check (#266) --- knownvalue/bool.go | 18 +++---- knownvalue/bool_test.go | 12 +++-- knownvalue/float64.go | 20 ++++---- knownvalue/float64_test.go | 12 +++-- knownvalue/int64.go | 20 ++++---- knownvalue/int64_test.go | 12 +++-- knownvalue/list.go | 18 +++---- knownvalue/list_elements.go | 20 ++++---- knownvalue/list_elements_test.go | 14 +++--- knownvalue/list_partial.go | 17 +++---- knownvalue/list_partial_test.go | 24 +++++---- knownvalue/list_test.go | 18 ++++--- knownvalue/map.go | 20 ++++---- knownvalue/map_elements.go | 20 ++++---- knownvalue/map_elements_test.go | 14 +++--- knownvalue/map_partial.go | 17 +++---- knownvalue/map_partial_test.go | 26 +++++----- knownvalue/map_test.go | 20 ++++---- knownvalue/number.go | 22 ++++---- knownvalue/number_test.go | 14 +++--- knownvalue/object.go | 20 ++++---- knownvalue/object_attributes.go | 20 ++++---- knownvalue/object_attributes_test.go | 14 +++--- knownvalue/object_partial.go | 17 +++---- knownvalue/object_partial_test.go | 26 +++++----- knownvalue/object_test.go | 20 ++++---- knownvalue/set.go | 20 ++++---- knownvalue/set_elements.go | 20 ++++---- knownvalue/set_elements_test.go | 14 +++--- knownvalue/set_partial.go | 17 +++---- knownvalue/set_partial_test.go | 18 ++++--- knownvalue/set_test.go | 16 +++--- knownvalue/string.go | 18 +++---- knownvalue/string_test.go | 12 +++-- .../expect_known_output_value_at_path_test.go | 50 +++++++++---------- plancheck/expect_known_output_value_test.go | 50 +++++++++---------- plancheck/expect_known_value_test.go | 50 +++++++++---------- 37 files changed, 378 insertions(+), 382 deletions(-) diff --git a/knownvalue/bool.go b/knownvalue/bool.go index f0e3a1f7b..fc2add0c8 100644 --- a/knownvalue/bool.go +++ b/knownvalue/bool.go @@ -8,39 +8,37 @@ import ( "strconv" ) -var _ Check = BoolValue{} +var _ Check = boolValueExact{} -// BoolValue is a Check for asserting equality between the value supplied -// to BoolValueExact and the value passed to the CheckValue method. -type BoolValue struct { +type boolValueExact struct { value bool } // CheckValue determines whether the passed value is of type bool, and // contains a matching bool value. -func (v BoolValue) CheckValue(other any) error { +func (v boolValueExact) CheckValue(other any) error { otherVal, ok := other.(bool) if !ok { - return fmt.Errorf("expected bool value for BoolValue check, got: %T", other) + return fmt.Errorf("expected bool value for BoolValueExact check, got: %T", other) } if otherVal != v.value { - return fmt.Errorf("expected value %t for BoolValue check, got: %t", v.value, otherVal) + return fmt.Errorf("expected value %t for BoolValueExact check, got: %t", v.value, otherVal) } return nil } // String returns the string representation of the bool value. -func (v BoolValue) String() string { +func (v boolValueExact) String() string { return strconv.FormatBool(v.value) } // BoolValueExact returns a Check for asserting equality between the // supplied bool and the value passed to the CheckValue method. -func BoolValueExact(value bool) BoolValue { - return BoolValue{ +func BoolValueExact(value bool) boolValueExact { + return boolValueExact{ value: value, } } diff --git a/knownvalue/bool_test.go b/knownvalue/bool_test.go index 21e9bee7e..bbbf45939 100644 --- a/knownvalue/bool_test.go +++ b/knownvalue/bool_test.go @@ -16,29 +16,31 @@ func TestBoolValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.BoolValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected bool value for BoolValue check, got: "), + self: knownvalue.BoolValueExact(false), + expectedError: fmt.Errorf("expected bool value for BoolValueExact check, got: "), }, "zero-other": { + self: knownvalue.BoolValueExact(false), other: false, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.BoolValueExact(false), - expectedError: fmt.Errorf("expected bool value for BoolValue check, got: "), + expectedError: fmt.Errorf("expected bool value for BoolValueExact check, got: "), }, "wrong-type": { self: knownvalue.BoolValueExact(true), other: 1.23, - expectedError: fmt.Errorf("expected bool value for BoolValue check, got: float64"), + expectedError: fmt.Errorf("expected bool value for BoolValueExact check, got: float64"), }, "not-equal": { self: knownvalue.BoolValueExact(true), other: false, - expectedError: fmt.Errorf("expected value true for BoolValue check, got: false"), + expectedError: fmt.Errorf("expected value true for BoolValueExact check, got: false"), }, "equal": { self: knownvalue.BoolValueExact(true), diff --git a/knownvalue/float64.go b/knownvalue/float64.go index 195ae8c30..5f05415b0 100644 --- a/knownvalue/float64.go +++ b/knownvalue/float64.go @@ -9,45 +9,43 @@ import ( "strconv" ) -var _ Check = Float64Value{} +var _ Check = float64ValueExact{} -// Float64Value is a Check for asserting equality between the value supplied -// to Float64ValueExact and the value passed to the CheckValue method. -type Float64Value struct { +type float64ValueExact struct { value float64 } // CheckValue determines whether the passed value is of type float64, and // contains a matching float64 value. -func (v Float64Value) CheckValue(other any) error { +func (v float64ValueExact) CheckValue(other any) error { jsonNum, ok := other.(json.Number) if !ok { - return fmt.Errorf("expected json.Number value for Float64Value check, got: %T", other) + return fmt.Errorf("expected json.Number value for Float64ValueExact check, got: %T", other) } otherVal, err := jsonNum.Float64() if err != nil { - return fmt.Errorf("expected json.Number to be parseable as float64 value for Float64Value check: %s", err) + return fmt.Errorf("expected json.Number to be parseable as float64 value for Float64ValueExact check: %s", err) } if otherVal != v.value { - return fmt.Errorf("expected value %s for Float64Value check, got: %s", v.String(), strconv.FormatFloat(otherVal, 'f', -1, 64)) + return fmt.Errorf("expected value %s for Float64ValueExact check, got: %s", v.String(), strconv.FormatFloat(otherVal, 'f', -1, 64)) } return nil } // String returns the string representation of the float64 value. -func (v Float64Value) String() string { +func (v float64ValueExact) String() string { return strconv.FormatFloat(v.value, 'f', -1, 64) } // Float64ValueExact returns a Check for asserting equality between the // supplied float64 and the value passed to the CheckValue method. -func Float64ValueExact(value float64) Float64Value { - return Float64Value{ +func Float64ValueExact(value float64) float64ValueExact { + return float64ValueExact{ value: value, } } diff --git a/knownvalue/float64_test.go b/knownvalue/float64_test.go index 7ddbde24f..f5f66c56a 100644 --- a/knownvalue/float64_test.go +++ b/knownvalue/float64_test.go @@ -17,29 +17,31 @@ func TestFloat64Value_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.Float64Value + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected json.Number value for Float64Value check, got: "), + self: knownvalue.Float64ValueExact(0), + expectedError: fmt.Errorf("expected json.Number value for Float64ValueExact check, got: "), }, "zero-other": { + self: knownvalue.Float64ValueExact(0), other: json.Number("0.0"), // checking against the underlying value field zero-value }, "nil": { self: knownvalue.Float64ValueExact(1.234), - expectedError: fmt.Errorf("expected json.Number value for Float64Value check, got: "), + expectedError: fmt.Errorf("expected json.Number value for Float64ValueExact check, got: "), }, "wrong-type": { self: knownvalue.Float64ValueExact(1.234), other: json.Number("str"), - expectedError: fmt.Errorf("expected json.Number to be parseable as float64 value for Float64Value check: strconv.ParseFloat: parsing \"str\": invalid syntax"), + expectedError: fmt.Errorf("expected json.Number to be parseable as float64 value for Float64ValueExact check: strconv.ParseFloat: parsing \"str\": invalid syntax"), }, "not-equal": { self: knownvalue.Float64ValueExact(1.234), other: json.Number("4.321"), - expectedError: fmt.Errorf("expected value 1.234 for Float64Value check, got: 4.321"), + expectedError: fmt.Errorf("expected value 1.234 for Float64ValueExact check, got: 4.321"), }, "equal": { self: knownvalue.Float64ValueExact(1.234), diff --git a/knownvalue/int64.go b/knownvalue/int64.go index bf3b5ad48..300fdfdb2 100644 --- a/knownvalue/int64.go +++ b/knownvalue/int64.go @@ -9,45 +9,43 @@ import ( "strconv" ) -var _ Check = Int64Value{} +var _ Check = int64ValueExact{} -// Int64Value is a Check for asserting equality between the value supplied -// to Int64ValueExact and the value passed to the CheckValue method. -type Int64Value struct { +type int64ValueExact struct { value int64 } // CheckValue determines whether the passed value is of type int64, and // contains a matching int64 value. -func (v Int64Value) CheckValue(other any) error { +func (v int64ValueExact) CheckValue(other any) error { jsonNum, ok := other.(json.Number) if !ok { - return fmt.Errorf("expected json.Number value for Int64Value check, got: %T", other) + return fmt.Errorf("expected json.Number value for Int64ValueExact check, got: %T", other) } otherVal, err := jsonNum.Int64() if err != nil { - return fmt.Errorf("expected json.Number to be parseable as int64 value for Int64Value check: %s", err) + return fmt.Errorf("expected json.Number to be parseable as int64 value for Int64ValueExact check: %s", err) } if otherVal != v.value { - return fmt.Errorf("expected value %d for Int64Value check, got: %d", v.value, otherVal) + return fmt.Errorf("expected value %d for Int64ValueExact check, got: %d", v.value, otherVal) } return nil } // String returns the string representation of the int64 value. -func (v Int64Value) String() string { +func (v int64ValueExact) String() string { return strconv.FormatInt(v.value, 10) } // Int64ValueExact returns a Check for asserting equality between the // supplied int64 and the value passed to the CheckValue method. -func Int64ValueExact(value int64) Int64Value { - return Int64Value{ +func Int64ValueExact(value int64) int64ValueExact { + return int64ValueExact{ value: value, } } diff --git a/knownvalue/int64_test.go b/knownvalue/int64_test.go index 0aba7a21e..03527b390 100644 --- a/knownvalue/int64_test.go +++ b/knownvalue/int64_test.go @@ -17,29 +17,31 @@ func TestInt64Value_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.Int64Value + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected json.Number value for Int64Value check, got: "), + self: knownvalue.Int64ValueExact(0), + expectedError: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: "), }, "zero-other": { + self: knownvalue.Int64ValueExact(0), other: json.Number("0"), // checking against the underlying value field zero-value }, "nil": { self: knownvalue.Int64ValueExact(1234), - expectedError: fmt.Errorf("expected json.Number value for Int64Value check, got: "), + expectedError: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: "), }, "wrong-type": { self: knownvalue.Int64ValueExact(1234), other: json.Number("str"), - expectedError: fmt.Errorf("expected json.Number to be parseable as int64 value for Int64Value check: strconv.ParseInt: parsing \"str\": invalid syntax"), + expectedError: fmt.Errorf("expected json.Number to be parseable as int64 value for Int64ValueExact check: strconv.ParseInt: parsing \"str\": invalid syntax"), }, "not-equal": { self: knownvalue.Int64ValueExact(1234), other: json.Number("4321"), - expectedError: fmt.Errorf("expected value 1234 for Int64Value check, got: 4321"), + expectedError: fmt.Errorf("expected value 1234 for Int64ValueExact check, got: 4321"), }, "equal": { self: knownvalue.Int64ValueExact(1234), diff --git a/knownvalue/list.go b/knownvalue/list.go index a14967b72..9d89cbdc4 100644 --- a/knownvalue/list.go +++ b/knownvalue/list.go @@ -7,21 +7,19 @@ import ( "fmt" ) -var _ Check = ListValue{} +var _ Check = listValueExact{} -// ListValue is a Check for asserting equality between the value supplied -// to ListValueExact and the value passed to the CheckValue method. -type ListValue struct { +type listValueExact struct { value []Check } // CheckValue determines whether the passed value is of type []any, and // contains matching slice entries in the same sequence. -func (v ListValue) CheckValue(other any) error { +func (v listValueExact) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("expected []any value for ListValue check, got: %T", other) + return fmt.Errorf("expected []any value for ListValueExact check, got: %T", other) } if len(otherVal) != len(v.value) { @@ -36,7 +34,7 @@ func (v ListValue) CheckValue(other any) error { actualElements = "element" } - return fmt.Errorf("expected %d %s for ListValue check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) + return fmt.Errorf("expected %d %s for ListValueExact check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) } for i := 0; i < len(v.value); i++ { @@ -49,7 +47,7 @@ func (v ListValue) CheckValue(other any) error { } // String returns the string representation of the value. -func (v ListValue) String() string { +func (v listValueExact) String() string { var listVals []string for _, val := range v.value { @@ -62,8 +60,8 @@ func (v ListValue) String() string { // ListValueExact returns a Check for asserting equality between the // supplied []Check and the value passed to the CheckValue method. // This is an order-dependent check. -func ListValueExact(value []Check) ListValue { - return ListValue{ +func ListValueExact(value []Check) listValueExact { + return listValueExact{ value: value, } } diff --git a/knownvalue/list_elements.go b/knownvalue/list_elements.go index ffb4b1eea..8e524e11d 100644 --- a/knownvalue/list_elements.go +++ b/knownvalue/list_elements.go @@ -8,21 +8,19 @@ import ( "strconv" ) -var _ Check = ListElements{} +var _ Check = listElementsExact{} -// ListElements is a Check for asserting equality between the value supplied -// to ListElementsExact and the value passed to the CheckValue method. -type ListElements struct { +type listElementsExact struct { num int } // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. -func (v ListElements) CheckValue(other any) error { +func (v listElementsExact) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("expected []any value for ListElements check, got: %T", other) + return fmt.Errorf("expected []any value for ListElementsExact check, got: %T", other) } if len(otherVal) != v.num { @@ -37,21 +35,21 @@ func (v ListElements) CheckValue(other any) error { actualElements = "element" } - return fmt.Errorf("expected %d %s for ListElements check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) + return fmt.Errorf("expected %d %s for ListElementsExact check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) } return nil } // String returns the string representation of the value. -func (v ListElements) String() string { +func (v listElementsExact) String() string { return strconv.FormatInt(int64(v.num), 10) } // ListElementsExact returns a Check for asserting that -// a list num elements. -func ListElementsExact(num int) ListElements { - return ListElements{ +// a list has num elements. +func ListElementsExact(num int) listElementsExact { + return listElementsExact{ num: num, } } diff --git a/knownvalue/list_elements_test.go b/knownvalue/list_elements_test.go index 242b13f61..d48196510 100644 --- a/knownvalue/list_elements_test.go +++ b/knownvalue/list_elements_test.go @@ -16,29 +16,31 @@ func TestListElements_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.ListElements + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected []any value for ListElements check, got: "), + self: knownvalue.ListElementsExact(0), + expectedError: fmt.Errorf("expected []any value for ListElementsExact check, got: "), }, "zero-other": { + self: knownvalue.ListElementsExact(0), other: []any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.ListElementsExact(3), - expectedError: fmt.Errorf("expected []any value for ListElements check, got: "), + expectedError: fmt.Errorf("expected []any value for ListElementsExact check, got: "), }, "wrong-type": { self: knownvalue.ListElementsExact(3), other: 1.234, - expectedError: fmt.Errorf("expected []any value for ListElements check, got: float64"), + expectedError: fmt.Errorf("expected []any value for ListElementsExact check, got: float64"), }, "empty": { self: knownvalue.ListElementsExact(3), other: []any{}, - expectedError: fmt.Errorf("expected 3 elements for ListElements check, got 0 elements"), + expectedError: fmt.Errorf("expected 3 elements for ListElementsExact check, got 0 elements"), }, "wrong-length": { self: knownvalue.ListElementsExact(3), @@ -46,7 +48,7 @@ func TestListElements_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("expected 3 elements for ListElements check, got 2 elements"), + expectedError: fmt.Errorf("expected 3 elements for ListElementsExact check, got 2 elements"), }, "equal": { self: knownvalue.ListElementsExact(3), diff --git a/knownvalue/list_partial.go b/knownvalue/list_partial.go index 0c6c075ea..1bd333ae3 100644 --- a/knownvalue/list_partial.go +++ b/knownvalue/list_partial.go @@ -10,18 +10,15 @@ import ( "strings" ) -var _ Check = ListValuePartial{} +var _ Check = listValuePartial{} -// ListValuePartial is a Check for asserting partial equality between the -// value supplied to ListValuePartialMatch and the value passed to the -// CheckValue method. -type ListValuePartial struct { +type listValuePartial struct { value map[int]Check } // CheckValue determines whether the passed value is of type []any, and // contains matching slice entries in the same sequence. -func (v ListValuePartial) CheckValue(other any) error { +func (v listValuePartial) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { @@ -52,7 +49,7 @@ func (v ListValuePartial) CheckValue(other any) error { } // String returns the string representation of the value. -func (v ListValuePartial) String() string { +func (v listValuePartial) String() string { var b bytes.Buffer b.WriteString("[") @@ -80,13 +77,13 @@ func (v ListValuePartial) String() string { return b.String() } -// ListValuePartialMatch returns a Check for asserting partial equality between the +// ListValuePartial returns a Check for asserting partial equality between the // supplied map[int]Check and the value passed to the CheckValue method. The // map keys represent the zero-ordered element indices within the list that is // being checked. Only the elements at the indices defined within the // supplied map[int]Check are checked. -func ListValuePartialMatch(value map[int]Check) ListValuePartial { - return ListValuePartial{ +func ListValuePartial(value map[int]Check) listValuePartial { + return listValuePartial{ value: value, } } diff --git a/knownvalue/list_partial_test.go b/knownvalue/list_partial_test.go index d2f640b1c..c32f5bbde 100644 --- a/knownvalue/list_partial_test.go +++ b/knownvalue/list_partial_test.go @@ -17,18 +17,20 @@ func TestListValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.ListValuePartial + self knownvalue.Check other any expectedError error }{ "zero-nil": { + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{}), expectedError: fmt.Errorf("expected []any value for ListValuePartial check, got: "), }, "zero-other": { + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{}), other: []any{}, // checking against the underlying value field zero-value }, "nil": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -36,7 +38,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("expected []any value for ListValuePartial check, got: "), }, "wrong-type": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -45,7 +47,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("expected []any value for ListValuePartial check, got: float64"), }, "empty": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -54,7 +56,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing element index 0 for ListValuePartial check"), }, "wrong-length": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -66,7 +68,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing element index 2 for ListValuePartial check"), }, "not-equal": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -77,10 +79,10 @@ func TestListValuePartial_CheckValue(t *testing.T) { json.Number("6.54"), json.Number("5.46"), }, - expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64Value check, got: 6.54"), + expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64ValueExact check, got: 6.54"), }, "wrong-order": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -91,10 +93,10 @@ func TestListValuePartial_CheckValue(t *testing.T) { json.Number("7.89"), json.Number("4.56"), }, - expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64Value check, got: 7.89"), + expectedError: fmt.Errorf("list element 2: expected value 4.56 for Float64ValueExact check, got: 7.89"), }, "equal": { - self: knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + self: knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), @@ -126,7 +128,7 @@ func TestListValuePartial_CheckValue(t *testing.T) { func TestListValuePartialPartial_String(t *testing.T) { t.Parallel() - got := knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + got := knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.Float64ValueExact(1.23), 2: knownvalue.Float64ValueExact(4.56), 3: knownvalue.Float64ValueExact(7.89), diff --git a/knownvalue/list_test.go b/knownvalue/list_test.go index 34c74752b..1563b473b 100644 --- a/knownvalue/list_test.go +++ b/knownvalue/list_test.go @@ -17,14 +17,16 @@ func TestListValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.ListValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected []any value for ListValue check, got: "), + self: knownvalue.ListValueExact([]knownvalue.Check{}), + expectedError: fmt.Errorf("expected []any value for ListValueExact check, got: "), }, "zero-other": { + self: knownvalue.ListValueExact([]knownvalue.Check{}), other: []any{}, // checking against the underlying value field zero-value }, "nil": { @@ -33,7 +35,7 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(456), knownvalue.Int64ValueExact(789), }), - expectedError: fmt.Errorf("expected []any value for ListValue check, got: "), + expectedError: fmt.Errorf("expected []any value for ListValueExact check, got: "), }, "wrong-type": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -42,7 +44,7 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: 1.234, - expectedError: fmt.Errorf("expected []any value for ListValue check, got: float64"), + expectedError: fmt.Errorf("expected []any value for ListValueExact check, got: float64"), }, "empty": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -51,7 +53,7 @@ func TestListValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{}, - expectedError: fmt.Errorf("expected 3 elements for ListValue check, got 0 elements"), + expectedError: fmt.Errorf("expected 3 elements for ListValueExact check, got 0 elements"), }, "wrong-length": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -63,7 +65,7 @@ func TestListValue_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("expected 3 elements for ListValue check, got 2 elements"), + expectedError: fmt.Errorf("expected 3 elements for ListValueExact check, got 2 elements"), }, "not-equal": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -76,7 +78,7 @@ func TestListValue_CheckValue(t *testing.T) { json.Number("456"), json.Number("654"), }, - expectedError: fmt.Errorf("list element index 2: expected value 789 for Int64Value check, got: 654"), + expectedError: fmt.Errorf("list element index 2: expected value 789 for Int64ValueExact check, got: 654"), }, "wrong-order": { self: knownvalue.ListValueExact([]knownvalue.Check{ @@ -89,7 +91,7 @@ func TestListValue_CheckValue(t *testing.T) { json.Number("789"), json.Number("456"), }, - expectedError: fmt.Errorf("list element index 1: expected value 456 for Int64Value check, got: 789"), + expectedError: fmt.Errorf("list element index 1: expected value 456 for Int64ValueExact check, got: 789"), }, "equal": { self: knownvalue.ListValueExact([]knownvalue.Check{ diff --git a/knownvalue/map.go b/knownvalue/map.go index b86a8c50f..11f69fef3 100644 --- a/knownvalue/map.go +++ b/knownvalue/map.go @@ -8,21 +8,19 @@ import ( "sort" ) -var _ Check = MapValue{} +var _ Check = mapValueExact{} -// MapValue is a Check for asserting equality between the value supplied -// to MapValueExact and the value passed to the CheckValue method. -type MapValue struct { +type mapValueExact struct { value map[string]Check } // CheckValue determines whether the passed value is of type map[string]any, and // contains matching map entries. -func (v MapValue) CheckValue(other any) error { +func (v mapValueExact) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("expected map[string]any value for MapValue check, got: %T", other) + return fmt.Errorf("expected map[string]any value for MapValueExact check, got: %T", other) } if len(otherVal) != len(v.value) { @@ -37,7 +35,7 @@ func (v MapValue) CheckValue(other any) error { actualElements = "element" } - return fmt.Errorf("expected %d %s for MapValue check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) + return fmt.Errorf("expected %d %s for MapValueExact check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) } var keys []string @@ -54,7 +52,7 @@ func (v MapValue) CheckValue(other any) error { otherValItem, ok := otherVal[k] if !ok { - return fmt.Errorf("missing element %s for MapValue check", k) + return fmt.Errorf("missing element %s for MapValueExact check", k) } if err := v.value[k].CheckValue(otherValItem); err != nil { @@ -66,7 +64,7 @@ func (v MapValue) CheckValue(other any) error { } // String returns the string representation of the value. -func (v MapValue) String() string { +func (v mapValueExact) String() string { var keys []string for k := range v.value { @@ -88,8 +86,8 @@ func (v MapValue) String() string { // MapValueExact returns a Check for asserting equality between the // supplied map[string]Check and the value passed to the CheckValue method. -func MapValueExact(value map[string]Check) MapValue { - return MapValue{ +func MapValueExact(value map[string]Check) mapValueExact { + return mapValueExact{ value: value, } } diff --git a/knownvalue/map_elements.go b/knownvalue/map_elements.go index 79b617206..4c5b12e1e 100644 --- a/knownvalue/map_elements.go +++ b/knownvalue/map_elements.go @@ -8,21 +8,19 @@ import ( "strconv" ) -var _ Check = MapElements{} +var _ Check = mapElementsExact{} -// MapElements is a Check for asserting equality between the value supplied -// to MapElementsExact and the value passed to the CheckValue method. -type MapElements struct { +type mapElementsExact struct { num int } // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. -func (v MapElements) CheckValue(other any) error { +func (v mapElementsExact) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("expected map[string]any value for MapElements check, got: %T", other) + return fmt.Errorf("expected map[string]any value for MapElementsExact check, got: %T", other) } if len(otherVal) != v.num { @@ -37,21 +35,21 @@ func (v MapElements) CheckValue(other any) error { actualElements = "element" } - return fmt.Errorf("expected %d %s for MapElements check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) + return fmt.Errorf("expected %d %s for MapElementsExact check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) } return nil } // String returns the string representation of the value. -func (v MapElements) String() string { +func (v mapElementsExact) String() string { return strconv.FormatInt(int64(v.num), 10) } // MapElementsExact returns a Check for asserting that -// a list num elements. -func MapElementsExact(num int) MapElements { - return MapElements{ +// a map has num elements. +func MapElementsExact(num int) mapElementsExact { + return mapElementsExact{ num: num, } } diff --git a/knownvalue/map_elements_test.go b/knownvalue/map_elements_test.go index 82297f623..0dca62afa 100644 --- a/knownvalue/map_elements_test.go +++ b/knownvalue/map_elements_test.go @@ -16,29 +16,31 @@ func TestMapElements_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.MapElements + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected map[string]any value for MapElements check, got: "), + self: knownvalue.MapElementsExact(0), + expectedError: fmt.Errorf("expected map[string]any value for MapElementsExact check, got: "), }, "zero-other": { + self: knownvalue.MapElementsExact(0), other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.MapElementsExact(3), - expectedError: fmt.Errorf("expected map[string]any value for MapElements check, got: "), + expectedError: fmt.Errorf("expected map[string]any value for MapElementsExact check, got: "), }, "wrong-type": { self: knownvalue.MapElementsExact(3), other: 1.234, - expectedError: fmt.Errorf("expected map[string]any value for MapElements check, got: float64"), + expectedError: fmt.Errorf("expected map[string]any value for MapElementsExact check, got: float64"), }, "empty": { self: knownvalue.MapElementsExact(3), other: map[string]any{}, - expectedError: fmt.Errorf("expected 3 elements for MapElements check, got 0 elements"), + expectedError: fmt.Errorf("expected 3 elements for MapElementsExact check, got 0 elements"), }, "wrong-length": { self: knownvalue.MapElementsExact(3), @@ -46,7 +48,7 @@ func TestMapElements_CheckValue(t *testing.T) { "one": int64(123), "two": int64(456), }, - expectedError: fmt.Errorf("expected 3 elements for MapElements check, got 2 elements"), + expectedError: fmt.Errorf("expected 3 elements for MapElementsExact check, got 2 elements"), }, "equal": { self: knownvalue.MapElementsExact(3), diff --git a/knownvalue/map_partial.go b/knownvalue/map_partial.go index da620c5b1..1ebcb5338 100644 --- a/knownvalue/map_partial.go +++ b/knownvalue/map_partial.go @@ -8,18 +8,15 @@ import ( "sort" ) -var _ Check = MapValuePartial{} +var _ Check = mapValuePartial{} -// MapValuePartial is a Check for asserting partial equality between the -// value supplied to MapValuePartialMatch and the value passed to the -// CheckValue method. -type MapValuePartial struct { +type mapValuePartial struct { value map[string]Check } // CheckValue determines whether the passed value is of type map[string]any, and // contains matching map entries. -func (v MapValuePartial) CheckValue(other any) error { +func (v mapValuePartial) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { @@ -52,7 +49,7 @@ func (v MapValuePartial) CheckValue(other any) error { } // String returns the string representation of the value. -func (v MapValuePartial) String() string { +func (v mapValuePartial) String() string { var keys []string for k := range v.value { @@ -72,12 +69,12 @@ func (v MapValuePartial) String() string { return fmt.Sprintf("%v", mapVals) } -// MapValuePartialMatch returns a Check for asserting partial equality between the +// MapValuePartial returns a Check for asserting partial equality between the // supplied map[string]Check and the value passed to the CheckValue method. Only // the elements at the map keys defined within the supplied map[string]Check are // checked. -func MapValuePartialMatch(value map[string]Check) MapValuePartial { - return MapValuePartial{ +func MapValuePartial(value map[string]Check) mapValuePartial { + return mapValuePartial{ value: value, } } diff --git a/knownvalue/map_partial_test.go b/knownvalue/map_partial_test.go index 04a19cfd1..3f500adee 100644 --- a/knownvalue/map_partial_test.go +++ b/knownvalue/map_partial_test.go @@ -17,25 +17,27 @@ func TestMapValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.MapValuePartial + self knownvalue.Check other any expectedError error }{ "zero-nil": { + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{}), expectedError: fmt.Errorf("expected map[string]any value for MapValuePartial check, got: "), }, "zero-other": { + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{}), other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), expectedError: fmt.Errorf("expected map[string]any value for MapValuePartial check, got: "), }, "wrong-type": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -43,7 +45,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("expected map[string]any value for MapValuePartial check, got: float64"), }, "empty": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -51,7 +53,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing element one for MapValuePartial check"), }, "wrong-length": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -62,7 +64,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing element three for MapValuePartial check"), }, "not-equal": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -71,10 +73,10 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "two": json.Number("4.56"), "three": json.Number("6.54"), }, - expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 6.54"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64ValueExact check, got: 6.54"), }, "wrong-order": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -83,10 +85,10 @@ func TestMapValuePartial_CheckValue(t *testing.T) { "two": json.Number("7.89"), "three": json.Number("4.56"), }, - expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 4.56"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64ValueExact check, got: 4.56"), }, "key-not-found": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), @@ -99,7 +101,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing element one for MapValuePartial check"), }, "equal": { - self: knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -129,7 +131,7 @@ func TestMapValuePartial_CheckValue(t *testing.T) { func TestMapValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + got := knownvalue.MapValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }).String() diff --git a/knownvalue/map_test.go b/knownvalue/map_test.go index c022f7eed..c47e516cf 100644 --- a/knownvalue/map_test.go +++ b/knownvalue/map_test.go @@ -17,14 +17,16 @@ func TestMapValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.MapValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected map[string]any value for MapValue check, got: "), + self: knownvalue.MapValueExact(map[string]knownvalue.Check{}), + expectedError: fmt.Errorf("expected map[string]any value for MapValueExact check, got: "), }, "zero-other": { + self: knownvalue.MapValueExact(map[string]knownvalue.Check{}), other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { @@ -33,7 +35,7 @@ func TestMapValue_CheckValue(t *testing.T) { "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("expected map[string]any value for MapValue check, got: "), + expectedError: fmt.Errorf("expected map[string]any value for MapValueExact check, got: "), }, "wrong-type": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -42,7 +44,7 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("expected map[string]any value for MapValue check, got: float64"), + expectedError: fmt.Errorf("expected map[string]any value for MapValueExact check, got: float64"), }, "empty": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -51,7 +53,7 @@ func TestMapValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{}, - expectedError: fmt.Errorf("expected 3 elements for MapValue check, got 0 elements"), + expectedError: fmt.Errorf("expected 3 elements for MapValueExact check, got 0 elements"), }, "wrong-length": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -63,7 +65,7 @@ func TestMapValue_CheckValue(t *testing.T) { "one": json.Number("1.23"), "two": json.Number("4.56"), }, - expectedError: fmt.Errorf("expected 3 elements for MapValue check, got 2 elements"), + expectedError: fmt.Errorf("expected 3 elements for MapValueExact check, got 2 elements"), }, "not-equal": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -76,7 +78,7 @@ func TestMapValue_CheckValue(t *testing.T) { "two": json.Number("4.56"), "three": json.Number("6.54"), }, - expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 6.54"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64ValueExact check, got: 6.54"), }, "wrong-order": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -89,7 +91,7 @@ func TestMapValue_CheckValue(t *testing.T) { "two": json.Number("7.89"), "three": json.Number("4.56"), }, - expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64Value check, got: 4.56"), + expectedError: fmt.Errorf("three map element: expected value 7.89 for Float64ValueExact check, got: 4.56"), }, "key-not-found": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ @@ -102,7 +104,7 @@ func TestMapValue_CheckValue(t *testing.T) { "five": json.Number("7.89"), "six": json.Number("4.56"), }, - expectedError: fmt.Errorf("missing element one for MapValue check"), + expectedError: fmt.Errorf("missing element one for MapValueExact check"), }, "equal": { self: knownvalue.MapValueExact(map[string]knownvalue.Check{ diff --git a/knownvalue/number.go b/knownvalue/number.go index 5f8700e70..98f54e733 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -9,49 +9,47 @@ import ( "math/big" ) -var _ Check = NumberValue{} +var _ Check = numberValueExact{} -// NumberValue is a Check for asserting equality between the value supplied -// to NumberValueExact and the value passed to the CheckValue method. -type NumberValue struct { +type numberValueExact struct { value *big.Float } // CheckValue determines whether the passed value is of type *big.Float, and // contains a matching *big.Float value. -func (v NumberValue) CheckValue(other any) error { +func (v numberValueExact) CheckValue(other any) error { if v.value == nil { - return fmt.Errorf("value in NumberValue check is nil") + return fmt.Errorf("value in NumberValueExact check is nil") } jsonNum, ok := other.(json.Number) if !ok { - return fmt.Errorf("expected json.Number value for NumberValue check, got: %T", other) + return fmt.Errorf("expected json.Number value for NumberValueExact check, got: %T", other) } otherVal, _, err := big.ParseFloat(jsonNum.String(), 10, 512, big.ToNearestEven) if err != nil { - return fmt.Errorf("expected json.Number to be parseable as big.Float value for NumberValue check: %s", err) + return fmt.Errorf("expected json.Number to be parseable as big.Float value for NumberValueExact check: %s", err) } if v.value.Cmp(otherVal) != 0 { - return fmt.Errorf("expected value %s for NumberValue check, got: %s", v.String(), otherVal.Text('f', -1)) + return fmt.Errorf("expected value %s for NumberValueExact check, got: %s", v.String(), otherVal.Text('f', -1)) } return nil } // String returns the string representation of the *big.Float value. -func (v NumberValue) String() string { +func (v numberValueExact) String() string { return v.value.Text('f', -1) } // NumberValueExact returns a Check for asserting equality between the // supplied *big.Float and the value passed to the CheckValue method. -func NumberValueExact(value *big.Float) NumberValue { - return NumberValue{ +func NumberValueExact(value *big.Float) numberValueExact { + return numberValueExact{ value: value, } } diff --git a/knownvalue/number_test.go b/knownvalue/number_test.go index 4d3e7b8a9..ca38be97f 100644 --- a/knownvalue/number_test.go +++ b/knownvalue/number_test.go @@ -24,30 +24,32 @@ func TestNumberValue_Equal(t *testing.T) { } testCases := map[string]struct { - self knownvalue.NumberValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("value in NumberValue check is nil"), + self: knownvalue.NumberValueExact(nil), + expectedError: fmt.Errorf("value in NumberValueExact check is nil"), }, "zero-other": { + self: knownvalue.NumberValueExact(nil), other: json.Number("1.797693134862315797693134862315797693134862314"), // checking against the underlying value field zero-value - expectedError: fmt.Errorf("value in NumberValue check is nil"), + expectedError: fmt.Errorf("value in NumberValueExact check is nil"), }, "nil": { self: knownvalue.NumberValueExact(bigFloat), - expectedError: fmt.Errorf("expected json.Number value for NumberValue check, got: "), + expectedError: fmt.Errorf("expected json.Number value for NumberValueExact check, got: "), }, "wrong-type": { self: knownvalue.NumberValueExact(bigFloat), other: json.Number("str"), - expectedError: fmt.Errorf("expected json.Number to be parseable as big.Float value for NumberValue check: number has no digits"), + expectedError: fmt.Errorf("expected json.Number to be parseable as big.Float value for NumberValueExact check: number has no digits"), }, "not-equal": { self: knownvalue.NumberValueExact(bigFloat), other: json.Number("1.797693134862315797693134862315797693134862314"), - expectedError: fmt.Errorf("expected value 1.797693134862315797693134862315797693134862315 for NumberValue check, got: 1.797693134862315797693134862315797693134862314"), + expectedError: fmt.Errorf("expected value 1.797693134862315797693134862315797693134862315 for NumberValueExact check, got: 1.797693134862315797693134862315797693134862314"), }, "equal": { self: knownvalue.NumberValueExact(bigFloat), diff --git a/knownvalue/object.go b/knownvalue/object.go index e8b74a4b5..7caf5a250 100644 --- a/knownvalue/object.go +++ b/knownvalue/object.go @@ -8,21 +8,19 @@ import ( "sort" ) -var _ Check = ObjectValue{} +var _ Check = objectValueExact{} -// ObjectValue is a Check for asserting equality between the value supplied -// to ObjectValueExact and the value passed to the CheckValue method. -type ObjectValue struct { +type objectValueExact struct { value map[string]Check } // CheckValue determines whether the passed value is of type map[string]any, and // contains matching object entries. -func (v ObjectValue) CheckValue(other any) error { +func (v objectValueExact) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("expected map[string]any value for ObjectValue check, got: %T", other) + return fmt.Errorf("expected map[string]any value for ObjectValueExact check, got: %T", other) } if len(otherVal) != len(v.value) { @@ -37,7 +35,7 @@ func (v ObjectValue) CheckValue(other any) error { actualAttributes = "attribute" } - return fmt.Errorf("expected %d %s for ObjectValue check, got %d %s", len(v.value), expectedAttributes, len(otherVal), actualAttributes) + return fmt.Errorf("expected %d %s for ObjectValueExact check, got %d %s", len(v.value), expectedAttributes, len(otherVal), actualAttributes) } var keys []string @@ -54,7 +52,7 @@ func (v ObjectValue) CheckValue(other any) error { otherValItem, ok := otherVal[k] if !ok { - return fmt.Errorf("missing attribute %s for ObjectValue check", k) + return fmt.Errorf("missing attribute %s for ObjectValueExact check", k) } if err := v.value[k].CheckValue(otherValItem); err != nil { @@ -66,7 +64,7 @@ func (v ObjectValue) CheckValue(other any) error { } // String returns the string representation of the value. -func (v ObjectValue) String() string { +func (v objectValueExact) String() string { var keys []string for k := range v.value { @@ -89,8 +87,8 @@ func (v ObjectValue) String() string { // ObjectValueExact returns a Check for asserting equality between the supplied // map[string]Check and the value passed to the CheckValue method. The map // keys represent object attribute names. -func ObjectValueExact(value map[string]Check) ObjectValue { - return ObjectValue{ +func ObjectValueExact(value map[string]Check) objectValueExact { + return objectValueExact{ value: value, } } diff --git a/knownvalue/object_attributes.go b/knownvalue/object_attributes.go index 80de51aa5..b4e03012e 100644 --- a/knownvalue/object_attributes.go +++ b/knownvalue/object_attributes.go @@ -8,21 +8,19 @@ import ( "strconv" ) -var _ Check = ObjectAttributes{} +var _ Check = objectAttributesExact{} -// ObjectAttributes is a Check for asserting equality between the value supplied -// to ObjectAttributesExact and the value passed to the CheckValue method. -type ObjectAttributes struct { +type objectAttributesExact struct { num int } // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. -func (v ObjectAttributes) CheckValue(other any) error { +func (v objectAttributesExact) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { - return fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: %T", other) + return fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: %T", other) } if len(otherVal) != v.num { @@ -37,21 +35,21 @@ func (v ObjectAttributes) CheckValue(other any) error { actualAttributes = "attribute" } - return fmt.Errorf("expected %d %s for ObjectAttributes check, got %d %s", v.num, expectedAttributes, len(otherVal), actualAttributes) + return fmt.Errorf("expected %d %s for ObjectAttributesExact check, got %d %s", v.num, expectedAttributes, len(otherVal), actualAttributes) } return nil } // String returns the string representation of the value. -func (v ObjectAttributes) String() string { +func (v objectAttributesExact) String() string { return strconv.FormatInt(int64(v.num), 10) } // ObjectAttributesExact returns a Check for asserting that -// a list num elements. -func ObjectAttributesExact(num int) ObjectAttributes { - return ObjectAttributes{ +// an object has num attributes. +func ObjectAttributesExact(num int) objectAttributesExact { + return objectAttributesExact{ num: num, } } diff --git a/knownvalue/object_attributes_test.go b/knownvalue/object_attributes_test.go index 7de835c51..963af7495 100644 --- a/knownvalue/object_attributes_test.go +++ b/knownvalue/object_attributes_test.go @@ -16,29 +16,31 @@ func TestObjectAttributes_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.ObjectAttributes + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: "), + self: knownvalue.ObjectAttributesExact(0), + expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: "), }, "zero-other": { + self: knownvalue.ObjectAttributesExact(0), other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.ObjectAttributesExact(3), - expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: "), + expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: "), }, "wrong-type": { self: knownvalue.ObjectAttributesExact(3), other: 1.234, - expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributes check, got: float64"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: float64"), }, "empty": { self: knownvalue.ObjectAttributesExact(3), other: map[string]any{}, - expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributes check, got 0 attributes"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributesExact check, got 0 attributes"), }, "wrong-length": { self: knownvalue.ObjectAttributesExact(3), @@ -46,7 +48,7 @@ func TestObjectAttributes_CheckValue(t *testing.T) { "one": int64(123), "two": int64(456), }, - expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributes check, got 2 attributes"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributesExact check, got 2 attributes"), }, "equal": { self: knownvalue.ObjectAttributesExact(3), diff --git a/knownvalue/object_partial.go b/knownvalue/object_partial.go index f024982b9..662edc735 100644 --- a/knownvalue/object_partial.go +++ b/knownvalue/object_partial.go @@ -8,18 +8,15 @@ import ( "sort" ) -var _ Check = ObjectValuePartial{} +var _ Check = objectValuePartial{} -// ObjectValuePartial is a Check for asserting partial equality between the -// value supplied to ObjectValuePartialMatch and the value passed to the -// CheckValue method. -type ObjectValuePartial struct { +type objectValuePartial struct { value map[string]Check } // CheckValue determines whether the passed value is of type map[string]any, and // contains matching map entries. -func (v ObjectValuePartial) CheckValue(other any) error { +func (v objectValuePartial) CheckValue(other any) error { otherVal, ok := other.(map[string]any) if !ok { @@ -52,7 +49,7 @@ func (v ObjectValuePartial) CheckValue(other any) error { } // String returns the string representation of the value. -func (v ObjectValuePartial) String() string { +func (v objectValuePartial) String() string { var keys []string for k := range v.value { @@ -72,12 +69,12 @@ func (v ObjectValuePartial) String() string { return fmt.Sprintf("%v", mapVals) } -// ObjectValuePartialMatch returns a Check for asserting partial equality between the +// ObjectValuePartial returns a Check for asserting partial equality between the // supplied map[string]Check and the value passed to the CheckValue method. The map // keys represent object attribute names. Only the object attributes defined by the // map keys within the supplied map[string]Check are checked. -func ObjectValuePartialMatch(value map[string]Check) ObjectValuePartial { - return ObjectValuePartial{ +func ObjectValuePartial(value map[string]Check) objectValuePartial { + return objectValuePartial{ value: value, } } diff --git a/knownvalue/object_partial_test.go b/knownvalue/object_partial_test.go index 150487c82..c0169f901 100644 --- a/knownvalue/object_partial_test.go +++ b/knownvalue/object_partial_test.go @@ -17,25 +17,27 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.ObjectValuePartial + self knownvalue.Check other any expectedError error }{ "zero-nil": { + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{}), expectedError: fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: "), }, "zero-other": { + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{}), other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), expectedError: fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: "), }, "wrong-type": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -43,7 +45,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("expected map[string]any value for ObjectValuePartial check, got: float64"), }, "empty": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -51,7 +53,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing attribute one for ObjectValuePartial check"), }, "wrong-length": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -62,7 +64,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing attribute three for ObjectValuePartial check"), }, "not-equal": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -71,10 +73,10 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "two": json.Number("4.56"), "three": json.Number("6.54"), }, - expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 6.54"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64ValueExact check, got: 6.54"), }, "wrong-order": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -83,10 +85,10 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { "two": json.Number("7.89"), "three": json.Number("4.56"), }, - expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 4.56"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64ValueExact check, got: 4.56"), }, "key-not-found": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), @@ -99,7 +101,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing attribute one for ObjectValuePartial check"), }, "equal": { - self: knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + self: knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }), @@ -129,7 +131,7 @@ func TestObjectValuePartial_CheckValue(t *testing.T) { func TestObjectValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ + got := knownvalue.ObjectValuePartial(map[string]knownvalue.Check{ "one": knownvalue.Float64ValueExact(1.23), "three": knownvalue.Float64ValueExact(7.89), }).String() diff --git a/knownvalue/object_test.go b/knownvalue/object_test.go index f281e3d6a..b6691c39f 100644 --- a/knownvalue/object_test.go +++ b/knownvalue/object_test.go @@ -17,14 +17,16 @@ func TestObjectValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.ObjectValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected map[string]any value for ObjectValue check, got: "), + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{}), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValueExact check, got: "), }, "zero-other": { + self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{}), other: map[string]any{}, // checking against the underlying value field zero-value }, "nil": { @@ -33,7 +35,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "two": knownvalue.Float64ValueExact(4.56), "three": knownvalue.Float64ValueExact(7.89), }), - expectedError: fmt.Errorf("expected map[string]any value for ObjectValue check, got: "), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValueExact check, got: "), }, "wrong-type": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -42,7 +44,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: 1.234, - expectedError: fmt.Errorf("expected map[string]any value for ObjectValue check, got: float64"), + expectedError: fmt.Errorf("expected map[string]any value for ObjectValueExact check, got: float64"), }, "empty": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -51,7 +53,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "three": knownvalue.Float64ValueExact(7.89), }), other: map[string]any{}, - expectedError: fmt.Errorf("expected 3 attributes for ObjectValue check, got 0 attributes"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectValueExact check, got 0 attributes"), }, "wrong-length": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -63,7 +65,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "one": json.Number("1.23"), "two": json.Number("4.56"), }, - expectedError: fmt.Errorf("expected 3 attributes for ObjectValue check, got 2 attributes"), + expectedError: fmt.Errorf("expected 3 attributes for ObjectValueExact check, got 2 attributes"), }, "not-equal": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -76,7 +78,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "two": json.Number("4.56"), "three": json.Number("6.54"), }, - expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 6.54"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64ValueExact check, got: 6.54"), }, "wrong-order": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -89,7 +91,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "two": json.Number("7.89"), "three": json.Number("4.56"), }, - expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64Value check, got: 4.56"), + expectedError: fmt.Errorf("three object attribute: expected value 7.89 for Float64ValueExact check, got: 4.56"), }, "key-not-found": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ @@ -102,7 +104,7 @@ func TestObjectValue_CheckValue(t *testing.T) { "five": json.Number("7.89"), "six": json.Number("4.56"), }, - expectedError: fmt.Errorf("missing attribute one for ObjectValue check"), + expectedError: fmt.Errorf("missing attribute one for ObjectValueExact check"), }, "equal": { self: knownvalue.ObjectValueExact(map[string]knownvalue.Check{ diff --git a/knownvalue/set.go b/knownvalue/set.go index 54996f164..c8c3ada22 100644 --- a/knownvalue/set.go +++ b/knownvalue/set.go @@ -7,21 +7,19 @@ import ( "fmt" ) -var _ Check = SetValue{} +var _ Check = setValueExact{} -// SetValue is a Check for asserting equality between the value supplied -// to SetValueExact and the value passed to the CheckValue method. -type SetValue struct { +type setValueExact struct { value []Check } // CheckValue determines whether the passed value is of type []any, and // contains matching slice entries independent of the sequence. -func (v SetValue) CheckValue(other any) error { +func (v setValueExact) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("expected []any value for SetValue check, got: %T", other) + return fmt.Errorf("expected []any value for SetValueExact check, got: %T", other) } if len(otherVal) != len(v.value) { @@ -36,7 +34,7 @@ func (v SetValue) CheckValue(other any) error { actualElements = "element" } - return fmt.Errorf("expected %d %s for SetValue check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) + return fmt.Errorf("expected %d %s for SetValueExact check, got %d %s", len(v.value), expectedElements, len(otherVal), actualElements) } otherValCopy := make([]any, len(otherVal)) @@ -44,7 +42,7 @@ func (v SetValue) CheckValue(other any) error { copy(otherValCopy, otherVal) for i := 0; i < len(v.value); i++ { - err := fmt.Errorf("missing value %s for SetValue check", v.value[i].String()) + err := fmt.Errorf("missing value %s for SetValueExact check", v.value[i].String()) for j := 0; j < len(otherValCopy); j++ { checkValueErr := v.value[i].CheckValue(otherValCopy[j]) @@ -68,7 +66,7 @@ func (v SetValue) CheckValue(other any) error { } // String returns the string representation of the value. -func (v SetValue) String() string { +func (v setValueExact) String() string { var setVals []string for _, val := range v.value { @@ -81,8 +79,8 @@ func (v SetValue) String() string { // SetValueExact returns a Check for asserting equality between the // supplied []Check and the value passed to the CheckValue method. // This is an order-independent check. -func SetValueExact(value []Check) SetValue { - return SetValue{ +func SetValueExact(value []Check) setValueExact { + return setValueExact{ value: value, } } diff --git a/knownvalue/set_elements.go b/knownvalue/set_elements.go index 25312b163..37d5f38ea 100644 --- a/knownvalue/set_elements.go +++ b/knownvalue/set_elements.go @@ -8,21 +8,19 @@ import ( "strconv" ) -var _ Check = SetElements{} +var _ Check = setElementsExact{} -// SetElements is a Check for asserting equality between the value supplied -// to SetElementsExact and the value passed to the CheckValue method. -type SetElements struct { +type setElementsExact struct { num int } // CheckValue verifies that the passed value is a list, map, object, // or set, and contains a matching number of elements. -func (v SetElements) CheckValue(other any) error { +func (v setElementsExact) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { - return fmt.Errorf("expected []any value for SetElements check, got: %T", other) + return fmt.Errorf("expected []any value for SetElementExact check, got: %T", other) } if len(otherVal) != v.num { @@ -37,21 +35,21 @@ func (v SetElements) CheckValue(other any) error { actualElements = "element" } - return fmt.Errorf("expected %d %s for SetElements check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) + return fmt.Errorf("expected %d %s for SetElementExact check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) } return nil } // String returns the string representation of the value. -func (v SetElements) String() string { +func (v setElementsExact) String() string { return strconv.FormatInt(int64(v.num), 10) } // SetElementsExact returns a Check for asserting that -// a list num elements. -func SetElementsExact(num int) SetElements { - return SetElements{ +// a set has num elements. +func SetElementsExact(num int) setElementsExact { + return setElementsExact{ num: num, } } diff --git a/knownvalue/set_elements_test.go b/knownvalue/set_elements_test.go index 522287dc3..cd2be6e36 100644 --- a/knownvalue/set_elements_test.go +++ b/knownvalue/set_elements_test.go @@ -16,29 +16,31 @@ func TestSetElements_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.SetElements + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected []any value for SetElements check, got: "), + self: knownvalue.SetElementsExact(0), + expectedError: fmt.Errorf("expected []any value for SetElementExact check, got: "), }, "zero-other": { + self: knownvalue.SetElementsExact(0), other: []any{}, // checking against the underlying value field zero-value }, "nil": { self: knownvalue.SetElementsExact(3), - expectedError: fmt.Errorf("expected []any value for SetElements check, got: "), + expectedError: fmt.Errorf("expected []any value for SetElementExact check, got: "), }, "wrong-type": { self: knownvalue.SetElementsExact(3), other: 1.234, - expectedError: fmt.Errorf("expected []any value for SetElements check, got: float64"), + expectedError: fmt.Errorf("expected []any value for SetElementExact check, got: float64"), }, "empty": { self: knownvalue.SetElementsExact(3), other: []any{}, - expectedError: fmt.Errorf("expected 3 elements for SetElements check, got 0 elements"), + expectedError: fmt.Errorf("expected 3 elements for SetElementExact check, got 0 elements"), }, "wrong-length": { self: knownvalue.SetElementsExact(3), @@ -46,7 +48,7 @@ func TestSetElements_CheckValue(t *testing.T) { int64(123), int64(456), }, - expectedError: fmt.Errorf("expected 3 elements for SetElements check, got 2 elements"), + expectedError: fmt.Errorf("expected 3 elements for SetElementExact check, got 2 elements"), }, "equal": { self: knownvalue.SetElementsExact(3), diff --git a/knownvalue/set_partial.go b/knownvalue/set_partial.go index 89da7510b..ba9717dc8 100644 --- a/knownvalue/set_partial.go +++ b/knownvalue/set_partial.go @@ -7,18 +7,15 @@ import ( "fmt" ) -var _ Check = SetValuePartial{} +var _ Check = setValuePartial{} -// SetValuePartial is a Check for asserting partial equality between the -// value supplied to SetValuePartialMatch and the value passed to the -// CheckValue method. -type SetValuePartial struct { +type setValuePartial struct { value []Check } // CheckValue determines whether the passed value is of type []any, and // contains matching slice entries in any sequence. -func (v SetValuePartial) CheckValue(other any) error { +func (v setValuePartial) CheckValue(other any) error { otherVal, ok := other.([]any) if !ok { @@ -54,7 +51,7 @@ func (v SetValuePartial) CheckValue(other any) error { } // String returns the string representation of the value. -func (v SetValuePartial) String() string { +func (v setValuePartial) String() string { var setVals []string for _, val := range v.value { @@ -64,12 +61,12 @@ func (v SetValuePartial) String() string { return fmt.Sprintf("%s", setVals) } -// SetValuePartialMatch returns a Check for asserting partial equality between the +// SetValuePartial returns a Check for asserting partial equality between the // supplied []Check and the value passed to the CheckValue method. Only the // elements defined within the supplied []Check are checked. This is an // order-independent check. -func SetValuePartialMatch(value []Check) SetValuePartial { - return SetValuePartial{ +func SetValuePartial(value []Check) setValuePartial { + return setValuePartial{ value: value, } } diff --git a/knownvalue/set_partial_test.go b/knownvalue/set_partial_test.go index 63d02d404..49f15cbdc 100644 --- a/knownvalue/set_partial_test.go +++ b/knownvalue/set_partial_test.go @@ -17,18 +17,20 @@ func TestSetValuePartial_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.SetValuePartial + self knownvalue.Check other any expectedError error }{ "zero-nil": { + self: knownvalue.SetValuePartial([]knownvalue.Check{}), expectedError: fmt.Errorf("expected []any value for SetValuePartial check, got: "), }, "zero-other": { + self: knownvalue.SetValuePartial([]knownvalue.Check{}), other: []any{}, // checking against the underlying value field zero-value }, "nil": { - self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + self: knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), @@ -36,7 +38,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("expected []any value for SetValuePartial check, got: "), }, "wrong-type": { - self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + self: knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), @@ -45,7 +47,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("expected []any value for SetValuePartial check, got: float64"), }, "equal-empty": { - self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + self: knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), @@ -54,7 +56,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing value 1.23 for SetValuePartial check"), }, "not-equal": { - self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + self: knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), @@ -68,7 +70,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { expectedError: fmt.Errorf("missing value 7.89 for SetValuePartial check"), }, "equal-different-order": { - self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + self: knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), @@ -81,7 +83,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { }, }, "equal-same-order": { - self: knownvalue.SetValuePartialMatch([]knownvalue.Check{ + self: knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), @@ -113,7 +115,7 @@ func TestSetValuePartial_CheckValue(t *testing.T) { func TestSetValuePartial_String(t *testing.T) { t.Parallel() - got := knownvalue.SetValuePartialMatch([]knownvalue.Check{ + got := knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.Float64ValueExact(1.23), knownvalue.Float64ValueExact(4.56), knownvalue.Float64ValueExact(7.89), diff --git a/knownvalue/set_test.go b/knownvalue/set_test.go index e89c89386..ebe03ec3d 100644 --- a/knownvalue/set_test.go +++ b/knownvalue/set_test.go @@ -17,14 +17,16 @@ func TestSetValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.SetValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected []any value for SetValue check, got: "), + self: knownvalue.SetValueExact([]knownvalue.Check{}), + expectedError: fmt.Errorf("expected []any value for SetValueExact check, got: "), }, "zero-other": { + self: knownvalue.SetValueExact([]knownvalue.Check{}), other: []any{}, // checking against the underlying value field zero-value }, "nil": { @@ -33,7 +35,7 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(456), knownvalue.Int64ValueExact(789), }), - expectedError: fmt.Errorf("expected []any value for SetValue check, got: "), + expectedError: fmt.Errorf("expected []any value for SetValueExact check, got: "), }, "wrong-type": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -42,7 +44,7 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: 1.234, - expectedError: fmt.Errorf("expected []any value for SetValue check, got: float64"), + expectedError: fmt.Errorf("expected []any value for SetValueExact check, got: float64"), }, "empty": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -51,7 +53,7 @@ func TestSetValue_CheckValue(t *testing.T) { knownvalue.Int64ValueExact(789), }), other: []any{}, - expectedError: fmt.Errorf("expected 3 elements for SetValue check, got 0 elements"), + expectedError: fmt.Errorf("expected 3 elements for SetValueExact check, got 0 elements"), }, "wrong-length": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -63,7 +65,7 @@ func TestSetValue_CheckValue(t *testing.T) { json.Number("123"), json.Number("456"), }, - expectedError: fmt.Errorf("expected 3 elements for SetValue check, got 2 elements"), + expectedError: fmt.Errorf("expected 3 elements for SetValueExact check, got 2 elements"), }, "not-equal": { self: knownvalue.SetValueExact([]knownvalue.Check{ @@ -76,7 +78,7 @@ func TestSetValue_CheckValue(t *testing.T) { json.Number("456"), json.Number("654"), }, - expectedError: fmt.Errorf("missing value 789 for SetValue check"), + expectedError: fmt.Errorf("missing value 789 for SetValueExact check"), }, "equal-different-order": { self: knownvalue.SetValueExact([]knownvalue.Check{ diff --git a/knownvalue/string.go b/knownvalue/string.go index 7ccc58aca..3686d5dda 100644 --- a/knownvalue/string.go +++ b/knownvalue/string.go @@ -5,39 +5,37 @@ package knownvalue import "fmt" -var _ Check = StringValue{} +var _ Check = stringValueExact{} -// StringValue is a Check for asserting equality between the value -// supplied to StringValueExact and the value passed to the CheckValue method. -type StringValue struct { +type stringValueExact struct { value string } // CheckValue determines whether the passed value is of type string, and // contains a matching sequence of bytes. -func (v StringValue) CheckValue(other any) error { +func (v stringValueExact) CheckValue(other any) error { otherVal, ok := other.(string) if !ok { - return fmt.Errorf("expected string value for StringValue check, got: %T", other) + return fmt.Errorf("expected string value for StringValueExact check, got: %T", other) } if otherVal != v.value { - return fmt.Errorf("expected value %s for StringValue check, got: %s", v.value, otherVal) + return fmt.Errorf("expected value %s for StringValueExact check, got: %s", v.value, otherVal) } return nil } // String returns the string representation of the value. -func (v StringValue) String() string { +func (v stringValueExact) String() string { return v.value } // StringValueExact returns a Check for asserting equality between the // supplied string and a value passed to the CheckValue method. -func StringValueExact(value string) StringValue { - return StringValue{ +func StringValueExact(value string) stringValueExact { + return stringValueExact{ value: value, } } diff --git a/knownvalue/string_test.go b/knownvalue/string_test.go index a08a53ee6..e97feaa92 100644 --- a/knownvalue/string_test.go +++ b/knownvalue/string_test.go @@ -16,29 +16,31 @@ func TestStringValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.StringValue + self knownvalue.Check other any expectedError error }{ "zero-nil": { - expectedError: fmt.Errorf("expected string value for StringValue check, got: "), + self: knownvalue.StringValueExact(""), + expectedError: fmt.Errorf("expected string value for StringValueExact check, got: "), }, "zero-other": { + self: knownvalue.StringValueExact(""), other: "", // checking against the underlying value field zero-value }, "nil": { self: knownvalue.StringValueExact("str"), - expectedError: fmt.Errorf("expected string value for StringValue check, got: "), + expectedError: fmt.Errorf("expected string value for StringValueExact check, got: "), }, "wrong-type": { self: knownvalue.StringValueExact("str"), other: 1.234, - expectedError: fmt.Errorf("expected string value for StringValue check, got: float64"), + expectedError: fmt.Errorf("expected string value for StringValueExact check, got: float64"), }, "not-equal": { self: knownvalue.StringValueExact("str"), other: "rts", - expectedError: fmt.Errorf("expected value str for StringValue check, got: rts"), + expectedError: fmt.Errorf("expected value str for StringValueExact check, got: rts"), }, "equal": { self: knownvalue.StringValueExact("str"), diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index ba3f2070f..fc44e6e3a 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -176,7 +176,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -217,7 +217,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), }, }, }) @@ -299,7 +299,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t ), }, }, - ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -340,7 +340,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t * ), }, }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -421,7 +421,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *te ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -511,7 +511,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -558,7 +558,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -598,7 +598,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -645,13 +645,13 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -738,7 +738,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListElements_WrongNum(t *testing ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -832,7 +832,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListNestedBlockPartial(t *testin plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -974,7 +974,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongType(t *testi ), }, }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -1021,7 +1021,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *test ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), }, }, }) @@ -1061,7 +1061,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -1106,7 +1106,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), @@ -1199,7 +1199,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapElements_WrongNum(t *testing. ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -1292,7 +1292,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Number_KnownValueWrongValue(t *t ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1385,7 +1385,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *test ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), }, }, }) @@ -1425,7 +1425,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1470,7 +1470,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), @@ -1613,7 +1613,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetNestedBlockPartial(t *testing plancheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -1744,7 +1744,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *te knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1784,7 +1784,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *t knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), }, }, }) @@ -1809,7 +1809,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_UnknownAttributeType(t *testing. }, }, }, - expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in plancheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers."), + expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.int64ValueExact\n\nThis is an error in plancheck.ExpectKnownOutputValueAtPath.\nPlease report this to the maintainers."), }, } diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 6e6363ffd..88192ede3 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -141,7 +141,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -174,7 +174,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), }, }, }) @@ -240,7 +240,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing ), }, }, - ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -273,7 +273,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongValue(t *testin ), }, }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -338,7 +338,7 @@ func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing. ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -412,7 +412,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -451,7 +451,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -483,7 +483,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -522,13 +522,13 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *te PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -599,7 +599,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -677,7 +677,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -795,7 +795,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -834,7 +834,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), }, }, }) @@ -866,7 +866,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -903,7 +903,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *tes PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), @@ -980,7 +980,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -1057,7 +1057,7 @@ func TestExpectKnownOutputValue_CheckPlan_Number_KnownValueWrongValue(t *testing ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1134,7 +1134,7 @@ func TestExpectKnownOutputValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), }, }, }) @@ -1166,7 +1166,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1203,7 +1203,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *tes PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), @@ -1322,7 +1322,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -1429,7 +1429,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongType(t *testing. knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1461,7 +1461,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongValue(t *testing knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), }, }, }) @@ -1486,7 +1486,7 @@ func TestExpectKnownOutputValue_CheckPlan_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in plancheck.ExpectKnownOutputValue.\nPlease report this to the maintainers."), + expectedErr: fmt.Errorf("unrecognised output type: float32, known value type is knownvalue.int64ValueExact\n\nThis is an error in plancheck.ExpectKnownOutputValue.\nPlease report this to the maintainers."), }, } diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index e4499bc01..05f87d226 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -130,7 +130,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -160,7 +160,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), }, }, }) @@ -220,7 +220,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -250,7 +250,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -309,7 +309,7 @@ func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -377,7 +377,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -413,7 +413,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -442,7 +442,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -478,13 +478,13 @@ func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing. plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -549,7 +549,7 @@ func TestExpectKnownValue_CheckPlan_ListElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -621,7 +621,7 @@ func TestExpectKnownValue_CheckPlan_ListNestedBlockPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -730,7 +730,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -766,7 +766,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), }, }, }) @@ -795,7 +795,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -829,7 +829,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), @@ -900,7 +900,7 @@ func TestExpectKnownValue_CheckPlan_MapElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -971,7 +971,7 @@ func TestExpectKnownValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1042,7 +1042,7 @@ func TestExpectKnownValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), }, }, }) @@ -1071,7 +1071,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1105,7 +1105,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), @@ -1215,7 +1215,7 @@ func TestExpectKnownValue_CheckPlan_SetNestedBlockPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -1313,7 +1313,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1342,7 +1342,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), }, }, }) @@ -1372,7 +1372,7 @@ func TestExpectKnownValue_CheckPlan_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("unrecognised attribute type: float32, known value type is knownvalue.Int64Value\n\nThis is an error in plancheck.ExpectKnownValue.\nPlease report this to the maintainers."), + expectedErr: fmt.Errorf("unrecognised attribute type: float32, known value type is knownvalue.int64ValueExact\n\nThis is an error in plancheck.ExpectKnownValue.\nPlease report this to the maintainers."), }, } From f1b96565241abb2b5d290e71076a46ad6b2c5251 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 10:40:48 +0000 Subject: [PATCH 38/48] Document usage of 512-bit precision in the number known value check (#266) --- knownvalue/number.go | 1 + 1 file changed, 1 insertion(+) diff --git a/knownvalue/number.go b/knownvalue/number.go index 98f54e733..042ba6a9c 100644 --- a/knownvalue/number.go +++ b/knownvalue/number.go @@ -48,6 +48,7 @@ func (v numberValueExact) String() string { // NumberValueExact returns a Check for asserting equality between the // supplied *big.Float and the value passed to the CheckValue method. +// The CheckValue method uses 512-bit precision to perform this assertion. func NumberValueExact(value *big.Float) numberValueExact { return numberValueExact{ value: value, From ed9d236b0d44040050e3b21b347caff4b0a7e95d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 12:02:26 +0000 Subject: [PATCH 39/48] Adding attribute or output path to error message (#266) --- plancheck/expect_known_output_value.go | 4 +- .../expect_known_output_value_at_path.go | 4 +- .../expect_known_output_value_at_path_test.go | 38 ++++++++--------- plancheck/expect_known_output_value_test.go | 38 ++++++++--------- plancheck/expect_known_value.go | 4 +- plancheck/expect_known_value_test.go | 38 ++++++++--------- tfjsonpath/path.go | 11 +++++ tfjsonpath/path_test.go | 42 +++++++++++++++++++ 8 files changed, 116 insertions(+), 63 deletions(-) diff --git a/plancheck/expect_known_output_value.go b/plancheck/expect_known_output_value.go index 8004f8764..33a27e2f5 100644 --- a/plancheck/expect_known_output_value.go +++ b/plancheck/expect_known_output_value.go @@ -49,7 +49,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ } if result == nil { - resp.Error = fmt.Errorf("value is null") + resp.Error = fmt.Errorf("value is null for output at path: %s", e.outputAddress) return } @@ -60,7 +60,7 @@ func (e expectKnownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRequ reflect.Slice, reflect.String: if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err + resp.Error = fmt.Errorf("error checking value for output at path: %s, err: %s", e.outputAddress, err) return } diff --git a/plancheck/expect_known_output_value_at_path.go b/plancheck/expect_known_output_value_at_path.go index 131cd86a5..056b7c2f7 100644 --- a/plancheck/expect_known_output_value_at_path.go +++ b/plancheck/expect_known_output_value_at_path.go @@ -50,7 +50,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl } if result == nil { - resp.Error = fmt.Errorf("value is null") + resp.Error = fmt.Errorf("value is null for output at path: %s.%s", e.outputAddress, e.outputPath.String()) return } @@ -61,7 +61,7 @@ func (e expectKnownOutputValueAtPath) CheckPlan(ctx context.Context, req CheckPl reflect.Slice, reflect.String: if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err + resp.Error = fmt.Errorf("error checking value for output at path: %s.%s, err: %s", e.outputAddress, e.outputPath.String(), err) return } diff --git a/plancheck/expect_known_output_value_at_path_test.go b/plancheck/expect_known_output_value_at_path_test.go index fc44e6e3a..ff2360324 100644 --- a/plancheck/expect_known_output_value_at_path_test.go +++ b/plancheck/expect_known_output_value_at_path_test.go @@ -95,7 +95,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_AttributeValueNull(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile("value is null"), + ExpectError: regexp.MustCompile("value is null for output at path: test_resource_one_output.bool_attribute"), }, }, }) @@ -176,7 +176,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.bool_attribute, err: expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -217,7 +217,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Bool_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.bool_attribute, err: expected value false for BoolValueExact check, got: true"), }, }, }) @@ -299,7 +299,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongType(t *t ), }, }, - ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.float_attribute, err: expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -340,7 +340,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Float64_KnownValueWrongValue(t * ), }, }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.float_attribute, err: expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -421,7 +421,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Int64_KnownValueWrongValue(t *te ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.int_attribute, err: expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -511,7 +511,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongType(t *test ), }, }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.list_attribute, err: expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -558,7 +558,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_List_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.list_attribute, err: list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -651,7 +651,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListPartial_KnownValueWrongValue ), }, }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.list_attribute, err: list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -738,7 +738,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_ListElements_WrongNum(t *testing ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.list_attribute, err: expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -974,7 +974,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongType(t *testi ), }, }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.map_attribute, err: expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -1021,7 +1021,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Map_KnownValueWrongValue(t *test ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.map_attribute, err: missing element key3 for MapValueExact check`), }, }, }) @@ -1112,7 +1112,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapPartial_KnownValueWrongValue( ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.map_attribute, err: missing element key3 for MapValuePartial check`), }, }, }) @@ -1199,7 +1199,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_MapElements_WrongNum(t *testing. ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.map_attribute, err: expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -1292,7 +1292,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Number_KnownValueWrongValue(t *t ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.int_attribute, err: expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1385,7 +1385,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_Set_KnownValueWrongValue(t *test ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.set_attribute, err: missing value value3 for SetValueExact check`), }, }, }) @@ -1476,7 +1476,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_SetPartial_KnownValueWrongValue( ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: test_resource_one_output.set_attribute, err: missing value value3 for SetValuePartial check`), }, }, }) @@ -1744,7 +1744,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongType(t *te knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.string_attribute, err: expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1784,7 +1784,7 @@ func TestExpectKnownOutputValueAtPath_CheckPlan_String_KnownValueWrongValue(t *t knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), + ExpectError: regexp.MustCompile("error checking value for output at path: test_resource_one_output.string_attribute, err: expected value rts for StringValueExact check, got: str"), }, }, }) diff --git a/plancheck/expect_known_output_value_test.go b/plancheck/expect_known_output_value_test.go index 88192ede3..03a018d55 100644 --- a/plancheck/expect_known_output_value_test.go +++ b/plancheck/expect_known_output_value_test.go @@ -76,7 +76,7 @@ func TestExpectKnownOutputValue_CheckPlan_AttributeValueNull(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("value is null"), + ExpectError: regexp.MustCompile("value is null for output at path: bool_output"), }, }, }) @@ -141,7 +141,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), + ExpectError: regexp.MustCompile(`error checking value for output at path: bool_output, err: expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -174,7 +174,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), + ExpectError: regexp.MustCompile("error checking value for output at path: bool_output, err: expected value false for BoolValueExact check, got: true"), }, }, }) @@ -240,7 +240,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongType(t *testing ), }, }, - ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), + ExpectError: regexp.MustCompile(`error checking value for output at path: float64_output, err: expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -273,7 +273,7 @@ func TestExpectKnownOutputValue_CheckPlan_Float64_KnownValueWrongValue(t *testin ), }, }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), + ExpectError: regexp.MustCompile("error checking value for output at path: float64_output, err: expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -338,7 +338,7 @@ func TestExpectKnownOutputValue_CheckPlan_Int64_KnownValueWrongValue(t *testing. ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), + ExpectError: regexp.MustCompile("error checking value for output at path: int64_output, err: expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -412,7 +412,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`error checking value for output at path: list_output, err: expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -451,7 +451,7 @@ func TestExpectKnownOutputValue_CheckPlan_List_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`error checking value for output at path: list_output, err: list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -528,7 +528,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListPartial_KnownValueWrongValue(t *te ), }, }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`error checking value for output at path: list_output, err: list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -599,7 +599,7 @@ func TestExpectKnownOutputValue_CheckPlan_ListElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("error checking value for output at path: list_output, err: expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -795,7 +795,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`error checking value for output at path: map_output, err: expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -834,7 +834,7 @@ func TestExpectKnownOutputValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: map_output, err: missing element key3 for MapValueExact check`), }, }, }) @@ -909,7 +909,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapPartial_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: map_output, err: missing element key3 for MapValuePartial check`), }, }, }) @@ -980,7 +980,7 @@ func TestExpectKnownOutputValue_CheckPlan_MapElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("error checking value for output at path: map_output, err: expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -1057,7 +1057,7 @@ func TestExpectKnownOutputValue_CheckPlan_Number_KnownValueWrongValue(t *testing ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), + ExpectError: regexp.MustCompile("error checking value for output at path: int64_output, err: expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1134,7 +1134,7 @@ func TestExpectKnownOutputValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: set_output, err: missing value value3 for SetValueExact check`), }, }, }) @@ -1209,7 +1209,7 @@ func TestExpectKnownOutputValue_CheckPlan_SetPartial_KnownValueWrongValue(t *tes ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + ExpectError: regexp.MustCompile(`error checking value for output at path: set_output, err: missing value value3 for SetValuePartial check`), }, }, }) @@ -1429,7 +1429,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongType(t *testing. knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), + ExpectError: regexp.MustCompile("error checking value for output at path: string_output, err: expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1461,7 +1461,7 @@ func TestExpectKnownOutputValue_CheckPlan_String_KnownValueWrongValue(t *testing knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), + ExpectError: regexp.MustCompile("error checking value for output at path: string_output, err: expected value rts for StringValueExact check, got: str"), }, }, }) diff --git a/plancheck/expect_known_value.go b/plancheck/expect_known_value.go index dc8829c97..1118b9a61 100644 --- a/plancheck/expect_known_value.go +++ b/plancheck/expect_known_value.go @@ -50,7 +50,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r } if result == nil { - resp.Error = fmt.Errorf("value is null") + resp.Error = fmt.Errorf("value is null for attribute at path: %s.%s", e.resourceAddress, e.attributePath.String()) return } @@ -61,7 +61,7 @@ func (e expectKnownValue) CheckPlan(ctx context.Context, req CheckPlanRequest, r reflect.Slice, reflect.String: if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err + resp.Error = fmt.Errorf("error checking value for attribute at path: %s.%s, err: %s", e.resourceAddress, e.attributePath.String(), err) return } diff --git a/plancheck/expect_known_value_test.go b/plancheck/expect_known_value_test.go index 05f87d226..ca122b91c 100644 --- a/plancheck/expect_known_value_test.go +++ b/plancheck/expect_known_value_test.go @@ -71,7 +71,7 @@ func TestExpectKnownValue_CheckPlan_AttributeValueNull(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("value is null"), + ExpectError: regexp.MustCompile("value is null for attribute at path: test_resource.one.bool_attribute"), }, }, }) @@ -130,7 +130,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.bool_attribute, err: expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -160,7 +160,7 @@ func TestExpectKnownValue_CheckPlan_Bool_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.bool_attribute, err: expected value false for BoolValueExact check, got: true"), }, }, }) @@ -220,7 +220,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.float_attribute, err: expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -250,7 +250,7 @@ func TestExpectKnownValue_CheckPlan_Float64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.float_attribute, err: expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -309,7 +309,7 @@ func TestExpectKnownValue_CheckPlan_Int64_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.int_attribute, err: expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -377,7 +377,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.list_attribute, err: expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -413,7 +413,7 @@ func TestExpectKnownValue_CheckPlan_List_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.list_attribute, err: list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -484,7 +484,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial_KnownValueWrongValue(t *testing. ), }, }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.list_attribute, err: list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -549,7 +549,7 @@ func TestExpectKnownValue_CheckPlan_ListElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.list_attribute, err: expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -730,7 +730,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongType(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.map_attribute, err: expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -766,7 +766,7 @@ func TestExpectKnownValue_CheckPlan_Map_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.map_attribute, err: missing element key3 for MapValueExact check`), }, }, }) @@ -835,7 +835,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.map_attribute, err: missing element key3 for MapValuePartial check`), }, }, }) @@ -900,7 +900,7 @@ func TestExpectKnownValue_CheckPlan_MapElements_WrongNum(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.map_attribute, err: expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -971,7 +971,7 @@ func TestExpectKnownValue_CheckPlan_Number_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.int_attribute, err: expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1042,7 +1042,7 @@ func TestExpectKnownValue_CheckPlan_Set_KnownValueWrongValue(t *testing.T) { ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.set_attribute, err: missing value value3 for SetValueExact check`), }, }, }) @@ -1111,7 +1111,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial_KnownValueWrongValue(t *testing.T ), }, }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + ExpectError: regexp.MustCompile(`error checking value for attribute at path: test_resource.one.set_attribute, err: missing value value3 for SetValuePartial check`), }, }, }) @@ -1313,7 +1313,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongType(t *testing.T) { knownvalue.BoolValueExact(true)), }, }, - ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.string_attribute, err: expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1342,7 +1342,7 @@ func TestExpectKnownValue_CheckPlan_String_KnownValueWrongValue(t *testing.T) { knownvalue.StringValueExact("rts")), }, }, - ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), + ExpectError: regexp.MustCompile("error checking value for attribute at path: test_resource.one.string_attribute, err: expected value rts for StringValueExact check, got: str"), }, }, }) diff --git a/tfjsonpath/path.go b/tfjsonpath/path.go index 980cf1fea..c29ae2608 100644 --- a/tfjsonpath/path.go +++ b/tfjsonpath/path.go @@ -74,6 +74,17 @@ func (s Path) AtMapKey(key string) Path { return s } +// String returns a string representation of the Path. +func (s Path) String() string { + var pathStr []string + + for _, step := range s.steps { + pathStr = append(pathStr, fmt.Sprintf("%v", step)) + } + + return strings.Join(pathStr, ".") +} + // Traverse returns the element found when traversing the given // object using the specified Path. The object is an unmarshalled // JSON object representing Terraform data. diff --git a/tfjsonpath/path_test.go b/tfjsonpath/path_test.go index e18448728..83c13061c 100644 --- a/tfjsonpath/path_test.go +++ b/tfjsonpath/path_test.go @@ -7,6 +7,8 @@ import ( "encoding/json" "strings" "testing" + + "github.com/google/go-cmp/cmp" ) func Test_Traverse_StringValue(t *testing.T) { @@ -488,6 +490,46 @@ func Test_Traverse_Array_ExpectError(t *testing.T) { } } +func TestPath_String(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + path Path + expected string + }{ + "slice_step": { + path: New(1), + expected: "1", + }, + "map_step": { + path: New("attr"), + expected: "attr", + }, + "slice_step_map_step": { + path: New(0).AtMapKey("attr"), + expected: "0.attr", + }, + "map_step_slice_step": { + path: New("attr").AtSliceIndex(0), + expected: "attr.0", + }, + } + + for name, tc := range testCases { + name, tc := name, tc + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := tc.path.String() + + if diff := cmp.Diff(got, tc.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func createTestObject() any { var jsonObject any jsonstring := From 9bdf445d861012ad2671034e79810ecc36ac50f8 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 12:07:53 +0000 Subject: [PATCH 40/48] Replacing alias in example code (#266) --- .../known-value-checks/bool.mdx | 6 +++--- .../known-value-checks/float64.mdx | 6 +++--- .../known-value-checks/int64.mdx | 6 +++--- .../known-value-checks/list.mdx | 18 +++++++++--------- .../known-value-checks/map.mdx | 18 +++++++++--------- .../known-value-checks/number.mdx | 6 +++--- .../known-value-checks/object.mdx | 18 +++++++++--------- .../known-value-checks/set.mdx | 18 +++++++++--------- .../known-value-checks/string.mdx | 6 +++--- 9 files changed, 51 insertions(+), 51 deletions(-) diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx index 9d5b345c6..039bc347b 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx @@ -20,15 +20,15 @@ Example usage of [BoolValueExact](https://pkg.go.dev/github.com/hashicorp/terraf func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { bool_attribute = true } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx index 6509178e1..d4bacb127 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx @@ -20,15 +20,15 @@ Example usage of [Float64ValueExact](https://pkg.go.dev/github.com/hashicorp/ter func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { float_attribute = 1.23 } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx index 0584c8cfc..9954cd7ec 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx @@ -20,15 +20,15 @@ Example usage of [Int64ValueExact](https://pkg.go.dev/github.com/hashicorp/terra func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { int_attribute = 123 } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx index 03d74d170..774cedc02 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx @@ -22,9 +22,9 @@ Example usage of [ListElementsExact](https://pkg.go.dev/github.com/hashicorp/ter func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { list_attribute = [ @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { ] } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -58,9 +58,9 @@ Example usage of [ListValueExact](https://pkg.go.dev/github.com/hashicorp/terraf func TestExpectKnownValue_CheckPlan_List(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { list_attribute = [ @@ -69,7 +69,7 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { ] } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -97,9 +97,9 @@ Example usage of [ListValuePartialMatch](https://pkg.go.dev/github.com/hashicorp func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { list_attribute = [ @@ -108,7 +108,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { ] } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx index 9b66acd21..ea1a5c252 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx @@ -22,9 +22,9 @@ Example usage of [MapElementsExact](https://pkg.go.dev/github.com/hashicorp/terr func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { map_attribute = { @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { } } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -58,9 +58,9 @@ Example usage of [MapValueExact](https://pkg.go.dev/github.com/hashicorp/terrafo func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { map_attribute = { @@ -69,7 +69,7 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { } } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -99,9 +99,9 @@ In this example, only the element associated with `key1` within the map is check func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { map_attribute = { @@ -110,7 +110,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { } } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx index c069eaa9b..784146c06 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx @@ -26,15 +26,15 @@ func TestExpectKnownValue_CheckPlan_Number(t *testing.T) { t.Errorf("%s", err) } - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { number_attribute = 123 } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx index 5f0f237a2..55e4b923b 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx @@ -22,9 +22,9 @@ Example usage of [ObjectElementsExact](https://pkg.go.dev/github.com/hashicorp/t func TestExpectKnownValue_CheckPlan_ObjectElements(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { object_attribute = { @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_ObjectElements(t *testing.T) { } } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -58,9 +58,9 @@ Example usage of [ObjectValueExact](https://pkg.go.dev/github.com/hashicorp/terr func TestExpectKnownValue_CheckPlan_Object(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { object_attribute = { @@ -69,7 +69,7 @@ func TestExpectKnownValue_CheckPlan_Object(t *testing.T) { } } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -99,9 +99,9 @@ In this example, only the attribute value associated with the attribute name `at func TestExpectKnownValue_CheckPlan_ObjectPartial(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { object_attribute = { @@ -110,7 +110,7 @@ func TestExpectKnownValue_CheckPlan_ObjectPartial(t *testing.T) { } } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx index 41d1e1319..64d646a2b 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx @@ -22,9 +22,9 @@ Example usage of [SetElementsExact](https://pkg.go.dev/github.com/hashicorp/terr func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { set_attribute = [ @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { ] } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -58,9 +58,9 @@ Example usage of [SetValueExact](https://pkg.go.dev/github.com/hashicorp/terrafo func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { set_attribute = [ @@ -69,7 +69,7 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { ] } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", @@ -97,9 +97,9 @@ Example usage of [SetValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { set_attribute = [ @@ -108,7 +108,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { ] } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx index 9b8dead06..2d771964b 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx @@ -20,15 +20,15 @@ Example usage of [StringValueExact](https://pkg.go.dev/github.com/hashicorp/terr func TestExpectKnownValue_CheckPlan_String(t *testing.T) { t.Parallel() - r.Test(t, r.TestCase{ + resource.Test(t, resource.TestCase{ // Provider definition omitted. - Steps: []r.TestStep{ + Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { string_attribute = "str" } `, - ConfigPlanChecks: r.ConfigPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownValue( "test_resource.one", From 0849854e89600688a16f848310f0435ab41af902 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 12:09:04 +0000 Subject: [PATCH 41/48] Rename file (#266) --- knownvalue/{known_value.go => check.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename knownvalue/{known_value.go => check.go} (100%) diff --git a/knownvalue/known_value.go b/knownvalue/check.go similarity index 100% rename from knownvalue/known_value.go rename to knownvalue/check.go From 831ba05303afa2eb663b97cc434282d55ac8cd3c Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 14:29:54 +0000 Subject: [PATCH 42/48] Adding changelog entries (#266) --- .changes/unreleased/FEATURES-20240111-142126.yaml | 6 ++++++ .changes/unreleased/FEATURES-20240111-142223.yaml | 6 ++++++ .changes/unreleased/FEATURES-20240111-142314.yaml | 6 ++++++ .changes/unreleased/FEATURES-20240111-142353.yaml | 6 ++++++ .changes/unreleased/FEATURES-20240111-142544.yaml | 6 ++++++ 5 files changed, 30 insertions(+) create mode 100644 .changes/unreleased/FEATURES-20240111-142126.yaml create mode 100644 .changes/unreleased/FEATURES-20240111-142223.yaml create mode 100644 .changes/unreleased/FEATURES-20240111-142314.yaml create mode 100644 .changes/unreleased/FEATURES-20240111-142353.yaml create mode 100644 .changes/unreleased/FEATURES-20240111-142544.yaml diff --git a/.changes/unreleased/FEATURES-20240111-142126.yaml b/.changes/unreleased/FEATURES-20240111-142126.yaml new file mode 100644 index 000000000..99c271b7c --- /dev/null +++ b/.changes/unreleased/FEATURES-20240111-142126.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'statecheck: Introduced new `statecheck` package with interface and built-in + state check functionality' +time: 2024-01-11T14:21:26.261094Z +custom: + Issue: "273" diff --git a/.changes/unreleased/FEATURES-20240111-142223.yaml b/.changes/unreleased/FEATURES-20240111-142223.yaml new file mode 100644 index 000000000..ca6a2a386 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240111-142223.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'statecheck: Added `ExpectKnownValue` state check, which asserts that a given + resource attribute has a defined type, and value' +time: 2024-01-11T14:22:23.072321Z +custom: + Issue: "273" diff --git a/.changes/unreleased/FEATURES-20240111-142314.yaml b/.changes/unreleased/FEATURES-20240111-142314.yaml new file mode 100644 index 000000000..3d683c564 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240111-142314.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'statecheck: Added `ExpectKnownOutputValue` state check, which asserts that + a given output value has a defined type, and value' +time: 2024-01-11T14:23:14.025585Z +custom: + Issue: "273" diff --git a/.changes/unreleased/FEATURES-20240111-142353.yaml b/.changes/unreleased/FEATURES-20240111-142353.yaml new file mode 100644 index 000000000..eaa67ae05 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240111-142353.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'statecheck: Added `ExpectKnownOutputValueAtPath` plan check, which asserts + that a given output value at a specified path has a defined type, and value' +time: 2024-01-11T14:23:53.633255Z +custom: + Issue: "273" diff --git a/.changes/unreleased/FEATURES-20240111-142544.yaml b/.changes/unreleased/FEATURES-20240111-142544.yaml new file mode 100644 index 000000000..42bf8aa03 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240111-142544.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'statecheck: Added `ExpectSensitiveValue` built-in state check, which asserts + that a given attribute has a sensitive value' +time: 2024-01-11T14:25:44.598583Z +custom: + Issue: "273" From 39cc063e173bb7ad42d72d74ddab803736f92562 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 11 Jan 2024 14:40:05 +0000 Subject: [PATCH 43/48] Refactoring to use updated known value check types (#266) --- .../expect_known_output_value_at_path_test.go | 50 +++++++++---------- statecheck/expect_known_output_value_test.go | 50 +++++++++---------- statecheck/expect_known_value_test.go | 50 +++++++++---------- statecheck/expect_sensitive_value.go | 2 - 4 files changed, 75 insertions(+), 77 deletions(-) diff --git a/statecheck/expect_known_output_value_at_path_test.go b/statecheck/expect_known_output_value_at_path_test.go index 371847b69..3fcd64637 100644 --- a/statecheck/expect_known_output_value_at_path_test.go +++ b/statecheck/expect_known_output_value_at_path_test.go @@ -138,7 +138,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongType(t *tes knownvalue.Float64ValueExact(1.23), ), }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -170,7 +170,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongValue(t *te knownvalue.BoolValueExact(false), ), }, - ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), }, }, }) @@ -234,7 +234,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongType(t * knownvalue.StringValueExact("str"), ), }, - ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -266,7 +266,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongValue(t knownvalue.Float64ValueExact(3.21), ), }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -329,7 +329,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Int64_KnownValueWrongValue(t *t knownvalue.Int64ValueExact(321), ), }, - ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -401,7 +401,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongType(t *tes knownvalue.MapValueExact(map[string]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -439,7 +439,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongValue(t *te }), ), }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -471,7 +471,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListPartial(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -509,12 +509,12 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListPartial_KnownValueWrongValu statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -583,7 +583,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListElements_WrongNum(t *testin knownvalue.ListElementsExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -660,7 +660,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockPartial(t *testi statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -774,7 +774,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongType(t *test knownvalue.ListValueExact([]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -812,7 +812,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongValue(t *tes }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), }, }, }) @@ -844,7 +844,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapPartial(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -880,7 +880,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapPartial_KnownValueWrongValue statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), @@ -954,7 +954,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapElements_WrongNum(t *testing knownvalue.MapElementsExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -1029,7 +1029,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Number_KnownValueWrongValue(t * knownvalue.NumberValueExact(f), ), }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1104,7 +1104,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Set_KnownValueWrongValue(t *tes }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), }, }, }) @@ -1136,7 +1136,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetPartial(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1172,7 +1172,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetPartial_KnownValueWrongValue statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), @@ -1288,7 +1288,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockPartial(t *testin statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -1391,7 +1391,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongType(t *t tfjsonpath.New("string_attribute"), knownvalue.BoolValueExact(true)), }, - ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1422,7 +1422,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongValue(t * tfjsonpath.New("string_attribute"), knownvalue.StringValueExact("rts")), }, - ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), }, }, }) @@ -1449,7 +1449,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64Value check, got: float32"), + expectedErr: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: float32"), }, } diff --git a/statecheck/expect_known_output_value_test.go b/statecheck/expect_known_output_value_test.go index e081b0716..e4af792d5 100644 --- a/statecheck/expect_known_output_value_test.go +++ b/statecheck/expect_known_output_value_test.go @@ -137,7 +137,7 @@ func TestExpectKnownOutputValue_CheckState_Bool_KnownValueWrongType(t *testing.T knownvalue.Float64ValueExact(1.23), ), }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -168,7 +168,7 @@ func TestExpectKnownOutputValue_CheckState_Bool_KnownValueWrongValue(t *testing. knownvalue.BoolValueExact(false), ), }, - ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), }, }, }) @@ -230,7 +230,7 @@ func TestExpectKnownOutputValue_CheckState_Float64_KnownValueWrongType(t *testin knownvalue.StringValueExact("str"), ), }, - ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -261,7 +261,7 @@ func TestExpectKnownOutputValue_CheckState_Float64_KnownValueWrongValue(t *testi knownvalue.Float64ValueExact(3.21), ), }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -322,7 +322,7 @@ func TestExpectKnownOutputValue_CheckState_Int64_KnownValueWrongValue(t *testing knownvalue.Int64ValueExact(321), ), }, - ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -392,7 +392,7 @@ func TestExpectKnownOutputValue_CheckState_List_KnownValueWrongType(t *testing.T knownvalue.MapValueExact(map[string]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -429,7 +429,7 @@ func TestExpectKnownOutputValue_CheckState_List_KnownValueWrongValue(t *testing. }), ), }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -460,7 +460,7 @@ func TestExpectKnownOutputValue_CheckState_ListPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -497,12 +497,12 @@ func TestExpectKnownOutputValue_CheckState_ListPartial_KnownValueWrongValue(t *t ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -569,7 +569,7 @@ func TestExpectKnownOutputValue_CheckState_ListElements_WrongNum(t *testing.T) { knownvalue.ListElementsExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -644,7 +644,7 @@ func TestExpectKnownOutputValue_CheckState_ListNestedBlockPartial(t *testing.T) ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -755,7 +755,7 @@ func TestExpectKnownOutputValue_CheckState_Map_KnownValueWrongType(t *testing.T) knownvalue.ListValueExact([]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -792,7 +792,7 @@ func TestExpectKnownOutputValue_CheckState_Map_KnownValueWrongValue(t *testing.T }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), }, }, }) @@ -823,7 +823,7 @@ func TestExpectKnownOutputValue_CheckState_MapPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -858,7 +858,7 @@ func TestExpectKnownOutputValue_CheckState_MapPartial_KnownValueWrongValue(t *te ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), @@ -930,7 +930,7 @@ func TestExpectKnownOutputValue_CheckState_MapElements_WrongNum(t *testing.T) { knownvalue.MapElementsExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -1003,7 +1003,7 @@ func TestExpectKnownOutputValue_CheckState_Number_KnownValueWrongValue(t *testin knownvalue.NumberValueExact(f), ), }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -1076,7 +1076,7 @@ func TestExpectKnownOutputValue_CheckState_Set_KnownValueWrongValue(t *testing.T }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), }, }, }) @@ -1107,7 +1107,7 @@ func TestExpectKnownOutputValue_CheckState_SetPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1142,7 +1142,7 @@ func TestExpectKnownOutputValue_CheckState_SetPartial_KnownValueWrongValue(t *te ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), @@ -1255,7 +1255,7 @@ func TestExpectKnownOutputValue_CheckState_SetNestedBlockPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -1355,7 +1355,7 @@ func TestExpectKnownOutputValue_CheckState_String_KnownValueWrongType(t *testing "string_output", knownvalue.BoolValueExact(true)), }, - ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1385,7 +1385,7 @@ func TestExpectKnownOutputValue_CheckState_String_KnownValueWrongValue(t *testin "string_output", knownvalue.StringValueExact("rts")), }, - ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), }, }, }) @@ -1412,7 +1412,7 @@ func TestExpectKnownOutputValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64Value check, got: float32"), + expectedErr: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: float32"), }, } diff --git a/statecheck/expect_known_value_test.go b/statecheck/expect_known_value_test.go index ce2d0a5c9..c95086d4b 100644 --- a/statecheck/expect_known_value_test.go +++ b/statecheck/expect_known_value_test.go @@ -122,7 +122,7 @@ func TestExpectKnownValue_CheckState_Bool_KnownValueWrongType(t *testing.T) { knownvalue.Float64ValueExact(1.23), ), }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Value check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), }, }, }) @@ -150,7 +150,7 @@ func TestExpectKnownValue_CheckState_Bool_KnownValueWrongValue(t *testing.T) { knownvalue.BoolValueExact(false), ), }, - ExpectError: regexp.MustCompile("expected value false for BoolValue check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), }, }, }) @@ -206,7 +206,7 @@ func TestExpectKnownValue_CheckState_Float64_KnownValueWrongType(t *testing.T) { knownvalue.StringValueExact("str"), ), }, - ExpectError: regexp.MustCompile(`expected string value for StringValue check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), }, }, }) @@ -234,7 +234,7 @@ func TestExpectKnownValue_CheckState_Float64_KnownValueWrongValue(t *testing.T) knownvalue.Float64ValueExact(3.21), ), }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64Value check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), }, }, }) @@ -289,7 +289,7 @@ func TestExpectKnownValue_CheckState_Int64_KnownValueWrongValue(t *testing.T) { knownvalue.Int64ValueExact(321), ), }, - ExpectError: regexp.MustCompile("expected value 321 for Int64Value check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), }, }, }) @@ -353,7 +353,7 @@ func TestExpectKnownValue_CheckState_List_KnownValueWrongType(t *testing.T) { knownvalue.MapValueExact(map[string]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValue check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), }, }, }) @@ -387,7 +387,7 @@ func TestExpectKnownValue_CheckState_List_KnownValueWrongValue(t *testing.T) { }), ), }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -415,7 +415,7 @@ func TestExpectKnownValue_CheckState_ListPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value1"), }), ), @@ -449,12 +449,12 @@ func TestExpectKnownValue_CheckState_ListPartial_KnownValueWrongValue(t *testing statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 0: knownvalue.StringValueExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValue check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), }, }, }) @@ -515,7 +515,7 @@ func TestExpectKnownValue_CheckState_ListElements_WrongNum(t *testing.T) { knownvalue.ListElementsExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), }, }, }) @@ -584,7 +584,7 @@ func TestExpectKnownValue_CheckState_ListNestedBlockPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ + knownvalue.ListValuePartial(map[int]knownvalue.Check{ 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ "list_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -686,7 +686,7 @@ func TestExpectKnownValue_CheckState_Map_KnownValueWrongType(t *testing.T) { knownvalue.ListValueExact([]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValue check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), }, }, }) @@ -720,7 +720,7 @@ func TestExpectKnownValue_CheckState_Map_KnownValueWrongValue(t *testing.T) { }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValue check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), }, }, }) @@ -748,7 +748,7 @@ func TestExpectKnownValue_CheckState_MapPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key1": knownvalue.StringValueExact("value1"), }), ), @@ -780,7 +780,7 @@ func TestExpectKnownValue_CheckState_MapPartial_KnownValueWrongValue(t *testing. statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ + knownvalue.MapValuePartial(map[string]knownvalue.Check{ "key3": knownvalue.StringValueExact("value1"), }), ), @@ -846,7 +846,7 @@ func TestExpectKnownValue_CheckState_MapElements_WrongNum(t *testing.T) { knownvalue.MapElementsExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElements check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), }, }, }) @@ -913,7 +913,7 @@ func TestExpectKnownValue_CheckState_Number_KnownValueWrongValue(t *testing.T) { knownvalue.NumberValueExact(f), ), }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValue check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), }, }, }) @@ -980,7 +980,7 @@ func TestExpectKnownValue_CheckState_Set_KnownValueWrongValue(t *testing.T) { }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValue check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), }, }, }) @@ -1008,7 +1008,7 @@ func TestExpectKnownValue_CheckState_SetPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value2"), }), ), @@ -1040,7 +1040,7 @@ func TestExpectKnownValue_CheckState_SetPartial_KnownValueWrongValue(t *testing. statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.StringValueExact("value3"), }), ), @@ -1144,7 +1144,7 @@ func TestExpectKnownValue_CheckState_SetNestedBlockPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ + knownvalue.SetValuePartial([]knownvalue.Check{ knownvalue.MapValueExact(map[string]knownvalue.Check{ "set_nested_block_attribute": knownvalue.StringValueExact("rts"), }), @@ -1235,7 +1235,7 @@ func TestExpectKnownValue_CheckState_String_KnownValueWrongType(t *testing.T) { tfjsonpath.New("string_attribute"), knownvalue.BoolValueExact(true)), }, - ExpectError: regexp.MustCompile("expected bool value for BoolValue check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), }, }, }) @@ -1262,7 +1262,7 @@ func TestExpectKnownValue_CheckState_String_KnownValueWrongValue(t *testing.T) { tfjsonpath.New("string_attribute"), knownvalue.StringValueExact("rts")), }, - ExpectError: regexp.MustCompile("expected value rts for StringValue check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), }, }, }) @@ -1294,7 +1294,7 @@ func TestExpectKnownValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64Value check, got: float32"), + expectedErr: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: float32"), }, } diff --git a/statecheck/expect_sensitive_value.go b/statecheck/expect_sensitive_value.go index 7e8ec7325..447a2cb27 100644 --- a/statecheck/expect_sensitive_value.go +++ b/statecheck/expect_sensitive_value.go @@ -78,8 +78,6 @@ func (e expectSensitiveValue) CheckState(ctx context.Context, req CheckStateRequ resp.Error = fmt.Errorf("attribute at path is not sensitive") return } - - return } // ExpectSensitiveValue returns a state check that asserts that the specified attribute at the given resource has a sensitive value. From 69f516d729446de35fe3d17c416d2d95036cc9dd Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 15 Jan 2024 14:57:15 +0000 Subject: [PATCH 44/48] Removing unused known value check types (#266) --- knownvalue/list_elements.go | 55 ------------------ knownvalue/list_elements_test.go | 86 ---------------------------- knownvalue/map_elements.go | 55 ------------------ knownvalue/map_elements_test.go | 86 ---------------------------- knownvalue/object_attributes.go | 55 ------------------ knownvalue/object_attributes_test.go | 86 ---------------------------- knownvalue/set_elements.go | 55 ------------------ knownvalue/set_elements_test.go | 86 ---------------------------- 8 files changed, 564 deletions(-) delete mode 100644 knownvalue/list_elements.go delete mode 100644 knownvalue/list_elements_test.go delete mode 100644 knownvalue/map_elements.go delete mode 100644 knownvalue/map_elements_test.go delete mode 100644 knownvalue/object_attributes.go delete mode 100644 knownvalue/object_attributes_test.go delete mode 100644 knownvalue/set_elements.go delete mode 100644 knownvalue/set_elements_test.go diff --git a/knownvalue/list_elements.go b/knownvalue/list_elements.go deleted file mode 100644 index 8e524e11d..000000000 --- a/knownvalue/list_elements.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue - -import ( - "fmt" - "strconv" -) - -var _ Check = listElementsExact{} - -type listElementsExact struct { - num int -} - -// CheckValue verifies that the passed value is a list, map, object, -// or set, and contains a matching number of elements. -func (v listElementsExact) CheckValue(other any) error { - otherVal, ok := other.([]any) - - if !ok { - return fmt.Errorf("expected []any value for ListElementsExact check, got: %T", other) - } - - if len(otherVal) != v.num { - expectedElements := "elements" - actualElements := "elements" - - if v.num == 1 { - expectedElements = "element" - } - - if len(otherVal) == 1 { - actualElements = "element" - } - - return fmt.Errorf("expected %d %s for ListElementsExact check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) - } - - return nil -} - -// String returns the string representation of the value. -func (v listElementsExact) String() string { - return strconv.FormatInt(int64(v.num), 10) -} - -// ListElementsExact returns a Check for asserting that -// a list has num elements. -func ListElementsExact(num int) listElementsExact { - return listElementsExact{ - num: num, - } -} diff --git a/knownvalue/list_elements_test.go b/knownvalue/list_elements_test.go deleted file mode 100644 index d48196510..000000000 --- a/knownvalue/list_elements_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue_test - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/hashicorp/terraform-plugin-testing/knownvalue" -) - -func TestListElements_CheckValue(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - self knownvalue.Check - other any - expectedError error - }{ - "zero-nil": { - self: knownvalue.ListElementsExact(0), - expectedError: fmt.Errorf("expected []any value for ListElementsExact check, got: "), - }, - "zero-other": { - self: knownvalue.ListElementsExact(0), - other: []any{}, // checking against the underlying value field zero-value - }, - "nil": { - self: knownvalue.ListElementsExact(3), - expectedError: fmt.Errorf("expected []any value for ListElementsExact check, got: "), - }, - "wrong-type": { - self: knownvalue.ListElementsExact(3), - other: 1.234, - expectedError: fmt.Errorf("expected []any value for ListElementsExact check, got: float64"), - }, - "empty": { - self: knownvalue.ListElementsExact(3), - other: []any{}, - expectedError: fmt.Errorf("expected 3 elements for ListElementsExact check, got 0 elements"), - }, - "wrong-length": { - self: knownvalue.ListElementsExact(3), - other: []any{ - int64(123), - int64(456), - }, - expectedError: fmt.Errorf("expected 3 elements for ListElementsExact check, got 2 elements"), - }, - "equal": { - self: knownvalue.ListElementsExact(3), - other: []any{ - int64(123), - int64(456), - int64(789), - }, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := testCase.self.CheckValue(testCase.other) - - if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} - -func TestListElements_String(t *testing.T) { - t.Parallel() - - got := knownvalue.ListElementsExact(2).String() - - if diff := cmp.Diff(got, "2"); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } -} diff --git a/knownvalue/map_elements.go b/knownvalue/map_elements.go deleted file mode 100644 index 9397a4252..000000000 --- a/knownvalue/map_elements.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue - -import ( - "fmt" - "strconv" -) - -var _ Check = mapElementsExact{} - -type mapElementsExact struct { - num int -} - -// CheckValue verifies that the passed value is a list, map, object, -// or set, and contains a matching number of elements. -func (v mapElementsExact) CheckValue(other any) error { - otherVal, ok := other.(map[string]any) - - if !ok { - return fmt.Errorf("expected map[string]any value for MapElementsExact check, got: %T", other) - } - - if len(otherVal) != v.num { - expectedElements := "elements" - actualElements := "elements" - - if v.num == 1 { - expectedElements = "element" - } - - if len(otherVal) == 1 { - actualElements = "element" - } - - return fmt.Errorf("expected %d %s for MapElementsExact check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) - } - - return nil -} - -// String returns the string representation of the value. -func (v mapElementsExact) String() string { - return strconv.Itoa(v.num) -} - -// MapElementsExact returns a Check for asserting that -// a map has num elements. -func MapElementsExact(num int) mapElementsExact { - return mapElementsExact{ - num: num, - } -} diff --git a/knownvalue/map_elements_test.go b/knownvalue/map_elements_test.go deleted file mode 100644 index 0dca62afa..000000000 --- a/knownvalue/map_elements_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue_test - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/hashicorp/terraform-plugin-testing/knownvalue" -) - -func TestMapElements_CheckValue(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - self knownvalue.Check - other any - expectedError error - }{ - "zero-nil": { - self: knownvalue.MapElementsExact(0), - expectedError: fmt.Errorf("expected map[string]any value for MapElementsExact check, got: "), - }, - "zero-other": { - self: knownvalue.MapElementsExact(0), - other: map[string]any{}, // checking against the underlying value field zero-value - }, - "nil": { - self: knownvalue.MapElementsExact(3), - expectedError: fmt.Errorf("expected map[string]any value for MapElementsExact check, got: "), - }, - "wrong-type": { - self: knownvalue.MapElementsExact(3), - other: 1.234, - expectedError: fmt.Errorf("expected map[string]any value for MapElementsExact check, got: float64"), - }, - "empty": { - self: knownvalue.MapElementsExact(3), - other: map[string]any{}, - expectedError: fmt.Errorf("expected 3 elements for MapElementsExact check, got 0 elements"), - }, - "wrong-length": { - self: knownvalue.MapElementsExact(3), - other: map[string]any{ - "one": int64(123), - "two": int64(456), - }, - expectedError: fmt.Errorf("expected 3 elements for MapElementsExact check, got 2 elements"), - }, - "equal": { - self: knownvalue.MapElementsExact(3), - other: map[string]any{ - "one": int64(123), - "two": int64(456), - "three": int64(789), - }, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := testCase.self.CheckValue(testCase.other) - - if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} - -func TestMapElements_String(t *testing.T) { - t.Parallel() - - got := knownvalue.MapElementsExact(2).String() - - if diff := cmp.Diff(got, "2"); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } -} diff --git a/knownvalue/object_attributes.go b/knownvalue/object_attributes.go deleted file mode 100644 index b4e03012e..000000000 --- a/knownvalue/object_attributes.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue - -import ( - "fmt" - "strconv" -) - -var _ Check = objectAttributesExact{} - -type objectAttributesExact struct { - num int -} - -// CheckValue verifies that the passed value is a list, map, object, -// or set, and contains a matching number of elements. -func (v objectAttributesExact) CheckValue(other any) error { - otherVal, ok := other.(map[string]any) - - if !ok { - return fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: %T", other) - } - - if len(otherVal) != v.num { - expectedAttributes := "attributes" - actualAttributes := "attributes" - - if v.num == 1 { - expectedAttributes = "attribute" - } - - if len(otherVal) == 1 { - actualAttributes = "attribute" - } - - return fmt.Errorf("expected %d %s for ObjectAttributesExact check, got %d %s", v.num, expectedAttributes, len(otherVal), actualAttributes) - } - - return nil -} - -// String returns the string representation of the value. -func (v objectAttributesExact) String() string { - return strconv.FormatInt(int64(v.num), 10) -} - -// ObjectAttributesExact returns a Check for asserting that -// an object has num attributes. -func ObjectAttributesExact(num int) objectAttributesExact { - return objectAttributesExact{ - num: num, - } -} diff --git a/knownvalue/object_attributes_test.go b/knownvalue/object_attributes_test.go deleted file mode 100644 index 963af7495..000000000 --- a/knownvalue/object_attributes_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue_test - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/hashicorp/terraform-plugin-testing/knownvalue" -) - -func TestObjectAttributes_CheckValue(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - self knownvalue.Check - other any - expectedError error - }{ - "zero-nil": { - self: knownvalue.ObjectAttributesExact(0), - expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: "), - }, - "zero-other": { - self: knownvalue.ObjectAttributesExact(0), - other: map[string]any{}, // checking against the underlying value field zero-value - }, - "nil": { - self: knownvalue.ObjectAttributesExact(3), - expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: "), - }, - "wrong-type": { - self: knownvalue.ObjectAttributesExact(3), - other: 1.234, - expectedError: fmt.Errorf("expected map[string]any value for ObjectAttributesExact check, got: float64"), - }, - "empty": { - self: knownvalue.ObjectAttributesExact(3), - other: map[string]any{}, - expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributesExact check, got 0 attributes"), - }, - "wrong-length": { - self: knownvalue.ObjectAttributesExact(3), - other: map[string]any{ - "one": int64(123), - "two": int64(456), - }, - expectedError: fmt.Errorf("expected 3 attributes for ObjectAttributesExact check, got 2 attributes"), - }, - "equal": { - self: knownvalue.ObjectAttributesExact(3), - other: map[string]any{ - "one": int64(123), - "two": int64(456), - "three": int64(789), - }, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := testCase.self.CheckValue(testCase.other) - - if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} - -func TestObjectAttributes_String(t *testing.T) { - t.Parallel() - - got := knownvalue.ObjectAttributesExact(2).String() - - if diff := cmp.Diff(got, "2"); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } -} diff --git a/knownvalue/set_elements.go b/knownvalue/set_elements.go deleted file mode 100644 index 37d5f38ea..000000000 --- a/knownvalue/set_elements.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue - -import ( - "fmt" - "strconv" -) - -var _ Check = setElementsExact{} - -type setElementsExact struct { - num int -} - -// CheckValue verifies that the passed value is a list, map, object, -// or set, and contains a matching number of elements. -func (v setElementsExact) CheckValue(other any) error { - otherVal, ok := other.([]any) - - if !ok { - return fmt.Errorf("expected []any value for SetElementExact check, got: %T", other) - } - - if len(otherVal) != v.num { - expectedElements := "elements" - actualElements := "elements" - - if v.num == 1 { - expectedElements = "element" - } - - if len(otherVal) == 1 { - actualElements = "element" - } - - return fmt.Errorf("expected %d %s for SetElementExact check, got %d %s", v.num, expectedElements, len(otherVal), actualElements) - } - - return nil -} - -// String returns the string representation of the value. -func (v setElementsExact) String() string { - return strconv.FormatInt(int64(v.num), 10) -} - -// SetElementsExact returns a Check for asserting that -// a set has num elements. -func SetElementsExact(num int) setElementsExact { - return setElementsExact{ - num: num, - } -} diff --git a/knownvalue/set_elements_test.go b/knownvalue/set_elements_test.go deleted file mode 100644 index cd2be6e36..000000000 --- a/knownvalue/set_elements_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package knownvalue_test - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/hashicorp/terraform-plugin-testing/knownvalue" -) - -func TestSetElements_CheckValue(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - self knownvalue.Check - other any - expectedError error - }{ - "zero-nil": { - self: knownvalue.SetElementsExact(0), - expectedError: fmt.Errorf("expected []any value for SetElementExact check, got: "), - }, - "zero-other": { - self: knownvalue.SetElementsExact(0), - other: []any{}, // checking against the underlying value field zero-value - }, - "nil": { - self: knownvalue.SetElementsExact(3), - expectedError: fmt.Errorf("expected []any value for SetElementExact check, got: "), - }, - "wrong-type": { - self: knownvalue.SetElementsExact(3), - other: 1.234, - expectedError: fmt.Errorf("expected []any value for SetElementExact check, got: float64"), - }, - "empty": { - self: knownvalue.SetElementsExact(3), - other: []any{}, - expectedError: fmt.Errorf("expected 3 elements for SetElementExact check, got 0 elements"), - }, - "wrong-length": { - self: knownvalue.SetElementsExact(3), - other: []any{ - int64(123), - int64(456), - }, - expectedError: fmt.Errorf("expected 3 elements for SetElementExact check, got 2 elements"), - }, - "equal": { - self: knownvalue.SetElementsExact(3), - other: []any{ - int64(123), - int64(456), - int64(789), - }, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := testCase.self.CheckValue(testCase.other) - - if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} - -func TestSetElements_String(t *testing.T) { - t.Parallel() - - got := knownvalue.SetElementsExact(2).String() - - if diff := cmp.Diff(got, "2"); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } -} From 66f9b5c2078525c2172f88534d1ca7fd91d2cac2 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 15 Jan 2024 15:24:13 +0000 Subject: [PATCH 45/48] Correcting documentation for revised naming of known value check types (#266) --- website/data/plugin-testing-nav-data.json | 25 ++++++++ .../known-value-checks/bool.mdx | 10 +-- .../known-value-checks/float64.mdx | 10 +-- .../known-value-checks/index.mdx | 8 +-- .../known-value-checks/int64.mdx | 10 +-- .../known-value-checks/list.mdx | 48 +++++++------- .../known-value-checks/map.mdx | 50 +++++++-------- .../known-value-checks/null.mdx | 10 +-- .../known-value-checks/number.mdx | 10 +-- .../known-value-checks/object.mdx | 63 ++++--------------- .../known-value-checks/set.mdx | 48 +++++++------- .../known-value-checks/string.mdx | 10 +-- .../acceptance-tests/plan-checks/output.mdx | 4 +- .../acceptance-tests/plan-checks/resource.mdx | 2 +- .../acceptance-tests/state-checks/custom.mdx | 2 +- .../acceptance-tests/state-checks/output.mdx | 4 +- .../state-checks/resource.mdx | 2 +- 17 files changed, 152 insertions(+), 164 deletions(-) diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index 7e581b6c3..a5a5487dc 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -50,6 +50,27 @@ } ] }, + { + "title": "State Checks", + "routes": [ + { + "title": "Overview", + "path": "acceptance-tests/state-checks" + }, + { + "title": "Resource State Checks", + "path": "acceptance-tests/state-checks/resource" + }, + { + "title": "Output Plan Checks", + "path": "acceptance-tests/state-checks/output" + }, + { + "title": "Custom Plan Checks", + "path": "acceptance-tests/state-checks/custom" + } + ] + }, { "title": "Known Value Checks", "routes": [ @@ -81,6 +102,10 @@ "title": "Map", "path": "acceptance-tests/known-value-checks/map" }, + { + "title": "Null", + "path": "acceptance-tests/known-value-checks/null" + }, { "title": "Number", "path": "acceptance-tests/known-value-checks/number" diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx index 039bc347b..1a5c09a53 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/bool.mdx @@ -8,13 +8,13 @@ description: >- The known value checks that are available for bool values are: -* [BoolValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/bool#boolvalueexact-check) +* [BoolExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/bool#boolexact-check) -## `BoolValueExact` Check +## `BoolExact` Check -The [BoolValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValueExact) check tests that a resource attribute, or output value has an exactly matching bool value. +The [BoolExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolExact) check tests that a resource attribute, or output value has an exactly matching bool value. -Example usage of [BoolValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [BoolExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#BoolExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_Bool(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx index d4bacb127..ebaa17d39 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float64.mdx @@ -8,13 +8,13 @@ description: >- The known value checks that are available for float64 values are: -* [Float64ValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#float64valueexact-check) +* [Float64Exact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#float64exact-check) -## `Float64ValueExact` Check +## `Float64Exact` Check -The [Float64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64ValueExact) check tests that a resource attribute, or output value has an exactly matching float64 value. +The [Float64Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Exact) check tests that a resource attribute, or output value has an exactly matching float64 value. -Example usage of [Float64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64ValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [Float64Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Exact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_Float64(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx index dae04a89d..bc22d96e5 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx @@ -20,15 +20,15 @@ Example uses in the testing module include: The known value check types are implemented within the `terraform-plugin-testing` module in the [`knownvalue` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue). Known value checks are instantiated by calling the relevant constructor function. ```go -knownvalue.BoolValueExact(true) +knownvalue.BoolExact(true) ``` For known value checks that represent collections, or objects, nesting of known value checks can be used to define a "composite" known value check for use in asserting against a resource attribute, or output value that contains other values. ```go -knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), +knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), }) ``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx index 9954cd7ec..214fcef25 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx @@ -8,13 +8,13 @@ description: >- The known value checks that are available for int64 values are: -* [Int64ValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#int64valueexact-check) +* [Int64Exact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#int64exact-check) -## `Int64ValueExact` Check +## `Int64Exact` Check -The [Int64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64ValueExact) check tests that a resource attribute, or output value has an exactly matching int64 value. +The [Int64Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Exact) check tests that a resource attribute, or output value has an exactly matching int64 value. -Example usage of [Int64ValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64ValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [Int64Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Exact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_Int64(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.Int64ValueExact(123), + knownvalue.Int64Exact(123), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx index 774cedc02..e491e58b6 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/list.mdx @@ -8,22 +8,22 @@ description: >- The known value checks that are available for list values are: -* [ListElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listelementsexact-check) -* [ListValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listvalueexact-check) -* [ListValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listvaluepartialmatch-check) +* [ListExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listexact-check) +* [ListPartial](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listpartial-check) +* [ListSizeExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/list#listsizeexact-check) -## `ListElementsExact` Check +## `ListExact` Check -The [ListElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListElementsExact) check tests that a resource attribute, or output value contains the specified number of elements. +The [ListExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListExact) check tests that a resource attribute, or output value has an order-dependent, matching collection of element values. -Example usage of [ListElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [ListExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_List(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ - // Provider definition omitted. + // Provider definition omitted. Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { @@ -38,7 +38,10 @@ func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListElementsExact(2), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), + }), ), }, }, @@ -48,18 +51,18 @@ func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { } ``` -## `ListValueExact` Check +## `ListPartial` Check -The [ListValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValueExact) check tests that a resource attribute, or output value has an order-dependent, matching collection of element values. +The [ListPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListPartial) check tests that a resource attribute, or output value has matching element values for the specified collection indices. -Example usage of [ListValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [ListPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListPartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the first element within the list, the element defined at index `0`, is checked. ```go -func TestExpectKnownValue_CheckPlan_List(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ - // Provider definition omitted. + // Provider definition omitted. Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { @@ -74,9 +77,8 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value1"), }), ), }, @@ -87,14 +89,14 @@ func TestExpectKnownValue_CheckPlan_List(t *testing.T) { } ``` -## `ListValuePartialMatch` Check +## `ListSizeExact` Check -The [ListValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartialMatch) check tests that a resource attribute, or output value has matching element values for the specified collection indices. +The [ListSizeExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListSizeExact) check tests that a resource attribute, or output value contains the specified number of elements. -Example usage of [ListValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the first element within the list, the element defined at index `0`, is checked. +Example usage of [ListSizeExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListSizeExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_ListElements(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -113,9 +115,7 @@ func TestExpectKnownValue_CheckPlan_ListPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartialMatch(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value1"), - }), + knownvalue.ListSizeExact(2), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx index ea1a5c252..fc04c2f80 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/map.mdx @@ -8,18 +8,18 @@ description: >- The known value checks that are available for map values are: -* [MapElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapelementsexact-check) -* [MapValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapvalueexact-check) -* [MapValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapvaluepartialmatch-check) +* [MapExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapexact-check) +* [MapPartial](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mappartial-check) +* [MapSizeExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/map#mapsizeexact-check) -## `MapElementsExact` Check +## `MapExact` Check -The [MapElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapElementsExact) check tests that a resource attribute, or output value contains the specified number of elements. +The [MapExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapExact) check tests that a resource attribute, or output value has a key-specified, matching collection of element values. -Example usage of [MapElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [MapExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -38,7 +38,10 @@ func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapElementsExact(2), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), + "key2": knownvalue.StringExact("value2"), + }), ), }, }, @@ -48,14 +51,16 @@ func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { } ``` -## `MapValueExact` Check +## `MapPartial` Check -The [MapValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValueExact) check tests that a resource attribute, or output value has a key-specified, matching collection of element values. +The [MapPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapPartial) check tests that a resource attribute, or output value has matching element values for the specified keys. -Example usage of [MapValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [MapPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapPartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +In this example, only the element associated with `key1` within the map is checked. ```go -func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -74,9 +79,8 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), - "key2": knownvalue.StringValueExact("value2"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), }), ), }, @@ -87,16 +91,14 @@ func TestExpectKnownValue_CheckPlan_Map(t *testing.T) { } ``` -## `MapValuePartialMatch` Check +## `MapSizeExact` Check -The [MapValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartialMatch) check tests that a resource attribute, or output value has matching element values for the specified keys. +The [MapSizeExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapSizeExact) check tests that a resource attribute, or output value contains the specified number of elements. -Example usage of [MapValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -In this example, only the element associated with `key1` within the map is checked. +Example usage of [MapSizeExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapSizeExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_MapElements(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -115,9 +117,7 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartialMatch(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), - }), + knownvalue.MapSizeExact(2), ), }, }, @@ -125,4 +125,4 @@ func TestExpectKnownValue_CheckPlan_MapPartial(t *testing.T) { }, }) } -``` +``` \ No newline at end of file diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx index 9d50ee65e..58d95ce8d 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/null.mdx @@ -8,13 +8,13 @@ description: >- The known value checks that are available for null values are: -* [NullValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/null#nullvalueexact-check) +* [NullExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/null#nullexact-check) -## `NullValueExact` Check +## `NullExact` Check -The [NullValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NullValueExact) check tests that a resource attribute, or output value has an exactly matching null value. +The [NullExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NullExact) check tests that a resource attribute, or output value has an exactly matching null value. -Example usage of [NullValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NullValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/state-checks/resource) state check. +Example usage of [NullExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NullExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/state-checks/resource) state check. ```go func TestExpectKnownValue_CheckState_AttributeValueNull(t *testing.T) { @@ -29,7 +29,7 @@ func TestExpectKnownValue_CheckState_AttributeValueNull(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.NullValueExact(), + knownvalue.NullExact(), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx index 784146c06..fe5345727 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/number.mdx @@ -8,13 +8,13 @@ description: >- The known value checks that are available for number values are: -* [NumberValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/number#numbervalueexact-check) +* [NumberExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/number#numberexact-check) -## `NumberValueExact` Check +## `NumberExact` Check -The [NumberValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValueExact) check tests that a resource attribute, or output value has an exactly matching number value. +The [NumberExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberExact) check tests that a resource attribute, or output value has an exactly matching number value. -Example usage of [NumberValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [NumberExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#NumberExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go func TestExpectKnownValue_CheckPlan_Number(t *testing.T) { @@ -39,7 +39,7 @@ func TestExpectKnownValue_CheckPlan_Number(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("number_attribute"), - knownvalue.NumberValueExact(num), + knownvalue.NumberExact(num), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx index 55e4b923b..86e62a786 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/object.mdx @@ -8,51 +8,14 @@ description: >- The known value checks that are available for object values are: -* [ObjectElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectelementsexact-check) -* [ObjectValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectvalueexact-check) -* [ObjectValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectvaluepartialmatch-check) +* [ObjectExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectexact-check) +* [ObjectPartial](/terraform/plugin/testing/acceptance-tests/known-value-checks/object#objectpartial-check) -## `ObjectElementsExact` Check +## `ObjectExact` Check -The [ObjectElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectElementsExact) check tests that a resource attribute, or output value contains the specified number of attributes. +The [ObjectExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectExact) check tests that a resource attribute, or output value has a matching collection of attribute name, and attribute values. -Example usage of [ObjectElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. - -```go -func TestExpectKnownValue_CheckPlan_ObjectElements(t *testing.T) { - t.Parallel() - - resource.Test(t, resource.TestCase{ - // Provider definition omitted. - Steps: []resource.TestStep{ - { - Config: `resource "test_resource" "one" { - object_attribute = { - key1 = "value1" - key2 = "value2" - } - } - `, - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue( - "test_resource.one", - tfjsonpath.New("object_attribute"), - knownvalue.ObjectElementsExact(2), - ), - }, - }, - }, - }, - }) -} -``` - -## `ObjectValueExact` Check - -The [ObjectValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValueExact) check tests that a resource attribute, or output value has a matching collection of attribute name, and attribute values. - -Example usage of [ObjectValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [ObjectExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go func TestExpectKnownValue_CheckPlan_Object(t *testing.T) { @@ -74,9 +37,9 @@ func TestExpectKnownValue_CheckPlan_Object(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("object_attribute"), - knownvalue.ObjectValueExact(map[string]knownvalue.Check{ - "attr1": knownvalue.StringValueExact("value1"), - "attr2": knownvalue.StringValueExact("value2"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "attr1": knownvalue.StringExact("value1"), + "attr2": knownvalue.StringExact("value2"), }), ), }, @@ -87,11 +50,11 @@ func TestExpectKnownValue_CheckPlan_Object(t *testing.T) { } ``` -## `ObjectValuePartialMatch` Check +## `ObjectPartial` Check -The [ObjectValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartialMatch) check tests that a resource attribute, or output value has matching attribute values for the specified attribute names. +The [ObjectPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectPartial) check tests that a resource attribute, or output value has matching attribute values for the specified attribute names. -Example usage of [ObjectValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [ObjectPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ObjectPartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the attribute value associated with the attribute name `attr1` within the object is checked. @@ -115,8 +78,8 @@ func TestExpectKnownValue_CheckPlan_ObjectPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("object_attribute"), - knownvalue.ObjectValuePartialMatch(map[string]knownvalue.Check{ - "attr1": knownvalue.StringValueExact("value1"), + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "attr1": knownvalue.StringExact("value1"), }), ), }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx index 64d646a2b..f4bf5730f 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/set.mdx @@ -8,22 +8,22 @@ description: >- The known value checks that are available for set values are: -* [SetElementsExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setelementsexact-check) -* [SetValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setvalueexact-check) -* [SetValuePartialMatch](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setvaluepartialmatch-check) +* [SetExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setexact-check) +* [SetPartial](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setpartial-check) +* [SetSizeExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/set#setsizeexact-check) -## `SetElementsExact` Check +## `SetExact` Check -The [SetElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetElementsExact) check tests that a resource attribute, or output value contains the specified number of elements. +The [SetExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetExact) check tests that a resource attribute, or output value has an order-independent, matching collection of element values. -Example usage of [SetElementsExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetElementsExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [SetExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { +func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ - // Provider definition omitted. + // Provider definition omitted. Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { @@ -38,7 +38,10 @@ func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetElementsExact(2), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value2"), + knownvalue.StringExact("value1"), + }), ), }, }, @@ -48,18 +51,18 @@ func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { } ``` -## `SetValueExact` Check +## `SetPartial` Check -The [SetValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValueExact) check tests that a resource attribute, or output value has an order-independent, matching collection of element values. +The [SetPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetPartial) check tests that a resource attribute, or output value contains matching element values. -Example usage of [SetValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [SetPartial](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetPartial) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the one element within the set is checked. ```go -func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { +func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ - // Provider definition omitted. + // Provider definition omitted. Steps: []resource.TestStep{ { Config: `resource "test_resource" "one" { @@ -74,9 +77,8 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value2"), - knownvalue.StringValueExact("value1"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value2"), }), ), }, @@ -87,14 +89,14 @@ func TestExpectKnownValue_CheckPlan_Set(t *testing.T) { } ``` -## `SetValuePartialMatch` Check +## `SetSizeExact` Check -The [SetValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartialMatch) check tests that a resource attribute, or output value contains matching element values. +The [SetSizeExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetSizeExact) check tests that a resource attribute, or output value contains the specified number of elements. -Example usage of [SetValuePartialMatch](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetValuePartialMatch) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. In this example, only the one element within the set is checked. +Example usage of [SetSizeExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#SetSizeExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go -func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { +func TestExpectKnownValue_CheckPlan_SetElements(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -113,9 +115,7 @@ func TestExpectKnownValue_CheckPlan_SetPartial(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartialMatch([]knownvalue.Check{ - knownvalue.StringValueExact("value2"), - }), + knownvalue.SetSizeExact(2), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx index 2d771964b..f25a66907 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/string.mdx @@ -8,13 +8,13 @@ description: >- The known value checks that are available for string values are: -* [StringValueExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/string#stringvalueexact-check) +* [StringExact](/terraform/plugin/testing/acceptance-tests/known-value-checks/string#stringexact-check) -## `StringValueExact` Check +## `StringExact` Check -The [StringValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValueExact) check tests that a resource attribute, or output value has an exactly matching string value. +The [StringExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringExact) check tests that a resource attribute, or output value has an exactly matching string value. -Example usage of [StringValueExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringValueExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. +Example usage of [StringExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#StringExact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. ```go func TestExpectKnownValue_CheckPlan_String(t *testing.T) { @@ -33,7 +33,7 @@ func TestExpectKnownValue_CheckPlan_String(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.StringValueExact("str")), + knownvalue.StringExact("str")), }, }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx index 146ea2de7..6dd2121cd 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/output.mdx @@ -44,7 +44,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, @@ -80,7 +80,7 @@ func TestExpectKnownOutputValue_CheckPlan_Bool(t *testing.T) { PreApply: []plancheck.PlanCheck{ plancheck.ExpectKnownOutputValue( "bool_output", - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx b/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx index c0f93b6e7..2ef10e073 100644 --- a/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx +++ b/website/docs/plugin/testing/acceptance-tests/plan-checks/resource.mdx @@ -39,7 +39,7 @@ func TestExpectKnownValue_CheckPlan_String(t *testing.T) { plancheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.StringValueExact("str")), + knownvalue.StringExact("str")), }, }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx index f3b3461b0..817be30fb 100644 --- a/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/custom.mdx @@ -109,7 +109,7 @@ func TestExpectKnownValue_CheckState_Bool(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx index 01caccdae..b1e02da1f 100644 --- a/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/output.mdx @@ -39,7 +39,7 @@ func TestExpectKnownOutputValue_CheckState_Bool(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "bool_output", - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, @@ -74,7 +74,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, diff --git a/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx b/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx index 990fd828b..582afbcdf 100644 --- a/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx +++ b/website/docs/plugin/testing/acceptance-tests/state-checks/resource.mdx @@ -36,7 +36,7 @@ func TestExpectKnownValue_CheckState_Bool(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, From 6c773ccd047bda40aab7740ac227c93eccf47539 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 15 Jan 2024 15:35:29 +0000 Subject: [PATCH 46/48] Renaming nul known value check (#266) --- knownvalue/null.go | 18 ++++++++---------- knownvalue/null_test.go | 15 +++++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/knownvalue/null.go b/knownvalue/null.go index 93e773cb0..f10c5a3f5 100644 --- a/knownvalue/null.go +++ b/knownvalue/null.go @@ -7,28 +7,26 @@ import ( "fmt" ) -var _ Check = NullValue{} +var _ Check = nullExact{} -// NullValue is a Check for asserting equality between the value supplied -// to NullValueExact and the value passed to the CheckValue method. -type NullValue struct{} +type nullExact struct{} // CheckValue determines whether the passed value is of nil. -func (v NullValue) CheckValue(other any) error { +func (v nullExact) CheckValue(other any) error { if other != nil { - return fmt.Errorf("expected value nil for NullValue check, got: %T", other) + return fmt.Errorf("expected value nil for NullExact check, got: %T", other) } return nil } // String returns the string representation of nil. -func (v NullValue) String() string { +func (v nullExact) String() string { return "nil" } -// NullValueExact returns a Check for asserting equality nil +// NullExact returns a Check for asserting equality nil // and the value passed to the CheckValue method. -func NullValueExact() NullValue { - return NullValue{} +func NullExact() nullExact { + return nullExact{} } diff --git a/knownvalue/null_test.go b/knownvalue/null_test.go index b185ca220..94682ed7b 100644 --- a/knownvalue/null_test.go +++ b/knownvalue/null_test.go @@ -16,21 +16,24 @@ func TestNullValue_CheckValue(t *testing.T) { t.Parallel() testCases := map[string]struct { - self knownvalue.NullValue + self knownvalue.Check other any expectedError error }{ - "zero-nil": {}, + "zero-nil": { + self: knownvalue.NullExact(), + }, "zero-other": { + self: knownvalue.NullExact(), other: nil, // checking against the underlying value field zero-value }, "not-nil": { - self: knownvalue.NullValueExact(), + self: knownvalue.NullExact(), other: false, - expectedError: fmt.Errorf("expected value nil for NullValue check, got: bool"), + expectedError: fmt.Errorf("expected value nil for NullExact check, got: bool"), }, "equal": { - self: knownvalue.NullValueExact(), + self: knownvalue.NullExact(), other: nil, }, } @@ -53,7 +56,7 @@ func TestNullValue_CheckValue(t *testing.T) { func TestNullValue_String(t *testing.T) { t.Parallel() - got := knownvalue.NullValueExact().String() + got := knownvalue.NullExact().String() if diff := cmp.Diff(got, "nil"); diff != "" { t.Errorf("unexpected difference: %s", diff) From 05d7c914ccb35c9fc8783c09c3947c24293e4cd3 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 15 Jan 2024 15:35:38 +0000 Subject: [PATCH 47/48] Fixing tests (#266) --- .../expect_known_output_value_at_path_test.go | 180 +++++++++--------- statecheck/expect_known_output_value_test.go | 180 +++++++++--------- statecheck/expect_known_value_test.go | 180 +++++++++--------- 3 files changed, 270 insertions(+), 270 deletions(-) diff --git a/statecheck/expect_known_output_value_at_path_test.go b/statecheck/expect_known_output_value_at_path_test.go index 3fcd64637..018deb31b 100644 --- a/statecheck/expect_known_output_value_at_path_test.go +++ b/statecheck/expect_known_output_value_at_path_test.go @@ -43,7 +43,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_ResourceNotFound(t *testing.T) statecheck.ExpectKnownOutputValueAtPath( "test_resource_two_output", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, ExpectError: regexp.MustCompile("test_resource_two_output - Output not found in state"), @@ -73,7 +73,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_AttributeValueNull(t *testing.T statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.NullValueExact(), + knownvalue.NullExact(), ), }, }, @@ -104,7 +104,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, @@ -135,10 +135,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongType(t *tes statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Exact check, got: bool`), }, }, }) @@ -167,10 +167,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Bool_KnownValueWrongValue(t *te statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(false), + knownvalue.BoolExact(false), ), }, - ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolExact check, got: true"), }, }, }) @@ -199,7 +199,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("float_attribute"), - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, }, @@ -231,10 +231,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongType(t * statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("float_attribute"), - knownvalue.StringValueExact("str"), + knownvalue.StringExact("str"), ), }, - ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringExact check, got: json\.Number`), }, }, }) @@ -263,10 +263,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Float64_KnownValueWrongValue(t statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("float_attribute"), - knownvalue.Float64ValueExact(3.21), + knownvalue.Float64Exact(3.21), ), }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Exact check, got: 1.23"), }, }, }) @@ -295,7 +295,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Int64(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.Int64ValueExact(123), + knownvalue.Int64Exact(123), ), }, }, @@ -326,10 +326,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Int64_KnownValueWrongValue(t *t statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.Int64ValueExact(321), + knownvalue.Int64Exact(321), ), }, - ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64Exact check, got: 123"), }, }, }) @@ -361,9 +361,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_List(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), }), ), }, @@ -398,10 +398,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongType(t *tes statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{}), + knownvalue.MapExact(map[string]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapExact check, got: \[\]interface {}`), }, }, }) @@ -433,13 +433,13 @@ func TestExpectKnownOutputValueAtPath_CheckState_List_KnownValueWrongValue(t *te statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value3"), - knownvalue.StringValueExact("value4"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value3"), + knownvalue.StringExact("value4"), }), ), }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringExact check, got: value1`), }, }, }) @@ -471,8 +471,8 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListPartial(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value1"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value1"), }), ), }, @@ -509,12 +509,12 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListPartial_KnownValueWrongValu statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value3"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringExact check, got: value1`), }, }, }) @@ -546,7 +546,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListElements(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListElementsExact(2), + knownvalue.ListSizeExact(2), ), }, }, @@ -580,10 +580,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListElements_WrongNum(t *testin statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_attribute"), - knownvalue.ListElementsExact(3), + knownvalue.ListSizeExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListSizeExact check, got 2 elements"), }, }, }) @@ -617,12 +617,12 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlock(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("str"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -660,9 +660,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockPartial(t *testi statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 1: knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -700,7 +700,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_ListNestedBlockElements(t *test statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("list_nested_block"), - knownvalue.ListElementsExact(2), + knownvalue.ListSizeExact(2), ), }, }, @@ -734,9 +734,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), - "key2": knownvalue.StringValueExact("value2"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), + "key2": knownvalue.StringExact("value2"), }), ), }, @@ -771,10 +771,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongType(t *test statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{}), + knownvalue.ListExact([]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListExact check, got: map\[string\]interface {}`), }, }, }) @@ -806,13 +806,13 @@ func TestExpectKnownOutputValueAtPath_CheckState_Map_KnownValueWrongValue(t *tes statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key3": knownvalue.StringValueExact("value3"), - "key4": knownvalue.StringValueExact("value4"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key3": knownvalue.StringExact("value3"), + "key4": knownvalue.StringExact("value4"), }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapExact check`), }, }, }) @@ -844,8 +844,8 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapPartial(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartial(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), }), ), }, @@ -880,12 +880,12 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapPartial_KnownValueWrongValue statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartial(map[string]knownvalue.Check{ - "key3": knownvalue.StringValueExact("value1"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key3": knownvalue.StringExact("value1"), }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapPartial check`), }, }, }) @@ -917,7 +917,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapElements(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapElementsExact(2), + knownvalue.MapSizeExact(2), ), }, }, @@ -951,10 +951,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_MapElements_WrongNum(t *testing statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("map_attribute"), - knownvalue.MapElementsExact(3), + knownvalue.MapSizeExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapSizeExact check, got 2 elements"), }, }, }) @@ -989,7 +989,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_Number(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.NumberValueExact(f), + knownvalue.NumberExact(f), ), }, }, @@ -1026,10 +1026,10 @@ func TestExpectKnownOutputValueAtPath_CheckState_Number_KnownValueWrongValue(t * statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("int_attribute"), - knownvalue.NumberValueExact(f), + knownvalue.NumberExact(f), ), }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberExact check, got: 123"), }, }, }) @@ -1061,9 +1061,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_Set(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), }), ), }, @@ -1098,13 +1098,13 @@ func TestExpectKnownOutputValueAtPath_CheckState_Set_KnownValueWrongValue(t *tes statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value3"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetExact check`), }, }, }) @@ -1136,8 +1136,8 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetPartial(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.StringValueExact("value2"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value2"), }), ), }, @@ -1172,12 +1172,12 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetPartial_KnownValueWrongValue statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.StringValueExact("value3"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetPartial check`), }, }, }) @@ -1209,7 +1209,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetElements(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_attribute"), - knownvalue.SetElementsExact(2), + knownvalue.SetSizeExact(2), ), }, }, @@ -1245,12 +1245,12 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlock(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("str"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -1288,9 +1288,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockPartial(t *testin statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -1328,7 +1328,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_SetNestedBlockElements(t *testi statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("set_nested_block"), - knownvalue.SetElementsExact(2), + knownvalue.SetSizeExact(2), ), }, }, @@ -1359,7 +1359,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_String(t *testing.T) { statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("string_attribute"), - knownvalue.StringValueExact("str")), + knownvalue.StringExact("str")), }, }, }, @@ -1389,9 +1389,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongType(t *t statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("string_attribute"), - knownvalue.BoolValueExact(true)), + knownvalue.BoolExact(true)), }, - ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolExact check, got: string"), }, }, }) @@ -1420,9 +1420,9 @@ func TestExpectKnownOutputValueAtPath_CheckState_String_KnownValueWrongValue(t * statecheck.ExpectKnownOutputValueAtPath( "test_resource_one_output", tfjsonpath.New("string_attribute"), - knownvalue.StringValueExact("rts")), + knownvalue.StringExact("rts")), }, - ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringExact check, got: str"), }, }, }) @@ -1437,7 +1437,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing expectedErr error }{ "unrecognised-type": { - knownValue: knownvalue.Int64ValueExact(123), + knownValue: knownvalue.Int64Exact(123), req: statecheck.CheckStateRequest{ State: &tfjson.State{ Values: &tfjson.StateValues{ @@ -1449,7 +1449,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: float32"), + expectedErr: fmt.Errorf("expected json.Number value for Int64Exact check, got: float32"), }, } diff --git a/statecheck/expect_known_output_value_test.go b/statecheck/expect_known_output_value_test.go index e4af792d5..612891f74 100644 --- a/statecheck/expect_known_output_value_test.go +++ b/statecheck/expect_known_output_value_test.go @@ -41,7 +41,7 @@ func TestExpectKnownOutputValue_CheckState_OutputNotFound(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "bool_not_found", - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, ExpectError: regexp.MustCompile("bool_not_found - Output not found in state"), @@ -73,7 +73,7 @@ func TestExpectKnownOutputValue_CheckState_AttributeValueNull(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "bool_output", - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, ExpectError: regexp.MustCompile("bool_output - Output not found in state"), @@ -104,7 +104,7 @@ func TestExpectKnownOutputValue_CheckState_Bool(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "bool_output", - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, @@ -134,10 +134,10 @@ func TestExpectKnownOutputValue_CheckState_Bool_KnownValueWrongType(t *testing.T ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "bool_output", - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Exact check, got: bool`), }, }, }) @@ -165,10 +165,10 @@ func TestExpectKnownOutputValue_CheckState_Bool_KnownValueWrongValue(t *testing. ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "bool_output", - knownvalue.BoolValueExact(false), + knownvalue.BoolExact(false), ), }, - ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolExact check, got: true"), }, }, }) @@ -196,7 +196,7 @@ func TestExpectKnownOutputValue_CheckState_Float64(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "float64_output", - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, }, @@ -227,10 +227,10 @@ func TestExpectKnownOutputValue_CheckState_Float64_KnownValueWrongType(t *testin ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "float64_output", - knownvalue.StringValueExact("str"), + knownvalue.StringExact("str"), ), }, - ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringExact check, got: json\.Number`), }, }, }) @@ -258,10 +258,10 @@ func TestExpectKnownOutputValue_CheckState_Float64_KnownValueWrongValue(t *testi ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "float64_output", - knownvalue.Float64ValueExact(3.21), + knownvalue.Float64Exact(3.21), ), }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Exact check, got: 1.23"), }, }, }) @@ -289,7 +289,7 @@ func TestExpectKnownOutputValue_CheckState_Int64(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "int64_output", - knownvalue.Int64ValueExact(123), + knownvalue.Int64Exact(123), ), }, }, @@ -319,10 +319,10 @@ func TestExpectKnownOutputValue_CheckState_Int64_KnownValueWrongValue(t *testing ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "int64_output", - knownvalue.Int64ValueExact(321), + knownvalue.Int64Exact(321), ), }, - ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64Exact check, got: 123"), }, }, }) @@ -353,9 +353,9 @@ func TestExpectKnownOutputValue_CheckState_List(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), }), ), }, @@ -389,10 +389,10 @@ func TestExpectKnownOutputValue_CheckState_List_KnownValueWrongType(t *testing.T ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.MapValueExact(map[string]knownvalue.Check{}), + knownvalue.MapExact(map[string]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapExact check, got: \[\]interface {}`), }, }, }) @@ -423,13 +423,13 @@ func TestExpectKnownOutputValue_CheckState_List_KnownValueWrongValue(t *testing. ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value3"), - knownvalue.StringValueExact("value4"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value3"), + knownvalue.StringExact("value4"), }), ), }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringExact check, got: value1`), }, }, }) @@ -460,8 +460,8 @@ func TestExpectKnownOutputValue_CheckState_ListPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value1"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value1"), }), ), }, @@ -497,12 +497,12 @@ func TestExpectKnownOutputValue_CheckState_ListPartial_KnownValueWrongValue(t *t ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value3"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringExact check, got: value1`), }, }, }) @@ -533,7 +533,7 @@ func TestExpectKnownOutputValue_CheckState_ListElements(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListElementsExact(2), + knownvalue.ListSizeExact(2), ), }, }, @@ -566,10 +566,10 @@ func TestExpectKnownOutputValue_CheckState_ListElements_WrongNum(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_output", - knownvalue.ListElementsExact(3), + knownvalue.ListSizeExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListSizeExact check, got 2 elements"), }, }, }) @@ -602,12 +602,12 @@ func TestExpectKnownOutputValue_CheckState_ListNestedBlock(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("str"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -644,9 +644,9 @@ func TestExpectKnownOutputValue_CheckState_ListNestedBlockPartial(t *testing.T) ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 1: knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -683,7 +683,7 @@ func TestExpectKnownOutputValue_CheckState_ListNestedBlockElements(t *testing.T) ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "list_nested_block_output", - knownvalue.ListElementsExact(2), + knownvalue.ListSizeExact(2), ), }, }, @@ -716,9 +716,9 @@ func TestExpectKnownOutputValue_CheckState_Map(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), - "key2": knownvalue.StringValueExact("value2"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), + "key2": knownvalue.StringExact("value2"), }), ), }, @@ -752,10 +752,10 @@ func TestExpectKnownOutputValue_CheckState_Map_KnownValueWrongType(t *testing.T) ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.ListValueExact([]knownvalue.Check{}), + knownvalue.ListExact([]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListExact check, got: map\[string\]interface {}`), }, }, }) @@ -786,13 +786,13 @@ func TestExpectKnownOutputValue_CheckState_Map_KnownValueWrongValue(t *testing.T ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key3": knownvalue.StringValueExact("value3"), - "key4": knownvalue.StringValueExact("value4"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key3": knownvalue.StringExact("value3"), + "key4": knownvalue.StringExact("value4"), }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapExact check`), }, }, }) @@ -823,8 +823,8 @@ func TestExpectKnownOutputValue_CheckState_MapPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartial(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), }), ), }, @@ -858,12 +858,12 @@ func TestExpectKnownOutputValue_CheckState_MapPartial_KnownValueWrongValue(t *te ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapValuePartial(map[string]knownvalue.Check{ - "key3": knownvalue.StringValueExact("value1"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key3": knownvalue.StringExact("value1"), }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapPartial check`), }, }, }) @@ -894,7 +894,7 @@ func TestExpectKnownOutputValue_CheckState_MapElements(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapElementsExact(2), + knownvalue.MapSizeExact(2), ), }, }, @@ -927,10 +927,10 @@ func TestExpectKnownOutputValue_CheckState_MapElements_WrongNum(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "map_output", - knownvalue.MapElementsExact(3), + knownvalue.MapSizeExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapSizeExact check, got 2 elements"), }, }, }) @@ -964,7 +964,7 @@ func TestExpectKnownOutputValue_CheckState_Number(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "int64_output", - knownvalue.NumberValueExact(f), + knownvalue.NumberExact(f), ), }, }, @@ -1000,10 +1000,10 @@ func TestExpectKnownOutputValue_CheckState_Number_KnownValueWrongValue(t *testin ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "int64_output", - knownvalue.NumberValueExact(f), + knownvalue.NumberExact(f), ), }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberExact check, got: 123"), }, }, }) @@ -1034,9 +1034,9 @@ func TestExpectKnownOutputValue_CheckState_Set(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), }), ), }, @@ -1070,13 +1070,13 @@ func TestExpectKnownOutputValue_CheckState_Set_KnownValueWrongValue(t *testing.T ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value3"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetExact check`), }, }, }) @@ -1107,8 +1107,8 @@ func TestExpectKnownOutputValue_CheckState_SetPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.StringValueExact("value2"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value2"), }), ), }, @@ -1142,12 +1142,12 @@ func TestExpectKnownOutputValue_CheckState_SetPartial_KnownValueWrongValue(t *te ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.StringValueExact("value3"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetPartial check`), }, }, }) @@ -1178,7 +1178,7 @@ func TestExpectKnownOutputValue_CheckState_SetElements(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_output", - knownvalue.SetElementsExact(2), + knownvalue.SetSizeExact(2), ), }, }, @@ -1213,12 +1213,12 @@ func TestExpectKnownOutputValue_CheckState_SetNestedBlock(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("str"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -1255,9 +1255,9 @@ func TestExpectKnownOutputValue_CheckState_SetNestedBlockPartial(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -1294,7 +1294,7 @@ func TestExpectKnownOutputValue_CheckState_SetNestedBlockElements(t *testing.T) ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "set_nested_block_output", - knownvalue.SetElementsExact(2), + knownvalue.SetSizeExact(2), ), }, }, @@ -1324,7 +1324,7 @@ func TestExpectKnownOutputValue_CheckState_String(t *testing.T) { ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "string_output", - knownvalue.StringValueExact("str")), + knownvalue.StringExact("str")), }, }, }, @@ -1353,9 +1353,9 @@ func TestExpectKnownOutputValue_CheckState_String_KnownValueWrongType(t *testing ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "string_output", - knownvalue.BoolValueExact(true)), + knownvalue.BoolExact(true)), }, - ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolExact check, got: string"), }, }, }) @@ -1383,9 +1383,9 @@ func TestExpectKnownOutputValue_CheckState_String_KnownValueWrongValue(t *testin ConfigStateChecks: r.ConfigStateChecks{ statecheck.ExpectKnownOutputValue( "string_output", - knownvalue.StringValueExact("rts")), + knownvalue.StringExact("rts")), }, - ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringExact check, got: str"), }, }, }) @@ -1400,7 +1400,7 @@ func TestExpectKnownOutputValue_CheckState_UnknownAttributeType(t *testing.T) { expectedErr error }{ "unrecognised-type": { - knownValue: knownvalue.Int64ValueExact(123), + knownValue: knownvalue.Int64Exact(123), req: statecheck.CheckStateRequest{ State: &tfjson.State{ Values: &tfjson.StateValues{ @@ -1412,7 +1412,7 @@ func TestExpectKnownOutputValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: float32"), + expectedErr: fmt.Errorf("expected json.Number value for Int64Exact check, got: float32"), }, } diff --git a/statecheck/expect_known_value_test.go b/statecheck/expect_known_value_test.go index c95086d4b..e275212de 100644 --- a/statecheck/expect_known_value_test.go +++ b/statecheck/expect_known_value_test.go @@ -40,7 +40,7 @@ func TestExpectKnownValue_CheckState_ResourceNotFound(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.two", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, ExpectError: regexp.MustCompile("test_resource.two - Resource not found in state"), @@ -65,7 +65,7 @@ func TestExpectKnownValue_CheckState_AttributeValueNull(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.NullValueExact(), + knownvalue.NullExact(), ), }, }, @@ -92,7 +92,7 @@ func TestExpectKnownValue_CheckState_Bool(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(true), + knownvalue.BoolExact(true), ), }, }, @@ -119,10 +119,10 @@ func TestExpectKnownValue_CheckState_Bool_KnownValueWrongType(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, - ExpectError: regexp.MustCompile(`expected json\.Number value for Float64ValueExact check, got: bool`), + ExpectError: regexp.MustCompile(`expected json\.Number value for Float64Exact check, got: bool`), }, }, }) @@ -147,10 +147,10 @@ func TestExpectKnownValue_CheckState_Bool_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("bool_attribute"), - knownvalue.BoolValueExact(false), + knownvalue.BoolExact(false), ), }, - ExpectError: regexp.MustCompile("expected value false for BoolValueExact check, got: true"), + ExpectError: regexp.MustCompile("expected value false for BoolExact check, got: true"), }, }, }) @@ -175,7 +175,7 @@ func TestExpectKnownValue_CheckState_Float64(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.Float64ValueExact(1.23), + knownvalue.Float64Exact(1.23), ), }, }, @@ -203,10 +203,10 @@ func TestExpectKnownValue_CheckState_Float64_KnownValueWrongType(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.StringValueExact("str"), + knownvalue.StringExact("str"), ), }, - ExpectError: regexp.MustCompile(`expected string value for StringValueExact check, got: json\.Number`), + ExpectError: regexp.MustCompile(`expected string value for StringExact check, got: json\.Number`), }, }, }) @@ -231,10 +231,10 @@ func TestExpectKnownValue_CheckState_Float64_KnownValueWrongValue(t *testing.T) statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("float_attribute"), - knownvalue.Float64ValueExact(3.21), + knownvalue.Float64Exact(3.21), ), }, - ExpectError: regexp.MustCompile("expected value 3.21 for Float64ValueExact check, got: 1.23"), + ExpectError: regexp.MustCompile("expected value 3.21 for Float64Exact check, got: 1.23"), }, }, }) @@ -259,7 +259,7 @@ func TestExpectKnownValue_CheckState_Int64(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.Int64ValueExact(123), + knownvalue.Int64Exact(123), ), }, }, @@ -286,10 +286,10 @@ func TestExpectKnownValue_CheckState_Int64_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.Int64ValueExact(321), + knownvalue.Int64Exact(321), ), }, - ExpectError: regexp.MustCompile("expected value 321 for Int64ValueExact check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for Int64Exact check, got: 123"), }, }, }) @@ -317,9 +317,9 @@ func TestExpectKnownValue_CheckState_List(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value2"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value2"), }), ), }, @@ -350,10 +350,10 @@ func TestExpectKnownValue_CheckState_List_KnownValueWrongType(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{}), + knownvalue.MapExact(map[string]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapValueExact check, got: \[\]interface {}`), + ExpectError: regexp.MustCompile(`expected map\[string\]any value for MapExact check, got: \[\]interface {}`), }, }, }) @@ -381,13 +381,13 @@ func TestExpectKnownValue_CheckState_List_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value3"), - knownvalue.StringValueExact("value4"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("value3"), + knownvalue.StringExact("value4"), }), ), }, - ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`list element index 0: expected value value3 for StringExact check, got: value1`), }, }, }) @@ -415,8 +415,8 @@ func TestExpectKnownValue_CheckState_ListPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value1"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value1"), }), ), }, @@ -449,12 +449,12 @@ func TestExpectKnownValue_CheckState_ListPartial_KnownValueWrongValue(t *testing statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 0: knownvalue.StringValueExact("value3"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 0: knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringValueExact check, got: value1`), + ExpectError: regexp.MustCompile(`list element 0: expected value value3 for StringExact check, got: value1`), }, }, }) @@ -482,7 +482,7 @@ func TestExpectKnownValue_CheckState_ListElements(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListElementsExact(2), + knownvalue.ListSizeExact(2), ), }, }, @@ -512,10 +512,10 @@ func TestExpectKnownValue_CheckState_ListElements_WrongNum(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_attribute"), - knownvalue.ListElementsExact(3), + knownvalue.ListSizeExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for ListElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for ListSizeExact check, got 2 elements"), }, }, }) @@ -545,12 +545,12 @@ func TestExpectKnownValue_CheckState_ListNestedBlock(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.ListValueExact([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("str"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -584,9 +584,9 @@ func TestExpectKnownValue_CheckState_ListNestedBlockPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.ListValuePartial(map[int]knownvalue.Check{ - 1: knownvalue.MapValueExact(map[string]knownvalue.Check{ - "list_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.ListPartial(map[int]knownvalue.Check{ + 1: knownvalue.MapExact(map[string]knownvalue.Check{ + "list_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -620,7 +620,7 @@ func TestExpectKnownValue_CheckState_ListNestedBlockElements(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("list_nested_block"), - knownvalue.ListElementsExact(2), + knownvalue.ListSizeExact(2), ), }, }, @@ -650,9 +650,9 @@ func TestExpectKnownValue_CheckState_Map(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), - "key2": knownvalue.StringValueExact("value2"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), + "key2": knownvalue.StringExact("value2"), }), ), }, @@ -683,10 +683,10 @@ func TestExpectKnownValue_CheckState_Map_KnownValueWrongType(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.ListValueExact([]knownvalue.Check{}), + knownvalue.ListExact([]knownvalue.Check{}), ), }, - ExpectError: regexp.MustCompile(`expected \[\]any value for ListValueExact check, got: map\[string\]interface {}`), + ExpectError: regexp.MustCompile(`expected \[\]any value for ListExact check, got: map\[string\]interface {}`), }, }, }) @@ -714,13 +714,13 @@ func TestExpectKnownValue_CheckState_Map_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "key3": knownvalue.StringValueExact("value3"), - "key4": knownvalue.StringValueExact("value4"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "key3": knownvalue.StringExact("value3"), + "key4": knownvalue.StringExact("value4"), }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValueExact check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapExact check`), }, }, }) @@ -748,8 +748,8 @@ func TestExpectKnownValue_CheckState_MapPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartial(map[string]knownvalue.Check{ - "key1": knownvalue.StringValueExact("value1"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key1": knownvalue.StringExact("value1"), }), ), }, @@ -780,12 +780,12 @@ func TestExpectKnownValue_CheckState_MapPartial_KnownValueWrongValue(t *testing. statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapValuePartial(map[string]knownvalue.Check{ - "key3": knownvalue.StringValueExact("value1"), + knownvalue.MapPartial(map[string]knownvalue.Check{ + "key3": knownvalue.StringExact("value1"), }), ), }, - ExpectError: regexp.MustCompile(`missing element key3 for MapValuePartial check`), + ExpectError: regexp.MustCompile(`missing element key3 for MapPartial check`), }, }, }) @@ -813,7 +813,7 @@ func TestExpectKnownValue_CheckState_MapElements(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapElementsExact(2), + knownvalue.MapSizeExact(2), ), }, }, @@ -843,10 +843,10 @@ func TestExpectKnownValue_CheckState_MapElements_WrongNum(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("map_attribute"), - knownvalue.MapElementsExact(3), + knownvalue.MapSizeExact(3), ), }, - ExpectError: regexp.MustCompile("expected 3 elements for MapElementsExact check, got 2 elements"), + ExpectError: regexp.MustCompile("expected 3 elements for MapSizeExact check, got 2 elements"), }, }, }) @@ -877,7 +877,7 @@ func TestExpectKnownValue_CheckState_Number(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.NumberValueExact(f), + knownvalue.NumberExact(f), ), }, }, @@ -910,10 +910,10 @@ func TestExpectKnownValue_CheckState_Number_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("int_attribute"), - knownvalue.NumberValueExact(f), + knownvalue.NumberExact(f), ), }, - ExpectError: regexp.MustCompile("expected value 321 for NumberValueExact check, got: 123"), + ExpectError: regexp.MustCompile("expected value 321 for NumberExact check, got: 123"), }, }, }) @@ -941,9 +941,9 @@ func TestExpectKnownValue_CheckState_Set(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value2"), - knownvalue.StringValueExact("value1"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value2"), + knownvalue.StringExact("value1"), }), ), }, @@ -974,13 +974,13 @@ func TestExpectKnownValue_CheckState_Set_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.StringValueExact("value1"), - knownvalue.StringValueExact("value3"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("value1"), + knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValueExact check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetExact check`), }, }, }) @@ -1008,8 +1008,8 @@ func TestExpectKnownValue_CheckState_SetPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.StringValueExact("value2"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value2"), }), ), }, @@ -1040,12 +1040,12 @@ func TestExpectKnownValue_CheckState_SetPartial_KnownValueWrongValue(t *testing. statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.StringValueExact("value3"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.StringExact("value3"), }), ), }, - ExpectError: regexp.MustCompile(`missing value value3 for SetValuePartial check`), + ExpectError: regexp.MustCompile(`missing value value3 for SetPartial check`), }, }, }) @@ -1073,7 +1073,7 @@ func TestExpectKnownValue_CheckState_SetElements(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_attribute"), - knownvalue.SetElementsExact(2), + knownvalue.SetSizeExact(2), ), }, }, @@ -1105,12 +1105,12 @@ func TestExpectKnownValue_CheckState_SetNestedBlock(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetValueExact([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("str"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("str"), }), - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -1144,9 +1144,9 @@ func TestExpectKnownValue_CheckState_SetNestedBlockPartial(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetValuePartial([]knownvalue.Check{ - knownvalue.MapValueExact(map[string]knownvalue.Check{ - "set_nested_block_attribute": knownvalue.StringValueExact("rts"), + knownvalue.SetPartial([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "set_nested_block_attribute": knownvalue.StringExact("rts"), }), }), ), @@ -1180,7 +1180,7 @@ func TestExpectKnownValue_CheckState_SetNestedBlockElements(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("set_nested_block"), - knownvalue.SetElementsExact(2), + knownvalue.SetSizeExact(2), ), }, }, @@ -1207,7 +1207,7 @@ func TestExpectKnownValue_CheckState_String(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.StringValueExact("str")), + knownvalue.StringExact("str")), }, }, }, @@ -1233,9 +1233,9 @@ func TestExpectKnownValue_CheckState_String_KnownValueWrongType(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.BoolValueExact(true)), + knownvalue.BoolExact(true)), }, - ExpectError: regexp.MustCompile("expected bool value for BoolValueExact check, got: string"), + ExpectError: regexp.MustCompile("expected bool value for BoolExact check, got: string"), }, }, }) @@ -1260,9 +1260,9 @@ func TestExpectKnownValue_CheckState_String_KnownValueWrongValue(t *testing.T) { statecheck.ExpectKnownValue( "test_resource.one", tfjsonpath.New("string_attribute"), - knownvalue.StringValueExact("rts")), + knownvalue.StringExact("rts")), }, - ExpectError: regexp.MustCompile("expected value rts for StringValueExact check, got: str"), + ExpectError: regexp.MustCompile("expected value rts for StringExact check, got: str"), }, }, }) @@ -1277,7 +1277,7 @@ func TestExpectKnownValue_CheckState_UnknownAttributeType(t *testing.T) { expectedErr error }{ "unrecognised-type": { - knownValue: knownvalue.Int64ValueExact(123), + knownValue: knownvalue.Int64Exact(123), req: statecheck.CheckStateRequest{ State: &tfjson.State{ Values: &tfjson.StateValues{ @@ -1294,7 +1294,7 @@ func TestExpectKnownValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64ValueExact check, got: float32"), + expectedErr: fmt.Errorf("expected json.Number value for Int64Exact check, got: float32"), }, } From 8b158ae45d503ed9acf627bd25bdf064587c5766 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 15 Jan 2024 16:33:28 +0000 Subject: [PATCH 48/48] Adding address and path to state check errors (#266) --- statecheck/expect_known_output_value.go | 2 +- statecheck/expect_known_output_value_at_path.go | 2 +- statecheck/expect_known_output_value_at_path_test.go | 10 ++++++---- statecheck/expect_known_output_value_test.go | 2 +- statecheck/expect_known_value.go | 2 +- statecheck/expect_known_value_test.go | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/statecheck/expect_known_output_value.go b/statecheck/expect_known_output_value.go index 1cf6b69e8..64c47f819 100644 --- a/statecheck/expect_known_output_value.go +++ b/statecheck/expect_known_output_value.go @@ -56,7 +56,7 @@ func (e expectKnownOutputValue) CheckState(ctx context.Context, req CheckStateRe } if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err + resp.Error = fmt.Errorf("error checking value for output at path: %s, err: %s", e.outputAddress, err) return } diff --git a/statecheck/expect_known_output_value_at_path.go b/statecheck/expect_known_output_value_at_path.go index 7ff704b06..9fb8cc4f1 100644 --- a/statecheck/expect_known_output_value_at_path.go +++ b/statecheck/expect_known_output_value_at_path.go @@ -57,7 +57,7 @@ func (e expectKnownOutputValueAtPath) CheckState(ctx context.Context, req CheckS } if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err + resp.Error = fmt.Errorf("error checking value for output at path: %s.%s, err: %s", e.outputAddress, e.outputPath.String(), err) return } diff --git a/statecheck/expect_known_output_value_at_path_test.go b/statecheck/expect_known_output_value_at_path_test.go index 018deb31b..078daee04 100644 --- a/statecheck/expect_known_output_value_at_path_test.go +++ b/statecheck/expect_known_output_value_at_path_test.go @@ -1442,14 +1442,16 @@ func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing State: &tfjson.State{ Values: &tfjson.StateValues{ Outputs: map[string]*tfjson.StateOutput{ - "float32_output": { - Value: float32(123), + "obj": { + Value: map[string]any{ + "float32_output": float32(123), + }, }, }, }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64Exact check, got: float32"), + expectedErr: fmt.Errorf("error checking value for output at path: obj.float32_output, err: expected json.Number value for Int64Exact check, got: float32"), }, } @@ -1459,7 +1461,7 @@ func TestExpectKnownOutputValueAtPath_CheckState_UnknownAttributeType(t *testing t.Run(name, func(t *testing.T) { t.Parallel() - e := statecheck.ExpectKnownOutputValueAtPath("float32_output", tfjsonpath.Path{}, testCase.knownValue) + e := statecheck.ExpectKnownOutputValueAtPath("obj", tfjsonpath.New("float32_output"), testCase.knownValue) resp := statecheck.CheckStateResponse{} diff --git a/statecheck/expect_known_output_value_test.go b/statecheck/expect_known_output_value_test.go index 612891f74..b3f5e2ccf 100644 --- a/statecheck/expect_known_output_value_test.go +++ b/statecheck/expect_known_output_value_test.go @@ -1412,7 +1412,7 @@ func TestExpectKnownOutputValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64Exact check, got: float32"), + expectedErr: fmt.Errorf("error checking value for output at path: float32_output, err: expected json.Number value for Int64Exact check, got: float32"), }, } diff --git a/statecheck/expect_known_value.go b/statecheck/expect_known_value.go index 096699cba..96662c32a 100644 --- a/statecheck/expect_known_value.go +++ b/statecheck/expect_known_value.go @@ -61,7 +61,7 @@ func (e expectKnownValue) CheckState(ctx context.Context, req CheckStateRequest, } if err := e.knownValue.CheckValue(result); err != nil { - resp.Error = err + resp.Error = fmt.Errorf("error checking value for attribute at path: %s.%s, err: %s", e.resourceAddress, e.attributePath.String(), err) } } diff --git a/statecheck/expect_known_value_test.go b/statecheck/expect_known_value_test.go index e275212de..9625ec089 100644 --- a/statecheck/expect_known_value_test.go +++ b/statecheck/expect_known_value_test.go @@ -1294,7 +1294,7 @@ func TestExpectKnownValue_CheckState_UnknownAttributeType(t *testing.T) { }, }, }, - expectedErr: fmt.Errorf("expected json.Number value for Int64Exact check, got: float32"), + expectedErr: fmt.Errorf("error checking value for attribute at path: example_resource.test.attribute, err: expected json.Number value for Int64Exact check, got: float32"), }, }