github.com/opentofu/opentofu@v1.7.1/internal/plans/objchange/lcs_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package objchange
     7  
     8  import (
     9  	"fmt"
    10  	"testing"
    11  
    12  	"github.com/opentofu/opentofu/internal/lang/marks"
    13  	"github.com/zclconf/go-cty/cty"
    14  )
    15  
    16  func TestLongestCommonSubsequence(t *testing.T) {
    17  	tests := []struct {
    18  		xs   []cty.Value
    19  		ys   []cty.Value
    20  		want []cty.Value
    21  	}{
    22  		{
    23  			[]cty.Value{},
    24  			[]cty.Value{},
    25  			[]cty.Value{},
    26  		},
    27  		{
    28  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    29  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    30  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    31  		},
    32  		{
    33  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    34  			[]cty.Value{cty.NumberIntVal(3), cty.NumberIntVal(4)},
    35  			[]cty.Value{},
    36  		},
    37  		{
    38  			[]cty.Value{cty.NumberIntVal(2)},
    39  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    40  			[]cty.Value{cty.NumberIntVal(2)},
    41  		},
    42  		{
    43  			[]cty.Value{cty.NumberIntVal(1)},
    44  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    45  			[]cty.Value{cty.NumberIntVal(1)},
    46  		},
    47  		{
    48  			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(1)},
    49  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
    50  			[]cty.Value{cty.NumberIntVal(1)}, // arbitrarily selected 1; 2 would also be valid
    51  		},
    52  		{
    53  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(4)},
    54  			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4), cty.NumberIntVal(5)},
    55  			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4)},
    56  		},
    57  		{
    58  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(4)},
    59  			[]cty.Value{cty.NumberIntVal(4), cty.NumberIntVal(2), cty.NumberIntVal(5)},
    60  			[]cty.Value{cty.NumberIntVal(4)}, // 2 would also be valid
    61  		},
    62  		{
    63  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(5)},
    64  			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4), cty.NumberIntVal(5)},
    65  			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(5)},
    66  		},
    67  
    68  		// unknowns never compare as equal
    69  		{
    70  			[]cty.Value{cty.NumberIntVal(1), cty.UnknownVal(cty.Number), cty.NumberIntVal(3)},
    71  			[]cty.Value{cty.NumberIntVal(1), cty.UnknownVal(cty.Number), cty.NumberIntVal(3)},
    72  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(3)},
    73  		},
    74  		{
    75  			[]cty.Value{cty.UnknownVal(cty.Number)},
    76  			[]cty.Value{cty.UnknownVal(cty.Number)},
    77  			[]cty.Value{},
    78  		},
    79  
    80  		// marked values
    81  		{
    82  			[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo"), cty.NumberIntVal(3)},
    83  			[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo")},
    84  			[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo")},
    85  		},
    86  		{
    87  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2).Mark("foo"), cty.NumberIntVal(3)},
    88  			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(3)},
    89  			[]cty.Value{cty.NumberIntVal(3)},
    90  		},
    91  		{
    92  			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2).Mark("foo")},
    93  			[]cty.Value{cty.NumberIntVal(2)},
    94  			[]cty.Value{},
    95  		},
    96  		{
    97  			[]cty.Value{
    98  				cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark(marks.Sensitive)}),
    99  				cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
   100  			},
   101  			[]cty.Value{
   102  				cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark(marks.Sensitive)}),
   103  				cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
   104  				cty.MapVal(map[string]cty.Value{"c": cty.StringVal("z")}),
   105  			},
   106  			[]cty.Value{
   107  				cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark(marks.Sensitive)}),
   108  				cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
   109  			},
   110  		},
   111  	}
   112  
   113  	for _, test := range tests {
   114  		t.Run(fmt.Sprintf("%#v,%#v", test.xs, test.ys), func(t *testing.T) {
   115  			got := LongestCommonSubsequence(test.xs, test.ys, ValueEqual)
   116  
   117  			wrong := func() {
   118  				t.Fatalf(
   119  					"wrong result\nX:    %#v\nY:    %#v\ngot:  %#v\nwant: %#v",
   120  					test.xs, test.ys, got, test.want,
   121  				)
   122  			}
   123  
   124  			if len(got) != len(test.want) {
   125  				wrong()
   126  			}
   127  
   128  			for i := range got {
   129  				if got[i] == cty.NilVal {
   130  					wrong()
   131  				}
   132  				if !got[i].RawEquals(test.want[i]) {
   133  					wrong()
   134  				}
   135  			}
   136  		})
   137  	}
   138  }