<commit_before>"use strict";

const path = require('path');
const fs = require('fs');

const chai = require('chai');
const expect = chai.expect;
const glob = require('glob');
const del = require('del');
const build = require('../lib/build');

function readFile(s) {
    return fs.readFileSync(s, 'utf-8');
}

function filterImageBase64(str) {
    return str.replace(/data:image\/[a-zA-Z0-9=\+\/,;]+/g, '');
}

function testBuild(webpackConfig, fixtureDir, options = {}) {
    return new Promise(function(resolve, reject) {
        const cwd = path.join(__dirname, 'fixtures', fixtureDir);
        const outputDir = path.join(cwd, 'dist');

        const expectDir = path.join(__dirname, 'expect', fixtureDir);

        process.chdir(cwd);
        del.sync(outputDir);

        webpackConfig.env || (webpackConfig.env = '');
        webpackConfig.cwd = cwd;
        webpackConfig.quiet = true; // 不输出任何信息

        build(webpackConfig, function (error) {
            if (error) {
                reject(error);
            }

            const actualFiles = glob.sync('**/*', {
                cwd: outputDir,
                nodir: true
            });

            actualFiles.forEach(function (file) {
                // 图片不作检查
                if ('.png|.jpeg|.jpg|.gif'.indexOf(path.extname(file)) === -1) {
                    let outputFile = readFile(path.join(outputDir, file));
                    let expectFile = readFile(path.join(expectDir, file));
                    if (options.ignoreImageBase64) { // 内联图片不作检查
                        outputFile = filterImageBase64(outputFile);
                        expectFile = filterImageBase64(expectFile);
                    }
                    expect(outputFile).to.equal(expectFile);
                }
            });
            resolve();
        });
    });
}

describe('Build', function() {
    this.timeout(10000);

    it('code-splitted-css-bundle', function() {
        return testBuild({}, 'code-splitted-css-bundle', {
            ignoreImageBase64: true
        });
    });
    /*it('code-splitted-require.context', function() {
        return testBuild({}, 'code-splitted-require.context');
    });
    it('code-splitted-require.context-amd', function() {
        return testBuild({}, 'code-splitted-require.context-amd');
    });
    it('code-splitting', function() {
        return testBuild({}, 'code-splitting');
    });
    it('code-splitting-harmony', function() {
        return testBuild({}, 'code-splitting-harmony');
    });
    it('common-chunk-and-vendor-chunk', function() {
        return testBuild({}, 'common-chunk-and-vendor-chunk');
    });
    it('commonjs', function() {
        return testBuild({}, 'commonjs');
    });
    it('css', function() {
        return testBuild({}, 'css');
    });
    it('css-font-url', function() {
        return testBuild({}, 'css-font-url');
    });
    it('css-modules', function() {
        return testBuild({}, 'css-modules');
    });
    it('development-env', function() {
        return testBuild({
            env: 'development'
        }, 'development-env');
    });
    it('es6 to es5', function() {
        return testBuild({}, 'es6-to-es5');
    });
    it('extra-async-chunk', function() {
        return testBuild({}, 'extra-async-chunk');
    });
    it('handlebars', function() {
        return testBuild({}, 'handlebars');
    });
    it('image-dataurl', function() {
        return testBuild({}, 'image-dataurl', {
            ignoreImageBase64: true
        });
    });
    it('jsx', function() {
        return testBuild({}, 'jsx');
    });
    it('production-env', function() {
        return testBuild({
            env: 'production'
        }, 'production-env');
    });
    it('require.context', function() {
        return testBuild({}, 'require.context');
    });
    it('require.resolve', function() {
        return testBuild({}, 'require.resolve');
    });
    it('scss', function() {
        return testBuild({}, 'scss');
    });
    it('scss-modules', function() {
        return testBuild({}, 'scss-modules');
    });
    it('sprites', function() {
        return testBuild({}, 'sprites');
    });
    it('sprites-retina', function() {
        return testBuild({}, 'sprites-retina');
    });
    it('svg-to-font', function() {
        return testBuild({}, 'svg-to-font');
    });
    it('sprites-split', function() {
        return testBuild({}, 'sprites-split');
    });
    it('sprites-split-retina', function() {
        return testBuild({}, 'sprites-split-retina');
    });
    it('template-css-inline', function() {
        return testBuild({}, 'template-css-inline');
    });
    it('template-image', function() {
        return testBuild({}, 'template-image', {
            ignoreImageBase64: true
        });
    });
    it('template-partial', function() {
        return testBuild({}, 'template-partial');
    });
    it('template-render-data', function() {
        return testBuild({}, 'template-render-data');
    });*/
});
<commit_msg>test: update ci test read file character<commit_after>"use strict";

const path = require('path');
const fs = require('fs');

const chai = require('chai');
const expect = chai.expect;
const glob = require('glob');
const del = require('del');
const build = require('../lib/build');

function readFile(s) {
    return fs.readFileSync(s, 'utf8');
}

function filterImageBase64(str) {
    return str.replace(/data:image\/[a-zA-Z0-9=\+\/,;]+/g, '');
}

function testBuild(webpackConfig, fixtureDir, options = {}) {
    return new Promise(function(resolve, reject) {
        const cwd = path.join(__dirname, 'fixtures', fixtureDir);
        const outputDir = path.join(cwd, 'dist');

        const expectDir = path.join(__dirname, 'expect', fixtureDir);

        process.chdir(cwd);
        del.sync(outputDir);

        webpackConfig.env || (webpackConfig.env = '');
        webpackConfig.cwd = cwd;
        webpackConfig.quiet = true; // 不输出任何信息

        build(webpackConfig, function (error) {
            if (error) {
                reject(error);
            }

            const actualFiles = glob.sync('**/*', {
                cwd: outputDir,
                nodir: true
            });

            actualFiles.forEach(function (file) {
                // 图片不作检查
                if ('.png|.jpeg|.jpg|.gif'.indexOf(path.extname(file)) === -1) {
                    let outputFile = readFile(path.join(outputDir, file));
                    let expectFile = readFile(path.join(expectDir, file));
                    if (options.ignoreImageBase64) { // 内联图片不作检查
                        outputFile = filterImageBase64(outputFile);
                        expectFile = filterImageBase64(expectFile);
                    }
                    expect(outputFile).to.equal(expectFile);
                }
            });
            resolve();
        });
    });
}

describe('Build', function() {
    this.timeout(10000);

    it('code-splitted-css-bundle', function() {
        return testBuild({}, 'code-splitted-css-bundle', {
            ignoreImageBase64: true
        });
    });
    /*it('code-splitted-require.context', function() {
        return testBuild({}, 'code-splitted-require.context');
    });
    it('code-splitted-require.context-amd', function() {
        return testBuild({}, 'code-splitted-require.context-amd');
    });
    it('code-splitting', function() {
        return testBuild({}, 'code-splitting');
    });
    it('code-splitting-harmony', function() {
        return testBuild({}, 'code-splitting-harmony');
    });
    it('common-chunk-and-vendor-chunk', function() {
        return testBuild({}, 'common-chunk-and-vendor-chunk');
    });
    it('commonjs', function() {
        return testBuild({}, 'commonjs');
    });
    it('css', function() {
        return testBuild({}, 'css');
    });
    it('css-font-url', function() {
        return testBuild({}, 'css-font-url');
    });
    it('css-modules', function() {
        return testBuild({}, 'css-modules');
    });
    it('development-env', function() {
        return testBuild({
            env: 'development'
        }, 'development-env');
    });
    it('es6 to es5', function() {
        return testBuild({}, 'es6-to-es5');
    });
    it('extra-async-chunk', function() {
        return testBuild({}, 'extra-async-chunk');
    });
    it('handlebars', function() {
        return testBuild({}, 'handlebars');
    });
    it('image-dataurl', function() {
        return testBuild({}, 'image-dataurl', {
            ignoreImageBase64: true
        });
    });
    it('jsx', function() {
        return testBuild({}, 'jsx');
    });
    it('production-env', function() {
        return testBuild({
            env: 'production'
        }, 'production-env');
    });
    it('require.context', function() {
        return testBuild({}, 'require.context');
    });
    it('require.resolve', function() {
        return testBuild({}, 'require.resolve');
    });
    it('scss', function() {
        return testBuild({}, 'scss');
    });
    it('scss-modules', function() {
        return testBuild({}, 'scss-modules');
    });
    it('sprites', function() {
        return testBuild({}, 'sprites');
    });
    it('sprites-retina', function() {
        return testBuild({}, 'sprites-retina');
    });
    it('svg-to-font', function() {
        return testBuild({}, 'svg-to-font');
    });
    it('sprites-split', function() {
        return testBuild({}, 'sprites-split');
    });
    it('sprites-split-retina', function() {
        return testBuild({}, 'sprites-split-retina');
    });
    it('template-css-inline', function() {
        return testBuild({}, 'template-css-inline');
    });
    it('template-image', function() {
        return testBuild({}, 'template-image', {
            ignoreImageBase64: true
        });
    });
    it('template-partial', function() {
        return testBuild({}, 'template-partial');
    });
    it('template-render-data', function() {
        return testBuild({}, 'template-render-data');
    });*/
});
<|endoftext|>


<commit_before>var net = require('net')
  , os = require('os')
  , dns_sd = require('./dns_sd')
  , interfaceIndexDeprecatedWarningPrinted = false
  ;

exports.interfaceIndex = function interfaceIndex(options) {
  var networkInterface
    , index = 0;
  if (typeof options.interfaceIndex !== 'undefined') {
    if( ! interfaceIndexDeprecatedWarningPrinted) {
      console.warn("WARNING: 'interfaceIndex' is deprecated and will be " +
          "removed. Please use 'networkInterface' instead and see the " +
          "documentation for new features.");
      interfaceIndexDeprecatedWarningPrinted = true;
    }
    networkInterface = options.interfaceIndex;
  } else {
    networkInterface = options.networkInterface;
  }
  if (typeof networkInterface !== 'undefined') {
    if (net.isIP(networkInterface)) {
      index = dns_sd.if_nametoindex(addressToName(networkInterface));
      //console.log('got IP', networkInterface, '->', index);
    } else if (isString(networkInterface)) {
      index = dns_sd.if_nametoindex(networkInterface);
      //console.log('got if name', networkInterface, '->', index);
    } else {
      //console.log('got index', networkInterface);
      index = networkInterface;
    }
  }
  return index;
}

function addressToName(address) {
  var addresses = os.networkInterfaces();
  for (var name in addresses) {
    for (var i = 0; i < addresses[name].length; ++i) {
      if (addresses[name][i].address === address) {
        return name;
      }
    }
  }
  throw new Error('interface with address ' + address + ' does not exist');
}

function isString(s) {
  return toString.call(s) == '[object String]';
}

<commit_msg>[iface] throw on unsupported platforms and node versions<commit_after>var net = require('net')
  , os = require('os')
  , dns_sd = require('./dns_sd')
  , interfaceIndexDeprecatedWarningPrinted = false
  ;

var have_if_nametoindex = typeof dns_sd.if_nametoindex !== 'undefined';

exports.interfaceIndex = function interfaceIndex(options) {
  var networkInterface
    , index = 0;
  if (typeof options.interfaceIndex !== 'undefined') {
    if( ! interfaceIndexDeprecatedWarningPrinted) {
      console.warn("WARNING: 'interfaceIndex' is deprecated and will be " +
          "removed. Please use 'networkInterface' instead and see the " +
          "documentation for new features.");
      interfaceIndexDeprecatedWarningPrinted = true;
    }
    networkInterface = options.interfaceIndex;
  } else {
    networkInterface = options.networkInterface;
  }
  if (typeof networkInterface !== 'undefined') {
    if (net.isIP(networkInterface)) {
      if ( ! have_if_nametoindex) {
        throw new Error('IP address to interface index conversion is not ' +
            'supported on this platform');
      }
      index = dns_sd.if_nametoindex(addressToName(networkInterface));
      //console.log('got IP', networkInterface, '->', index);
    } else if (isString(networkInterface)) {
      if ( ! have_if_nametoindex) {
        throw new Error('interface name to index conversion is not supported ' +
            'on this platform');
      }
      index = dns_sd.if_nametoindex(networkInterface);
      //console.log('got if name', networkInterface, '->', index);
    } else {
      //console.log('got index', networkInterface);
      index = networkInterface;
    }
  }
  return index;
}

function addressToName(address) {
  if (typeof os.networkInterfaces === 'undefined') {
    throw new Error('IP address to interface index conversion is not ' +
        'supported with this version of node');
  }
  var addresses = os.networkInterfaces();
  for (var name in addresses) {
    for (var i = 0; i < addresses[name].length; ++i) {
      if (addresses[name][i].address === address) {
        return name;
      }
    }
  }
  throw new Error('interface with address ' + address + ' does not exist');
}

function isString(s) {
  return toString.call(s) == '[object String]';
}

<|endoftext|>


<commit_before>'use strict';

class PersonManager {

    constructor(statusBar, panel, portField, historyPanel) {
        this._statusBar = statusBar;
        this._panel = panel;
        this._portField = portField;
        this._historyPanel = historyPanel;

        this._history = [];
        this.checkPorts();
    }

    setPort(port) {
        this._port = port;
    }

    setStatus(description, error, code) {
        this._statusBar.innerHTML = description;
        if (!!code) {
             this._statusBar.innerHTM += `(${code})`;
        } else {
        }
        if (!!error) {
            this._statusBar.className = 'alert alert-danger';
        } else {
            this._statusBar.className = 'alert alert-success';
        }
    }

    loadPerson(name) {
        this.setStatus(`Loading ${name}`);
        var url = `http://localhost:${this._port}/${name}`;
        var http_request = new XMLHttpRequest();

        var historyEntry = this.addHistoryEntry({
            type: 'request',
            method: 'GET',
            url: url,
            data: {
                name: name
            }
        });
        http_request.onreadystatechange = this.gotPerson.bind(this,
                                               http_request, historyEntry);
        http_request.open('GET', url, true);

        http_request.send();
    }

    savePerson(name, age) {
        var url = `http://localhost:${this._port}/`;
        var http_request = new XMLHttpRequest();

        var data = {
            name: name,
            age: age
        };
        var historyEntry = this.addHistoryEntry({
            type: 'request',
            method: 'POST',
            url: url,
            data: data
        });

        http_request.onreadystatechange = this.sentPerson.bind(this,
                                               http_request, historyEntry);
        http_request.open("POST", url, true);
        http_request.setRequestHeader('Content-Type', 'application/json');
        http_request.send(JSON.stringify(data));
    }

    gotPerson(http_request, historyEntry) {
        if (http_request.readyState == 4 && http_request.status) {
            this.setStatus(`Parsing GET result`);
            try {
                console.log(http_request.responseText);
                var jsonObj = JSON.parse(http_request.responseText);
                if (jsonObj.success) {
                    this.displayPerson(jsonObj.response.person,
                                       false, http_request.status);
                    this.displayServicesInfo(jsonObj.response);
                    this.setHistoryEntryState(historyEntry, true);
                } else {
                    this.setStatus(jsonObj.error || "Error occured",
                                   true, http_request.status);
                    this.displayServicesInfo();
                    this.setHistoryEntryState(historyEntry, false);
                }
            } catch (e) {
                this.setStatus(e.toString(), true, http_request.status);
                this.displayServicesInfo();
                this.setHistoryEntryState(historyEntry, false);
            }
        }
    }

    sentPerson(http_request, historyEntry) {
        if (http_request.readyState == 4){
            this.setStatus(`Parsing POST result`);
            try {
                this.response = http_request;
                console.log(`Response is ${http_request.responseText}`);
                var jsonObj = JSON.parse(http_request.responseText);
                if (jsonObj.success) {
                    this.displayPerson(jsonObj.response.person,
                                       false, http_request.status);
                    this.displayServicesInfo(jsonObj.response);
                    this.setHistoryEntryState(historyEntry, true);
                } else {
                    this.setStatus(jsonObj.error || "Error occured",
                                   true, http_request.status);
                    this.displayServicesInfo();
                    this.setHistoryEntryState(historyEntry, false);
                }
            } catch (e) {
                this.setStatus(e.toString(), true, http_request.status);
                this.displayServicesInfo();
                this.setHistoryEntryState(historyEntry, false);
            }
        }
    }

    displayPerson(person) {
        this.setStatus(`
Name: ${person.name}

Age: ${person.age}

UUID: ${person.id}
`);
    }

    displayServicesInfo(response) {
        if (!response) {
            ['rest', 'logic', 'repository'].forEach((key) => {
                window.document.getElementById(`${key}-service`).innerHTML = '';
            })
            return;
        }
        Object.keys(response).forEach((key) => {
            if (['rest', 'logic', 'repository'].indexOf(key) > -1) {
                window.document.getElementById(`${key}-service`).innerHTML =
                    response[key];
            }
        });
    }

    checkPorts() {
        var port = 8080;
        this.checkPort(port, [], (err, ports) => {
            this.setPorts(ports);
        });
    }

    setPorts(ports) {
        console.log(`Set ports ${ports}`);
        let port = this._port;
        while (this._portField.firstChild) {
            this._portField.removeChild(this._portField.firstChild);
        }
        ports.forEach((i) => {
            let opt = window.document.createElement("option");
            opt.value = i;
            opt.textContent = i;
            this._portField.appendChild(opt);
        });
        !port && (this._port = port = ports[0]);
        this._portField.value = port;
        setTimeout(this.checkPorts.bind(this), 10000);
    }

    checkPort(port, ports, callback) {
        var url = `http://localhost:${port}`;
        var http_request = new XMLHttpRequest();

        http_request.onreadystatechange = () => {
            if (http_request.readyState == 4) {
                if (http_request.status == 200) {
                    ports.push(port);
                }
                if (port > 8089) {
                    return callback(null, ports);
                }
                this.checkPort(port + 1, ports, callback);
            }
        }
        http_request.open("OPTIONS", url, true);
        http_request.send();
    }

    addHistoryEntry(entry) {
        this._history.push(entry);
        var content = '';
        if (entry.type === 'request') {
            if (entry.method === 'GET') {
                content = `${entry.method} => ${entry.url}`;
            } else if (entry.method === 'POST') {
                content = `${entry.method} => ${entry.url}
                          (${entry.data.name}, ${entry.data.age})`;
            }
        }
        var id = `history-${this._history.length-1}`;
        var newItem = document.createElement("li");
        newItem.id = id;
        var textnode = document.createTextNode(content);
        newItem.appendChild(textnode);
        this._historyPanel.insertBefore(newItem, this._historyPanel.childNodes[0]);

        window.document.getElementById(id).onclick = this.restoreHistoryEntry.bind(this, this._history.length-1);
        return this._history.length-1;
    }

    setHistoryEntryState(number, success) {
        var id = `history-${number}`;
        var className = `list-group-item-${success? 'success' : 'danger'}`;
        window.document.getElementById(id).className = className;
    }

    restoreHistoryEntry(number) {
        console.log(`Entry ${JSON.stringify(this._history[number])}`);
        if ('name' in this._history[number].data) {
            window.document.getElementById('name').value =
                this._history[number].data.name;
        }
        if ('age' in this._history[number].data) {
            window.document.getElementById('age').value =
                this._history[number].data.age;
        }
    }

    addHistoryLabel(description) {
        var newItem = document.createElement("li");
        newItem.className = 'list-group-item-info';
        var textnode = document.createTextNode(description);
        newItem.appendChild(textnode);
        this._historyPanel.insertBefore(newItem, this._historyPanel.childNodes[0]);
    }
}

<commit_msg>Added method to add history element<commit_after>'use strict';

class PersonManager {

    constructor(statusBar, panel, portField, historyPanel) {
        this._statusBar = statusBar;
        this._panel = panel;
        this._portField = portField;
        this._historyPanel = historyPanel;

        this._history = [];
        this.checkPorts();
    }

    setPort(port) {
        this._port = port;
    }

    setStatus(description, error, code) {
        this._statusBar.innerHTML = description;
        if (!!code) {
             this._statusBar.innerHTM += `(${code})`;
        } else {
        }
        if (!!error) {
            this._statusBar.className = 'alert alert-danger';
        } else {
            this._statusBar.className = 'alert alert-success';
        }
    }

    loadPerson(name) {
        this.setStatus(`Loading ${name}`);
        var url = `http://localhost:${this._port}/${name}`;
        var http_request = new XMLHttpRequest();

        var historyEntry = this.addHistoryEntry({
            type: 'request',
            method: 'GET',
            url: url,
            data: {
                name: name
            }
        });
        http_request.onreadystatechange = this.gotPerson.bind(this,
                                               http_request, historyEntry);
        http_request.open('GET', url, true);

        http_request.send();
    }

    savePerson(name, age) {
        var url = `http://localhost:${this._port}/`;
        var http_request = new XMLHttpRequest();

        var data = {
            name: name,
            age: age
        };
        var historyEntry = this.addHistoryEntry({
            type: 'request',
            method: 'POST',
            url: url,
            data: data
        });

        http_request.onreadystatechange = this.sentPerson.bind(this,
                                               http_request, historyEntry);
        http_request.open("POST", url, true);
        http_request.setRequestHeader('Content-Type', 'application/json');
        http_request.send(JSON.stringify(data));
    }

    gotPerson(http_request, historyEntry) {
        if (http_request.readyState == 4 && http_request.status) {
            this.setStatus(`Parsing GET result`);
            try {
                console.log(http_request.responseText);
                var jsonObj = JSON.parse(http_request.responseText);
                if (jsonObj.success) {
                    this.displayPerson(jsonObj.response.person,
                                       false, http_request.status);
                    this.displayServicesInfo(jsonObj.response);
                    this.setHistoryEntryState(historyEntry, true);
                } else {
                    this.setStatus(jsonObj.error || "Error occured",
                                   true, http_request.status);
                    this.displayServicesInfo();
                    this.setHistoryEntryState(historyEntry, false);
                }
            } catch (e) {
                this.setStatus(e.toString(), true, http_request.status);
                this.displayServicesInfo();
                this.setHistoryEntryState(historyEntry, false);
            }
        }
    }

    sentPerson(http_request, historyEntry) {
        if (http_request.readyState == 4){
            this.setStatus(`Parsing POST result`);
            try {
                this.response = http_request;
                console.log(`Response is ${http_request.responseText}`);
                var jsonObj = JSON.parse(http_request.responseText);
                if (jsonObj.success) {
                    this.displayPerson(jsonObj.response.person,
                                       false, http_request.status);
                    this.displayServicesInfo(jsonObj.response);
                    this.setHistoryEntryState(historyEntry, true);
                } else {
                    this.setStatus(jsonObj.error || "Error occured",
                                   true, http_request.status);
                    this.displayServicesInfo();
                    this.setHistoryEntryState(historyEntry, false);
                }
            } catch (e) {
                this.setStatus(e.toString(), true, http_request.status);
                this.displayServicesInfo();
                this.setHistoryEntryState(historyEntry, false);
            }
        }
    }

    displayPerson(person) {
        this.setStatus(`
Name: ${person.name}

Age: ${person.age}

UUID: ${person.id}
`);
    }

    displayServicesInfo(response) {
        if (!response) {
            ['rest', 'logic', 'repository'].forEach((key) => {
                window.document.getElementById(`${key}-service`).innerHTML = '';
            })
            return;
        }
        Object.keys(response).forEach((key) => {
            if (['rest', 'logic', 'repository'].indexOf(key) > -1) {
                window.document.getElementById(`${key}-service`).innerHTML =
                    response[key];
            }
        });
    }

    checkPorts() {
        var port = 8080;
        this.checkPort(port, [], (err, ports) => {
            this.setPorts(ports);
        });
    }

    setPorts(ports) {
        console.log(`Set ports ${ports}`);
        let port = this._port;
        while (this._portField.firstChild) {
            this._portField.removeChild(this._portField.firstChild);
        }
        ports.forEach((i) => {
            let opt = window.document.createElement("option");
            opt.value = i;
            opt.textContent = i;
            this._portField.appendChild(opt);
        });
        !port && (this._port = port = ports[0]);
        this._portField.value = port;
        setTimeout(this.checkPorts.bind(this), 10000);
    }

    checkPort(port, ports, callback) {
        var url = `http://localhost:${port}`;
        var http_request = new XMLHttpRequest();

        http_request.onreadystatechange = () => {
            if (http_request.readyState == 4) {
                if (http_request.status == 200) {
                    ports.push(port);
                }
                if (port > 8089) {
                    return callback(null, ports);
                }
                this.checkPort(port + 1, ports, callback);
            }
        }
        http_request.open("OPTIONS", url, true);
        http_request.send();
    }

    addHistoryEntry(entry) {
        this._history.push(entry);
        var content = '';
        if (entry.type === 'request') {
            if (entry.method === 'GET') {
                content = `${entry.method} => ${entry.url}`;
            } else if (entry.method === 'POST') {
                content = `${entry.method} => ${entry.url}
                          (${entry.data.name}, ${entry.data.age})`;
            }
        }
        var onclick = this.restoreHistoryEntry.bind(this, this._history.length-1);
        this.addHistoryElement(this._history.length-1, content, '', onclick);
        return this._history.length-1;
    }

    setHistoryEntryState(number, success) {
        var id = `history-${number}`;
        var className = success? 'success' : 'danger';
        window.document.getElementById(id).className = className;
    }

    restoreHistoryEntry(number) {
        console.log(`Entry ${JSON.stringify(this._history[number])}`);
        if ('name' in this._history[number].data) {
            window.document.getElementById('name').value =
                this._history[number].data.name;
        }
        if ('age' in this._history[number].data) {
            window.document.getElementById('age').value =
                this._history[number].data.age;
        }
    }

    addHistoryLabel(description) {
        this.addHistoryElement('', description, 'info');
    }

    addHistoryElement(id, description, kind, onclick) {
        var tr = document.createElement("tr");
        tr.className = kind;
        if (id !== '' && id !== null && id !== undefined) {
            tr.id = `history-${id}`;
        }
        if (typeof onclick === 'function') {
            tr.onclick = onclick;
        }

        var tdDescription = tr.insertCell(document.createElement("td"));
        var tdId = tr.insertCell(document.createElement("td"));

        tdId.appendChild(document.createTextNode(id));
        tdDescription.appendChild(document.createTextNode(description));

        this._historyPanel.insertBefore(tr, this._historyPanel.childNodes[0]);
    }
}

<|endoftext|>


<commit_before>/*
 * node-static-alias
 * https://github.com/anseki/node-static-alias
 *
 * Copyright (c) 2017 anseki
 * Licensed under the MIT license.
 */

'use strict';

var staticSuper = require('node-static'),
  fs = require('fs'),
  events = require('events'),
  path = require('path'),
  url = require('url'),
  querystring = require('querystring'),
  platform = process.platform;

function Server() {
  var that = this;
  staticSuper.Server.apply(that, arguments); // Super class constructor

  if (that.options.alias) { // To Array
    if (!Array.isArray(that.options.alias)) {
      that.options.alias = [that.options.alias];
    }
    that.options.alias.forEach(function(alias) {
      alias.match = !alias.match ? [] :
        !Array.isArray(alias.match) ? [alias.match] :
        alias.match;
      alias.serve = !alias.serve ? ['<% absPath %>'] :
        !Array.isArray(alias.serve) ? [alias.serve] :
        alias.serve;
    });
  }

  if (that.options.logger) {
    ['info', 'log'].some(function(methodName) {
      if (typeof that.options.logger[methodName] === 'function') {
        that._log = function() {
          that.options.logger[methodName].apply(that.options.logger, arguments);
        };
        return true;
      }
      return false;
    });
  }
  that._log = that._log || function() {};
}

// util.inherits()
Server.prototype = Object.create(staticSuper.Server.prototype);
Server.prototype.constructor = Server;

Server.prototype.servePath = function(pathname, status, headers, req, res, finish) {
  var that = this,
    servePath = that.parsePath(pathname, req),
    promise = new events.EventEmitter();

  if (servePath) {
    fs.stat(servePath, function(e, stat) {
      if (e) {
        finish(404, {});
      } else if (stat.isFile()) { // Stream a single file.
        that.respond(null, status, headers, [servePath], stat, req, res, finish);
      } else if (stat.isDirectory()) { // Stream a directory of files.
        that.serveDir(servePath, req, res, finish);
      } else {
        finish(400, {});
      }
    });
  } else {
    // Forbidden
    finish(403, {});
  }
  return promise;
};

Server.prototype.parsePath = function(pathname, req) {
  var that = this,
    params = {absPath: that.resolve(pathname)},
    allowOutside = false,
    key, query, servePath;

  if (!that.options.alias) { return params.absPath; }

  if (req.headers) {
    // The strange HTTP header like a 'reqPath' may come from client. But, ignore it.
    for (key in req.headers) {
      if (key !== 'absPath') { params[key] = req.headers[key] + ''; }
    }
  }

  params.reqPath = pathname;
  params.reqDir = path.dirname(params.reqPath);
  params.absDir = path.dirname(params.absPath);
  params.fileName = path.basename(params.reqPath);
  // params.suffix = path.extname(params.reqPath).replace(/^\./, '');
  params.basename = params.fileName.replace(/^([^.].*)\.([^.]*)$/,
    function(s, basename, suffix) {
      params.suffix = suffix;
      return basename;
    });
  params.suffix = params.suffix != null ? params.suffix : '';

  if ((params.reqUrl = req.url) && (params.reqQuery = url.parse(params.reqUrl).query)) {
    query = querystring.parse(params.reqQuery);
    Object.keys(query).forEach(function(key) {
      if (typeof query[key] === 'string') {
        params['query_' + key] = query[key];
      } else { // it should be Array
        query[key].forEach(function(value, i) {
          params['query_' + key + '[' + i + ']'] = value + '';
        });
      }
    });
  }

  that._log('(%s) Requested: "%s"', params.reqPath, params.absPath);

  function inRoot(servePath) {
    return (platform === 'win32'
      ? servePath.toLowerCase().indexOf(that.root.toLowerCase()) : // Windows
      servePath.indexOf(that.root) // Others
    ) === 0 ? servePath : false;
  }

  function parseTemplate(template) {
    return template.replace(/<%\s*(.+?)\s*%>/g, function(s, key) {
      return params[key] != null ? params[key] : '';
    });
  }

  return that.options.alias.some(function(alias, iAlias) {
    var iMatch;
    if (!alias.match.some(function(match, i) {
      var key, value;
      if (typeof match === 'string') {
        value = match.replace(/^(?:(.*?)=)?(.*)$/, function(s, pKey, pValue) {
          key = pKey;
          return pValue;
        });
        if (params[key || 'reqPath'] === value) {
          iMatch = i;
          return true;
        }
        return false;
      }
      if (typeof match === 'object' && match instanceof RegExp && match.test(params.reqPath) ||
          typeof match === 'function' && match(params)) {
        iMatch = i;
        return true;
      }
      return false;
    })) {
      return false;
    }
    // matched
    return alias.serve.some(function(serve, iServe) {
      var absPath = // Not that.resolve() because it's not uri.
        typeof serve === 'string' ? path.resolve(that.root, parseTemplate(serve)) :
        typeof serve === 'function' ? path.resolve(that.root, serve(params)) :
        params.absPath;
      if (alias.force || fs.existsSync(absPath)) {
        servePath = absPath;
        allowOutside = alias.allowOutside;
        that._log('(%s) For Serve: "%s" alias[%d] match[%d] serve[%d]',
          params.reqPath, servePath, iAlias, iMatch, iServe);
        return true;
      }
      return false;
    });
  }) ? (allowOutside ? servePath : inRoot(servePath)) :
    inRoot(params.absPath);
};

exports.Server = Server;
exports.mime = staticSuper.mime;
<commit_msg>Pass request and response to `match` and `serve`<commit_after>/*
 * node-static-alias
 * https://github.com/anseki/node-static-alias
 *
 * Copyright (c) 2017 anseki
 * Licensed under the MIT license.
 */

'use strict';

var staticSuper = require('node-static'),
  fs = require('fs'),
  events = require('events'),
  path = require('path'),
  url = require('url'),
  querystring = require('querystring'),
  platform = process.platform;

function Server() {
  var that = this;
  staticSuper.Server.apply(that, arguments); // Super class constructor

  if (that.options.alias) { // To Array
    if (!Array.isArray(that.options.alias)) {
      that.options.alias = [that.options.alias];
    }
    that.options.alias.forEach(function(alias) {
      alias.match = !alias.match ? [] :
        !Array.isArray(alias.match) ? [alias.match] :
        alias.match;
      alias.serve = !alias.serve ? ['<% absPath %>'] :
        !Array.isArray(alias.serve) ? [alias.serve] :
        alias.serve;
    });
  }

  if (that.options.logger) {
    ['info', 'log'].some(function(methodName) {
      if (typeof that.options.logger[methodName] === 'function') {
        that._log = function() {
          that.options.logger[methodName].apply(that.options.logger, arguments);
        };
        return true;
      }
      return false;
    });
  }
  that._log = that._log || function() {};
}

// util.inherits()
Server.prototype = Object.create(staticSuper.Server.prototype);
Server.prototype.constructor = Server;

Server.prototype.servePath = function(pathname, status, headers, req, res, finish) {
  var that = this,
    servePath = that.parsePath(pathname, req, res),
    promise = new events.EventEmitter();

  if (servePath) {
    fs.stat(servePath, function(e, stat) {
      if (e) {
        finish(404, {});
      } else if (stat.isFile()) { // Stream a single file.
        that.respond(null, status, headers, [servePath], stat, req, res, finish);
      } else if (stat.isDirectory()) { // Stream a directory of files.
        that.serveDir(servePath, req, res, finish);
      } else {
        finish(400, {});
      }
    });
  } else {
    // Forbidden
    finish(403, {});
  }
  return promise;
};

Server.prototype.parsePath = function(pathname, req, res) {
  var that = this,
    params = {absPath: that.resolve(pathname)},
    allowOutside = false,
    key, query, servePath;

  if (!that.options.alias) { return params.absPath; }

  if (req.headers) {
    // The strange HTTP header like a 'reqPath' may come from client. But, ignore it.
    for (key in req.headers) {
      if (key !== 'absPath') { params[key] = req.headers[key] + ''; }
    }
  }

  params.reqPath = pathname;
  params.reqDir = path.dirname(params.reqPath);
  params.absDir = path.dirname(params.absPath);
  params.fileName = path.basename(params.reqPath);
  // params.suffix = path.extname(params.reqPath).replace(/^\./, '');
  params.basename = params.fileName.replace(/^([^.].*)\.([^.]*)$/,
    function(s, basename, suffix) {
      params.suffix = suffix;
      return basename;
    });
  params.suffix = params.suffix != null ? params.suffix : '';

  if ((params.reqUrl = req.url) && (params.reqQuery = url.parse(params.reqUrl).query)) {
    query = querystring.parse(params.reqQuery);
    Object.keys(query).forEach(function(key) {
      if (typeof query[key] === 'string') {
        params['query_' + key] = query[key];
      } else { // it should be Array
        query[key].forEach(function(value, i) {
          params['query_' + key + '[' + i + ']'] = value + '';
        });
      }
    });
  }

  that._log('(%s) Requested: "%s"', params.reqPath, params.absPath);

  function inRoot(servePath) {
    return (platform === 'win32'
      ? servePath.toLowerCase().indexOf(that.root.toLowerCase()) : // Windows
      servePath.indexOf(that.root) // Others
    ) === 0 ? servePath : false;
  }

  function parseTemplate(template) {
    return template.replace(/<%\s*(.+?)\s*%>/g, function(s, key) {
      return params[key] != null ? params[key] : '';
    });
  }

  return that.options.alias.some(function(alias, iAlias) {
    var iMatch;
    if (!alias.match.some(function(match, i) {
      var key, value;
      if (typeof match === 'string') {
        value = match.replace(/^(?:(.*?)=)?(.*)$/, function(s, pKey, pValue) {
          key = pKey;
          return pValue;
        });
        if (params[key || 'reqPath'] === value) {
          iMatch = i;
          return true;
        }
        return false;
      }
      if (typeof match === 'object' && match instanceof RegExp && match.test(params.reqPath) ||
          typeof match === 'function' && match(params, req, res)) {
        iMatch = i;
        return true;
      }
      return false;
    })) {
      return false;
    }
    // matched
    return alias.serve.some(function(serve, iServe) {
      var absPath = // Not that.resolve() because it's not uri.
        typeof serve === 'string' ? path.resolve(that.root, parseTemplate(serve)) :
        typeof serve === 'function' ? path.resolve(that.root, serve(params, req, res)) :
        params.absPath;
      if (alias.force || fs.existsSync(absPath)) {
        servePath = absPath;
        allowOutside = alias.allowOutside;
        that._log('(%s) For Serve: "%s" alias[%d] match[%d] serve[%d]',
          params.reqPath, servePath, iAlias, iMatch, iServe);
        return true;
      }
      return false;
    });
  }) ? (allowOutside ? servePath : inRoot(servePath)) :
    inRoot(params.absPath);
};

exports.Server = Server;
exports.mime = staticSuper.mime;
<|endoftext|>


<commit_before>var redis = require('redis');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

var redisStore = function(options) {
	this.options = options || {};
	this.host = this.options.host || 'localhost';
	this.port = this.options.port || 6379;
	this.prefix = this.options.prefix || 'kafka-node'
	this.delimiter = this.options.delimiter || ':'
}

util.inherits(redisStore, EventEmitter)

redisStore.prototype.init = function() {
	var self = this;
	this.store = redis.createClient(this.port, this.host, this.options);

	this.store.on('error', function(err) {

	})

	this.store.on('ready', function() {
		self.emit('ready');
	});

}

redisStore.prototype.fetch = function(topic, group, partition, callback) {
	var key = this.prefix + this.delimiter + topic + this.delimiter + group + this.delimiter + partition;
	this.store.get(key, function(err, reply) {
		var index = parseInt(reply);
		if (isNaN(reply)) {
			index = 0;
		}
		callback && callback(index);
	});
}

redisStore.prototype.commit = function(offset, topic, group, partition, callback) {
	var key = this.prefix + this.delimiter + topic + this.delimiter + group + this.delimiter + partition;
	this.store.watch(key);
	this.store
			.multi()
			.set(key, offset)
			.exec(function(err, reply) {
				callback && callback(err);
			});
}

redisStore.prototype.cleanup = function() {
	this.store.quit();
}

module.exports = redisStore;
<commit_msg>check correct variable for isNaN<commit_after>var redis = require('redis');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

var redisStore = function(options) {
	this.options = options || {};
	this.host = this.options.host || 'localhost';
	this.port = this.options.port || 6379;
	this.prefix = this.options.prefix || 'kafka-node'
	this.delimiter = this.options.delimiter || ':'
}

util.inherits(redisStore, EventEmitter)

redisStore.prototype.init = function() {
	var self = this;
	this.store = redis.createClient(this.port, this.host, this.options);

	this.store.on('error', function(err) {

	})

	this.store.on('ready', function() {
		self.emit('ready');
	});

}

redisStore.prototype.fetch = function(topic, group, partition, callback) {
	var key = this.prefix + this.delimiter + topic + this.delimiter + group + this.delimiter + partition;
	this.store.get(key, function(err, reply) {
		var index = parseInt(reply);
		if (isNaN(index)) {
			index = 0;
		}
		callback && callback(index);
	});
}

redisStore.prototype.commit = function(offset, topic, group, partition, callback) {
	var key = this.prefix + this.delimiter + topic + this.delimiter + group + this.delimiter + partition;
	this.store.watch(key);
	this.store
			.multi()
			.set(key, offset)
			.exec(function(err, reply) {
				callback && callback(err);
			});
}

redisStore.prototype.cleanup = function() {
	this.store.quit();
}

module.exports = redisStore;
<|endoftext|>


<commit_before>var _ = require('underscore'),
    assert = require('assert'),
    build = require('../lib/build'),
    Config = require('../lib/config'),
    Context = require('../lib/context'),
    Mixins = require('../lib/mixins'),
    plugin = require('../lib/plugin').create({});

plugin.initialize({ attributes: {} });

function exec(module, mixins, config, callback) {
  if (_.isFunction(config)) {
    callback = config;
    config = undefined;
  }

  config = Config.create(_.defaults({modules: {module: module}}, config));
  var context = new Context({module: module}, config, plugin, new Mixins({mixins: mixins}));

  context.mixins.initialize(context, function(err) {
    if (err) {
      throw err;
    }

    plugin.loadConfig(context, function(err) {
      if (err) {
        throw err;
      }

      callback(context.mixins, context);
    });
  });
}

describe('mixins', function() {
  describe('modules', function() {
    it('should mixin module attributes', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2'],
        bat: 3
      };

      var mixins = {
        mixin1: { foo: 1, baz: 1, bat: 1 },
        mixin2: { bar: 2, baz: 2, bat: 2 }
      };

      exec(module, [{mixins: mixins}], function() {
          assert.equal(module.foo, 1, 'foo should be written');
          assert.equal(module.bar, 2, 'bar should be written');
          assert.equal(module.baz, 2, 'baz should be overwritten');
          assert.equal(module.bat, 3, 'bat should not be overwritten');

          assert.deepEqual(mixins.mixin1, {foo: 1, baz: 1, bat: 1});
          assert.deepEqual(mixins.mixin2, {bar: 2, baz: 2, bat: 2});

          done();
        });
    });

    it('should merge routes', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2'],
        routes: { bat: 3 }
      };

      var mixins = {
        mixin1: {routes: { foo: 1, baz: 1, bat: 1 }},
        mixin2: {routes: { bar: 2, baz: 2, bat: 2 }}
      };

      exec(module, [{mixins: mixins}], function() {
          assert.equal(module.routes.foo, 1);//, 'foo should be written');
          assert.equal(module.routes.bar, 2, 'bar should be written');
          assert.equal(module.routes.baz, 2, 'baz should be overwritten');
          assert.equal(module.routes.bat, 3, 'bat should not be overwritten');

          assert.deepEqual(mixins.mixin1.routes, {foo: 1, baz: 1, bat: 1});
          assert.deepEqual(mixins.mixin2.routes, {bar: 2, baz: 2, bat: 2});

          done();
        });
    });

    it('should merge routes without modification', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2']
      };

      var mixins = {
        mixin1: {routes: { foo: 1, baz: 1, bat: 1 }},
        mixin2: {routes: { bar: 2, baz: 2, bat: 2 }}
      };

      exec(module, [{mixins: mixins}], function() {
          assert.equal(module.routes.foo, 1, 'foo should be written');
          assert.equal(module.routes.bar, 2, 'bar should be written');
          assert.equal(module.routes.baz, 2, 'baz should be overwritten');
          assert.equal(module.routes.bat, 2, 'bat should not be overwritten');

          assert.deepEqual(mixins.mixin1.routes, {foo: 1, baz: 1, bat: 1});
          assert.deepEqual(mixins.mixin2.routes, {bar: 2, baz: 2, bat: 2});

          done();
        });
    });

    it('should merge file arrays', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2'],
        scripts: [ {src: 'foo0', global: true }, {src: 'foo0.1', global: true}, 'bar0.1', 'bar0.2' ],
        styles: [ 'foo0', 'bar0' ]
      };

      var mixins = [
        {
          root: 'mixin1/',
          mixins: {
            mixin1: {
              scripts: [ {src: 'foo1.1', global: true}, {src: 'foo1.2', global: true}, 'bar1.1', 'bar1.2'],
              static: [ 'baz1.1', 'baz1.2' ]
            }
          }
        },
        {
          root: 'mixin2/',
          mixins: {
            mixin2: {
              scripts: [ {src: 'foo2.1', global: true}, {src: 'foo2.2', global: true}, 'bar2.1', 'bar2.2'],
              styles: [ 'foo2', 'bar2' ],
              static: [ 'baz2.1', 'baz2.2' ]
            }
          }
        }
      ];

      exec(module, mixins, function(mixins) {
          mixins = mixins.mixins;

          assert.deepEqual(module.scripts, [
            {src: 'mixin1/foo1.1', global: true, mixin: mixins.mixin1}, {src: 'mixin1/foo1.2', global: true, mixin: mixins.mixin1},
            {src: 'mixin2/foo2.1', global: true, mixin: mixins.mixin2}, {src: 'mixin2/foo2.2', global: true, mixin: mixins.mixin2},
            {src: 'foo0', global: true }, {src: 'foo0.1', global: true},
            {src: 'mixin1/bar1.1', mixin: mixins.mixin1}, {src: 'mixin1/bar1.2', mixin: mixins.mixin1},
            {src: 'mixin2/bar2.1', mixin: mixins.mixin2}, {src: 'mixin2/bar2.2', mixin: mixins.mixin2},
            'bar0.1', 'bar0.2'
          ]);
          assert.deepEqual(module.styles, [
            {src: 'mixin2/foo2', mixin: mixins.mixin2}, {src: 'mixin2/bar2', mixin: mixins.mixin2},
            'foo0', 'bar0'
          ]);
          assert.deepEqual(module.static, [
            {src: 'mixin1/baz1.1', mixin: mixins.mixin1}, {src: 'mixin1/baz1.2', mixin: mixins.mixin1},
            {src: 'mixin2/baz2.1', mixin: mixins.mixin2}, {src: 'mixin2/baz2.2', mixin: mixins.mixin2}
          ]);

          assert.deepEqual(mixins.mixin1.attributes.scripts, [ {src: 'foo1.1', global: true}, {src: 'foo1.2', global: true}, 'bar1.1', 'bar1.2']);
          assert.deepEqual(mixins.mixin1.attributes.static, [ 'baz1.1', 'baz1.2' ]);

          assert.deepEqual(mixins.mixin2.attributes.scripts, [ {src: 'foo2.1', global: true}, {src: 'foo2.2', global: true}, 'bar2.1', 'bar2.2']);
          assert.deepEqual(mixins.mixin2.attributes.styles, [ 'foo2', 'bar2' ]);
          assert.deepEqual(mixins.mixin2.attributes.static, [ 'baz2.1', 'baz2.2' ]);
          done();
        });
    });

    it('should allow files to be overriden', function(done) {
      var mixinDecl = {
        name: 'mixin1',
        overrides: {
          'baz1.1': 'foo',
          'baz1.2': true
        }
      };
      var module = {
        mixins: [
          mixinDecl,
          'mixin2'
        ],
        static: [ 'baz1.1' ]
      };

      var mixins = [
        {
          root: 'mixin1/',
          mixins: {
            mixin1: {
              static: [ 'baz1.1', 'baz1.2' ]
            }
          }
        },
        {
          root: 'mixin2/',
          mixins: {
            mixin2: {
              static: [ 'baz1.1', 'baz1.2' ]
            }
          }
        }
      ];

      exec(module, mixins, function(mixins) {
          mixins = mixins.mixins;

          var mixin1 = _.extend({}, mixinDecl, mixins.mixin1);

          assert.deepEqual(module.static, [
            {src: 'foo', originalSrc: 'mixin1/baz1.1', mixin: mixin1},
            {src: 'baz1.2', originalSrc: 'mixin1/baz1.2', mixin: mixin1},
            {src: 'mixin2/baz1.1', mixin: mixins.mixin2},
            {src: 'mixin2/baz1.2', mixin: mixins.mixin2},
            'baz1.1'
          ]);

          assert.deepEqual(mixins.mixin1.attributes.static, [ 'baz1.1', 'baz1.2' ]);
          assert.deepEqual(mixins.mixin2.attributes.static, [ 'baz1.1', 'baz1.2' ]);
          done();
        });
    });
  });
});

<commit_msg>Use mixinExec in mixin tests<commit_after>var _ = require('underscore'),
    assert = require('assert'),
    lib = require('./lib');

describe('mixins', function() {
  describe('modules', function() {
    it('should mixin module attributes', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2'],
        bat: 3
      };

      var mixins = {
        mixin1: { foo: 1, baz: 1, bat: 1 },
        mixin2: { bar: 2, baz: 2, bat: 2 }
      };

      lib.mixinExec(module, [{mixins: mixins}], function() {
          assert.equal(module.foo, 1, 'foo should be written');
          assert.equal(module.bar, 2, 'bar should be written');
          assert.equal(module.baz, 2, 'baz should be overwritten');
          assert.equal(module.bat, 3, 'bat should not be overwritten');

          assert.deepEqual(mixins.mixin1, {foo: 1, baz: 1, bat: 1});
          assert.deepEqual(mixins.mixin2, {bar: 2, baz: 2, bat: 2});

          done();
        });
    });

    it('should merge routes', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2'],
        routes: { bat: 3 }
      };

      var mixins = {
        mixin1: {routes: { foo: 1, baz: 1, bat: 1 }},
        mixin2: {routes: { bar: 2, baz: 2, bat: 2 }}
      };

      lib.mixinExec(module, [{mixins: mixins}], function() {
          assert.equal(module.routes.foo, 1);//, 'foo should be written');
          assert.equal(module.routes.bar, 2, 'bar should be written');
          assert.equal(module.routes.baz, 2, 'baz should be overwritten');
          assert.equal(module.routes.bat, 3, 'bat should not be overwritten');

          assert.deepEqual(mixins.mixin1.routes, {foo: 1, baz: 1, bat: 1});
          assert.deepEqual(mixins.mixin2.routes, {bar: 2, baz: 2, bat: 2});

          done();
        });
    });

    it('should merge routes without modification', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2']
      };

      var mixins = {
        mixin1: {routes: { foo: 1, baz: 1, bat: 1 }},
        mixin2: {routes: { bar: 2, baz: 2, bat: 2 }}
      };

      lib.mixinExec(module, [{mixins: mixins}], function() {
          assert.equal(module.routes.foo, 1, 'foo should be written');
          assert.equal(module.routes.bar, 2, 'bar should be written');
          assert.equal(module.routes.baz, 2, 'baz should be overwritten');
          assert.equal(module.routes.bat, 2, 'bat should not be overwritten');

          assert.deepEqual(mixins.mixin1.routes, {foo: 1, baz: 1, bat: 1});
          assert.deepEqual(mixins.mixin2.routes, {bar: 2, baz: 2, bat: 2});

          done();
        });
    });

    it('should merge file arrays', function(done) {
      var module = {
        mixins: ['mixin1', 'mixin2'],
        scripts: [ {src: 'foo0', global: true }, {src: 'foo0.1', global: true}, 'bar0.1', 'bar0.2' ],
        styles: [ 'foo0', 'bar0' ]
      };

      var mixins = [
        {
          root: 'mixin1/',
          mixins: {
            mixin1: {
              scripts: [ {src: 'foo1.1', global: true}, {src: 'foo1.2', global: true}, 'bar1.1', 'bar1.2'],
              static: [ 'baz1.1', 'baz1.2' ]
            }
          }
        },
        {
          root: 'mixin2/',
          mixins: {
            mixin2: {
              scripts: [ {src: 'foo2.1', global: true}, {src: 'foo2.2', global: true}, 'bar2.1', 'bar2.2'],
              styles: [ 'foo2', 'bar2' ],
              static: [ 'baz2.1', 'baz2.2' ]
            }
          }
        }
      ];

      lib.mixinExec(module, mixins, function(mixins) {
          mixins = mixins.mixins;

          assert.deepEqual(module.scripts, [
            {src: 'mixin1/foo1.1', global: true, mixin: mixins.mixin1}, {src: 'mixin1/foo1.2', global: true, mixin: mixins.mixin1},
            {src: 'mixin2/foo2.1', global: true, mixin: mixins.mixin2}, {src: 'mixin2/foo2.2', global: true, mixin: mixins.mixin2},
            {src: 'foo0', global: true }, {src: 'foo0.1', global: true},
            {src: 'mixin1/bar1.1', mixin: mixins.mixin1}, {src: 'mixin1/bar1.2', mixin: mixins.mixin1},
            {src: 'mixin2/bar2.1', mixin: mixins.mixin2}, {src: 'mixin2/bar2.2', mixin: mixins.mixin2},
            'bar0.1', 'bar0.2'
          ]);
          assert.deepEqual(module.styles, [
            {src: 'mixin2/foo2', mixin: mixins.mixin2}, {src: 'mixin2/bar2', mixin: mixins.mixin2},
            'foo0', 'bar0'
          ]);
          assert.deepEqual(module.static, [
            {src: 'mixin1/baz1.1', mixin: mixins.mixin1}, {src: 'mixin1/baz1.2', mixin: mixins.mixin1},
            {src: 'mixin2/baz2.1', mixin: mixins.mixin2}, {src: 'mixin2/baz2.2', mixin: mixins.mixin2}
          ]);

          assert.deepEqual(mixins.mixin1.attributes.scripts, [ {src: 'foo1.1', global: true}, {src: 'foo1.2', global: true}, 'bar1.1', 'bar1.2']);
          assert.deepEqual(mixins.mixin1.attributes.static, [ 'baz1.1', 'baz1.2' ]);

          assert.deepEqual(mixins.mixin2.attributes.scripts, [ {src: 'foo2.1', global: true}, {src: 'foo2.2', global: true}, 'bar2.1', 'bar2.2']);
          assert.deepEqual(mixins.mixin2.attributes.styles, [ 'foo2', 'bar2' ]);
          assert.deepEqual(mixins.mixin2.attributes.static, [ 'baz2.1', 'baz2.2' ]);
          done();
        });
    });

    it('should allow files to be overriden', function(done) {
      var mixinDecl = {
        name: 'mixin1',
        overrides: {
          'baz1.1': 'foo',
          'baz1.2': true
        }
      };
      var module = {
        mixins: [
          mixinDecl,
          'mixin2'
        ],
        static: [ 'baz1.1' ]
      };

      var mixins = [
        {
          root: 'mixin1/',
          mixins: {
            mixin1: {
              static: [ 'baz1.1', 'baz1.2' ]
            }
          }
        },
        {
          root: 'mixin2/',
          mixins: {
            mixin2: {
              static: [ 'baz1.1', 'baz1.2' ]
            }
          }
        }
      ];

      lib.mixinExec(module, mixins, function(mixins) {
          mixins = mixins.mixins;

          var mixin1 = _.extend({}, mixinDecl, mixins.mixin1);

          assert.deepEqual(module.static, [
            {src: 'foo', originalSrc: 'mixin1/baz1.1', mixin: mixin1},
            {src: 'baz1.2', originalSrc: 'mixin1/baz1.2', mixin: mixin1},
            {src: 'mixin2/baz1.1', mixin: mixins.mixin2},
            {src: 'mixin2/baz1.2', mixin: mixins.mixin2},
            'baz1.1'
          ]);

          assert.deepEqual(mixins.mixin1.attributes.static, [ 'baz1.1', 'baz1.2' ]);
          assert.deepEqual(mixins.mixin2.attributes.static, [ 'baz1.1', 'baz1.2' ]);
          done();
        });
    });
  });
});

<|endoftext|>


<commit_before>import chai from 'chai';
import sinon from 'sinon';
import { JSDOM } from 'jsdom';
import Modal from '../src/modal';
import Util from '../src/util';

chai.should();

const loading = () => {
  const arr = [...new Array(12).keys()].map(d => d + 1);

  const circles = arr.reduce((prev, d) => (
    `${prev}<span class="loading__circle loading__circle--${d}"></span>`
  ), '');

  return `<div class="loading">${circles}</div>`;
};

const domStr = `
<!DOCTYPE html>

      ${loading()}

`;

describe('Modal', () => {
  describe('Basic', () => {
    let modal = null;

    before(() => {
      const window = new JSDOM(domStr).window;
      global.document = window.document;

      modal = new Modal('main');
    });

    it('Extends: Util', () => {
      modal.should.be.an.instanceof(Util);
    });

    /**
     * Properties
     */
    it('Prop: modal, 容器实例', () => {
      const target = document.querySelector('.modal');

      modal.modal.should.be.eql(target);
    });
  });

  describe('Methods', () => {
    let modal = null;
    // dialogs
    let loading = null;
    let prompt = null;

    const activeName = 'modal--active';
    const dialogName = 'modal__dialog';
    const dialogActive = 'modal__dialog--active';

    const msgList = [
      ['custome message', 'custome message'],
      [NaN, 'NaN'],
      [0, '0'],
      [false, 'false'],
      [undefined, ''],
      [null, 'null'],
      [[], ''],
      [{}, '[object Object]'],
      ['', '<script>alert(\'&\');</script>'],
    ];

    before(() => {
      const window = new JSDOM(domStr).window;
      global.document = window.document;

      modal = new Modal('main');

      loading = document.querySelector('.modal__dialog--loading');
      prompt = document.querySelector('.modal__dialog--message');
    });

    it('prompt, 正确显示modal并切换dialog，可自定义message', () => {
      const [raw, encoded] = msgList[0];
      const state = {
        'loading': false,
        'message': true,
      };

      modal.prompt('message', raw);

      const result = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.true;
      // dialog状态
      result.should.be.eql(state);
      // 自定义message
      prompt.querySelector('.message').innerHTML.should.equal(encoded);
    });

    it('prompt, 无匹配dialog将抛出Error', () => {
      const func = () => { modal.prompt('nopanel'); };

      func.should.throw(Error);
    });

    it('prompt, 能处理多种数据类型message', () => {
      msgList.forEach(([raw, encoded]) => {
        modal.prompt('message', raw);
        prompt.querySelector('.message').innerHTML.should.equal(encoded);
      });
    });

    it('loading, loading效果，prompt语法糖', () => {
      const spy = sinon.spy(modal, 'prompt');

      modal.loading();

      spy.calledWithExactly('loading').should.be.true;
    });

    it('open, 显示modal，不显示任何dialog', () => {
      const state = {
        'loading': false,
        'message': false,
      };

      modal.open();

      const result = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.true;
      // dialog状态
      result.should.be.eql(state);
    });

    it('close, 隐藏modal，不显示任何dialog', () => {
      const state = {
        'loading': false,
        'message': false,
      };

      modal.close();

      const result = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.false;
      // dialog状态
      result.should.be.eql(state);
    });
  });
});
<commit_msg>test: 完善modal测试，methods每个test case新建modal实例，增加close属性的测试内容<commit_after>import chai from 'chai';
import sinon from 'sinon';
import { JSDOM } from 'jsdom';
import Modal from '../src/modal';
import Util from '../src/util';

chai.should();

const loading = () => {
  const arr = [...new Array(12).keys()].map(d => d + 1);

  const circles = arr.reduce((prev, d) => (
    `${prev}<span class="loading__circle loading__circle--${d}"></span>`
  ), '');

  return `<div class="loading">${circles}</div>`;
};

const domStr = `
<!DOCTYPE html>

      ${loading()}

`;

describe('Modal', () => {
  describe('Basic', () => {
    let modal = null;

    before(() => {
      const window = new JSDOM(domStr).window;
      global.document = window.document;

      modal = new Modal('main');
    });

    it('Extends: Util', () => {
      modal.should.be.an.instanceof(Util);
    });

    /**
     * Properties
     */
    it('Prop: modal, 容器实例', () => {
      const target = document.querySelector('.modal');

      modal.modal.should.be.eql(target);
    });
  });

  describe('Methods', () => {
    let modal = null;
    // dialogs
    let loading = null;
    let prompt = null;

    const activeName = 'modal--active';
    const dialogName = 'modal__dialog';
    const dialogActive = 'modal__dialog--active';

    const msgList = [
      ['custome message', 'custome message'],
      [NaN, 'NaN'],
      [0, '0'],
      [false, 'false'],
      [undefined, ''],
      [null, 'null'],
      [[], ''],
      [{}, '[object Object]'],
      ['', '<script>alert(\'&\');</script>'],
    ];

    beforeEach(() => {
      const window = new JSDOM(domStr).window;
      global.document = window.document;

      modal = new Modal('main');

      loading = document.querySelector('.modal__dialog--loading');
      prompt = document.querySelector('.modal__dialog--message');
    });

    it('初始态modal、dialogs都隐藏', () => {
      const state = {
        'loading': false,
        'message': false,
      };

      const result = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.false;
      // dialog状态
      result.should.be.eql(state);
    });

    it('prompt, 正确显示modal并切换dialog，可自定义message', () => {
      const [raw, encoded] = msgList[0];
      const state = {
        'loading': false,
        'message': true,
      };

      modal.prompt('message', raw);

      const result = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.true;
      // dialog状态
      result.should.be.eql(state);
      // 自定义message
      prompt.querySelector('.message').innerHTML.should.equal(encoded);
    });

    it('prompt, 无匹配dialog将抛出Error', () => {
      const func = () => { modal.prompt('nopanel'); };

      func.should.throw(Error);
    });

    it('prompt, 能处理多种数据类型message', () => {
      msgList.forEach(([raw, encoded]) => {
        modal.prompt('message', raw);
        prompt.querySelector('.message').innerHTML.should.equal(encoded);
      });
    });

    it('loading, loading效果，prompt语法糖', () => {
      const spy = sinon.spy(modal, 'prompt');

      modal.loading();

      spy.calledWithExactly('loading').should.be.true;
    });

    it('open, 显示modal，不显示任何dialog', () => {
      const state = {
        'loading': false,
        'message': false,
      };

      modal.open();

      const result = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.true;
      // dialog状态
      result.should.be.eql(state);
    });

    it('close, 隐藏modal，不显示任何dialog', () => {
      const state = {
        'loading': false,
        'message': false,
      };

      // testA
      modal.loading();
      modal.close();

      const resultA = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.false;
      // dialog状态
      resultA.should.be.eql(state);

      // testB
      modal.prompt('message', 'foo_bar_baz');
      modal.close();

      const resultB = {
        'loading': loading.classList.contains(dialogActive),
        'message': prompt.classList.contains(dialogActive),
      };

      // modal状态
      modal.modal.classList.contains(activeName).should.be.false;
      // dialog状态
      resultB.should.be.eql(state);
    });
  });
});
<|endoftext|>


<commit_before>
var venacava = require('../venacava.js')
, Core = venacava.Core
, Model = venacava.Model
, assert = require('assert')
, EventEmitter = require('events').EventEmitter
;

var randomId = function () {
    return 'test' + Math.floor(Math.random() * 1000000);
};

describe('Model', function () {

    var redis
    , newModel = function (options) {
	return new Model(randomId(), options);
    }
    ;

    it('should be constructable', function () {
	assert(newModel({}), 'unable to create a new model');
    });

    it('should have a name', function () {
	assert(newModel({}).hasOwnProperty('name'), 'model does not have a name');
    });

    describe('#methods', function () {
	it('should exist', function () {
	    assert(newModel({}).methods, 'model did not have the methods property.');
	});

	it('should have the functions from the construction argument', function () {
	    assert(newModel({
		methods: {
		    method: function () {}
		}
	    }).methods.method, 'model proto did not have the argument\'s method');
	});
    });

    describe('#createIfNotExists', function () {
	it('should exist and create a new instance', function (done) {
	    var id = randomId();
	    return newModel({}).createIfNotExists(id, {x: 1}, function (err, instance) {
		assert.ifError(err);
		assert(instance);
		done();
	    });
	});

	it('should call initialize on non-existant channels', function (done) {
	    var numCalled = 0
	    , model = newModel({
		initialize: function () {
		    numCalled = numCalled + 1;
		}
	    })
	    , id = randomId()
	    ;
	    return model.createIfNotExists(id, {x: 1}, function (err, instance) {
		assert.ifError(err);
		assert.equal(1,numCalled);
		done();
	    });
	});

	it('should not call initialize on existant channels', function (done) {
	    var numCalled = 0
	    , model = newModel({
		initialize: function () {
		    numCalled = numCalled + 1;
		}
	    })
	    , id = model.create({x: 1}).id
	    ;

	    assert.equal(1,numCalled)

	    return model.createIfNotExists(id, {x: 1}, function (err, instance) {
		assert.ifError(err);
		assert.equal(1,numCalled)
		done();
	    });
	});

	it('should have initial values equal to the creation arguments', function (done) {
	    var attrs = {x: 1}
	    , model = newModel({})
	    ;

	    return model.createIfNotExists(randomId(), attrs, function (err, instance) {
		assert.ifError(err);
		assert.deepEqual(instance.core.toJSON(), attrs, 'initial core did not have provided attributes.');
		done();
	    });
	});

	it('should return the object to be created', function (done) {
	    var model = newModel({})
	    , instance = model.createIfNotExists(randomId(), function (err, cbInstance) {
		assert.ifError(err);
		assert.equal(instance, cbInstance);
		done();
	    })
	    ;
	});

    });

    describe('#create', function () {

	it('should exist and create a new instance', function () {
	    assert(newModel({}).create({x: 1}));
	});

	describe('-> instance', function () {

	    it('should have a core', function () {
		var instance = newModel({}).create({x: 1});
		assert(instance.hasOwnProperty('core'), 'new instance did not have a core.');
		assert.equal(typeof instance.core, 'object', 'new instance core was not an object');
	    });

	    it('should have an id', function () {
		assert(newModel({}).create({x: 1}).hasOwnProperty('id'));
	    });

	    it('should have a channel property equal to the core channel', function () {
		var instance = newModel({}).create({x: 1});
		assert(instance.hasOwnProperty('channel'), 'new instance did not have a channel.');
		assert.equal(instance.channel, instance.core.channel);
	    });

	    it('should have a core channel prefixed with the model name', function () {
		var model = newModel({})
		, instance = model.create({x: 1})
		;
		assert.equal(0, instance.channel.indexOf(model.name));
	    });

	    it('should initialize with distinct channel names', function () {
		var model = newModel({});
		assert.notEqual(model.create({x: 1}).channel
				, model.create({x: 1}).channel);

	    });

	    it('should have initial values equal to the creation arguments', function () {
		var attrs = {x: 1}
		, instance = newModel({}).create(attrs)
		;
		assert.deepEqual(instance.core.toJSON(), attrs);
	    });

	    describe(':defaults', function () {
		it('should have default values from instance creation', function () {
		    var attrs = {x: 1}
		    , instance = newModel({
			defaults: attrs
		    }).create({})
		    ;
		    assert.deepEqual(instance.core.toJSON(), attrs, 'initial core did not have default attributes.');
		});

		it ('should override defaults with creation parameter', function () {
		    var attrs = {x: 2}
		    , instance = newModel({
			defaults: {
			    x: 1
			    , y: 1
			}
		    }).create(attrs)
		    ;
		    assert.deepEqual(instance.core.toJSON(), {
			x: 2
			, y: 1
		    }, 'initial core defaults were not overriden by creation argument.');
		    assert.deepEqual(attrs, {x: 2}, 'creation argument was mutated');
		});
	    });

	    describe(':initialize', function () {

		it('should be called by create', function (done) {
		    newModel({
			initialize: function () {
			    return done();
			}
		    }).create({});
		});

		it('should be called with an initialized core', function (done) {
		    var attrs = {x: 1};
		    newModel({
			defaults: attrs
			, initialize: function () {
			    assert.equal(typeof this.core, 'object', 'initialze called with a core which was not an object');
			    assert.deepEqual(this.core.toJSON(), attrs, 'core was not properly initialized before initialize method was called');
			    return done();
			}
		    }).create({});
		});

		it('should be called synchronously', function () {
		    var instance = newModel({
			initialize: function () {
			    this.initialized = true;
			}
		    }).create({});
		    assert(instance.initialized, 'create callback did not invoke initialized on the instance');
		});

		it('should not be called by get', function () {
		    var numCalled = 0;
		    var model = newModel({
			initialize: function () {
			    numCalled = numCalled + 1;
			}
		    });

		    model.get(randomId());
		    assert.equal(0, numCalled);
		});

		it('should get a model with the provided id', function () {
		    var model = newModel({})
		    , instance = model.create({})
		    ;
		    assert.equal(instance.channel, model.get(instance.id).channel);
		});

	    });

	    describe(':methods', function () {
		it('should exist on created instances', function () {
		    var instance = newModel({
			methods: {
			    method: function (arg) {
				assert(this.core, 'method was not called with a context containing the core.');
				assert.equal(arg, 1, 'method was not called with arguments');
			    }
			}
		    }).create({});
		    assert(instance.method, 'instance was not created with the defined method');
		    assert.equal(typeof instance.method, 'function', 'instance was not created with the defined method as a function');
		    instance.method(1)
		});
	    });

	});

    // 	describe(':async', function () {
    // 	    it('should be provided', function (done) {
    // 		newModel({}).create({}, done);
    // 	    });

    // 	    it('should be called after the core has been stored', function (done) {
    // 		var attrs = {x: 1};
    // 		newModel({}).create(attrs, function (err, instance) {
    // 		    assert.ifError(err);
    // 		    var dupCore = new Core(instance.core.channel, redis);
    // 		    dupCore.fetch(function (err) {
    // 			assert.ifError(err);
    // 			assert.deepEqual(dupCore.toJSON(), attrs);
    // 			return done();
    // 		    });
    // 		});
    // 	    });

    // 	    it('should be called after initialization', function (done) {
    // 		var instance = newModel({
    // 		    initialize: function () {
    // 			this.initialized = true;
    // 		    }
    // 		}).create({}, function () {
    // 		    assert(this.initialized, 'create callback called before initialize');
    // 		});
    // 	    });
    // 	});

    });

    describe('#get', function () {
	it('should retrieve an object with a core of the same channel', function () {
	    var model = newModel({})
	    , instance = model.create({})
	    , dup = model.get(instance.id)
	    ;
	    assert.equal(dup.channel, instance.channel);
	});
    });

    describe(':initialize', function () {
	it('should not be called by create', function () {
	    var model = newModel({
		initialize: function () {
		    this.initialized = true;
		}
	    })
	    , instance = model.create({})
	    , dup = model.get(instance.id)
	    ;
	    assert(!dup.initialized);
	});
    });

    describe(':methods', function () {
	it('should exist on instances obtained from #get', function () {
	    var model = newModel({
		methods: {
		    method: function (arg) {
			assert(this.core, 'method was not called with a context containing the core.');
			assert.equal(arg, 1, 'method was not called with arguments');
		    }
		}
	    })
	    , instance = model.create({})
	    , dup = model.get(instance.channel)
	    ;
	    assert(dup.method);
	    assert.equal('function', typeof dup.method);
	    dup.method(1)
	});
    });
});
<commit_msg>Add test for default arguments in model.createIfNotExists, and fix some additional minor issues.<commit_after>
var venacava = require('../venacava.js')
, Core = venacava.Core
, Model = venacava.Model
, assert = require('assert')
, EventEmitter = require('events').EventEmitter
;

var randomId = function () {
    return 'test' + Math.floor(Math.random() * 1000000);
};

describe('Model', function () {

    var redis
    , newModel = function (options) {
	return new Model(randomId(), options);
    }
    ;

    it('should be constructable', function () {
	assert(newModel({}), 'unable to create a new model');
    });

    it('should have a name', function () {
	assert(newModel({}).hasOwnProperty('name'), 'model does not have a name');
    });

    describe('#methods', function () {
	it('should exist', function () {
	    assert(newModel({}).methods, 'model did not have the methods property.');
	});

	it('should have the functions from the construction argument', function () {
	    assert(newModel({
		methods: {
		    method: function () {}
		}
	    }).methods.method, 'model proto did not have the argument\'s method');
	});
    });

    describe('#createIfNotExists', function () {
	it('should exist and create a new instance', function (done) {
	    var id = randomId();
	    return newModel({}).createIfNotExists(id, {x: 1}, function (err, instance) {
		assert.ifError(err);
		assert(instance);
		done();
	    });
	});

	it('should call initialize on non-existant channels', function (done) {
	    var numCalled = 0
	    , model = newModel({
		initialize: function () {
		    numCalled = numCalled + 1;
		}
	    })
	    , id = randomId()
	    ;
	    return model.createIfNotExists(id, {x: 1}, function (err, instance) {
		assert.ifError(err);
		assert.equal(1,numCalled);
		done();
	    });
	});

	it('should not call initialize on existant channels', function (done) {
	    var numCalled = 0
	    , model = newModel({
		initialize: function () {
		    numCalled = numCalled + 1;
		}
	    })
	    , id = model.create({x: 1}).id
	    ;

	    assert.equal(1,numCalled)

	    return model.createIfNotExists(id, {x: 1}, function (err, instance) {
		assert.ifError(err);
		assert.equal(1,numCalled)
		done();
	    });
	});

	it('should have initial values equal to defaults when no attrs provided', function (done) {
	    var numCalled = 0
	    , model = newModel({
		defaults: {
		    x: 1
		}
	    })
	    ;
	    return model.createIfNotExists(randomId(), function (err, instance) {
		assert.ifError(err);
		instance.core.fetch(function (err) {
		    assert.ifError(err);
		    assert.equal(instance.core.get('x'), 1);
		    done();
		});
	    });
	});

	it('should have initial values equal to the creation arguments', function (done) {
	    var attrs = {x: 1}
	    , model = newModel({})
	    ;

	    return model.createIfNotExists(randomId(), attrs, function (err, instance) {
		assert.ifError(err);
		assert.deepEqual(instance.core.toJSON(), attrs, 'initial core did not have provided attributes.');
		done();
	    });
	});

	it('should return the object to be created', function (done) {
	    var model = newModel({})
	    , instance = model.createIfNotExists(randomId(), function (err, cbInstance) {
		assert.ifError(err);
		assert.equal(instance, cbInstance);
		done();
	    })
	    ;
	});

    });

    describe('#create', function () {

	it('should exist and create a new instance', function () {
	    assert(newModel({}).create({x: 1}));
	});

	describe('-> instance', function () {

	    it('should have a core', function () {
		var instance = newModel({}).create({x: 1});
		assert(instance.hasOwnProperty('core'), 'new instance did not have a core.');
		assert.equal(typeof instance.core, 'object', 'new instance core was not an object');
	    });

	    it('should have an id', function () {
		assert(newModel({}).create({x: 1}).hasOwnProperty('id'));
	    });

	    it('should have a channel property equal to the core channel', function () {
		var instance = newModel({}).create({x: 1});
		assert(instance.hasOwnProperty('channel'), 'new instance did not have a channel.');
		assert.equal(instance.channel, instance.core.channel);
	    });

	    it('should have a core channel prefixed with the model name', function () {
		var model = newModel({})
		, instance = model.create({x: 1})
		;
		assert.equal(0, instance.channel.indexOf(model.name));
	    });

	    it('should initialize with distinct channel names', function () {
		var model = newModel({});
		assert.notEqual(model.create({x: 1}).channel
				, model.create({x: 1}).channel);

	    });

	    it('should have initial values equal to the creation arguments', function () {
		var attrs = {x: 1}
		, instance = newModel({}).create(attrs)
		;
		assert.deepEqual(instance.core.toJSON(), attrs);
	    });

	    describe(':defaults', function () {
		it('should have default values from instance creation', function () {
		    var attrs = {x: 1}
		    , instance = newModel({
			defaults: attrs
		    }).create({})
		    ;
		    assert.deepEqual(instance.core.toJSON(), attrs, 'initial core did not have default attributes.');
		});

		it ('should override defaults with creation parameter', function () {
		    var attrs = {x: 2}
		    , instance = newModel({
			defaults: {
			    x: 1
			    , y: 1
			}
		    }).create(attrs)
		    ;
		    assert.deepEqual(instance.core.toJSON(), {
			x: 2
			, y: 1
		    }, 'initial core defaults were not overriden by creation argument.');
		    assert.deepEqual(attrs, {x: 2});
		});
	    });

	    describe(':initialize', function () {

		it('should be called by create', function (done) {
		    newModel({
			initialize: function () {
			    return done();
			}
		    }).create({});
		});

		it('should be called with an initialized core', function (done) {
		    var attrs = {x: 1};
		    newModel({
			defaults: attrs
			, initialize: function () {
			    assert.equal(typeof this.core, 'object', 'initialze called with a core which was not an object');
			    assert.deepEqual(this.core.toJSON(), attrs, 'core was not properly initialized before initialize method was called');
			    return done();
			}
		    }).create({});
		});

		it('should be called synchronously', function () {
		    var instance = newModel({
			initialize: function () {
			    this.initialized = true;
			}
		    }).create({});
		    assert(instance.initialized, 'create callback did not invoke initialized on the instance');
		});

		it('should not be called by get', function () {
		    var numCalled = 0;
		    var model = newModel({
			initialize: function () {
			    numCalled = numCalled + 1;
			}
		    });

		    model.get(randomId());
		    assert.equal(0, numCalled);
		});

		it('should get a model with the provided id', function () {
		    var model = newModel({})
		    , instance = model.create({})
		    ;
		    assert.equal(instance.channel, model.get(instance.id).channel);
		});

	    });

	    describe(':methods', function () {
		it('should exist on created instances', function () {
		    var instance = newModel({
			methods: {
			    method: function (arg) {
				assert(this.core, 'method was not called with a context containing the core.');
				assert.equal(arg, 1, 'method was not called with arguments');
			    }
			}
		    }).create({});
		    assert(instance.method, 'instance was not created with the defined method');
		    assert.equal(typeof instance.method, 'function', 'instance was not created with the defined method as a function');
		    instance.method(1)
		});
	    });

	});

    // 	describe(':async', function () {
    // 	    it('should be provided', function (done) {
    // 		newModel({}).create({}, done);
    // 	    });

    // 	    it('should be called after the core has been stored', function (done) {
    // 		var attrs = {x: 1};
    // 		newModel({}).create(attrs, function (err, instance) {
    // 		    assert.ifError(err);
    // 		    var dupCore = new Core(instance.core.channel, redis);
    // 		    dupCore.fetch(function (err) {
    // 			assert.ifError(err);
    // 			assert.deepEqual(dupCore.toJSON(), attrs);
    // 			return done();
    // 		    });
    // 		});
    // 	    });

    // 	    it('should be called after initialization', function (done) {
    // 		var instance = newModel({
    // 		    initialize: function () {
    // 			this.initialized = true;
    // 		    }
    // 		}).create({}, function () {
    // 		    assert(this.initialized, 'create callback called before initialize');
    // 		});
    // 	    });
    // 	});

    });

    describe('#get', function () {
	it('should retrieve an object with a core of the same channel', function () {
	    var model = newModel({})
	    , instance = model.create({})
	    , dup = model.get(instance.id)
	    ;
	    assert.equal(dup.channel, instance.channel);
	});
    });

    describe(':initialize', function () {
	it('should not be called by get', function () {
	    var model = newModel({
		initialize: function () {
		    this.initialized = true;
		}
	    })
	    , instance = model.create({})
	    , dup = model.get(instance.id)
	    ;
	    assert(!dup.initialized);
	});
    });

    describe(':methods', function () {
	it('should exist on instances obtained from #get', function () {
	    var model = newModel({
		methods: {
		    method: function (arg) {
			assert(this.core, 'method was not called with a context containing the core.');
			assert.equal(arg, 1, 'method was not called with arguments');
		    }
		}
	    })
	    , instance = model.create({})
	    , dup = model.get(instance.channel)
	    ;
	    assert(dup.method);
	    assert.equal('function', typeof dup.method);
	    dup.method(1)
	});
    });
});
<|endoftext|>


<commit_before>/* global $ requests server sidebar edits helper */
'use strict';
// ==UserScript==
// @name         MusicBrainz edit: Mark recordings as video
// @namespace    mbz-loujine
// @author       loujine
// @version      2021.4.24
// @downloadURL  https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/mb-edit-set_video_recordings.user.js
// @updateURL    https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/mb-edit-set_video_recordings.user.js
// @supportURL   https://github.com/loujine/musicbrainz-scripts
// @icon         https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/icon.png
// @description  musicbrainz.org: Mark recordings as video
// @compatible   firefox+tampermonkey
// @license      MIT
// @require      https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/mbz-loujine-common.js
// @include      http*://*musicbrainz.org/release/*
// @exclude      http*://*musicbrainz.org/release/add
// @exclude      http*://*musicbrainz.org/release/*/edit
// @exclude      http*://*musicbrainz.org/release/*/edit-relationships
// @grant        none
// @run-at       document-end
// ==/UserScript==

function showSelectors() {
    Array.from(document.getElementsByClassName('subh')).map(
        el => el.insertAdjacentHTML('beforeend',
            'video	')
    );

    const rows = document.querySelectorAll('table.tbl tr.odd,tr.even');
    Array.from(rows).map(row => {
        const mbid = helper.mbidFromURL(
            row.querySelector('a[href*="/recording/"]').href
        );
        row.insertAdjacentHTML('beforeend', `

              <input id="video-${mbid}" class="replacevideo" type="checkbox" value="Set video">

        `);
    });

    let lastChecked;
    $('.replacevideo').click(function (evt) {
        let currentChecked = $('.replacevideo').index(evt.target);
        if (evt.shiftKey && lastChecked !== undefined) {
            if (lastChecked > currentChecked) {
                // es6 syntax
                [lastChecked, currentChecked] = [currentChecked, lastChecked];
            }
            $('.replacevideo').slice(lastChecked,
                currentChecked).prop('checked', evt.target.checked);
        }
        lastChecked = $('.replacevideo').index(evt.target);
    });
}

function parseEditData(editData, msg) {
    const data = {};
    data.name = edits.encodeName(editData.name);
    data.video = "1";
    if (!editData.isrcs.length) {
        data['isrcs.0'] = null;
    } else {
        editData.isrcs.forEach(function (isrc, idx) {
            data['isrcs.' + idx] = isrc.isrc;
        });
    }
    data.edit_note = sidebar.editNote(GM_info.script, msg);
    data.make_votable = document.getElementById('votable').checked ? '1' : '0';
    return data;
}

function setVideo() {
    $('.replacevideo:input:checked:enabled').each(function (idx, node) {
        const mbid = node.id.replace('video-', '');
        const url = edits.urlFromMbid('recording', mbid);
        const msg = `
            Track ${document.URL.split('release')[0]}track/${node.parentElement.parentElement.id}
            on release ${document.URL}
        `;
        function success(xhr) {
            const $status = $('#' + node.id + '-text');
            node.disabled = true;
            $status.text(
                'Success (code ' + xhr.status + ')'
            ).parent().css('color', 'green');
            const editId = new RegExp(
                '/edit/(\\d+)">edit'
            ).exec(xhr.responseText)[1];
            $status.after(
                $('
').append(
                    `<a href="/edit/${editId}" target="_blank">` +
                    `edit ${editId}</a>`
                )
            )
        }
        function fail(xhr) {
            $('#' + node.id + '-text').text(
                'Error (code ' + xhr.status + ')'
            ).parent().css('color', 'red');
        }
        function callback(editData) {
            if (editData.video) {
                $('#' + node.id + '-text').text('Already video recording');
                node.disabled = true;
                return;
            }
            $('#' + node.id + '-text').text('Sending edit data');
            const postData = parseEditData(editData, msg);
            console.info('Data ready to be posted: ', postData);
            requests.POST(
                url,
                edits.formatEdit('edit-recording', postData),
                success,
                fail
            );
        }
        setTimeout(function () {
            $('#' + node.id + '-text').empty();
            $(node).after(
                `<span id="${node.id}-text">Fetching required data</span>`
            );
            edits.getEditParams(url, callback);
        }, 2 * idx * server.timeout);
    });
}

(function displaySidebar() {
    sidebar.container().insertAdjacentHTML('beforeend', `

            Set video

          <input type="button" id="batch_video_select" value="Select all">

              Make all edits votable
              <input type="checkbox" id="votable">

          <input type="button" id="batch_video" value="Set video attribute">

    `);
})();

$(document).ready(function () {
    document.getElementById('video_script_toggle').addEventListener('click', () => {
        if (!document.getElementsByClassName('videoSelectorColumn').length) {
            showSelectors();
        }
    });
    document.getElementById('batch_video_select').addEventListener('click', () => {
        $('.replacevideo:input').filter(':visible').prop('checked', true);
    });
    document.getElementById('batch_video').addEventListener('click', setVideo);
    return false;
});
<commit_msg>[video recordings] Add editable edit note<commit_after>/* global $ requests server sidebar edits helper */
'use strict';
// ==UserScript==
// @name         MusicBrainz edit: Mark recordings as video
// @namespace    mbz-loujine
// @author       loujine
// @version      2021.4.27
// @downloadURL  https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/mb-edit-set_video_recordings.user.js
// @updateURL    https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/mb-edit-set_video_recordings.user.js
// @supportURL   https://github.com/loujine/musicbrainz-scripts
// @icon         https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/icon.png
// @description  musicbrainz.org: Mark recordings as video
// @compatible   firefox+tampermonkey
// @license      MIT
// @require      https://raw.githubusercontent.com/loujine/musicbrainz-scripts/master/mbz-loujine-common.js
// @include      http*://*musicbrainz.org/release/*
// @exclude      http*://*musicbrainz.org/release/add
// @exclude      http*://*musicbrainz.org/release/*/edit
// @exclude      http*://*musicbrainz.org/release/*/edit-relationships
// @grant        none
// @run-at       document-end
// ==/UserScript==

const editNoteMsg = `
    From release ${document.URL}
`;

function showSelectors() {
    Array.from(document.getElementsByClassName('subh')).map(
        el => el.insertAdjacentHTML('beforeend',
            'video	')
    );

    const rows = document.querySelectorAll('table.tbl tr.odd,tr.even');
    Array.from(rows).map(row => {
        const mbid = helper.mbidFromURL(
            row.querySelector('a[href*="/recording/"]').href
        );
        row.insertAdjacentHTML('beforeend', `

              <input id="video-${mbid}" class="replacevideo" type="checkbox" value="Set video">

        `);
    });

    let lastChecked;
    $('.replacevideo').click(function (evt) {
        let currentChecked = $('.replacevideo').index(evt.target);
        if (evt.shiftKey && lastChecked !== undefined) {
            if (lastChecked > currentChecked) {
                // es6 syntax
                [lastChecked, currentChecked] = [currentChecked, lastChecked];
            }
            $('.replacevideo').slice(lastChecked,
                currentChecked).prop('checked', evt.target.checked);
        }
        lastChecked = $('.replacevideo').index(evt.target);
    });
}

function parseEditData(editData) {
    const data = {};
    data.name = edits.encodeName(editData.name);
    data.video = "1";
    if (!editData.isrcs.length) {
        data['isrcs.0'] = null;
    } else {
        editData.isrcs.forEach(function (isrc, idx) {
            data['isrcs.' + idx] = isrc.isrc;
        });
    }
    data.make_votable = document.getElementById('votable').checked ? '1' : '0';
    return data;
}

function setVideo() {
    $('.replacevideo:input:checked:enabled').each(function (idx, node) {
        const mbid = node.id.replace('video-', '');
        const url = edits.urlFromMbid('recording', mbid);
        function success(xhr) {
            const $status = $('#' + node.id + '-text');
            node.disabled = true;
            $status.text(
                'Success (code ' + xhr.status + ')'
            ).parent().css('color', 'green');
            const editId = new RegExp(
                '/edit/(\\d+)">edit'
            ).exec(xhr.responseText)[1];
            $status.after(
                $('
').append(
                    `<a href="/edit/${editId}" target="_blank">` +
                    `edit ${editId}</a>`
                )
            )
        }
        function fail(xhr) {
            $('#' + node.id + '-text').text(
                'Error (code ' + xhr.status + ')'
            ).parent().css('color', 'red');
        }
        function callback(editData) {
            if (editData.video) {
                $('#' + node.id + '-text').text('Already video recording');
                node.disabled = true;
                return;
            }
            $('#' + node.id + '-text').text('Sending edit data');
            const postData = parseEditData(editData);
            console.info('Data ready to be posted: ', postData);
            requests.POST(
                url,
                edits.formatEdit('edit-recording', postData),
                success,
                fail
            );
        }
        setTimeout(function () {
            $('#' + node.id + '-text').empty();
            $(node).after(
                `<span id="${node.id}-text">Fetching required data</span>`
            );
            edits.getEditParams(url, callback);
        }, 2 * idx * server.timeout);
    });
}

(function displaySidebar() {
    sidebar.container().insertAdjacentHTML('beforeend', `

            Set video

          <input type="button" id="batch_video_select" value="Select all">

              Make all edits votable
              <input type="checkbox" id="votable">

Edit note:
          <textarea id="batch_video_edit_note">
            ${sidebar.editNote(GM_info.script, editNoteMsg)}
          </textarea>
          <input type="button" id="batch_video" value="Set video attribute">

    `);
})();

$(document).ready(function () {
    document.getElementById('video_script_toggle').addEventListener('click', () => {
        if (!document.getElementsByClassName('videoSelectorColumn').length) {
            showSelectors();
        }
    });
    document.getElementById('batch_video_select').addEventListener('click', () => {
        $('.replacevideo:input').filter(':visible').prop('checked', true);
    });
    document.getElementById('batch_video').addEventListener('click', setVideo);
    return false;
});
<|endoftext|>