Files
dingtalk-workspace-cli/internal/helpers/doc_jsonml_fragment_strip_test.go

312 lines
9.0 KiB
Go

package helpers
import (
"io"
"os"
"reflect"
"strings"
"testing"
)
func captureDocFragmentStderr(t *testing.T, run func()) string {
t.Helper()
reader, writer, err := os.Pipe()
if err != nil {
t.Fatalf("create stderr pipe: %v", err)
}
previous := os.Stderr
os.Stderr = writer
defer func() {
os.Stderr = previous
_ = writer.Close()
_ = reader.Close()
}()
run()
if err := writer.Close(); err != nil {
t.Fatalf("close stderr writer: %v", err)
}
os.Stderr = previous
output, err := io.ReadAll(reader)
if err != nil {
t.Fatalf("read stderr: %v", err)
}
return string(output)
}
func TestCrossPlatformCoverageJSONMLFragmentStripHelpers(t *testing.T) {
t.Run("child start", func(t *testing.T) {
tests := []struct {
name string
node []any
want int
}{
{name: "empty", node: nil, want: 1},
{name: "tag only", node: []any{"p"}, want: 1},
{name: "first child", node: []any{"p", "text"}, want: 1},
{name: "attributes", node: []any{"p", map[string]any{}}, want: 2},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := jsonmlChildStart(tt.node); got != tt.want {
t.Fatalf("jsonmlChildStart(%#v) = %d, want %d", tt.node, got, tt.want)
}
})
}
})
t.Run("children recursively splice fragments", func(t *testing.T) {
children := []any{
"text",
[]any{},
[]any{
"fragment",
map[string]any{"source": "range"},
[]any{"p", map[string]any{}},
[]any{"fragment", []any{"h1", map[string]any{}}},
},
[]any{
"div",
map[string]any{},
[]any{"fragment", map[string]any{}, []any{"span", map[string]any{}, "inside"}},
},
}
got, count := stripFragmentChildren(children)
want := []any{
"text",
[]any{},
[]any{"p", map[string]any{}},
[]any{"h1", map[string]any{}},
[]any{"div", map[string]any{}, []any{"span", map[string]any{}, "inside"}},
}
if count != 3 || !reflect.DeepEqual(got, want) {
t.Fatalf("stripFragmentChildren() = %#v, %d; want %#v, 3", got, count, want)
}
})
t.Run("ordinary children are unchanged", func(t *testing.T) {
children := []any{"text", []any{"p", map[string]any{}, "body"}}
got, count := stripFragmentChildren(children)
if count != 0 || !reflect.DeepEqual(got, children) {
t.Fatalf("stripFragmentChildren() = %#v, %d", got, count)
}
})
t.Run("node branches", func(t *testing.T) {
leaf := []any{"p", map[string]any{}}
got, count := stripFragmentInNode(leaf)
if count != 0 || !reflect.DeepEqual(got, leaf) {
t.Fatalf("leaf = %#v, %d", got, count)
}
ordinary := []any{"p", map[string]any{}, []any{"span", map[string]any{}, "body"}}
got, count = stripFragmentInNode(ordinary)
if count != 0 || !reflect.DeepEqual(got, ordinary) {
t.Fatalf("ordinary = %#v, %d", got, count)
}
nested := []any{"p", map[string]any{}, []any{"fragment", map[string]any{}, []any{"span", map[string]any{}, "body"}}}
got, count = stripFragmentInNode(nested)
want := []any{"p", map[string]any{}, []any{"span", map[string]any{}, "body"}}
if count != 1 || !reflect.DeepEqual(got, want) {
t.Fatalf("nested = %#v, %d; want %#v, 1", got, count, want)
}
})
t.Run("body branches", func(t *testing.T) {
if got, count := stripBodyFragments(nil); got != nil || count != 0 {
t.Fatalf("empty body = %#v, %d", got, count)
}
ordinary := []any{"root", map[string]any{}, []any{"p", map[string]any{}}}
got, count := stripBodyFragments(ordinary)
if count != 0 || !reflect.DeepEqual(got, ordinary) {
t.Fatalf("ordinary body = %#v, %d", got, count)
}
top := []any{
"fragment",
map[string]any{"source": "outline"},
[]any{"fragment", map[string]any{}, []any{"h1", map[string]any{}}},
}
got, count = stripBodyFragments(top)
want := []any{"root", map[string]any{}, []any{"h1", map[string]any{}}}
if count != 2 || !reflect.DeepEqual(got, want) {
t.Fatalf("top fragment body = %#v, %d; want %#v, 2", got, count, want)
}
})
t.Run("single node branches", func(t *testing.T) {
if got, count, err := stripNodeFragments(nil); err != nil || got != nil || count != 0 {
t.Fatalf("empty node = %#v, %d, %v", got, count, err)
}
ordinary := []any{"p", map[string]any{}, "body"}
got, count, err := stripNodeFragments(ordinary)
if err != nil || count != 0 || !reflect.DeepEqual(got, ordinary) {
t.Fatalf("ordinary node = %#v, %d, %v", got, count, err)
}
nested := []any{"p", map[string]any{}, []any{"fragment", map[string]any{}, []any{"span", map[string]any{}, "body"}}}
got, count, err = stripNodeFragments(nested)
want := []any{"p", map[string]any{}, []any{"span", map[string]any{}, "body"}}
if err != nil || count != 1 || !reflect.DeepEqual(got, want) {
t.Fatalf("nested node = %#v, %d, %v; want %#v", got, count, err, want)
}
top := []any{
"fragment",
map[string]any{"source": "section"},
[]any{"fragment", map[string]any{}, []any{"p", map[string]any{}, "body"}},
}
got, count, err = stripNodeFragments(top)
want = []any{"p", map[string]any{}, "body"}
if err != nil || count != 2 || !reflect.DeepEqual(got, want) {
t.Fatalf("top node = %#v, %d, %v; want %#v", got, count, err, want)
}
})
t.Run("single node top fragment errors", func(t *testing.T) {
tests := []struct {
name string
node []any
want string
}{
{
name: "empty",
node: []any{"fragment", map[string]any{}},
want: "无可写回的节点",
},
{
name: "non node child",
node: []any{"fragment", map[string]any{}, "text"},
want: "子节点不是合法 JSONML 节点",
},
{
name: "multiple nodes",
node: []any{"fragment", map[string]any{}, []any{"p", map[string]any{}}, []any{"p", map[string]any{}}},
want: "一次只能写一个",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, count, err := stripNodeFragments(tt.node)
if err == nil || !strings.Contains(err.Error(), tt.want) {
t.Fatalf("result = %#v, %d, %v; want error containing %q", got, count, err, tt.want)
}
})
}
})
}
func TestCrossPlatformCoveragePrepareJSONMLStripsReadOnlyFragments(t *testing.T) {
strict := jsonMLTestCommand(t, false)
t.Run("body top fragment becomes root", func(t *testing.T) {
var got string
var prepareErr error
stderr := captureDocFragmentStderr(t, func() {
got, prepareErr = prepareJsonMLBody(
strict,
`{"jsonml":["fragment",{"source":"outline"},["p",{},["span",{},"ok"]]]}`,
)
})
if prepareErr != nil {
t.Fatalf("prepare body: %v", prepareErr)
}
want := `["root",{},["p",{},["span",{},"ok"]]]`
if got != want {
t.Fatalf("body = %s, want %s", got, want)
}
if !strings.Contains(stderr, "fragment 只读容器") || !strings.Contains(stderr, "已自动移除 1 处") {
t.Fatalf("stderr = %q", stderr)
}
})
t.Run("body nested fragment is spliced", func(t *testing.T) {
var got string
var prepareErr error
stderr := captureDocFragmentStderr(t, func() {
got, prepareErr = prepareJsonMLBody(
strict,
`{"jsonml":["root",{},["fragment",{},["p",{},["span",{},"nested"]]]]}`,
)
})
if prepareErr != nil {
t.Fatalf("prepare body: %v", prepareErr)
}
want := `["root",{},["p",{},["span",{},"nested"]]]`
if got != want {
t.Fatalf("body = %s, want %s", got, want)
}
if !strings.Contains(stderr, "已自动移除 1 处") {
t.Fatalf("stderr = %q", stderr)
}
})
t.Run("node top fragment is unwrapped", func(t *testing.T) {
var got string
var prepareErr error
stderr := captureDocFragmentStderr(t, func() {
got, prepareErr = prepareJsonMLNode(
strict,
`["fragment",{"source":"section"},["p",{},["span",{},"ok"]]]`,
)
})
if prepareErr != nil {
t.Fatalf("prepare node: %v", prepareErr)
}
want := `["p",{},["span",{},"ok"]]`
if got != want {
t.Fatalf("node = %s, want %s", got, want)
}
if !strings.Contains(stderr, "fragment 只读容器") || !strings.Contains(stderr, "已自动移除 1 处") {
t.Fatalf("stderr = %q", stderr)
}
})
t.Run("node nested fragment is spliced", func(t *testing.T) {
var got string
var prepareErr error
stderr := captureDocFragmentStderr(t, func() {
got, prepareErr = prepareJsonMLNode(
strict,
`["p",{},["fragment",{},["span",{},"nested"]]]`,
)
})
if prepareErr != nil {
t.Fatalf("prepare node: %v", prepareErr)
}
want := `["p",{},["span",{},"nested"]]`
if got != want {
t.Fatalf("node = %s, want %s", got, want)
}
if !strings.Contains(stderr, "已自动移除 1 处") {
t.Fatalf("stderr = %q", stderr)
}
})
t.Run("top node fragment errors remain actionable", func(t *testing.T) {
tests := []struct {
name string
raw string
want string
}{
{name: "empty", raw: `["fragment",{}]`, want: "无可写回的节点"},
{name: "text", raw: `["fragment",{},"text"]`, want: "子节点不是合法 JSONML 节点"},
{
name: "multiple",
raw: `["fragment",{},["p",{}],["p",{}]]`,
want: "一次只能写一个",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if _, err := prepareJsonMLNode(strict, tt.raw); err == nil || !strings.Contains(err.Error(), tt.want) {
t.Fatalf("prepareJsonMLNode(%s) error = %v, want %q", tt.raw, err, tt.want)
}
})
}
})
}