summaryrefslogtreecommitdiff
path: root/comments_test.go
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-07-15 17:26:22 -0500
committerGitHub <[email protected]>2026-07-15 17:26:22 -0500
commitb80180e77eebad8476aa66c8a5433764da672c62 (patch)
tree3078b122345c45a4bd8a5477ae21ad63fa56f13d /comments_test.go
parentb70d3dd588c8f9d6c9ed0ff111af06b76fa1f6ba (diff)
downloaddevianter-b80180e77eebad8476aa66c8a5433764da672c62.tar.gz
devianter-b80180e77eebad8476aa66c8a5433764da672c62.tar.bz2
devianter-b80180e77eebad8476aa66c8a5433764da672c62.zip
docs: document the exported API, and fix five bugs found writing it (#2)v0.3.2
* docs: translate Russian comments and document exported API The package carried 35 Russian comments and no doc comments on its exported identifiers, so pkg.go.dev rendered a bare list of signatures. Translate the Russian to English and give every exported identifier a doc comment in godoc form. Add doc.go with a package overview covering the guest-session requirement, the Error-as-struct convention, and CloudFront blocking. The comments record what the signatures cannot: that UpdateCSRF must run first and that its token expires, that Error is a struct and so is never nil, that Thread is one comment rather than a thread, and that GetComments' page parameter costs one request per page. Comments only; the struct field realignment is gofmt's, from doc comments splitting alignment groups. Refs #1 * add CODEOWNERS * fix: stop the library killing its caller, and flatten text correctly Writing doc comments for the exported API surfaced behavior too alarming to document and leave alone. A library should never terminate the process that imports it. Crashes: - GetComments panicked on a comment with an empty body: the shape check read m[0] and m[len(m)-1] with no length check. - Group.Favourites and Group.Gallery indexed their variadic folderid without checking len, so omitting it — which the signature invites — panicked. Omitting it now means 0. - AEmedia and PerformSearch called log.Fatalln on a bad argument rune, terminating the caller. Both now return an error, which their signatures already allowed for. Draft.js flattening, in the same code both callers share: - The block loop assigned rather than accumulated, so every block but the last was dropped and a multi-paragraph body came back as its closing line alone. Blocks are block-level elements, so join them with newlines. - GetDeviation guarded on txt[1] == '{', the second character of a body that opens with {"blocks". It never fired, so descriptions were handed back as raw Draft.js JSON. It now shares flattenComment with GetComments rather than keeping its own copy. Both flattening fixes change output for existing callers. Refs #1
Diffstat (limited to 'comments_test.go')
-rw-r--r--comments_test.go51
1 files changed, 51 insertions, 0 deletions
diff --git a/comments_test.go b/comments_test.go
new file mode 100644
index 0000000..a6c5a47
--- /dev/null
+++ b/comments_test.go
@@ -0,0 +1,51 @@
+package devianter
+
+import "testing"
+
+// Regression: flattenComment's shape check used to read m[0] and m[len(m)-1]
+// without a length check, so a comment with an empty markup body panicked with
+// index out of range and killed the caller's process.
+func TestFlattenCommentEmptyMarkup(t *testing.T) {
+ if got := flattenComment(""); got != "" {
+ t.Errorf("want an empty comment for empty markup, got %q", got)
+ }
+}
+
+func TestFlattenComment(t *testing.T) {
+ // A newer, Draft.js-encoded body is flattened to its text.
+ draft := `{"blocks":[{"text":"hello there"}]}`
+ if got := flattenComment(draft); got != "hello there" {
+ t.Errorf("want the Draft.js block text, got %q", got)
+ }
+
+ // An older, plain-HTML body passes through untouched.
+ html := "<b>hello</b> there"
+ if got := flattenComment(html); got != html {
+ t.Errorf("want plain HTML passed through, got %q", got)
+ }
+
+ // Regression: the block loop used to assign rather than accumulate, so every
+ // block but the last was silently dropped and a multi-paragraph comment came
+ // back as its closing line only.
+ multi := `{"blocks":[{"text":"first"},{"text":"second"},{"text":"third"}]}`
+ if got, want := flattenComment(multi), "first\nsecond\nthird"; got != want {
+ t.Errorf("want every block, one per line:\n got %q\nwant %q", got, want)
+ }
+
+ // An empty block is a blank line in the comment, not something to skip.
+ blank := `{"blocks":[{"text":"first"},{"text":""},{"text":"third"}]}`
+ if got, want := flattenComment(blank), "first\n\nthird"; got != want {
+ t.Errorf("want an empty block preserved as a blank line:\n got %q\nwant %q", got, want)
+ }
+
+ // Brace-shaped markup that isn't a Draft.js document falls back to itself
+ // rather than to an empty string.
+ if got := flattenComment("{}"); got != "{}" {
+ t.Errorf("want the original markup when there are no blocks, got %q", got)
+ }
+
+ // A single brace satisfies neither end of the shape check.
+ if got := flattenComment("{"); got != "{" {
+ t.Errorf("want a lone brace passed through, got %q", got)
+ }
+}