diff --git a/src/xpath/lib b/src/xpath/lib index 5ec18e4..1e9b871 160000 --- a/src/xpath/lib +++ b/src/xpath/lib @@ -1 +1 @@ -Subproject commit 5ec18e4561f754e78d94d0dc6a3c12b020230c64 +Subproject commit 1e9b871bd6b328fa4a130d5b4c0088adc842ed93 diff --git a/tests/xslt/arithmetic.test.ts b/tests/xslt/arithmetic.test.ts new file mode 100644 index 0000000..b574ab6 --- /dev/null +++ b/tests/xslt/arithmetic.test.ts @@ -0,0 +1,133 @@ +import { Xslt, XmlParser } from '../../src/index'; + +describe('XPath arithmetic operations', () => { + let xslt: Xslt; + let xmlParser: XmlParser; + + beforeEach(() => { + xslt = new Xslt(); + xmlParser = new XmlParser(); + }); + + it('addition: number + 1 returns 2', async () => { + const xml = xmlParser.xmlParse('1'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('2'); + }); + + it('subtraction: number - 1 returns 0', async () => { + const xml = xmlParser.xmlParse('1'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('0'); + }); + + it('multiplication: number * 2 returns 2', async () => { + const xml = xmlParser.xmlParse('1'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('2'); + }); + + it('division: number div 2 returns 5', async () => { + const xml = xmlParser.xmlParse('10'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('5'); + }); + + it('modulo: number mod 3 returns 1', async () => { + const xml = xmlParser.xmlParse('10'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('1'); + }); + + it('node + node: first + second returns correct sum', async () => { + const xml = xmlParser.xmlParse('34'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('7'); + }); + + it('decimal node: price * 2 returns 7', async () => { + const xml = xmlParser.xmlParse('3.5'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('7'); + }); + + it('attribute node: @value + 1 returns 6', async () => { + const xml = xmlParser.xmlParse(''); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('6'); + }); + + it('unary negation on node: -number returns -5', async () => { + const xml = xmlParser.xmlParse('5'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('-5'); + }); + + it('empty node-set in arithmetic does not throw', async () => { + // XPath 1.0 typically yields NaN for arithmetic on an empty node-set. + // This test only asserts that xsltProcess resolves without throwing. + const xml = xmlParser.xmlParse('1'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + await xslt.xsltProcess(xml, stylesheet); + }); + + it('plain number select still works: select="number" returns 1', async () => { + const xml = xmlParser.xmlParse('1'); + const stylesheet = xmlParser.xmlParse(` + + + +`); + const result = await xslt.xsltProcess(xml, stylesheet); + expect(result).toBe('1'); + }); +}); diff --git a/tests/xslt/copy-of.test.tsx b/tests/xslt/copy-of.test.tsx index 56098cd..5384712 100644 --- a/tests/xslt/copy-of.test.tsx +++ b/tests/xslt/copy-of.test.tsx @@ -1,9 +1,48 @@ import assert from 'assert'; -import { XmlParser } from '../../src/dom'; -import { Xslt } from '../../src/xslt'; +import { Xslt, XmlParser } from '../../src/index'; describe('xsl:copy-of', () => { + it('keeps comment content stable across repeated identity transforms', async () => { + const xslt = new Xslt(); + const xmlParser = new XmlParser(); + + const xmlInput = ''; + const stylesheet = xmlParser.xmlParse(` + + + +`); + + const firstInputDoc = xmlParser.xmlParse(xmlInput); + const firstPass = await xslt.xsltProcess(firstInputDoc, stylesheet); + assert.equal(firstPass, xmlInput); + + const secondInputDoc = xmlParser.xmlParse(firstPass); + const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet); + assert.equal(secondPass, firstPass); + }); + + it('keeps empty comments stable across repeated identity transforms', async () => { + const xslt = new Xslt(); + const xmlParser = new XmlParser(); + + const xmlInput = ''; + const stylesheet = xmlParser.xmlParse(` + + + +`); + + const firstInputDoc = xmlParser.xmlParse(xmlInput); + const firstPass = await xslt.xsltProcess(firstInputDoc, stylesheet); + assert.equal(firstPass, xmlInput); + + const secondInputDoc = xmlParser.xmlParse(firstPass); + const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet); + assert.equal(secondPass, firstPass); + }); + it('Trivial', async () => { const xmlSource = ` diff --git a/tests/xslt/issue-187.test.ts b/tests/xslt/issue-187.test.ts deleted file mode 100644 index f95cc46..0000000 --- a/tests/xslt/issue-187.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Xslt, XmlParser } from '../../src/index'; - -describe('Issue #187: Identity transformation adds spaces to comments', () => { - it('keeps comment content stable across repeated identity transforms', async () => { - const xslt = new Xslt(); - const xmlParser = new XmlParser(); - - const xmlInput = ''; - const stylesheet = xmlParser.xmlParse(` - - - -`); - - const firstInputDoc = xmlParser.xmlParse(xmlInput); - const firstPass = await xslt.xsltProcess(firstInputDoc, stylesheet); - expect(firstPass).toBe(xmlInput); - - const secondInputDoc = xmlParser.xmlParse(firstPass); - const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet); - expect(secondPass).toBe(firstPass); - }); - - it('keeps empty comments stable across repeated identity transforms', async () => { - const xslt = new Xslt(); - const xmlParser = new XmlParser(); - - const xmlInput = ''; - const stylesheet = xmlParser.xmlParse(` - - - -`); - - const firstInputDoc = xmlParser.xmlParse(xmlInput); - const firstPass = await xslt.xsltProcess(firstInputDoc, stylesheet); - expect(firstPass).toBe(xmlInput); - - const secondInputDoc = xmlParser.xmlParse(firstPass); - const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet); - expect(secondPass).toBe(firstPass); - }); -}); \ No newline at end of file diff --git a/tests/xslt/issue-183.test.ts b/tests/xslt/template-match.test.ts similarity index 74% rename from tests/xslt/issue-183.test.ts rename to tests/xslt/template-match.test.ts index 0aea773..5a6c0b1 100644 --- a/tests/xslt/issue-183.test.ts +++ b/tests/xslt/template-match.test.ts @@ -1,47 +1,43 @@ import { Xslt, XmlParser } from '../../src/index'; -describe('Issue #183: Template match with nested elements', () => { - it('should match //message when nested under ', async () => { - const xslt = new Xslt(); - const xmlParser = new XmlParser(); +describe('xsl:template match patterns', () => { + let xslt: Xslt; + let xmlParser: XmlParser; + beforeEach(() => { + xslt = new Xslt(); + xmlParser = new XmlParser(); + }); + + it('matches //message when nested under a child element', async () => { const xml = xmlParser.xmlParse('Hello World.'); const stylesheet = xmlParser.xmlParse(`
`); - const result = await xslt.xsltProcess(xml, stylesheet); expect(result).toBe('
Hello World.
'); }); - it('should match with explicit path /page/child/message', async () => { - const xslt = new Xslt(); - const xmlParser = new XmlParser(); - + it('matches with explicit absolute path /page/child/message', async () => { const xml = xmlParser.xmlParse('Hello World.'); const stylesheet = xmlParser.xmlParse(`
`); - const result = await xslt.xsltProcess(xml, stylesheet); expect(result).toBe('
Hello World.
'); }); - it('should match //message when NOT nested (direct child of root)', async () => { - const xslt = new Xslt(); - const xmlParser = new XmlParser(); - + it('matches //message when element is a direct child of root', async () => { const xml = xmlParser.xmlParse('Hello World.'); const stylesheet = xmlParser.xmlParse(`
`); - const result = await xslt.xsltProcess(xml, stylesheet); expect(result).toBe('
Hello World.
'); });