From 7bd6152ccafc06fdd273dd16b836f620d2c62188 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 31 Jul 2026 19:58:41 +0900 Subject: [PATCH] =?UTF-8?q?test(backend):=20LogNormalizer=E3=81=AE?= =?UTF-8?q?=E6=96=87=E5=AD=97=E5=88=97=E5=88=87=E3=82=8A=E8=A9=B0=E3=82=81?= =?UTF-8?q?=E3=81=AB=E5=A2=83=E7=95=8C=E3=82=B1=E3=83=BC=E3=82=B9=E3=81=AE?= =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 線形走査への変更に対し、2/3/4バイト文字が切り詰め境界に来る場合と、 接尾辞が上限に収まらない場合の挙動を検証する。 Co-Authored-By: Claude Opus 5 (1M context) --- .../test/unit/logging/LogNormalizer.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/backend/test/unit/logging/LogNormalizer.ts b/packages/backend/test/unit/logging/LogNormalizer.ts index b183f03fcd..24efd14909 100644 --- a/packages/backend/test/unit/logging/LogNormalizer.ts +++ b/packages/backend/test/unit/logging/LogNormalizer.ts @@ -115,6 +115,44 @@ describe('LogNormalizer', () => { expect(JSON.stringify(normalized.value)).not.toContain('�'); }); + test('truncates at UTF-8 character boundaries for every character width', () => { + const suffix = '…[Truncated]'; + const suffixBytes = Buffer.byteLength(suffix, 'utf8'); + + // 2 / 3 / 4バイト文字それぞれについて、切り詰め位置が文字の途中に落ちる場合を網羅する + const cases = [ + ['é', 2], // é + ['あ', 3], // あ + ['\u{1f600}', 4], // 😀 (サロゲート対) + ] as const; + + for (const [char, charBytes] of cases) { + for (let slack = 0; slack < charBytes; slack++) { + const maxStringBytes = suffixBytes + charBytes + slack; + const normalized = normalizeLogAttributes( + { value: char.repeat(20) }, + { limits: { maxStringBytes, maxBytes: 4096 } }, + ).value as string; + + expect(Buffer.byteLength(normalized, 'utf8')).toBeLessThanOrEqual(maxStringBytes); + expect(normalized).toBe(char + suffix); + // サロゲート対の分割などで不正なUTF-8になっていないこと + expect(Buffer.from(normalized, 'utf8').toString('utf8')).toBe(normalized); + } + } + }); + + test('drops the truncation suffix when it does not fit within the byte limit', () => { + const normalized = normalizeLogAttributes( + { value: 'あ'.repeat(20) }, + { limits: { maxStringBytes: 10, maxBytes: 4096 } }, + ).value as string; + + // 接尾辞(14バイト)が上限に収まらないので、接尾辞なしで文字境界まで切り詰める + expect(normalized).toBe('あ'.repeat(3)); + expect(Buffer.byteLength(normalized, 'utf8')).toBeLessThanOrEqual(10); + }); + test('serializes Error and its cause consistently', () => { const cause = new Error('root cause'); const error = new TypeError('outer error', { cause });