~bigbes/sr-ht-spec

ref: e97532ccd54a6aacc597e9db1648e580e2936132 sr-ht-spec/prosediff/segment_test.go -rw-r--r-- 4.3 KiB
e97532cc — Eugene Blikh test(db): guard OpenProposal branch SQL against core.ProposalBranch drift (spec-wcr #1) 25 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)
	}
}