d2ir: Import and cleanup
Test files still need cleanup.
This commit is contained in:
parent
ef0e197a63
commit
a277d10dda
4 changed files with 719 additions and 0 deletions
57
d2ir/apply.go
Normal file
57
d2ir/apply.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package d2ir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
"oss.terrastruct.com/d2/d2graph"
|
||||
"oss.terrastruct.com/d2/d2parser"
|
||||
)
|
||||
|
||||
type compiler struct {
|
||||
err d2parser.ParseError
|
||||
}
|
||||
|
||||
func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
|
||||
f = "%v: " + f
|
||||
v = append([]interface{}{n.GetRange()}, v...)
|
||||
c.err.Errors = append(c.err.Errors, d2ast.Error{
|
||||
Range: n.GetRange(),
|
||||
Message: fmt.Sprintf(f, v...),
|
||||
})
|
||||
}
|
||||
|
||||
func Apply(dst *Map, ast *d2ast.Map) error {
|
||||
var c compiler
|
||||
c.apply(dst, ast)
|
||||
return c.err
|
||||
}
|
||||
|
||||
func (c *compiler) apply(dst *Map, ast *d2ast.Map) {
|
||||
for _, n := range ast.Nodes {
|
||||
if n.MapKey == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
c.applyKey(dst, n.MapKey)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) applyKey(dst *Map, k *d2ast.Key) {
|
||||
if k.Key != nil && len(k.Key.Path) > 0 {
|
||||
f, ok := dst.Ensure(d2graph.Key(k.Key))
|
||||
if !ok {
|
||||
c.errorf(k.Key, "cannot index into array")
|
||||
return
|
||||
}
|
||||
|
||||
if len(k.Edges) == 0 {
|
||||
if k.Primary.Unbox() != nil {
|
||||
f.Primary = &Scalar{
|
||||
parent: f,
|
||||
Value: k.Primary.Unbox(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
199
d2ir/apply_test.go
Normal file
199
d2ir/apply_test.go
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
package d2ir_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"oss.terrastruct.com/util-go/diff"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
"oss.terrastruct.com/d2/d2ir"
|
||||
"oss.terrastruct.com/d2/d2parser"
|
||||
"oss.terrastruct.com/d2/internal/assert"
|
||||
)
|
||||
|
||||
type testCase struct {
|
||||
name string
|
||||
text string
|
||||
base *d2ir.Map
|
||||
|
||||
exp func(testing.TB, *d2ir.Map, error)
|
||||
}
|
||||
|
||||
func TestApply(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("simple", testApplySimple)
|
||||
}
|
||||
|
||||
func testApplySimple(t *testing.T) {
|
||||
tcs := []testCase{
|
||||
{
|
||||
name: "one",
|
||||
text: `x`,
|
||||
|
||||
exp: func(t testing.TB, m *d2ir.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assertField(t, m, 1, 0, nil)
|
||||
|
||||
assertField(t, m, 0, 0, nil, "x")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested",
|
||||
text: `x.y -> z.p`,
|
||||
|
||||
exp: func(t testing.TB, m *d2ir.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assertField(t, m, 4, 1, nil)
|
||||
|
||||
assertField(t, m, 1, 0, nil, "x")
|
||||
assertField(t, m, 0, 0, nil, "x", "y")
|
||||
|
||||
assertField(t, m, 1, 0, nil, "z")
|
||||
assertField(t, m, 0, 0, nil, "z", "p")
|
||||
|
||||
assertEdge(t, m, 0, nil, &d2ir.EdgeID{
|
||||
[]string{"x", "y"}, false,
|
||||
[]string{"z", "p"}, true,
|
||||
-1,
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "underscore_parent",
|
||||
text: `x._ -> z`,
|
||||
|
||||
exp: func(t testing.TB, m *d2ir.Map, err error) {
|
||||
assert.Success(t, err)
|
||||
assertField(t, m, 2, 1, nil)
|
||||
|
||||
assertField(t, m, 0, 0, nil, "x")
|
||||
assertField(t, m, 0, 0, nil, "z")
|
||||
|
||||
assertEdge(t, m, 0, nil, &d2ir.EdgeID{
|
||||
[]string{"x"}, false,
|
||||
[]string{"z"}, true,
|
||||
-1,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runa(t, tcs)
|
||||
}
|
||||
|
||||
func runa(t *testing.T, tcs []testCase) {
|
||||
for _, tc := range tcs {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
run(t, tc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func run(t testing.TB, tc testCase) {
|
||||
d2Path := fmt.Sprintf("d2/testdata/d2ir/%v.d2", t.Name())
|
||||
ast, err := d2parser.Parse(d2Path, strings.NewReader(tc.text), nil)
|
||||
if err != nil {
|
||||
tc.exp(t, nil, err)
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
dst := tc.base.Copy(nil).(*d2ir.Map)
|
||||
err = d2ir.Apply(dst, ast)
|
||||
tc.exp(t, dst, err)
|
||||
|
||||
err = diff.Testdata(filepath.Join("..", "testdata", "d2ir", t.Name()), dst)
|
||||
if err != nil {
|
||||
tc.exp(t, nil, err)
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func assertField(t testing.TB, n d2ir.Node, nfields, nedges int, primary interface{}, ida ...string) *d2ir.Field {
|
||||
t.Helper()
|
||||
|
||||
m := d2ir.NodeToMap(n)
|
||||
p := d2ir.NodeToPrimary(n)
|
||||
|
||||
var f *d2ir.Field
|
||||
if len(ida) > 0 {
|
||||
f = m.Get(ida)
|
||||
if f == nil {
|
||||
t.Fatalf("expected field %#v in map %#v but not found", ida, m)
|
||||
}
|
||||
p = f.Primary
|
||||
m = d2ir.NodeToMap(f)
|
||||
}
|
||||
|
||||
if m.FieldCount() != nfields {
|
||||
t.Fatalf("expected %d fields but got %d", nfields, m.FieldCount())
|
||||
}
|
||||
if m.EdgeCount() != nedges {
|
||||
t.Fatalf("expected %d edges but got %d", nedges, m.EdgeCount())
|
||||
}
|
||||
if !p.Equal(makeScalar(primary)) {
|
||||
t.Fatalf("expected primary %#v but %#v", primary, p)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func assertEdge(t testing.TB, n d2ir.Node, nfields int, primary interface{}, eid *d2ir.EdgeID) *d2ir.Edge {
|
||||
t.Helper()
|
||||
|
||||
m := d2ir.NodeToMap(n)
|
||||
|
||||
e := m.GetEdge(eid)
|
||||
if e == nil {
|
||||
t.Fatalf("expected edge %#v in map %#v but not found", eid, m)
|
||||
}
|
||||
|
||||
if e.Map.FieldCount() != nfields {
|
||||
t.Fatalf("expected %d fields but got %d", nfields, e.Map.FieldCount())
|
||||
}
|
||||
if e.Map.EdgeCount() != 0 {
|
||||
t.Fatalf("expected %d edges but got %d", 0, e.Map.EdgeCount())
|
||||
}
|
||||
if !e.Primary.Equal(makeScalar(primary)) {
|
||||
t.Fatalf("expected primary %#v but %#v", primary, e.Primary)
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func makeScalar(v interface{}) *d2ir.Scalar {
|
||||
s := &d2ir.Scalar{}
|
||||
switch v := v.(type) {
|
||||
case bool:
|
||||
s.Value = &d2ast.Boolean{
|
||||
Value: v,
|
||||
}
|
||||
case float64:
|
||||
bv := &big.Rat{}
|
||||
bv.SetFloat64(v)
|
||||
s.Value = &d2ast.Number{
|
||||
Value: bv,
|
||||
}
|
||||
case int:
|
||||
s.Value = &d2ast.Number{
|
||||
Value: big.NewRat(int64(v), 1),
|
||||
}
|
||||
case string:
|
||||
s.Value = d2ast.FlatDoubleQuotedString(v)
|
||||
default:
|
||||
if v != nil {
|
||||
panic(fmt.Sprintf("d2ir: unexpected type to makeScalar: %#v", v))
|
||||
}
|
||||
s.Value = &d2ast.Null{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
386
d2ir/d2ir.go
Normal file
386
d2ir/d2ir.go
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
package d2ir
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
)
|
||||
|
||||
type Node interface {
|
||||
node()
|
||||
Copy(newp Parent) Node
|
||||
}
|
||||
|
||||
var _ Node = &Scalar{}
|
||||
var _ Node = &Field{}
|
||||
var _ Node = &Edge{}
|
||||
var _ Node = &Array{}
|
||||
var _ Node = &Map{}
|
||||
|
||||
type Parent interface {
|
||||
Node
|
||||
Parent() Parent
|
||||
}
|
||||
|
||||
var _ Parent = &Field{}
|
||||
var _ Parent = &Edge{}
|
||||
var _ Parent = &Array{}
|
||||
var _ Parent = &Map{}
|
||||
|
||||
type Value interface {
|
||||
Node
|
||||
value()
|
||||
}
|
||||
|
||||
var _ Value = &Scalar{}
|
||||
var _ Value = &Array{}
|
||||
var _ Value = &Map{}
|
||||
|
||||
type Composite interface {
|
||||
Node
|
||||
Value
|
||||
composite()
|
||||
}
|
||||
|
||||
var _ Composite = &Array{}
|
||||
var _ Composite = &Map{}
|
||||
|
||||
func (n *Scalar) node() {}
|
||||
func (n *Field) node() {}
|
||||
func (n *Edge) node() {}
|
||||
func (n *Array) node() {}
|
||||
func (n *Map) node() {}
|
||||
|
||||
func (n *Field) Parent() Parent { return n.parent }
|
||||
func (n *Edge) Parent() Parent { return n.parent }
|
||||
func (n *Array) Parent() Parent { return n.parent }
|
||||
func (n *Map) Parent() Parent { return n.parent }
|
||||
|
||||
func (n *Scalar) value() {}
|
||||
func (n *Array) value() {}
|
||||
func (n *Map) value() {}
|
||||
|
||||
func (n *Array) composite() {}
|
||||
func (n *Map) composite() {}
|
||||
|
||||
type Scalar struct {
|
||||
parent Parent
|
||||
Value d2ast.Scalar `json:"value"`
|
||||
}
|
||||
|
||||
func (s *Scalar) Copy(newp Parent) Node {
|
||||
tmp := *s
|
||||
s = &tmp
|
||||
|
||||
s.parent = newp
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Scalar) Equal(s2 *Scalar) bool {
|
||||
return s.Value.ScalarString() == s2.Value.ScalarString() && s.Value.Type() == s2.Value.Type()
|
||||
}
|
||||
|
||||
type Map struct {
|
||||
parent Parent
|
||||
Fields []*Field `json:"fields"`
|
||||
Edges []*Edge `json:"edges"`
|
||||
}
|
||||
|
||||
func (m *Map) Copy(newp Parent) Node {
|
||||
tmp := *m
|
||||
m = &tmp
|
||||
|
||||
m.parent = newp
|
||||
m.Fields = append([]*Field(nil), m.Fields...)
|
||||
for i := range m.Fields {
|
||||
m.Fields[i] = m.Fields[i].Copy(m).(*Field)
|
||||
}
|
||||
m.Edges = append([]*Edge(nil), m.Edges...)
|
||||
for i := range m.Edges {
|
||||
m.Edges[i] = m.Edges[i].Copy(m).(*Edge)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Root reports whether the Map is the root of the D2 tree.
|
||||
// The root map has no parent.
|
||||
func (m *Map) Root() bool {
|
||||
return m.parent == nil
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
parent *Map
|
||||
|
||||
Name string `json:"name"`
|
||||
|
||||
Primary *Scalar `json:"primary"`
|
||||
Composite Composite `json:"composite"`
|
||||
|
||||
Refs []KeyReference `json:"refs"`
|
||||
}
|
||||
|
||||
func (f *Field) Copy(newp Parent) Node {
|
||||
tmp := *f
|
||||
f = &tmp
|
||||
|
||||
f.parent = newp.(*Map)
|
||||
f.Refs = append([]KeyReference(nil), f.Refs...)
|
||||
if f.Primary != nil {
|
||||
f.Primary = f.Primary.Copy(f).(*Scalar)
|
||||
}
|
||||
if f.Composite != nil {
|
||||
f.Composite = f.Composite.Copy(f).(Composite)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
type EdgeID struct {
|
||||
SrcPath []string `json:"src_path"`
|
||||
SrcArrow bool `json:"src_arrow"`
|
||||
|
||||
DstPath []string `json:"dst_path"`
|
||||
DstArrow bool `json:"dst_arrow"`
|
||||
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
func (eid *EdgeID) Copy() *EdgeID {
|
||||
tmp := *eid
|
||||
eid = &tmp
|
||||
|
||||
eid.SrcPath = append([]string(nil), eid.SrcPath...)
|
||||
eid.DstPath = append([]string(nil), eid.DstPath...)
|
||||
return eid
|
||||
}
|
||||
|
||||
func (eid *EdgeID) Equal(eid2 *EdgeID) bool {
|
||||
if eid.Index != eid2.Index {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(eid.SrcPath) != len(eid2.SrcPath) {
|
||||
return false
|
||||
}
|
||||
if eid.SrcArrow != eid2.SrcArrow {
|
||||
return false
|
||||
}
|
||||
for i, s := range eid.SrcPath {
|
||||
if !strings.EqualFold(s, eid2.SrcPath[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if len(eid.DstPath) != len(eid2.DstPath) {
|
||||
return false
|
||||
}
|
||||
if eid.DstArrow != eid2.DstArrow {
|
||||
return false
|
||||
}
|
||||
for i, s := range eid.DstPath {
|
||||
if !strings.EqualFold(s, eid2.DstPath[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (eid *EdgeID) trimCommon() (common []string, _ *EdgeID) {
|
||||
eid = eid.Copy()
|
||||
for len(eid.SrcPath) > 1 && len(eid.DstPath) > 1 {
|
||||
if !strings.EqualFold(eid.SrcPath[0], eid.DstPath[0]) {
|
||||
return common, eid
|
||||
}
|
||||
common = append(common, eid.SrcPath[0])
|
||||
eid.SrcPath = eid.SrcPath[1:]
|
||||
eid.DstPath = eid.DstPath[1:]
|
||||
}
|
||||
return common, eid
|
||||
}
|
||||
|
||||
type Edge struct {
|
||||
parent *Map
|
||||
|
||||
ID *EdgeID `json:"edge_id"`
|
||||
|
||||
Primary *Scalar `json:"primary"`
|
||||
Map *Map `json:"map"`
|
||||
|
||||
Refs []EdgeReference `json:"refs"`
|
||||
}
|
||||
|
||||
func (e *Edge) Copy(newp Parent) Node {
|
||||
tmp := *e
|
||||
e = &tmp
|
||||
|
||||
e.parent = newp.(*Map)
|
||||
e.Refs = append([]EdgeReference(nil), e.Refs...)
|
||||
if e.Primary != nil {
|
||||
e.Primary = e.Primary.Copy(e).(*Scalar)
|
||||
}
|
||||
if e.Map != nil {
|
||||
e.Map = e.Map.Copy(e).(*Map)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type Array struct {
|
||||
parent Parent
|
||||
Values []Value `json:"values"`
|
||||
}
|
||||
|
||||
func (a *Array) Copy(newp Parent) Node {
|
||||
tmp := *a
|
||||
a = &tmp
|
||||
|
||||
a.parent = newp
|
||||
a.Values = append([]Value(nil), a.Values...)
|
||||
for i := range a.Values {
|
||||
a.Values[i] = a.Values[i].Copy(a).(Value)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
type KeyReference struct {
|
||||
String *d2ast.StringBox `json:"string"`
|
||||
KeyPath *d2ast.KeyPath `json:"key_path"`
|
||||
|
||||
RefCtx *RefContext `json:"ref_ctx"`
|
||||
}
|
||||
|
||||
type EdgeReference struct {
|
||||
RefCtx *RefContext `json:"ref_ctx"`
|
||||
}
|
||||
|
||||
type RefContext struct {
|
||||
Key *d2ast.Key `json:"-"`
|
||||
Edge *d2ast.Edge `json:"-"`
|
||||
Scope *d2ast.Map `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Map) FieldCount() int {
|
||||
acc := len(m.Fields)
|
||||
for _, f := range m.Fields {
|
||||
if f_m, ok := f.Composite.(*Map); ok {
|
||||
acc += f_m.FieldCount()
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
func (m *Map) EdgeCount() int {
|
||||
acc := len(m.Edges)
|
||||
for _, e := range m.Edges {
|
||||
if e.Map != nil {
|
||||
acc += e.Map.EdgeCount()
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
func (m *Map) Get(ida []string) (*Field, bool) {
|
||||
if len(ida) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
s := ida[0]
|
||||
rest := ida[1:]
|
||||
|
||||
for _, f := range m.Fields {
|
||||
if !strings.EqualFold(f.Name, s) {
|
||||
continue
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
return f, true
|
||||
}
|
||||
if f_m, ok := f.Composite.(*Map); ok {
|
||||
return f_m.Get(rest)
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (m *Map) Ensure(ida []string) (*Field, bool) {
|
||||
if len(ida) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
s := ida[0]
|
||||
rest := ida[1:]
|
||||
|
||||
for _, f := range m.Fields {
|
||||
if !strings.EqualFold(f.Name, s) {
|
||||
continue
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
return f, true
|
||||
}
|
||||
switch fc := f.Composite.(type) {
|
||||
case *Map:
|
||||
return fc.Ensure(rest)
|
||||
case *Array:
|
||||
return nil, false
|
||||
}
|
||||
f.Composite = &Map{
|
||||
parent: f,
|
||||
}
|
||||
return f.Composite.(*Map).Ensure(rest)
|
||||
}
|
||||
|
||||
f := &Field{
|
||||
parent: m,
|
||||
Name: s,
|
||||
}
|
||||
m.Fields = append(m.Fields, f)
|
||||
if len(rest) == 0 {
|
||||
return f, true
|
||||
}
|
||||
f.Composite = &Map{
|
||||
parent: f,
|
||||
}
|
||||
return f.Composite.(*Map).Ensure(rest)
|
||||
}
|
||||
|
||||
func (m *Map) Delete(ida []string) bool {
|
||||
if len(ida) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
s := ida[0]
|
||||
rest := ida[1:]
|
||||
|
||||
for i, f := range m.Fields {
|
||||
if !strings.EqualFold(f.Name, s) {
|
||||
continue
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
copy(m.Fields[i:], m.Fields[i+1:])
|
||||
return true
|
||||
}
|
||||
if f_m, ok := f.Composite.(*Map); ok {
|
||||
return f_m.Delete(rest)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Map) GetEdge(eid *EdgeID) (*Edge, bool) {
|
||||
common, eid := eid.trimCommon()
|
||||
if len(common) > 0 {
|
||||
f, ok := m.Get(common)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
if f_m, ok := f.Composite.(*Map); ok {
|
||||
return f_m.GetEdge(eid)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for _, e := range m.Edges {
|
||||
if e.ID.Equal(eid) {
|
||||
return e, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
77
d2ir/d2ir_test.go
Normal file
77
d2ir/d2ir_test.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package d2ir_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"oss.terrastruct.com/d2/d2ast"
|
||||
"oss.terrastruct.com/d2/d2ir"
|
||||
"oss.terrastruct.com/d2/internal/assert"
|
||||
)
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const scalStr = `Those who claim the dead never return to life haven't ever been around.`
|
||||
s := &d2ir.Scalar{
|
||||
parent: nil,
|
||||
Value: d2ast.FlatUnquotedString(scalStr),
|
||||
}
|
||||
a := &d2ir.Array{
|
||||
Parent: nil,
|
||||
Values: []d2ir.Value{
|
||||
&d2ir.Scalar{
|
||||
parent: nil,
|
||||
Value: &d2ast.Boolean{
|
||||
Value: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
m2 := &d2ir.Map{
|
||||
Parent: nil,
|
||||
Fields: []*d2ir.Field{
|
||||
{Primary: s},
|
||||
},
|
||||
}
|
||||
|
||||
const keyStr = `Absence makes the heart grow frantic.`
|
||||
f := &d2ir.Field{
|
||||
Parent: nil,
|
||||
Name: keyStr,
|
||||
|
||||
Primary: s,
|
||||
Composite: a,
|
||||
}
|
||||
e := &d2ir.Edge{
|
||||
Parent: nil,
|
||||
|
||||
Primary: s,
|
||||
Map: m2,
|
||||
}
|
||||
m := &d2ir.Map{
|
||||
Parent: nil,
|
||||
|
||||
Fields: []*d2ir.Field{f},
|
||||
Edges: []*d2ir.Edge{e},
|
||||
}
|
||||
|
||||
m = m.Copy(nil).(*d2ir.Map)
|
||||
f.Name = `Many a wife thinks her husband is the world's greatest lover.`
|
||||
|
||||
assert.Equal(t, m, m.Fields[0].Parent)
|
||||
assert.Equal(t, keyStr, m.Fields[0].Name)
|
||||
assert.Equal(t, m.Fields[0], m.Fields[0].Primary.parent)
|
||||
assert.Equal(t, m.Fields[0], m.Fields[0].Composite.(*d2ir.Array).Parent)
|
||||
|
||||
assert.Equal(t,
|
||||
m.Fields[0].Composite,
|
||||
m.Fields[0].Composite.(*d2ir.Array).Values[0].(*d2ir.Scalar).parent,
|
||||
)
|
||||
|
||||
assert.Equal(t, m, m.Edges[0].Parent)
|
||||
assert.Equal(t, m.Edges[0], m.Edges[0].Primary.parent)
|
||||
assert.Equal(t, m.Edges[0], m.Edges[0].Map.Parent)
|
||||
|
||||
assert.Equal(t, m.Edges[0].Map, m.Edges[0].Map.Fields[0].Parent)
|
||||
assert.Equal(t, m.Edges[0].Map.Fields[0], m.Edges[0].Map.Fields[0].Primary.parent)
|
||||
}
|
||||
Loading…
Reference in a new issue