1522 lines
39 KiB
Go
1522 lines
39 KiB
Go
package d2compiler_test
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"oss.terrastruct.com/diff"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"oss.terrastruct.com/d2/d2compiler"
|
|
"oss.terrastruct.com/d2/d2format"
|
|
"oss.terrastruct.com/d2/d2graph"
|
|
"oss.terrastruct.com/d2/d2target"
|
|
)
|
|
|
|
func TestCompile(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
text string
|
|
|
|
expErr string
|
|
assertions func(t *testing.T, g *d2graph.Graph)
|
|
}{
|
|
{
|
|
name: "basic_shape",
|
|
|
|
text: `
|
|
x: {
|
|
shape: circle
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatalf("expected 1 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
|
|
if g.Objects[0].Attributes.Shape.Value != d2target.ShapeCircle {
|
|
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value to be circle: %#v", g.Objects[0].Attributes.Shape.Value)
|
|
}
|
|
|
|
},
|
|
},
|
|
{
|
|
name: "basic_style",
|
|
|
|
text: `
|
|
x: {
|
|
style.opacity: 0.4
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatalf("expected 1 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
|
|
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("expected g.Objects[0].Attributes.Style.Opacity.Value to be 0.4: %#v", g.Objects[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
|
|
},
|
|
},
|
|
{
|
|
name: "image_style",
|
|
|
|
text: `hey: "" {
|
|
icon: https://icons.terrastruct.com/essentials/004-picture.svg
|
|
shape: image
|
|
style.stroke: "#0D32B2"
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatalf("expected 1 objects: %#v", g.Objects)
|
|
}
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "dimensions_on_nonimage",
|
|
|
|
text: `hey: "" {
|
|
shape: hexagon
|
|
width: 200
|
|
height: 230
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/dimensions_on_nonimage.d2:3:2: width is only applicable to image shapes.
|
|
d2/testdata/d2compiler/TestCompile/dimensions_on_nonimage.d2:4:2: height is only applicable to image shapes.
|
|
`,
|
|
},
|
|
{
|
|
name: "basic_icon",
|
|
|
|
text: `hey: "" {
|
|
icon: https://icons.terrastruct.com/essentials/004-picture.svg
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if g.Objects[0].Attributes.Icon == nil {
|
|
t.Fatal("Attribute icon is nil")
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "shape_unquoted_hex",
|
|
|
|
text: `x: {
|
|
style: {
|
|
fill: #ffffff
|
|
}
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/shape_unquoted_hex.d2:3:10: missing value after colon
|
|
`,
|
|
},
|
|
{
|
|
name: "edge_unquoted_hex",
|
|
|
|
text: `x -> y: {
|
|
style: {
|
|
fill: #ffffff
|
|
}
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/edge_unquoted_hex.d2:3:10: missing value after colon
|
|
`,
|
|
},
|
|
{
|
|
name: "blank_underscore",
|
|
|
|
text: `x: {
|
|
y
|
|
_
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/blank_underscore.d2:3:3: invalid use of parent "_"
|
|
`,
|
|
},
|
|
{
|
|
name: "image_non_style",
|
|
|
|
text: `x: {
|
|
shape: image
|
|
icon: https://icons.terrastruct.com/aws/_Group%20Icons/EC2-instance-container_light-bg.svg
|
|
name: y
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/image_non_style.d2:4:3: image shapes cannot have children.
|
|
`,
|
|
},
|
|
{
|
|
name: "stroke-width",
|
|
|
|
text: `hey {
|
|
style.stroke-width: 0
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatalf("expected 1 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].Attributes.Style.StrokeWidth.Value != "0" {
|
|
t.Fatalf("unexpected")
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "illegal-stroke-width",
|
|
|
|
text: `hey {
|
|
style.stroke-width: -1
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/illegal-stroke-width.d2:2:23: expected "stroke-width" to be a number between 0 and 15
|
|
`,
|
|
},
|
|
{
|
|
name: "underscore_parent_create",
|
|
|
|
text: `
|
|
x: {
|
|
_.y
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Root.ChildrenArray) != 2 {
|
|
t.Fatalf("expected 2 objects at the root: %#v", len(g.Root.ChildrenArray))
|
|
}
|
|
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_parent_not_root",
|
|
|
|
text: `
|
|
x: {
|
|
y: {
|
|
_.z
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Root.ChildrenArray) != 1 {
|
|
t.Fatalf("expected 1 object at the root: %#v", len(g.Root.ChildrenArray))
|
|
}
|
|
if len(g.Objects[0].ChildrenArray) != 2 {
|
|
t.Fatalf("expected 2 objects within x: %v", len(g.Objects[0].ChildrenArray))
|
|
}
|
|
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_parent_preference_1",
|
|
|
|
text: `
|
|
x: {
|
|
_.y: "All we are given is possibilities -- to make ourselves one thing or another."
|
|
}
|
|
y: "But it's real. And if it's real it can be affected ... we may not be able"
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Root.ChildrenArray) != 2 {
|
|
t.Fatalf("expected 2 objects at the root: %#v", len(g.Root.ChildrenArray))
|
|
}
|
|
if g.Objects[1].Attributes.Label.Value != "But it's real. And if it's real it can be affected ... we may not be able" {
|
|
t.Fatalf("expected g.Objects[1].Label.Value to be last value: %#v", g.Objects[1].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_parent_preference_2",
|
|
|
|
text: `
|
|
y: "But it's real. And if it's real it can be affected ... we may not be able"
|
|
x: {
|
|
_.y: "All we are given is possibilities -- to make ourselves one thing or another."
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "y" {
|
|
t.Fatalf("expected g.Objects[0].ID to be y: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "x" {
|
|
t.Fatalf("expected g.Objects[1].ID to be x: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Root.ChildrenArray) != 2 {
|
|
t.Fatalf("expected 2 objects at the root: %#v", len(g.Root.ChildrenArray))
|
|
}
|
|
if g.Objects[0].Attributes.Label.Value != "All we are given is possibilities -- to make ourselves one thing or another." {
|
|
t.Fatalf("expected g.Objects[0].Label.Value to be last value: %#v", g.Objects[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_parent_squared",
|
|
|
|
text: `
|
|
x: {
|
|
y: {
|
|
_._.z
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", len(g.Objects))
|
|
}
|
|
|
|
if len(g.Root.ChildrenArray) != 2 {
|
|
t.Fatalf("expected 2 objects at the root: %#v", len(g.Root.ChildrenArray))
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_parent_root",
|
|
|
|
text: `
|
|
_.x
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_root.d2:2:1: parent "_" cannot be used in the root scope
|
|
`,
|
|
},
|
|
{
|
|
name: "underscore_parent_middle_path",
|
|
|
|
text: `
|
|
x: {
|
|
y._.z
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_middle_path.d2:3:3: parent "_" can only be used in the beginning of paths, e.g. "_.x"
|
|
`,
|
|
},
|
|
{
|
|
name: "underscore_parent_sandwich_path",
|
|
|
|
text: `
|
|
x: {
|
|
_.z._
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_sandwich_path.d2:3:3: parent "_" can only be used in the beginning of paths, e.g. "_.x"
|
|
`,
|
|
},
|
|
{
|
|
name: "underscore_edge",
|
|
|
|
text: `
|
|
x: {
|
|
_.y -> _.x
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "y" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be y: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "x" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be x: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].SrcArrow {
|
|
t.Fatalf("expected g.Edges[0].SrcArrow to be false: %#v", g.Edges[0])
|
|
}
|
|
if !g.Edges[0].DstArrow {
|
|
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0])
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_edge_chain",
|
|
|
|
text: `
|
|
x: {
|
|
_.y -> _.x -> _.z
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
if g.Objects[2].ID != "z" {
|
|
t.Fatalf("expected g.Objects[2].ID to be z: %#v", g.Objects[2])
|
|
}
|
|
|
|
if len(g.Edges) != 2 {
|
|
t.Fatalf("expected 2 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "y" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be y: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "x" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be x: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[1].Src.ID != "x" {
|
|
t.Fatalf("expected g.Edges[1].Src.ID to be x: %#v", g.Edges[1])
|
|
}
|
|
if g.Edges[1].Dst.ID != "z" {
|
|
t.Fatalf("expected g.Edges[1].Dst.ID to be z: %#v", g.Edges[1])
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_edge_existing",
|
|
|
|
text: `
|
|
a -> b: "Can you imagine how life could be improved if we could do away with"
|
|
x: {
|
|
_.a -> _.b: "Well, it's garish, ugly, and derelicts have used it for a toilet."
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if len(g.Edges) != 2 {
|
|
t.Fatalf("expected 2 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "a" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be a: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "b" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be b: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[1].Src.ID != "a" {
|
|
t.Fatalf("expected g.Edges[1].Src.ID to be a: %#v", g.Edges[1])
|
|
}
|
|
if g.Edges[1].Dst.ID != "b" {
|
|
t.Fatalf("expected g.Edges[1].Dst.ID to be b: %#v", g.Edges[1])
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "Can you imagine how life could be improved if we could do away with" {
|
|
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Attributes.Label)
|
|
}
|
|
if g.Edges[1].Attributes.Label.Value != "Well, it's garish, ugly, and derelicts have used it for a toilet." {
|
|
t.Fatalf("unexpected g.Edges[1].Label: %#v", g.Edges[1].Attributes.Label)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_edge_index",
|
|
|
|
text: `
|
|
a -> b: "Can you imagine how life could be improved if we could do away with"
|
|
x: {
|
|
(_.a -> _.b)[0]: "Well, it's garish, ugly, and derelicts have used it for a toilet."
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "a" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be a: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "b" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be b: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "Well, it's garish, ugly, and derelicts have used it for a toilet." {
|
|
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Attributes.Label)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "underscore_edge_nested",
|
|
|
|
text: `
|
|
x: {
|
|
y: {
|
|
_._.z -> _.y
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.AbsID() != "z" {
|
|
t.Fatalf("expected g.Edges[0].Src.AbsID() to be z: %#v", g.Edges[0].Src.AbsID())
|
|
}
|
|
if g.Edges[0].Dst.AbsID() != "x.y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.AbsID() to be x.y: %#v", g.Edges[0].Dst.AbsID())
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge",
|
|
|
|
text: `
|
|
x -> y
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "x" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be x: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be y: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].SrcArrow {
|
|
t.Fatalf("expected g.Edges[0].SrcArrow to be false: %#v", g.Edges[0])
|
|
}
|
|
if !g.Edges[0].DstArrow {
|
|
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0])
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_chain",
|
|
|
|
text: `
|
|
x -> y -> z: "The kids will love our inflatable slides"
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
if g.Objects[2].ID != "z" {
|
|
t.Fatalf("expected g.Objects[2].ID to be z: %#v", g.Objects[2])
|
|
}
|
|
|
|
if len(g.Edges) != 2 {
|
|
t.Fatalf("expected 2 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "x" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be x: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be y: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[1].Src.ID != "y" {
|
|
t.Fatalf("expected g.Edges[1].Src.ID to be x: %#v", g.Edges[1])
|
|
}
|
|
if g.Edges[1].Dst.ID != "z" {
|
|
t.Fatalf("expected g.Edges[1].Dst.ID to be y: %#v", g.Edges[1])
|
|
}
|
|
|
|
if g.Edges[0].Attributes.Label.Value != "The kids will love our inflatable slides" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label: %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
if g.Edges[1].Attributes.Label.Value != "The kids will love our inflatable slides" {
|
|
t.Fatalf("unexpected g.Edges[1].Attributes.Label: %#v", g.Edges[1].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_index",
|
|
|
|
text: `
|
|
x -> y: one
|
|
(x -> y)[0]: two
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "x" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be x: %#v", g.Edges[0].Src)
|
|
}
|
|
if g.Edges[0].Dst.ID != "y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be y: %#v", g.Edges[0].Dst)
|
|
}
|
|
if g.Edges[0].SrcArrow {
|
|
t.Fatalf("expected g.Edges[0].SrcArrow to be false: %#v", g.Edges[0].SrcArrow)
|
|
}
|
|
if !g.Edges[0].DstArrow {
|
|
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0].DstArrow)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "two" {
|
|
t.Fatalf("expected g.Edges[0].Attributes.Label to be two: %#v", g.Edges[0].Attributes.Label)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_index_nested",
|
|
|
|
text: `
|
|
b: {
|
|
x -> y: one
|
|
(x -> y)[0]: two
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "b" {
|
|
t.Fatalf("expected g.Objects[0].ID to be b: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "x" {
|
|
t.Fatalf("expected g.Objects[1].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[2].ID != "y" {
|
|
t.Fatalf("expected g.Objects[2].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.AbsID() != "b.x" {
|
|
t.Fatalf("expected g.Edges[0].Src.AbsoluteID() to be x: %#v", g.Edges[0].Src)
|
|
}
|
|
if g.Edges[0].Dst.AbsID() != "b.y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.AbsoluteID() to be y: %#v", g.Edges[0].Dst)
|
|
}
|
|
if g.Edges[0].SrcArrow {
|
|
t.Fatalf("expected g.Edges[0].SrcArrow to be false: %#v", g.Edges[0].SrcArrow)
|
|
}
|
|
if !g.Edges[0].DstArrow {
|
|
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0].DstArrow)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "two" {
|
|
t.Fatalf("expected g.Edges[0].Attributes.Label to be two: %#v", g.Edges[0].Attributes.Label)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_index_nested_cross_scope",
|
|
|
|
text: `
|
|
b: {
|
|
x -> y: one
|
|
}
|
|
b.(x -> y)[0]: two
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "b" {
|
|
t.Fatalf("expected g.Objects[0].ID to be b: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "x" {
|
|
t.Fatalf("expected g.Objects[1].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[2].ID != "y" {
|
|
t.Fatalf("expected g.Objects[2].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.AbsID() != "b.x" {
|
|
t.Fatalf("expected g.Edges[0].Src.AbsoluteID() to be x: %#v", g.Edges[0].Src)
|
|
}
|
|
if g.Edges[0].Dst.AbsID() != "b.y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.AbsoluteID() to be y: %#v", g.Edges[0].Dst)
|
|
}
|
|
if g.Edges[0].SrcArrow {
|
|
t.Fatalf("expected g.Edges[0].SrcArrow to be false: %#v", g.Edges[0].SrcArrow)
|
|
}
|
|
if !g.Edges[0].DstArrow {
|
|
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0].DstArrow)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "two" {
|
|
t.Fatalf("expected g.Edges[0].Attributes.Label to be two: %#v", g.Edges[0].Attributes.Label)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map",
|
|
|
|
text: `
|
|
x -> y: {
|
|
label: "Space: the final frontier. These are the voyages of the starship Enterprise."
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
if g.Objects[0].ID != "x" {
|
|
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
|
|
}
|
|
if g.Objects[1].ID != "y" {
|
|
t.Fatalf("expected g.Objects[1].ID to be y: %#v", g.Objects[1])
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Src.ID != "x" {
|
|
t.Fatalf("expected g.Edges[0].Src.ID to be x: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Dst.ID != "y" {
|
|
t.Fatalf("expected g.Edges[0].Dst.ID to be y: %#v", g.Edges[0])
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_label_map",
|
|
|
|
text: `hey y9 -> qwer: asdf {style.opacity: 0.5}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "asdf" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map_arrowhead",
|
|
|
|
text: `x -> y: {
|
|
source-arrowhead: {
|
|
shape: diamond
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Shape.Value)
|
|
// Make sure the DSL didn't change. this is a regression test where it did
|
|
exp := `x -> y: {
|
|
source-arrowhead: {
|
|
shape: diamond
|
|
}
|
|
}
|
|
`
|
|
newText := d2format.Format(g.AST)
|
|
ds, err := diff.Strings(exp, newText)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ds != "" {
|
|
t.Fatalf("exp != newText:\n%s", ds)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_arrowhead_fields",
|
|
|
|
text: `x -> y: {
|
|
source-arrowhead: Reisner's Rule of Conceptual Inertia {
|
|
shape: diamond
|
|
}
|
|
target-arrowhead: QOTD
|
|
target-arrowhead: {
|
|
style.filled: true
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
|
|
diff.AssertStringEq(t, "Reisner's Rule of Conceptual Inertia", g.Edges[0].SrcArrowhead.Label.Value)
|
|
diff.AssertStringEq(t, "QOTD", g.Edges[0].DstArrowhead.Label.Value)
|
|
diff.AssertStringEq(t, "true", g.Edges[0].DstArrowhead.Style.Filled.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Shape.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Label.Value)
|
|
assert.Nil(t, g.Edges[0].Attributes.Style.Filled)
|
|
},
|
|
},
|
|
{
|
|
name: "edge_flat_arrowhead",
|
|
|
|
text: `x -> y
|
|
(x -> y)[0].source-arrowhead.shape: diamond
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Shape.Value)
|
|
},
|
|
},
|
|
{
|
|
// tests setting to an arrowhead-only shape
|
|
name: "edge_non_shape_arrowhead",
|
|
|
|
text: `x -> y: { source-arrowhead.shape: triangle }
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "triangle", g.Edges[0].SrcArrowhead.Shape.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Shape.Value)
|
|
},
|
|
},
|
|
{
|
|
name: "object_arrowhead_shape",
|
|
|
|
text: `x: {shape: triangle}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/object_arrowhead_shape.d2:1:5: invalid shape, can only set "triangle" for arrowheads
|
|
`,
|
|
},
|
|
{
|
|
name: "edge_flat_label_arrowhead",
|
|
|
|
text: `x -> y: {
|
|
# comment
|
|
source-arrowhead.label: yo
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "yo", g.Edges[0].SrcArrowhead.Label.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Label.Value)
|
|
},
|
|
},
|
|
{
|
|
name: "edge_semiflat_arrowhead",
|
|
|
|
text: `x -> y
|
|
(x -> y)[0].source-arrowhead: {
|
|
shape: diamond
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Shape.Value)
|
|
},
|
|
},
|
|
{
|
|
name: "edge_mixed_arrowhead",
|
|
|
|
text: `x -> y: {
|
|
target-arrowhead.shape: diamond
|
|
}
|
|
(x -> y)[0].source-arrowhead: {
|
|
shape: diamond
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
|
|
diff.AssertStringEq(t, "diamond", g.Edges[0].DstArrowhead.Shape.Value)
|
|
assert.Empty(t, g.Edges[0].Attributes.Shape.Value)
|
|
},
|
|
},
|
|
{
|
|
name: "edge_exclusive_style",
|
|
|
|
text: `
|
|
x -> y: {
|
|
style.animated: true
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Animated.Value != "true" {
|
|
t.Fatalf("Edges[0].Attributes.Style.Animated.Value: %#v", g.Edges[0].Attributes.Style.Animated.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "nested_edge",
|
|
|
|
text: `sequence -> quest: {
|
|
space -> stars
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/nested_edge.d2:1:1: edges cannot be nested within another edge
|
|
`,
|
|
},
|
|
{
|
|
name: "shape_edge_style",
|
|
|
|
text: `
|
|
x: {
|
|
style.animated: true
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/shape_edge_style.d2:3:2: key "animated" can only be applied to edges
|
|
`,
|
|
},
|
|
{
|
|
name: "edge_chain_map",
|
|
|
|
text: `
|
|
x -> y -> z: {
|
|
label: "Space: the final frontier. These are the voyages of the starship Enterprise."
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 2 {
|
|
t.Fatalf("expected 2 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
if g.Edges[1].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[1].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_index_map",
|
|
|
|
text: `
|
|
x -> y
|
|
(x -> y)[0]: {
|
|
label: "Space: the final frontier. These are the voyages of the starship Enterprise."
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map_nested",
|
|
|
|
text: `
|
|
x -> y: {
|
|
style: {
|
|
opacity: 0.4
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map_nested_flat",
|
|
|
|
text: `
|
|
x -> y: {
|
|
style.opacity: 0.4
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map_group_flat",
|
|
|
|
text: `
|
|
x -> y
|
|
(x -> y)[0].style.opacity: 0.4
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map_group_semiflat",
|
|
|
|
text: `x -> y
|
|
(x -> y)[0].style: {
|
|
opacity: 0.4
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatalf("expected 2 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_key_group_flat_nested",
|
|
|
|
text: `
|
|
x: {
|
|
a -> b
|
|
}
|
|
x.(a -> b)[0].style.opacity: 0.4
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_key_group_flat_nested_underscore",
|
|
|
|
text: `
|
|
a -> b
|
|
x: {
|
|
(_.a -> _.b)[0].style.opacity: 0.4
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_key_group_map_nested_underscore",
|
|
|
|
text: `
|
|
a -> b
|
|
x: {
|
|
(_.a -> _.b)[0]: {
|
|
style: {
|
|
opacity: 0.4
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_key_group_map_flat_nested_underscore",
|
|
|
|
text: `
|
|
a -> b
|
|
x: {
|
|
(_.a -> _.b)[0]: {
|
|
style.opacity: 0.4
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 3 {
|
|
t.Fatalf("expected 3 objects: %#v", g.Objects)
|
|
}
|
|
|
|
if len(g.Edges) != 1 {
|
|
t.Fatalf("expected 1 edge: %#v", g.Edges)
|
|
}
|
|
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
if g.Edges[0].Attributes.Label.Value != "" {
|
|
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "edge_map_non_reserved",
|
|
|
|
text: `
|
|
x -> y: {
|
|
z
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/edge_map_non_reserved.d2:2:1: edge map keys must be reserved keywords
|
|
`,
|
|
},
|
|
{
|
|
name: "url_link",
|
|
|
|
text: `x: {
|
|
link: https://google.com
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if g.Objects[0].Attributes.Link != "https://google.com" {
|
|
t.Fatal(g.Objects[0].Attributes.Link)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "path_link",
|
|
|
|
text: `x: {
|
|
link: Overview.Untitled board 7.zzzzz
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if g.Objects[0].Attributes.Link != "Overview.Untitled board 7.zzzzz" {
|
|
t.Fatal(g.Objects[0].Attributes.Link)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "reserved_icon_near_style",
|
|
|
|
text: `x: {
|
|
icon: orange
|
|
style.opacity: 0.5
|
|
style.stroke: red
|
|
style.fill: green
|
|
}
|
|
x.near: y
|
|
y
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if g.Objects[0].Attributes.NearKey == nil {
|
|
t.Fatal("missing near key")
|
|
}
|
|
if g.Objects[0].Attributes.Icon.Path != "orange" {
|
|
t.Fatal(g.Objects[0].Attributes.Icon)
|
|
}
|
|
if g.Objects[0].Attributes.Style.Opacity.Value != "0.5" {
|
|
t.Fatal(g.Objects[0].Attributes.Style.Opacity)
|
|
}
|
|
if g.Objects[0].Attributes.Style.Stroke.Value != "red" {
|
|
t.Fatal(g.Objects[0].Attributes.Style.Stroke)
|
|
}
|
|
if g.Objects[0].Attributes.Style.Fill.Value != "green" {
|
|
t.Fatal(g.Objects[0].Attributes.Style.Fill)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "errors/reserved_icon_style",
|
|
|
|
text: `x: {
|
|
near: y
|
|
icon: "::????:::%%orange"
|
|
style.opacity: -1
|
|
style.opacity: 232
|
|
}
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:3:9: bad icon url "::????:::%%orange": parse "::????:::%%orange": missing protocol scheme
|
|
d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:4:18: expected "opacity" to be a number between 0.0 and 1.0
|
|
d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:5:18: expected "opacity" to be a number between 0.0 and 1.0
|
|
d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:1:1: near key "y" does not exist. It must be the absolute path to a shape.
|
|
`,
|
|
},
|
|
{
|
|
name: "errors/missing_shape_icon",
|
|
|
|
text: `x.shape: image`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/errors/missing_shape_icon.d2:1:1: image shape must include an "icon" field
|
|
`,
|
|
},
|
|
{
|
|
name: "edge_in_column",
|
|
|
|
text: `x: {
|
|
shape: sql_table
|
|
x: {p -> q}
|
|
}`,
|
|
},
|
|
{
|
|
name: "edge_to_style",
|
|
|
|
text: `x: {style.opacity: 0.4}
|
|
y -> x.style
|
|
`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/edge_to_style.d2:2:1: cannot connect to reserved keyword
|
|
`,
|
|
},
|
|
{
|
|
name: "escaped_id",
|
|
|
|
text: `b\nb`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, `b
|
|
b`, g.Objects[0].Attributes.Label.Value)
|
|
},
|
|
},
|
|
{
|
|
name: "class_style",
|
|
|
|
text: `IUserProperties: {
|
|
shape: "class"
|
|
firstName?: "string"
|
|
style.opacity: 0.4
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if len(g.Objects[0].Class.Fields) != 1 {
|
|
t.Fatal(len(g.Objects[0].Class.Fields))
|
|
}
|
|
if len(g.Objects[0].Class.Methods) != 0 {
|
|
t.Fatal(len(g.Objects[0].Class.Methods))
|
|
}
|
|
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatal(g.Objects[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "table_style",
|
|
|
|
text: `IUserProperties: {
|
|
shape: sql_table
|
|
GetType(): string
|
|
style.opacity: 0.4
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if len(g.Objects[0].SQLTable.Columns) != 1 {
|
|
t.Fatal(len(g.Objects[0].SQLTable.Columns))
|
|
}
|
|
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatal(g.Objects[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "table_style_map",
|
|
|
|
text: `IUserProperties: {
|
|
shape: sql_table
|
|
GetType(): string
|
|
style: {
|
|
opacity: 0.4
|
|
color: blue
|
|
}
|
|
}
|
|
`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if len(g.Objects[0].SQLTable.Columns) != 1 {
|
|
t.Fatal(len(g.Objects[0].SQLTable.Columns))
|
|
}
|
|
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
|
|
t.Fatal(g.Objects[0].Attributes.Style.Opacity.Value)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "class_paren",
|
|
|
|
text: `_shape_: "shape" {
|
|
shape: class
|
|
|
|
field here
|
|
GetType(): string
|
|
Is(): bool
|
|
}`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, `field here`, g.Objects[0].Class.Fields[0].Name)
|
|
diff.AssertStringEq(t, `GetType()`, g.Objects[0].Class.Methods[0].Name)
|
|
diff.AssertStringEq(t, `Is()`, g.Objects[0].Class.Methods[1].Name)
|
|
},
|
|
},
|
|
{
|
|
name: "sql_paren",
|
|
|
|
text: `_shape_: "shape" {
|
|
shape: sql_table
|
|
|
|
GetType(): string
|
|
Is(): bool
|
|
}`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, `GetType()`, g.Objects[0].SQLTable.Columns[0].Name)
|
|
diff.AssertStringEq(t, `Is()`, g.Objects[0].SQLTable.Columns[1].Name)
|
|
},
|
|
},
|
|
{
|
|
name: "nested_sql",
|
|
|
|
text: `outer: {
|
|
table: {
|
|
shape: sql_table
|
|
|
|
GetType(): string
|
|
Is(): bool
|
|
}
|
|
}`,
|
|
assertions: func(t *testing.T, g *d2graph.Graph) {
|
|
if len(g.Objects) != 2 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if _, has := g.Objects[0].HasChild([]string{"table"}); !has {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
if len(g.Objects[0].ChildrenArray) != 1 {
|
|
t.Fatal(g.Objects)
|
|
}
|
|
diff.AssertStringEq(t, `GetType()`, g.Objects[1].SQLTable.Columns[0].Name)
|
|
diff.AssertStringEq(t, `Is()`, g.Objects[1].SQLTable.Columns[1].Name)
|
|
},
|
|
},
|
|
{
|
|
name: "3d_oval",
|
|
|
|
text: `SVP1.style.shape: oval
|
|
SVP1.style.3d: true`,
|
|
expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares and rectangles
|
|
`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
d2Path := fmt.Sprintf("d2/testdata/d2compiler/%v.d2", t.Name())
|
|
g, err := d2compiler.Compile(d2Path, strings.NewReader(tc.text), nil)
|
|
if tc.expErr != "" {
|
|
if err == nil {
|
|
t.Fatalf("expected error with: %q", tc.expErr)
|
|
}
|
|
ds, err := diff.Strings(tc.expErr, err.Error())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ds != "" {
|
|
t.Fatalf("unexpected error: %s", ds)
|
|
}
|
|
} else if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if tc.expErr == "" && tc.assertions != nil {
|
|
t.Run("assertions", func(t *testing.T) {
|
|
tc.assertions(t, g)
|
|
})
|
|
}
|
|
|
|
got := struct {
|
|
Graph *d2graph.Graph `json:"graph"`
|
|
Err error `json:"err"`
|
|
}{
|
|
Graph: g,
|
|
Err: err,
|
|
}
|
|
|
|
err = diff.Testdata(filepath.Join("..", "testdata", "d2compiler", t.Name()), got)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
}
|