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 = `<"'&color1>`;
mangledExtension.color2 = `<"'&color2>`;
mangledExtension.color3 = `<"'&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;color1>', 'escaped category color');
t.equal(category.attribs.secondarycolour, '<"'&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