d2/d2exporter/export_test.go
Anmol Sethi c4ef432daf
Move textmeasure into lib
It's not a d2renderer.
2022-12-01 06:51:17 -08:00

259 lines
4.7 KiB
Go

package d2exporter_test
import (
"context"
"path/filepath"
"strings"
"testing"
"cdr.dev/slog"
"oss.terrastruct.com/diff"
"github.com/stretchr/testify/assert"
"oss.terrastruct.com/d2/d2compiler"
"oss.terrastruct.com/d2/d2exporter"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/log"
"oss.terrastruct.com/d2/lib/textmeasure"
)
type testCase struct {
name string
dsl string
themeID int64
assertions func(t *testing.T, d *d2target.Diagram)
}
func TestExport(t *testing.T) {
t.Parallel()
t.Run("shape", testShape)
t.Run("connection", testConnection)
t.Run("label", testLabel)
t.Run("theme", testTheme)
}
func testShape(t *testing.T) {
tcs := []testCase{
{
name: "basic",
dsl: `x
`,
},
{
name: "synonyms",
dsl: `x: {shape: circle}
y: {shape: square}
`,
},
{
name: "text_color",
dsl: `x: |md yo | { style.font-color: red }
`,
},
{
name: "border-radius",
dsl: `Square: "" { style.border-radius: 5 }
`,
},
{
name: "image_dimensions",
dsl: `hey: "" {
icon: https://icons.terrastruct.com/essentials/004-picture.svg
shape: image
width: 200
height: 230
}
`,
assertions: func(t *testing.T, d *d2target.Diagram) {
if d.Shapes[0].Width != 200 {
t.Fatalf("expected width 200, got %v", d.Shapes[0].Width)
}
if d.Shapes[0].Height != 230 {
t.Fatalf("expected height 230, got %v", d.Shapes[0].Height)
}
},
},
}
runa(t, tcs)
}
func testConnection(t *testing.T) {
tcs := []testCase{
{
name: "basic",
dsl: `x -> y
`,
},
{
name: "stroke-dash",
dsl: `x -> y: { style.stroke-dash: 4 }
`,
},
{
name: "arrowhead",
dsl: `x -> y: {
source-arrowhead: If you've done six impossible things before breakfast, why not round it
target-arrowhead: {
label: A man with one watch knows what time it is.
shape: diamond
style.filled: true
}
}
`,
},
{
// This is a regression test where a connection with stroke-dash of 0 on terrastruct flagship theme would have a diff color
// than a connection without stroke dash
themeID: d2themescatalog.FlagshipTerrastruct.ID,
name: "theme_stroke-dash",
dsl: `x -> y: { style.stroke-dash: 0 }
x -> y
`,
},
}
runa(t, tcs)
}
func testLabel(t *testing.T) {
tcs := []testCase{
{
name: "basic_shape",
dsl: `x: yo
`,
},
{
name: "shape_font_color",
dsl: `x: yo { style.font-color: red }
`,
},
{
name: "connection_font_color",
dsl: `x -> y: yo { style.font-color: red }
`,
},
}
runa(t, tcs)
}
func testTheme(t *testing.T) {
tcs := []testCase{
{
name: "shape_without_bold",
themeID: d2themescatalog.FlagshipTerrastruct.ID,
dsl: `x: {
style.bold: false
}
`,
},
{
name: "shape_with_italic",
themeID: d2themescatalog.FlagshipTerrastruct.ID,
dsl: `x: {
style.italic: true
}
`,
},
{
name: "connection_without_italic",
dsl: `x -> y: asdf { style.italic: false }
`,
themeID: d2themescatalog.FlagshipTerrastruct.ID,
},
{
name: "connection_with_italic",
dsl: `x -> y: asdf {
style.italic: true
}
`,
themeID: d2themescatalog.FlagshipTerrastruct.ID,
},
{
name: "connection_with_bold",
dsl: `x -> y: asdf {
style.bold: true
}
`,
themeID: d2themescatalog.FlagshipTerrastruct.ID,
},
}
runa(t, tcs)
}
func runa(t *testing.T, tcs []testCase) {
for _, tc := range tcs {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
run(t, tc)
})
}
}
func run(t *testing.T, tc testCase) {
ctx := context.Background()
ctx = log.WithTB(ctx, t, nil)
ctx = log.Leveled(ctx, slog.LevelDebug)
g, err := d2compiler.Compile("", strings.NewReader(tc.dsl), &d2compiler.CompileOptions{
UTF16: true,
})
if err != nil {
t.Fatal(err)
}
ruler, err := textmeasure.NewRuler()
assert.Nil(t, err)
err = g.SetDimensions(nil, ruler)
assert.Nil(t, err)
err = d2dagrelayout.Layout(ctx, g)
if err != nil {
t.Fatal(err)
}
got, err := d2exporter.Export(ctx, g, tc.themeID)
if err != nil {
t.Fatal(err)
}
if tc.assertions != nil {
t.Run("assertions", func(t *testing.T) {
tc.assertions(t, got)
})
}
// This test is agnostic of layout changes
for i := range got.Shapes {
got.Shapes[i].Pos = d2target.Point{}
got.Shapes[i].Width = 0
got.Shapes[i].Height = 0
got.Shapes[i].LabelWidth = 0
got.Shapes[i].LabelHeight = 0
got.Shapes[i].LabelPosition = ""
}
for i := range got.Connections {
got.Connections[i].Route = []*geo.Point{}
got.Connections[i].LabelWidth = 0
got.Connections[i].LabelHeight = 0
got.Connections[i].LabelPosition = ""
}
err = diff.Testdata(filepath.Join("..", "testdata", "d2exporter", t.Name()), got)
if err != nil {
t.Fatal(err)
}
}