'use strict'; const test = require('node:test'); const H = require('./public-cli-helper.cjs'); const fixture = H.fs.readFileSync(H.path.join(__dirname, 'visual-state.raw.xml'), 'utf8'); test('public roundtrip retains an active null clip-action pointer without adding an array', () => { const work = H.testCase('empty-clip-actions'); const raw = fixture.replace('flags="126"', 'flags="254"'); H.assert.notEqual(raw, fixture); const source = H.expanded(work, raw); const rebuilt = H.build(work, source.xml); H.succeeded(rebuilt.result); H.assert.equal(Number(H.element(H.frame(rebuilt.raw, 0), 'placeobject', 'depth', 1).flags), 254); H.assert.doesNotMatch(source.xml, / { const work = H.testCase('text-height'); const source = H.expanded(work, fixture); H.assert.deepEqual(['red', 'green', 'blue', 'alpha'].map(k => H.element(source.xml, 'edittext', 'id', 2)[k]), ['17', '83', '201', '137']); const edited = source.xml.replace('height="18"', 'height="16"'); H.assert.notEqual(edited, source.xml, 'the requested edit must actually alter the XML'); const rebuilt = H.build(work, edited); H.succeeded(rebuilt.result); const text = H.element(rebuilt.raw, 'edittext', 'id', 2); H.assert.equal(Number(text.height), 16); for (const [key, expected] of Object.entries({ red: '17', green: '83', blue: '201', alpha: '137', top: '-2', left: '-2', bottom: '26', right: '317', alignment: '0', readonly: '1', multiline: '0', wordwrap: '0' })) { H.assert.equal(text[key], expected, `${key} is unrelated to the height edit`); } H.assert.equal(H.element(rebuilt.raw, 'movieclip', 'id', 0).unknown, '33'); H.assert.equal(H.element(rebuilt.raw, 'ettext', 'text', 'A & B "menu"').text, 'A & B "menu"'); }); test('public build honors deliberately edited text RGB in the same contract as expand', () => { const work = H.testCase('text-color-edit'); const source = H.expanded(work, fixture); const edited = source.xml.replace(/(]*?)red="17" green="83" blue="201"/, '$1red="7" green="19" blue="233"'); H.assert.notEqual(edited, source.xml); const rebuilt = H.build(work, edited); H.succeeded(rebuilt.result); const text = H.element(rebuilt.raw, 'edittext', 'id', 2); H.assert.deepEqual(['red', 'green', 'blue', 'alpha'].map(k => text[k]), ['7', '19', '233', '137']); H.assert.equal(Number(text.height), 18); }); test('public roundtrip retains transparent/dim color transforms and additive color values', () => { const work = H.testCase('placement-color'); const source = H.expanded(work, fixture); const rebuilt = H.build(work, source.xml); H.succeeded(rebuilt.result); for (const depth of [1, 2]) { const before = H.element(H.frame(fixture, 0), 'placeobject', 'depth', depth); const after = H.element(H.frame(rebuilt.raw, 0), 'placeobject', 'depth', depth); H.assert.equal(Number(after.flags), Number(before.flags)); H.assert.ok(Number(after.flags) & 8, 'HasColorTransform is semantically active'); for (const key of ['red', 'green', 'blue', 'alpha', 'unknown']) { H.assert.equal(after[key], before[key], `depth ${depth}: preserve ${key}`); } } }); test('public roundtrip retains Move-only and active zero ratio/clipdepth without inventing matrix/color state', () => { const work = H.testCase('move-flags'); const source = H.expanded(work, fixture); const move = H.element(H.frame(source.xml, 1), 'placeobject', 'depth', 1); H.assert.equal(move.flags, 'Move'); for (const key of ['matrix', 'rotm00', 'rotm01', 'rotm10', 'rotm11', 'tx', 'ty', 'rgbamul', 'rgbaadd', 'red', 'green', 'blue', 'alpha', 'unknown']) { H.assert.equal(move[key], undefined, `inactive raw dump field ${key} must not become an authored edit`); } const rebuilt = H.build(work, source.xml); H.succeeded(rebuilt.result); H.assert.equal(Number(H.element(H.frame(rebuilt.raw, 1), 'placeobject', 'depth', 1).flags), 1); const zero = H.element(H.frame(rebuilt.raw, 2), 'placeobject', 'depth', 1); H.assert.equal(Number(zero.flags), 81); H.assert.equal(Number(zero.ratio), 0); H.assert.equal(Number(zero.clipdepth), 0); }); test('public build applies one translation edit while retaining the nonidentity matrix, ratio and clipping contract', () => { const work = H.testCase('matrix-edit'); const source = H.expanded(work, fixture); const edited = source.xml.replace('tx="12.25"', 'tx="32.25"'); H.assert.notEqual(edited, source.xml); const rebuilt = H.build(work, edited); H.succeeded(rebuilt.result); const placement = H.element(H.frame(rebuilt.raw, 0), 'placeobject', 'depth', 1); H.assert.equal(Number(placement.tx), 32.25); H.assert.equal(Number(placement.flags), 126); H.assert.deepEqual(['rotm00', 'rotm01', 'rotm10', 'rotm11', 'ty'].map(k => Number(placement[k])), [0.85, 0.125, -0.25, 1.25, -3.5]); H.assert.equal(Number(placement.ratio), 0); H.assert.equal(Number(placement.clipdepth), 8); });