From 6fd39ad70c3a6bbdb1b4e47444e4cce72f901200 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 6 Jun 2019 16:40:01 -0700 Subject: [PATCH] cty/diff: Remove the diff package This package was never actually completed and is not fully-functional. The code that was in here is now available via a separate Go Module at github.com/zclconf/go-cty-diff , where it can stay with an experimental version number until such time that its basic functionality is complete. --- cty/diff/change.go | 118 ------------- cty/diff/diff.go | 90 ---------- cty/diff/diff_list.go | 113 ------------ cty/diff/diff_list_test.go | 345 ------------------------------------- cty/diff/diff_test.go | 1 - cty/diff/doc.go | 12 -- cty/diff/lcs.go | 100 ----------- cty/diff/lcs_test.go | 100 ----------- 8 files changed, 879 deletions(-) delete mode 100644 cty/diff/change.go delete mode 100644 cty/diff/diff.go delete mode 100644 cty/diff/diff_list.go delete mode 100644 cty/diff/diff_list_test.go delete mode 100644 cty/diff/diff_test.go delete mode 100644 cty/diff/doc.go delete mode 100644 cty/diff/lcs.go delete mode 100644 cty/diff/lcs_test.go diff --git a/cty/diff/change.go b/cty/diff/change.go deleted file mode 100644 index d05c404c..00000000 --- a/cty/diff/change.go +++ /dev/null @@ -1,118 +0,0 @@ -package diff - -import ( - "github.com/zclconf/go-cty/cty" -) - -// Change is an abstract type representing a single change operation as -// part of a Diff. -// -// Change is a closed interface, meaning that the only permitted -// implementations are those within this package. -type Change interface { - changeSigil() changeImpl -} - -// Embed changeImpl into a struct to make it a Change implementation -type changeImpl struct{} - -func (c changeImpl) changeSigil() changeImpl { - return c -} - -// ReplaceChange is a Change implementation that represents replacing an -// existing value with an entirely new value. -// -// When adding a new element to a map value, this change type should be used -// with OldValue set to a null value of the appropriate type. -type ReplaceChange struct { - changeImpl - Path cty.Path - OldValue cty.Value - NewValue cty.Value -} - -// DeleteChange is a Change implementation that represents removing an -// element from an indexable collection. -// -// For a list type, if the deleted element is not the final element in -// the list then the resulting "gap" is closed by renumbering all subsequent -// items. Therefore a Diff containing a sequence of DeleteChange operations -// on the same list must be careful to consider the new state of the element -// indices after each step, or present the deletions in reverse order to -// avoid such complexity. -type DeleteChange struct { - changeImpl - Path cty.Path - OldValue cty.Value -} - -// InsertChange is a Change implementation that represents inserting a new -// element into a list. -// -// When appending to a list, the Path should be to the not-yet-existing index -// and BeforeValue should be a null of the appropriate type. -type InsertChange struct { - changeImpl - Path cty.Path - NewValue cty.Value - BeforeValue cty.Value -} - -// AddChange is a Change implementation that represents adding a value to -// a set. The Path is to the set itself, and NewValue is the value to insert. -type AddChange struct { - changeImpl - Path cty.Path - NewValue cty.Value -} - -// RemoveChange is a Change implementation that represents removing a value -// from a set. The path is to the set itself, and OldValue is the value to -// remove. -// -// Note that it is not possible to remove an unknown value from a set -// because no two unknown values are equal, so a diff whose source value -// had sets with unknown members cannot be applied and is useful only -// for presentation to a user. Generally-speaking one should avoid including -// unknowns in the source value when creating a diff. -type RemoveChange struct { - changeImpl - Path cty.Path - OldValue cty.Value -} - -// NestedDiff is a Change implementation that applies a nested diff to a -// value. -// -// A NestedDiff is similar to a ReplaceChange, except that rather than -// providing a literal new value the replacement value is instead the result -// of applying the diff to the old value. -// -// The Paths in the nested diff are relative to the path of the NestedDiff -// node, so the absolute paths of the affected elements are the concatenation -// of the two. -// -// This is primarily useful for representing updates to set elements. Since -// set elements are addressed by their own value, it convenient to specify -// the value path only once and apply a number of other operations to it. -// However, it's acceptable to use NestedDiff on any value type as long as -// the nested diff is valid for that type. -type NestedDiff struct { - changeImpl - Path cty.Path - OldValue cty.Value - Diff Diff -} - -// Context is a funny sort of Change implementation that doesn't actually -// change anything but fails if the value at the given path doesn't match -// the given value. -// -// This can be used to add additional context to a diff so that merge -// conflicts can be detected. -type Context struct { - changeImpl - Path cty.Path - WantValue cty.Value -} diff --git a/cty/diff/diff.go b/cty/diff/diff.go deleted file mode 100644 index ef49bb17..00000000 --- a/cty/diff/diff.go +++ /dev/null @@ -1,90 +0,0 @@ -package diff - -import ( - "errors" - - "github.com/zclconf/go-cty/cty" -) - -// Diff represents a sequence of changes to transform one Value into another -// Value. -// -// Diff has convenience methods for appending changes one by one, but each -// of these allocates a fresh list and so they may create memory pressure. -// Callers can and should construct and convert []Change values directly -// where appropriate. -type Diff []Change - -// NewDiff produces a new diff by comparing the two given values. the -// returned diff represents a sequence of changes required to transform -// a value equal to source into a value equal to target. -// -// Since cty unknown values are never equal, any unknown values will -// *always* produce a ReplaceChange, even if the source and target values -// are both unknown. This represents the fact that we don't know yet whether -// the value will actually change. -// -// For best results the source value should be free of unknowns, since an -// entirely-deterministic diff cannot be created when the source contains -// nested unknown values. However, this function will -// still attempt to construct such a diff since it may still be useful to -// display to a user. -func NewDiff(source, target cty.Value) Diff { - panic("NewDiff is not yet implemented") -} - -// Apply produces a new value by applying the receiving Diff to the given -// source value. If any one change fails then the entire operation is -// considered to have failed. -func (d Diff) Apply(source cty.Value) (cty.Value, error) { - return cty.NullVal(source.Type()), errors.New("not yet implemented") -} - -// Replace returns a copy of the receiver with a ReplaceChange appended. -func (d Diff) Replace(path cty.Path, old, new cty.Value) Diff { - return d.append(ReplaceChange{ - Path: path, - OldValue: old, - NewValue: new, - }) -} - -// Delete returns a copy of the receiver with a DeleteChange appended. -func (d Diff) Delete(path cty.Path, old cty.Value) Diff { - return d.append(DeleteChange{ - Path: path, - OldValue: old, - }) -} - -// Insert returns a copy of the receiver with a DeleteChange appended. -func (d Diff) Insert(path cty.Path, new, before cty.Value) Diff { - return d.append(InsertChange{ - Path: path, - NewValue: new, - BeforeValue: before, - }) -} - -// Add returns a copy of the receiver with an AddChange appended. -func (d Diff) Add(path cty.Path, new cty.Value) Diff { - return d.append(AddChange{ - Path: path, - NewValue: new, - }) -} - -// Remove returns a copy of the receiver with a RemoveChange appended. -func (d Diff) Remove(path cty.Path, old cty.Value) Diff { - return d.append(RemoveChange{ - Path: path, - OldValue: old, - }) -} - -func (d Diff) append(change Change) Diff { - ret := make(Diff, len(d)+1) - copy(ret, d) - ret[len(d)] = change - return ret -} diff --git a/cty/diff/diff_list.go b/cty/diff/diff_list.go deleted file mode 100644 index caac10f3..00000000 --- a/cty/diff/diff_list.go +++ /dev/null @@ -1,113 +0,0 @@ -package diff - -import "github.com/zclconf/go-cty/cty" - -// diffListsShallow takes two values that must be known, non-null lists of the -// same element type and returns a shallow diff that adds and removes only -// direct list members, even if they are themselves collection- or -// structural-typed values. -func diffListsShallow(old cty.Value, new cty.Value, path cty.Path) Diff { - var diff Diff - - oldEls := make([]cty.Value, 0, old.LengthInt()) - newEls := make([]cty.Value, 0, old.LengthInt()) - it := old.ElementIterator() - for it.Next() { - _, v := it.Element() - oldEls = append(oldEls, v) - } - it = new.ElementIterator() - for it.Next() { - _, v := it.Element() - newEls = append(newEls, v) - } - - lcs := longestCommonSubsequence(oldEls, newEls) - op := 0 // position in "old" - np := 0 // position in "new" - cp := 0 // position in "lcs" - ip := int64(0) // current index for diff changes - - path = append(path, nil) - step := &path[len(path)-1] - - for op < len(oldEls) || np < len(newEls) { - - // We want to produce blocks of removes, adds, and contexts - // until we run out of items. - - // Elements unique to old are deleted - for op < len(oldEls) { - if cp < len(lcs) { - eq := oldEls[op].Equals(lcs[cp]) - if eq.IsKnown() && eq.True() { - break - } - } - *step = cty.IndexStep{ - Key: cty.NumberIntVal(ip), - } - diff = append(diff, DeleteChange{ - Path: path.Copy(), - OldValue: oldEls[op], - }) - op++ - } - - // Elements unique to new are inserted - for np < len(newEls) { - if cp < len(lcs) { - eq := newEls[np].Equals(lcs[cp]) - if eq.IsKnown() && eq.True() { - break - } - } - *step = cty.IndexStep{ - Key: cty.NumberIntVal(ip), - } - var beforeVal cty.Value - if op < len(oldEls) { - beforeVal = oldEls[op] - } else { - beforeVal = cty.NullVal(old.Type().ElementType()) - } - diff = append(diff, InsertChange{ - Path: path.Copy(), - NewValue: newEls[np], - BeforeValue: beforeVal, - }) - np++ - ip++ - } - - // Elements common to both are context. - // For this loop we'll advance all three pointers at once because - // we expect to be walking through the same elements in all three. - for cp < len(lcs) && op < len(oldEls) && np < len(newEls) { - oeq := oldEls[op].Equals(lcs[cp]) - if !(oeq.IsKnown() && oeq.True()) { - break - } - neq := newEls[np].Equals(lcs[cp]) - if !(neq.IsKnown() && neq.True()) { - break - } - - *step = cty.IndexStep{ - Key: cty.NumberIntVal(ip), - } - diff = append(diff, Context{ - Path: path.Copy(), - WantValue: lcs[cp], - }) - - cp++ - op++ - np++ - ip++ - } - - } - - return diff -} diff --git a/cty/diff/diff_list_test.go b/cty/diff/diff_list_test.go deleted file mode 100644 index 4d94a16b..00000000 --- a/cty/diff/diff_list_test.go +++ /dev/null @@ -1,345 +0,0 @@ -package diff - -import ( - "fmt" - "testing" - - "reflect" - - "github.com/zclconf/go-cty/cty" - "github.com/kylelemons/godebug/pretty" -) - -func TestDiffListsShallow(t *testing.T) { - tests := []struct { - Old []cty.Value - New []cty.Value - Want Diff - }{ - { - []cty.Value{}, - []cty.Value{}, - Diff(nil), - }, - { - []cty.Value{cty.NumberIntVal(1)}, - []cty.Value{}, - Diff{ - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - OldValue: cty.NumberIntVal(1), - }, - }, - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{}, - Diff{ - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - OldValue: cty.NumberIntVal(1), - }, - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - OldValue: cty.NumberIntVal(2), - }, - }, - }, - { - []cty.Value{}, - []cty.Value{cty.NumberIntVal(1)}, - Diff{ - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - NewValue: cty.NumberIntVal(1), - BeforeValue: cty.NullVal(cty.Number), - }, - }, - }, - { - []cty.Value{}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - Diff{ - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - NewValue: cty.NumberIntVal(1), - BeforeValue: cty.NullVal(cty.Number), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(1)}, - }, - NewValue: cty.NumberIntVal(2), - BeforeValue: cty.NullVal(cty.Number), - }, - }, - }, - { - []cty.Value{cty.NumberIntVal(1)}, - []cty.Value{cty.NumberIntVal(1)}, - Diff{ - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - WantValue: cty.NumberIntVal(1), - }, - }, - }, - { - []cty.Value{cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1)}, - Diff{ - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - OldValue: cty.NumberIntVal(2), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - NewValue: cty.NumberIntVal(1), - BeforeValue: cty.NullVal(cty.Number), - }, - }, - }, - { - []cty.Value{cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - Diff{ - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - NewValue: cty.NumberIntVal(1), - BeforeValue: cty.NumberIntVal(2), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(1)}, - }, - WantValue: cty.NumberIntVal(2), - }, - }, - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(2)}, - Diff{ - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - OldValue: cty.NumberIntVal(1), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - WantValue: cty.NumberIntVal(2), - }, - }, - }, - { - []cty.Value{ - cty.NumberIntVal(1), - cty.NumberIntVal(4), - cty.NumberIntVal(6), - }, - []cty.Value{ - cty.NumberIntVal(1), - cty.NumberIntVal(2), - cty.NumberIntVal(3), - cty.NumberIntVal(4), - cty.NumberIntVal(5), - cty.NumberIntVal(6), - }, - Diff{ - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - WantValue: cty.NumberIntVal(1), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(1)}, - }, - NewValue: cty.NumberIntVal(2), - BeforeValue: cty.NumberIntVal(4), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(2)}, - }, - NewValue: cty.NumberIntVal(3), - BeforeValue: cty.NumberIntVal(4), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(3)}, - }, - WantValue: cty.NumberIntVal(4), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(4)}, - }, - NewValue: cty.NumberIntVal(5), - BeforeValue: cty.NumberIntVal(6), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(5)}, - }, - WantValue: cty.NumberIntVal(6), - }, - }, - }, - { - []cty.Value{ - cty.NumberIntVal(1), - cty.NumberIntVal(4), - cty.NumberIntVal(6), - }, - []cty.Value{ - cty.NumberIntVal(1), - cty.NumberIntVal(2), - cty.NumberIntVal(3), - cty.NumberIntVal(5), - cty.NumberIntVal(6), - }, - Diff{ - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - WantValue: cty.NumberIntVal(1), - }, - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(1)}, - }, - OldValue: cty.NumberIntVal(4), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(1)}, - }, - NewValue: cty.NumberIntVal(2), - BeforeValue: cty.NumberIntVal(6), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(2)}, - }, - NewValue: cty.NumberIntVal(3), - BeforeValue: cty.NumberIntVal(6), - }, - InsertChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(3)}, - }, - NewValue: cty.NumberIntVal(5), - BeforeValue: cty.NumberIntVal(6), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(4)}, - }, - WantValue: cty.NumberIntVal(6), - }, - }, - }, - { - []cty.Value{ - cty.NumberIntVal(1), - cty.NumberIntVal(2), - cty.NumberIntVal(2), - cty.NumberIntVal(2), - cty.NumberIntVal(3), - }, - []cty.Value{ - cty.NumberIntVal(1), - cty.NumberIntVal(2), - cty.NumberIntVal(3), - }, - Diff{ - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(0)}, - }, - WantValue: cty.NumberIntVal(1), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(1)}, - }, - WantValue: cty.NumberIntVal(2), - }, - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(2)}, - }, - OldValue: cty.NumberIntVal(2), - }, - DeleteChange{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(2)}, - }, - OldValue: cty.NumberIntVal(2), - }, - Context{ - Path: cty.Path{ - cty.IndexStep{Key: cty.NumberIntVal(2)}, - }, - WantValue: cty.NumberIntVal(3), - }, - }, - }, - } - - pr := &pretty.Config{ - Diffable: true, - Formatter: map[reflect.Type]interface{}{ - reflect.TypeOf(cty.NilVal): func(val cty.Value) string { - return val.GoString() - }, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%#v,%#v", test.Old, test.New), func(t *testing.T) { - var ov cty.Value - var nv cty.Value - if len(test.Old) == 0 { - ov = cty.ListValEmpty(cty.Number) - } else { - ov = cty.ListVal(test.Old) - } - if len(test.New) == 0 { - nv = cty.ListValEmpty(cty.Number) - } else { - nv = cty.ListVal(test.New) - } - - got := diffListsShallow(ov, nv, cty.Path(nil)) - - if !reflect.DeepEqual(got, test.Want) { - t.Errorf("wrong result\n%s", pr.Compare(test.Want, got)) - } - }) - } -} diff --git a/cty/diff/diff_test.go b/cty/diff/diff_test.go deleted file mode 100644 index f8689a22..00000000 --- a/cty/diff/diff_test.go +++ /dev/null @@ -1 +0,0 @@ -package diff diff --git a/cty/diff/doc.go b/cty/diff/doc.go deleted file mode 100644 index 0d19f36f..00000000 --- a/cty/diff/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// package diff contains utilities for computing and applying structural -// diffs against data structures within the cty type system. -// -// This can be useful for showing a user how a cty-based configuration -// structure has changed over time, using concepts that are congruent with the -// way the values themselves are expressed. -// -// This package does not contain any functions for rendering a diff for -// display to a user, since it is expected that a language building on cty -// will want to use its own familiar syntax for presenting diffs and will thus -// provide its own diff-presentation functionality. -package diff diff --git a/cty/diff/lcs.go b/cty/diff/lcs.go deleted file mode 100644 index 70b7ea95..00000000 --- a/cty/diff/lcs.go +++ /dev/null @@ -1,100 +0,0 @@ -package diff - -import "github.com/zclconf/go-cty/cty" - -// longestCommonSubsequence finds a sequence of values that are common to both -// x and y, with the same relative ordering as in both collections. -// -// The approached used here is a "naive" one, assuming that both x and y will -// generally be small in the use-cases cty is aimed at. For larger lists -// the time/space usage may be sub-optimal. -// -// A pair of lists may have multiple longest common subsequences. In that -// case, the one selected by this function is undefined. -func longestCommonSubsequence(xs, ys []cty.Value) []cty.Value { - if len(xs) == 0 || len(ys) == 0 { - return make([]cty.Value, 0) - } - - c := make([]int, len(xs)*len(ys)) - eqs := make([]bool, len(xs)*len(ys)) - w := len(xs) - - for y := 0; y < len(ys); y++ { - for x := 0; x < len(xs); x++ { - eqV := xs[x].Equals(ys[y]) - eq := false - if eqV.IsKnown() && eqV.True() { - eq = true - eqs[(w*y)+x] = true // equality tests can be expensive, so cache it - } - if eq { - // Sequence gets one longer than for the cell at top left, - // since we'd append a new item to the sequence here. - if x == 0 || y == 0 { - c[(w*y)+x] = 1 - } else { - c[(w*y)+x] = c[(w*(y-1))+(x-1)] + 1 - } - } else { - // We follow the longest of the sequence above and the sequence - // to the left of us in the matrix. - l := 0 - u := 0 - if x > 0 { - l = c[(w*y)+(x-1)] - } - if y > 0 { - u = c[(w*(y-1))+x] - } - if l > u { - c[(w*y)+x] = l - } else { - c[(w*y)+x] = u - } - } - } - } - - // The bottom right cell tells us how long our longest sequence will be - seq := make([]cty.Value, c[len(c)-1]) - - // Now we will walk back from the bottom right cell, finding again all - // of the equal pairs to construct our sequence. - x := len(xs) - 1 - y := len(ys) - 1 - i := len(seq) - 1 - - for x > -1 && y > -1 { - if eqs[(w*y)+x] { - // Add the value to our result list and then walk diagonally - // up and to the left. - seq[i] = xs[x] - x-- - y-- - i-- - } else { - // Take the path with the greatest sequence length in the matrix. - l := 0 - u := 0 - if x > 0 { - l = c[(w*y)+(x-1)] - } - if y > 0 { - u = c[(w*(y-1))+x] - } - if l > u { - x-- - } else { - y-- - } - } - } - - if i > -1 { - // should never happen if the matrix was constructed properly - panic("not enough elements in sequence") - } - - return seq -} diff --git a/cty/diff/lcs_test.go b/cty/diff/lcs_test.go deleted file mode 100644 index cfbadf68..00000000 --- a/cty/diff/lcs_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package diff - -import ( - "fmt" - "testing" - - "github.com/zclconf/go-cty/cty" -) - -func TestLongestCommonSubsequence(t *testing.T) { - tests := []struct { - xs []cty.Value - ys []cty.Value - want []cty.Value - }{ - { - []cty.Value{}, - []cty.Value{}, - []cty.Value{}, - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(3), cty.NumberIntVal(4)}, - []cty.Value{}, - }, - { - []cty.Value{cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(2)}, - }, - { - []cty.Value{cty.NumberIntVal(1)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1)}, - }, - { - []cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(1)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)}, - []cty.Value{cty.NumberIntVal(1)}, // arbitrarily selected 1; 2 would also be valid - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(4)}, - []cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4), cty.NumberIntVal(5)}, - []cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4)}, - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(4)}, - []cty.Value{cty.NumberIntVal(4), cty.NumberIntVal(2), cty.NumberIntVal(5)}, - []cty.Value{cty.NumberIntVal(4)}, // 2 would also be valid - }, - { - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(5)}, - []cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4), cty.NumberIntVal(5)}, - []cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(5)}, - }, - - // unknowns never compare as equal - { - []cty.Value{cty.NumberIntVal(1), cty.UnknownVal(cty.Number), cty.NumberIntVal(3)}, - []cty.Value{cty.NumberIntVal(1), cty.UnknownVal(cty.Number), cty.NumberIntVal(3)}, - []cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(3)}, - }, - { - []cty.Value{cty.UnknownVal(cty.Number)}, - []cty.Value{cty.UnknownVal(cty.Number)}, - []cty.Value{}, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%#v,%#v", test.xs, test.ys), func(t *testing.T) { - got := longestCommonSubsequence(test.xs, test.ys) - - wrong := func() { - t.Fatalf( - "wrong result\nX: %#v\nY: %#v\ngot: %#v\nwant: %#v", - test.xs, test.ys, got, test.want, - ) - } - - if len(got) != len(test.want) { - wrong() - } - - for i := range got { - if got[i] == cty.NilVal { - wrong() - } - if !got[i].RawEquals(test.want[i]) { - wrong() - } - } - }) - } -}