2022-11-03 13:54:49 +00:00
package d2compiler_test
import (
"fmt"
"path/filepath"
"strings"
"testing"
2022-12-04 20:47:55 +00:00
tassert "github.com/stretchr/testify/assert"
2022-12-08 07:22:20 +00:00
2023-01-04 01:50:27 +00:00
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff"
2022-11-03 13:54:49 +00:00
"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 ] )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Shape . Value != d2target . ShapeCircle {
t . Fatalf ( "expected g.Objects[0].Shape.Value to be circle: %#v" , g . Objects [ 0 ] . Shape . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 ] )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "expected g.Objects[0].Style.Opacity.Value to be 0.4: %#v" , g . Objects [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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
}
` ,
2022-12-29 04:47:40 +00:00
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 != "hey" {
t . Fatalf ( "expected g.Objects[0].ID to be 'hey': %#v" , g . Objects [ 0 ] )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Shape . Value != d2target . ShapeHexagon {
t . Fatalf ( "expected g.Objects[0].Shape.Value to be hexagon: %#v" , g . Objects [ 0 ] . Shape . Value )
2022-12-29 04:47:40 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . WidthAttr . Value != "200" {
t . Fatalf ( "expected g.Objects[0].Width.Value to be 200: %#v" , g . Objects [ 0 ] . WidthAttr . Value )
2022-12-29 04:47:40 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . HeightAttr . Value != "230" {
t . Fatalf ( "expected g.Objects[0].Height.Value to be 230: %#v" , g . Objects [ 0 ] . HeightAttr . Value )
2022-12-29 04:47:40 +00:00
}
} ,
} ,
2023-02-18 22:54:10 +00:00
{
name : "positions" ,
text : ` hey : {
2023-02-19 00:23:27 +00:00
top : 200
left : 230
2023-02-18 22:54:10 +00:00
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "200" , g . Objects [ 0 ] . Top . Value )
2023-02-18 22:54:10 +00:00
} ,
} ,
2023-02-22 04:09:23 +00:00
{
name : "positions_negative" ,
text : ` hey : {
top : 200
left : - 200
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/positions_negative.d2:3:8: left must be a non-negative integer: "-200" ` ,
} ,
2022-12-29 04:47:40 +00:00
{
name : "equal_dimensions_on_circle" ,
text : ` hey : "" {
shape : circle
width : 200
height : 230
}
` ,
expErr : ` d2 / testdata / d2compiler / TestCompile / equal_dimensions_on_circle . d2 : 3 : 2 : width and height must be equal for circle shapes
2023-01-24 11:09:40 +00:00
d2 / testdata / d2compiler / TestCompile / equal_dimensions_on_circle . d2 : 4 : 2 : width and height must be equal for circle shapes ` ,
2022-12-29 04:47:40 +00:00
} ,
{
name : "single_dimension_on_circle" ,
text : ` hey : "" {
shape : circle
height : 230
}
` ,
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 != "hey" {
t . Fatalf ( "expected ID to be 'hey': %#v" , g . Objects [ 0 ] )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Shape . Value != d2target . ShapeCircle {
t . Fatalf ( "expected Attributes.Shape.Value to be circle: %#v" , g . Objects [ 0 ] . Shape . Value )
2022-12-29 04:47:40 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . WidthAttr != nil {
t . Fatalf ( "expected Attributes.Width to be nil: %#v" , g . Objects [ 0 ] . WidthAttr )
2022-12-29 04:47:40 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . HeightAttr == nil {
2022-12-29 04:47:40 +00:00
t . Fatalf ( "Attributes.Height is nil" )
}
} ,
2022-11-03 13:54:49 +00:00
} ,
2022-12-29 05:14:25 +00:00
{
2023-02-19 05:51:55 +00:00
name : "dimensions_on_containers" ,
2022-12-29 05:14:25 +00:00
text : `
containers : {
circle container : {
shape : circle
width : 512
diamond : {
shape : diamond
width : 128
height : 64
}
}
diamond container : {
shape : diamond
width : 512
height : 256
circle : {
shape : circle
width : 128
}
}
oval container : {
shape : oval
width : 512
height : 256
hexagon : {
shape : hexagon
width : 128
height : 64
}
}
hexagon container : {
shape : hexagon
width : 512
height : 256
oval : {
shape : oval
width : 128
height : 64
}
}
}
` ,
2023-01-06 19:01:45 +00:00
} ,
{
name : "dimension_with_style" ,
text : ` x : {
width : 200
style . multiple : true
}
2022-12-29 05:14:25 +00:00
` ,
} ,
2022-11-03 13:54:49 +00:00
{
name : "basic_icon" ,
text : ` hey : "" {
icon : https : //icons.terrastruct.com/essentials/004-picture.svg
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Icon == nil {
2022-11-03 13:54:49 +00:00
t . Fatal ( "Attribute icon is nil" )
}
} ,
} ,
2023-03-14 03:07:13 +00:00
{
name : "fill-pattern" ,
text : ` x : {
style : {
fill - pattern : dots
}
}
` ,
} ,
{
name : "invalid-fill-pattern" ,
text : ` x : {
style : {
fill - pattern : ddots
}
}
` ,
2023-03-18 22:43:28 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/invalid-fill-pattern.d2:3:19: expected "fill-pattern" to be one of: dots, lines, grain, paper ` ,
2023-03-14 03:07:13 +00:00
} ,
2022-11-03 13:54:49 +00:00
{
name : "shape_unquoted_hex" ,
text : ` x : {
style : {
fill : # ffffff
}
}
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/shape_unquoted_hex.d2:3:10: missing value after colon ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "edge_unquoted_hex" ,
text : ` x - > y : {
style : {
fill : # ffffff
}
}
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/edge_unquoted_hex.d2:3:10: missing value after colon ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "blank_underscore" ,
text : ` x : {
y
_
}
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/blank_underscore.d2:3:3: field key must contain more than underscores ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "image_non_style" ,
text : ` x : {
shape : image
icon : https : //icons.terrastruct.com/aws/_Group%20Icons/EC2-instance-container_light-bg.svg
name : y
}
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/image_non_style.d2:4:3: image shapes cannot have children. ` ,
2022-11-03 13:54:49 +00:00
} ,
2023-03-05 17:43:42 +00:00
{
name : "image_children_Steps" ,
text : ` x : {
icon : https : //icons.terrastruct.com/aws/_Group%20Icons/EC2-instance-container_light-bg.svg
shape : image
Steps
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/image_children_Steps.d2:4:3: steps is only allowed at a board root ` ,
} ,
2022-11-03 13:54:49 +00:00
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . StrokeWidth . Value != "0" {
2022-11-03 13:54:49 +00:00
t . Fatalf ( "unexpected" )
}
} ,
} ,
{
name : "illegal-stroke-width" ,
text : ` hey {
style . stroke - width : - 1
}
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/illegal-stroke-width.d2:2:23: expected "stroke-width" to be a number between 0 and 15 ` ,
2022-11-03 13:54:49 +00:00
} ,
{
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 ) )
}
} ,
} ,
2022-12-04 20:47:55 +00:00
{
name : "underscore_unresolved_obj" ,
text : `
x : {
_ . y
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , "y" , g . Objects [ 1 ] . ID )
2023-01-24 05:48:43 +00:00
tassert . Equal ( t , g . Objects [ 0 ] . AbsID ( ) , g . Objects [ 1 ] . References [ 0 ] . ScopeObj . AbsID ( ) )
2022-12-04 20:47:55 +00:00
} ,
} ,
2023-02-15 00:45:55 +00:00
{
name : "underscore_connection" ,
text : ` a : {
_ . c . d - > _ . c . b
}
` ,
2023-02-15 00:48:16 +00:00
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-02-15 00:52:50 +00:00
tassert . Equal ( t , 4 , len ( g . Objects ) )
2023-02-15 00:48:16 +00:00
tassert . Equal ( t , 1 , len ( g . Edges ) )
} ,
2023-02-15 00:45:55 +00:00
} ,
2022-11-03 13:54:49 +00:00
{
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 ) )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 1 ] . 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 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 ) )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . 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 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/underscore_parent_root.d2:2:1: invalid underscore: no parent ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "underscore_parent_middle_path" ,
text : `
x : {
y . _ . z
}
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/underscore_parent_middle_path.d2:3:5: parent "_" can only be used in the beginning of paths, e.g. "_.x" ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "underscore_parent_sandwich_path" ,
text : `
x : {
_ . z . _
}
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/underscore_parent_sandwich_path.d2:3:7: parent "_" can only be used in the beginning of paths, e.g. "_.x" ` ,
2022-11-03 13:54:49 +00:00
} ,
{
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 ] )
}
} ,
} ,
2023-04-30 03:45:03 +00:00
{
name : "md_block_string_err" ,
text : ` test : | md
# What about pipes
Will escaping \ | work ?
|
` ,
expErr : ` d2 / testdata / d2compiler / TestCompile / md_block_string_err . d2 : 4 : 19 : unexpected text after md block string . See https : //d2lang.com/tour/text#advanced-block-strings.
d2 / testdata / d2compiler / TestCompile / md_block_string_err . d2 : 5 : 1 : block string must be terminated with | ` ,
} ,
2023-06-02 01:48:37 +00:00
{
2023-06-02 17:42:44 +00:00
name : "no_empty_block_string" ,
2023-06-02 01:48:37 +00:00
text : ` Text: |md | ` ,
2023-06-02 17:42:44 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/no_empty_block_string.d2:1:1: block string cannot be empty ` ,
} ,
{
name : "no_white_spaces_only_block_string" ,
text : ` Text: |md | ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no_white_spaces_only_block_string.d2:1:1: block string cannot be empty ` ,
} ,
{
name : "no_new_lines_only_block_string" ,
text : ` Text : | md
| ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no_new_lines_only_block_string.d2:1:1: block string cannot be empty ` ,
2023-06-02 01:48:37 +00:00
} ,
2022-11-03 13:54:49 +00:00
{
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 ] )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . 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 ] . Label )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 1 ] . 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 ] . Label )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 ] )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . 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 ] . Label )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 ] )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "The kids will love our inflatable slides" {
t . Fatalf ( "unexpected g.Edges[0].Label: %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 1 ] . Label . Value != "The kids will love our inflatable slides" {
t . Fatalf ( "unexpected g.Edges[1].Label: %#v" , g . Edges [ 1 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "two" {
t . Fatalf ( "expected g.Edges[0].Label to be two: %#v" , g . Edges [ 0 ] . Label )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "two" {
t . Fatalf ( "expected g.Edges[0].Label to be two: %#v" , g . Edges [ 0 ] . Label )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "two" {
t . Fatalf ( "expected g.Edges[0].Label to be two: %#v" , g . Edges [ 0 ] . Label )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
2023-03-07 17:00:45 +00:00
{
name : "unsemantic_markdown" ,
text : ` test : |
foobar
< p >
|
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/unsemantic_markdown.d2:1:1: malformed Markdown: element <p> closed by </div> ` ,
} ,
{
name : "unsemantic_markdown_2" ,
text : ` test : |
foo < br >
bar
|
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/unsemantic_markdown_2.d2:1:1: malformed Markdown: element <br> closed by </p> ` ,
} ,
2022-11-03 13:54:49 +00:00
{
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 ] )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "asdf" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "diamond" , g . Edges [ 0 ] . SrcArrowhead . Shape . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Shape . Value )
2022-11-03 13:54:49 +00:00
// 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 )
}
} ,
} ,
2023-03-11 21:21:13 +00:00
{
name : "edge_arrowhead_primary" ,
text : ` x - > y : {
source - arrowhead : Reisner ' s Rule of Conceptual Inertia
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
assert . String ( t , "Reisner's Rule of Conceptual Inertia" , g . Edges [ 0 ] . SrcArrowhead . Label . Value )
} ,
} ,
2022-11-03 13:54:49 +00:00
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "diamond" , g . Edges [ 0 ] . SrcArrowhead . Shape . Value )
assert . String ( t , "Reisner's Rule of Conceptual Inertia" , g . Edges [ 0 ] . SrcArrowhead . Label . Value )
assert . String ( t , "QOTD" , g . Edges [ 0 ] . DstArrowhead . Label . Value )
assert . String ( t , "true" , g . Edges [ 0 ] . DstArrowhead . Style . Filled . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Shape . Value )
assert . String ( t , "" , g . Edges [ 0 ] . Label . Value )
assert . JSON ( t , nil , g . Edges [ 0 ] . Style . Filled )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "diamond" , g . Edges [ 0 ] . SrcArrowhead . Shape . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Shape . Value )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
// 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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "triangle" , g . Edges [ 0 ] . SrcArrowhead . Shape . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Shape . Value )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
name : "object_arrowhead_shape" ,
text : ` x : { shape : triangle }
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/object_arrowhead_shape.d2:1:5: invalid shape, can only set "triangle" for arrowheads ` ,
2022-11-03 13:54:49 +00:00
} ,
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "yo" , g . Edges [ 0 ] . SrcArrowhead . Label . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "diamond" , g . Edges [ 0 ] . SrcArrowhead . Shape . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Shape . Value )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , "diamond" , g . Edges [ 0 ] . SrcArrowhead . Shape . Value )
assert . String ( t , "diamond" , g . Edges [ 0 ] . DstArrowhead . Shape . Value )
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Edges [ 0 ] . Shape . Value )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Animated . Value != "true" {
t . Fatalf ( "Edges[0].Style.Animated.Value: %#v" , g . Edges [ 0 ] . Style . Animated . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
name : "nested_edge" ,
text : ` sequence - > quest : {
space - > stars
}
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/nested_edge.d2:2:3: cannot create edge inside edge ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "shape_edge_style" ,
text : `
x : {
style . animated : true
}
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/shape_edge_style.d2:3:2: key "animated" can only be applied to edges ` ,
2022-11-03 13:54:49 +00:00
} ,
2023-03-07 06:42:52 +00:00
{
name : "edge_invalid_style" ,
text : ` x - > y : {
opacity : 0.5
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/edge_invalid_style.d2:2:3: opacity must be style.opacity ` ,
} ,
{
name : "obj_invalid_style" ,
text : ` x : {
opacity : 0.5
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/obj_invalid_style.d2:2:3: opacity must be style.opacity ` ,
} ,
2022-11-03 13:54:49 +00:00
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 1 ] . Label . Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 1 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatalf ( "unexpected g.Edges[0].Style.Opacity.Value: %#v" , g . Edges [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Edges [ 0 ] . Label . Value != "" {
t . Fatalf ( "unexpected g.Edges[0].Label.Value : %#v" , g . Edges [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
name : "edge_map_non_reserved" ,
text : `
x - > y : {
z
}
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/edge_map_non_reserved.d2:3:3: edge map keys must be reserved keywords ` ,
2022-11-03 13:54:49 +00:00
} ,
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Link . Value != "https://google.com" {
t . Fatal ( g . Objects [ 0 ] . Link . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
2023-03-26 16:45:05 +00:00
{
name : "url_tooltip" ,
text : ` x: { tooltip: https://google.com} ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
if len ( g . Objects ) != 1 {
t . Fatal ( g . Objects )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Tooltip . Value != "https://google.com" {
t . Fatal ( g . Objects [ 0 ] . Tooltip . Value )
2023-03-26 16:45:05 +00:00
}
} ,
} ,
{
name : "no_url_link_and_url_tooltip_concurrently" ,
text : ` x: { link: https://not-google.com; tooltip: https://google.com} ` ,
2023-03-27 22:07:24 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/no_url_link_and_url_tooltip_concurrently.d2:1:44: Tooltip cannot be set to URL when link is also set (for security) ` ,
2023-03-26 16:45:05 +00:00
} ,
{
name : "url_link_and_not_url_tooltip_concurrently" ,
text : ` x: { link: https://google.com; tooltip: hello world} ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
if len ( g . Objects ) != 1 {
t . Fatal ( g . Objects )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Link . Value != "https://google.com" {
t . Fatal ( g . Objects [ 0 ] . Link . Value )
2023-03-26 16:45:05 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Tooltip . Value != "hello world" {
t . Fatal ( g . Objects [ 0 ] . Tooltip . Value )
2023-03-26 16:45:05 +00:00
}
} ,
} ,
2023-02-23 16:49:02 +00:00
{
name : "nil_scope_obj_regression" ,
text : ` a
b : {
_ . a
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , "a" , g . Objects [ 0 ] . ID )
for _ , ref := range g . Objects [ 0 ] . References {
tassert . NotNil ( t , ref . ScopeObj )
}
} ,
} ,
2022-11-03 13:54:49 +00:00
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Link . Value != "Overview.Untitled board 7.zzzzz" {
t . Fatal ( g . Objects [ 0 ] . Link . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
2022-12-25 21:42:11 +00:00
{
name : "near_constant" ,
text : ` x . near : top - center
` ,
2023-02-19 16:15:59 +00:00
} ,
{
name : "near-invalid" ,
text : ` mongodb : MongoDB {
perspective : perspective ( View ) {
password
}
explanation : | md
perspective . model . js
| {
near : mongodb
}
}
a : {
near : a . b
b
}
` ,
expErr : ` d2 / testdata / d2compiler / TestCompile / near - invalid . d2 : 9 : 11 : near keys cannot be set to an ancestor
d2 / testdata / d2compiler / TestCompile / near - invalid . d2 : 14 : 9 : near keys cannot be set to an descendant ` ,
2022-12-25 21:42:11 +00:00
} ,
{
name : "near_bad_constant" ,
text : ` x . near : txop - center
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/near_bad_constant.d2:1:9: near key "txop-center" must be the absolute path to a shape or one of the following constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right ` ,
2022-12-27 05:22:23 +00:00
} ,
{
2023-03-22 04:12:04 +00:00
name : "near_bad_connected" ,
2022-12-27 05:22:23 +00:00
2023-03-22 04:12:04 +00:00
text : `
x : {
near : top - center
}
x - > y
` ,
2023-04-05 21:00:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/near_bad_connected.d2:5:5: cannot connect objects from within a container, that has near constant set, to objects outside that container ` ,
2022-12-27 05:22:23 +00:00
} ,
{
2023-03-22 05:43:25 +00:00
name : "near_descendant_connect_to_outside" ,
text : `
x : {
near : top - left
y
}
x . y - > z
` ,
2023-03-30 10:15:35 +00:00
expErr : "d2/testdata/d2compiler/TestCompile/near_descendant_connect_to_outside.d2:6:5: cannot connect objects from within a container, that has near constant set, to objects outside that container" ,
2022-12-25 21:42:11 +00:00
} ,
{
name : "nested_near_constant" ,
text : ` x . y . near : top - center
` ,
2023-01-24 06:45:21 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/nested_near_constant.d2:1:11: constant near keys can only be set on root level shapes ` ,
2022-12-25 21:42:11 +00:00
} ,
2022-11-03 13:54:49 +00:00
{
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 )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . NearKey == nil {
2022-11-03 13:54:49 +00:00
t . Fatal ( "missing near key" )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Icon . Path != "orange" {
t . Fatal ( g . Objects [ 0 ] . Icon )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Opacity . Value != "0.5" {
t . Fatal ( g . Objects [ 0 ] . Style . Opacity )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Stroke . Value != "red" {
t . Fatal ( g . Objects [ 0 ] . Style . Stroke )
2022-11-03 13:54:49 +00:00
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Fill . Value != "green" {
t . Fatal ( g . Objects [ 0 ] . Style . Fill )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 : 5 : 18 : expected "opacity" to be a number between 0.0 and 1.0
2023-01-24 06:45:21 +00:00
d2 / testdata / d2compiler / TestCompile / errors / reserved_icon_style . d2 : 2 : 9 : near key "y" must be the absolute path to a shape or one of the following constants : top - left , top - center , top - right , center - left , center - right , bottom - left , bottom - center , bottom - right ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "errors/missing_shape_icon" ,
2023-01-18 12:32:12 +00:00
text : ` x.shape: image ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/errors/missing_shape_icon.d2:1:1: image shape must include an "icon" field ` ,
2022-11-03 13:54:49 +00:00
} ,
{
name : "edge_in_column" ,
text : ` x : {
shape : sql_table
x : { p - > q }
} ` ,
2023-02-17 01:44:54 +00:00
expErr : ` d2 / testdata / d2compiler / TestCompile / edge_in_column . d2 : 3 : 7 : sql_table columns cannot have children
d2 / testdata / d2compiler / TestCompile / edge_in_column . d2 : 3 : 12 : sql_table columns cannot have children ` ,
} ,
{
name : "no-nested-columns-sql" ,
text : ` x : {
shape : sql_table
a -- b . b
} ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no-nested-columns-sql.d2:3:10: sql_table columns cannot have children ` ,
} ,
{
name : "no-nested-columns-sql-2" ,
text : ` x : {
shape : sql_table
a
}
x . a . b ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.d2:5:5: sql_table columns cannot have children ` ,
} ,
{
name : "no-nested-columns-class" ,
text : ` x : {
shape : class
a . a
} ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no-nested-columns-class.d2:3:5: class fields cannot have children ` ,
2022-11-03 13:54:49 +00:00
} ,
2023-04-27 18:22:10 +00:00
{
name : "improper-class-ref" ,
text : ` myobj.class.style.stroke-dash: 3 ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/improper-class-ref.d2:1:7: "class" must be the last part of the key ` ,
} ,
{
name : "tail-style" ,
text : ` myobj.style: 3 ` ,
2023-05-16 17:45:35 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/tail-style.d2:1:7: "style" expected to be set to a map of key-values, or contain an additional keyword like "style.opacity: 0.4" ` ,
} ,
{
name : "tail-style-map" ,
text : ` myobj.style: { } ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/tail-style-map.d2:1:7: "style" expected to be set to a map of key-values, or contain an additional keyword like "style.opacity: 0.4" ` ,
2023-04-27 18:22:10 +00:00
} ,
{
name : "bad-style-nesting" ,
text : ` myobj.style.style.stroke-dash: 3 ` ,
expErr : ` d2/testdata/d2compiler/TestCompile/bad-style-nesting.d2:1:13: invalid style keyword: "style" ` ,
} ,
2022-11-03 13:54:49 +00:00
{
name : "edge_to_style" ,
text : ` x : { style . opacity : 0.4 }
y - > x . style
` ,
2023-01-28 01:19:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/edge_to_style.d2:2:8: reserved keywords are prohibited in edges ` ,
2022-11-03 13:54:49 +00:00
} ,
2023-06-01 06:04:09 +00:00
{
name : "keyword-container" ,
text : ` a . near . b
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/keyword-container.d2:1:3: "near" must be the last part of the key ` ,
} ,
2022-11-03 13:54:49 +00:00
{
name : "escaped_id" ,
text : ` b\nb ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
if len ( g . Objects ) != 1 {
t . Fatal ( g . Objects )
}
2022-12-05 21:46:42 +00:00
assert . String ( t , ` "b\nb" ` , g . Objects [ 0 ] . ID )
2022-12-01 19:32:57 +00:00
assert . String ( t , ` b
2023-04-14 03:04:55 +00:00
b ` , g . Objects [ 0 ] . Label . Value )
2022-11-03 13:54:49 +00:00
} ,
} ,
2022-12-05 19:40:21 +00:00
{
name : "unescaped_id_cr" ,
text : ` b\rb ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
if len ( g . Objects ) != 1 {
t . Fatal ( g . Objects )
}
2022-12-05 21:46:42 +00:00
assert . String ( t , "b\rb" , g . Objects [ 0 ] . ID )
2023-04-14 03:04:55 +00:00
assert . String ( t , "b\rb" , g . Objects [ 0 ] . Label . Value )
2022-12-05 19:40:21 +00:00
} ,
} ,
2022-11-03 13:54:49 +00:00
{
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 ) )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatal ( g . Objects [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
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 ) )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatal ( g . Objects [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
{
name : "table_style_map" ,
text : ` IUserProperties : {
shape : sql_table
GetType ( ) : string
style : {
opacity : 0.4
2023-01-24 06:45:21 +00:00
font - color : blue
2022-11-03 13:54:49 +00:00
}
}
` ,
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 ) )
}
2023-04-14 03:04:55 +00:00
if g . Objects [ 0 ] . Style . Opacity . Value != "0.4" {
t . Fatal ( g . Objects [ 0 ] . Style . Opacity . Value )
2022-11-03 13:54:49 +00:00
}
} ,
} ,
2023-01-13 16:21:32 +00:00
{
name : "table_connection_attr" ,
text : ` x : {
shape : sql_table
y
}
a : {
shape : sql_table
b
}
x . y - > a . b : {
style . animated : true
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "true" , g . Edges [ 0 ] . Style . Animated . Value )
2023-01-13 16:21:32 +00:00
} ,
} ,
2022-11-03 13:54:49 +00:00
{
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 )
}
2022-12-01 19:32:57 +00:00
assert . String ( t , ` field here ` , g . Objects [ 0 ] . Class . Fields [ 0 ] . Name )
assert . String ( t , ` GetType() ` , g . Objects [ 0 ] . Class . Methods [ 0 ] . Name )
assert . String ( t , ` Is() ` , g . Objects [ 0 ] . Class . Methods [ 1 ] . Name )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
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 )
}
2022-12-20 01:14:39 +00:00
assert . String ( t , ` GetType() ` , g . Objects [ 0 ] . SQLTable . Columns [ 0 ] . Name . Label )
assert . String ( t , ` Is() ` , g . Objects [ 0 ] . SQLTable . Columns [ 1 ] . Name . Label )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
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 )
}
2022-12-20 01:14:39 +00:00
assert . String ( t , ` GetType() ` , g . Objects [ 1 ] . SQLTable . Columns [ 0 ] . Name . Label )
assert . String ( t , ` Is() ` , g . Objects [ 1 ] . SQLTable . Columns [ 1 ] . Name . Label )
2022-11-03 13:54:49 +00:00
} ,
} ,
{
name : "3d_oval" ,
2023-01-24 06:45:21 +00:00
text : ` SVP1 . shape : oval
2022-11-03 13:54:49 +00:00
SVP1 . style .3 d : true ` ,
2023-02-25 03:16:30 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares, rectangles, and hexagons ` ,
2022-11-16 17:58:06 +00:00
} , {
name : "edge_column_index" ,
text : ` src : {
shape : sql_table
id : int
dst_id : int
}
dst : {
shape : sql_table
id : int
name : string
}
dst . id <- > src . dst_id
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2022-11-16 18:54:34 +00:00
srcIndex := g . Edges [ 0 ] . SrcTableColumnIndex
if srcIndex == nil || * srcIndex != 0 {
2022-11-16 19:15:14 +00:00
t . Fatalf ( "expected SrcTableColumnIndex to be 0, got %v" , srcIndex )
2022-11-16 17:58:06 +00:00
}
2022-11-16 18:54:34 +00:00
dstIndex := g . Edges [ 0 ] . DstTableColumnIndex
if dstIndex == nil || * dstIndex != 1 {
2022-11-16 19:15:14 +00:00
t . Fatalf ( "expected DstTableColumnIndex to be 1, got %v" , dstIndex )
2022-11-16 17:58:06 +00:00
}
} ,
2022-11-03 13:54:49 +00:00
} ,
2022-11-28 22:10:24 +00:00
{
name : "basic_sequence" ,
text : ` x : {
2022-11-28 22:21:50 +00:00
shape : sequence_diagram
2022-11-28 22:10:24 +00:00
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
assert . String ( t , "sequence_diagram" , g . Objects [ 0 ] . Shape . Value )
2022-11-28 22:10:24 +00:00
} ,
} ,
2023-02-25 03:05:23 +00:00
{
name : "near_sequence" ,
text : ` x : {
shape : sequence_diagram
a
}
b . near : x . a
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/near_sequence.d2:5:9: near keys cannot be set to an object within sequence diagrams ` ,
} ,
2023-02-22 21:21:29 +00:00
{
name : "sequence-timestamp" ,
text : ` shape : sequence_diagram
a
b
"04:20,11:20" : {
"loop through each table" : {
a . "start_time = datetime.datetime.now"
a - > b
}
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 1 , len ( g . Edges ) )
tassert . Equal ( t , 5 , len ( g . Objects ) )
tassert . Equal ( t , "a" , g . Objects [ 0 ] . ID )
tassert . Equal ( t , "b" , g . Objects [ 1 ] . ID )
tassert . Equal ( t , ` "04:20,11:20" ` , g . Objects [ 2 ] . ID )
tassert . Equal ( t , ` loop through each table ` , g . Objects [ 3 ] . ID )
tassert . Equal ( t , 1 , len ( g . Objects [ 0 ] . ChildrenArray ) )
tassert . Equal ( t , 0 , len ( g . Objects [ 1 ] . ChildrenArray ) )
tassert . Equal ( t , 1 , len ( g . Objects [ 2 ] . ChildrenArray ) )
tassert . True ( t , g . Edges [ 0 ] . ContainedBy ( g . Objects [ 3 ] ) )
} ,
} ,
2022-11-28 22:10:24 +00:00
{
name : "root_sequence" ,
2022-11-28 22:21:50 +00:00
text : ` shape : sequence_diagram
2022-11-28 22:10:24 +00:00
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
assert . String ( t , "sequence_diagram" , g . Root . Shape . Value )
2022-11-28 22:10:24 +00:00
} ,
} ,
2022-12-03 08:06:59 +00:00
{
name : "leaky_sequence" ,
text : ` x : {
shape : sequence_diagram
2022-12-06 03:50:08 +00:00
a
2022-12-03 08:06:59 +00:00
}
b - > x . a
` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/leaky_sequence.d2:5:1: connections within sequence diagrams can connect only to other objects within the same sequence diagram ` ,
2022-12-03 08:06:59 +00:00
} ,
2022-12-06 03:50:08 +00:00
{
name : "sequence_scoping" ,
text : ` x : {
shape : sequence_diagram
a ; b
group : {
a - > b
a . t1 - > b . t1
b . t1 . t2 - > b . t1
}
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 7 , len ( g . Objects ) )
tassert . Equal ( t , 3 , len ( g . Objects [ 0 ] . ChildrenArray ) )
} ,
} ,
{
name : "sequence_grouped_note" ,
text : ` shape : sequence_diagram
a ; d
choo : {
d . "this note"
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 4 , len ( g . Objects ) )
tassert . Equal ( t , 3 , len ( g . Root . ChildrenArray ) )
} ,
} ,
2022-11-29 05:39:36 +00:00
{
2023-01-24 11:09:40 +00:00
name : "sequence_container" ,
text : ` shape : sequence_diagram
x . y . q - > j . y . p
ok : {
x . y . q - > j . y . p
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 7 , len ( g . Objects ) )
tassert . Equal ( t , 3 , len ( g . Root . ChildrenArray ) )
} ,
} ,
{
name : "sequence_container_2" ,
text : ` shape : sequence_diagram
x . y . q
ok : {
x . y . q - > j . y . p
meow
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 8 , len ( g . Objects ) )
tassert . Equal ( t , 2 , len ( g . Root . ChildrenArray ) )
} ,
} ,
{
2022-11-30 00:02:37 +00:00
name : "root_direction" ,
2022-11-29 05:39:36 +00:00
2022-11-30 00:02:37 +00:00
text : ` direction: right ` ,
2022-11-29 05:39:36 +00:00
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
assert . String ( t , "right" , g . Root . Direction . Value )
2022-11-29 05:39:36 +00:00
} ,
} ,
2022-11-29 05:01:42 +00:00
{
2022-11-30 00:02:37 +00:00
name : "default_direction" ,
2022-11-29 05:01:42 +00:00
text : ` x ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
assert . String ( t , "" , g . Objects [ 0 ] . Direction . Value )
2022-11-29 05:01:42 +00:00
} ,
} ,
2022-11-29 05:39:36 +00:00
{
2022-11-30 00:02:37 +00:00
name : "set_direction" ,
2022-11-29 05:39:36 +00:00
text : ` x : {
2022-11-30 00:02:37 +00:00
direction : left
2022-11-29 05:39:36 +00:00
} ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
assert . String ( t , "left" , g . Objects [ 0 ] . Direction . Value )
2022-11-29 05:39:36 +00:00
} ,
} ,
2022-12-12 00:46:09 +00:00
{
name : "constraint_label" ,
text : ` foo {
label : bar
constraint : BIZ
} ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
assert . String ( t , "bar" , g . Objects [ 0 ] . Label . Value )
2022-12-12 00:46:09 +00:00
} ,
} ,
2022-11-29 05:39:36 +00:00
{
2022-11-30 00:02:37 +00:00
name : "invalid_direction" ,
2022-11-29 05:39:36 +00:00
text : ` x : {
2022-11-30 00:02:37 +00:00
direction : diagonal
2022-11-29 05:39:36 +00:00
} ` ,
2023-01-18 12:32:12 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/invalid_direction.d2:2:14: direction must be one of up, down, right, left, got "diagonal" ` ,
2022-11-29 05:39:36 +00:00
} ,
2022-11-30 01:54:25 +00:00
{
name : "self-referencing" ,
text : ` x - > x
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2022-12-03 03:55:49 +00:00
_ , err := diff . Strings ( g . Edges [ 0 ] . Dst . ID , g . Edges [ 0 ] . Src . ID )
if err != nil {
t . Fatal ( err )
}
2022-11-30 01:54:25 +00:00
} ,
} ,
2022-12-23 03:29:13 +00:00
{
name : "null" ,
text : ` null
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2022-12-26 19:18:09 +00:00
tassert . Equal ( t , "'null'" , g . Objects [ 0 ] . ID )
2022-12-23 03:29:13 +00:00
tassert . Equal ( t , "null" , g . Objects [ 0 ] . IDVal )
} ,
} ,
2022-12-23 05:20:18 +00:00
{
name : "sql-regression" ,
text : ` a : {
style : {
fill : lemonchiffon
}
2022-12-23 07:41:15 +00:00
b : {
2022-12-23 05:20:18 +00:00
shape : sql_table
2022-12-23 07:41:15 +00:00
c
2022-12-23 05:20:18 +00:00
}
2022-12-23 05:23:17 +00:00
d
2022-12-23 05:20:18 +00:00
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 3 , len ( g . Objects ) )
} ,
} ,
2022-12-24 21:11:45 +00:00
{
name : "sql-panic" ,
text : ` test {
shape : sql_table
test_id : varchar ( 64 ) { constraint : [ primary_key , foreign_key ] }
}
` ,
2023-01-24 05:48:43 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/sql-panic.d2:3:27: reserved field constraint does not accept composite ` ,
2022-12-24 21:11:45 +00:00
} ,
2023-01-06 19:03:39 +00:00
{
name : "wrong_column_index" ,
text : ` Chinchillas : {
shape : sql_table
id : int { constraint : primary_key }
whisker_len : int
fur_color : string
age : int
server : int { constraint : foreign_key }
caretaker : int { constraint : foreign_key }
}
Chinchillas_Collectibles : {
shape : sql_table
id : int
collectible : id { constraint : foreign_key }
chinchilla : id { constraint : foreign_key }
}
Chinchillas_Collectibles . chinchilla - > Chinchillas . id ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 0 , * g . Edges [ 0 ] . DstTableColumnIndex )
tassert . Equal ( t , 2 , * g . Edges [ 0 ] . SrcTableColumnIndex )
} ,
} ,
2023-02-05 18:36:38 +00:00
{
name : "link-board-ok" ,
text : ` x . link : layers . x
layers : {
2023-03-01 18:28:01 +00:00
x : {
y
}
2023-02-05 19:04:38 +00:00
} ` ,
2023-03-01 18:28:01 +00:00
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "root.layers.x" , g . Objects [ 0 ] . Link . Value )
2023-03-01 18:28:01 +00:00
} ,
2023-02-05 19:04:38 +00:00
} ,
{
name : "link-board-mixed" ,
text : ` question : How does the cat go ?
question . link : layers . cat
layers : {
cat : {
the cat - > meeeowwww : goes
}
}
scenarios : {
green : {
2023-03-03 01:56:32 +00:00
question . style . fill : green
2023-02-05 19:04:38 +00:00
}
2023-02-05 18:36:38 +00:00
} ` ,
2023-03-01 18:28:01 +00:00
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "root.layers.cat" , g . Objects [ 0 ] . Link . Value )
tassert . Equal ( t , "root.layers.cat" , g . Scenarios [ 0 ] . Objects [ 0 ] . Link . Value )
2023-03-01 18:28:01 +00:00
} ,
2023-02-05 18:36:38 +00:00
} ,
{
name : "link-board-not-found" ,
text : ` x . link : layers . x
` ,
2023-03-01 23:38:02 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/link-board-not-found.d2:1:1: linked board not found ` ,
2023-02-05 18:36:38 +00:00
} ,
{
name : "link-board-not-board" ,
text : ` zzz
x . link : layers . x . y
layers : {
2023-03-03 01:56:32 +00:00
x : {
2023-02-05 18:36:38 +00:00
y
}
} ` ,
2023-03-01 23:38:02 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/link-board-not-board.d2:2:1: linked board not found ` ,
2023-02-05 18:36:38 +00:00
} ,
{
name : "link-board-nested" ,
text : ` x . link : layers . x . layers . x
layers : {
2023-03-03 01:56:32 +00:00
x : {
2023-02-05 18:36:38 +00:00
layers : {
2023-03-03 01:56:32 +00:00
x : {
2023-03-01 18:28:01 +00:00
hello
2023-03-03 01:56:32 +00:00
}
2023-02-05 18:36:38 +00:00
}
}
} ` ,
2023-03-01 18:28:01 +00:00
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "root.layers.x.layers.x" , g . Objects [ 0 ] . Link . Value )
2023-03-01 22:53:58 +00:00
} ,
} ,
{
name : "link-board-key-nested" ,
text : ` x : {
y . link : layers . x
}
layers : {
2023-03-03 01:56:32 +00:00
x : {
2023-03-01 22:53:58 +00:00
yo
}
} ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "root.layers.x" , g . Objects [ 1 ] . Link . Value )
2023-03-01 18:28:01 +00:00
} ,
2023-02-05 18:36:38 +00:00
} ,
2023-03-01 19:27:18 +00:00
{
name : "link-board-underscore" ,
text : ` x
layers : {
x : {
yo
layers : {
2023-03-03 01:56:32 +00:00
x : {
hello . link : _ . _ . layers . x
hey . link : _
}
2023-03-01 19:27:18 +00:00
}
}
} ` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . NotNil ( t , g . Layers [ 0 ] . Layers [ 0 ] . Objects [ 0 ] . Link . Value )
tassert . Equal ( t , "root.layers.x" , g . Layers [ 0 ] . Layers [ 0 ] . Objects [ 0 ] . Link . Value )
tassert . Equal ( t , "root.layers.x" , g . Layers [ 0 ] . Layers [ 0 ] . Objects [ 1 ] . Link . Value )
2023-03-01 19:27:18 +00:00
} ,
} ,
{
name : "link-board-underscore-not-found" ,
text : ` x
layers : {
2023-03-03 01:56:32 +00:00
x : {
yo
2023-03-01 19:27:18 +00:00
layers : {
2023-03-03 01:56:32 +00:00
x : {
hello . link : _ . _ . _
}
2023-03-01 19:27:18 +00:00
}
}
} ` ,
2023-03-03 01:56:32 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/link-board-underscore-not-found.d2:7:9: invalid underscore usage ` ,
2023-03-01 19:27:18 +00:00
} ,
2023-03-30 16:43:16 +00:00
{
name : "border-radius-negative" ,
text : ` x
x : {
style . border - radius : - 1
} ` ,
2023-04-13 16:18:28 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/border-radius-negative.d2:3:24: expected "border-radius" to be a number greater or equal to 0 ` ,
2023-03-30 16:43:16 +00:00
} ,
2023-04-08 19:24:29 +00:00
{
name : "text-transform" ,
text : ` direction : right
x - > y : hi {
style : {
text - transform : capitalize
}
}
x . style . text - transform : uppercase
y . style . text - transform : lowercase ` ,
} ,
2023-03-28 18:37:40 +00:00
{
name : "near_near_const" ,
text : `
title : Title {
near : top - center
}
obj {
near : title
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/near_near_const.d2:7:8: near keys cannot be set to an object with a constant near key ` ,
} ,
2023-04-01 00:18:17 +00:00
{
name : "grid" ,
text : ` hey : {
2023-04-06 22:43:03 +00:00
grid - rows : 200
grid - columns : 230
2023-04-01 00:18:17 +00:00
}
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "200" , g . Objects [ 0 ] . GridRows . Value )
2023-04-01 00:18:17 +00:00
} ,
} ,
{
name : "grid_negative" ,
text : ` hey : {
2023-04-06 22:43:03 +00:00
grid - rows : 200
grid - columns : - 200
2023-04-01 00:18:17 +00:00
}
` ,
2023-04-06 22:43:03 +00:00
expErr : ` d2/testdata/d2compiler/TestCompile/grid_negative.d2:3:16: grid-columns must be a positive integer: "-200" ` ,
2023-04-01 00:18:17 +00:00
} ,
2023-04-11 01:21:26 +00:00
{
name : "grid_gap_negative" ,
text : ` hey : {
2023-04-12 20:48:53 +00:00
horizontal - gap : - 200
vertical - gap : - 30
2023-04-11 01:21:26 +00:00
}
` ,
2023-04-12 20:48:53 +00:00
expErr : ` d2 / testdata / d2compiler / TestCompile / grid_gap_negative . d2 : 2 : 18 : horizontal - gap must be a non - negative integer : "-200"
d2 / testdata / d2compiler / TestCompile / grid_gap_negative . d2 : 3 : 16 : vertical - gap must be a non - negative integer : "-30" ` ,
2023-04-11 01:21:26 +00:00
} ,
2023-04-05 00:44:05 +00:00
{
name : "grid_edge" ,
text : ` hey : {
2023-04-06 22:43:03 +00:00
grid - rows : 1
2023-04-05 00:44:05 +00:00
a - > b
}
c - > hey . b
hey . a - > c
hey - > c : ok
` ,
2023-04-06 22:32:09 +00:00
expErr : ` d2 / testdata / d2compiler / TestCompile / grid_edge . d2 : 3 : 2 : edges in grid diagrams are not supported yet
d2 / testdata / d2compiler / TestCompile / grid_edge . d2 : 5 : 2 : edges in grid diagrams are not supported yet
d2 / testdata / d2compiler / TestCompile / grid_edge . d2 : 6 : 2 : edges in grid diagrams are not supported yet ` ,
2023-04-05 00:44:05 +00:00
} ,
2023-04-05 04:00:40 +00:00
{
name : "grid_nested" ,
text : ` hey : {
2023-04-06 22:43:03 +00:00
grid - rows : 200
grid - columns : 200
2023-04-05 04:00:40 +00:00
a
b
c
2023-05-09 01:41:47 +00:00
d . valid descendant
e : {
grid - rows : 1
grid - columns : 2
a
b
}
2023-04-05 04:00:40 +00:00
}
` ,
2023-05-09 01:41:47 +00:00
expErr : ` ` ,
2023-04-05 04:00:40 +00:00
} ,
2023-02-06 21:32:08 +00:00
{
name : "classes" ,
text : ` classes : {
dragon_ball : {
label : ""
shape : circle
style . fill : orange
}
path : {
label : "then"
style . stroke - width : 4
}
}
nostar : { class : dragon_ball }
1 star : "*" { class : dragon_ball ; style . fill : red }
2 star : { label : "**" ; class : dragon_ball }
nostar - > 1 star : { class : path }
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 3 , len ( g . Objects ) )
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "dragon_ball" , g . Objects [ 0 ] . Classes [ 0 ] )
tassert . Equal ( t , "" , g . Objects [ 0 ] . Label . Value )
2023-02-06 21:32:08 +00:00
// Class field overrides primary
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "" , g . Objects [ 1 ] . Label . Value )
tassert . Equal ( t , "**" , g . Objects [ 2 ] . Label . Value )
tassert . Equal ( t , "orange" , g . Objects [ 0 ] . Style . Fill . Value )
tassert . Equal ( t , "red" , g . Objects [ 1 ] . Style . Fill . Value )
2023-02-06 21:32:08 +00:00
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "4" , g . Edges [ 0 ] . Style . StrokeWidth . Value )
tassert . Equal ( t , "then" , g . Edges [ 0 ] . Label . Value )
2023-04-27 22:09:43 +00:00
} ,
} ,
{
name : "array-classes" ,
text : ` classes : {
dragon_ball : {
label : ""
shape : circle
style . fill : orange
}
path : {
label : "then"
style . stroke - width : 4
}
path2 : {
style . stroke - width : 2
}
}
nostar : { class : [ dragon_ball ; path ] }
1 star : { class : [ path ; dragon_ball ] }
nostar - > 1 star : { class : [ path ; path2 ] }
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , "then" , g . Objects [ 0 ] . Label . Value )
tassert . Equal ( t , "" , g . Objects [ 1 ] . Label . Value )
tassert . Equal ( t , "circle" , g . Objects [ 0 ] . Shape . Value )
tassert . Equal ( t , "circle" , g . Objects [ 1 ] . Shape . Value )
tassert . Equal ( t , "2" , g . Edges [ 0 ] . Style . StrokeWidth . Value )
2023-02-06 21:32:08 +00:00
} ,
} ,
{
name : "reordered-classes" ,
text : ` classes : {
x : {
shape : circle
}
}
a . class : x
classes . x . shape : diamond
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
tassert . Equal ( t , 1 , len ( g . Objects ) )
2023-04-14 03:04:55 +00:00
tassert . Equal ( t , "diamond" , g . Objects [ 0 ] . Shape . Value )
2023-02-06 21:32:08 +00:00
} ,
} ,
2023-06-02 00:11:11 +00:00
{
name : "nested-array-classes" ,
text : ` classes : {
one target : {
target - arrowhead . label : 1
}
association : {
target - arrowhead . shape : arrow
}
}
a - > b : { class : [ one target ; association ] }
a - > b : { class : [ association ; one target ] }
` ,
assertions : func ( t * testing . T , g * d2graph . Graph ) {
// They have the same, regardless of order of class application
// since the classes modify attributes exclusive of each other
tassert . Equal ( t , "1" , g . Edges [ 0 ] . DstArrowhead . Label . Value )
tassert . Equal ( t , "1" , g . Edges [ 1 ] . DstArrowhead . Label . Value )
tassert . Equal ( t , "arrow" , g . Edges [ 0 ] . DstArrowhead . Shape . Value )
tassert . Equal ( t , "arrow" , g . Edges [ 1 ] . DstArrowhead . Shape . Value )
} ,
} ,
2023-04-26 19:38:41 +00:00
{
name : "class-shape-class" ,
text : ` classes : {
classClass : {
shape : class
}
}
object : {
class : classClass
length ( ) : int
}
` ,
} ,
2023-02-06 21:32:08 +00:00
{
name : "no-class-primary" ,
text : ` x . class
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no-class-primary.d2:1:3: class missing value ` ,
} ,
{
name : "no-class-inside-classes" ,
text : ` classes : {
x : {
class : y
}
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/no-class-inside-classes.d2:3:5: "class" cannot appear within "classes" ` ,
} ,
{
// This is okay
name : "missing-class" ,
text : ` x . class : yo
` ,
} ,
{
name : "classes-unreserved" ,
text : ` classes : {
mango : {
seed
}
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/classes-unreserved.d2:3:5: seed is an invalid class field, must be reserved keyword ` ,
} ,
{
name : "classes-internal-edge" ,
text : ` classes : {
mango : {
width : 100
}
jango : {
height : 100
}
mango - > jango
}
` ,
expErr : ` d2/testdata/d2compiler/TestCompile/classes-internal-edge.d2:8:3: classes cannot contain an edge ` ,
} ,
2022-11-03 13:54:49 +00:00
}
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 ,
}
2022-12-01 19:32:57 +00:00
err = diff . TestdataJSON ( filepath . Join ( ".." , "testdata" , "d2compiler" , t . Name ( ) ) , got )
assert . Success ( t , err )
2022-11-03 13:54:49 +00:00
} )
}
}
2023-01-04 01:50:27 +00:00
func TestCompile2 ( t * testing . T ) {
t . Parallel ( )
2023-01-28 01:19:12 +00:00
t . Run ( "boards" , testBoards )
2023-02-02 18:30:54 +00:00
t . Run ( "seqdiagrams" , testSeqDiagrams )
2023-01-04 01:50:27 +00:00
}
2023-01-28 01:19:12 +00:00
func testBoards ( t * testing . T ) {
2023-01-04 01:50:27 +00:00
t . Parallel ( )
tca := [ ] struct {
name string
run func ( t * testing . T )
} {
{
2023-01-24 05:48:43 +00:00
name : "root" ,
2023-01-04 01:50:27 +00:00
run : func ( t * testing . T ) {
g := assertCompile ( t , ` base
layers : {
one : {
santa
}
two : {
clause
}
}
` , "" )
2023-02-27 21:34:03 +00:00
assert . Equal ( t , 2 , len ( g . Layers ) )
assert . Equal ( t , "one" , g . Layers [ 0 ] . Name )
assert . Equal ( t , "two" , g . Layers [ 1 ] . Name )
2023-01-04 01:50:27 +00:00
} ,
} ,
2023-01-24 05:48:43 +00:00
{
name : "recursive" ,
run : func ( t * testing . T ) {
g := assertCompile ( t , ` base
layers : {
one : {
santa
}
two : {
clause
steps : {
seinfeld : {
reindeer
}
missoula : {
montana
}
}
}
}
` , "" )
assert . Equal ( t , 2 , len ( g . Layers ) )
assert . Equal ( t , "one" , g . Layers [ 0 ] . Name )
assert . Equal ( t , "two" , g . Layers [ 1 ] . Name )
assert . Equal ( t , 2 , len ( g . Layers [ 1 ] . Steps ) )
} ,
} ,
2023-02-27 21:34:03 +00:00
{
2023-02-27 22:33:33 +00:00
name : "isFolderOnly" ,
2023-02-27 21:34:03 +00:00
run : func ( t * testing . T ) {
g := assertCompile ( t , `
layers : {
one : {
santa
}
two : {
clause
scenarios : {
seinfeld : {
}
missoula : {
steps : {
missus : one two three
}
}
}
}
}
` , "" )
2023-02-27 22:33:33 +00:00
assert . True ( t , g . IsFolderOnly )
2023-02-27 21:34:03 +00:00
assert . Equal ( t , 2 , len ( g . Layers ) )
assert . Equal ( t , "one" , g . Layers [ 0 ] . Name )
assert . Equal ( t , "two" , g . Layers [ 1 ] . Name )
assert . Equal ( t , 2 , len ( g . Layers [ 1 ] . Scenarios ) )
2023-02-27 22:33:33 +00:00
assert . False ( t , g . Layers [ 1 ] . Scenarios [ 0 ] . IsFolderOnly )
assert . False ( t , g . Layers [ 1 ] . Scenarios [ 1 ] . IsFolderOnly )
2023-02-27 21:34:03 +00:00
} ,
} ,
2023-03-25 19:06:06 +00:00
{
name : "scenarios_edge_index" ,
run : func ( t * testing . T ) {
assertCompile ( t , ` a - > x
scenarios : {
1 : {
( a - > x ) [ 0 ] . style . opacity : 0.1
}
}
` , "" )
} ,
} ,
2023-01-27 18:41:25 +00:00
{
2023-01-28 01:19:12 +00:00
name : "errs/duplicate_board" ,
2023-01-27 18:41:25 +00:00
run : func ( t * testing . T ) {
assertCompile ( t , ` base
layers : {
one : {
santa
}
}
steps : {
one : {
clause
}
}
2023-01-28 01:19:12 +00:00
` , ` d2 / testdata / d2compiler / TestCompile2 / boards / errs / duplicate_board . d2 : 9 : 2 : board name one already used by another board ` )
2023-01-27 18:41:25 +00:00
} ,
} ,
2023-01-04 01:50:27 +00:00
}
for _ , tc := range tca {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
tc . run ( t )
} )
}
}
2023-02-02 18:30:54 +00:00
func testSeqDiagrams ( t * testing . T ) {
t . Parallel ( )
t . Run ( "errs" , func ( t * testing . T ) {
t . Parallel ( )
tca := [ ] struct {
name string
skip bool
run func ( t * testing . T )
} {
{
name : "sequence_diagram_edge_between_edge_groups" ,
// New sequence diagram scoping implementation is disabled.
skip : true ,
run : func ( t * testing . T ) {
assertCompile ( t , `
Office chatter : {
shape : sequence_diagram
alice : Alice
bob : Bobby
awkward small talk : {
alice - > bob : uhm , hi
bob - > alice : oh , hello
icebreaker attempt : {
alice - > bob : what did you have for lunch ?
}
unfortunate outcome : {
bob - > alice : that ' s personal
}
}
awkward small talk . icebreaker attempt . alice - > awkward small talk . unfortunate outcome . bob
}
` , "d2/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.d2:16:3: edges between edge groups are not allowed" )
} ,
} ,
}
for _ , tc := range tca {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
if tc . skip {
t . SkipNow ( )
}
tc . run ( t )
} )
}
} )
}
2023-01-04 01:50:27 +00:00
func assertCompile ( t * testing . T , text string , expErr string ) * d2graph . Graph {
d2Path := fmt . Sprintf ( "d2/testdata/d2compiler/%v.d2" , t . Name ( ) )
g , err := d2compiler . Compile ( d2Path , strings . NewReader ( text ) , nil )
if expErr != "" {
assert . Error ( t , err )
assert . ErrorString ( t , err , expErr )
} else {
assert . Success ( t , err )
}
got := struct {
Graph * d2graph . Graph ` json:"graph" `
Err error ` json:"err" `
} {
Graph : g ,
Err : err ,
}
err = diff . TestdataJSON ( filepath . Join ( ".." , "testdata" , "d2compiler" , t . Name ( ) ) , got )
assert . Success ( t , err )
return g
}