UNPKG

rollup-plugin-glsl-optimize

Version:

Import GLSL source files as strings. Pre-processed, validated and optimized with Khronos Group SPIRV-Tools. Supports glslify.

214 lines (210 loc) 8.57 kB
import {assert} from 'chai'; import * as parse from '../../src/lib/parse.js'; const consoleOrig = global.console; let outBuf; function mockConsoleError() { outBuf = ''; global.console = {...consoleOrig}; global.console.error = (...args) => { outBuf += `${args.map(String).join(' ')}\n`; }; global.console.warn = global.console.error; } function unMockConsoleError() { global.console = consoleOrig; return outBuf; } export function parserTests() { describe('Parser', function() { describe('#lexer()', function() { const lexerTest = (input) => [...parse.test.lexer(input)].map(parse.test.printToken); it('should lex empty input', function() { const input = ``; const expected = [ `<EOF L1:0> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex single char input', function() { const input = `A`; const expected = [ `<Line L1:1> v:'A' t:'A'`, `<EOF L1:1> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex single newline input', function() { const input = `\n`; const expected = [ `<EOL L1:1> v:'<EOL>' t:'<EOL>'`, `<EOF L2:0> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex input without terminating newline', function() { const input = `A`; const expected = [ `<Line L1:1> v:'A' t:'A'`, `<EOF L1:1> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex newlines correctly', function() { /* GLSL ES 300 spec: Lines are relevant for compiler diagnostic messages and the preprocessor. They are terminated by carriage-return or line-feed. If both are used together, it will count as only a single line termination. */ const input = `A\nB\rC\r\nD\n\rE\n\r\nF\r\n\rG`; const expected = [ `<Line L1:1> v:'A' t:'A'`, `<EOL L1:2> v:'<EOL>' t:'<EOL>'`, `<Line L2:1> v:'B' t:'B'`, `<EOL L2:2> v:'<EOL>' t:'<CR>'`, `<Line L3:1> v:'C' t:'C'`, `<EOL L3:2> v:'<EOL>' t:'<CR><EOL>'`, `<Line L4:2> v:'D' t:'D'`, `<EOL L4:3> v:'<EOL>' t:'<EOL><CR>'`, `<Line L5:2> v:'E' t:'E'`, `<EOL L5:3> v:'<EOL>' t:'<EOL><CR>'`, `<EOL L6:2> v:'<EOL>' t:'<EOL>'`, `<Line L7:1> v:'F' t:'F'`, `<EOL L7:2> v:'<EOL>' t:'<CR><EOL>'`, `<EOL L8:2> v:'<EOL>' t:'<CR>'`, `<Line L9:1> v:'G' t:'G'`, `<EOF L9:1> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex line continuations correctly', function() { /* GLSL ES 300 spec: Lines separated by the line-continuation character preceding a new line are concatenated together before either comment processing or preprocessing. This means that no white space is substituted for the line-continuation character. That is, a single token could be formed by the concatenation by taking the characters at the end of one line concatenating them with the characters at the beginning of the next line. */ const input = `A\\\nB\\\rC\\\r\nD\\\n\rE\\\n\r\\\nF\\\r\n\\\rG/*test\\\ntest*/`; const expected = [ `<Line L1:1> v:'ABCDEFG' t:'A\\<EOL>B\\<CR>C\\<CR><EOL>D\\<EOL><CR>E\\<EOL><CR>\\<EOL>F\\<CR><EOL>\\<CR>G'`, `<Comment L9:2> v:'testtest' t:'/*test\\<EOL>test*/'`, `<EOF L10:6> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex comments correctly', function() { const input = `/*A*/\n` + `X\n` + `//B\n` + `Y\n` + `/*C//D*/\n` + `Z`; const expected = [ `<Comment L1:1> v:'A' t:'/*A*/'`, `<EOL L1:6> v:'<EOL>' t:'<EOL>'`, `<Line L2:1> v:'X' t:'X'`, `<EOL L2:2> v:'<EOL>' t:'<EOL>'`, `<Comment L3:1> v:'B' t:'//B'`, `<EOL L3:4> v:'<EOL>' t:'<EOL>'`, `<Line L4:1> v:'Y' t:'Y'`, `<EOL L4:2> v:'<EOL>' t:'<EOL>'`, `<Comment L5:1> v:'C//D' t:'/*C//D*/'`, `<EOL L5:9> v:'<EOL>' t:'<EOL>'`, `<Line L6:1> v:'Z' t:'Z'`, `<EOF L6:1> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex multi-line comments correctly', function() { const input = `/*A\n` + `B\tC*/\n` + `X\n`; const expected = [ `<Comment L1:1> v:'A<EOL>B<TAB>C' t:'/*A<EOL>B<TAB>C*/'`, `<EOL L2:6> v:'<EOL>' t:'<EOL>'`, `<Line L3:1> v:'X' t:'X'`, `<EOL L3:2> v:'<EOL>' t:'<EOL>'`, `<EOF L4:0> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); it('should lex non-tokens correctly', function() { const input = `/A\n` + `\\B\tC*/\n` + `//X\n`; const expected = [ `<Line L1:1> v:'/A' t:'/A'`, `<EOL L1:3> v:'<EOL>' t:'<EOL>'`, `<Line L2:1> v:'\\B<TAB>C*/' t:'\\B<TAB>C*/'`, `<EOL L2:7> v:'<EOL>' t:'<EOL>'`, `<Comment L3:1> v:'X' t:'//X'`, `<EOL L3:4> v:'<EOL>' t:'<EOL>'`, `<EOF L4:0> v:'' t:''`, ]; assert.deepStrictEqual(lexerTest(input), expected); }); }); describe('#simpleParse()', function() { const parserTest = (input) => [...parse.simpleParse(input)].map(parse.test.printToken); const parserDirectTest = (input) => [...parse.test.parser(input)].map(parse.test.printToken); it('should parse empty input', function() { const input = ``; const expected = [ `<EOF L1:0> v:'' t:''`, ]; assert.deepStrictEqual(parserTest(input), expected); }); it('should pass-through existing tokens', function() { const input = [{type: 8, text: '', col: 1, line: 1, value: '', test: 'test'}]; const expected = [ `<Directive L1:1> v:'' t:'' | test : 'test'`, ]; assert.deepStrictEqual(parserDirectTest(input), expected); }); it('should parse inline comments as a single space', function() { /* GLSL ES 300 spec: * All comments are replaced with a single space */ const input = `#pragma/* A B \n C */test`; const expected = [ `<Directive L1:1> v:'#pragma test' t:'#pragma/* A B <EOL> C */test'`, `<EOF L2:9> v:'' t:''`, ]; assert.deepStrictEqual(parserTest(input), expected); }); it('should yield top level comments', function() { const input = `#pragma test\n/* A B \n C */\ntest`; const expected = [ `<Directive L1:1> v:'#pragma test' t:'#pragma test'`, `<EOL L1:13> v:'<EOL>' t:'<EOL>'`, `<Comment L2:1> v:' A B <EOL> C ' t:'/* A B <EOL> C */'`, `<EOL L3:6> v:'<EOL>' t:'<EOL>'`, `<Line L4:1> v:'test' t:'test'`, `<EOF L4:4> v:'' t:''`, ]; assert.deepStrictEqual(parserTest(input), expected); }); it('should parse directives', function() { const input = `#version test\n#line test\n#extension test : require\n`; const expected = [ `<Version L1:1> v:'#version test' t:'#version test' | Version : 'test'`, `<EOL L1:14> v:'<EOL>' t:'<EOL>'`, `<LineNo L2:1> v:'#line test' t:'#line test'`, `<EOL L2:11> v:'<EOL>' t:'<EOL>'`, `<Extension L3:1> v:'#extension test : require' t:` + `'#extension test : require' | ExtensionName : 'test' | ExtensionBehavior : 'require'`, `<EOL L3:26> v:'<EOL>' t:'<EOL>'`, `<EOF L4:0> v:'' t:''`, ]; assert.deepStrictEqual(parserTest(input), expected); }); it('should warn about invalid extension directives', function() { mockConsoleError(); parserTest('#extension test'); assert.include(unMockConsoleError(), 'Warning: #extension directive: parse error'); mockConsoleError(); parserTest('#extension test : potato'); assert.include(unMockConsoleError(), `unknown behavior 'potato'`); }); }); }); }