<commit_before>import fs from 'fs';
import shell from 'shell';
import {Message, DraftStore} from 'nylas-exports';
import TemplateStore from '../lib/template-store';

const stubTemplatesDir = '~/.nylas/templates';

const stubTemplateFiles = {
  'template1.html': '
bla1
',
  'template2.html': '
bla2
',
};

const stubTemplates = [
  {id: 'template1.html', name: 'template1', path: `${stubTemplatesDir}/template1.html`},
  {id: 'template2.html', name: 'template2', path: `${stubTemplatesDir}/template2.html`},
];

describe('TemplateStore', ()=> {
  beforeEach(()=> {
    spyOn(fs, 'mkdir');
    spyOn(shell, 'showItemInFolder').andCallFake(()=> {});
    spyOn(fs, 'writeFile').andCallFake((path, contents, callback)=> {
      callback(null);
    });
    spyOn(fs, 'readFile').andCallFake((path, callback)=> {
      const filename = path.split('/').pop();
      callback(null, stubTemplateFiles[filename]);
    });
  });

  it('should create the templates folder if it does not exist', ()=> {
    spyOn(fs, 'exists').andCallFake((path, callback)=> callback(false) );
    TemplateStore._init(stubTemplatesDir);
    expect(fs.mkdir).toHaveBeenCalled();
  });

  it('should expose templates in the templates directory', ()=> {
    let watchCallback;
    spyOn(fs, 'exists').andCallFake((path, callback)=> { callback(true); });
    spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
    spyOn(fs, 'readdir').andCallFake((path, callback)=> { callback(null, Object.keys(stubTemplateFiles)); });
    TemplateStore._init(stubTemplatesDir);
    watchCallback();
    expect(TemplateStore.items()).toEqual(stubTemplates);
  });

  it('should watch the templates directory and reflect changes', ()=> {
    let watchCallback = null;
    let watchFired = false;

    spyOn(fs, 'exists').andCallFake((path, callback)=> callback(true));
    spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
    spyOn(fs, 'readdir').andCallFake((path, callback)=> {
      if (watchFired) {
        callback(null, Object.keys(stubTemplateFiles));
      } else {
        callback(null, []);
      }
    });
    TemplateStore._init(stubTemplatesDir);
    expect(TemplateStore.items()).toEqual([]);

    watchFired = true;
    watchCallback();
    expect(TemplateStore.items()).toEqual(stubTemplates);
  });

  describe('insertTemplateId', ()=> {
    xit('should insert the template with the given id into the draft with the given id', ()=> {
      let watchCallback;
      spyOn(fs, 'exists').andCallFake((path, callback)=> { callback(true); });
      spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
      spyOn(fs, 'readdir').andCallFake((path, callback)=> { callback(null, Object.keys(stubTemplateFiles)); });
      TemplateStore._init(stubTemplatesDir);
      watchCallback();
      const add = jasmine.createSpy('add');
      spyOn(DraftStore, 'sessionForClientId').andCallFake(()=> {
        return Promise.resolve({changes: {add}});
      });

      runs(()=> {
        TemplateStore._onInsertTemplateId({
          templateId: 'template1.html',
          draftClientId: 'localid-draft',
        });
      });
      waitsFor(()=> add.calls.length > 0);
      runs(()=> {
        expect(add).toHaveBeenCalledWith({
          body: stubTemplateFiles['template1.html'],
        });
      });
    });
  });

  describe('onCreateTemplate', ()=> {
    beforeEach(()=> {
      let d;
      spyOn(DraftStore, 'sessionForClientId').andCallFake((draftClientId)=> {
        if (draftClientId === 'localid-nosubject') {
          d = new Message({subject: '', body: '
Body
'});
        } else {
          d = new Message({subject: 'Subject', body: '
Body
'});
        }
        const session = {draft() { return d; }};
        return Promise.resolve(session);
      });
      TemplateStore._init(stubTemplatesDir);
    });

    xit('should create a template with the given name and contents', ()=> {
      const ref = TemplateStore.items();
      TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
      const item = (ref != null ? ref[0] : undefined);
      expect(item.id).toBe('123.html');
      expect(item.name).toBe('123');
      expect(item.path.split('/').pop()).toBe('123.html');
    });

    xit('should display an error if no name is provided', ()=> {
      spyOn(TemplateStore, '_displayError');
      TemplateStore._onCreateTemplate({contents: 'bla'});
      expect(TemplateStore._displayError).toHaveBeenCalled();
    });

    xit('should display an error if no content is provided', ()=> {
      spyOn(TemplateStore, '_displayError');
      TemplateStore._onCreateTemplate({name: 'bla'});
      expect(TemplateStore._displayError).toHaveBeenCalled();
    });

    xit('should save the template file to the templates folder', ()=> {
      TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
      const path = `${stubTemplatesDir}/123.html`;
      expect(fs.writeFile).toHaveBeenCalled();
      expect(fs.writeFile.mostRecentCall.args[0]).toEqual(path);
      expect(fs.writeFile.mostRecentCall.args[1]).toEqual('bla');
    });

    xit('should open the template so you can see it', ()=> {
      TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
      expect(shell.showItemInFolder).toHaveBeenCalled();
    });

    describe('when given a draft id', ()=> {
      xit('should create a template from the name and contents of the given draft', ()=> {
        spyOn(TemplateStore, 'trigger');
        spyOn(TemplateStore, '_populate');
        runs(()=> {
          TemplateStore._onCreateTemplate({draftClientId: 'localid-b'});
        });
        waitsFor(()=> TemplateStore.trigger.callCount > 0 );
        runs(()=> {
          expect(TemplateStore.items().length).toEqual(1);
        });
      });

      it('should display an error if the draft has no subject', ()=> {
        spyOn(TemplateStore, '_displayError');
        runs(()=> {
          TemplateStore._onCreateTemplate({draftClientId: 'localid-nosubject'});
        });
        waitsFor(()=> TemplateStore._displayError.callCount > 0 );
        runs(()=> {
          expect(TemplateStore._displayError).toHaveBeenCalled();
        });
      });
    });
  });

  describe('onShowTemplates', ()=> {
    xit('should open the templates folder in the Finder', ()=> {
      TemplateStore._onShowTemplates();
      expect(shell.showItemInFolder).toHaveBeenCalled();
    });
  });
});
<commit_msg>fix(specs): Minor change to templates package for Travis<commit_after>import fs from 'fs';
import shell from 'shell';
import {Message, DraftStore} from 'nylas-exports';
import TemplateStore from '../lib/template-store';

const stubTemplatesDir = '~/.nylas/templates';

const stubTemplateFiles = {
  'template1.html': '
bla1
',
  'template2.html': '
bla2
',
};

const stubTemplates = [
  {id: 'template1.html', name: 'template1', path: `${stubTemplatesDir}/template1.html`},
  {id: 'template2.html', name: 'template2', path: `${stubTemplatesDir}/template2.html`},
];

describe('TemplateStore', ()=> {
  beforeEach(()=> {
    spyOn(fs, 'mkdir');
    spyOn(shell, 'showItemInFolder').andCallFake(()=> {});
    spyOn(fs, 'writeFile').andCallFake((path, contents, callback)=> {
      callback(null);
    });
    spyOn(fs, 'readFile').andCallFake((path, callback)=> {
      const filename = path.split('/').pop();
      callback(null, stubTemplateFiles[filename]);
    });
  });

  it('should create the templates folder if it does not exist', ()=> {
    spyOn(fs, 'exists').andCallFake((path, callback)=> callback(false) );
    TemplateStore._init(stubTemplatesDir);
    expect(fs.mkdir).toHaveBeenCalled();
  });

  it('should expose templates in the templates directory', ()=> {
    let watchCallback;
    spyOn(fs, 'exists').andCallFake((path, callback)=> { callback(true); });
    spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
    spyOn(fs, 'readdir').andCallFake((path, callback)=> { callback(null, Object.keys(stubTemplateFiles)); });
    TemplateStore._init(stubTemplatesDir);
    watchCallback();
    expect(TemplateStore.items()).toEqual(stubTemplates);
  });

  it('should watch the templates directory and reflect changes', ()=> {
    let watchCallback = null;
    let watchFired = false;

    spyOn(fs, 'exists').andCallFake((path, callback)=> callback(true));
    spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
    spyOn(fs, 'readdir').andCallFake((path, callback)=> {
      if (watchFired) {
        callback(null, Object.keys(stubTemplateFiles));
      } else {
        callback(null, []);
      }
    });
    TemplateStore._init(stubTemplatesDir);
    expect(TemplateStore.items()).toEqual([]);

    watchFired = true;
    watchCallback();
    expect(TemplateStore.items()).toEqual(stubTemplates);
  });

  describe('insertTemplateId', ()=> {
    xit('should insert the template with the given id into the draft with the given id', ()=> {
      let watchCallback;
      spyOn(fs, 'exists').andCallFake((path, callback)=> { callback(true); });
      spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
      spyOn(fs, 'readdir').andCallFake((path, callback)=> { callback(null, Object.keys(stubTemplateFiles)); });
      TemplateStore._init(stubTemplatesDir);
      watchCallback();
      const add = jasmine.createSpy('add');
      spyOn(DraftStore, 'sessionForClientId').andCallFake(()=> {
        return Promise.resolve({changes: {add}});
      });

      runs(()=> {
        TemplateStore._onInsertTemplateId({
          templateId: 'template1.html',
          draftClientId: 'localid-draft',
        });
      });
      waitsFor(()=> add.calls.length > 0);
      runs(()=> {
        expect(add).toHaveBeenCalledWith({
          body: stubTemplateFiles['template1.html'],
        });
      });
    });
  });

  describe('onCreateTemplate', ()=> {
    beforeEach(()=> {
      let d;
      spyOn(DraftStore, 'sessionForClientId').andCallFake((draftClientId)=> {
        if (draftClientId === 'localid-nosubject') {
          d = new Message({subject: '', body: '
Body
'});
        } else {
          d = new Message({subject: 'Subject', body: '
Body
'});
        }
        const session = {draft() { return d; }};
        return Promise.resolve(session);
      });
      TemplateStore._init(stubTemplatesDir);
    });

    xit('should create a template with the given name and contents', ()=> {
      const ref = TemplateStore.items();
      TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
      const item = (ref != null ? ref[0] : undefined);
      expect(item.id).toBe('123.html');
      expect(item.name).toBe('123');
      expect(item.path.split('/').pop()).toBe('123.html');
    });

    xit('should display an error if no name is provided', ()=> {
      spyOn(TemplateStore, '_displayError');
      TemplateStore._onCreateTemplate({contents: 'bla'});
      expect(TemplateStore._displayError).toHaveBeenCalled();
    });

    xit('should display an error if no content is provided', ()=> {
      spyOn(TemplateStore, '_displayError');
      TemplateStore._onCreateTemplate({name: 'bla'});
      expect(TemplateStore._displayError).toHaveBeenCalled();
    });

    xit('should save the template file to the templates folder', ()=> {
      TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
      const path = `${stubTemplatesDir}/123.html`;
      expect(fs.writeFile).toHaveBeenCalled();
      expect(fs.writeFile.mostRecentCall.args[0]).toEqual(path);
      expect(fs.writeFile.mostRecentCall.args[1]).toEqual('bla');
    });

    xit('should open the template so you can see it', ()=> {
      TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
      expect(shell.showItemInFolder).toHaveBeenCalled();
    });

    describe('when given a draft id', ()=> {
      xit('should create a template from the name and contents of the given draft', ()=> {
        spyOn(TemplateStore, 'trigger');
        spyOn(TemplateStore, '_populate');
        runs(()=> {
          TemplateStore._onCreateTemplate({draftClientId: 'localid-b'});
        });
        waitsFor(()=> TemplateStore.trigger.callCount > 0 );
        runs(()=> {
          expect(TemplateStore.items().length).toEqual(1);
        });
      });

      it('should display an error if the draft has no subject', ()=> {
        spyOn(TemplateStore, '_displayError');
        spyOn(fs, 'watch');
        runs(()=> {
          TemplateStore._onCreateTemplate({draftClientId: 'localid-nosubject'});
        });
        waitsFor(()=> TemplateStore._displayError.callCount > 0 );
        runs(()=> {
          expect(TemplateStore._displayError).toHaveBeenCalled();
        });
      });
    });
  });

  describe('onShowTemplates', ()=> {
    xit('should open the templates folder in the Finder', ()=> {
      TemplateStore._onShowTemplates();
      expect(shell.showItemInFolder).toHaveBeenCalled();
    });
  });
});
<|endoftext|>


<commit_before>import {expect} from 'chai';
import path from 'path';
import fse from 'fs-extra';
import _ from 'lodash';

import * as utils from '../../lib/generators/utils';

describe("removeWholeLine", function() {
  it("removes the whole line on which the given string appears", function() {
    let line = '{\n  User,\n  Posts,\n  Comments}';
    let result = utils.removeWholeLine(line, 'User');
    expect(result).to.equal('{\n  Posts,\n  Comments}');
  });

  it("removes the whole line on which the given regex matches", function() {
    let line = '{\n  User,\n  Posts,\n  Comments}';
    let result = utils.removeWholeLine(line, /[a-zA-Z]{5}/g);
    expect(result).to.equal('{\n  User,\n  Comments}');
  });
});

describe("removeFromIndexFile", function() {
  let dummyPath = path.resolve(__dirname, '../../tmp/removeFromIndexFile.js');

  afterEach(function() {
    // Cleanup
    fse.removeSync(dummyPath);
  });

  it("removes import/export lines - capitalizeVarName", function() {
    // Setup
    fse.outputFileSync(dummyPath, `
import Comments from './comments';
import Users from './users';
import Posts from './posts';

export {
  Commnets,
  Users,
  Posts
};
`
    );

    utils.removeFromIndexFile(dummyPath, 'users', {capitalizeVarName: true});
    let result = fse.readFileSync(dummyPath, {encoding: 'utf-8'});
    expect(result).to.equal(`
import Comments from './comments';
import Posts from './posts';

export {
  Commnets,
  Posts
};
`
    );
  });

  it("removes import/export lines", function() {
    // Setup
    fse.outputFileSync(dummyPath, `
import comments from './comments';
import users from './users';

export default function () {
  comments();
  users();
}
`
    );

    utils.removeFromIndexFile(dummyPath, 'users', {capitalizeVarName: false});
    let result = fse.readFileSync(dummyPath, {encoding: 'utf-8'});
    expect(result).to.equal(`
import comments from './comments';

export default function () {
  comments();
}
`
    );
  });
});

describe("getOutputPath", function() {
  const customConfig = {};
  it("returns a correct output path for collection", function() {
    let result = utils.getOutputPath(customConfig, 'collection', 'users');
    expect(result).to.equal('./lib/collections/users.js');
  });

  it("returns a correct output path for method", function() {
    let result = utils.getOutputPath(customConfig, 'method', 'users');
    expect(result).to.equal('./server/methods/users.js');
  });

  it("returns a correct output path for publication", function() {
    let result = utils.getOutputPath(customConfig, 'publication', 'users');
    expect(result).to.equal('./server/publications/users.js');
  });

  it("returns a correct output path for action", function() {
    let result = utils.getOutputPath(customConfig, 'action', 'users', 'core');
    expect(result).to.equal('./client/modules/core/actions/users.js');
  });

  it("returns a correct output path for container", function() {
    let result = utils.getOutputPath(customConfig, 'container', 'user_list', 'core');
    expect(result).to.equal('./client/modules/core/containers/user_list.js');
  });

  it("returns a correct output path for component", function() {
    let result = utils.getOutputPath(customConfig, 'component', 'user_list', 'core');
    expect(result).to.equal('./client/modules/core/components/user_list.jsx');
  });

  it("returns a correct output path for a storybook", function() {
    let result = utils.getOutputPath(customConfig, 'storybook', 'user_list', 'core');
    expect(result).to.equal('./client/modules/core/components/.stories/user_list.js');
  });
});

describe("getTemplateVaraibles", function() {
  describe("for components", function() {
    let expected = {
      componentName: 'UserList',
      moduleName: 'core'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('component', 'core', 'userList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('component', 'core', 'user_list');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('component', 'core', 'UserList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for storybook", function() {
    let expected = {
      moduleName: "core",
      componentName: 'UserList',
      componentFileName: 'user_list'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('storybook', 'core', 'userList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('storybook', 'core', 'user_list');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('storybook', 'core', 'UserList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for containers", function() {
    let expected = {
      componentName: 'UserList',
      componentFileName: 'user_list',
      moduleName: 'core'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('container', 'core', 'userList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('container', 'core', 'user_list');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('container', 'core', 'UserList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for collections", function() {
    let expected = {
      collectionName: 'PullRequests',
      collectionFileName: 'pull_requests',
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'pullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'pull_requests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'PullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets templates variables with collection2 option", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'PullRequests', {schema: 'collection2'});
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets templates variables with astronomy option", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'PullRequests', {schema: 'astronomy'});
      let matched = _.isEqual(result, {
        collectionName: 'PullRequests',
        collectionFileName: 'pull_requests',
        className: 'PullRequest'
      });
      expect(matched).to.equal(true);
    });
  });

  describe("for methods", function() {
    let expected = {
      collectionName: 'PullRequests',
      methodFileName: 'pull_requests'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('method', null, 'pullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('method', null, 'pull_requests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('method', null, 'PullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for publications", function() {
    let expected = {
      collectionName: 'PullRequests',
      publicationFileName: 'pull_requests'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('publication', null, 'pullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('publication', null, 'pull_requests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('publication', null, 'PullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });
});

describe("checkForModuleName", function() {
  it("returns true if module name is provided", function() {
    let result = utils.checkForModuleName('core:user_list');
    expect(result).to.equal(true);
  });

  it("returns false if module name is provided", function() {
    let result = utils.checkForModuleName('user_list');
    expect(result).to.equal(false);
  });
});

describe("getTestTemplateVaraibles", function() {
  describe("for components", function() {
    let expected = {
      componentName: 'HeaderMenu',
      componentFileName: 'header_menu',
      moduleName: 'user_management'
    };

    it("getes templates varaibles - variation 1", function() {
      let result = utils.getTestTemplateVaraibles('component', 'user_management', 'headerMenu');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 2", function() {
      let result = utils.getTestTemplateVaraibles('component', 'userManagement', 'headerMenu');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 3", function() {
      let result = utils.getTestTemplateVaraibles('component', 'UserManagement', 'header_menu');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for actions", function() {
    let expected = {
      actionFileName: 'flagged_comments',
      moduleName: 'core'
    };

    it("getes templates varaibles - variation 1", function() {
      let result = utils.getTestTemplateVaraibles('action', 'core', 'flagged_comments');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 2", function() {
      let result = utils.getTestTemplateVaraibles('action', 'core', 'flaggedComments');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for containers", function() {
    let expected = {
      containerFileName: 'comment_lists',
      moduleName: 'core'
    };

    it("getes templates varaibles - variation 1", function() {
      let result = utils.getTestTemplateVaraibles('container', 'core', 'comment_lists');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 2", function() {
      let result = utils.getTestTemplateVaraibles('container', 'core', 'comment_lists');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });
});

describe("getTemplatePath", function() {
  it("gets template path for collection - collection2", function() {
    let result = utils.getTemplatePath('collection', {schema: 'collection2'});
    expect(result).to.match(/generic_collection2.tt/);
  });
});

describe("compileTemplate", function() {
  it("applies tabSize", function() {
    let content = `function() {
  if (true) {
    console.log('hello world');
  }
}
`;
    let result = utils.compileTemplate(content, {}, {tabSize: 4});
    expect(result).to.equal(`function() {
    if (true) {
        console.log('hello world');
    }
}
`);
  });
});

describe("readTemplateContent", function() {
  it("returns the default content if no config is provided", function() {
    let options = {};
    let configs = {};
    let defaultTemplatePath = path.resolve(__dirname, '../../templates/client/modules/core/actions/generic.tt');

    let result = utils.readTemplateContent('action', options, configs);
    let expected = fse.readFileSync(defaultTemplatePath);

    expect(result.equals(expected)).to.equal(true);
  });

  it("returns the custom content if config is provided", function() {
    let options = {};
    let customContent = 'hello world';
    let configs = {templates: [{name: 'action', text: customContent}]};
    let result = utils.readTemplateContent('action', options, configs);

    expect(result).to.equal(customContent);
  });
});
<commit_msg>add additional tests<commit_after>import {expect} from 'chai';
import path from 'path';
import fse from 'fs-extra';
import _ from 'lodash';

import * as utils from '../../lib/generators/utils';

describe("removeWholeLine", function() {
  it("removes the whole line on which the given string appears", function() {
    let line = '{\n  User,\n  Posts,\n  Comments}';
    let result = utils.removeWholeLine(line, 'User');
    expect(result).to.equal('{\n  Posts,\n  Comments}');
  });

  it("removes the whole line on which the given regex matches", function() {
    let line = '{\n  User,\n  Posts,\n  Comments}';
    let result = utils.removeWholeLine(line, /[a-zA-Z]{5}/g);
    expect(result).to.equal('{\n  User,\n  Comments}');
  });
});

describe("removeFromIndexFile", function() {
  let dummyPath = path.resolve(__dirname, '../../tmp/removeFromIndexFile.js');

  afterEach(function() {
    // Cleanup
    fse.removeSync(dummyPath);
  });

  it("removes import/export lines - capitalizeVarName", function() {
    // Setup
    fse.outputFileSync(dummyPath, `
import Comments from './comments';
import Users from './users';
import Posts from './posts';

export {
  Commnets,
  Users,
  Posts
};
`
    );

    utils.removeFromIndexFile(dummyPath, 'users', {capitalizeVarName: true});
    let result = fse.readFileSync(dummyPath, {encoding: 'utf-8'});
    expect(result).to.equal(`
import Comments from './comments';
import Posts from './posts';

export {
  Commnets,
  Posts
};
`
    );
  });

  it("removes import/export lines", function() {
    // Setup
    fse.outputFileSync(dummyPath, `
import comments from './comments';
import users from './users';

export default function () {
  comments();
  users();
}
`
    );

    utils.removeFromIndexFile(dummyPath, 'users', {capitalizeVarName: false});
    let result = fse.readFileSync(dummyPath, {encoding: 'utf-8'});
    expect(result).to.equal(`
import comments from './comments';

export default function () {
  comments();
}
`
    );
  });
});

describe("getOutputPath", function() {
  const customConfig = {};
  it("returns a correct output path for collection", function() {
    let result = utils.getOutputPath(customConfig, 'collection', 'users');
    expect(result).to.equal('./lib/collections/users.js');
  });

  it("returns a correct output path for method", function() {
    let result = utils.getOutputPath(customConfig, 'method', 'users');
    expect(result).to.equal('./server/methods/users.js');
  });

  it("returns a correct output path for publication", function() {
    let result = utils.getOutputPath(customConfig, 'publication', 'users');
    expect(result).to.equal('./server/publications/users.js');
  });

  it("returns a correct output path for action", function() {
    let result = utils.getOutputPath(customConfig, 'action', 'users', 'core');
    expect(result).to.equal('./client/modules/core/actions/users.js');
  });

  it("returns a correct output path for container", function() {
    let result = utils.getOutputPath(customConfig, 'container', 'user_list', 'core');
    expect(result).to.equal('./client/modules/core/containers/user_list.js');
  });

  it("returns a correct output path for component", function() {
    let result = utils.getOutputPath(customConfig, 'component', 'user_list', 'core');
    expect(result).to.equal('./client/modules/core/components/user_list.jsx');
  });

  it("returns a correct output path for a storybook", function() {
    let result = utils.getOutputPath(customConfig, 'storybook', 'user_list', 'core');
    expect(result).to.equal('./client/modules/core/components/.stories/user_list.js');
  });
  describe("with custom modules path", function() {
    const customConfig = {modulesPath: "foo/bar/mantra/modules"};
    it("returns a correct output path for action", function() {
      let result = utils.getOutputPath(customConfig, 'action', 'users', 'core');
      expect(result).to.equal('./foo/bar/mantra/modules/core/actions/users.js');
    });

    it("returns a correct output path for container", function() {
      let result = utils.getOutputPath(customConfig, 'container', 'user_list', 'core');
      expect(result).to.equal('./foo/bar/mantra/modules/core/containers/user_list.js');
    });

    it("returns a correct output path for component", function() {
      let result = utils.getOutputPath(customConfig, 'component', 'user_list', 'core');
      expect(result).to.equal('./foo/bar/mantra/modules/core/components/user_list.jsx');
    });

    it("returns a correct output path for a storybook", function() {
      let result = utils.getOutputPath(customConfig, 'storybook', 'user_list', 'core');
      expect(result).to.equal('./foo/bar/mantra/modules/core/components/.stories/user_list.js');
    });
  });
});

describe("getTemplateVaraibles", function() {
  describe("for components", function() {
    let expected = {
      componentName: 'UserList',
      moduleName: 'core'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('component', 'core', 'userList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('component', 'core', 'user_list');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('component', 'core', 'UserList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for storybook", function() {
    let expected = {
      moduleName: "core",
      componentName: 'UserList',
      componentFileName: 'user_list'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('storybook', 'core', 'userList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('storybook', 'core', 'user_list');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('storybook', 'core', 'UserList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for containers", function() {
    let expected = {
      componentName: 'UserList',
      componentFileName: 'user_list',
      moduleName: 'core'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('container', 'core', 'userList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('container', 'core', 'user_list');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('container', 'core', 'UserList');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for collections", function() {
    let expected = {
      collectionName: 'PullRequests',
      collectionFileName: 'pull_requests',
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'pullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'pull_requests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'PullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets templates variables with collection2 option", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'PullRequests', {schema: 'collection2'});
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets templates variables with astronomy option", function() {
      let result = utils.getTemplateVaraibles('collection', null, 'PullRequests', {schema: 'astronomy'});
      let matched = _.isEqual(result, {
        collectionName: 'PullRequests',
        collectionFileName: 'pull_requests',
        className: 'PullRequest'
      });
      expect(matched).to.equal(true);
    });
  });

  describe("for methods", function() {
    let expected = {
      collectionName: 'PullRequests',
      methodFileName: 'pull_requests'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('method', null, 'pullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('method', null, 'pull_requests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('method', null, 'PullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for publications", function() {
    let expected = {
      collectionName: 'PullRequests',
      publicationFileName: 'pull_requests'
    };

    it("gets template variables - variation 1", function() {
      let result = utils.getTemplateVaraibles('publication', null, 'pullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 2", function() {
      let result = utils.getTemplateVaraibles('publication', null, 'pull_requests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("gets template variables - variation 3", function() {
      let result = utils.getTemplateVaraibles('publication', null, 'PullRequests');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });
});

describe("checkForModuleName", function() {
  it("returns true if module name is provided", function() {
    let result = utils.checkForModuleName('core:user_list');
    expect(result).to.equal(true);
  });

  it("returns false if module name is provided", function() {
    let result = utils.checkForModuleName('user_list');
    expect(result).to.equal(false);
  });
});

describe("getTestTemplateVaraibles", function() {
  describe("for components", function() {
    let expected = {
      componentName: 'HeaderMenu',
      componentFileName: 'header_menu',
      moduleName: 'user_management'
    };

    it("getes templates varaibles - variation 1", function() {
      let result = utils.getTestTemplateVaraibles('component', 'user_management', 'headerMenu');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 2", function() {
      let result = utils.getTestTemplateVaraibles('component', 'userManagement', 'headerMenu');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 3", function() {
      let result = utils.getTestTemplateVaraibles('component', 'UserManagement', 'header_menu');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for actions", function() {
    let expected = {
      actionFileName: 'flagged_comments',
      moduleName: 'core'
    };

    it("getes templates varaibles - variation 1", function() {
      let result = utils.getTestTemplateVaraibles('action', 'core', 'flagged_comments');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 2", function() {
      let result = utils.getTestTemplateVaraibles('action', 'core', 'flaggedComments');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });

  describe("for containers", function() {
    let expected = {
      containerFileName: 'comment_lists',
      moduleName: 'core'
    };

    it("getes templates varaibles - variation 1", function() {
      let result = utils.getTestTemplateVaraibles('container', 'core', 'comment_lists');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });

    it("getes templates varaibles - variation 2", function() {
      let result = utils.getTestTemplateVaraibles('container', 'core', 'comment_lists');
      let matched = _.isEqual(result, expected);
      expect(matched).to.equal(true);
    });
  });
});

describe("getTemplatePath", function() {
  it("gets template path for collection - collection2", function() {
    let result = utils.getTemplatePath('collection', {schema: 'collection2'});
    expect(result).to.match(/generic_collection2.tt/);
  });
});

describe("compileTemplate", function() {
  it("applies tabSize", function() {
    let content = `function() {
  if (true) {
    console.log('hello world');
  }
}
`;
    let result = utils.compileTemplate(content, {}, {tabSize: 4});
    expect(result).to.equal(`function() {
    if (true) {
        console.log('hello world');
    }
}
`);
  });
});

describe("readTemplateContent", function() {
  it("returns the default content if no config is provided", function() {
    let options = {};
    let configs = {};
    let defaultTemplatePath = path.resolve(__dirname, '../../templates/client/modules/core/actions/generic.tt');

    let result = utils.readTemplateContent('action', options, configs);
    let expected = fse.readFileSync(defaultTemplatePath);

    expect(result.equals(expected)).to.equal(true);
  });

  it("returns the custom content if config is provided", function() {
    let options = {};
    let customContent = 'hello world';
    let configs = {templates: [{name: 'action', text: customContent}]};
    let result = utils.readTemplateContent('action', options, configs);

    expect(result).to.equal(customContent);
  });
});
<|endoftext|>


<commit_before>// Generated by Creer at 10:54PM on October 16, 2015 UTC, git hash: '98604e3773d1933864742cb78acbf6ea0b4ecd7b'

var Class = require(__basedir + "/utilities/class");
var serializer = require(__basedir + "/gameplay/serializer");
var log = require(__basedir + "/gameplay/log");
var Building = require("./building");

//<<-- Creer-Merge: requires -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

// any additional requires you want can be required here safely between cree runs
//<<-- /Creer-Merge: requires -->>

// @class PoliceDepartment: Used to keep cities under control and raid Warehouses.
var PoliceDepartment = Class(Building, {
    /**
     * Initializes PoliceDepartments.
     *
     * @param {Object} a simple mapping passsed in to the constructor with whatever you sent with it.
     */
    init: function(data) {
        Building.init.apply(this, arguments);

        //<<-- Creer-Merge: init -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

        // put any initialization logic here. the base variables should be set from 'data' above
        // NOTE: no players are connected (nor created) at this point. For that logic use 'begin()'

        //<<-- /Creer-Merge: init -->>
    },

    gameObjectName: "PoliceDepartment",

    /**
     * Bribe the police to raid a Warehouse, dealing damage equal based on the Warehouse's current exposure, and then resetting it to 0.
     *
     * @param {Player} player - the player that called this.
     * @param {Warehouse} warehouse - The warehouse you want to raid.
     * @param {function} asyncReturn - if you nest orders in this function you must return that value via this function in the order's callback.
     * @returns {number} The amount of damage dealt to the warehouse, or -1 if there was an error.
     */
    raid: function(player, warehouse, asyncReturn) {
        // <<-- Creer-Merge: raid -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

        // Developer: Put your game logic for the PoliceDepartment's raid function here
        return 0;

        // <<-- /Creer-Merge: raid -->>
    },

    //<<-- Creer-Merge: added-functions -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

    // You can add additional functions here. These functions will not be directly callable by client AIs

    //<<-- /Creer-Merge: added-functions -->>

});

module.exports = PoliceDepartment;
<commit_msg>PoliceDepartment.raid for @Uhuh as shown in Friday's code sprint.<commit_after>// Generated by Creer at 10:54PM on October 16, 2015 UTC, git hash: '98604e3773d1933864742cb78acbf6ea0b4ecd7b'

var Class = require(__basedir + "/utilities/class");
var serializer = require(__basedir + "/gameplay/serializer");
var log = require(__basedir + "/gameplay/log");
var Building = require("./building");

//<<-- Creer-Merge: requires -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

// any additional requires you want can be required here safely between cree runs
//<<-- /Creer-Merge: requires -->>

// @class PoliceDepartment: Used to keep cities under control and raid Warehouses.
var PoliceDepartment = Class(Building, {
    /**
     * Initializes PoliceDepartments.
     *
     * @param {Object} a simple mapping passsed in to the constructor with whatever you sent with it.
     */
    init: function(data) {
        Building.init.apply(this, arguments);

        //<<-- Creer-Merge: init -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

        // put any initialization logic here. the base variables should be set from 'data' above
        // NOTE: no players are connected (nor created) at this point. For that logic use 'begin()'

        //<<-- /Creer-Merge: init -->>
    },

    gameObjectName: "PoliceDepartment",

    /**
     * Bribe the police to raid a Warehouse, dealing damage equal based on the Warehouse's current exposure, and then resetting it to 0.
     *
     * @param {Player} player - the player that called this.
     * @param {Warehouse} warehouse - The warehouse you want to raid.
     * @param {function} asyncReturn - if you nest orders in this function you must return that value via this function in the order's callback.
     * @returns {number} The amount of damage dealt to the warehouse, or -1 if there was an error.
     */
    raid: function(player, warehouse, asyncReturn) {
        // <<-- Creer-Merge: raid -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

        var logicError = this._checkIfBribeIsValid(player, -1);
        if(logicError) {
            return logicError;
        }

        if(warehouse && warehouse.gameObjectName !== "Warehouse") {
            return game.logicError(-1, "PoliceDepartments can only raid Warehouses.");
        }

        var oldHealth = warehouse.oldHealth;
        warehouse.health = math.max(warehouse.health - warehouse.exposure, 0);
        warehouse.exposure = 0;

        this.bribed = true;
        player.bribesRemaining--;

        return oldHealth - warehouse.health;

        // <<-- /Creer-Merge: raid -->>
    },

    //<<-- Creer-Merge: added-functions -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs.

    // You can add additional functions here. These functions will not be directly callable by client AIs

    //<<-- /Creer-Merge: added-functions -->>

});

module.exports = PoliceDepartment;
<|endoftext|>


<commit_before>import React from "react"
import { Link, graphql } from "gatsby"
import Img from 'gatsby-image';

import { upperCaseFirst } from '../utils/uppercase-first';
import LayoutWithSignUp from "../components/LayoutWithSignUp"
import "prismjs/themes/prism-okaidia.css"

class BlogPostTemplate extends React.Component {
  render() {
    const post = this.props.data.markdownRemark
    const author = this.props.data.site.siteMetadata.authors
                        .find(a => a.id === post.frontmatter.author)
    const category = post.frontmatter.categories && post.frontmatter.categories[0];
    const categoryLink = `/categories/${category}`;
    const twitterLink = `https://twitter.com/${author.twitter}`;

    /* const { previous, next } = this.props.pageContext */

    return (
      <LayoutWithSignUp title={post.frontmatter.title} description={post.frontmatter.summary}>

         <Link to="/" title="Back to Blog">← Back to Blog</Link>

{author.name}

              <time dateTime={post.frontmatter.date} className="thtrm-metabar__item thtrm-topic u-color--grey">{post.frontmatter.date}</time>
              {category &&
<Link to={categoryLink} className="u-link-plain">{upperCaseFirst(category)}</Link>
}

{post.frontmatter.title}

          {post.frontmatter.imageUrl && }
          {post.frontmatter.imgCaption &&
{post.frontmatter.imgCaption}
}

                  Written by

{author.name}

      </LayoutWithSignUp>
    )
  }
}

export default BlogPostTemplate

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        authors {
          id
          name
          twitter
          img
        }
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      excerpt(pruneLength: 160)
      html
      frontmatter {
        author
        title
        author
        imageUrl {
          childImageSharp{
            sizes(maxWidth: 630) {
                ...GatsbyImageSharpSizes
            }
          }
        }
        date(formatString: "DD MMMM YYYY")
        summary
        categories
      }
    }
  }
`
<commit_msg>chore: add rebase-book add<commit_after>import React from "react"
import { Link, graphql } from "gatsby"
import Img from 'gatsby-image';

import { upperCaseFirst } from '../utils/uppercase-first';
import LayoutWithSignUp from "../components/LayoutWithSignUp"
import "prismjs/themes/prism-okaidia.css"

class BlogPostTemplate extends React.Component {
  render() {
    const post = this.props.data.markdownRemark
    const author = this.props.data.site.siteMetadata.authors
                        .find(a => a.id === post.frontmatter.author)
    const category = post.frontmatter.categories && post.frontmatter.categories[0];
    const categoryLink = `/categories/${category}`;
    const twitterLink = `https://twitter.com/${author.twitter}`;

    /* const { previous, next } = this.props.pageContext */

    return (
      <LayoutWithSignUp title={post.frontmatter.title} description={post.frontmatter.summary}>

         <Link to="/" title="Back to Blog">← Back to Blog</Link>

{author.name}

              <time dateTime={post.frontmatter.date} className="thtrm-metabar__item thtrm-topic u-color--grey">{post.frontmatter.date}</time>
              {category &&
<Link to={categoryLink} className="u-link-plain">{upperCaseFirst(category)}</Link>
}

{post.frontmatter.title}

          {post.frontmatter.imageUrl && }
          {post.frontmatter.imgCaption &&
{post.frontmatter.imgCaption}
}

                  Written by

{author.name}

      </LayoutWithSignUp>
    )
  }
}

export default BlogPostTemplate

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        authors {
          id
          name
          twitter
          img
        }
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      excerpt(pruneLength: 160)
      html
      frontmatter {
        author
        title
        author
        imageUrl {
          childImageSharp{
            sizes(maxWidth: 630) {
                ...GatsbyImageSharpSizes
            }
          }
        }
        date(formatString: "DD MMMM YYYY")
        summary
        categories
      }
    }
  }
`
<|endoftext|>


<commit_before>/**
 * Software License Agreement (BSD License)
 *
 * Copyright (c) 2010 IBM Corporation.
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above
 *   copyright notice, this list of conditions and the
 *   following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the
 *   following disclaimer in the documentation and/or other
 *   materials provided with the distribution.
 *
 * * Neither the name of IBM nor the names of its
 *   contributors may be used to endorse or promote products
 *   derived from this software without specific prior
 *   written permission of IBM.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * Describes a compilation unit in a browser context. A compilation unit
 * may originate from a JavaScript source file or a script element in HTML.
 *
 * @constructor
 * @param url compilation unit URL - a {@link String} or null if none
 * @param context the {@link BrowserContext} this compilation unit is contained in
 * @type CompilationUnit
 * @return a new CompilationUnit
 * @version 1.0
 */
function CompilationUnit(url, context) {
	this.url = url;
	this.context = context;
	this.breakpoints = [];
}

// ---- API ----

/**
 * Returns the URL of this compilation unit.
 *

 * This function does not require communication with
 * the browser.
 *

 *
 * @function
 * @returns compilation unit identifier as a {@link String}
 */
CompilationUnit.prototype.getURL = function() {
	return this.url;
};

/**
 * Returns the browser context this compilation unit was compiled in.
 *

 * This function does not require communication with
 * the browser.
 *

 *
 * @function
 * @returns a {@link BrowserContext}
 */
CompilationUnit.prototype.getBrowserContext = function() {
	return this.context;
};

/**
 * Returns the breakpoints that have been created in this compilation unit and
 * have not been cleared.
 *

 * This function does not require communication with
 * the browser.
 *

 * @function
 * @returns an array of {@link Breakpoint}'s
 */
CompilationUnit.prototype.getBreakpoints = function() {
	// return a copy of scripts so the master copy is not corrupted
	var bps = [];
	for ( var i = 0; i < this.breakpoints.length; i++) {
		bps.push(this.breakpoints[i]);
	}
	return bps;
};

/**
 * Requests the source of this compilation unit asynchronously. Source will be
 * retrieved from the browser and reported back to the listener function when available.
 * The handler may be called before or after this function returns.
 *

 * TODO: what if the compilation unit no longer exists in the browser
 *

 * @function
 * @param listener a listener (function) that accepts a {@link String} of source code
 */
CompilationUnit.prototype.getSource = function(listener) {
	//TODO:
};

/**
 * Requests to create a breakpoint in this compilation unit asynchronously. The breakpoint
 * request will be sent to the browser and an onToggleBreakpoint event will
 * be sent by the browser when the breakpoint is installed.
 *

 *

 *
TODO: onToggleBreakpoint event is not spec'd - is this the intended use?

 *
TODO: line number out of range

 *
TODO: compilation unit no longer exists in the browser

 *
TODO: breakpoint already set

 *
TODO: is line number 0 or 1 based

 *

 *

 * @function
 * @param lineNumber the source line number in this compilation unit to set the breakpoint on
 */
CompilationUnit.prototype.setBreakpoint = function(lineNumber) {
	// TODO:
};

// ---- PRIVATE ----
<commit_msg>added convenience methods to add and remove breakpoints from a compilation unit<commit_after>/**
 * Software License Agreement (BSD License)
 *
 * Copyright (c) 2010 IBM Corporation.
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above
 *   copyright notice, this list of conditions and the
 *   following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the
 *   following disclaimer in the documentation and/or other
 *   materials provided with the distribution.
 *
 * * Neither the name of IBM nor the names of its
 *   contributors may be used to endorse or promote products
 *   derived from this software without specific prior
 *   written permission of IBM.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * Describes a compilation unit in a browser context. A compilation unit
 * may originate from a JavaScript source file or a script element in HTML.
 *
 * @constructor
 * @param url compilation unit URL - a {@link String} or null if none
 * @param context the {@link BrowserContext} this compilation unit is contained in
 * @type CompilationUnit
 * @return a new CompilationUnit
 * @version 1.0
 */
function CompilationUnit(url, context) {
	this.url = url;
	this.context = context;
	this.breakpoints = [];
}

// ---- API ----

/**
 * Returns the URL of this compilation unit.
 *

 * This function does not require communication with
 * the browser.
 *

 *
 * @function
 * @returns compilation unit identifier as a {@link String}
 */
CompilationUnit.prototype.getURL = function() {
	return this.url;
};

/**
 * Returns the browser context this compilation unit was compiled in.
 *

 * This function does not require communication with
 * the browser.
 *

 *
 * @function
 * @returns a {@link BrowserContext}
 */
CompilationUnit.prototype.getBrowserContext = function() {
	return this.context;
};

/**
 * Returns the breakpoints that have been created in this compilation unit and
 * have not been cleared.
 *

 * This function does not require communication with
 * the browser.
 *

 * @function
 * @returns an array of {@link Breakpoint}'s
 */
CompilationUnit.prototype.getBreakpoints = function() {
	// return a copy of scripts so the master copy is not corrupted
	var bps = [];
	for ( var i = 0; i < this.breakpoints.length; i++) {
		bps.push(this.breakpoints[i]);
	}
	return bps;
};

/**
 * Requests the source of this compilation unit asynchronously. Source will be
 * retrieved from the browser and reported back to the listener function when available.
 * The handler may be called before or after this function returns.
 *

 * TODO: what if the compilation unit no longer exists in the browser
 *

 * @function
 * @param listener a listener (function) that accepts a {@link String} of source code
 */
CompilationUnit.prototype.getSource = function(listener) {
	//TODO:
};

/**
 * Requests to create a breakpoint in this compilation unit asynchronously. A breakpoint
 * creation request will be sent to the browser and an onToggleBreakpoint
 * event will be sent by the browser when the breakpoint is installed.
 *

 *

 *
TODO: onToggleBreakpoint event is not spec'd - is this the intended use?

 *
TODO: line number out of range

 *
TODO: compilation unit no longer exists in the browser

 *
TODO: breakpoint already set

 *
TODO: is line number 0 or 1 based

 *

 *

 * @function
 * @param lineNumber the source line number in this compilation unit to set the breakpoint on
 */
CompilationUnit.prototype.setBreakpoint = function(lineNumber) {
	// TODO:
};

// ---- PRIVATE ----

/**
 * Adds the specified breakpoint to this compilation unit's collection of breakpoints.
 * Implementation should call this method when a breakpoint is created in a compilation
 * unit.
 *
 * @param breakpoint the breakpoint that was created
 * @function
 */
CompilationUnit.prototype._addBreakpoint = function(breakpoint) {
	this.breakpoints.push(breakpoint);
};

/**
 * Removes the specified breakpoint from this compilation unit's collection of breakpoints.
 * Implementation should call this method when a breakpoint is cleared from a compilation
 * unit.
 *
 * @param breakpoint the breakpoint that was removed
 * @function
 */
CompilationUnit.prototype._removeBreakpoint = function(breakpoint) {
	for ( var i = 0; i < this.breakpoints.length; i++) {
		if (this.breakpoints[i] == breakpoint) {
			this.breakpoints.splice(i, 1);
			return;
		}
	}
};
<|endoftext|>


<commit_before>import SEGMENT_COMPONENTS from './components.json'
import SEGMENT_LOOKUP from './segment-lookup.json'
import { SEGMENT_UNKNOWN, SEGMENT_UNKNOWN_VARIANT } from './info'
import { uniq } from 'lodash'

/**
 * Retrieves the necessary information required to map the old segment data model to the
 * new segment data model for the specific segment using the segment's `type` and `variant`.
 *
 * @param {string} type
 * @param {string} variant
 * @returns {object|boolean} segmentLookup - returns an object in the shape of: { lanes, objects, vehicles } or `false` if not found.
 */
function getSegmentLookup (type, variant) {
  return SEGMENT_LOOKUP[type] && SEGMENT_LOOKUP[type][variant]
}

/**
 * Retrieves the specified segment information from the new segment data model using the
 * component group and the segment id.
 *
 * @param {string} group - component group, one of values "lanes", "vehicles" or "objects"
 * @param {string} id - name of segment component, e.g. "scooter"
 * @returns {object} segmentInfo
 */
function getSegmentInfo (group, id) {
  return (SEGMENT_COMPONENTS[group] && SEGMENT_COMPONENTS[group][id]) || SEGMENT_UNKNOWN
}

/**
 * Retrieves the information for all items that make up a particular component group by
 * looking up the component group and item id in `SEGMENT_COMPONENTS`.
 *
 * @param {string} group - component group name (i.e. `lanes`, `objects`, or `vehicles`)
 * @param {Array} groupItems - items that make up the component group in shape of [{ id, variants }]
 * @returns {object} componentGroupInfo - returns object in shape of { id: { characteristics, rules, variants } }
 */
function getComponentGroupInfo (group, groupItems) {
  return groupItems.reduce((obj, item) => {
    obj[item.id] = getSegmentInfo(group, item.id)
    return obj
  }, {})
}

/**
 * Retrieves all graphics definitions for the component group based on each `variant`
 * specified for each component group item.
 *
 * @param {Array} groupItems - items that make up the component group in shape of [ { id, variants } ]
 * @param {object} componentGroupInfo - definition of each item from `SEGMENT_COMPONENTS` in shape of { id: { characteristics, rules, variants } }
 * @returns {Array} componentGroupVariants - returns array of graphic definitions in shape of [ { graphics } ]
 */
function getComponentGroupVariants (groupItems, componentGroupInfo) {
  return groupItems.reduce((array, item) => {
    const { id, variants } = item
    // groupItemVariants - all variants possible for the particular group item
    const groupItemVariants = componentGroupInfo[id] && componentGroupInfo[id].variants

    if (groupItemVariants) {
      Object.entries(variants).forEach(([variantName, variantKey]) => {
        // variantInfo - graphics definition for specific variants defined by group item
        const variantInfo = (groupItemVariants[variantName] && groupItemVariants[variantName][variantKey]) || SEGMENT_UNKNOWN_VARIANT
        array.push(variantInfo.graphics)
      })
    }

    return array
  }, [])
}

/**
 * A segment may contain multiple graphics for the same graphics type ('left', 'right', 'repeat', 'center').
 * When encountering a new graphic for the same graphics type, this function creates a new array that
 * contains both the new graphic as well as the existing graphics.
 *
 * @param {Array|string} target
 * @param {Array|string} source
 * @returns {Array} graphicsInfo
 */
function appendVariantSprites (target, source) {
  const targetArray = Array.isArray(target) ? target : [target]
  const sourceArray = Array.isArray(source) ? source : [source]

  const graphicsInfo = targetArray.concat(sourceArray)
  return uniq(graphicsInfo)
}

/**
 * Merges the array of graphic definition objects needed to draw the segment into a single object.
 *
 * @param {Array} variantGraphics
 * @returns {object} graphics
 */
function mergeVariantGraphics (variantGraphics) {
  return variantGraphics.reduce((graphics, variantInfo) => {
    Object.keys(variantInfo).forEach((key) => {
      const target = graphics[key]
      const source = variantInfo[key]

      if (target) {
        graphics[key] = appendVariantSprites(target, source)
      } else {
        graphics[key] = source
      }
    })

    return graphics
  }, {})
}

/**
 * Collects all rules associated with any items that make up the component group into a single object.
 *
 * @param {Array} groupItems - items that make up the component group in shape of [{ id, variants }]
 * @param {object} componentGroupInfo - definition of each item from `SEGMENT_COMPONENTS` in shape of { id: { characteristics, rules, variants } }
 * @returns {object} componentGroupRules
 */
function getComponentGroupRules (groupItems, componentGroupInfo) {
  const componentGroupRules = groupItems.reduce((obj, item) => {
    const { id, variants } = item

    let groupItemRules = {}

    if (componentGroupInfo[id] && componentGroupInfo[id].rules) {
      groupItemRules = { ...componentGroupInfo[id].rules }
    }

    const groupItemVariants = componentGroupInfo[id] && componentGroupInfo[id].variants

    Object.keys(variants).forEach((variantName) => {
      if (groupItemVariants[variantName] && groupItemVariants[variantName].rules) {
        groupItemRules = { ...groupItemRules, ...groupItemVariants[variantName].rules }
      }
    })

    return { ...obj, ...groupItemRules }
  }, {})

  return Object.keys(componentGroupRules).length && componentGroupRules
}

/**
 * Maps the old segment data model to the new segment data model and returns the graphic sprites necessary
 * to draw the segment as well as any rules to follow, e.g. `minWidth` based on the `type` and `variant`.
 *
 * @param {string} type
 * @param {string} variant
 * @returns {object} variantInfo - returns an object in the shape of { graphics, ...rules }
 */
function getSegmentVariantInfo (type, variant) {
  const segmentLookup = getSegmentLookup(type, variant)

  if (!segmentLookup) {
    return SEGMENT_UNKNOWN_VARIANT
  }

  // 1) Loop through each component group that makes up the segment.
  const variantInfo = Object.entries(segmentLookup).reduce((variantInfo, componentGroup) => {
    const [ group, groupItems ] = componentGroup
    // 2) For each component group, look up the segment information for every item that makes up the component group.
    // componentGroupInfo = [ { characteristics, rules, variants } ]
    const componentGroupInfo = getComponentGroupInfo(group, groupItems)

    // componentGroupVariants = [ { graphics } ]
    // 3) For each component group, look up the segment variant graphics for every item that makes up the component group.
    const componentGroupVariants = getComponentGroupVariants(groupItems, componentGroupInfo)

    if (componentGroupVariants.length) {
      // 4) Combine the variant graphics for each component group into one array
      componentGroupVariants.forEach((groupItemVariants) => { variantInfo.graphics.push(groupItemVariants) })
    }

    // 5) For each component group, look up any rules associated with each of the items that make up the component group.
    const componentGroupRules = getComponentGroupRules(groupItems, componentGroupInfo)
    if (componentGroupRules) {
      return Object.assign(variantInfo, componentGroupRules)
    }

    return variantInfo
  }, { graphics: [] })

  // 6) Combine the variant graphics into one graphics definition object.
  variantInfo.graphics = mergeVariantGraphics(variantInfo.graphics)
  return variantInfo
}

/**
 * Temporary helper method that compares the original segment variant info with the variant info returned
 * by the new data model. If the new variant info contains all the keys from the original variant info, then
 * the variant info is correct.
 *
 * TODO - migrate helper method to become a test suite
 *
 * @param {object} originalVariantInfo
 * @param {object} newVariantInfo
 * @returns {boolean} correct
 */
function verifyCorrectness (originalVariantInfo, newVariantInfo) {
  const filteredKeys = Object.keys(originalVariantInfo).filter(key => !newVariantInfo[key])
  const filteredGraphics = Object.entries(originalVariantInfo.graphics).filter((item) => {
    const [ key, value ] = item
    const originalGraphics = Array.isArray(value) ? value.sort() : value
    const newGraphics = Array.isArray(newVariantInfo.graphics[key]) ? newVariantInfo.graphics[key].sort() : newVariantInfo.graphics[key]
    return !(JSON.stringify(originalGraphics) === JSON.stringify(newGraphics))
  })

  return (filteredKeys.length === 0 && filteredGraphics.length === 0)
}

/**
 * Tests the mapping of the old segment data model to the new segment data model and
 * returns the correct `variantInfo` needed to draw the segment.
 *
 * @param {string} type
 * @param {string} variant
 * @param {object} segmentVariantInfo
 * @returns {object} variantInfo
 */
export function testSegmentLookup (type, variant, segmentVariantInfo) {
  const newVariantInfo = getSegmentVariantInfo(type, variant)

  if (verifyCorrectness(segmentVariantInfo, newVariantInfo)) {
    return newVariantInfo
  } else {
    return segmentVariantInfo
  }
}
<commit_msg>fixed verifyCorrectness to correctly check for elevation and rules; handle nested variants in getComponentGroupVariantInfo; add elevation to variantInfo object<commit_after>import SEGMENT_COMPONENTS from './components.json'
import SEGMENT_LOOKUP from './segment-lookup.json'
import { SEGMENT_UNKNOWN, SEGMENT_UNKNOWN_VARIANT } from './info'
import { uniq } from 'lodash'

/**
 * Retrieves the necessary information required to map the old segment data model to the
 * new segment data model for the specific segment using the segment's `type` and `variant`.
 *
 * @param {string} type
 * @param {string} variant
 * @returns {object|boolean} segmentLookup - returns an object in the shape of: { lanes, objects, vehicles } or `false` if not found.
 */
function getSegmentLookup (type, variant) {
  return SEGMENT_LOOKUP[type] && SEGMENT_LOOKUP[type][variant]
}

/**
 * Retrieves the specified segment information from the new segment data model using the
 * component group and the segment id.
 *
 * @param {string} group - component group, one of values "lanes", "vehicles" or "objects"
 * @param {string} id - name of segment component, e.g. "scooter"
 * @returns {object} segmentInfo
 */
function getSegmentInfo (group, id) {
  return (SEGMENT_COMPONENTS[group] && SEGMENT_COMPONENTS[group][id]) || SEGMENT_UNKNOWN
}

/**
 * Retrieves the information for all items that make up a particular component group by
 * looking up the component group and item id in `SEGMENT_COMPONENTS`.
 *
 * @param {string} group - component group name (i.e. `lanes`, `objects`, or `vehicles`)
 * @param {Array} groupItems - items that make up the component group in shape of [{ id, variants }]
 * @returns {object} componentGroupInfo - returns object in shape of { id: { characteristics, rules, variants } }
 */
function getComponentGroupInfo (group, groupItems) {
  return groupItems.reduce((obj, item) => {
    obj[item.id] = getSegmentInfo(group, item.id)
    return obj
  }, {})
}

/**
 * Retrieves all graphics definitions for the component group based on each `variant`
 * specified for each component group item.
 *
 * @param {Array} groupItems - items that make up the component group in shape of [ { id, variants } ]
 * @param {object} componentGroupInfo - definition of each item from `SEGMENT_COMPONENTS` in shape of { id: { characteristics, rules, variants } }
 * @returns {Array} componentGroupVariants - returns array of graphic definitions in shape of [ { graphics } ]
 */
function getComponentGroupVariants (groupItems, componentGroupInfo) {
  return groupItems.reduce((array, item) => {
    const { id, variants } = item
    // groupItemVariants - all variants possible for the particular group item
    const groupItemVariants = componentGroupInfo[id] && componentGroupInfo[id].variants

    if (groupItemVariants) {
      Object.entries(variants).forEach(([variantName, variantKey]) => {
        // variantInfo - graphics definition for specific variants defined by group item
        let variantInfo = groupItemVariants[variantName] || SEGMENT_UNKNOWN_VARIANT

        const variantKeys = Array.isArray(variantKey) ? variantKey : [ variantKey ]
        variantKeys.forEach((key) => {
          variantInfo = (variantInfo && variantInfo[key]) || SEGMENT_UNKNOWN_VARIANT
        })

        array.push(variantInfo.graphics)
      })
    }

    return array
  }, [])
}

/**
 * A segment may contain multiple graphics for the same graphics type ('left', 'right', 'repeat', 'center').
 * When encountering a new graphic for the same graphics type, this function creates a new array that
 * contains both the new graphic as well as the existing graphics.
 *
 * @param {Array|string} target
 * @param {Array|string} source
 * @returns {Array} graphicsInfo
 */
function appendVariantSprites (target, source) {
  const targetArray = Array.isArray(target) ? target : [target]
  const sourceArray = Array.isArray(source) ? source : [source]

  const graphicsInfo = targetArray.concat(sourceArray)
  return uniq(graphicsInfo)
}

/**
 * Merges the array of graphic definition objects needed to draw the segment into a single object.
 *
 * @param {Array} variantGraphics
 * @returns {object} graphics
 */
function mergeVariantGraphics (variantGraphics) {
  return variantGraphics.reduce((graphics, variantInfo) => {
    Object.keys(variantInfo).forEach((key) => {
      const target = graphics[key]
      const source = variantInfo[key]

      if (target) {
        graphics[key] = appendVariantSprites(target, source)
      } else {
        graphics[key] = source
      }
    })

    return graphics
  }, {})
}

/**
 * Collects all rules associated with any items that make up the component group into a single object.
 *
 * @param {Array} groupItems - items that make up the component group in shape of [{ id, variants }]
 * @param {object} componentGroupInfo - definition of each item from `SEGMENT_COMPONENTS` in shape of { id: { characteristics, rules, variants } }
 * @returns {object} componentGroupRules
 */
function getComponentGroupRules (groupItems, componentGroupInfo) {
  const componentGroupRules = groupItems.reduce((obj, item) => {
    const { id, variants } = item

    let groupItemRules = {}

    if (componentGroupInfo[id] && componentGroupInfo[id].rules) {
      groupItemRules = { ...componentGroupInfo[id].rules }
    }

    const groupItemVariants = componentGroupInfo[id] && componentGroupInfo[id].variants

    Object.keys(variants).forEach((variantName) => {
      if (groupItemVariants[variantName] && groupItemVariants[variantName].rules) {
        groupItemRules = { ...groupItemRules, ...groupItemVariants[variantName].rules }
      }
    })

    return { ...obj, ...groupItemRules }
  }, {})

  return Object.keys(componentGroupRules).length && componentGroupRules
}

/**
 * Maps the old segment data model to the new segment data model and returns the graphic sprites necessary
 * to draw the segment as well as any rules to follow, e.g. `minWidth` based on the `type` and `variant`.
 *
 * @param {string} type
 * @param {string} variant
 * @returns {object} variantInfo - returns an object in the shape of { graphics, ...rules }
 */
function getSegmentVariantInfo (type, variant) {
  const segmentLookup = getSegmentLookup(type, variant)

  if (!segmentLookup) {
    return SEGMENT_UNKNOWN_VARIANT
  }

  // 1) Loop through each component group that makes up the segment.
  const variantInfo = Object.entries(segmentLookup).reduce((variantInfo, componentGroup) => {
    const [ group, groupItems ] = componentGroup
    // 2) For each component group, look up the segment information for every item that makes up the component group.
    // componentGroupInfo = [ { characteristics, rules, variants } ]
    const componentGroupInfo = getComponentGroupInfo(group, groupItems)

    // componentGroupVariants = [ { graphics } ]
    // 3) For each component group, look up the segment variant graphics for every item that makes up the component group.
    const componentGroupVariants = getComponentGroupVariants(groupItems, componentGroupInfo)

    if (componentGroupVariants.length) {
      // 4) Combine the variant graphics for each component group into one array
      componentGroupVariants.forEach((groupItemVariants) => { variantInfo.graphics.push(groupItemVariants) })
    }

    // 5) For each component group, look up any rules associated with each of the items that make up the component group.
    const componentGroupRules = getComponentGroupRules(groupItems, componentGroupInfo)
    if (componentGroupRules) {
      return Object.assign(variantInfo, componentGroupRules)
    }

    return variantInfo
  }, { graphics: [] })

  // 6) Combine the variant graphics into one graphics definition object.
  variantInfo.graphics = mergeVariantGraphics(variantInfo.graphics)

  // Assuming a segment has one "lane" component, a segment's elevation can be found using the id
  // of the first item in the "lane" component group.
  const lane = getSegmentInfo('lanes', segmentLookup.lanes[0].id)
  variantInfo.elevation = lane.elevation

  return variantInfo
}

/**
 * Temporary helper method that compares the original segment variant info with the variant info returned
 * by the new data model. If the new variant info contains all the keys from the original variant info, then
 * the variant info is correct.
 *
 * TODO - migrate helper method to become a test suite
 *
 * @param {object} originalVariantInfo
 * @param {object} newVariantInfo
 * @returns {boolean} correct
 */
function verifyCorrectness (originalVariantInfo, newVariantInfo) {
  const filteredKeys = Object.keys(originalVariantInfo).filter((key) => {
    return (key === 'graphics') ? !newVariantInfo.graphics : originalVariantInfo[key] !== newVariantInfo[key]
  })

  const filteredGraphics = Object.entries(originalVariantInfo.graphics).filter((item) => {
    const [ key, value ] = item
    const originalGraphics = Array.isArray(value) ? value.sort() : value
    const newGraphics = Array.isArray(newVariantInfo.graphics[key]) ? newVariantInfo.graphics[key].sort() : newVariantInfo.graphics[key]
    return !(JSON.stringify(originalGraphics) === JSON.stringify(newGraphics))
  })

  return (filteredKeys.length === 0 && filteredGraphics.length === 0)
}

/**
 * Tests the mapping of the old segment data model to the new segment data model and
 * returns the correct `variantInfo` needed to draw the segment.
 *
 * @param {string} type
 * @param {string} variant
 * @param {object} segmentVariantInfo
 * @returns {object} variantInfo
 */
export function testSegmentLookup (type, variant, segmentVariantInfo) {
  const newVariantInfo = getSegmentVariantInfo(type, variant)

  console.log(segmentVariantInfo)
  if (verifyCorrectness(segmentVariantInfo, newVariantInfo)) {
    console.log('Correctly mapped segment.')
    return newVariantInfo
  } else {
    console.log(newVariantInfo)
    return segmentVariantInfo
  }
}
<|endoftext|>


<commit_before>//__BEGIN_LICENSE__
//Copyright (c) 2015, United States Government, as represented by the
//Administrator of the National Aeronautics and Space Administration.
//All rights reserved.

//The xGDS platform is licensed under the Apache License, Version 2.0
//(the "License"); you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0.

//Unless required by applicable law or agreed to in writing, software distributed
//under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//CONDITIONS OF ANY KIND, either express or implied. See the License for the
//specific language governing permissions and limitations under the License.
//__END_LICENSE__

//This simple javascript is called by tungsten replicator after it does an insertion.
//To test in your virtual machine, type
//rhino handle_data_insertion.js

//naive java implementation variant, if curl is not available
var prefix = 'http://localhost:8181';
var tableListUrl = '/xgds_core/rebroadcast/tableNamesAndKeys/'
var url = '/xgds_core/tungsten/dataInsert/';
var httpStatusOK = 200;
var colTypeInt = 4;
var colTypeVarchar = 12;

var tableNamesAndKeys = {};
var getTableNamesAndKeys = function() {
    // TODO: Manage exceptions on HTTP GET
    resp = httpGet(prefix + tableListUrl);
    if (resp.statusCode == httpStatusOK) {   // Only process data if we get OK status code
        tableNamesStr = resp.data;
        tableNamesAndKeys = JSON.parse(tableNamesStr);
    }
    logger.info("TABLE LIST: " + tableNamesAndKeys);
    return tableNamesAndKeys;
}

function getMethods(obj) {
    var result = [];
    for (var id in obj) {
        try {
            result.push(id + ": " + obj[id].toString());
        } catch (err) {
            result.push(id + ": inaccessible");
        }
    }
    return result;
}

var prepare = function()
{
    getTableNamesAndKeys();
}

//Perform the filter process; function is called for each event in the THL

var filter= function(event)
{
    if (Object.keys(tableNamesAndKeys).length == 0) {
        logger.info("NO TABLES IN LIST!");
        return;
    }
// Get the array of DBMSData objects
    data = event.getData();

    // Iterate over the individual DBMSData objects
    for(i=0;i<data.size();i++)
    {
      // Get a single DBMSData object
      d = data.get(i);

      // Process a Statement Event; event type is identified by comparing the object class type

      if (d instanceof com.continuent.tungsten.replicator.dbms.StatementData)
      {
        // Do statement processing
    	  logger.info('STATEMENT UPDATE:');
    	  logger.info('  ' + d.getQuery());
      }
      else if (d instanceof com.continuent.tungsten.replicator.dbms.RowChangeData)
      {
        // Get an array of all the row changes
        rows = data.get(i).getRowChanges();

        // Iterate over row changes
        for(j=0;j<rows.size();j++)
        {
        	// Get the single row change
        	rowchange = rows.get(j);

        	// Identify the row change type

        	logger.info(rowchange.getAction());
        	var tableName = rowchange.getTableName();
        	logger.info('TABLE NAME: ' + tableName);

        	if (!tableNamesAndKeys[tableName]) {
        		logger.info("SKIPPING TABLE: " + tableName);
        		return;
        	}

//        	var colSpecs = rowchange.getColumnSpec();
//        	var idIndex = -1;
//        	logger.info('COL SPEC SIZE: ' + colSpecs.size());

//        	for (var c=0; c<colSpecs.size(); c++) {
//        		logger.info(c);
//        		logger.info(colSpecs.get(c));
//        		var colName = colSpecs.get(c).getName();
//        		var colLength = colSpecs.get(c).getLength();
//        		logger.info('COL NAME: ' + colName + '(' + colLength +')');
//
//        		if (colName == 'id'){
//        			logger.info('COLUMN ID FOUND ');
//        			idIndex = c;
//        			break;
//        		}
//        	}

        	var dbAction = rowchange.getAction();
        	logger.info('ROW CHANGE ACTION: ' + dbAction);
        	var pkType = 0;
        	var pkValue = -1;

        	if ((dbAction == "UPDATE") || (dbAction == "DELETE")) {
        		var rowKeys = rowchange.getKeyValues();
        		var rowKeyTypes = rowchange.getKeySpec();
        		if (rowKeyTypes.size() != 1) {
        			logger.info("ONLY Single Column PK's supported for table: " + tableName + " - " + rowKeyTypes.size());
        			return;
        		}
        		pkType = rowKeyTypes.get(0).getType();
        		for (var i=0; i<rowKeys.size(); i++) {
        			switch (pkType) {
        			case colTypeInt:
        				pkValue = rowKeys.get(i).get(0).getValue();
        				break;
        			case colTypeVarchar:
        				pkValue = java.lang.String(rowKeys.get(i).get(0).getValue())
        				break;
        			default:
        				logger.info("TYPE code " + pkType + " not recognized for PK in table: " + tableName);
        				break;
        			}
        			logger.info("DOING " + dbAction + " on table: " + tableName + " for PK: " + pkValue);
        		}
        	}

        	if (dbAction == "INSERT") {
        		var colValues = rowchange.getColumnValues();
        		logger.info("ROWS INSERTED: " + colValues.size());
        		for (var r=0; r<colValues.size(); r++) {
        			var pkType = tableNamesAndKeys[tableName].pkType;
        			logger.info("TYPE from django: " + pkType);
        			if (pkType == "int") {
        				pKValue = colValues.get(r).get(tableNamesAndKeys[tableName].pkColNum-1).getValue();
        				logger.info("INT case);
        			} else {
        				pKValue = java.lang.String(colValues.get(r).get(tableNamesAndKeys[tableName].pkColNum-1).getValue());
        				logger.info("STRING case);
        			}
        			logger.info("DOING " + dbAction + " on table: " + tableName + " for PK: " + pkValue);
//      			var styleName = colValues.get(r).get(1).getValue();
//      			var styleColor = colValues.get(r).get(2).getValue();
//        			logger.info('PK: (' + pkType + ')' + pKValue);
//      			logger.info('Style Name: ' + java.lang.String(styleName));
//      			logger.info('Style Color: ' + java.lang.String(styleColor));
        		}
        	}
        	//logger.info(rowchange.getColumnSpec());
        }
      }
    }
}

function doThings() {

	response = httpPost(prefix + url, data).data;

	logger.info('response: ' + response);
	var theResponse = JSON.parse(response);
	logger.info ('timestamp: ' + theResponse.timestamp);
	logger.info ('data: ' + theResponse.data);
}

function httpGet(theUrl){
	var con = new java.net.URL(theUrl).openConnection();
	con.requestMethod = "GET";
	return asResponse(con);
}

function httpPost(theUrl, data, contentType){
	var con = new java.net.URL(theUrl).openConnection();

	con.setRequestMethod("POST");

	var contentType = contentType || "application/json";
	con.setRequestProperty("Content-Type", contentType);

	con.setDoOutput(true);
	con.setDoInput(true);
	con.setAllowUserInteraction(false);
	logger.info('ABOUT TO POST:' + JSON.stringify(data));
	write(con.getOutputStream(), data);
	return asResponse(con);
}

function asResponse(con){
    var d = read(con.inputStream);
    return {data : d, statusCode : con.responseCode};
}

function write(outputStream, data){
	// either way seems to work but on the django side content is in request.body
	var wr = new java.io.OutputStreamWriter(outputStream);
	wr.write(JSON.stringify(data));
//	var wr = new java.io.DataOutputStream(outputStream);
//	wr.writeBytes(data);
	wr.flush();
	wr.close();
}

function read(inputStream){
	var inReader = new java.io.BufferedReader(new java.io.InputStreamReader(inputStream));
	var inputLine;
	var response = new java.lang.StringBuffer();

	while ((inputLine = inReader.readLine()) != null) {
		response.append(inputLine);
	}
	inReader.close();
	return response.toString();
}
<commit_msg>switch from switch to if<commit_after>//__BEGIN_LICENSE__
//Copyright (c) 2015, United States Government, as represented by the
//Administrator of the National Aeronautics and Space Administration.
//All rights reserved.

//The xGDS platform is licensed under the Apache License, Version 2.0
//(the "License"); you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0.

//Unless required by applicable law or agreed to in writing, software distributed
//under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//CONDITIONS OF ANY KIND, either express or implied. See the License for the
//specific language governing permissions and limitations under the License.
//__END_LICENSE__

//This simple javascript is called by tungsten replicator after it does an insertion.
//To test in your virtual machine, type
//rhino handle_data_insertion.js

//naive java implementation variant, if curl is not available
var prefix = 'http://localhost:8181';
var tableListUrl = '/xgds_core/rebroadcast/tableNamesAndKeys/'
var url = '/xgds_core/tungsten/dataInsert/';
var httpStatusOK = 200;
var colTypeInt = 4;
var colTypeVarchar = 12;

var tableNamesAndKeys = {};
var getTableNamesAndKeys = function() {
    // TODO: Manage exceptions on HTTP GET
    resp = httpGet(prefix + tableListUrl);
    if (resp.statusCode == httpStatusOK) {   // Only process data if we get OK status code
        tableNamesStr = resp.data;
        tableNamesAndKeys = JSON.parse(tableNamesStr);
    }
    logger.info("TABLE LIST: " + tableNamesAndKeys);
    return tableNamesAndKeys;
}

function getMethods(obj) {
    var result = [];
    for (var id in obj) {
        try {
            result.push(id + ": " + obj[id].toString());
        } catch (err) {
            result.push(id + ": inaccessible");
        }
    }
    return result;
}

var prepare = function()
{
    getTableNamesAndKeys();
}

//Perform the filter process; function is called for each event in the THL

var filter= function(event)
{
    if (Object.keys(tableNamesAndKeys).length == 0) {
        logger.info("NO TABLES IN LIST!");
        return;
    }
// Get the array of DBMSData objects
    data = event.getData();

    // Iterate over the individual DBMSData objects
    for(i=0;i<data.size();i++)
    {
      // Get a single DBMSData object
      d = data.get(i);

      // Process a Statement Event; event type is identified by comparing the object class type

      if (d instanceof com.continuent.tungsten.replicator.dbms.StatementData)
      {
        // Do statement processing
    	  logger.info('STATEMENT UPDATE:');
    	  logger.info('  ' + d.getQuery());
      }
      else if (d instanceof com.continuent.tungsten.replicator.dbms.RowChangeData)
      {
        // Get an array of all the row changes
        rows = data.get(i).getRowChanges();

        // Iterate over row changes
        for(j=0;j<rows.size();j++)
        {
        	// Get the single row change
        	rowchange = rows.get(j);

        	// Identify the row change type

        	logger.info(rowchange.getAction());
        	var tableName = rowchange.getTableName();
        	logger.info('TABLE NAME: ' + tableName);

        	if (!tableNamesAndKeys[tableName]) {
        		logger.info("SKIPPING TABLE: " + tableName);
        		return;
        	}

//        	var colSpecs = rowchange.getColumnSpec();
//        	var idIndex = -1;
//        	logger.info('COL SPEC SIZE: ' + colSpecs.size());

//        	for (var c=0; c<colSpecs.size(); c++) {
//        		logger.info(c);
//        		logger.info(colSpecs.get(c));
//        		var colName = colSpecs.get(c).getName();
//        		var colLength = colSpecs.get(c).getLength();
//        		logger.info('COL NAME: ' + colName + '(' + colLength +')');
//
//        		if (colName == 'id'){
//        			logger.info('COLUMN ID FOUND ');
//        			idIndex = c;
//        			break;
//        		}
//        	}

        	var dbAction = rowchange.getAction();
        	logger.info('ROW CHANGE ACTION: ' + dbAction);
        	var pkType = 0;
        	var pkValue = -1;

        	if ((dbAction == "UPDATE") || (dbAction == "DELETE")) {
        		var rowKeys = rowchange.getKeyValues();
        		var rowKeyTypes = rowchange.getKeySpec();
        		if (rowKeyTypes.size() != 1) {
        			logger.info("ONLY Single Column PK's supported for table: " + tableName + " - " + rowKeyTypes.size());
        			return;
        		}
        		pkType = rowKeyTypes.get(0).getType();
        		for (var i=0; i<rowKeys.size(); i++) {
        			switch (pkType) {
        			case colTypeInt:
        				pkValue = rowKeys.get(i).get(0).getValue();
        				break;
        			case colTypeVarchar:
        				pkValue = java.lang.String(rowKeys.get(i).get(0).getValue())
        				break;
        			default:
        				logger.info("TYPE code " + pkType + " not recognized for PK in table: " + tableName);
        				break;
        			}
        			logger.info("DOING " + dbAction + " on table: " + tableName + " for PK: " + pkValue);
        		}
        	}

        	if (dbAction == "INSERT") {
        		var colValues = rowchange.getColumnValues();
        		logger.info("ROWS INSERTED: " + colValues.size());
        		for (var r=0; r<colValues.size(); r++) {
        			var pkType = tableNamesAndKeys[tableName].pkType;
        			logger.info("TYPE from django: " + pkType);
        			if (pkType == "int") {
        				pKValue = colValues.get(r).get(tableNamesAndKeys[tableName].pkColNum-1).getValue();
        				logger.info("INT case");
        			} else {
        				pKValue = java.lang.String(colValues.get(r).get(tableNamesAndKeys[tableName].pkColNum-1).getValue());
        				logger.info("STRING case");
        			}
        			logger.info("DOING " + dbAction + " on table: " + tableName + " for PK: " + pkValue);
//      			var styleName = colValues.get(r).get(1).getValue();
//      			var styleColor = colValues.get(r).get(2).getValue();
//        			logger.info('PK: (' + pkType + ')' + pKValue);
//      			logger.info('Style Name: ' + java.lang.String(styleName));
//      			logger.info('Style Color: ' + java.lang.String(styleColor));
        		}
        	}
        	//logger.info(rowchange.getColumnSpec());
        }
      }
    }
}

function doThings() {

	response = httpPost(prefix + url, data).data;

	logger.info('response: ' + response);
	var theResponse = JSON.parse(response);
	logger.info ('timestamp: ' + theResponse.timestamp);
	logger.info ('data: ' + theResponse.data);
}

function httpGet(theUrl){
	var con = new java.net.URL(theUrl).openConnection();
	con.requestMethod = "GET";
	return asResponse(con);
}

function httpPost(theUrl, data, contentType){
	var con = new java.net.URL(theUrl).openConnection();

	con.setRequestMethod("POST");

	var contentType = contentType || "application/json";
	con.setRequestProperty("Content-Type", contentType);

	con.setDoOutput(true);
	con.setDoInput(true);
	con.setAllowUserInteraction(false);
	logger.info('ABOUT TO POST:' + JSON.stringify(data));
	write(con.getOutputStream(), data);
	return asResponse(con);
}

function asResponse(con){
    var d = read(con.inputStream);
    return {data : d, statusCode : con.responseCode};
}

function write(outputStream, data){
	// either way seems to work but on the django side content is in request.body
	var wr = new java.io.OutputStreamWriter(outputStream);
	wr.write(JSON.stringify(data));
//	var wr = new java.io.DataOutputStream(outputStream);
//	wr.writeBytes(data);
	wr.flush();
	wr.close();
}

function read(inputStream){
	var inReader = new java.io.BufferedReader(new java.io.InputStreamReader(inputStream));
	var inputLine;
	var response = new java.lang.StringBuffer();

	while ((inputLine = inReader.readLine()) != null) {
		response.append(inputLine);
	}
	inReader.close();
	return response.toString();
}
<|endoftext|>