UNPKG

adxutil

Version:

Utilities tools for Askia Design eXtension

1,200 lines (1,005 loc) 122 kB
describe('ADXValidator', function () { var fs = require('fs'), spies = {}, format = require('util').format, common, adxValidator, Validator, Configurator, errMsg, warnMsg, successMsg, msg; beforeEach(function () { // Clean the cache, obtain a fresh instance of the ADXValidator each time var adxValidatorKey = require.resolve('../../app/validator/ADXValidator.js'), commonKey = require.resolve('../../app/common/common.js'); delete require.cache[commonKey]; common = require('../../app/common/common.js'); delete require.cache[adxValidatorKey]; adxValidator = require('../../app/validator/ADXValidator.js'); Configurator = require('../../app/configurator/ADXConfigurator.js').Configurator; Validator = adxValidator.Validator; var oldValidate = Validator.prototype.validate; spies.validateHook = function () {}; spies.sequence = null; Validator.prototype.validate = function () { this.rootdir = '/root'; if (spies.sequence) { this.validators.sequence = spies.sequence; } spies.validateHook.apply(this, arguments); oldValidate.apply(this, arguments); }; // Messages errMsg = common.messages.error; warnMsg = common.messages.warning; successMsg = common.messages.success; msg = common.messages.message; // Court-circuit the Configurator spyOn(Configurator.prototype, 'load'); // Court-circuit the validation outputs spyOn(common, 'writeError'); spyOn(common, 'writeWarning'); spyOn(common, 'writeSuccess'); spyOn(common, 'writeMessage'); // Court-circuit the access of the filesystem spies.fs = { stat : spyOn(fs, 'stat'), exists : spyOn(fs, 'exists'), readdirSync : spyOn(fs, 'readdirSync'), readFile : spyOn(fs, 'readFile') }; // Add matchers this.addMatchers({ /** * Validate that the actual array contains the expected value * @param {*} expected * @returns {Boolean} */ toContains: function(expected) { var actual = this.actual, notText = this.isNot ? " not" : "", expectedValue = expected; this.message = function () { return "Expected " + actual + notText + " contains " + expectedValue; }; if (!Array.isArray(actual)) { return false; } return actual.some(function (value) { if (Array.isArray(expected)) { expectedValue = value; return (expected.indexOf(value) !== -1); } return value === expected; }); } }); }); // Add extra hook function extraHook(fn){ var previousHook = spies.validateHook; spies.validateHook = function () { previousHook.apply(this, arguments); fn.apply(this, arguments); }; } describe('#validate', function () { beforeEach(function () { spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it("should call each function in the ADXValidator.validators.sequence", function () { var seqLen, callCount = 0; function increment() { callCount++; this.resume(null); } spies.validateHook = function () { var i, seq = this.validators.sequence; for (i = 0, seqLen = seq.length; i < seqLen; i++) { this[seq[i]] = increment; } }; adxValidator.validate(null, 'adx/path/dir'); expect(callCount).toBe(seqLen); }); it("should break the validations when at least one validators call #resume with an error", function () { var key, callCount = 0; function increment() { var err = null; callCount++; if (callCount === 3) { err = new Error("An error occurred in the third validation"); } this.resume(err); } spies.validateHook = function () { var i, seq = this.validators.sequence; for (i = 0, seqLen = seq.length; i < seqLen; i++) { this[seq[i]] = increment; } }; adxValidator.validate(null, 'adx/path/dir'); expect(callCount).toBe(3); }); it("should call the callback function in arg at the end of the validation", function () { var key, wasCalled = false; function fakeValidation() { this.resume(null); } spies.validateHook = function () { var i, seq = this.validators.sequence; for (i = 0, seqLen = seq.length; i < seqLen; i++) { this[seq[i]] = fakeValidation; } }; adxValidator.validate(null, 'adx/path/dir', function () { wasCalled = true; }); expect(wasCalled).toBe(true); }); it("should output error message of the failed validator", function () { spies.validateHook = function () { this.validators.sequence = ['raiseError']; this.raiseError = function () { this.resume(new Error("An error occurred")); }; }; adxValidator.validate(null, 'adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith("An error occurred"); }); it("should run the unit tests when called with the `program#test=true`", function () { var seq; spies.validateHook = function () { this.resume = function () { seq = this.validators.sequence; }; }; adxValidator.validate({ test : true }, 'adx/path/dir'); expect(seq).toContains(['runADXUnitTests']); }); it("should not run the unit tests when called with the `program#test=false`", function () { var seq; spies.validateHook = function () { this.resume = function () { seq = this.validators.sequence; }; }; adxValidator.validate({ test : false }, 'adc/path/dir'); expect(seq).not.toContains(['runADXUnitTests']); }); it("should run the auto unit tests when called with the `program#autoTest=true`", function () { var seq; spies.validateHook = function () { this.resume = function () { seq = this.validators.sequence; }; }; adxValidator.validate({ autoTest : true }, 'adx/path/dir'); expect(seq).toContains(['runAutoTests']); }); it("should not run the auto unit tests when called with the `program#autoTest=false`", function () { var seq; spies.validateHook = function () { this.resume = function () { seq = this.validators.sequence; }; }; adxValidator.validate({ autoTest : false }, 'adx/path/dir'); expect(seq).not.toContains(['runAutoTests']); }); it("should run the xml validation when called with the `program#xml=true`", function () { var seq; spies.validateHook = function () { this.resume = function () { seq = this.validators.sequence; }; }; adxValidator.validate({ xml : true }, 'adx/path/dir'); expect(seq).toContains([ 'validateXMLAgainstXSD', 'initConfigXMLDoc', 'validateADXInfo', 'validateADXInfoConstraints', 'validateADXOutputs', 'validateADXProperties' ]); }); it("should not run the xml validation when called with the `program#xml=false`", function () { var seq; spies.validateHook = function () { this.resume = function () { seq = this.validators.sequence; }; }; adxValidator.validate({ xml : false }, 'adx/path/dir'); expect(seq).not.toContains([ 'validateXMLAgainstXSD', 'initConfigXMLDoc', 'validateADXInfo', 'validateADXInfoConstraints', 'validateADXOutputs', 'validateADXProperties', 'validateMasterPage' ]); }); it("should display a report with the execution time", function () { spies.validateHook = function () { this.validators.sequence = []; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeMessage).toHaveBeenCalledWith(msg.validationFinishedIn, 0); }); it("should display a report using #writeError with the number of success, warnings and failures when at least one error", function () { spies.validateHook = function () { this.validators.sequence = []; this.validators.sequence.length = 8; this.report.runs = 6; this.report.success = 1; this.report.warnings = 2; this.report.errors = 3; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(msg.validationReport,6, 8, 1, 2, 3, 2)); }); it("should display a report in #writeWarning with the number of success, warnings and failures when at least one warning", function () { spies.validateHook = function () { this.validators.sequence = []; this.validators.sequence.length = 6; this.report.runs = 6; this.report.success = 1; this.report.warnings = 2; this.report.errors = 0; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).toHaveBeenCalledWith(format(msg.validationReport, 6, 6, 1, 2, 0, 0)); }); it("should display a report in #writeSuccess with the number of success, warnings and failures when no warning and error", function () { spies.validateHook = function () { this.validators.sequence = []; this.validators.sequence.length = 6; this.report.runs = 6; this.report.success = 1; this.report.warnings = 0; this.report.errors = 0; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeSuccess).toHaveBeenCalledWith(format(msg.validationReport,6, 6, 1, 0, 0, 0)); }); it("should set the #logger when it's defined in the options arg", function () { var instance; spies.validateHook = function () { this.validators.sequence = []; instance = this; }; var logger = { key : "val" }; adxValidator.validate({ logger : logger }, '/adx/path/dir'); expect(instance.logger).toBe(logger); }); it("should set the #printMode when it's defined in the options arg", function () { var instance; spies.validateHook = function () { this.validators.sequence = []; instance = this; }; adxValidator.validate({ printMode : 'html' }, '/adx/path/dir'); expect(instance.printMode).toBe('html'); }); }); describe('#validatePathArg', function () { beforeEach(function () { // Modify the sequence of the validation to only call the validatePathArg method spies.sequence = ['validatePathArg']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it("should output an error when the path specified doesn't exist", function () { spies.fs.stat.andCallFake(function (path, callback) { callback(new Error("No such file or directory")); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.noSuchFileOrDirectory, "\\adx\\path\\dir")); }); it("should not output an error when the path specified exist", function () { spies.fs.stat.andCallFake(function (path, callback) { callback(null); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it("should use the current directory when the path is not specified", function () { spyOn(process, 'cwd').andReturn('/cwd/'); var dir; spies.validateHook = function () { dir = this.adxDirectoryPath; }; adxValidator.validate(null); expect(dir).toBe('/cwd/'); }); }); describe('#validateADXDirectoryStructure', function () { beforeEach(function () { // Modify the sequence of the validation to only call the validateADXDirectoryStructure method spies.sequence = ['validateADXDirectoryStructure']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it("should output an error when the config.xml file doesn't exist", function () { spies.fs.exists.andCallFake(function (path, callback) { callback(false); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(errMsg.noConfigFile); }); it("should not output an error when the config.xml file exist", function () { spies.fs.exists.andCallFake(function (path, callback) { callback(true); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it("should output a success message when the config.xml file exist", function () { spies.fs.exists.andCallFake(function (path, callback) { callback(true); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeSuccess).toHaveBeenCalled(); }); it("should search the `resources` directory", function () { var searchResourcesDirectory = false; spies.fs.exists.andCallFake(function (path, callback) { callback(true); }); spies.fs.stat.andCallFake(function (path) { if (path === '\\adx\\path\\dir\\resources') { searchResourcesDirectory = true; } }); adxValidator.validate('null', '/adx/path/dir'); expect(searchResourcesDirectory).toBe(true); }); function loadResourcesDirectory(mode) { it("should search the `resources/" + mode + "/` directory", function () { var searchResources = false; spies.fs.exists.andCallFake(function (path, callback) { callback(true); }); spies.fs.stat.andCallFake(function (path, callback) { if (path === '\\adx\\path\\dir\\resources') { callback(null, true); } else if (path === '\\adx\\path\\dir\\resources\\' + mode) { searchResources = true; } else { callback(null, false); } }); adxValidator.validate('null', '/adx/path/dir'); expect(searchResources).toBe(true); }); it("should load files from the `resources/" + mode + "/` directory", function () { var files = ['123.txt', '456.html'], key = (mode === 'static') ? 'statics' : mode, instance; spies.fs.exists.andCallFake(function (path, callback) { callback(true); }); spies.validateHook = function () { instance = this; }; spies.fs.stat.andCallFake(function (path, callback) { if (path === '\\adx\\path\\dir\\resources') { callback(null, true); } else if (path === '\\adx\\path\\dir\\resources\\' + mode) { callback(null, true); } else { callback(null, false); } }); spies.fs.readdirSync.andReturn(files); spyOn(common, 'isIgnoreFile').andReturn(false); adxValidator.validate(null, '/adx/path/dir'); expect(instance.dirResources[key]).toEqual({ isExist : true, '123.txt' : '123.txt', '456.html' : '456.html' }); }); it("should ignore certain files from the `resources/" + mode + "/` directory", function () { var files = ['123.txt', '456.html', 'Thumbs.db'], key = (mode === 'static') ? 'statics' : mode, instance; spies.fs.exists.andCallFake(function (path, callback) { callback(true); }); spies.validateHook = function () { instance = this; }; spies.fs.stat.andCallFake(function (path, callback) { if (path === '\\adx\\path\\dir\\resources') { callback(null, true); } else if (path === '\\adx\\path\\dir\\resources\\' + mode) { callback(null, true); } else { callback(null, false); } }); spies.fs.readdirSync.andReturn(files); spyOn(common, 'isIgnoreFile').andCallFake(function (f) { return (f === 'Thumbs.db'); }); adxValidator.validate('null', '/adx/path/dir'); expect(instance.dirResources[key]).toEqual({ isExist : true, '123.txt' : '123.txt', '456.html' : '456.html' }); }); } ['dynamic', 'static', 'share'].forEach(loadResourcesDirectory); }); describe('#validateFileExtensions', function () { beforeEach(function () { // Modify the sequence of the validation to only call the validateFileExtensions method spies.sequence = ['validateFileExtensions']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); var directories = ['dynamic', 'static', 'share']; function testForbiddenExtensionIn(directoryName) { it('should output an error when found in `' + directoryName + '` directory', function () { (directoryName = directoryName === 'static' ? 'statics' : directoryName); spies.validateHook = function () { var dirResources = this.dirResources; dirResources.isExist = true; dirResources[directoryName].isExist = true; dirResources[directoryName]['filewithforbiddenextension.exe'] = 'filewithforbiddenextension.exe'; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.fileExtensionForbidden, ".exe")); }); } function testTrustExtensionIn(directoryName) { it('should not output an error when found in `' + directoryName + '` directory', function () { (directoryName = directoryName === 'static' ? 'statics' : directoryName); spies.validateHook = function () { var dirResources = this.dirResources; dirResources.isExist = true; dirResources[directoryName].isExist = true; dirResources[directoryName]['trustfileextension.html'] = 'trustfileextension.html'; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it('should not output a warning when found in `' + directoryName + '` directory', function () { (directoryName = directoryName === 'static' ? 'statics' : directoryName); spies.validateHook = function () { var dirResources = this.dirResources; dirResources.isExist = true; dirResources[directoryName].isExist = true; dirResources[directoryName]['trustfileextension.html'] = 'trustfileextension.html'; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).not.toHaveBeenCalled(); }); } function testUnknownExtensionIn(directoryName) { it('should output a warning when found in `' + directoryName + '` directory', function () { (directoryName = directoryName === 'static' ? 'statics' : directoryName); spies.validateHook = function () { var dirResources = this.dirResources; dirResources.isExist = true; dirResources[directoryName].isExist = true; dirResources[directoryName]['unknownextension.unknown'] = 'unknownextension.unknown'; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).toHaveBeenCalledWith(warnMsg.untrustExtension, 'unknownextension.unknown'); }); } describe('file with forbidden extension', function () { directories.forEach(testForbiddenExtensionIn); }); describe('file with trust extension', function () { directories.forEach(testTrustExtensionIn); }); describe('file with unknown extension', function () { directories.forEach(testUnknownExtensionIn); }); describe('all files are valid', function () { beforeEach(function () { spies.validateHook = function () { var dirResources = this.dirResources; dirResources.isExist = true; dirResources.dynamic.isExist = true; dirResources.statics.isExist = true; dirResources.share.isExist = true; dirResources.dynamic['valid.html'] = 'valid.html'; dirResources.statics['valid.js'] = 'valid.js'; dirResources.share['valid.css'] = 'valid.css'; }; }) it('should not output an error', function () { adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it('should output a success message', function () { adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeSuccess).toHaveBeenCalledWith(successMsg.fileExtensionValidate); }); }); describe('at least one invalid files', function () { it('should output an error', function () { spies.validateHook = function () { var dirResources = this.dirResources; dirResources.isExist = true; dirResources.dynamic.isExist = true; dirResources.statics.isExist = true; dirResources.share.isExist = true; dirResources.dynamic['valid.html'] = 'valid.html'; dirResources.statics['valid.js'] = 'valid.js'; dirResources.statics['invalid.exe'] = 'invalid.exe'; dirResources.share['valid.css'] = 'valid.css'; }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalled(); }); }); }); describe('#initConfigXMLDoc', function () { var validatorInstance = null; beforeEach(function () { validatorInstance = null; spies.validateHook = function () { validatorInstance = this; }; // Modify the sequence of the validation to only call the initConfigXMLDoc method spies.sequence = ['initConfigXMLDoc']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it("should init and load the ADXConfigurator", function () { adxValidator.validate(null, '/adx/path/dir'); expect(validatorInstance.adxConfigurator instanceof Configurator).toBe(true); expect(validatorInstance.adxConfigurator.path).toEqual('\\adx\\path\\dir'); expect(Configurator.prototype.load).toHaveBeenCalled(); }); it("should output an error when the ADXConfigurator could not load the xml", function () { Configurator.prototype.load.andCallFake(function (cb) { cb(new Error("Fake error")); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalled(); }); it("should not output an error when the ADXConfigurator was successfully loaded", function () { Configurator.prototype.load.andCallFake(function (cb) { cb(null); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it("should remove the validateMasterPage in the sequence while using an ADC", function () { Configurator.prototype.load.andCallFake(function (cb) { this.fromXml('<control></control>'); cb(null); }); spies.sequence = ['initConfigXMLDoc', 'validateMasterPage']; adxValidator.validate(null, '/adx/path/dir'); expect(validatorInstance.validators.sequence).toEqual(['initConfigXMLDoc']); expect(validatorInstance.report.total).toEqual(1); }); it("should remove the validateADXInfoConstraints in the sequence while using an ADP", function () { Configurator.prototype.load.andCallFake(function (cb) { this.fromXml('<page></page>'); cb(null); }); spies.sequence = ['initConfigXMLDoc', 'validateADXInfoConstraints']; adxValidator.validate(null, '/adx/path/dir'); expect(validatorInstance.validators.sequence).toEqual(['initConfigXMLDoc']); expect(validatorInstance.report.total).toEqual(1); }); }); describe('#validateXMLAgainstXSD', function () { beforeEach(function () { // Modify the sequence of the validation to only call the validateXMLAgainstXSD method spies.sequence = ['validateXMLAgainstXSD']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it('should run the xmllint process with the 2.0.0alpha/Config.xsd and the config.xml file with old ADC 2.0 namespace', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control xmlns="http://www.askia.com/ADCSchema"></control>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command) { expect(command).toBe('"\\root\\lib\\libxml\\xmllint.exe" --noout --schema "\\root\\schema\\2.0.0alpha\\Config.xsd" "\\adx\\path\\dir\\config.xml"'); }); adxValidator.validate(null, '/adx/path/dir'); expect(childProc.exec).toHaveBeenCalled(); }); it('should run the xmllint process with the 2.0.0/ADCSchema.xsd and the config.xml file with ADC 2.0', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control></control>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command) { expect(command).toBe('"\\root\\lib\\libxml\\xmllint.exe" --noout --schema "\\root\\schema\\2.0.0\\ADCSchema.xsd" "\\adx\\path\\dir\\config.xml"'); }); adxValidator.validate(null, '/adx/path/dir'); expect(childProc.exec).toHaveBeenCalled(); }); it('should run the xmllint process with the 2.1.0/ADCSchema.xsd and the config.xml file with ADC 2.1', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control version="2.1.0"></control>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command) { expect(command).toBe('"\\root\\lib\\libxml\\xmllint.exe" --noout --schema "\\root\\schema\\2.1.0\\ADCSchema.xsd" "\\adx\\path\\dir\\config.xml"'); }); adxValidator.validate(null, '/adx/path/dir'); expect(childProc.exec).toHaveBeenCalled(); }); it('should run the xmllint process with the 2.1.0/ADPSchema.xsd and the config.xml file with ADP 2.1', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<page version="2.1.0"></page>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command) { expect(command).toBe('"\\root\\lib\\libxml\\xmllint.exe" --noout --schema "\\root\\schema\\2.1.0\\ADPSchema.xsd" "\\adx\\path\\dir\\config.xml"'); }); adxValidator.validate(null, '/adx/path/dir'); expect(childProc.exec).toHaveBeenCalled(); }); it('should output an error when the xmllint process failed', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control></control>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command, callback) { callback(new Error('Fake validation error')); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalled(); }); it("should not output an error when the xmllint process doesn't failed", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control></control>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command, callback) { callback(null); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it("should output a success when the xmllint process doesn't failed", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control></control>'); }; var childProc = require('child_process'); spyOn(childProc, 'exec').andCallFake(function (command, callback) { callback(null); }); adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeSuccess).toHaveBeenCalledWith(successMsg.xsdValidate); }); }); describe("#validateADXInfo", function () { beforeEach(function () { // Modify the sequence of the validation to only call the validateADXInfo method spies.sequence = ['validateADXInfo']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it("should output an error when the info doesn't exist", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(errMsg.missingInfoNode); }); it("should output an error when the info/name doesn't exist", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(errMsg.missingOrEmptyNameNode); }); it("should output an error when the info/name is empty", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><name></name></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(errMsg.missingOrEmptyNameNode); }); it("should not output an error when the info/name is valid", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><name>Something</name></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it("should initialize the adxName property with the name of the ADX", function () { var instance; spies.validateHook = function () { instance = this; this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><name>test</name></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(instance.adxName).toBe('test'); }); it("should output a warning when the `style` tag is used with ADC 2.1", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control version="2.1.0"><info><name>something</name><style width="200" height="400" /></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).toHaveBeenCalledWith(warnMsg.deprecatedInfoStyleTag); }); it("should not output a warning when the `style` tag is used with ADC 2.0", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><name>something</name><style width="200" height="400" /></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).not.toHaveBeenCalledWith(warnMsg.deprecatedInfoStyleTag); }); it("should output a warning when the `categories` tag is used with ADC 2.1", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control version="2.1.0"><info><name>something</name><categories><category>test</category></categories></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).toHaveBeenCalledWith(warnMsg.deprecatedInfoCategoriesTag); }); it("should not output a warning when the `categories` tag is used with ADC 2.0", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><name>something</name><categories><category>test</category></categories></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).not.toHaveBeenCalledWith(warnMsg.deprecatedInfoCategoriesTag); }); }); describe('#validateADXInfoConstraints', function () { beforeEach(function () { // Modify the sequence of the validation to only call the validateADXInfoConstraints method spies.sequence = ['validateADXInfoConstraints']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); var elements = ['questions', 'responses', 'controls'], constraintAttrs = [ { name : 'chapter', on : 'questions' }, { name : 'single', on : 'questions' }, { name : 'multiple', on : 'questions' }, { name : 'open', on : 'questions' }, { name : 'numeric', on : 'questions' }, { name : 'date', on : 'questions' }, { name : 'requireParentLoop', on : 'questions' }, { name : 'min', on : 'responses' }, { name : 'max', on : 'responses' }, { name : 'label', on : 'controls' }, { name : 'checkbox', on : 'controls' }, { name : 'textbox', on : 'controls' }, { name : 'listbox', on : 'controls' }, { name : 'radiobutton', on : 'controls' }, { name : 'responseblock', on : 'controls' } ], fakeAttr = { 'questions' : 'single', 'responses' : 'min', 'controls' : 'label' }; function testDuplicateConstraints(element) { it("should output an error when 2 constraints defined on " + element, function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><constraints>' + '<constraint on="' + element + '" ' + fakeAttr[element] + '="1"></constraint>' + '<constraint on="' + element + '" ' + fakeAttr[element] + '="1"></constraint>' + '</constraints></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.duplicateConstraints, element)); }); } elements.forEach(testDuplicateConstraints); function testRequireConstraint(element) { it("should output an error when no constraint defined on `" + element + "`", function () { var oppositeElement = (element === 'questions') ? 'controls' : 'questions'; spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><constraints>' + '<constraint on="' + oppositeElement + '" ' + fakeAttr[oppositeElement] + '="1"></constraint>' + '</constraints></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.requireConstraintOn, element)); }); } ['questions', 'controls'].forEach(testRequireConstraint); it("should not output an error when constraints are defined on `questions` and `controls`", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><constraints>' + '<constraint on="questions" single="true"></constraint>' + '<constraint on="controls" label="true"></constraint>' + '</constraints></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); function testConstraintAttribute(element) { describe('constraint@on=' + element, function () { constraintAttrs.forEach(function (attribute) { var notText = (attribute.on === element) ? 'not ' : ''; it("should " + notText + "output an error when the attribute `" + attribute.name + "` is present", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><constraints>' + '<constraint on="' + element + '" ' + attribute.name + '="true"></constraint>' + '</constraints></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); if (attribute.on === element) { expect(Validator.prototype.writeError).not.toHaveBeenCalledWith(format(errMsg.invalidConstraintAttribute, element, attribute.name)); } else { expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.invalidConstraintAttribute, element, attribute.name)); } }); }); it("should output an error when no other attribute is specified", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><constraints>' + '<constraint on="' + element + '"></constraint>' + '</constraints></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.noRuleOnConstraint, element)); }); if (element !== 'responses') { it("should output an error when no other attribute is specified with the truthly value", function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><info><constraints>' + '<constraint on="' + element + '" ' + fakeAttr[element] + '="false"></constraint>' + '</constraints></info></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).toHaveBeenCalledWith(format(errMsg.noRuleOnConstraint, element)); }); } }); } elements.forEach(testConstraintAttribute); }); describe('#validateADXOutputs', function () { beforeEach(function () { // Modify the sequence of the validation to only call the validateADXOutputs method spies.sequence = ['validateADXOutputs']; spyOn(Validator.prototype, 'writeError'); spyOn(Validator.prototype, 'writeWarning'); spyOn(Validator.prototype, 'writeSuccess'); spyOn(Validator.prototype, 'writeMessage'); }); it('should output a warning when duplicate conditions', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><outputs>' + '<output id="first" defaultGeneration="true">' + '<condition>duplicate condition</condition>'+ '</output>' + '<output id="second" defaultGeneration="true">' + '<condition>duplicate condition</condition>'+ '</output>' + '</outputs></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeWarning).toHaveBeenCalledWith(warnMsg.duplicateOutputCondition, "first", "second"); }); it('should not output an error when one condition is empty', function () { spies.validateHook = function () { this.adxConfigurator = new Configurator('/adx/path/dir'); this.adxConfigurator.fromXml('<control><outputs>' + '<output id="empty" defaultGeneration="true">' + '</output>' + '</outputs></control>'); }; adxValidator.validate(null, '/adx/path/dir'); expect(Validator.prototype.writeError).not.toHaveBeenCalled(); }); it('should output an error when at least two conditions are empty', function () { spies.validateHook = function () {