d2/d2format/format_test.go
2022-12-01 11:48:49 -08:00

626 lines
11 KiB
Go

package d2format_test
import (
"fmt"
"strings"
"testing"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/d2/d2format"
"oss.terrastruct.com/d2/d2parser"
)
func TestPrint(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
in string
exp string
}{
{
name: "basic",
in: `
x -> y
`,
exp: `x -> y
`,
},
{
name: "complex",
in: `
sql_example : sql_example {
board : {
shape: sql_table
id: int {constraint: primary_key}
frame: int {constraint: foreign_key}
diagram: int {constraint: foreign_key}
board_objects: jsonb
last_updated: timestamp with time zone
last_thumbgen: timestamp with time zone
dsl : text
}
# Normal.
board.diagram -> diagrams.id
# Self referential.
diagrams.id -> diagrams.representation
# SrcArrow test.
diagrams.id <- views . diagram
diagrams.id <-> steps . diagram
diagrams: {
shape: sql_table
id: {type: int ; constraint: primary_key}
representation: {type: jsonb}
}
views: {
shape: sql_table
id: {type: int; constraint: primary_key}
representation: {type: jsonb}
diagram: int {constraint: foreign_key}
}
steps: {
shape: sql_table
id: { type: int; constraint: primary_key }
representation: { type: jsonb }
diagram: int {constraint: foreign_key}
}
meow <- diagrams.id
}
D2 AST Parser {
shape: class
+prevRune : rune
prevColumn : int
+eatSpace(eatNewlines bool): (rune, error)
unreadRune()
\#scanKey(r rune): (k Key, _ error)
}
"""dmaskkldsamkld """
"""
dmaskdmasl
mdlkasdaskml
daklsmdakms
"""
bs: |
dmasmdkals
dkmsamdklsa
|
bs2: | mdsalldkams|
y-->q: meow
x->y->z
meow: {
x: |` + "`" + `
meow
meow
` + "`" + `| {
}
}
"meow\t": ok
`,
exp: `sql_example: sql_example {
board: {
shape: sql_table
id: int {constraint: primary_key}
frame: int {constraint: foreign_key}
diagram: int {constraint: foreign_key}
board_objects: jsonb
last_updated: timestamp with time zone
last_thumbgen: timestamp with time zone
dsl: text
}
# Normal.
board.diagram -> diagrams.id
# Self referential.
diagrams.id -> diagrams.representation
# SrcArrow test.
diagrams.id <- views.diagram
diagrams.id <-> steps.diagram
diagrams: {
shape: sql_table
id: {type: int; constraint: primary_key}
representation: {type: jsonb}
}
views: {
shape: sql_table
id: {type: int; constraint: primary_key}
representation: {type: jsonb}
diagram: int {constraint: foreign_key}
}
steps: {
shape: sql_table
id: {type: int; constraint: primary_key}
representation: {type: jsonb}
diagram: int {constraint: foreign_key}
}
meow <- diagrams.id
}
D2 AST Parser: {
shape: class
+prevRune: rune
prevColumn: int
+eatSpace(eatNewlines bool): (rune, error)
unreadRune()
\#scanKey(r rune): (k Key, _ error)
}
""" dmaskkldsamkld """
"""
dmaskdmasl
mdlkasdaskml
daklsmdakms
"""
bs: |md
dmasmdkals
dkmsamdklsa
|
bs2: |md mdsalldkams |
y -> q: meow
x -> y -> z
meow: {
x: |` + "`" + `md
meow
meow
` + "`" + `|
}
"meow\t": ok
`,
},
{
name: "block_comment",
in: `
"""
D2 AST Parser2: {
shape: class
reader: io.RuneReader
readerPos: d2ast.Position
lookahead: "[]rune"
lookaheadPos: d2ast.Position
peek() (r rune, eof bool)
-rewind(): ()
+commit()
\#peekn(n int) (s string, eof bool)
}
"""
`,
exp: `"""
D2 AST Parser2: {
shape: class
reader: io.RuneReader
readerPos: d2ast.Position
lookahead: "[]rune"
lookaheadPos: d2ast.Position
peek() (r rune, eof bool)
-rewind(): ()
+commit()
\#peekn(n int) (s string, eof bool)
}
"""
`,
},
{
name: "block_string_indent",
in: `
parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|}`,
exp: `parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|
}
`,
},
{
// This one we test that the common indent is stripped before the correct indent is
// applied.
name: "block_string_indent_2",
in: `
parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|}`,
exp: `parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|
}
`,
},
{
// This one we test that the common indent is stripped before the correct indent is
// applied even when there's too much indent.
name: "block_string_indent_3",
in: `
parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|}`,
exp: `parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|
}
`,
},
{
// This one has 3 space indent and whitespace only lines.
name: "block_string_uneven_indent",
in: `
parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|}`,
exp: `parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
` + "`" + `|
}
`,
},
{
// This one has 3 space indent and large whitespace only lines.
name: "block_string_uneven_indent_2",
in: `
parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
` + "`" + `|}`,
exp: `parent: {
example_code: |` + "`" + `go
package fs
type FS interface {
Open(name string) (File, error)
}
` + "`" + `|
}
`,
},
{
name: "block_comment_indent",
in: `
parent: {
"""
hello
""" }`,
exp: `parent: {
"""
hello
"""
}
`,
},
{
name: "scalars",
in: `x: null
y: true
z: 343`,
exp: `x: null
y: true
z: 343
`,
},
{
name: "substitution",
in: `x: ${ok}; y: [...${yes}]`,
exp: `x: ${ok}; y: [...${yes}]
`,
},
{
name: "line_comment_block",
in: `# wsup
# hello
# The Least Successful Collector`,
exp: `# wsup
# hello
# The Least Successful Collector
`,
},
{
name: "inline_comment",
in: `hello: x # soldier
more`,
exp: `hello: x # soldier
more
`,
},
{
name: "array_one_line",
in: `a: [1;2;3;4]`,
exp: `a: [1; 2; 3; 4]
`,
},
{
name: "array",
in: `a: [
hi # Fraud is the homage that force pays to reason.
1
2
3
4
5; 6; 7
]`,
exp: `a: [
hi # Fraud is the homage that force pays to reason.
1
2
3
4
5
6
7
]
`,
},
{
name: "ampersand",
in: `&scenario: red`,
exp: `&scenario: red
`,
},
{
name: "complex_edge",
in: `pre.(src -> dst -> more)[3].post`,
exp: `pre.(src -> dst -> more)[3].post
`,
},
{
name: "edge_index_glob",
in: `(x -> y)[*]`,
exp: `(x -> y)[*]
`,
},
{
name: "bidirectional",
in: `x<>y`,
exp: `x <-> y
`,
},
{
name: "empty_map",
in: `x: {}
`,
exp: `x
`,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
ast, err := d2parser.Parse(fmt.Sprintf("%s.d2", t.Name()), strings.NewReader(tc.in), nil)
if err != nil {
t.Fatal(err)
}
assert.String(t, tc.exp, d2format.Format(ast))
})
}
}
func TestEdge(t *testing.T) {
t.Parallel()
mk, err := d2parser.ParseMapKey(`(x -> y)[0]`)
if err != nil {
t.Fatal(err)
}
if len(mk.Edges) != 1 {
t.Fatalf("expected one edge: %#v", mk.Edges)
}
assert.String(t, `x -> y`, d2format.Format(mk.Edges[0]))
assert.String(t, `[0]`, d2format.Format(mk.EdgeIndex))
}