import { describe, it, expect } from 'vitest'; import { withUtf8Locale, DEFAULT_UTF8_LOCALE } from '../src/session/locale.js'; /** * locale.ts — UTF-8 locale guarantee for the spawned PTY. * * Why this exists: when the server is launched from Finder / launchd (the Mac * desktop app) the process env has NO `LANG`/`LC_*`. tmux then runs in its * non-UTF-8 mode and rewrites every wide character to `_` and downgrades * double-line box drawing (`═║╔╗`) to DEC Special Graphics single lines — so all * CJK output in the Claude Code TUI is destroyed before it ever reaches xterm. */ describe('withUtf8Locale', () => { it('adds LANG when no locale variable is set at all', () => { const out = withUtf8Locale({ PATH: '/usr/bin' }); expect(out.LANG).toBe(DEFAULT_UTF8_LOCALE); expect(out.PATH).toBe('/usr/bin'); }); it('keeps a UTF-8 LANG the user already has', () => { const out = withUtf8Locale({ LANG: 'zh_CN.UTF-8' }); expect(out.LANG).toBe('zh_CN.UTF-8'); }); it('accepts lowercase / hyphen-less spellings of utf8', () => { expect(withUtf8Locale({ LANG: 'en_US.utf8' }).LANG).toBe('en_US.utf8'); expect(withUtf8Locale({ LANG: 'C.UTF8' }).LANG).toBe('C.UTF8'); }); it('replaces a non-UTF-8 LANG (C / POSIX / latin1) with the default', () => { expect(withUtf8Locale({ LANG: 'C' }).LANG).toBe(DEFAULT_UTF8_LOCALE); expect(withUtf8Locale({ LANG: 'POSIX' }).LANG).toBe(DEFAULT_UTF8_LOCALE); expect(withUtf8Locale({ LANG: 'en_US.ISO8859-1' }).LANG).toBe(DEFAULT_UTF8_LOCALE); }); it('respects LC_ALL — it outranks LANG, so a UTF-8 LC_ALL is enough', () => { const out = withUtf8Locale({ LC_ALL: 'ja_JP.UTF-8', LANG: 'C' }); expect(out.LC_ALL).toBe('ja_JP.UTF-8'); expect(out.LANG).toBe('C'); // untouched — LC_ALL already decides the charset }); it('respects a UTF-8 LC_CTYPE (macOS Terminal.app sets only this)', () => { const out = withUtf8Locale({ LC_CTYPE: 'UTF-8' }); expect(out.LC_CTYPE).toBe('UTF-8'); expect(out.LANG).toBeUndefined(); }); it('overrides LANG when LC_CTYPE is present but not UTF-8', () => { const out = withUtf8Locale({ LC_CTYPE: 'C' }); expect(out.LANG).toBe(DEFAULT_UTF8_LOCALE); }); it('does not mutate the input env (immutability)', () => { const input = { PATH: '/usr/bin' }; const out = withUtf8Locale(input); expect(input).toEqual({ PATH: '/usr/bin' }); expect(out).not.toBe(input); }); it('ignores an empty-string locale (unset in practice)', () => { expect(withUtf8Locale({ LANG: '' }).LANG).toBe(DEFAULT_UTF8_LOCALE); expect(withUtf8Locale({ LC_ALL: '' }).LANG).toBe(DEFAULT_UTF8_LOCALE); }); });