~bigbes/sr-ht-spec

ref: e183a11e6590550c867395a5e1ef1acf9c16adf9 sr-ht-spec/prosediff/segment_test.go -rw-r--r-- 4.3 KiB
e183a11e — Eugene Blikh feat(core,db): comment anchors and the comment table (spec-by6.3.1) 24 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package prosediff

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

type wantBlock struct {
	kind  BlockKind
	level int
	quote int
	text  string
	path  []string
}

func TestSegment(t *testing.T) {
	tests := []struct {
		name string
		src  string
		want []wantBlock
	}{
		{
			name: "headings and paragraphs",
			src:  "# Title\n\nFirst para\nwrapped over lines.\n\n## Sub\n\nSecond para.\n",
			want: []wantBlock{
				{kind: KindHeading, level: 1, text: "Title"},
				{kind: KindParagraph, text: "First para\nwrapped over lines.", path: []string{"Title"}},
				{kind: KindHeading, level: 2, text: "Sub", path: []string{"Title"}},
				{kind: KindParagraph, text: "Second para.", path: []string{"Title", "Sub"}},
			},
		},
		{
			name: "list items are separate blocks",
			src:  "- alpha\n- beta\n  - nested\n",
			want: []wantBlock{
				{kind: KindListItem, level: 1, text: "alpha"},
				{kind: KindListItem, level: 1, text: "beta"},
				{kind: KindListItem, level: 2, text: "nested"},
			},
		},
		{
			name: "fenced code is one block",
			src:  "text\n\n```go\na := 1\nb := 2\n```\n",
			want: []wantBlock{
				{kind: KindParagraph, text: "text"},
				{kind: KindCode, text: "a := 1\nb := 2"},
			},
		},
		{
			name: "table rows are separate blocks",
			src:  "| a | b |\n|---|---|\n| 1 | 2 |\n| 3 | 4 |\n",
			want: []wantBlock{
				{kind: KindTableHeader, text: "| a | b |"},
				{kind: KindTableRow, text: "| 1 | 2 |"},
				{kind: KindTableRow, text: "| 3 | 4 |"},
			},
		},
		{
			name: "block quote carries depth",
			src:  "> quoted text\n> continues\n",
			want: []wantBlock{
				{kind: KindParagraph, quote: 1, text: "quoted text\ncontinues"},
			},
		},
		{
			name: "frontmatter is its own block",
			src:  "---\nid: SPEC-0007\ntitle: x\n---\n\nBody.\n",
			want: []wantBlock{
				{kind: KindFrontmatter, text: "---\nid: SPEC-0007\ntitle: x\n---"},
				{kind: KindParagraph, text: "Body."},
			},
		},
		{
			name: "empty document",
			src:  "",
			want: nil,
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			got := Segment([]byte(tc.src))
			require.Len(t, got, len(tc.want))
			for i, w := range tc.want {
				b := got[i]
				assert.Equal(t, w.kind, b.Kind, "block %d kind", i)
				assert.Equal(t, w.level, b.Level, "block %d level", i)
				assert.Equal(t, w.quote, b.QuoteDepth, "block %d quote depth", i)
				assert.Equal(t, w.text, b.Text, "block %d text", i)
				assert.Equal(t, w.path, b.HeadingPath, "block %d heading path", i)
				assert.Equal(t, i, b.Ordinal)
				assert.NotEmpty(t, b.Hash)
			}
		})
	}
}

func TestSegmentLineNumbers(t *testing.T) {
	src := "# Title\n\npara one\n\n```\ncode\n```\n"
	got := Segment([]byte(src))
	require.Len(t, got, 3)
	assert.Equal(t, 1, got[0].StartLine)
	assert.Equal(t, 3, got[1].StartLine)
	assert.Equal(t, 6, got[2].StartLine)
}

func TestSegmentFrontmatterLineOffset(t *testing.T) {
	src := "---\nid: X\n---\n\n# Title\n"
	got := Segment([]byte(src))
	require.Len(t, got, 2)
	assert.Equal(t, KindFrontmatter, got[0].Kind)
	assert.Equal(t, 5, got[1].StartLine)
}

// TestHashIgnoresWrappingForProse and its code counterpart are the two halves
// of the design's "code fences diff as code, prose diffs as prose" rule.
func TestHashIgnoresWrappingForProse(t *testing.T) {
	a := Segment([]byte("one two three four\nfive six\n"))
	b := Segment([]byte("one two\nthree four five six\n"))
	require.Len(t, a, 1)
	require.Len(t, b, 1)
	assert.Equal(t, a[0].Hash, b[0].Hash)
}

func TestHashRespectsWhitespaceForCode(t *testing.T) {
	a := Segment([]byte("```\nif x:\n    y()\n```\n"))
	b := Segment([]byte("```\nif x:\n\ty()\n```\n"))
	require.Len(t, a, 1)
	require.Len(t, b, 1)
	assert.NotEqual(t, a[0].Hash, b[0].Hash)
}

func TestHashRespectsStructure(t *testing.T) {
	para := Segment([]byte("same words here\n"))
	item := Segment([]byte("- same words here\n"))
	require.Len(t, para, 1)
	require.Len(t, item, 1)
	assert.NotEqual(t, para[0].Hash, item[0].Hash)
}

func TestKindProse(t *testing.T) {
	for _, k := range []BlockKind{KindHeading, KindParagraph, KindListItem, KindTableRow, KindTableHeader, KindThematicBreak} {
		assert.True(t, k.Prose(), "%s should diff as prose", k)
	}
	for _, k := range []BlockKind{KindCode, KindFrontmatter, KindHTML} {
		assert.False(t, k.Prose(), "%s should diff as code", k)
	}
}