2 changed files with 76 additions and 0 deletions
@ -0,0 +1,38 @@ |
|||||
|
import { describe, expect, test } from "bun:test"; |
||||
|
import { |
||||
|
GuestCommentValidationError, |
||||
|
normalizeGuestDisplayName, |
||||
|
validateGuestCommentBody, |
||||
|
} from "./post-comment-guest"; |
||||
|
|
||||
|
describe("normalizeGuestDisplayName", () => { |
||||
|
test("trims and accepts valid name", () => { |
||||
|
expect(normalizeGuestDisplayName(" ada ")).toBe("ada"); |
||||
|
}); |
||||
|
|
||||
|
test("rejects empty", () => { |
||||
|
expect(() => normalizeGuestDisplayName(" ")).toThrow(GuestCommentValidationError); |
||||
|
}); |
||||
|
|
||||
|
test("rejects too long", () => { |
||||
|
expect(() => normalizeGuestDisplayName("a".repeat(33))).toThrow(GuestCommentValidationError); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe("validateGuestCommentBody", () => { |
||||
|
test("accepts plain text", () => { |
||||
|
expect(validateGuestCommentBody("你好,世界")).toBe("你好,世界"); |
||||
|
}); |
||||
|
|
||||
|
test("rejects http URL", () => { |
||||
|
expect(() => validateGuestCommentBody("see http://x.com")).toThrow(GuestCommentValidationError); |
||||
|
}); |
||||
|
|
||||
|
test("rejects markdown link", () => { |
||||
|
expect(() => validateGuestCommentBody("[a](http://b)")).toThrow(GuestCommentValidationError); |
||||
|
}); |
||||
|
|
||||
|
test("rejects too long", () => { |
||||
|
expect(() => validateGuestCommentBody("z".repeat(501))).toThrow(GuestCommentValidationError); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,38 @@ |
|||||
|
const MAX_NAME = 32; |
||||
|
const MAX_BODY = 500; |
||||
|
|
||||
|
export class GuestCommentValidationError extends Error { |
||||
|
constructor(message: string) { |
||||
|
super(message); |
||||
|
this.name = "GuestCommentValidationError"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function normalizeGuestDisplayName(raw: string): string { |
||||
|
const t = raw.trim(); |
||||
|
if (!t) { |
||||
|
throw new GuestCommentValidationError("请填写昵称"); |
||||
|
} |
||||
|
if (t.length > MAX_NAME) { |
||||
|
throw new GuestCommentValidationError("昵称过长"); |
||||
|
} |
||||
|
return t; |
||||
|
} |
||||
|
|
||||
|
/** 返回 trim 后正文;违规抛 GuestCommentValidationError(由 API 映射为 400) */ |
||||
|
export function validateGuestCommentBody(raw: string): string { |
||||
|
const t = raw.trim(); |
||||
|
if (!t) { |
||||
|
throw new GuestCommentValidationError("请填写内容"); |
||||
|
} |
||||
|
if (t.length > MAX_BODY) { |
||||
|
throw new GuestCommentValidationError("内容过长"); |
||||
|
} |
||||
|
if (/https?:\/\//i.test(t) || /\bwww\./i.test(t)) { |
||||
|
throw new GuestCommentValidationError("不能包含链接"); |
||||
|
} |
||||
|
if (/\[[^\]]*\]\([^)]*\)/.test(t)) { |
||||
|
throw new GuestCommentValidationError("不能使用 Markdown 链接"); |
||||
|
} |
||||
|
return t; |
||||
|
} |
||||
Loading…
Reference in new issue