mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
My original intention was just to reduce our number of dependencies by standardizing on a single comparison library, but in the process of doing so I found various examples of the kinds of problems that caused this codebase to begin adopting go-cmp instead of go-test/deep in the first place, which make it easy to accidentally write a false-positive test that doesn't actually check what the author thinks is being checked: - deep.Equal silently ignores unexported fields, so comparing two values that differ only in data in unexported fields succeeds even when it ought not to. TestContext2Apply_multiVarComprehensive in package tofu was an excellent example of this problem: it had various test assertions that were actually checking absolutely nothing, despite appearing to compare pairs of cty.Value. - deep.Equal also silently ignores anything below a certain level of nesting, and so comparison of deep data structures can appear to succeed even though they don't actually match. There were a few examples where that problem had already been found and fixed by temporarily overriding the package deep global settings, but with go-cmp the default behavior already visits everything, or panics if it cannot. This does mean that in a few cases this needed some more elaborate options to cmp.Diff to align with the previous behavior, which is a little annoying but overall I think better to be explicit about what each test is relying on. Perhaps we can rework these tests to need fewer unusual cmp options in future, but for this commit I want to keep focused on the smallest possible changes to remove our dependency on github.com/go-test/deep . Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
137 lines
3.1 KiB
Go
137 lines
3.1 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package addrs
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
)
|
|
|
|
func TestAbsOutputValueInstanceEqual_true(t *testing.T) {
|
|
foo, diags := ParseModuleInstanceStr("module.foo")
|
|
if len(diags) > 0 {
|
|
t.Fatalf("unexpected diags: %s", diags.Err())
|
|
}
|
|
foobar, diags := ParseModuleInstanceStr("module.foo[1].module.bar")
|
|
if len(diags) > 0 {
|
|
t.Fatalf("unexpected diags: %s", diags.Err())
|
|
}
|
|
|
|
ovs := []AbsOutputValue{
|
|
foo.OutputValue("a"),
|
|
foobar.OutputValue("b"),
|
|
}
|
|
for _, r := range ovs {
|
|
t.Run(r.String(), func(t *testing.T) {
|
|
if !r.Equal(r) {
|
|
t.Fatalf("expected %#v to be equal to itself", r)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAbsOutputValueInstanceEqual_false(t *testing.T) {
|
|
foo, diags := ParseModuleInstanceStr("module.foo")
|
|
if len(diags) > 0 {
|
|
t.Fatalf("unexpected diags: %s", diags.Err())
|
|
}
|
|
foobar, diags := ParseModuleInstanceStr("module.foo[1].module.bar")
|
|
if len(diags) > 0 {
|
|
t.Fatalf("unexpected diags: %s", diags.Err())
|
|
}
|
|
|
|
testCases := []struct {
|
|
left AbsOutputValue
|
|
right AbsOutputValue
|
|
}{
|
|
{
|
|
foo.OutputValue("a"),
|
|
foo.OutputValue("b"),
|
|
},
|
|
{
|
|
foo.OutputValue("a"),
|
|
foobar.OutputValue("a"),
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
|
|
if tc.left.Equal(tc.right) {
|
|
t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
|
|
}
|
|
|
|
if tc.right.Equal(tc.left) {
|
|
t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseAbsOutputValueStr(t *testing.T) {
|
|
tests := map[string]struct {
|
|
want AbsOutputValue
|
|
wantErr string
|
|
}{
|
|
"module.foo": {
|
|
wantErr: "An output name is required",
|
|
},
|
|
"module.foo.output": {
|
|
wantErr: "An output name is required",
|
|
},
|
|
"module.foo.boop.beep": {
|
|
wantErr: "Output address must start with \"output.\"",
|
|
},
|
|
"module.foo.output[0]": {
|
|
wantErr: "An output name is required",
|
|
},
|
|
"output": {
|
|
wantErr: "An output name is required",
|
|
},
|
|
"output[0]": {
|
|
wantErr: "An output name is required",
|
|
},
|
|
"output.boop": {
|
|
want: AbsOutputValue{
|
|
Module: RootModuleInstance,
|
|
OutputValue: OutputValue{
|
|
Name: "boop",
|
|
},
|
|
},
|
|
},
|
|
"module.foo.output.beep": {
|
|
want: AbsOutputValue{
|
|
Module: mustParseModuleInstanceStr("module.foo"),
|
|
OutputValue: OutputValue{
|
|
Name: "beep",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for input, tc := range tests {
|
|
t.Run(input, func(t *testing.T) {
|
|
got, diags := ParseAbsOutputValueStr(input)
|
|
if diff := cmp.Diff(tc.want, got, CmpOptionsForTesting); diff != "" {
|
|
t.Error("wrong result:\n" + diff)
|
|
}
|
|
if len(diags) > 0 {
|
|
gotErr := diags.Err().Error()
|
|
if tc.wantErr == "" {
|
|
t.Errorf("got error, expected success: %s", gotErr)
|
|
} else if !strings.Contains(gotErr, tc.wantErr) {
|
|
t.Errorf("unexpected error\n got: %s\nwant: %s", gotErr, tc.wantErr)
|
|
}
|
|
} else {
|
|
if tc.wantErr != "" {
|
|
t.Errorf("got success, expected error: %s", tc.wantErr)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|