diff --git a/internal/putil/putil.go b/internal/putil/putil.go index f88f446..1d8a3f9 100644 --- a/internal/putil/putil.go +++ b/internal/putil/putil.go @@ -15,7 +15,10 @@ // Package putil contains utility functions for working with [resource.PropertyValue]s. package putil -import "github.com/pulumi/pulumi/sdk/v3/go/common/resource" +import ( + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" + "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" +) // IsComputed checks if v is some form of a computed/unknown value. func IsComputed(v resource.PropertyValue) bool { @@ -106,6 +109,8 @@ func MakeKnown(v resource.PropertyValue) resource.PropertyValue { // 2. It doesn't panic when computed values are present. func DeepEquals(a, b resource.PropertyValue) bool { a, b = foldOutputValue(a), foldOutputValue(b) + contract.Assertf(!a.IsSecret() && !b.IsSecret(), "Secrets should be Outputs at this point") + contract.Assertf(!a.IsComputed() && !b.IsComputed(), "Computed should be Outputs at this point") switch { case a.IsOutput() && b.IsOutput(): a, b := a.OutputValue(), b.OutputValue() diff --git a/internal/putil/putil_test.go b/internal/putil/putil_test.go new file mode 100644 index 0000000..d38874e --- /dev/null +++ b/internal/putil/putil_test.go @@ -0,0 +1,103 @@ +// Copyright 2024, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package putil_test + +import ( + "testing" + + "github.com/pulumi/pulumi-go-provider/internal/putil" + rresource "github.com/pulumi/pulumi-go-provider/internal/rapid/resource" + r "github.com/pulumi/pulumi/sdk/v3/go/common/resource" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource/urn" + "github.com/stretchr/testify/assert" + "pgregory.net/rapid" +) + +func TestRapidDeepEqual(t *testing.T) { + t.Parallel() + + t.Run("reflexivity", rapid.MakeCheck(func(t *rapid.T) { //nolint:paralleltest + value := rresource.PropertyValue(5).Draw(t, "value") + assert.True(t, putil.DeepEquals(value, value)) + })) + + // Check that "distinct" values never equal themselves. + t.Run("distinct-values", rapid.MakeCheck(func(t *rapid.T) { //nolint:paralleltest + // keyFn is how [rapid] determines that values are distinct. + // + // We do this by calling [fmt.Stringer.String] on the normalized form of v. + keyFn := func(v r.PropertyValue) string { return normalize(v).String() } + values := rapid.SliceOfNDistinct( + rresource.PropertyValue(5), 2, 2, keyFn, + ).Draw(t, "distinct") + assert.False(t, putil.DeepEquals(values[0], values[1])) + })) + + t.Run("nested-outputs", func(t *testing.T) { + t.Parallel() + + v1 := r.NewProperty(r.Output{ + Element: r.NewProperty(r.Output{ + Element: r.PropertyValue{V: interface{}(nil)}, + Known: false, + Secret: false, + Dependencies: []urn.URN{ + "", + "&\n[?", "\x7f=&\u202c\x7fᾩ:AȺ~", + "!aAὂ̥\ue007~a\x01?۵%", + "*\"\u2005\ue005-a=\v\u2008䍨~ᶞ٣_", + }, + }), + Known: true, + Secret: true, + Dependencies: []urn.URN{ + "", + "A#@\u008b%\x00$\u202e\U000e006a|ᛮ<:ፘ.᭴ो〦\U000fd7da!𞥋\v%\x7fڌ֝[A{ॊⅣ\nA1|_\u3000%a", + "%", + }, + }) + v2 := r.NewProperty(r.Output{ + Element: r.PropertyValue{V: interface{}(nil)}, + Known: false, + Secret: true, + Dependencies: []urn.URN{ + "", + "̿A#꙲ .\u2029\u1680~;,*\ue000֍\ue001º`a貦", + "_¦?!", + "\u2007�", + ";\U000e003e\r𞥋\\𞓶\x02٦Lj$=1𝛜ᾫ?", + "{Aັ\\Dž", + "̆aLjⅺ*~", + }, + }) + + assert.True(t, putil.DeepEquals(v1, v2)) + }) + + t.Run("folding-secret-computed", func(t *testing.T) { + t.Parallel() + + assert.True(t, putil.DeepEquals( + r.MakeComputed(r.MakeSecret(r.NewStringProperty("hi"))), + r.MakeSecret(r.MakeComputed(r.NewStringProperty("hi"))))) + assert.False(t, putil.DeepEquals( + r.MakeSecret(r.NewStringProperty("hi")), + r.MakeComputed(r.NewStringProperty("hi")))) + }) +} + +func normalize(p r.PropertyValue) r.PropertyValue { + return r.ToResourcePropertyValue(r.FromResourcePropertyValue(p)) +} diff --git a/putil/putil_test.go b/putil/putil_test.go deleted file mode 100644 index c13eae0..0000000 --- a/putil/putil_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2024, Pulumi Corporation. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package putil_test - -import ( - "testing" - - "github.com/pulumi/pulumi-go-provider/internal/putil" - rresource "github.com/pulumi/pulumi-go-provider/internal/rapid/resource" - r "github.com/pulumi/pulumi/sdk/v3/go/common/resource" - "github.com/stretchr/testify/assert" - "pgregory.net/rapid" -) - -func TestRapidDeepEqual(t *testing.T) { - t.Parallel() - // Check that a value always equals itself - rapid.Check(t, func(t *rapid.T) { - value := rresource.PropertyValue(5).Draw(t, "value") - - assert.True(t, putil.DeepEquals(value, value)) - }) - - // Check that "distinct" values never equal themselves. - rapid.Check(t, func(t *rapid.T) { - values := rapid.SliceOfNDistinct(rresource.PropertyValue(5), 2, 2, - func(v r.PropertyValue) string { - return v.String() - }).Draw(t, "distinct") - assert.False(t, putil.DeepEquals(values[0], values[1])) - }) - - t.Run("folding", func(t *testing.T) { - assert.True(t, putil.DeepEquals( - r.MakeComputed(r.MakeSecret(r.NewStringProperty("hi"))), - r.MakeSecret(r.MakeComputed(r.NewStringProperty("hi"))))) - assert.False(t, putil.DeepEquals( - r.MakeSecret(r.NewStringProperty("hi")), - r.MakeComputed(r.NewStringProperty("hi")))) - }) -}