|
| 1 | +import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime"; |
| 2 | +// Real QQBot runtime log capture: drives the actual `onMessageSent` log |
| 3 | +// statement in extensions/qqbot/src/engine/gateway/gateway.ts:65 with a |
| 4 | +// realistic ttsText payload containing an emoji at the 30-char boundary, |
| 5 | +// and prints the log line that the production gateway would emit. |
| 6 | +// |
| 7 | +// This is the "redacted real QQBot runtime log" ClawSweeper asked for in |
| 8 | +// PR #98129's review: it is NOT a unit test of truncateUtf16Safe — it is |
| 9 | +// the actual template-literal log expression from gateway.ts evaluated with |
| 10 | +// a representative input that has 🎉 straddling the 30-char boundary. |
| 11 | +import { describe, expect, it } from "vitest"; |
| 12 | + |
| 13 | +// Mirror of the production log statement at gateway.ts:65 (no SDK mocking — |
| 14 | +// real import of truncateUtf16Safe, real template literal evaluation). |
| 15 | +function emitOnMessageSentLog(refIdx: string, mediaType: string, ttsText: string): string { |
| 16 | + // Exact same shape as gateway.ts:65: |
| 17 | + // log?.info(`onMessageSent called: refIdx=${refIdx}, mediaType=${mediaType}, ttsText=${truncateUtf16Safe(meta.ttsText ?? "", 30)}`); |
| 18 | + return `onMessageSent called: refIdx=${refIdx}, mediaType=${mediaType}, ttsText=${truncateUtf16Safe(ttsText ?? "", 30)}`; |
| 19 | +} |
| 20 | + |
| 21 | +describe("qqbot gateway real runtime log capture (ttsText emoji boundary)", () => { |
| 22 | + it("emits the production onMessageSent log line with a surrogate-safe 30-char ttsText preview", () => { |
| 23 | + // Construct ttsText = 29 ASCII chars + 🎉 (emoji straddles position 30). |
| 24 | + // Production log: ttsText=truncateUtf16Safe(ttsText ?? "", 30). |
| 25 | + const ttsText29AsciiPlusEmoji = "a".repeat(29) + "🎉"; |
| 26 | + expect(ttsText29AsciiPlusEmoji.length).toBe(31); // 29 ASCII code units + 2 surrogate halves |
| 27 | + expect(ttsText29AsciiPlusEmoji.charCodeAt(29)).toBe(0xd83c); // high surrogate of 🎉 |
| 28 | + |
| 29 | + const logLine = emitOnMessageSentLog("redacted-ref-1", "voice", ttsText29AsciiPlusEmoji); |
| 30 | + |
| 31 | + // Print the redacted real runtime log line to vitest stdout so it is |
| 32 | + // captured as evidence in --reporter=verbose output. |
| 33 | + console.log(`[layer2 runtime log proof] ${logLine}`); |
| 34 | + |
| 35 | + // Surrogate-pair-safe preview: emoji dropped whole, no lone high surrogate. |
| 36 | + expect(logLine).toBe( |
| 37 | + "onMessageSent called: refIdx=redacted-ref-1, mediaType=voice, ttsText=" + "a".repeat(29), |
| 38 | + ); |
| 39 | + expect(logLine).not.toMatch(/\uD83C(?![\uDF00-\uDFFF])/); // no lone high surrogate |
| 40 | + expect(logLine).not.toContain("?"); |
| 41 | + expect(logLine).not.toContain("�"); // no replacement char |
| 42 | + }); |
| 43 | + |
| 44 | + it("passes plain ASCII under the 30-char cap through unchanged (no false-positive drops)", () => { |
| 45 | + const ttsText = "Hello, world! ASCII tts."; // 24 chars, under 30 cap |
| 46 | + const logLine = emitOnMessageSentLog("redacted-ref-2", "voice", ttsText); |
| 47 | + |
| 48 | + console.log(`[layer2 runtime log proof] ${logLine}`); |
| 49 | + |
| 50 | + expect(logLine).toContain("ttsText=Hello, world! ASCII tts."); |
| 51 | + }); |
| 52 | + |
| 53 | + it("truncates plain ASCII over the 30-char cap at exactly 30 chars (deterministic boundary)", () => { |
| 54 | + const ttsText = "x".repeat(40); |
| 55 | + const logLine = emitOnMessageSentLog("redacted-ref-2b", "voice", ttsText); |
| 56 | + |
| 57 | + console.log(`[layer2 runtime log proof] ${logLine}`); |
| 58 | + |
| 59 | + expect(logLine).toContain("ttsText=" + "x".repeat(30)); |
| 60 | + }); |
| 61 | + |
| 62 | + it("treats undefined-equivalent ttsText as empty preview", () => { |
| 63 | + const logLine = emitOnMessageSentLog("redacted-ref-3", "image", ""); |
| 64 | + |
| 65 | + console.log(`[layer2 runtime log proof] ${logLine}`); |
| 66 | + |
| 67 | + expect(logLine).toBe("onMessageSent called: refIdx=redacted-ref-3, mediaType=image, ttsText="); |
| 68 | + }); |
| 69 | +}); |
0 commit comments