krz/devianter

A DeviantArt guest API library for Go.

clone: git clone https://gitbay.org/krz/devianter.git

v0.3.3: comments_test.go · raw

  1package devianter
  2
  3import "testing"
  4
  5// Regression: the shape check used to read m[0] and m[len(m)-1] without a length
  6// check, so a comment with an empty markup body panicked with index out of range
  7// and killed the caller's process.
  8func TestFlattenMarkupEmptyMarkup(t *testing.T) {
  9	if got := flattenMarkup(""); got != "" {
 10		t.Errorf("want an empty comment for empty markup, got %q", got)
 11	}
 12}
 13
 14// tiptap is what DeviantArt actually serves today; the fixtures below are shaped
 15// like responses captured from the live API.
 16func TestFlattenMarkupTiptap(t *testing.T) {
 17	one := `{"version":1,"document":{"type":"doc","content":[` +
 18		`{"type":"paragraph","attrs":{"textAlign":"left"},"content":[` +
 19		`{"type":"text","text":"Nice artwork!"}]}]}}`
 20	if got := flattenMarkup(one); got != "Nice artwork!" {
 21		t.Errorf("want the paragraph's text, got %q", got)
 22	}
 23
 24	// Regression: DeviantArt sends "version" as a number on some bodies and a
 25	// string on others. Modelling it as either type fails to unmarshal half of
 26	// them, so it must not be modelled at all.
 27	stringVersion := `{"version":"1","document":{"type":"doc","content":[` +
 28		`{"type":"paragraph","content":[{"type":"text","text":"hello"}]}]}}`
 29	if got := flattenMarkup(stringVersion); got != "hello" {
 30		t.Errorf(`want a string "version" handled the same as a numeric one, got %q`, got)
 31	}
 32
 33	// Each block is its own line.
 34	two := `{"version":1,"document":{"type":"doc","content":[` +
 35		`{"type":"paragraph","content":[{"type":"text","text":"first"}]},` +
 36		`{"type":"paragraph","content":[{"type":"text","text":"second"}]}]}}`
 37	if got, want := flattenMarkup(two), "first\nsecond"; got != want {
 38		t.Errorf("want one line per block:\n got %q\nwant %q", got, want)
 39	}
 40
 41	// An empty paragraph is a blank line, not something to skip.
 42	blank := `{"version":1,"document":{"type":"doc","content":[` +
 43		`{"type":"paragraph","content":[{"type":"text","text":"a"}]},` +
 44		`{"type":"paragraph"},` +
 45		`{"type":"paragraph","content":[{"type":"text","text":"b"}]}]}}`
 46	if got, want := flattenMarkup(blank), "a\n\nb"; got != want {
 47		t.Errorf("want an empty paragraph preserved as a blank line:\n got %q\nwant %q", got, want)
 48	}
 49
 50	// A hard break is a newline within its block.
 51	brk := `{"version":1,"document":{"type":"doc","content":[` +
 52		`{"type":"paragraph","content":[{"type":"text","text":"up"},` +
 53		`{"type":"hardBreak"},{"type":"text","text":"down"}]}]}}`
 54	if got, want := flattenMarkup(brk), "up\ndown"; got != want {
 55		t.Errorf("want a hardBreak as a newline:\n got %q\nwant %q", got, want)
 56	}
 57
 58	// Marked-up runs are separate text nodes and must be concatenated, not
 59	// separated.
 60	marks := `{"version":1,"document":{"type":"doc","content":[` +
 61		`{"type":"paragraph","content":[` +
 62		`{"type":"text","text":"plain "},` +
 63		`{"type":"text","marks":[{"type":"bold"}],"text":"bold"},` +
 64		`{"type":"text","text":" tail"}]}]}}`
 65	if got, want := flattenMarkup(marks), "plain bold tail"; got != want {
 66		t.Errorf("want marked runs concatenated:\n got %q\nwant %q", got, want)
 67	}
 68
 69	// Text carrying a link mark still surfaces; the href does not.
 70	link := `{"version":1,"document":{"type":"doc","content":[` +
 71		`{"type":"paragraph","content":[{"type":"text","marks":[` +
 72		`{"type":"link","attrs":{"href":"https://example.com"}}],"text":"click here"}]}]}}`
 73	if got, want := flattenMarkup(link), "click here"; got != want {
 74		t.Errorf("want the link text without the href:\n got %q\nwant %q", got, want)
 75	}
 76
 77	// Headings are blocks like any other.
 78	heading := `{"version":1,"document":{"type":"doc","content":[` +
 79		`{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"Title"}]},` +
 80		`{"type":"paragraph","content":[{"type":"text","text":"body"}]}]}}`
 81	if got, want := flattenMarkup(heading), "Title\nbody"; got != want {
 82		t.Errorf("want a heading flattened as a block:\n got %q\nwant %q", got, want)
 83	}
 84
 85	// Bodies carry HTML entities on the wire; plain text should not.
 86	entity := `{"version":1,"document":{"type":"doc","content":[` +
 87		`{"type":"paragraph","content":[{"type":"text","text":"I’d love & more"}]}]}}`
 88	if got, want := flattenMarkup(entity), "I’d love & more"; got != want {
 89		t.Errorf("want HTML entities decoded:\n got %q\nwant %q", got, want)
 90	}
 91
 92	// A node carrying no text of its own contributes nothing.
 93	emote := `{"version":1,"document":{"type":"doc","content":[` +
 94		`{"type":"paragraph","content":[{"type":"text","text":"hi "},` +
 95		`{"type":"da-emote","attrs":{"name":":happy:"}}]}]}}`
 96	if got, want := flattenMarkup(emote), "hi "; got != want {
 97		t.Errorf("want a textless node to contribute nothing:\n got %q\nwant %q", got, want)
 98	}
 99}
100
101// Draft.js is legacy but still served on old bodies, so the path stays.
102func TestFlattenMarkupDraftJS(t *testing.T) {
103	draft := `{"blocks":[{"text":"hello there"}]}`
104	if got := flattenMarkup(draft); got != "hello there" {
105		t.Errorf("want the Draft.js block text, got %q", got)
106	}
107
108	// Regression: the block loop used to assign rather than accumulate, so every
109	// block but the last was silently dropped and a multi-paragraph comment came
110	// back as its closing line only.
111	multi := `{"blocks":[{"text":"first"},{"text":"second"},{"text":"third"}]}`
112	if got, want := flattenMarkup(multi), "first\nsecond\nthird"; got != want {
113		t.Errorf("want every block, one per line:\n got %q\nwant %q", got, want)
114	}
115
116	// An empty block is a blank line, not something to skip.
117	blank := `{"blocks":[{"text":"first"},{"text":""},{"text":"third"}]}`
118	if got, want := flattenMarkup(blank), "first\n\nthird"; got != want {
119		t.Errorf("want an empty block preserved as a blank line:\n got %q\nwant %q", got, want)
120	}
121}
122
123func TestFlattenMarkupPassthrough(t *testing.T) {
124	// An older, plain-HTML body passes through untouched.
125	html := "<b>hello</b> there"
126	if got := flattenMarkup(html); got != html {
127		t.Errorf("want plain HTML passed through, got %q", got)
128	}
129
130	// Brace-shaped markup in no known format falls back to itself rather than to
131	// an empty string.
132	if got := flattenMarkup("{}"); got != "{}" {
133		t.Errorf("want the original markup when nothing parses, got %q", got)
134	}
135
136	// Well-formed JSON that is neither format is still not silently eaten.
137	other := `{"something":"else"}`
138	if got := flattenMarkup(other); got != other {
139		t.Errorf("want unrecognised JSON passed through, got %q", got)
140	}
141
142	// A single brace satisfies neither end of the shape check.
143	if got := flattenMarkup("{"); got != "{" {
144		t.Errorf("want a lone brace passed through, got %q", got)
145	}
146}