<commit_before>var expect = require('chai').expect
    should = require('chai').should()
    sinon = require('sinon')
    proxyquire = require('proxyquire').noCallThru()
    path = require('path')

describe('update', function () {
    var update,
        _mocks,
        _deps,
        _got,
        _res,
        _cache,
        _file,
        _unpack,
        _directory,
        _logger

    beforeEach(function () {
        _deps = {
            context: {
                name: 'test',
                appDir: '/test'
            },
            dependencies: [],
            plugins: []
        }
        _res = { on: sinon.stub() }
        _got = sinon.stub().returns(_res)
        _cache = {
            get: sinon.stub()
        }
        _file = {
            readJson: sinon.stub(),
            writeJson: sinon.stub()
        }
        _directory = {
            create: sinon.stub(),
            remove: sinon.stub(),
            appDir: sinon.stub().returns('/test')
        }
        _unpack = {

        }
        _logger = {
            log: sinon.stub(),
            info: sinon.stub(),
            warn: sinon.stub(),
            error: sinon.stub(),
            debug: sinon.stub()
        }
        _mocks = {
            'got': _got,
            './unpack.js': _unpack,
            './cache.js': _cache,
            './file.js': _file,
            './directory.js': _directory,
            './logger.js': _logger
        }
        update = proxyquire('../lib/update.js', _mocks)

        _got.withArgs(sinon.match.string, {json:true}).callsArgWith(2, null, { versions: { '1.0.0': {}, '1.0.1': {} }, dist: { tarball: 'http://test.com/update.tgz' } })
        _cache.get.callsArgWith(5, null)
        _file.readJson.callsArgWith(1, null, { dependencies: {} })
        _file.writeJson.callsArgWith(2, null)
        _directory.create.callsArgWith(1, null)
        _directory.remove.callsArgWith(1, null)
    })

    describe('app', function () {
        describe('update available', function () {
            beforeEach(function () {
                _deps.app = { name: 'test', available: '1.0.1' }
            })
            describe('in dev environment', function () {
                beforeEach(function () {
                    _deps.context.dev = true
                })
                it('should not update the app', function (done) {
                    update.update(_deps, '/electron', _logger, function (err) {
                        expect(_got.called).to.be.false
                        done(err)
                    })
                })
            })
            it('should update the app', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.true
                    expect(_cache.get.called).to.be.true
                    done(err)
                })
            })
            it('should download binaries', function (done) {
                var pkg = { binaries: ['http://example.com/test.tgz'] }
                _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_cache.get.withArgs('http://example.com/test.tgz').called).to.be.true
                    done(err)
                })
            })
        })
        describe('update not available', function () {
            it('should not update the app if its not out of date', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.false
                    done(err)
                })
            })
        })
    })

    describe('dependencies', function () {
        beforeEach(function () {
            _deps.dependencies.push({ name: 'test', available: '1.0.1' })
        })
        describe('in dev environment', function () {
            beforeEach(function () {
                _deps.context.dev = true
            })
            it('should not update dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.false
                    done(err)
                })
            })
        })
        it('should update dependencies', function (done) {
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_got.called).to.be.true
                expect(_cache.get.called).to.be.true
                done(err)
            })
        })
        it('should download binaries', function (done) {
            var pkg = { binaries: ['http://example.com/test.tgz'] }
            _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_cache.get.withArgs('http://example.com/test.tgz').called).to.be.true
                done(err)
            })
        })
        describe('with sub-dependencies', function () {
            beforeEach(function () {
                var pkg = { dependencies: { testSub: '^1.0.0' } }
                _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
                _file.readJson.onSecondCall().callsArgWith(1, null, pkg)
            })
            it('should get sub dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.callCount).to.equal(3)
                    done(err)
                })
            })
            it('should extract sub dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_cache.get.calledTwice).to.be.true
                    done(err)
                })
            })
        })
    })

    describe('plugins', function () {
        beforeEach(function () {
            _deps.plugins.push({ name: 'test', available: '1.0.1' })
        })
        describe('in dev environment', function () {
            it('should update plugins', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.true
                    expect(_cache.get.called).to.be.true
                    done(err)
                })
            })
        })
        describe('with sub-dependencies', function () {
            beforeEach(function () {
                var pkg = { dependencies: { testSub: '^1.0.0' } }
                _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
                _file.readJson.onSecondCall().callsArgWith(1, null, pkg)
            })
            it('should get sub dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.callCount).to.equal(3)
                    done(err)
                })
            })
            it('should extract sub dependencies', function (done) {
                update.update(_deps, '/electron',  _logger, function (err) {
                    expect(_cache.get.calledTwice).to.be.true
                    done(err)
                })
            })
        })
        it('should download binaries', function (done) {
            var pkg = { binaries: ['http://example.com/test.tgz'] }
            _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_cache.get.withArgs('http://example.com/test.tgz').called).to.be.true
                done(err)
            })
        })
        it('should update plugins', function (done) {
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_got.called).to.be.true
                expect(_cache.get.called).to.be.true
                done(err)
            })
        })
        it('should update the .current file', function (done) {
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_file.writeJson.called).to.be.true
                done(err)
            })
        })
    })
})<commit_msg>fix update tests<commit_after>var expect = require('chai').expect
    should = require('chai').should()
    sinon = require('sinon')
    proxyquire = require('proxyquire').noCallThru()
    path = require('path')

describe('update', function () {
    var update,
        _mocks,
        _deps,
        _got,
        _res,
        _cache,
        _file,
        _unpack,
        _directory,
        _logger

    beforeEach(function () {
        _deps = {
            context: {
                name: 'test',
                appDir: '/test'
            },
            dependencies: [],
            plugins: []
        }
        _res = { on: sinon.stub() }
        _got = sinon.stub().returns(_res)
        _cache = {
            get: sinon.stub()
        }
        _file = {
            readJson: sinon.stub(),
            writeJson: sinon.stub()
        }
        _directory = {
            create: sinon.stub(),
            remove: sinon.stub(),
            appDir: sinon.stub().returns('/test')
        }
        _unpack = {

        }
        _logger = {
            log: sinon.stub(),
            info: sinon.stub(),
            warn: sinon.stub(),
            error: sinon.stub(),
            debug: sinon.stub()
        }
        _mocks = {
            'got': _got,
            './unpack.js': _unpack,
            './cache.js': _cache,
            './file.js': _file,
            './directory.js': _directory,
            './logger.js': _logger
        }
        update = proxyquire('../lib/update.js', _mocks)

        _got.withArgs(sinon.match.string, {json:true}).callsArgWith(2, null, { versions: { '1.0.0': {}, '1.0.1': {} }, dist: { tarball: 'http://test.com/update.tgz' } })
        _cache.get.callsArgWith(6, null)
        _file.readJson.callsArgWith(1, null, { dependencies: {} })
        _file.writeJson.callsArgWith(2, null)
        _directory.create.callsArgWith(1, null)
        _directory.remove.callsArgWith(1, null)
    })

    describe('app', function () {
        describe('update available', function () {
            beforeEach(function () {
                _deps.app = { name: 'test', available: '1.0.1' }
            })
            describe('in dev environment', function () {
                beforeEach(function () {
                    _deps.context.dev = true
                })
                it('should not update the app', function (done) {
                    update.update(_deps, '/electron', _logger, function (err) {
                        expect(_got.called).to.be.false
                        done(err)
                    })
                })
            })
            it('should update the app', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.true
                    expect(_cache.get.called).to.be.true
                    done(err)
                })
            })
            it('should download binaries', function (done) {
                var pkg = { binaries: ['http://example.com/test.tgz'] }
                _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_cache.get.withArgs('http://example.com/test.tgz').called).to.be.true
                    done(err)
                })
            })
        })
        describe('update not available', function () {
            it('should not update the app if its not out of date', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.false
                    done(err)
                })
            })
        })
    })

    describe('dependencies', function () {
        beforeEach(function () {
            _deps.dependencies.push({ name: 'test', available: '1.0.1' })
        })
        describe('in dev environment', function () {
            beforeEach(function () {
                _deps.context.dev = true
            })
            it('should not update dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.false
                    done(err)
                })
            })
        })
        it('should update dependencies', function (done) {
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_got.called).to.be.true
                expect(_cache.get.called).to.be.true
                done(err)
            })
        })
        it('should download binaries', function (done) {
            var pkg = { binaries: ['http://example.com/test.tgz'] }
            _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_cache.get.withArgs('http://example.com/test.tgz').called).to.be.true
                done(err)
            })
        })
        describe('with sub-dependencies', function () {
            beforeEach(function () {
                var pkg = { dependencies: { testSub: '^1.0.0' } }
                _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
                _file.readJson.onSecondCall().callsArgWith(1, null, pkg)
            })
            it('should get sub dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.callCount).to.equal(3)
                    done(err)
                })
            })
            it('should extract sub dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_cache.get.calledTwice).to.be.true
                    done(err)
                })
            })
        })
    })

    describe('plugins', function () {
        beforeEach(function () {
            _deps.plugins.push({ name: 'test', available: '1.0.1' })
        })
        describe('in dev environment', function () {
            it('should update plugins', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.called).to.be.true
                    expect(_cache.get.called).to.be.true
                    done(err)
                })
            })
        })
        describe('with sub-dependencies', function () {
            beforeEach(function () {
                var pkg = { dependencies: { testSub: '^1.0.0' } }
                _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
                _file.readJson.onSecondCall().callsArgWith(1, null, pkg)
            })
            it('should get sub dependencies', function (done) {
                update.update(_deps, '/electron', _logger, function (err) {
                    expect(_got.callCount).to.equal(3)
                    done(err)
                })
            })
            it('should extract sub dependencies', function (done) {
                update.update(_deps, '/electron',  _logger, function (err) {
                    expect(_cache.get.calledTwice).to.be.true
                    done(err)
                })
            })
        })
        it('should download binaries', function (done) {
            var pkg = { binaries: ['http://example.com/test.tgz'] }
            _file.readJson.onFirstCall().callsArgWith(1, null, pkg)
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_cache.get.withArgs('http://example.com/test.tgz').called).to.be.true
                done(err)
            })
        })
        it('should update plugins', function (done) {
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_got.called).to.be.true
                expect(_cache.get.called).to.be.true
                done(err)
            })
        })
        it('should update the .current file', function (done) {
            update.update(_deps, '/electron', _logger, function (err) {
                expect(_file.writeJson.called).to.be.true
                done(err)
            })
        })
    })
})<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

// Limits taken from WasmLimits.h
const MaxTypes = 1000000;
const MaxFunctions = 1000000;
const MaxImports = 100000;
const MaxExports = 100000;
const MaxGlobals = 1000000;
const MaxDataSegments = 100000;
const MaxElementSegments = 10000000;
const MaxTableSize = 10000000;

const MaxStringSize = 100000;
const MaxFunctionLocals = 50000;
const MaxFunctionParams = 1000;
const MaxBrTableElems = 1000000;

const MaxMemoryInitialPages = 16384;
const MaxMemoryMaximumPages = 65536;
const MaxModuleSize = 1024 * 1024 * 1024;
const MaxFunctionSize = 7654321;

/* global assert,testRunner */ // eslint rule
WScript.LoadScriptFile("../UnitTestFrameWork/UnitTestFrameWork.js");
WScript.LoadScriptFile("../wasmspec/testsuite/harness/wasm-constants.js");
WScript.LoadScriptFile("../wasmspec/testsuite/harness/wasm-module-builder.js");
WScript.Flag("-off:wasmdeferred");

function compile(moduleStr) {
  const buf = WebAssembly.wabt.convertWast2Wasm(moduleStr);
  return new WebAssembly.Module(buf);
}

const notTooLongName = "a".repeat(MaxStringSize);
const tooLongName = "a".repeat(MaxStringSize + 1);

function makeLimitTests(opt) {
  return [{
    name: "valid: " + opt.name,
    validTest: true,
    body() {
      const builder = new WasmModuleBuilder();
      opt.makeModule(builder, opt.limit);
      assert.doesNotThrow(() => new WebAssembly.Module(builder.toBuffer()), `WebAssembly should allow up to ${opt.limit} ${opt.type}`);
    }
  }, {
    name: "invalid: " + opt.name,
    invalidTest: true,
    body() {
      const builder = new WasmModuleBuilder();
      opt.makeModule(builder, opt.limit + 1);
      assert.throws(() => new WebAssembly.Module(builder.toBuffer()), WebAssembly.CompileError, `WebAssembly should not allow ${opt.limit + 1} ${opt.type}`, opt.errorMsg);
    }
  }];
}

const tests = [
  // Tests 0,1
  ...makeLimitTests({
    name: "test max types",
    limit: MaxTypes,
    type: "types",
    errorMsg: "Too many signatures",
    makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addType(kSig_v_v);}}
  }),
  // Tests 2,3
  ...makeLimitTests({
    name: "test max functions",
    limit: MaxFunctions,
    type: "functions",
    errorMsg: "Too many functions",
    makeModule: (builder, limit) => {
      const typeIndex = builder.addType(kSig_v_v);
      for (let i = 0; i < limit; ++i) {builder.addFunction(null, typeIndex).addBody([]);}
    }
  }),
  // Tests 4,5
  ...makeLimitTests({
    name: "test max imports",
    limit: MaxImports,
    type: "imports",
    errorMsg: "Too many imports",
    makeModule: (builder, limit) => {
      const typeIndex = builder.addType(kSig_v_v);
      for (let i = 0; i < limit; ++i) {builder.addImport("", "", typeIndex);}
    }
  }),
  // Tests 6,7
  ...makeLimitTests({
    name: "test max exports",
    limit: MaxExports,
    type: "exports",
    errorMsg: "Too many exports",
    makeModule: (builder, limit) => {
      builder.addFunction(null, kSig_v_v).addBody([]);
      for (let i = 0; i < limit; ++i) {builder.addExport("" + i, 0);}
    }
  }),
  // Tests 8,9
  ...makeLimitTests({
    name: "test max globals",
    limit: MaxGlobals,
    type: "globals",
    errorMsg: "Too many globals",
    makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addGlobal(kWasmI32, /* mutable */ false);}}
  }),
  // Tests 10,11
  ...makeLimitTests({
    name: "test max data segments",
    limit: MaxDataSegments,
    type: "data segments",
    errorMsg: "Too many data segments",
    makeModule: (builder, limit) => {
      builder.addMemory(0);
      for (let i = 0; i < limit; ++i) {builder.addDataSegment(0, "");}
    }
  }),
  // Tests 12,13
  ...makeLimitTests({
    name: "test max element segments",
    limit: MaxElementSegments,
    type: "element segments",
    errorMsg: "Too many element segments",
    makeModule: (builder, limit) => {
      builder.addFunction(null, kSig_v_v).addBody([]);
      builder.setFunctionTableLength(1);
      builder.function_table_inits.length = limit;
      builder.function_table_inits.fill({base: 0, is_global: false, array: [0]})
    }
  }),
  // Test 14
  {
    name: "test max table size",
    body() {
      assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize}));
      assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize, maximum: MaxTableSize}));
      assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize}));
      assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1}));
      assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1, maximum: MaxTableSize + 1}));
      assert.throws(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize + 1}));

      assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} anyfunc))`));
      assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} ${MaxTableSize} anyfunc))`));
      assert.doesNotThrow(() => compile(`(module (table 0 ${MaxTableSize} anyfunc))`));
      assert.throws(() => compile(`(module (table ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
      assert.throws(() => compile(`(module (table ${MaxTableSize + 1} ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
      assert.throws(() => compile(`(module (table 0 ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
    }
  },
  // Test 15
  {
    name: "test custom sections with long names",
    body() {
      function makeCustomSection(name) {
        const customSection = new Binary();
        customSection.emit_section(0, section => {
          section.emit_string(name)
          section.emit_string("payload")
        });
        const builder = new WasmModuleBuilder();
        builder.addExplicitSection(customSection);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeCustomSection(notTooLongName));
      assert.throws(() => makeCustomSection(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Test 16
  {
    name: "test exports with long names",
    body() {
      function makeExportName(name)
      {
        const builder = new WasmModuleBuilder();
        builder
          .addFunction(name, kSig_v_v)
          .exportFunc()
          .addBody([]);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeExportName(notTooLongName));
      assert.throws(() => makeExportName(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Test 17
  {
    name: "test imports with long names",
    body() {
      function makeImportName(name)
      {
        const builder = new WasmModuleBuilder();
        builder.addImport(name, 'b', kSig_v_v);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeImportName(notTooLongName));
      assert.throws(() => makeImportName(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Test 18
  {
    name: "test Name section with long names",
    body() {
      function makeName(name)
      {
        const builder = new WasmModuleBuilder();
        builder
          .addFunction(notTooLongName, kSig_v_v)
          .addBody([]);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeName(notTooLongName));
      // todo:: enable test once we start using the Name section
      // assert.throws(() => makeName(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Tests 19,20
  ...makeLimitTests({
    name: "test max function locals",
    limit: MaxFunctionLocals,
    type: "locals",
    makeModule: (builder, limit) => {
      builder.addFunction(null, kSig_v_v).addLocals({i32_count: limit}).addBody([]);
    }
  }),
  // Tests 21,22
  ...makeLimitTests({
    name: "test max function params",
    limit: MaxFunctionParams,
    type: "params",
    errorMsg: "Too many arguments in signature",
    makeModule: (builder, limit) => {
      builder.addFunction(null, {params: (new Array(limit)).fill(kWasmI32), results: []}).addBody([]);
    }
  }),
  // Tests 23
  {
    name: "test max memory pages",
    body() {
      assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages}));
      assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages, maximum: MaxMemoryMaximumPages}));
      assert.doesNotThrow(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages}));
      assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1}));
      assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1, maximum: MaxMemoryMaximumPages + 1}));
      assert.throws(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages + 1}));

      assert.doesNotThrow(() => compile(`(module (memory ${MaxMemoryInitialPages}))`));
      assert.doesNotThrow(() => compile(`(module (memory ${MaxMemoryInitialPages} ${MaxMemoryMaximumPages}))`));
      assert.doesNotThrow(() => compile(`(module (memory 0 ${MaxMemoryMaximumPages}))`));
      assert.throws(() => compile(`(module (memory ${MaxMemoryInitialPages + 1}))`), WebAssembly.CompileError, "Minimum memory size too big");
      assert.throws(() => compile(`(module (memory ${MaxMemoryInitialPages + 1} ${MaxMemoryMaximumPages + 1}))`), WebAssembly.CompileError, "Minimum memory size too big");
      assert.throws(() => compile(`(module (memory 0 ${MaxMemoryMaximumPages + 1}))`), WebAssembly.CompileError, "Maximum memory size too big");
    }
  },
  // Tests 24
  {
    name: "test max module size",
    body() {
      assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize)), WebAssembly.CompileError, "Malformed WASM module header");
      assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize + 1)), WebAssembly.CompileError, "Module too big");
    }
  },
  // Tests 25,26
  ...makeLimitTests({
    name: "test max function size",
    limit: MaxFunctionSize,
    type: "size",
    errorMsg: "Function body too big",
    makeModule: (builder, limit) => {
      // limit -1 (number of locals byte) -1 (endOpCode)
      builder.addFunction(null, kSig_v_v).addBody((new Array(limit - 2)).fill(kExprNop));
    }
  }),
  // todo:: test MaxBrTableElems
];

WScript.LoadScriptFile("../UnitTestFrameWork/yargs.js");
const argv = yargsParse(WScript.Arguments, {
  boolean: ["valid", "invalid", "verbose"],
  number: ["start", "end"],
  default: {
    verbose: true,
    valid: true,
    invalid: true,
    start: 0,
    end: tests.length
  }
}).argv;

const todoTests = tests
  .slice(argv.start, argv.end)
  .filter(test => (!test.invalidTest || argv.invalid) &&
                  (!test.validTest || argv.valid));

testRunner.run(todoTests, {verbose: argv.verbose});
<commit_msg>Fix limit test by not using wabt. Wabt was throwing when parsing the .wast and we need the invalid module to test our validation. Fixes #4302<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

// Limits taken from WasmLimits.h
const MaxTypes = 1000000;
const MaxFunctions = 1000000;
const MaxImports = 100000;
const MaxExports = 100000;
const MaxGlobals = 1000000;
const MaxDataSegments = 100000;
const MaxElementSegments = 10000000;
const MaxTableSize = 10000000;

const MaxStringSize = 100000;
const MaxFunctionLocals = 50000;
const MaxFunctionParams = 1000;
const MaxBrTableElems = 1000000;

const MaxMemoryInitialPages = 16384;
const MaxMemoryMaximumPages = 65536;
const MaxModuleSize = 1024 * 1024 * 1024;
const MaxFunctionSize = 7654321;

/* global assert,testRunner */ // eslint rule
WScript.LoadScriptFile("../UnitTestFrameWork/UnitTestFrameWork.js");
WScript.LoadScriptFile("../wasmspec/testsuite/harness/wasm-constants.js");
WScript.LoadScriptFile("../wasmspec/testsuite/harness/wasm-module-builder.js");
WScript.Flag("-off:wasmdeferred");

function compile(moduleStr) {
  const buf = WebAssembly.wabt.convertWast2Wasm(moduleStr);
  return new WebAssembly.Module(buf);
}

const notTooLongName = "a".repeat(MaxStringSize);
const tooLongName = "a".repeat(MaxStringSize + 1);

function makeLimitTests(opt) {
  return [{
    name: "valid: " + opt.name,
    validTest: true,
    body() {
      const builder = new WasmModuleBuilder();
      opt.makeModule(builder, opt.limit);
      assert.doesNotThrow(() => new WebAssembly.Module(builder.toBuffer()), `WebAssembly should allow up to ${opt.limit} ${opt.type}`);
    }
  }, {
    name: "invalid: " + opt.name,
    invalidTest: true,
    body() {
      const builder = new WasmModuleBuilder();
      opt.makeModule(builder, opt.limit + 1);
      assert.throws(() => new WebAssembly.Module(builder.toBuffer()), WebAssembly.CompileError, `WebAssembly should not allow ${opt.limit + 1} ${opt.type}`, opt.errorMsg);
    }
  }];
}

const tests = [
  // Tests 0,1
  ...makeLimitTests({
    name: "test max types",
    limit: MaxTypes,
    type: "types",
    errorMsg: "Too many signatures",
    makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addType(kSig_v_v);}}
  }),
  // Tests 2,3
  ...makeLimitTests({
    name: "test max functions",
    limit: MaxFunctions,
    type: "functions",
    errorMsg: "Too many functions",
    makeModule: (builder, limit) => {
      const typeIndex = builder.addType(kSig_v_v);
      for (let i = 0; i < limit; ++i) {builder.addFunction(null, typeIndex).addBody([]);}
    }
  }),
  // Tests 4,5
  ...makeLimitTests({
    name: "test max imports",
    limit: MaxImports,
    type: "imports",
    errorMsg: "Too many imports",
    makeModule: (builder, limit) => {
      const typeIndex = builder.addType(kSig_v_v);
      for (let i = 0; i < limit; ++i) {builder.addImport("", "", typeIndex);}
    }
  }),
  // Tests 6,7
  ...makeLimitTests({
    name: "test max exports",
    limit: MaxExports,
    type: "exports",
    errorMsg: "Too many exports",
    makeModule: (builder, limit) => {
      builder.addFunction(null, kSig_v_v).addBody([]);
      for (let i = 0; i < limit; ++i) {builder.addExport("" + i, 0);}
    }
  }),
  // Tests 8,9
  ...makeLimitTests({
    name: "test max globals",
    limit: MaxGlobals,
    type: "globals",
    errorMsg: "Too many globals",
    makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addGlobal(kWasmI32, /* mutable */ false);}}
  }),
  // Tests 10,11
  ...makeLimitTests({
    name: "test max data segments",
    limit: MaxDataSegments,
    type: "data segments",
    errorMsg: "Too many data segments",
    makeModule: (builder, limit) => {
      builder.addMemory(0);
      for (let i = 0; i < limit; ++i) {builder.addDataSegment(0, "");}
    }
  }),
  // Tests 12,13
  ...makeLimitTests({
    name: "test max element segments",
    limit: MaxElementSegments,
    type: "element segments",
    errorMsg: "Too many element segments",
    makeModule: (builder, limit) => {
      builder.addFunction(null, kSig_v_v).addBody([]);
      builder.setFunctionTableLength(1);
      builder.function_table_inits.length = limit;
      builder.function_table_inits.fill({base: 0, is_global: false, array: [0]})
    }
  }),
  // Test 14
  {
    name: "test max table size",
    body() {
      assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize}));
      assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize, maximum: MaxTableSize}));
      assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize}));
      assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1}));
      assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1, maximum: MaxTableSize + 1}));
      assert.throws(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize + 1}));

      assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} anyfunc))`));
      assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} ${MaxTableSize} anyfunc))`));
      assert.doesNotThrow(() => compile(`(module (table 0 ${MaxTableSize} anyfunc))`));
      assert.throws(() => compile(`(module (table ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
      assert.throws(() => compile(`(module (table ${MaxTableSize + 1} ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
      assert.throws(() => compile(`(module (table 0 ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
    }
  },
  // Test 15
  {
    name: "test custom sections with long names",
    body() {
      function makeCustomSection(name) {
        const customSection = new Binary();
        customSection.emit_section(0, section => {
          section.emit_string(name)
          section.emit_string("payload")
        });
        const builder = new WasmModuleBuilder();
        builder.addExplicitSection(customSection);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeCustomSection(notTooLongName));
      assert.throws(() => makeCustomSection(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Test 16
  {
    name: "test exports with long names",
    body() {
      function makeExportName(name)
      {
        const builder = new WasmModuleBuilder();
        builder
          .addFunction(name, kSig_v_v)
          .exportFunc()
          .addBody([]);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeExportName(notTooLongName));
      assert.throws(() => makeExportName(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Test 17
  {
    name: "test imports with long names",
    body() {
      function makeImportName(name)
      {
        const builder = new WasmModuleBuilder();
        builder.addImport(name, 'b', kSig_v_v);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeImportName(notTooLongName));
      assert.throws(() => makeImportName(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Test 18
  {
    name: "test Name section with long names",
    body() {
      function makeName(name)
      {
        const builder = new WasmModuleBuilder();
        builder
          .addFunction(notTooLongName, kSig_v_v)
          .addBody([]);
        return new WebAssembly.Module(builder.toBuffer());
      }
      assert.doesNotThrow(() => makeName(notTooLongName));
      // todo:: enable test once we start using the Name section
      // assert.throws(() => makeName(tooLongName), WebAssembly.CompileError, "Name too long");
    }
  },
  // Tests 19,20
  ...makeLimitTests({
    name: "test max function locals",
    limit: MaxFunctionLocals,
    type: "locals",
    makeModule: (builder, limit) => {
      builder.addFunction(null, kSig_v_v).addLocals({i32_count: limit}).addBody([]);
    }
  }),
  // Tests 21,22
  ...makeLimitTests({
    name: "test max function params",
    limit: MaxFunctionParams,
    type: "params",
    errorMsg: "Too many arguments in signature",
    makeModule: (builder, limit) => {
      builder.addFunction(null, {params: (new Array(limit)).fill(kWasmI32), results: []}).addBody([]);
    }
  }),
  // Tests 23
  {
    name: "test max memory pages",
    body() {
      assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages}));
      assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages, maximum: MaxMemoryMaximumPages}));
      assert.doesNotThrow(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages}));
      assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1}));
      assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1, maximum: MaxMemoryMaximumPages + 1}));
      assert.throws(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages + 1}));

      const makeModule = (min, max) => {
        const builder = new WasmModuleBuilder();
        builder.addMemory(min, max);
        return new WebAssembly.Module(builder.toBuffer());
      };

      assert.doesNotThrow(() => makeModule(MaxMemoryInitialPages));
      assert.doesNotThrow(() => makeModule(MaxMemoryInitialPages, MaxMemoryMaximumPages));
      assert.doesNotThrow(() => makeModule(0, MaxMemoryMaximumPages));
      assert.throws(() => makeModule(MaxMemoryInitialPages + 1), WebAssembly.CompileError, "Minimum memory size too big");
      assert.throws(() => makeModule(MaxMemoryInitialPages + 1, MaxMemoryMaximumPages + 1), WebAssembly.CompileError, "Minimum memory size too big");
      assert.throws(() => makeModule(0, MaxMemoryMaximumPages + 1), WebAssembly.CompileError, "Maximum memory size too big");
    }
  },
  // Tests 24
  {
    name: "test max module size",
    body() {
      assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize)), WebAssembly.CompileError, "Malformed WASM module header");
      assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize + 1)), WebAssembly.CompileError, "Module too big");
    }
  },
  // Tests 25,26
  ...makeLimitTests({
    name: "test max function size",
    limit: MaxFunctionSize,
    type: "size",
    errorMsg: "Function body too big",
    makeModule: (builder, limit) => {
      // limit -1 (number of locals byte) -1 (endOpCode)
      builder.addFunction(null, kSig_v_v).addBody((new Array(limit - 2)).fill(kExprNop));
    }
  }),
  // todo:: test MaxBrTableElems
];

WScript.LoadScriptFile("../UnitTestFrameWork/yargs.js");
const argv = yargsParse(WScript.Arguments, {
  boolean: ["valid", "invalid", "verbose"],
  number: ["start", "end"],
  default: {
    verbose: true,
    valid: true,
    invalid: true,
    start: 0,
    end: tests.length
  }
}).argv;

const todoTests = tests
  .slice(argv.start, argv.end)
  .filter(test => (!test.invalidTest || argv.invalid) &&
                  (!test.validTest || argv.valid));

testRunner.run(todoTests, {verbose: argv.verbose});
<|endoftext|>


<commit_before>// xss-blacklist-test.js
//
// Test the XSS blacklist middleware
//
// Copyright 2016 Alex Jordan <alex@strugee.net>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

"use strict";

var assert = require("assert"),
    vows = require("vows"),
    _ = require("lodash"),
    Step = require("step"),
    Browser = require("zombie"),
    oauthutil = require("./lib/oauth"),
    apputil = require("./lib/app"),
    http = require("http"),
    withAppSetup = apputil.withAppSetup,
    br;

vows.describe("XSS blacklist middleware").addBatch(
    withAppSetup({
        "and we visit the home page with an IE11 User-Agent header": {
            topic: function(app) {
                var callback = this.callback;
                br = new Browser({runScripts: false});

                br.userAgent = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
                br.visit("http://localhost:4815/", callback);
            },
            "it works": function(err) {
                assert.ifError(err);
                br.assert.success();
            },
            "it has a status code of 200": function() {
                br.assert.status(200);
            }
        }
    })
).addBatch(
    withAppSetup({
        "and we visit the home page with an IE10 User-Agent header": {
            topic: function(app) {
                var callback = this.callback;

                br.userAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)";
                // TODO: this shows errors even though it technically succeeds
                br.visit("http://localhost:4815/");
                br.wait();
                // TODO: this is hacky
                setTimeout(callback, 3000);
            },
            "it works": function(err) {
                assert.ifError(err);
            },
            "it has a status code of 400": function() {
                br.assert.status(400);
            }
        }
    })
)["export"](module);
<commit_msg>Remove some unnecessary requires<commit_after>// xss-blacklist-test.js
//
// Test the XSS blacklist middleware
//
// Copyright 2016 Alex Jordan <alex@strugee.net>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

"use strict";

var assert = require("assert"),
    vows = require("vows"),
    Browser = require("zombie"),
    apputil = require("./lib/app"),
    withAppSetup = apputil.withAppSetup,
    br;

vows.describe("XSS blacklist middleware").addBatch(
    withAppSetup({
        "and we visit the home page with an IE11 User-Agent header": {
            topic: function(app) {
                var callback = this.callback;
                br = new Browser({runScripts: false});

                br.userAgent = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
                br.visit("http://localhost:4815/", callback);
            },
            "it works": function(err) {
                assert.ifError(err);
                br.assert.success();
            },
            "it has a status code of 200": function() {
                br.assert.status(200);
            }
        }
    })
).addBatch(
    withAppSetup({
        "and we visit the home page with an IE10 User-Agent header": {
            topic: function(app) {
                var callback = this.callback;

                br.userAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)";
                // TODO: this shows errors even though it technically succeeds
                br.visit("http://localhost:4815/");
                br.wait();
                // TODO: this is hacky
                setTimeout(callback, 3000);
            },
            "it works": function(err) {
                assert.ifError(err);
            },
            "it has a status code of 400": function() {
                br.assert.status(400);
            }
        }
    })
)["export"](module);
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var yeoman = require('yeoman-generator');
var path = require("path");

var InteractionGenerator = module.exports = function InteractionGenerator(args, options, config) {
    // By calling `NamedBase` here, we get the argument to the subgenerator call
    // as `this.name`.
    yeoman.generators.NamedBase.apply(this, arguments);

    console.log('You called the interaction subgenerator with the argument ' + this.name + '.');
};

util.inherits(InteractionGenerator, yeoman.generators.NamedBase);

InteractionGenerator.prototype.updateGeneratorYui3 = function updateGeneratorYui3() {

    this.projectName = this._currentProjectName();

    this.projectNameToAdd = arguments[0];
    this.base = arguments[1];

    var stringData = this.readFileAsString(path.join(__dirname, "../app/templates/.generator-yui3.json"));

    var filePath = path.join(process.cwd(), ".generator-yui3.json");

    var file = JSON.parse(this.readFileAsString(filePath));

    file.interactions[this.projectNameToAdd] = {};
    file.interactions[this.projectNameToAdd].base = this.base;

    this.write(filePath, JSON.stringify(file));

};

InteractionGenerator.prototype.updateLoaderCommon = function updateLoaderCommon() {

    var stringData = this.readFileAsString(path.join(__dirname, "../app/templates/loader/tests/_common.js"));
    var yui3GenOriginFilePath = path.join(process.cwd(), ".generator-yui3.json");
    var interactions = JSON.parse(this.readFileAsString(yui3GenOriginFilePath)).interactions;

    var keys = Object.keys(interactions),
        i,
        iLength = keys.length,
        projectName, value, base;

    for (i = 0; i < iLength; i++) {
        projectName = keys[i];
        value = interactions[projectName];
        base = value.base;
        console.log(projectName);
        console.log(value);

        stringData += "\n// " + projectName + "\n";
        stringData += "YUI_config.groups." + projectName + ".combine = false\n";
        stringData += "YUI_config.groups." + projectName + ".base = \"" + base + "\"\n";
        stringData += "YUI_config.groups." + projectName + ".filter = (window.location.search.match(/[?&]filter=([^&]+)/) || [])[1] || 'raw'";

    }

    this.write(path.join(process.cwd(), "src/" + this.projectName + "-loader/tests/common.js"), this.engine(stringData, {
        "projectName": this.projectName
    }));

}

// get currentProjectName
InteractionGenerator.prototype._currentProjectName = function _currentProjectName() {
    var pkg = JSON.parse(this.readFileAsString(path.join(process.cwd(), './package.json')));
    return pkg.name;
};
<commit_msg>add interaction/index.js fn<commit_after>'use strict';
var util = require('util');
var yeoman = require('yeoman-generator');
var path = require("path");

var InteractionGenerator = module.exports = function InteractionGenerator(args, options, config) {
    // By calling `NamedBase` here, we get the argument to the subgenerator call
    // as `this.name`.
    yeoman.generators.NamedBase.apply(this, arguments);

    console.log('You called the interaction subgenerator with the argument ' + this.name + '.');
};

util.inherits(InteractionGenerator, yeoman.generators.NamedBase);

InteractionGenerator.prototype.setPaths = function setPaths() {

    this.generatorYUI3FilePath = path.join(process.cwd(), ".generator-yui3.json");

};

InteractionGenerator.prototype.updateGeneratorYui3 = function updateGeneratorYui3() {

    this.projectName = this._currentProjectName();

    this.projectNameToAdd = arguments[0];
    this.base = arguments[1];

    var stringData = this.readFileAsString(path.join(__dirname, "../app/templates/.generator-yui3.json"));

    var file = JSON.parse(this.readFileAsString(this.generatorYUI3FilePath));

    file.interactions[this.projectNameToAdd] = {};
    file.interactions[this.projectNameToAdd].base = this.base;

    this.write(this.generatorYUI3FilePath, JSON.stringify(file));

};

InteractionGenerator.prototype.updateLoaderCommon = function updateLoaderCommon() {

    var stringData = this.readFileAsString(path.join(__dirname, "../app/templates/loader/tests/_common.js"));
    var interactions = JSON.parse(this.readFileAsString(this.generatorYUI3FilePath)).interactions;

    var keys = Object.keys(interactions),
        i,
        iLength = keys.length,
        projectName, value, base;

    for (i = 0; i < iLength; i++) {
        projectName = keys[i];
        value = interactions[projectName];
        base = value.base;
        console.log(projectName);
        console.log(value);

        stringData += "\n// " + projectName + "\n";
        stringData += "YUI_config.groups." + projectName + ".combine = false\n";
        stringData += "YUI_config.groups." + projectName + ".base = \"" + base + "\"\n";
        stringData += "YUI_config.groups." + projectName + ".filter = (window.location.search.match(/[?&]filter=([^&]+)/) || [])[1] || 'raw'";

    }

    this.write(path.join(process.cwd(), "src/" + this.projectName + "-loader/tests/common.js"), this.engine(stringData, {
        "projectName": this.projectName
    }));

    var muVar = this._lookForProjectRoot
    console.log(muVar);

}

// get currentProjectName
InteractionGenerator.prototype._currentProjectName = function _currentProjectName() {
    var pkg = JSON.parse(this.readFileAsString(path.join(process.cwd(), './package.json')));
    return pkg.name;

};

/*
 * @method _lookForProjectRoot
 *
 */
TestgenGenerator.prototype._lookForProjectRoot = function _lookForProjectRoot() {
    var model = "";

    while (true) {

        var pathFile = path.join(process.cwd(), model, './package.json');
        if (fs.existsSync(pathFile)) {
            return pathFile;
        }
        //change path
        model = model + "../";
    }

};
<|endoftext|>


<commit_before>var dhcp_server = require('node-dhcpd');
var netmask = require('netmask').Netmask;
var ee = require('events').EventEmitter;
var util = require('util');
var clone = require('clone');
var async = require('async');

var requests = {};
function _clean_request(mac_addr){
  if(requests[mac_addr]) {
    if( requests[mac_addr].offer && requests[mac_addr].offer.timeout_id){
      clearTimeout(requests[mac_addr].offer.timeout_id);
    }
    requests[mac_addr] = null;
    delete requests[mac_addr];
  }
}

const
  BOOTREQUEST       = 1,
  DHCP_MESSAGE_TYPE = 0x35,
  DHCP_SERVER_ID    = 0x36,
  DHCP_DISCOVER     = 1,
  DHCP_INFORM       = 8,
  DHCP_MINTYPE      = DHCP_DISCOVER,
  DHCP_MAXTYPE      = DHCP_INFORM,
  DHCP_REQUESTED_IP = 0x32,
  DHCP_HOST_NAME    = 0x0c;

var leases = {};
var ip_map = {};
function lease_store (){
  return this;
}
lease_store.prototype.remove_lease = function remove_lease (mac_addr, cb) {
  // XXX this should probably be made to be a lot more careful
  this.get_lease(mac_addr, function(lease){
    delete ip_map[ lease.yiaddr ];
    delete leases[mac_addr];
    cb();
  });
}
lease_store.prototype.save_lease = function save_lease (lease, cb) {
  var mac_addr = lease.chaddr;
  leases[mac_addr] = clone(lease);
  ip_map[lease.yiaddr] = mac_addr;
  cb();
};
lease_store.prototype.get_lease = function get_lease (mac_addr, cb) {
  var lease;
  if(leases[mac_addr]){
    // ensure we return a new copy!!
    lease = clone(leases[mac_addr]);
  }
  cb(lease);
};
lease_store.prototype.get_lease_by_ip = function get_lease_by_ip (ip, cb) {
  var lease;
  if(ip_map[ip]){
    lease = clone(leases[ ip_map[ip] ]);
  }
  cb(lease);
};
lease_store.prototype.get_next_ip = function get_next_ip (cb) {
  var latest = Object.keys(ip_map).sort()[-1];
  if(!latest) return cb(undefined);
  var next_ip = (ip2long(latest) + 1);
  cb(long2ip(next_ip));
};

function dhcpd (opts) {
  var self = this;
  if(!(self instanceof dhcpd)){
    return new dhcpd(opts);
  }
  ee.call(self);

  self.s = dhcp_server.createServer('udp4');
  self.s.on("listening", function () {
      var address = self.s.address();
      console.log("server listening ------> " +
        address.address + ":" + address.port);
  });

  // cidr
  if(opts.subnet){
    var block = new netmask(opts.subnet);
    if(block){
      self.subnet_range = opts.range_start + "-" + opts.range_end;
      self.start_end    = self.subnet_range.split('-');
      self.network      = block.base;
      self.netmask      = block.mask;
      self.broadcast    = block.broadcast;

      self.routers       = opts.routers || [];
      self.nameservers   = opts.nameservers || [];
      self.default_lease = opts.default_lease || 3600;
                         // default lease time of one hour
      self.host = opts.host;
    } else {
      throw new Error("Unable to grok network details from '"+opts.subnet+"'");
    }
  }

  self.s.on('discover', self.discover.bind(self));
  self.s.on('request', self.request.bind(self));
  self.s.on('decline', self.decline.bind(self));
  self.s.on('release', self.release.bind(self));

  self.save_lease       = opts.save_lease;
  self.get_lease        = opts.get_lease;
  self.get_lease_by_ip  = opts.get_lease_by_ip;
  self.get_next_ip      = opts.get_next_ip;
  self.remove_lease     = opts.remove_lease;

  self.s.bind(67, '0.0.0.0', function() {
    self.s.setBroadcast(true);
    self.s.setTTL(255)
    self.s.setMulticastTTL(255);
    self.s.addMembership('239.255.255.249', self.host);
    self.s.setMulticastLoopback(true);
  });
  return self;
}
util.inherits(dhcpd, ee);

function _get_option(pkt, opt) {
  return pkt.options[opt];
}

dhcpd.prototype.pre_init = function pre_init (pkt, cb) {
  var self = this;
  // Ignore packet
  if(pkt.hlen != 6) return;

  // Ignore if this isn't a BOOTREQUEST
  if(pkt.op != BOOTREQUEST) return;

  var state = _get_option(pkt, DHCP_MESSAGE_TYPE);
  if(state == undefined || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) return;

  // Get SERVER_ID if present
  var server_id_opt = _get_option(pkt, DHCP_SERVER_ID);
  //console.dir(server_id_opt);
  if (server_id_opt) {
    if (server_id_opt != self.host) {
      return;
    }
  }

  // Look for a static/dynamic lease
  self.get_lease(pkt.chaddr, function(lease){
    // Get REQUESTED_IP if present
    var requested_ip = _get_option(pkt, DHCP_REQUESTED_IP);
    //console.dir(requested_ip_opt);
    return cb(lease, requested_ip);
  });

}

dhcpd.prototype.discover = function discover (pkt) {
    var self = this;
    console.log("Got DISCOVER request");

    var offer = {};
    offer.siaddr = self.host;
    offer.options = clone(pkt.options);
    offer.options['1'] = self.netmask;
    offer.options['3'] = self.routers;
    offer.options['28'] = self.broadcast;
    offer.options['51'] = self.default_lease;

    async.waterfall([
      function($cb){
        self.pre_init(pkt, function(lease, requested_ip){
          $cb(null, lease, requested_ip);
        });
      },
      function(lease, requested_ip, $cb) {
        if(lease){
          console.log("Using pre-existing lease's offer", lease);
          offer = lease.offer;
          return;
        }

        console.log("Creating new lease");
        var ip = requested_ip;
        if(ip && !self.get_lease_by_ip(ip) ){
          // An IP has been requested and isn't in use

          // If we recieve an IP as part of the discover, make sure it's in our range
          // otherwise NAK to put client back into INIT mode
          if( ip && (ip2long(self.start_end[0]) <= ip2long(ip) <= ip2long(self.start_end[1])) ){
            // Supplied IP is within the range
            console.log("Using ip requested by client");
            offer.yiaddr = ip;
            $cb(null);
          } else {
            console.log("Client requested invalid IP");
            return self.s.nak(pkt);
          }
        } else {
          // We need to get a new IP
          console.log("Getting new IP");
          self.get_next_ip(function (new_ip) {
            if(new_ip == undefined) new_ip = self.start_end[0];
            if(new_ip && (ip2long(self.start_end[0]) <= ip2long(new_ip) <= ip2long(self.start_end[1])) ){
              console.log("Using new IP of: "+new_ip);
              offer.yiaddr = new_ip;
              $cb(null);
            } else {
              // We don't have a new IP to offer =0(
              console.log("Unable to find IP for use, ignoring");
              return;
            }
          });
        }
        //var dhcp_host_opt = _get_option(pkt, DHCP_HOST_NAME);
        //offer.options[ DHCP_HOST_NAME ] = dhcp_host_opt;

      }
    ],
    function(err, result){

      // Set a short-term record so we can match against XID
      if(!requests[pkt.chaddr]){
        // Lets forget about this request after 60 seconds
        var cleanup = function(){
          _clean_request(pkt.chaddr);
        };

        requests[pkt.chaddr] = {
          xid: pkt.xid,
          chaddr: pkt.chaddr,
          offer: offer,
          when: new Date(),
          timeout_id: setTimeout(cleanup, 60000)
        };
      }

      console.log("Making an offer:\n\tmac: "+pkt.chaddr+"\n\tip: "+offer.yiaddr);
      return self.s.offer(pkt, offer);
    });

};

dhcpd.prototype.request = function request (pkt) {
    var self = this;
    var cur_request = requests[pkt.chaddr];
    console.log("GOT REQUEST");
    if(cur_request) {
      // We're serving a request based on a DISCOVER

      // if we'll receive a request from a client
      // which sent a discover before but the xid
      // does not match, discard the offer we sent
      if(cur_request && cur_request.xid && cur_request.xid !== pkt.xid) {
        _clean_request(pkt.chaddr);
        return self.s.nak(pkt);
      }

      if(cur_request && cur_request.offer){
        console.log("Receieved valid request from '"+pkt.chaddr+"' for ip '"+cur_request.offer.yiaddr+"'");
        var mac_addr = pkt.chaddr + '';
        console.log("mac: "+mac_addr+"   chaddr:"+pkt.chaddr);
        var offer = clone(cur_request.offer);
        self.save_lease({
          yiaddr: cur_request.offer.yiaddr,
          offer: offer,
          chaddr: mac_addr
        }, function() {
          console.log("DONE");
          _clean_request(pkt.chaddr);
          return self.s.ack(pkt, offer);
        });
      }
    } else {
      // We're serving a request from a client that either didn't
      // run a DISCOVER or has come back from reboot in INIT-REBOOT
      // phase
      // OR
      // we're getting a request due to the client going into RENEW
      // OR
      // we're getting a request from the client because it's lease
      // is about to expire
      console.log("ATTEMPTING TO GET LEASE FOR:  "+pkt.chaddr);
      self.get_lease(pkt.chaddr, function(lease){
        if(lease) {
          // we got a lease back, lets update it and
          var offer = {};
          console.log("Got lease for host --- " +pkt.chaddr);
          //self.set_lease(offer, pkt);
          self.save_lease({
            chaddr: pkt.chaddr,
            yiaddr: lease.yiaddr,
            offer: clone(lease.offer)
          }, function(){
            return self.s.ack(pkt); // ???
          });
        } else {
          console.log("Didn't find a matching lease for this host");
          //_clean_request(pkt.chaddr);
          return self.s.nak(pkt);
        }

      });
    }
};

dhcpd.prototype.decline = function decline (pkt) {
    var cur_request = requests[pkt.chaddr];
    if(cur_request && cur_request.offer){
      self.remove_lease(pkt.chaddr, function(){
        _clean_request(pkt.chaddr);
      });
    }
    return;
};

dhcpd.prototype.release = function release (pkt) {
    var cur_request = requests[pkt.chaddr];
    // We shouldn't really get into a position where we've got a request
    // without a lease, but lets double check
    if(cur_request && cur_request.offer){
      _clean_request(pkt.chaddr);
    }
    self.remove_lease(pkt.chaddr, function(){});
};

dhcpd.prototype.inform = function inform (pkt) {
  // not currently supporting INFORM, so ignore
  return;
};

function long2ip(ip) {
  if (!isFinite(ip))
    return false;
  return '' + [ip >>> 24, ip >>> 16 & 0xFF, ip >>> 8 & 0xFF, ip & 0xFF].join('.');
}

function ip2long (ip_address) {
  var parts = ip_address.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
  return parts.length == 5 ?
      parseInt(+parts[1],10) * 16777216 + parseInt(+parts[2],10) * 65536 +
      parseInt(+parts[3],10) * 256      + parseInt(+parts[4],10) * 1
    : false;
};

var store = new lease_store();

var server = new dhcpd({
    subnet: '192.168.119.0/24',
    range_start: '192.168.119.30',
    range_end: '192.168.119.60',
    routers: [ '192.168.119.1' ],
    nameservers: [ '8.8.8.8', '8.8.4.4' ],
    //set_lease: set_lease,
    save_lease: function(lease, cb){ store.save_lease(lease, cb) },
    get_lease: function(mac_addr, cb){ store.get_lease(mac_addr, cb) },
    get_lease_by_ip: function(ip, cb){ store.get_lease_by_ip(ip, cb) },
    get_next_ip: function(cb){ store.get_next_ip(cb) },
    remove_lease: function(mac_addr, cb){ store.remove_lease(mac_addr, cb) },
    host: '192.168.119.1'
});

module.exports = dhcpd;
<commit_msg>Tidy up the request handler<commit_after>var dhcp_server = require('node-dhcpd');
var netmask = require('netmask').Netmask;
var ee = require('events').EventEmitter;
var util = require('util');
var clone = require('clone');
var async = require('async');

var requests = {};
function _clean_request(mac_addr){
  if(requests[mac_addr]) {
    if( requests[mac_addr].offer && requests[mac_addr].offer.timeout_id){
      clearTimeout(requests[mac_addr].offer.timeout_id);
    }
    requests[mac_addr] = null;
    delete requests[mac_addr];
  }
}

const
  BOOTREQUEST       = 1,
  DHCP_MESSAGE_TYPE = 0x35,
  DHCP_SERVER_ID    = 0x36,
  DHCP_DISCOVER     = 1,
  DHCP_INFORM       = 8,
  DHCP_MINTYPE      = DHCP_DISCOVER,
  DHCP_MAXTYPE      = DHCP_INFORM,
  DHCP_REQUESTED_IP = 0x32,
  DHCP_HOST_NAME    = 0x0c;

var leases = {};
var ip_map = {};
function lease_store (){
  return this;
}
lease_store.prototype.remove_lease = function remove_lease (mac_addr, cb) {
  // XXX this should probably be made to be a lot more careful
  this.get_lease(mac_addr, function(lease){
    delete ip_map[ lease.yiaddr ];
    delete leases[mac_addr];
    cb();
  });
}
lease_store.prototype.save_lease = function save_lease (lease, cb) {
  var mac_addr = lease.chaddr;
  leases[mac_addr] = clone(lease);
  ip_map[lease.yiaddr] = mac_addr;
  cb();
};
lease_store.prototype.get_lease = function get_lease (mac_addr, cb) {
  var lease;
  if(leases[mac_addr]){
    // ensure we return a new copy!!
    lease = clone(leases[mac_addr]);
  }
  cb(lease);
};
lease_store.prototype.get_lease_by_ip = function get_lease_by_ip (ip, cb) {
  var lease;
  if(ip_map[ip]){
    lease = clone(leases[ ip_map[ip] ]);
  }
  cb(lease);
};
lease_store.prototype.get_next_ip = function get_next_ip (cb) {
  var latest = Object.keys(ip_map).sort()[-1];
  if(!latest) return cb(undefined);
  var next_ip = (ip2long(latest) + 1);
  cb(long2ip(next_ip));
};

function dhcpd (opts) {
  var self = this;
  if(!(self instanceof dhcpd)){
    return new dhcpd(opts);
  }
  ee.call(self);

  self.s = dhcp_server.createServer('udp4');
  self.s.on("listening", function () {
      var address = self.s.address();
      console.log("server listening ------> " +
        address.address + ":" + address.port);
  });

  // cidr
  if(opts.subnet){
    var block = new netmask(opts.subnet);
    if(block){
      self.subnet_range = opts.range_start + "-" + opts.range_end;
      self.start_end    = self.subnet_range.split('-');
      self.network      = block.base;
      self.netmask      = block.mask;
      self.broadcast    = block.broadcast;

      self.routers       = opts.routers || [];
      self.nameservers   = opts.nameservers || [];
      self.default_lease = opts.default_lease || 3600;
                         // default lease time of one hour
      self.host = opts.host;
    } else {
      throw new Error("Unable to grok network details from '"+opts.subnet+"'");
    }
  }

  self.s.on('discover', self.discover.bind(self));
  self.s.on('request', self.request.bind(self));
  self.s.on('decline', self.decline.bind(self));
  self.s.on('release', self.release.bind(self));

  self.save_lease       = opts.save_lease;
  self.get_lease        = opts.get_lease;
  self.get_lease_by_ip  = opts.get_lease_by_ip;
  self.get_next_ip      = opts.get_next_ip;
  self.remove_lease     = opts.remove_lease;

  self.s.bind(67, '0.0.0.0', function() {
    //self.s.setBroadcast(true);
    //self.s.setTTL(255)
    self.s.setMulticastTTL(255);
    self.s.addMembership('239.255.255.249', self.host);
    self.s.setMulticastLoopback(true);
  });
  return self;
}
util.inherits(dhcpd, ee);

function _get_option(pkt, opt) {
  return pkt.options[opt];
}

dhcpd.prototype.pre_init = function pre_init (pkt, cb) {
  var self = this;
  // Ignore packet
  if(pkt.hlen != 6) return;

  // Ignore if this isn't a BOOTREQUEST
  if(pkt.op != BOOTREQUEST) return;

  var state = _get_option(pkt, DHCP_MESSAGE_TYPE);
  if(state == undefined || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) return;

  // Get SERVER_ID if present
  var server_id_opt = _get_option(pkt, DHCP_SERVER_ID);
  //console.dir(server_id_opt);
  if (server_id_opt) {
    if (server_id_opt != self.host) {
      return;
    }
  }

  // Look for a static/dynamic lease
  self.get_lease(pkt.chaddr, function(lease){
    // Get REQUESTED_IP if present
    var requested_ip = _get_option(pkt, DHCP_REQUESTED_IP);
    //console.dir(requested_ip_opt);
    return cb(lease, requested_ip);
  });

}

dhcpd.prototype.discover = function discover (pkt) {
    var self = this;
    console.log("Got DISCOVER request");

    var offer = {};
    offer.siaddr = self.host;
    offer.options = clone(pkt.options);
    offer.options['1'] = self.netmask;
    offer.options['3'] = self.routers;
    offer.options['28'] = self.broadcast;
    offer.options['51'] = self.default_lease;

    async.waterfall([
      function($cb){
        self.pre_init(pkt, function(lease, requested_ip){
          $cb(null, lease, requested_ip);
        });
      },
      function(lease, requested_ip, $cb) {
        if(lease){
          console.log("Using pre-existing lease's offer", lease);
          offer = lease.offer;
          return;
        }

        console.log("Creating new lease");
        var ip = requested_ip;
        if(ip && !self.get_lease_by_ip(ip) ){
          // An IP has been requested and isn't in use

          // If we recieve an IP as part of the discover, make sure it's in our range
          // otherwise NAK to put client back into INIT mode
          if( ip && (ip2long(self.start_end[0]) <= ip2long(ip) <= ip2long(self.start_end[1])) ){
            // Supplied IP is within the range
            console.log("Using ip requested by client");
            offer.yiaddr = ip;
            $cb(null);
          } else {
            console.log("Client requested invalid IP");
            return self.s.nak(pkt);
          }
        } else {
          // We need to get a new IP
          console.log("Getting new IP");
          self.get_next_ip(function (new_ip) {
            if(new_ip == undefined) new_ip = self.start_end[0];
            if(new_ip && (ip2long(self.start_end[0]) <= ip2long(new_ip) <= ip2long(self.start_end[1])) ){
              console.log("Using new IP of: "+new_ip);
              offer.yiaddr = new_ip;
              $cb(null);
            } else {
              // We don't have a new IP to offer =0(
              console.log("Unable to find IP for use, ignoring");
              return;
            }
          });
        }
        //var dhcp_host_opt = _get_option(pkt, DHCP_HOST_NAME);
        //offer.options[ DHCP_HOST_NAME ] = dhcp_host_opt;

      }
    ],
    function(err, result){

      // Set a short-term record so we can match against XID
      if(!requests[pkt.chaddr]){
        // Lets forget about this request after 60 seconds
        var cleanup = function(){
          _clean_request(pkt.chaddr);
        };

        requests[pkt.chaddr] = {
          xid: pkt.xid,
          chaddr: pkt.chaddr,
          offer: offer,
          when: new Date(),
          timeout_id: setTimeout(cleanup, 60000)
        };
      }

      console.log("Making an offer:\n\tmac: "+pkt.chaddr+"\n\tip: "+offer.yiaddr);
      return self.s.offer(pkt, offer);
    });

};

dhcpd.prototype.request = function request (pkt) {
    var self = this;
    var cur_request = requests[pkt.chaddr];
    console.log("GOT REQUEST");
    self.pre_init(pkt, function(lease, requested_ip) {
      if(cur_request) {
        // We're serving a request based on a DISCOVER

        // if we'll receive a request from a client
        // which sent a discover before but the xid
        // does not match, discard the offer we sent
        if(cur_request && cur_request.xid && cur_request.xid !== pkt.xid) {
          _clean_request(pkt.chaddr);
          return self.s.nak(pkt);
        }

        if(cur_request && cur_request.offer){
          console.log("Receieved valid request from '"+pkt.chaddr+"' for ip '"+cur_request.offer.yiaddr+"'");
          var mac_addr = pkt.chaddr + '';
          console.log("mac: "+mac_addr+"   chaddr:"+pkt.chaddr);
          var offer = clone(cur_request.offer);
          self.save_lease({
            yiaddr: cur_request.offer.yiaddr,
            offer: offer,
            chaddr: mac_addr
          }, function() {
            console.log("DONE");
            _clean_request(pkt.chaddr);
            return self.s.ack(pkt, offer);
          });
        }
      } else {
        // We're serving a request from a client that either didn't
        // run a DISCOVER or has come back from reboot in INIT-REBOOT
        // phase
        // OR
        // we're getting a request due to the client going into RENEW
        // OR
        // we're getting a request from the client because it's lease
        // is about to expire
        console.log("ATTEMPTING TO GET LEASE FOR:  "+pkt.chaddr);
        if(lease) {
          // we got a lease back, lets update it and
          var offer = {};
          console.log("Got lease for host --- " +pkt.chaddr);
          //self.set_lease(offer, pkt);
          self.save_lease({
            chaddr: pkt.chaddr,
            yiaddr: lease.yiaddr,
            offer: clone(lease.offer)
          }, function(){
            return self.s.ack(pkt); // ???
          });
        } else {
          console.log("Didn't find a matching lease for this host");
          //_clean_request(pkt.chaddr);
          return self.s.nak(pkt);
        }

      }
  });
};

dhcpd.prototype.decline = function decline (pkt) {
    var cur_request = requests[pkt.chaddr];
    if(cur_request && cur_request.offer){
      self.remove_lease(pkt.chaddr, function(){
        _clean_request(pkt.chaddr);
      });
    }
    return;
};

dhcpd.prototype.release = function release (pkt) {
    var cur_request = requests[pkt.chaddr];
    // We shouldn't really get into a position where we've got a request
    // without a lease, but lets double check
    if(cur_request && cur_request.offer){
      _clean_request(pkt.chaddr);
    }
    self.remove_lease(pkt.chaddr, function(){});
};

dhcpd.prototype.inform = function inform (pkt) {
  // not currently supporting INFORM, so ignore
  return;
};

function long2ip(ip) {
  if (!isFinite(ip))
    return false;
  return '' + [ip >>> 24, ip >>> 16 & 0xFF, ip >>> 8 & 0xFF, ip & 0xFF].join('.');
}

function ip2long (ip_address) {
  var parts = ip_address.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
  return parts.length == 5 ?
      parseInt(+parts[1],10) * 16777216 + parseInt(+parts[2],10) * 65536 +
      parseInt(+parts[3],10) * 256      + parseInt(+parts[4],10) * 1
    : false;
};

var store = new lease_store();

var server = new dhcpd({
    subnet: '192.168.119.0/24',
    range_start: '192.168.119.30',
    range_end: '192.168.119.60',
    routers: [ '192.168.119.1' ],
    nameservers: [ '8.8.8.8', '8.8.4.4' ],
    //set_lease: set_lease,
    save_lease: function(lease, cb){ store.save_lease(lease, cb) },
    get_lease: function(mac_addr, cb){ store.get_lease(mac_addr, cb) },
    get_lease_by_ip: function(ip, cb){ store.get_lease_by_ip(ip, cb) },
    get_next_ip: function(cb){ store.get_next_ip(cb) },
    remove_lease: function(mac_addr, cb){ store.remove_lease(mac_addr, cb) },
    host: '192.168.119.1'
});

module.exports = dhcpd;
<|endoftext|>


<commit_before>var NotImpementedError = require('../lib/NotImplementedError');
var request = require('supertest-as-promised');
var expect = require('expect.js');
var AppFactory = require('../lib/AppFactory');

describe('API endpoint',function(){
	var appFactory = new AppFactory();

	var app = appFactory.NewApp();

	describe('/scene',function(){
		describe('GET',function(){
			var response;

			before(function(done){
				request(app)
					.post('/scene')
					.send({
						resource:{
							type:'url',
							location:'http://www.google.com'
						}
					})
					.then(function(res){
						return request(app)
							.post('/scene')
							.send({
								resource:{
									type:'url',
									location:'http://www.github.com'
								}
							});
					})
					.then(function(res){
						return request(app).get('/scene');
					})
					.then(function(res){
						response = res;
						done();
					})
					.catch(function(err){
						done(err);
					});
			});

			it('should return all scenes in JSON',function(){
				expect(response.body).to.be.ok();
				expect(response.body).to.eql([
					{
						_id:0,
						resource:{
							type:'url',
							location:'http://www.google.com'
						}
					}, {
						_id:1,
						resource:{
							type:'url',
							location:'http://www.github.com'
						}
					}]);
			});

			it('should respond with code 200 upon success',function(){
				expect(response.statusCode).to.be(200);
			});
		});
		describe('POST',function(){
			var response;

			before(function(done){
				request(app)
					.post('/scene')
					.send({
						resource:{
							type:'url',
							location:'http://www.youtube.com'
						}
					})
					.then(function(res){
						response = res;
						done();
					})
					.catch(done);
			});

			// it('should create a new scene',function(){
			// 	throw new NotImpementedError();
			// });
			it('should respond with code 201 upon success',function(){
				expect(response.statusCode).to.be(201);
			});
			it('should return a `Location` header with a link to the newly-created resource',function(){
				expect(response.headers.location).to.be.ok();
				expect(response.headers.location).to.be.contain('http://127.0.0.1/scene/');
			});
		});
	});
	describe('/scene/{id}/processes',function(){
		describe('POST',function(){
			var response;

			before(function(done){
				request(app)
					.post('/scene/1/processes')
					.send({
						'status':'InProgress'
					})
					.then(function(res){
						response = res;
						done();
					})
					.catch(done);
			});

			it('should create a new process for the desired scene',function(done){
				request(app).get('/scene')
					.then(function(getRes){
						expect(getRes.body[1].processes).to.be.an(Array);
						expect(getRes.body[1].processes[0].status).to.eql('InProgress');
						done();
					})
					.catch(done);
			});

			it('should return a `Location` header with a link to the newly-created resource',function(){
				throw new NotImpementedError();
			});
		});

		describe('PUT',function(){
			it('should update process',function(){
				throw new NotImpementedError();
			});
			it('should require result if complete',function(){
				throw new NotImpementedError();
			});
		});
	});
});<commit_msg>Write test for 'API endpoint /scene/{id}/processes POST should return a `Location` header with a link to the newly-created resource'<commit_after>var NotImpementedError = require('../lib/NotImplementedError');
var request = require('supertest-as-promised');
var expect = require('expect.js');
var AppFactory = require('../lib/AppFactory');

describe('API endpoint',function(){
	var appFactory = new AppFactory();

	var app = appFactory.NewApp();

	describe('/scene',function(){
		describe('GET',function(){
			var response;

			before(function(done){
				request(app)
					.post('/scene')
					.send({
						resource:{
							type:'url',
							location:'http://www.google.com'
						}
					})
					.then(function(res){
						return request(app)
							.post('/scene')
							.send({
								resource:{
									type:'url',
									location:'http://www.github.com'
								}
							});
					})
					.then(function(res){
						return request(app).get('/scene');
					})
					.then(function(res){
						response = res;
						done();
					})
					.catch(function(err){
						done(err);
					});
			});

			it('should return all scenes in JSON',function(){
				expect(response.body).to.be.ok();
				expect(response.body).to.eql([
					{
						_id:0,
						resource:{
							type:'url',
							location:'http://www.google.com'
						}
					}, {
						_id:1,
						resource:{
							type:'url',
							location:'http://www.github.com'
						}
					}]);
			});

			it('should respond with code 200 upon success',function(){
				expect(response.statusCode).to.be(200);
			});
		});
		describe('POST',function(){
			var response;

			before(function(done){
				request(app)
					.post('/scene')
					.send({
						resource:{
							type:'url',
							location:'http://www.youtube.com'
						}
					})
					.then(function(res){
						response = res;
						done();
					})
					.catch(done);
			});

			// it('should create a new scene',function(){
			// 	throw new NotImpementedError();
			// });
			it('should respond with code 201 upon success',function(){
				expect(response.statusCode).to.be(201);
			});
			it('should return a `Location` header with a link to the newly-created resource',function(){
				expect(response.headers).to.have.key('location');
				expect(response.headers.location).to.be.contain('http://127.0.0.1/scene/');
			});
		});
	});
	describe('/scene/{id}/processes',function(){
		describe('POST',function(){
			var response;

			before(function(done){
				request(app)
					.post('/scene/1/processes')
					.send({
						'status':'InProgress'
					})
					.then(function(res){
						response = res;
						done();
					})
					.catch(done);
			});

			it('should create a new process for the desired scene',function(done){
				request(app).get('/scene')
					.then(function(getRes){
						console.log(getRes.body);
						expect(getRes.body[1].processes).to.be.an(Array);
						expect(getRes.body[1].processes[0].status).to.eql('InProgress');
						done();
					})
					.catch(done);
			});

			it('should return a `Location` header with a link to the newly-created resource',function(){
				expect(response.headers).to.have.key('location');
				expect(response.headers.location).to.be.contain('http://127.0.0.1/scene/1/processes/0');
			});
		});

	});
	describe('/scene/{id}/processes/{id}',function(){
		describe('PUT',function(){
			it('should update process',function(){
				throw new NotImpementedError();
			});
			it('should require result if complete',function(){
				throw new NotImpementedError();
			});
		});
	});
});<|endoftext|>


<commit_before>console.log("current version - 1");

/** GISD - Sharingan **/
$("#gisd-image").click(addSharingan());

// create image
var img = document.createElement("img");
img.className = "img-circle img-responsive";
img.src = "../img/sharingan/msharingan.png";
img.alt = "Mangekyo Sharingan";

// create div
var div = document.createElement("div");
div.className = "timeline-image";

// create li
var li = document.createElement("li");
li.className = "timeline-inverted wow rotateIn";

// add to timeline
function addSharingan() {
    div.appendChild(img);
    li.appendChild(div);
    $("#timeline-list").append(li);
}

var easterImg = document.createElement("img");
easterImg.className = "text-center";
easterImg.style.width = "100%";
easterImg.style.height = "100%";

function updtImg(newSrc) {
    easterImg.src = "../img/easter-eggs/" + newSrc;
}

// Android
$("#android-image").click(function () {
    updtImg("android-doughnut.jpg");
    bootbox.alert({
        size: 'large',
        title: 'My kind of doughnut! (me at Google HQ)',
        message: easterImg.innerHTML,
        callback: function () {
            console.log("bootbox over and out");
        }
    })

});<commit_msg>moved sharingan code into function<commit_after>console.log("current version - 1");

/** GISD - Sharingan **/
$("#gisd-image").click(addSharingan());

// add to timeline
function addSharingan() {

    // create image
    var img = document.createElement("img");
    img.className = "img-circle img-responsive";
    img.src = "../img/sharingan/msharingan.png";
    img.alt = "Mangekyo Sharingan";

    // create div
    var div = document.createElement("div");
    div.className = "timeline-image";

    // create li
    var li = document.createElement("li");
    li.className = "timeline-inverted wow rotateIn";

    div.appendChild(img);
    li.appendChild(div);
    $("#timeline-list").append(li);
}

var easterImg = document.createElement("img");
easterImg.className = "text-center";
easterImg.style.width = "100%";
easterImg.style.height = "100%";

function updtImg(newSrc) {
    easterImg.src = "../img/easter-eggs/" + newSrc;
}

// Android
$("#android-image").click(function () {
    updtImg("android-doughnut.jpg");
    bootbox.alert({
        size: 'large',
        title: 'My kind of doughnut! (me at Google HQ)',
        message: easterImg.innerHTML,
        callback: function () {
            console.log("bootbox over and out");
        }
    })

});<|endoftext|>


<commit_before>'use strict';

(function() {

	var $btnEdit = $('#btnEdit'),
	$contentContainer = $('#contentContainer'),
	$contentViewport = $('#contentContainer').find('#contentViewport'),
	$inputContainer = $('#inputContainer'),
	$txtUserHTML = $('#inputContainer').find('#txtUserHTML'),
	$btnSave = $('#inputContainer').find('#btnSave'),
	$btnCancel = $('#inputContainer').find('#btnCancel'),
	$formMsg = $('#inputContainer').find('#formMsg');

	var illegal = ['style', 'html', 'body', 'script'];

	var illegalItem,
	errorState; //0: no error, 1:empty html form, 2:general tag error

	var networkAvailable = 0; // 0: no connection to Server, 1: Server is available

	//For Test data
	var $testDiv = $contentContainer.find('.testDiv'),
	$networkStatus =  $contentContainer.find('#networkStatus'),
	$btnTestData = $contentContainer.find('#btnTestData');

	function checkAvailability() {
		$networkStatus.removeClass();
		$networkStatus.html('*....*');
		$.ajax({
		type: 'GET',
		url: 'http://localhost:3000/',
		success: function() {
			networkAvailable = 1;
			$networkStatus.addClass('networkStatusOK');
			$networkStatus.html('*ONLINE MODE*');
		},
		error: function() {
			networkAvailable = 0;
			$networkStatus.addClass('networkStatusNOK');
			$networkStatus.html('*OFFLINE MODE*');
		}
	});
	}

	function process(html, callback) {
		//Apply form content
		//TODO : Integrate with backend
		if (!networkAvailable) {

		}
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);

		$contentViewport.html(callback(html));
	}

	function convertToHtml(html) {
		html = html.replace(/\<image\>\n/g, '
');
		html = html.replace(/\n\<\/image\>/g, '
');
		html = html.replace(/\n/g, '
');
		return html;
	}

	function convertToWYS(content) {
		content = content.replace(/\
/g, '\n');
		content = content.replace(/\
/g, '<image>\n');
		content = content.replace(/\<\/div\>/g, '\n</image>');
		return content;
	}

	function removeStatusMsg() {
		$formMsg.html('');
		$formMsg.removeClass();
	}

	function hideElements(arr) {
		removeStatusMsg();

		if (arr.length > 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].hide();
			}
		} else {
			arr[0].hide();
		}
	}

	function showElements(arr) {
		removeStatusMsg();

		if (arr.length > 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].show();
			}
		} else {
			arr[0].show();
		}
	}

	$("textarea").on('keydown', function(e) {
	    if(e.keyCode === 9) { // tab was pressed
	        // get caret position/selection
	        var start = this.selectionStart,
	        end = this.selectionEnd;

	        var $this = $(this),
	        value = $this.val();

	        // set textarea value to: text before caret + tab + text after caret
	        $this.val(value.substring(0, start)
	                    + "\t"
	                    + value.substring(end));

	        // put caret at right position again (add one for the tab)
	        this.selectionStart = this.selectionEnd = start + 1;

	        // prevent the focus lose
	        e.preventDefault();
	    }
	});

	$btnEdit.on('click', function() {
		var content = $contentViewport.html();

		hideElements([$contentViewport]);
		showElements([$btnTestData, $inputContainer]);

		$txtUserHTML.val(convertToWYS(content));
	});

	$btnSave.on('click', function() {
	  var illegalPrefix = '<',
	  html = $txtUserHTML.val();

	  for (var i=0; i<illegal.length; i++) {
	    illegalItem = illegal[i];

	    //Error cases
	    if (!html) {
	    	errorState = 1;
			$formMsg.addClass('callout alert');
			$formMsg.html('Content is empty.');
	     	break;
	    } else if (html.indexOf(illegalPrefix + illegalItem) > -1) {
	    	errorState = 2;
			$formMsg.addClass('callout alert');
			$formMsg.html(`<${illegalItem}> tags are not allowed.`);
			break;
	    }
	  }

	  if (!errorState) {
	  	process(html, convertToHtml);
	  }

	  errorState = 0;
	});

	$btnCancel.on('click', function() {
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);

		$txtUserHTML.val('');
	});

	//Input test data
	$btnTestData.on('click', function() {
		var client = new XMLHttpRequest();
		client.open('GET', './test.html');
		client.onreadystatechange = function() {
		  $txtUserHTML.val(client.responseText);
		}
		client.send();
	});

	//show form by default if article is empty
	if (!$contentViewport.html()) {
		hideElements([$contentViewport]);
		showElements([$btnTestData, $inputContainer]);
	} else {
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);
	}

	checkAvailability();

}());

<commit_msg>multibrowser support<commit_after>'use strict';

(function() {

	var $btnEdit = $('#btnEdit'),
	$contentContainer = $('#contentContainer'),
	$contentViewport = $('#contentContainer').find('#contentViewport'),
	$inputContainer = $('#inputContainer'),
	$txtUserHTML = $('#inputContainer').find('#txtUserHTML'),
	$btnSave = $('#inputContainer').find('#btnSave'),
	$btnCancel = $('#inputContainer').find('#btnCancel'),
	$formMsg = $('#inputContainer').find('#formMsg');

	var illegal = ['style', 'html', 'body', 'script'];

	var illegalItem,
	errorState; //0: no error, 1:empty html form, 2:general tag error

	var networkAvailable = 0; // 0: no connection to Server, 1: Server is available

	//For Test data
	var $testDiv = $contentContainer.find('.testDiv'),
	$networkStatus =  $contentContainer.find('#networkStatus'),
	$btnTestData = $contentContainer.find('#btnTestData');

	function checkAvailability() {
		$networkStatus.removeClass();
		$networkStatus.html('*....*');
		$.ajax({
		type: 'GET',
		url: 'http://localhost:3000/',
		success: function() {
			networkAvailable = 1;
			$networkStatus.addClass('networkStatusOK');
			$networkStatus.html('*ONLINE MODE*');
		},
		error: function() {
			networkAvailable = 0;
			$networkStatus.addClass('networkStatusNOK');
			$networkStatus.html('*OFFLINE MODE*');
		}
	});
	}

	function process(html, callback) {
		//Apply form content
		//TODO : Integrate with backend
		if (!networkAvailable) {

		}
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);

		$contentViewport.html(callback(html));
	}

	function convertToHtml(html) {
		html = html.replace(/\<image\>\n/g, '
');
		html = html.replace(/\n\<\/image\>/g, '
');
		html = html.replace(/\n/g, '
');
		return html;
	}

	function convertToWYS(content) {
		content = content.replace(/\
/g, '\n');
		content = content.replace(/\
/g, '<image>\n');
		content = content.replace(/\<\/div\>/g, '\n</image>');
		return content;
	}

	function removeStatusMsg() {
		$formMsg.html('');
		$formMsg.removeClass();
	}

	function hideElements(arr) {
		removeStatusMsg();

		if (arr.length > 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].hide();
			}
		} else {
			arr[0].hide();
		}
	}

	function showElements(arr) {
		removeStatusMsg();

		if (arr.length > 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].show();
			}
		} else {
			arr[0].show();
		}
	}

	$("textarea").on('keydown', function(e) {
	    if(e.keyCode === 9) { // tab was pressed
	        // get caret position/selection
	        var start = this.selectionStart,
	        end = this.selectionEnd;

	        var $this = $(this),
	        value = $this.val();

	        // set textarea value to: text before caret + tab + text after caret
	        $this.val(value.substring(0, start)
	                    + "\t"
	                    + value.substring(end));

	        // put caret at right position again (add one for the tab)
	        this.selectionStart = this.selectionEnd = start + 1;

	        // prevent the focus lose
	        e.preventDefault();
	    }
	});

	$btnEdit.on('click', function() {
		var content = $contentViewport.html();

		hideElements([$contentViewport]);
		showElements([$btnTestData, $inputContainer]);

		$txtUserHTML.val(convertToWYS(content));
	});

	$btnSave.on('click', function() {
	  var illegalPrefix = '<',
	  html = $txtUserHTML.val();

	  for (var i=0; i<illegal.length; i++) {
	    illegalItem = illegal[i];

	    //Error cases
	    if (!html) {
	    	errorState = 1;
			$formMsg.addClass('callout alert');
			$formMsg.html('Content is empty.');
	     	break;
	    } else if (html.indexOf(illegalPrefix + illegalItem) > -1) {
	    	errorState = 2;
			$formMsg.addClass('callout alert');
			$formMsg.html(illegalItem + ' tags are not allowed.');
			break;
	    }
	  }

	  if (!errorState) {
	  	process(html, convertToHtml);
	  }

	  errorState = 0;
	});

	$btnCancel.on('click', function() {
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);

		$txtUserHTML.val('');
	});

	//Input test data
	$btnTestData.on('click', function() {
		var client = new XMLHttpRequest();
		client.open('GET', './test.html');
		client.onreadystatechange = function() {
		  $txtUserHTML.val(client.responseText);
		}
		client.send();
	});

	//show form by default if article is empty
	if (!$contentViewport.html()) {
		hideElements([$contentViewport]);
		showElements([$btnTestData, $inputContainer]);
	} else {
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);
	}

	checkAvailability();

}());

<|endoftext|>