const fs = require('fs'); const pathUtil = require('path'); const htmlparser = require('htmlparser2'); const {test} = require('tap'); const VirtualMachine = require('../../src/virtual-machine'); const Runtime = require('../../src/engine/runtime'); const ArgumentType = require('../../src/extension-support/argument-type'); const BlockType = require('../../src/extension-support/block-type'); const baseExtensionInfo = { id: 'xmltest', name: `<>"'&& Name`, docsURI: `https://example.com/&''""<<>>`, menuIconURI: `data:<>&"' category icon`, blocks: [ { blockType: `block type <>&"'`, opcode: `opcode <>&"'`, text: `<>&"' [string argument <>&"'] [inputMenu <"'&>] [fieldMenu <"'&>] [image <"'&>]`, blockIconURI: `'data:<>&"' block icon`, arguments: { [`string argument <>&"'`]: { type: ArgumentType.STRING, defaultValue: `default string <>&"'` }, [`inputMenu <"'&>`]: { type: ArgumentType.STRING, menu: `input <>&"'`, defaultValue: `default input <>&"'` }, [`fieldMenu <"'&>`]: { type: `argument type <>&"'`, menu: `field <>&"'`, defaultValue: `default field <>&"'` }, [`image <"'&>`]: { type: ArgumentType.IMAGE, dataURI: `data:<>&"' image input` } } }, { opcode: 'button', blockType: BlockType.BUTTON, text: `'"><& button text`, func: `'"><& func` } ], menus: { [`input <>&"'`]: { acceptReporters: true, items: [ `1 <>&"`, `2 <>&"`, `3 <>&"` ] }, [`field <>&"'`]: { acceptReporters: false, items: [ `1 <>&"`, `2 <>&"`, `3 <>&"` ] } } }; test('XML escaped in Runtime.getBlocksXML()', t => { // While these changes will make the extension unusable in a real editor environment, we still // want to make sure that these fields are actually being escaped. const mangledExtension = JSON.parse(JSON.stringify(baseExtensionInfo)); mangledExtension.color1 = `<"'&amp;color1>`; mangledExtension.color2 = `<"'&amp;color2>`; mangledExtension.color3 = `<"'&amp;color3>`; const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => mangledExtension }); const xmlList = vm.runtime.getBlocksXML(); t.type(xmlList, Array, 'getBlocksXML returns array'); t.equal(xmlList.length, 1, 'array has 1 item'); const xmlEntry = xmlList[0]; t.equal(xmlEntry.id, `xmltest`, 'id worked'); const parsedXml = htmlparser.parseDOM(xmlEntry.xml); t.equal(parsedXml.length, 1, 'xml has 1 root node'); /* Expected XML structure: default value default value default value */ const category = parsedXml[0]; t.equal(category.name, 'category', 'has '); t.equal(category.attribs.name, '<>"'&& Name', 'escaped category name'); t.equal(category.attribs.id, 'xmltest', 'category id'); t.equal(category.attribs.colour, '<"'&amp;amp;color1>', 'escaped category color'); t.equal(category.attribs.secondarycolour, '<"'&amp;amp;color2>', 'escaped category color 2'); t.equal(category.attribs.iconuri, 'data:<>&"' category icon', 'escaped category icon'); t.equal(category.children.length, 3, 'category has 3 children'); // Check docsURI const docsButton = category.children[0]; t.equal(docsButton.name, 'button', 'has docs