const { test } = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const crypto = require('node:crypto') const postcss = require('postcss') const root = path.resolve(__dirname, '..') const source = fs.readFileSync(path.join(root, 'src/renderer/src/styles/nanumSquare.css'), 'utf8') const css = postcss.parse(source) const faces = [] css.walkAtRules('font-face', rule => { faces.push(Object.fromEntries(rule.nodes.filter(node => node.type === 'decl').map(node => [node.prop, node.value]))) }) function codepoints(range) { const result = new Set() let previous = -1 for (const entry of range.split(',')) { const match = entry.trim().match(/^U\+([0-9A-F]+)(?:-([0-9A-F]+))?$/) assert.ok(match, `Invalid unicode-range: ${entry}`) const start = parseInt(match[1], 16) const end = parseInt(match[2] ?? match[1], 16) assert.ok(start > previous && end >= start && end <= 0x10ffff) for (let code = start; code <= end; code++) result.add(code) previous = end } return result } test('coverage is tied to the original bundled font bytes for all four weights', () => { assert.equal(faces.length, 4) assert.deepEqual(faces.map(face => face['font-weight']), ['300', '400', '700', '800']) for (const face of faces) { assert.equal(face['font-family'], "'NanumSquare'") assert.equal(face['font-display'], 'swap') const filename = face.src.match(/\/([^/]+\.woff2)'/)[1] const hash = crypto.createHash('sha256').update(fs.readFileSync(path.join(root, 'src/renderer/public/assets/fonts', filename))).digest('hex') assert.ok(source.includes(`${filename} sha256: ${hash}`), 'Regenerate coverage if a font changes') } }) for (const face of faces) { test(`weight ${face['font-weight']} preserves visible Hangul and lets blank glyphs fall back`, () => { const included = codepoints(face['unicode-range']) assert.equal([...included].filter(code => code >= 0xac00 && code <= 0xd7a3).length, 2479) for (const char of '가모한글학생SLAM0123 →') assert.ok(included.has(char.codePointAt(0)), `Keep ${char}`) for (const char of ['몯', '힣', '\u2022']) assert.equal(included.has(char.codePointAt(0)), false, `Let ${char} use fallback`) for (const code of [0x20, 0x3000, 0x3164]) assert.ok(included.has(code), 'Preserve intentional spacing') }) } test('UI keeps its original default font and native fallback without Neo', () => { const entry = fs.readFileSync(path.join(root, 'src/renderer/src/index.css'), 'utf8') assert.match(entry, /@import "\.\/styles\/nanumSquare\.css"/) assert.match(entry, /font-family: 'NanumSquare', Inter, system-ui, sans-serif/) assert.doesNotMatch(entry + source, /NanumSquareNeo/) const directFaces = [] postcss.parse(entry).walkAtRules('font-face', rule => directFaces.push(rule)) assert.equal(directFaces.length, 0, 'Unrestricted duplicate faces would suppress fallback') })