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 }