Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helpers for accessing unknown state information #781

Merged
merged 1 commit into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions common/types/unknown.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"math"
"reflect"
"sort"
"strings"
"unicode"

Expand Down Expand Up @@ -160,6 +161,26 @@ func NewUnknown(id int64, attr *AttributeTrail) *Unknown {
}
}

// IDs returns the set of unknown expression ids contained by this value.
//
// Numeric identifiers are guaranteed to be in sorted order.
func (u *Unknown) IDs() []int64 {
ids := make(int64Slice, len(u.attributeTrails))
i := 0
for id := range u.attributeTrails {
ids[i] = id
i++
}
ids.Sort()
return ids
}

// GetAttributeTrails returns the attribute trails, if present, missing for a given expression id.
func (u *Unknown) GetAttributeTrails(id int64) ([]*AttributeTrail, bool) {
trails, found := u.attributeTrails[id]
return trails, found
}

// Contains returns true if the input unknown is a subset of the current unknown.
func (u *Unknown) Contains(other *Unknown) bool {
for id, otherTrails := range other.attributeTrails {
Expand Down Expand Up @@ -288,3 +309,18 @@ func MergeUnknowns(unk1, unk2 *Unknown) *Unknown {
}
return out
}

// int64Slice is an implementation of the sort.Interface
type int64Slice []int64

// Len returns the number of elements in the slice.
func (x int64Slice) Len() int { return len(x) }

// Less indicates whether the value at index i is less than the value at index j.
func (x int64Slice) Less(i, j int) bool { return x[i] < x[j] }

// Swap swaps the values at indices i and j in place.
func (x int64Slice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

// Sort is a convenience method: x.Sort() calls Sort(x).
func (x int64Slice) Sort() { sort.Sort(x) }
67 changes: 64 additions & 3 deletions common/types/unknown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package types
import (
"fmt"
"math"
"reflect"
"strings"
"testing"

Expand Down Expand Up @@ -228,6 +229,68 @@ func TestUnknownContains(t *testing.T) {
}
}

func TestUnknownIDs(t *testing.T) {
tests := []struct {
unk *Unknown
ids []int64
attrs []string
}{
{
unk: NewUnknown(1, nil),
ids: []int64{1},
attrs: []string{"<unspecified>"},
},
{
unk: NewUnknown(2, QualifyAttribute[bool](NewAttributeTrail("a"), true)),
ids: []int64{2},
attrs: []string{"a[true]"},
},
{
unk: NewUnknown(3, QualifyAttribute[string](NewAttributeTrail("a"), "b")),
ids: []int64{3},
attrs: []string{"a.b"},
},
{
unk: NewUnknown(4, QualifyAttribute[string](NewAttributeTrail("a"), "c")),
ids: []int64{4},
attrs: []string{"a.c"},
},
{
unk: MergeUnknowns(
NewUnknown(4, QualifyAttribute[string](NewAttributeTrail("a"), "b")),
NewUnknown(3, QualifyAttribute[bool](NewAttributeTrail("a"), true)),
),
ids: []int64{3, 4},
attrs: []string{"a[true]", "a.b"},
},
}
for i, tst := range tests {
tc := tst
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
ids := tc.unk.IDs()
if !reflect.DeepEqual(ids, tc.ids) {
t.Errorf("%v.IDs() got %v, wanted %v", tc.unk, ids, tc.ids)
}
attrs := make([]string, len(ids))
idx := 0
for _, id := range ids {
trails, found := tc.unk.GetAttributeTrails(id)
if !found {
t.Fatalf("GetAttributeTrails(%d) not found", id)
}
if len(trails) != 1 {
t.Fatalf("GetAttributeTrails(%d) got %d trails, wanted 1", id, len(trails))
}
attrs[idx] = trails[0].String()
idx++
}
if !reflect.DeepEqual(attrs, tc.attrs) {
t.Errorf("%v.GetAttributeTrails() got %v, wanted %v", tc.unk, attrs, tc.attrs)
}
})
}
}

func TestUnknownString(t *testing.T) {
tests := []struct {
unk *Unknown
Expand Down Expand Up @@ -340,7 +403,5 @@ func TestMaybeMergeUnknowns(t *testing.T) {

func newUnk(t *testing.T, id int64, varName string) *Unknown {
t.Helper()
attr := NewAttributeTrail(varName)
unk := NewUnknown(id, attr)
return unk
return NewUnknown(id, NewAttributeTrail(varName))
}