<commit_before>describe('Gateway to Meido', function() {
    integration(function() {
        describe('Gateway to Meido\'s constant ability', function() {
            beforeEach(function() {
                this.setupTest({
                    phase: 'conflict',
                    player1: {
                        inPlay: ['doomed-shugenja'],
                        hand: ['grasp-of-earth']
                    },
                    player2: {
                        inPlay: ['akodo-gunso'],
                        provinces: ['gateway-to-meido'],
                        dynastyDiscard: ['kitsu-warrior', 'akodo-zentaro']
                    }
                });
                this.doomedShugenja = this.player1.findCardByName('doomed-shugenja');
                this.graspOfEarth = this.player1.findCardByName('grasp-of-earth');
                this.akodoGunso = this.player2.findCardByName('akodo-gunso');
                this.kitsuWarrior = this.player2.findCardByName('kitsu-warrior', 'dynasty discard pile');
                this.akodoZentaro = this.player2.findCardByName('akodo-zentaro', 'dynasty discard pile');
                this.gatewayToMeido = this.player2.findCardByName('gateway-to-meido', 'province 1');
                this.shamefulDisplay = this.player2.findCardByName('shameful-display', 'province 2');
            });

            it('should allow you to play characters from dynasty discard pile', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.kitsuWarrior);
                expect(this.player2).toHavePrompt('Choose additional fate');
            });

            it('should only allow you to play characters into the conflict', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.kitsuWarrior);
                this.player2.clickPrompt('1');
                expect(this.player2).not.toHavePrompt('"Where do you wish to play this character?');
                expect(this.player1).toHavePrompt('Conflict Action Window');
                expect(this.kitsuWarrior.location).toBe('play area');
                expect(this.kitsuWarrior.isParticipating()).toBe(true);
                expect(this.kitsuWarrior.fate).toBe(1);
            });

            it('should not be active when conflict is not at this province', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [],
                    province: this.shamefulDisplay
                });
                this.player2.clickCard(this.kitsuWarrior);
                expect(this.player2).not.toHavePrompt('Choose additional fate');
                expect(this.player2).toHavePrompt('Conflict Action Window');
            });

            it('should allow you to use the disguised keyword when you play from discard', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [this.akodoGunso],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.akodoZentaro);
                expect(this.player2).toHavePrompt('Akodo Zentarō');
                expect(this.player2).toHavePromptButton('Play this character with Disguise');
                expect(this.player2).toHavePromptButton('Play this character');
            });

            it('should only allow you to replace a character in the conflict if using the disguised keyword', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [this.akodoGunso],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.akodoZentaro);
                this.player2.clickPrompt('Play this character with Disguise');
                expect(this.player2).toHavePrompt('Choose a character to replace');
                expect(this.player2).toBeAbleToSelect(this.akodoGunso);
                expect(this.player2).not.toBeAbleToSelect(this.kitsuWarrior);
                this.player2.clickCard(this.akodoGunso);
                expect(this.akodoGunso.location).toBe('dynasty discard pile');
                expect(this.akodoZentaro.isParticipating()).toBe(true);
            });

            it('should not allow you to play using the disguised keyword if there is no appropriate character in the conflict', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.akodoZentaro);
                expect(this.player2).toHavePrompt('Choose additional fate');
            });

            it('should not allow characters to be played if grasp of earth has been activated', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.doomedShugenja],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.pass();
                this.player1.clickCard(this.graspOfEarth);
                this.player1.clickCard(this.doomedShugenja);
                this.player2.pass();
                this.player1.clickCard(this.graspOfEarth);
                expect(this.player2).toHavePrompt('Conflict Action Window');
                this.player2.clickCard(this.kitsuWarrior);
                expect(this.player2).toHavePrompt('Conflict Action Window');
            });
        });
    });
});
<commit_msg>Add doomed shugenja meido test (#3352)<commit_after>describe('Gateway to Meido', function() {
    integration(function() {
        describe('Gateway to Meido\'s constant ability', function() {
            beforeEach(function() {
                this.setupTest({
                    phase: 'conflict',
                    player1: {
                        inPlay: ['agasha-swordsmith'],
                        hand: ['grasp-of-earth']
                    },
                    player2: {
                        inPlay: ['akodo-gunso'],
                        provinces: ['gateway-to-meido'],
                        dynastyDiscard: ['kitsu-warrior', 'akodo-zentaro', 'doomed-shugenja', 'agasha-taiko']
                    }
                });
                this.agashaSwordsmith = this.player1.findCardByName('agasha-swordsmith');
                this.graspOfEarth = this.player1.findCardByName('grasp-of-earth');
                this.akodoGunso = this.player2.findCardByName('akodo-gunso');
                this.kitsuWarrior = this.player2.findCardByName('kitsu-warrior', 'dynasty discard pile');
                this.akodoZentaro = this.player2.findCardByName('akodo-zentaro', 'dynasty discard pile');
                this.doomedShugenja = this.player2.findCardByName('doomed-shugenja', 'dynasty discard pile');
                this.agashaTaiko = this.player2.findCardByName('agasha-taiko', 'dynasty discard pile');
                this.gatewayToMeido = this.player2.findCardByName('gateway-to-meido', 'province 1');
                this.shamefulDisplay = this.player2.findCardByName('shameful-display', 'province 2');
            });

            it('should allow you to play characters from dynasty discard pile', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.kitsuWarrior);
                expect(this.player2).toHavePrompt('Choose additional fate');
            });

            it('should only allow you to play characters into the conflict', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.kitsuWarrior);
                this.player2.clickPrompt('1');
                expect(this.player2).not.toHavePrompt('"Where do you wish to play this character?');
                expect(this.player1).toHavePrompt('Conflict Action Window');
                expect(this.kitsuWarrior.location).toBe('play area');
                expect(this.kitsuWarrior.isParticipating()).toBe(true);
                expect(this.kitsuWarrior.fate).toBe(1);
            });

            it('should not be active when conflict is not at this province', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [],
                    province: this.shamefulDisplay
                });
                this.player2.clickCard(this.kitsuWarrior);
                expect(this.player2).not.toHavePrompt('Choose additional fate');
                expect(this.player2).toHavePrompt('Conflict Action Window');
            });

            it('should allow you to use the disguised keyword when you play from discard', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [this.akodoGunso],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.akodoZentaro);
                expect(this.player2).toHavePrompt('Akodo Zentarō');
                expect(this.player2).toHavePromptButton('Play this character with Disguise');
                expect(this.player2).toHavePromptButton('Play this character');
            });

            it('should only allow you to replace a character in the conflict if using the disguised keyword', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [this.akodoGunso],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.akodoZentaro);
                this.player2.clickPrompt('Play this character with Disguise');
                expect(this.player2).toHavePrompt('Choose a character to replace');
                expect(this.player2).toBeAbleToSelect(this.akodoGunso);
                expect(this.player2).not.toBeAbleToSelect(this.kitsuWarrior);
                this.player2.clickCard(this.akodoGunso);
                expect(this.akodoGunso.location).toBe('dynasty discard pile');
                expect(this.akodoZentaro.isParticipating()).toBe(true);
            });

            it('should not allow you to play using the disguised keyword if there is no appropriate character in the conflict', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.clickCard(this.akodoZentaro);
                expect(this.player2).toHavePrompt('Choose additional fate');
            });

            it('should not allow characters to be played if grasp of earth has been activated', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.pass();
                this.player1.clickCard(this.graspOfEarth);
                this.player1.clickCard(this.agashaSwordsmith);
                this.player2.pass();
                this.player1.clickCard(this.graspOfEarth);
                expect(this.player2).toHavePrompt('Conflict Action Window');
                this.player2.clickCard(this.kitsuWarrior);
                expect(this.player2).toHavePrompt('Conflict Action Window');
            });

            it('should allow additional fate to be added to doomed shugenja', function() {
                this.noMoreActions();
                this.initiateConflict({
                    attackers: [this.agashaSwordsmith],
                    defenders: [],
                    province: this.gatewayToMeido
                });
                this.player2.pass();
                this.player1.clickCard(this.doomedShugenja);
                expect(this.player1).toHavePrompt('Choose additional fate');
                expect(this.player1).toHavePromptButton('1');
                this.player1.clickPrompt('1');
                expect(this.doomedShugenja.isParticipating()).toBe(true);
                expect(this.doomedShugenja.fate).toBe(1);
            });
        });
    });
});
<|endoftext|>


<commit_before>/**
 * @license
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * https://blockly.googlecode.com/
 *
 * 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.
 */

/**
 * @fileoverview Generating Python for logic blocks.
 * @author q.neutron@gmail.com (Quynh Neutron)
 */
'use strict';

goog.provide('Blockly.Python.logic');

goog.require('Blockly.Python');

Blockly.Python['controls_if'] = function(block) {
  // If/elseif/else condition.
  var n = 0;
  var argument = Blockly.Python.valueToCode(block, 'IF' + n,
      Blockly.Python.ORDER_NONE) || 'False';
  var branch = Blockly.Python.statementToCode(block, 'DO' + n) || '  pass\n';
  var code = 'if ' + argument + ':\n' + branch;
  for (n = 1; n <= block.elseifCount_; n++) {
    argument = Blockly.Python.valueToCode(block, 'IF' + n,
        Blockly.Python.ORDER_NONE) || 'False';
    branch = Blockly.Python.statementToCode(block, 'DO' + n) || '  pass\n';
    code += 'elif ' + argument + ':\n' + branch;
  }
  if (block.elseCount_) {
    branch = Blockly.Python.statementToCode(block, 'ELSE') || '  pass\n';
    code += 'else:\n' + branch;
  }
  return code;
};

Blockly.Python['logic_compare'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'EQ': '==',
    'NEQ': '!=',
    'LT': '<',
    'LTE': '<=',
    'GT': '>',
    'GTE': '>='
  };
  var operator = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_RELATIONAL;
  var argument0 = Blockly.Python.valueToCode(block, 'A', order) || '0';
  var argument1 = Blockly.Python.valueToCode(block, 'B', order) || '0';
  var code = argument0 + ' ' + operator + ' ' + argument1;
  return [code, order];
};

Blockly.Python['logic_operation'] = function(block) {
  // Operations 'and', 'or'.
  var operator = (block.getFieldValue('OP') == 'AND') ? 'and' : 'or';
  var order = (operator == 'and') ? Blockly.Python.ORDER_LOGICAL_AND :
      Blockly.Python.ORDER_LOGICAL_OR;
  var argument0 = Blockly.Python.valueToCode(block, 'A', order);
  var argument1 = Blockly.Python.valueToCode(block, 'B', order);
  if (!argument0 && !argument1) {
    // If there are no arguments, then the return value is false.
    argument0 = 'False';
    argument1 = 'False';
  } else {
    // Single missing arguments have no effect on the return value.
    var defaultArgument = (operator == 'and') ? 'True' : 'False';
    if (!argument0) {
      argument0 = defaultArgument;
    }
    if (!argument1) {
      argument1 = defaultArgument;
    }
  }
  var code = argument0 + ' ' + operator + ' ' + argument1;
  return [code, order];
};

Blockly.Python['logic_negate'] = function(block) {
  // Negation.
  var argument0 = Blockly.Python.valueToCode(block, 'BOOL',
      Blockly.Python.ORDER_LOGICAL_NOT) || 'True';
  var code = 'not ' + argument0;
  return [code, Blockly.Python.ORDER_LOGICAL_NOT];
};

Blockly.Python['logic_boolean'] = function(block) {
  // Boolean values true and false.
  var code = (block.getFieldValue('BOOL') == 'TRUE') ? 'True' : 'False';
  return [code, Blockly.Python.ORDER_ATOMIC];
};

Blockly.Python['logic_null'] = function(block) {
  // Null data type.
  return ['None', Blockly.Python.ORDER_ATOMIC];
};

Blockly.Python['logic_ternary'] = function(block) {
  // Ternary operator.
  var value_if = Blockly.Python.valueToCode(block, 'IF',
      Blockly.Python.ORDER_CONDITIONAL) || 'False';
  var value_then = Blockly.Python.valueToCode(block, 'THEN',
      Blockly.Python.ORDER_CONDITIONAL) || 'None';
  var value_else = Blockly.Python.valueToCode(block, 'ELSE',
      Blockly.Python.ORDER_CONDITIONAL) || 'None';
  var code = value_then + ' if ' + value_if + ' else ' + value_else
  return [code, Blockly.Python.ORDER_CONDITIONAL];
};

Blockly.Python['logic_isCase'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'ISLOWER': 'islower',
    'ISUPPER': 'isupper',
    'ISTITLE': 'istitle',
  };
  var method = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_MEMBER;
  var text = Blockly.Python.valueToCode(block, 'TEXT', order) || '\'\'';
  var code = text + '.' + method + '()';
  return [code, order];
};

Blockly.Python['logic_isEmpty'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'IS': '',
    'IS_NOT': 'not ',
  };
  var op = block.getFieldValue('OP');
  var order = (op === 'IS') ? Blockly.Python.ORDER_NONE : Blockly.Python.ORDER_RELATIONAL;
  var value = Blockly.Python.valueToCode(block, 'VALUE', order) || '\'\'';
  var code = OPERATORS[op] + value;
  return [code, order];
};

Blockly.Python['logic_isMember'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'IN': 'in',
    'NOT_IN': 'not in',
  };
  var op = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_RELATIONAL;
  var text = Blockly.Python.valueToCode(block, 'TEXT', order) || '\'\'';
  var member = Blockly.Python.valueToCode(block, 'MEMBER', order) || '\'\'';
  var code = member + ' ' + op + ' ' + text;
  return [code, order];
};

Blockly.Python['logic_stringEnds'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'STARTSWITH': 'startswith',
    'ENDSWITH': 'endswith'
  };
  var method = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_MEMBER;
  var text = Blockly.Python.valueToCode(block, 'TEXT', order) || '\'\'';
  var fix = Blockly.Python.valueToCode(block, 'FIX', Blockly.Python.ORDER_FUNCTION_CALL) || '\'\'';
  var code = text + '.' + method + '(' + fix + ')';
  return [code, order];
};
<commit_msg>Fixed an error in the isEmpty generated Python ('not' in the wrong spot).<commit_after>/**
 * @license
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * https://blockly.googlecode.com/
 *
 * 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.
 */

/**
 * @fileoverview Generating Python for logic blocks.
 * @author q.neutron@gmail.com (Quynh Neutron)
 */
'use strict';

goog.provide('Blockly.Python.logic');

goog.require('Blockly.Python');

Blockly.Python['controls_if'] = function(block) {
  // If/elseif/else condition.
  var n = 0;
  var argument = Blockly.Python.valueToCode(block, 'IF' + n,
      Blockly.Python.ORDER_NONE) || 'False';
  var branch = Blockly.Python.statementToCode(block, 'DO' + n) || '  pass\n';
  var code = 'if ' + argument + ':\n' + branch;
  for (n = 1; n <= block.elseifCount_; n++) {
    argument = Blockly.Python.valueToCode(block, 'IF' + n,
        Blockly.Python.ORDER_NONE) || 'False';
    branch = Blockly.Python.statementToCode(block, 'DO' + n) || '  pass\n';
    code += 'elif ' + argument + ':\n' + branch;
  }
  if (block.elseCount_) {
    branch = Blockly.Python.statementToCode(block, 'ELSE') || '  pass\n';
    code += 'else:\n' + branch;
  }
  return code;
};

Blockly.Python['logic_compare'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'EQ': '==',
    'NEQ': '!=',
    'LT': '<',
    'LTE': '<=',
    'GT': '>',
    'GTE': '>='
  };
  var operator = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_RELATIONAL;
  var argument0 = Blockly.Python.valueToCode(block, 'A', order) || '0';
  var argument1 = Blockly.Python.valueToCode(block, 'B', order) || '0';
  var code = argument0 + ' ' + operator + ' ' + argument1;
  return [code, order];
};

Blockly.Python['logic_operation'] = function(block) {
  // Operations 'and', 'or'.
  var operator = (block.getFieldValue('OP') == 'AND') ? 'and' : 'or';
  var order = (operator == 'and') ? Blockly.Python.ORDER_LOGICAL_AND :
      Blockly.Python.ORDER_LOGICAL_OR;
  var argument0 = Blockly.Python.valueToCode(block, 'A', order);
  var argument1 = Blockly.Python.valueToCode(block, 'B', order);
  if (!argument0 && !argument1) {
    // If there are no arguments, then the return value is false.
    argument0 = 'False';
    argument1 = 'False';
  } else {
    // Single missing arguments have no effect on the return value.
    var defaultArgument = (operator == 'and') ? 'True' : 'False';
    if (!argument0) {
      argument0 = defaultArgument;
    }
    if (!argument1) {
      argument1 = defaultArgument;
    }
  }
  var code = argument0 + ' ' + operator + ' ' + argument1;
  return [code, order];
};

Blockly.Python['logic_negate'] = function(block) {
  // Negation.
  var argument0 = Blockly.Python.valueToCode(block, 'BOOL',
      Blockly.Python.ORDER_LOGICAL_NOT) || 'True';
  var code = 'not ' + argument0;
  return [code, Blockly.Python.ORDER_LOGICAL_NOT];
};

Blockly.Python['logic_boolean'] = function(block) {
  // Boolean values true and false.
  var code = (block.getFieldValue('BOOL') == 'TRUE') ? 'True' : 'False';
  return [code, Blockly.Python.ORDER_ATOMIC];
};

Blockly.Python['logic_null'] = function(block) {
  // Null data type.
  return ['None', Blockly.Python.ORDER_ATOMIC];
};

Blockly.Python['logic_ternary'] = function(block) {
  // Ternary operator.
  var value_if = Blockly.Python.valueToCode(block, 'IF',
      Blockly.Python.ORDER_CONDITIONAL) || 'False';
  var value_then = Blockly.Python.valueToCode(block, 'THEN',
      Blockly.Python.ORDER_CONDITIONAL) || 'None';
  var value_else = Blockly.Python.valueToCode(block, 'ELSE',
      Blockly.Python.ORDER_CONDITIONAL) || 'None';
  var code = value_then + ' if ' + value_if + ' else ' + value_else
  return [code, Blockly.Python.ORDER_CONDITIONAL];
};

Blockly.Python['logic_isCase'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'ISLOWER': 'islower',
    'ISUPPER': 'isupper',
    'ISTITLE': 'istitle',
  };
  var method = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_MEMBER;
  var text = Blockly.Python.valueToCode(block, 'TEXT', order) || '\'\'';
  var code = text + '.' + method + '()';
  return [code, order];
};

Blockly.Python['logic_isEmpty'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'IS': 'not ',
    'IS_NOT': '',
  };
  var op = block.getFieldValue('OP');
  var order = (op === 'IS') ? Blockly.Python.ORDER_NONE : Blockly.Python.ORDER_RELATIONAL;
  var value = Blockly.Python.valueToCode(block, 'VALUE', order) || '\'\'';
  var code = OPERATORS[op] + value;
  return [code, order];
};

Blockly.Python['logic_isMember'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'IN': 'in',
    'NOT_IN': 'not in',
  };
  var op = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_RELATIONAL;
  var text = Blockly.Python.valueToCode(block, 'TEXT', order) || '\'\'';
  var member = Blockly.Python.valueToCode(block, 'MEMBER', order) || '\'\'';
  var code = member + ' ' + op + ' ' + text;
  return [code, order];
};

Blockly.Python['logic_stringEnds'] = function(block) {
  // Comparison operator.
  var OPERATORS = {
    'STARTSWITH': 'startswith',
    'ENDSWITH': 'endswith'
  };
  var method = OPERATORS[block.getFieldValue('OP')];
  var order = Blockly.Python.ORDER_MEMBER;
  var text = Blockly.Python.valueToCode(block, 'TEXT', order) || '\'\'';
  var fix = Blockly.Python.valueToCode(block, 'FIX', Blockly.Python.ORDER_FUNCTION_CALL) || '\'\'';
  var code = text + '.' + method + '(' + fix + ')';
  return [code, order];
};
<|endoftext|>


<commit_before>'use strict';

describe('unavailableevents accout rest service', function() {

    var server, userAccount;

    beforeEach(function(done) {

        var helpers = require('../mockServer');

        helpers.mockServer('accountUnavailableEvents', function(_mockServer) {
            server = _mockServer;
            done();
        });
    });

    it('verify the mock server', function(done) {
        expect(server.app).toBeDefined();
        done();
    });

    it('request unavailableevents list as anonymous', function(done) {
        server.get('/rest/account/unavailableevents', {}, function(res) {
            expect(res.statusCode).toEqual(401);
            done();
        });
    });

    it('Create account session', function(done) {

        server.createUserAccount()
        .then(function(account) {
            userAccount = account;
            server.authenticateUser(account).then(function() {
                done();
            });
        });

    });

    it('request unavailableevents list as account with missing parameters', function(done) {
        server.get('/rest/account/unavailableevents', {}, function(res, body) {
            expect(res.statusCode).toEqual(403);
            expect(body.$outcome.success).toBeFalsy();
            done();
        });
    });

    it('request unavailableevents as account, without working period', function(done) {

        var dtstart, dtend;

        dtstart = new Date(2015,1,1).toJSON();
        dtend = new Date(2015,2,1).toJSON();

        server.get('/rest/account/unavailableevents', { dtstart: dtstart, dtend: dtend }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toBe(1); // no working period defined
            done();
        });
    });

    it('logout', function(done) {
        server.get('/rest/logout', {}, function(res) {
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('login as admin', function(done) {
        server.createAdminSession().then(function() {
            done();
        });
    });

    it('set a working period for account', function(done) {

        var find = server.app.db.models.Calendar.findOne({ type: 'workschedule' });
        find.exec(function(err, calendar) {
            var from = new Date(2015,1,1);
            var to = new Date(2022,1,1);

            server.post('/rest/admin/accountschedulecalendars', {
                user: userAccount.user._id,
                calendar: { _id: calendar._id },
                from: from,
                to: to
            }, function(res, body) {
                expect(res.statusCode).toEqual(200);
                server.expectSuccess(body);
                done();
            });
        });
    });

    it('logout', function(done) {
        server.get('/rest/logout', {}, function(res) {
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('Authenticate as account', function(done) {
        server.authenticateUser(userAccount).then(function() {
            done();
        });
    });

    function testDate(dtstart, expectedNonWorkingPeriod, callback) {

        let event;
        let dtend = new Date(dtstart);
        dtend.setDate(dtend.getDate()+1);

        server.get('/rest/account/unavailableevents', { dtstart: dtstart.toJSON(), dtend: dtend.toJSON() }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toEqual(expectedNonWorkingPeriod);

            for(var i=0; i<body.length; i++) {
                event = body[i];
                expect(event.dtstart).toBeDefined();
                expect(event.dtend).toBeDefined();
            }

            callback();
        });

    }

    it('request unavailableevents as account on a monday, with working period set', function(done) {

        testDate(new Date(2015, 4, 4), 3, done);
    });

    it('request unavailableevents as account on a sunday', function(done) {

        testDate(new Date(2015, 4, 2), 1, done);
    });

    it('request unavailableevents as account on a non-working day', function(done) {

        testDate(new Date(2015, 4, 1), 1, done);
    });

    it('request unavailableevents as account on one year', function(done) {

        var dtstart, dtend;

        dtstart = new Date(2015,0,1).toJSON();
        dtend = new Date(2016,0,1).toJSON();

        server.get('/rest/account/unavailableevents', { dtstart: dtstart, dtend: dtend }, function(res, body) {
            expect(body.length).toEqual(463);
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('request unavailableevents on a working day', function(done) {
        const dtstart = new Date(2020,5,2, 7, 0);
        const dtend = new Date(2020,5,2, 12, 0);
        server.get('/rest/account/unavailableevents', { dtstart: dtstart.toJSON(), dtend: dtend.toJSON() }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toEqual(1);
            const event = body[0];
            const dtstart = new Date(event.dtstart);
            const dtend = new Date(event.dtend);
            expect(dtstart.getDate()).toEqual(2);
            expect(dtend.getDate()).toEqual(2);
            const startHour = (dtstart.getHours() + (dtstart.getMinutes() / 60));
            const endHour = (dtend.getHours() + (dtend.getMinutes() / 60));
            expect(endHour - startHour).toEqual(1);
            done();
        });
    });

    it('request unavailableevents on a non working day', function(done) {
        const dtstart = new Date(2020,5,1, 8, 0);
        const dtend = new Date(2020,5,1, 12, 0);
        server.get('/rest/account/unavailableevents', { dtstart: dtstart.toJSON(), dtend: dtend.toJSON() }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toEqual(1);
            const event = body[0];
            const dtstart = new Date(event.dtstart);
            const dtend = new Date(event.dtend);
            expect(dtstart.getDate()).toEqual(1);
            expect(dtend.getDate()).toEqual(1);
            const startHour = (dtstart.getHours() + (dtstart.getMinutes() / 60));
            const endHour = (dtend.getHours() + (dtend.getMinutes() / 60));
            expect(endHour - startHour).toEqual(4);
            done();
        });
    });

    it('close the mock server', function(done) {
        server.close(done);
    });

});
<commit_msg>Add test on one month<commit_after>'use strict';

describe('unavailableevents accout rest service', function() {

    var server, userAccount;

    beforeEach(function(done) {

        var helpers = require('../mockServer');

        helpers.mockServer('accountUnavailableEvents', function(_mockServer) {
            server = _mockServer;
            done();
        });
    });

    it('verify the mock server', function(done) {
        expect(server.app).toBeDefined();
        done();
    });

    it('request unavailableevents list as anonymous', function(done) {
        server.get('/rest/account/unavailableevents', {}, function(res) {
            expect(res.statusCode).toEqual(401);
            done();
        });
    });

    it('Create account session', function(done) {

        server.createUserAccount()
        .then(function(account) {
            userAccount = account;
            server.authenticateUser(account).then(function() {
                done();
            });
        });

    });

    it('request unavailableevents list as account with missing parameters', function(done) {
        server.get('/rest/account/unavailableevents', {}, function(res, body) {
            expect(res.statusCode).toEqual(403);
            expect(body.$outcome.success).toBeFalsy();
            done();
        });
    });

    it('request unavailableevents as account, without working period', function(done) {

        var dtstart, dtend;

        dtstart = new Date(2015,1,1).toJSON();
        dtend = new Date(2015,2,1).toJSON();

        server.get('/rest/account/unavailableevents', { dtstart: dtstart, dtend: dtend }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toBe(1); // no working period defined
            done();
        });
    });

    it('logout', function(done) {
        server.get('/rest/logout', {}, function(res) {
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('login as admin', function(done) {
        server.createAdminSession().then(function() {
            done();
        });
    });

    it('set a working period for account', function(done) {

        var find = server.app.db.models.Calendar.findOne({ type: 'workschedule' });
        find.exec(function(err, calendar) {
            var from = new Date(2015,1,1);
            var to = new Date(2022,1,1);

            server.post('/rest/admin/accountschedulecalendars', {
                user: userAccount.user._id,
                calendar: { _id: calendar._id },
                from: from,
                to: to
            }, function(res, body) {
                expect(res.statusCode).toEqual(200);
                server.expectSuccess(body);
                done();
            });
        });
    });

    it('logout', function(done) {
        server.get('/rest/logout', {}, function(res) {
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('Authenticate as account', function(done) {
        server.authenticateUser(userAccount).then(function() {
            done();
        });
    });

    function testDate(dtstart, expectedNonWorkingPeriod, callback) {

        let event;
        let dtend = new Date(dtstart);
        dtend.setDate(dtend.getDate()+1);

        server.get('/rest/account/unavailableevents', { dtstart: dtstart.toJSON(), dtend: dtend.toJSON() }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toEqual(expectedNonWorkingPeriod);

            for(var i=0; i<body.length; i++) {
                event = body[i];
                expect(event.dtstart).toBeDefined();
                expect(event.dtend).toBeDefined();
            }

            callback();
        });

    }

    it('request unavailableevents as account on a monday, with working period set', function(done) {

        testDate(new Date(2015, 4, 4), 3, done);
    });

    it('request unavailableevents as account on a sunday', function(done) {

        testDate(new Date(2015, 4, 2), 1, done);
    });

    it('request unavailableevents as account on a non-working day', function(done) {

        testDate(new Date(2015, 4, 1), 1, done);
    });

    it('request unavailableevents as account on one month', function(done) {
        server.get('/rest/account/unavailableevents', { dtstart: new Date(2015,11,1).toJSON(), dtend: new Date(2016,0,1).toJSON() }, function(res, body) {
            expect(body.length).toEqual(45);
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('request unavailableevents as account on one year', function(done) {
        server.get('/rest/account/unavailableevents', { dtstart: new Date(2015,0,1).toJSON(), dtend: new Date(2016,0,1).toJSON() }, function(res, body) {
            expect(body.length).toEqual(463);
            expect(res.statusCode).toEqual(200);
            done();
        });
    });

    it('request unavailableevents on a working day', function(done) {
        const dtstart = new Date(2020,5,2, 7, 0);
        const dtend = new Date(2020,5,2, 12, 0);
        server.get('/rest/account/unavailableevents', { dtstart: dtstart.toJSON(), dtend: dtend.toJSON() }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toEqual(1);
            const event = body[0];
            const dtstart = new Date(event.dtstart);
            const dtend = new Date(event.dtend);
            expect(dtstart.getDate()).toEqual(2);
            expect(dtend.getDate()).toEqual(2);
            const startHour = (dtstart.getHours() + (dtstart.getMinutes() / 60));
            const endHour = (dtend.getHours() + (dtend.getMinutes() / 60));
            expect(endHour - startHour).toEqual(1);
            done();
        });
    });

    it('request unavailableevents on a non working day', function(done) {
        const dtstart = new Date(2020,5,1, 8, 0);
        const dtend = new Date(2020,5,1, 12, 0);
        server.get('/rest/account/unavailableevents', { dtstart: dtstart.toJSON(), dtend: dtend.toJSON() }, function(res, body) {
            expect(res.statusCode).toEqual(200);
            expect(body.length).toEqual(1);
            const event = body[0];
            const dtstart = new Date(event.dtstart);
            const dtend = new Date(event.dtend);
            expect(dtstart.getDate()).toEqual(1);
            expect(dtend.getDate()).toEqual(1);
            const startHour = (dtstart.getHours() + (dtstart.getMinutes() / 60));
            const endHour = (dtend.getHours() + (dtend.getMinutes() / 60));
            expect(endHour - startHour).toEqual(4);
            done();
        });
    });

    it('close the mock server', function(done) {
        server.close(done);
    });

});
<|endoftext|>


<commit_before>'use strict';

describe('location tests', function () {

  var $scope, element, $routeParams, locationFactory, q, deferred, $httpBackend;

  beforeEach(module('templates'));

  beforeEach(module('myApp', function($provide) {
    locationFactory = {
      query: function () {
        deferred = q.defer();
        return {$promise: deferred.promise};
      },
      users: function () {
        deferred = q.defer();
        return {$promise: deferred.promise};
      }
    };
    $provide.value("Location", locationFactory);
  }));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.whenGET('/translations/en_GB.json').respond("");
  }));

  describe('creation of users for a location', function() {
    beforeEach(inject(function($compile, $rootScope, $q, _$routeParams_, $injector) {
      $scope = $rootScope;
      q = $q;

      $routeParams = _$routeParams_;
      $routeParams.page = 10;
      $routeParams.per = 5;

      $scope.location = {}
      $scope.loading = true;
      var elem = angular.element('<location-admins location="location" loading="loading"></location-admins>');
      element = $compile(elem)($rootScope);
      element.scope().$digest();
    }));

    it("should display the users for the brand", function() {
      element.isolateScope().location = {};

      spyOn(locationFactory, 'users').and.callThrough()
      expect(element.isolateScope().users.length).toEqual(0)

      var email = 'foo@bar.com';
      var results = [{ email: email }];
      deferred.resolve(results);
      $scope.$digest();

      expect(element.isolateScope().users[0].email).toBe(email);
      expect(element.isolateScope().allowed).toBe(true);
      expect(element.isolateScope().menu.length).toBe(2);
      expect(element.isolateScope().menu[0].type).toBe('view');
      expect(element.isolateScope().menu[1].type).toBe('revoke');
      expect(element.isolateScope().query.order).toBe('state');
      expect(element.isolateScope().query.limit).toBe(5);
      expect(element.isolateScope().query.page).toBe(10);
      expect(element.isolateScope().loading).toBe(undefined);

      expect(element.isolateScope().roles.length).toBe(3);
      expect(element.isolateScope().roles[0].role_id).toBe(101);
      expect(element.isolateScope().roles[0].name).toBe('Administrator');
    });

  });

});

<commit_msg>Adds tests for new permissions<commit_after>'use strict';

describe('location tests', function () {

  var $scope, element, $routeParams, locationFactory, q, deferred, $httpBackend;

  beforeEach(module('templates'));

  beforeEach(module('myApp', function($provide) {
    locationFactory = {
      query: function () {
        deferred = q.defer();
        return {$promise: deferred.promise};
      },
      users: function () {
        deferred = q.defer();
        return {$promise: deferred.promise};
      }
    };
    $provide.value("Location", locationFactory);
  }));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.whenGET('/translations/en_GB.json').respond("");
  }));

  describe('creation of users for a location', function() {
    beforeEach(inject(function($compile, $rootScope, $q, _$routeParams_, $injector) {
      $scope = $rootScope;
      q = $q;

      $routeParams = _$routeParams_;
      $routeParams.page = 10;
      $routeParams.per = 5;

      $scope.location = {}
      $scope.loading = true;
      var elem = angular.element('<location-admins location="location" loading="loading"></location-admins>');
      element = $compile(elem)($rootScope);
      element.scope().$digest();
    }));

    it("should display the users for the brand", function() {
      element.isolateScope().location = {};

      spyOn(locationFactory, 'users').and.callThrough()
      expect(element.isolateScope().users.length).toEqual(0)

      var email = 'foo@bar.com';
      var results = [{ email: email }];
      deferred.resolve(results);
      $scope.$digest();

      expect(element.isolateScope().users[0].email).toBe(email);
      expect(element.isolateScope().allowed).toBe(true);
      expect(element.isolateScope().menu.length).toBe(2);
      expect(element.isolateScope().menu[0].type).toBe('view');
      expect(element.isolateScope().menu[1].type).toBe('revoke');
      expect(element.isolateScope().query.order).toBe('state');
      expect(element.isolateScope().query.limit).toBe(5);
      expect(element.isolateScope().query.page).toBe(10);
      expect(element.isolateScope().loading).toBe(undefined);

      expect(element.isolateScope().roles.length).toBe(4);
      expect(element.isolateScope().roles[0].role_id).toBe(110);
      expect(element.isolateScope().roles[0].name).toBe('Administrator');
      expect(element.isolateScope().roles[1].role_id).toBe(120);
      expect(element.isolateScope().roles[1].name).toBe('Editor');
      expect(element.isolateScope().roles[2].role_id).toBe(130);
      expect(element.isolateScope().roles[2].name).toBe('Supporter');
      expect(element.isolateScope().roles[3].role_id).toBe(140);
      expect(element.isolateScope().roles[3].name).toBe('Observer');
    });

  });

});

<|endoftext|>


<commit_before>var root = require('../root'),
  fs = require('fs'),
  util = require('util'),
  events = require('events'),
  serialport = require("serialport"),
  SerialPort = serialport.SerialPort; // localize object constructor

/**
 * Communication class to talk with the drawbot
 */
var Communication = function() {
  var firstArrow = true,
    index = 0,
    EOF = false,
    serial,
    self = this,
    isConnected = false,
    emitEventOnFinish = false,
    cmdBuffer = fs.readFileSync(root.path + '/communication/setup.gcode').toString().split('\n'); //init the buffer with setup code

  this.EVENT = {
    CONNECTED: 'connected',
    PORT_OPENED: 'portOpened',
    DISCONNECTED: 'disconnected',
    LOG: 'log',
    DRAW_STARTED: 'drawStarted',
    DRAW_FINISHED: 'drawFinished'
  };

  this.isDrawing = false;

  /**
   * get serial ports available
   * @param callback this will be called with ports as parameters
   */
  this.getSerialPortList = function(callback) {
    serialport.list(function(err, ports) {
      callback(ports);
    });
  };

  /**
   * Connect to drawbot on given port comName
   * @param portComName
   */
  this.connect = function(portComName) {
    if(!isConnected) {
      if(!portComName) {
        util.error('Called connect but no port defined');
        return;
      }

      isConnected = true;
      self.emit(self.EVENT.CONNECTED);

      serial = new SerialPort(portComName, {
        parser: serialport.parsers.readline("\n"),
        baudrate: 57600
      });

      serial.on("open", function () {
        self.emit(self.EVENT.PORT_OPENED);
        //get data and log
        self.log('-- [COMM] communication opened on ' + portComName);

        serial.on('data', function(data) {
          //path is clear
          self.log('IN: ' + data);

          if(data.length > 2){
            //self.log('IN: ' + data);
          }else if(data.indexOf(">") >= 0) // TODO : better string
          {
            //roger
            if(!firstArrow)
            {
              self.write(); // send next line
            }else
            {
              firstArrow = false;
            }
          }
        });

        serial.on('error', function(error) {
          self.emit(self.EVENT.DISCONNECTED);
          self.Log.error('ERROR + serial error - disconnected \n' + error);
          isConnected = false;
        });
      });
    }
  };

  this.disconnect = function() {
    if(serial && isConnected) {
      self.emit(self.EVENT.DISCONNECTED);
      serial.close();
      isConnected = false;
    }
  };

  /**
   * Send a line to a robot and add a \n
   * @param string
   */
  this.writeLine = function(string) {
    cmdBuffer.push(string);
  };

  /**
   * send the next line to the robot
   */
  this.write = function() {
    if(serial) {
      var cmd = cmdBuffer.splice(0, 1);
      if(cmd.length){
        if(cmd.indexOf('M200') > -1) {
          self.isDrawing = true;
          self.emit(self.EVENT.DRAW_STARTED);
        } else if(cmd.indexOf('M201') > -1) {
          self.isDrawing = false;
          self.emit(self.EVENT.DRAW_FINISHED);
        } else {
          self.Log.debug('SENDING : ' + cmd);
          serial.write(cmd + '\n', function(err, results) {
            if(err) self.Log.error('ERROR ' + err);
          });
        }
      }
    }
  };

  /**
   * read batch and push in buffer
   */
  this.batch = function(text) {
    emitEventOnFinish = true;

    var oldSize = cmdBuffer.length;
    cmdBuffer = cmdBuffer.concat(text.split('\n'));
    self.Log.debug('Pushed ' + (cmdBuffer.length - oldSize) + ' new command in Buffer');
  };

  /**
   * Move the robot around
   * @param direction {'up', 'down', 'left', 'right'}
   */
  this.jog = function(direction) {
    this.writeLine('G91');

    if(direction === 'up') {
      this.writeLine('G00 F2000 Y20');
    } else if(direction === 'down') {
      this.writeLine('G00 F2000 Y-20');
    } else if(direction === 'left') {
      this.writeLine('G00 F2000 X-20');
    } else if(direction === 'right') {
      this.writeLine('G00 F2000 X20');
    }

    this.writeLine('G90');
  };

  /**
   * Check if we're connected to drawbot.
   * Useful when a user connects, so we can
   * directly tell him the state of the robot
   * @returns {boolean}
   */
  this.isSerialConnected = function() {
    return isConnected;
  };

  /**
   * Logging
   *
   * trace: for output purpose
   * error: for errors (displayed in red on web page)
   * debug: only for debugging, temporary logs (displayed in blue on web page)
   */

  this.Log = {
    trace: function(string) {
      util.log(string);
      self.emit(self.EVENT.LOG, string, 'trace');
    },
    error: function(string) {
      util.error(string);
      self.emit(self.EVENT.LOG, string, 'error');
    },
    debug: function(string) {
      util.debug(string);
      self.emit(self.EVENT.LOG, string, 'debug');
    }
  };

  // proxy method for confort
  this.log = function(string) {
    this.Log.trace(string);
  }
};

/**
 * Prototype inheritance for EventEmitter
 */
util.inherits(Communication, events.EventEmitter);

module.exports = Communication;
<commit_msg>bugfix process<commit_after>var root = require('../root'),
  fs = require('fs'),
  util = require('util'),
  events = require('events'),
  serialport = require("serialport"),
  SerialPort = serialport.SerialPort; // localize object constructor

/**
 * Communication class to talk with the drawbot
 */
var Communication = function() {
  var firstArrow = true,
    index = 0,
    EOF = false,
    serial,
    self = this,
    isConnected = false,
    emitEventOnFinish = false,
    cmdBuffer = fs.readFileSync(root.path + '/communication/setup.gcode').toString().split('\n'); //init the buffer with setup code

  this.EVENT = {
    CONNECTED: 'connected',
    PORT_OPENED: 'portOpened',
    DISCONNECTED: 'disconnected',
    LOG: 'log',
    DRAW_STARTED: 'drawStarted',
    DRAW_FINISHED: 'drawFinished'
  };

  this.isDrawing = false;

  /**
   * get serial ports available
   * @param callback this will be called with ports as parameters
   */
  this.getSerialPortList = function(callback) {
    serialport.list(function(err, ports) {
      callback(ports);
    });
  };

  /**
   * Connect to drawbot on given port comName
   * @param portComName
   */
  this.connect = function(portComName) {
    if(!isConnected) {
      if(!portComName) {
        util.error('Called connect but no port defined');
        return;
      }

      isConnected = true;
      self.emit(self.EVENT.CONNECTED);

      serial = new SerialPort(portComName, {
        parser: serialport.parsers.readline("\n"),
        baudrate: 57600
      });

      serial.on("open", function () {
        self.emit(self.EVENT.PORT_OPENED);
        //get data and log
        self.log('-- [COMM] communication opened on ' + portComName);

        serial.on('data', function(data) {
          //path is clear
          //self.log('IN: ' + data);

          if(data.length > 2){
            //self.log('IN: ' + data);
          }else if(data.indexOf(">") >= 0) // TODO : better string
          {
            //roger
            if(!firstArrow)
            {
              self.write(); // send next line
            }else
            {
              firstArrow = false;
            }
          }
        });

        serial.on('error', function(error) {
          self.emit(self.EVENT.DISCONNECTED);
          self.Log.error('ERROR + serial error - disconnected \n' + error);
          isConnected = false;
        });
      });
    }
  };

  this.disconnect = function() {
    if(serial && isConnected) {
      self.emit(self.EVENT.DISCONNECTED);
      serial.close();
      isConnected = false;
    }
  };

  /**
   * Send a line to a robot and add a \n
   * @param string
   */
  this.writeLine = function(string) {
    cmdBuffer.push(string);
  };

  /**
   * send the next line to the robot
   */
  this.write = function() {
    if(serial) {
      var cmd = cmdBuffer.splice(0, 1);
      if(cmd.length){
        if(cmd.indexOf('M200') > -1) {
          self.isDrawing = true;
          self.emit(self.EVENT.DRAW_STARTED);
        } else if(cmd.indexOf('M201') > -1) {
          self.isDrawing = false;
          self.emit(self.EVENT.DRAW_FINISHED);
        } else {
          //self.Log.debug('SENDING : ' + cmd);
          serial.write(cmd + '\n', function(err, results) {
            if(err) self.Log.error('ERROR ' + err);
          });
        }
      }
    }
  };

  /**
   * read batch and push in buffer
   */
  this.batch = function(text) {
    emitEventOnFinish = true;

    var oldSize = cmdBuffer.length;
    cmdBuffer = cmdBuffer.concat(text.split('\n'));
    self.Log.debug('Pushed ' + (cmdBuffer.length - oldSize) + ' new command in Buffer');
  };

  /**
   * Move the robot around
   * @param direction {'up', 'down', 'left', 'right'}
   */
  this.jog = function(direction) {
    this.writeLine('G91');

    if(direction === 'up') {
      this.writeLine('G00 F2000 Y20');
    } else if(direction === 'down') {
      this.writeLine('G00 F2000 Y-20');
    } else if(direction === 'left') {
      this.writeLine('G00 F2000 X-20');
    } else if(direction === 'right') {
      this.writeLine('G00 F2000 X20');
    }

    this.writeLine('G90');
  };

  /**
   * Check if we're connected to drawbot.
   * Useful when a user connects, so we can
   * directly tell him the state of the robot
   * @returns {boolean}
   */
  this.isSerialConnected = function() {
    return isConnected;
  };

  /**
   * Logging
   *
   * trace: for output purpose
   * error: for errors (displayed in red on web page)
   * debug: only for debugging, temporary logs (displayed in blue on web page)
   */

  this.Log = {
    trace: function(string) {
      util.log(string);
      self.emit(self.EVENT.LOG, string, 'trace');
    },
    error: function(string) {
      util.error(string);
      self.emit(self.EVENT.LOG, string, 'error');
    },
    debug: function(string) {
      util.debug(string);
      self.emit(self.EVENT.LOG, string, 'debug');
    }
  };

  // proxy method for confort
  this.log = function(string) {
    this.Log.trace(string);
  }
};

/**
 * Prototype inheritance for EventEmitter
 */
util.inherits(Communication, events.EventEmitter);

module.exports = Communication;
<|endoftext|>


<commit_before>define([
	'goo/entities/Entity',
	'goo/entities/components/TransformComponent',
	'goo/entities/components/LightComponent',
	'goo/entities/systems/LightingSystem'
], function (
	Entity,
	TransformComponent,
	LightComponent,
	LightingSystem
) {
	describe('LightingSystem', function () {
		describe('inserted', function () {
			it('will update a light\'s transform', function () {
				var light = jasmine.createSpyObj('Light', ['update']);
				var lightComponent = new LightComponent(light);
				var entity = new Entity().setComponent(lightComponent).setComponent(new TransformComponent());
				var lightingSystem = new LightingSystem();

				lightingSystem.inserted(entity);

				expect(light.update).toHaveBeenCalledWith(entity.transformComponent.worldTransform);
			});
		});
	});
});<commit_msg>Post-reviewed - added 2 more lighting-system-related unit tests<commit_after>define([
	'goo/entities/Entity',
	'goo/entities/World',
	'goo/entities/components/TransformComponent',
	'goo/entities/components/LightComponent',
	'goo/entities/systems/LightingSystem'
], function (
	Entity,
	World,
	TransformComponent,
	LightComponent,
	LightingSystem
) {
	'use strict';

	describe('LightingSystem', function () {
		describe('inserted', function () {
			it('will update a light\'s transform', function () {
				var light = jasmine.createSpyObj('Light', ['update']);
				var lightComponent = new LightComponent(light);
				var entity = new Entity().setComponent(lightComponent).setComponent(new TransformComponent());
				var lightingSystem = new LightingSystem();

				lightingSystem.inserted(entity);

				expect(light.update).toHaveBeenCalledWith(entity.transformComponent.worldTransform);
			});
		});

		// testing interaction coming from 'world-space'
		describe('+World', function () {
			it('adds and updates a light when adding an entity with a light component to the world', function () {
				var light = jasmine.createSpyObj('Light', ['update']);
				var lightComponent = new LightComponent(light);
				var lightingSystem = new LightingSystem();

				var world = new World();
				world.setSystem(lightingSystem);
				var entity = world.createEntity(lightComponent).addToWorld();

				world.process();

				expect(lightingSystem.lights).toContain(light);
				expect(light.update).toHaveBeenCalledWith(entity.transformComponent.worldTransform);
			});

			it('adds and updates a light when adding a light component on an existing entity', function () {
				var light = jasmine.createSpyObj('Light', ['update']);
				var lightComponent = new LightComponent(light);
				var lightingSystem = new LightingSystem();

				var world = new World();
				world.setSystem(lightingSystem);
				var entity = world.createEntity().addToWorld();

				world.process();

				entity.setComponent(lightComponent);

				world.process();

				expect(lightingSystem.lights).toContain(light);
				expect(light.update).toHaveBeenCalledWith(entity.transformComponent.worldTransform);
			});
		});
	});
});<|endoftext|>


<commit_before>const debug = require('debug')('connman-tests:ethernet');
const async = require('async');

var _connMan;
var _tech;
var _service;
var _available = false;

module.exports = Ethernet;

const ETHERNET_STATES = {
  IDLE: 'idle',
  FAILURE: 'failure',
  ASSOCIATION: 'association',
  CONFIGURATION: 'configuration',
  READY: 'ready',
  DISCONNECT: 'disconnect',
  ONLINE: 'online',
  CONNECTING: 'connecting', //--extra
  UNKNOWN: 'unkown', //--extra
  DISABLED: 'disabled'
};

function Ethernet(connMan) {
  _connMan = connMan;
}

Ethernet.prototype.init = function(callback) {
  _tech = _connMan.technologies.Wired;

  async.series([
    function(next) {
      if(_tech === undefined) {
        return next(new Error("No ethernet available"));
      }
      next();
    },
    function(next) {
      _tech.getServices(function(err, services) {
        if(err) return next(err);
        if(Object.keys(services).length === 0) return next(new Error("No ethernet service available"));
        _available = true;
        //debug('found ethernet services: ' + Object.keys(services));
        async.eachSeries(Object.keys(services), function(serviceName,eachNext) {
          //debug('get ethernet service: ' + serviceName);
          _connMan.getService(serviceName, function(err, service) {
            if(err) return next(err);
            //debug('wired getConnection response: ',err/*,connection*/);
            _service = service;
            _service.getProperties(function(err, props) {
              if(err) return next(err);
              //debug('wired service \''+serviceName+'\' properties: ',err,props);
              //debug('wired service \''+serviceName+'\' state: ',props.State);
              debug('State: ',props.State);
              next(err,props);
            });
            _service.on('PropertyChanged', function(name, value) {
              debug(name,'changed:',value);
            });
          });
        });
      })
    }
  ],function(err) {
    if(callback) callback(err);
  });
}
Ethernet.prototype.getAvailable = function() {
  return _available;
}<commit_msg>Ethernet improvements<commit_after>const debug = require('debug')('connman-tests:ethernet');
const async = require('async');

var _connman;
var _tech;
var _service;
var _available = false;

module.exports = Ethernet;

const ETHERNET_STATES = {
  IDLE: 'idle',
  FAILURE: 'failure',
  ASSOCIATION: 'association',
  CONFIGURATION: 'configuration',
  READY: 'ready',
  DISCONNECT: 'disconnect',
  ONLINE: 'online',
  CONNECTING: 'connecting', //--extra
  UNKNOWN: 'unkown', //--extra
  DISABLED: 'disabled'
};

function Ethernet(connMan) {
  _connman = connMan;
}

Ethernet.prototype.init = function(callback) {
  _tech = _connman.technologies.Wired;

  async.series([
    function(next) {
      if(_tech === undefined) {
        return next(new Error("No ethernet available"));
      }
      next();
    },
    function(next) {
      _tech.getServices(function(err, services) {
        if(err) return next(err);
        if(Object.keys(services).length === 0) return next(new Error("No ethernet service available"));
        _available = true;
        //debug('found ethernet services: ', Object.keys(services));
        var serviceName = Object.keys(services)[0];
        //debug('get ethernet service: ' + serviceName);
        _connman.getService(serviceName, function(err, service) {
          if(err) return next(err);
          //debug('wired getConnection response: ',err/*,connection*/);
          _service = service;
          _service.getProperties(function(err, props) {
            if(err) return next(err);
            //debug('wired service \''+serviceName+'\' properties: ',err,props);
            //debug('wired service \''+serviceName+'\' state: ',props.State);
            debug('State: ',props.State);
            next(err,props);
          });
          _service.on('PropertyChanged', function(name, value) {
            debug(name,'changed:',value);
          });
        });
      })
    }
  ],function(err) {
    if(callback) callback(err);
  });
}
Ethernet.prototype.getAvailable = function() {
  return _available;
}<|endoftext|>


<commit_before>'use strict';
var tape = require('../lib/thali-tape');
var express = require('express');
var crypto = require('crypto');
var sinon = require('sinon');
var Promise = require('lie');
var http = require('http');

var proxyquire = require('proxyquire').noCallThru();
var ThaliNotificationClient =
  require('thali/NextGeneration/notification/thaliNotificationClient');
var ThaliNotificationServer =
  require('thali/NextGeneration/notification/thaliNotificationServer');
var ThaliMobile =
  require('thali/NextGeneration/thaliMobile');
var ThaliPeerPoolDefault =
  require('thali/NextGeneration/thaliPeerPool/thaliPeerPoolDefault');
var makeIntoCloseAllServer =
  require('thali/NextGeneration/makeIntoCloseAllServer');
var NotificationBeacons =
  require('thali/NextGeneration/notification/thaliNotificationBeacons');

var SECP256K1 = 'secp256k1';

var globals = {};

/**
 * @classdesc This class is a container for all variables and
 * functionality that are common to most of the ThaliNoficationtests.
 */
var GlobalVariables = function () {

  this.expressApp = express();
  this.expressRouter = express.Router();

  // Creates a proxyquired ThaliNotificationServer class.
  var MockThaliMobile = { };
  this.ThaliNotificationServerProxyquired =
    proxyquire('thali/NextGeneration/notification/thaliNotificationServer',
      { '../thaliMobile':
      MockThaliMobile});

  // Mocks ThaliMobile.startUpdateAdvertisingAndListening function
  MockThaliMobile.startUpdateAdvertisingAndListening = function () {
    return Promise.resolve();
  };

  // Mocks ThaliMobile.stopAdvertisingAndListening function
  MockThaliMobile.stopAdvertisingAndListening = function () {
    return Promise.resolve();
  };

  this.TCPEvent = {
    peerIdentifier: 'id123',
    hostAddress: '127.0.0.1',
    portNumber: 0,
    connectionType: ThaliMobile.connectionTypes.TCP_NATIVE,
    suggestedTCPTimeout: 10000
  };
};

GlobalVariables.prototype.initLocal = function () {
  var self = this;
  self.createKeysForLocalTest();
  return new Promise(function (resolve, reject) {
    self.expressApp.use('/', self.expressRouter);
    self.expressServer = self.expressApp.listen(0, function (err) {
      if (err) {
        reject(err);
      } else {
        makeIntoCloseAllServer(self.expressServer);
        self.TCPEvent.portNumber = self.expressServer.address().port;
        resolve();
      }
    });
  });
};

GlobalVariables.prototype.initCoordinated = function () {
  this.expressApp.use('/', this.expressRouter);
};

/**
 * Frees GlobalVariables instance's resources.
 * @returns {Promise<?Error>} Returns a promise that will resolve when the
 * resources are released.
 */
GlobalVariables.prototype.kill = function () {
  if (this.expressServer) {
    return this.expressServer.closeAllPromise();
  }
  return Promise.resolve();
};

GlobalVariables.prototype.createKeysForLocalTest = function () {

  // These keys are for local test
  this.targetPublicKeysToNotify = [];
  this.targetDeviceKeyExchangeObjects = [];

  this.serverKeyExchangeObject = crypto.createECDH(SECP256K1);
  this.serverPublicKey = this.serverKeyExchangeObject.generateKeys();

  var device1 = crypto.createECDH(SECP256K1);
  var device1Key = device1.generateKeys();
  var device2 = crypto.createECDH(SECP256K1);
  var device2Key = device2.generateKeys();

  this.targetPublicKeysToNotify.push(device1Key, device2Key);
  this.targetDeviceKeyExchangeObjects.push(device2, device2);

};

GlobalVariables.prototype.createKeysForCoordinatedTest = function () {
  this.ecdh = crypto.createECDH(SECP256K1);
  this.myKeyExchangeObject = this.ecdh.generateKeys();
  this.myPublicBase64 = this.ecdh.getPublicKey('base64');
};

var test = tape({
  setup: function (t) {
    globals = new GlobalVariables();

    if (tape.coordinated) {
      globals.createKeysForCoordinatedTest();
      t.data = globals.myPublicBase64;
    }
    t.end();
  },

  teardown: function (t) {

    globals.kill().then(function () {
      console.log('killed properly');
      t.end();
    }).catch(function (failure) {
      t.fail('Server cleaning failed:' + failure);
      t.end();
    });
  }
});
/*
test('Client to server request locally', function (t) {

  var p = globals.initLocal();

  p.then(function () {

    var peerPool = new ThaliPeerPoolDefault();

    // Simulates how the peer pool runs actions
    var enqueue = function (action) {
      var keepAliveAgent = new http.Agent({ keepAlive: true });
      action.start(keepAliveAgent).then( function () {
      }).catch( function ( ) {
        t.fail('This action should not fail!');
      });
    };

    sinon.stub(peerPool, 'enqueue', enqueue);

    // Initialize the ThaliNotificationClient
    var notificationClient =
      new ThaliNotificationClient(peerPool,
        globals.targetDeviceKeyExchangeObjects[0]);

    notificationClient.on(ThaliNotificationClient.Events.PeerAdvertisesDataForUs,
      function ( res) {
        t.equals(
          res.hostAddress,
          globals.TCPEvent.hostAddress,
          'Host address must match');
        t.equals(
          res.suggestedTCPTimeout,
          globals.TCPEvent.suggestedTCPTimeout,
          'suggestedTCPTimeout must match');
        t.equals(
          res.connectionType,
          globals.TCPEvent.connectionType,
          'connectionType must match');
        t.equals(
          res.portNumber,
          globals.TCPEvent.portNumber,
          'portNumber must match');

        t.end();
      });

    // Initializes ThaliNotificationServer
    var notificationServer = new globals.ThaliNotificationServerProxyquired(
      globals.expressRouter, globals.serverKeyExchangeObject, 90000);

    notificationServer.start(globals.targetPublicKeysToNotify).
    then(function () {
      notificationClient.start([globals.serverPublicKey]);
      notificationClient._peerAvailabilityChanged(globals.TCPEvent);
    });

  }).catch(function (failure) {
    t.fail('Test setting up failed:' + failure);
    t.end();
  });

});
*/
if (!tape.coordinated) {
  return;
}
var NO_REPLY = 1;
var REPLY = 2;

test('Client to server request coordinated', function (t) {

  globals.initCoordinated();

  var addressBook = [];
  var replies = {};

  if (t.participants) {
    t.participants.forEach(function (participant) {
      if (participant.data !== globals.myPublicBase64) {
        var publicKey = new Buffer(participant.data, 'base64');
        addressBook.push(publicKey);
        var publicKeyHash = NotificationBeacons.createPublicKeyHash(publicKey);
        replies[publicKeyHash] = NO_REPLY;
      }
    });
  }

  if (!t.participants || addressBook.length === 0) {
    t.pass('Can\'t run the test because no participants');
    return t.end();
  }

  console.log('participants:' + addressBook.length);

  var peerPool = new ThaliPeerPoolDefault();

  // Initialize the ThaliNotificationClient
  var notificationClient =
    new ThaliNotificationClient(peerPool,
      globals.ecdh);

  // Initializes ThaliNotificationServer
  var notificationServer = new ThaliNotificationServer(
    globals.expressRouter, globals.ecdh, 90000);

  var finished = false;

  notificationClient.on(ThaliNotificationClient.Events.PeerAdvertisesDataForUs,
    function (res) {

      replies[res.keyId] = REPLY;
      var allReplied = true;
      Object.keys(replies).forEach(function (key) {
        if (replies[key] === NO_REPLY) {
          allReplied = false;
        }
      });
      if (allReplied && !finished) {
        finished = true;
        ThaliMobile.stopListeningForAdvertisements();
        //  Kills services after 3 seconds gives all peers time to run their tests.
        setTimeout( function () {
          t.pass('We pass to any results at this point ');
          t.end();

          notificationServer.stop();
          notificationClient.stop();
        }, 3000);
      }
    });

  var pThaliMobile = ThaliMobile.start(globals.expressRouter);
  pThaliMobile.then( function () {
    return notificationServer.start(addressBook).then(function () {
      console.log('server started!');
      return;
    });
  }).then( function () {
    notificationClient.start(addressBook);
    return ThaliMobile.startListeningForAdvertisements().then( function ( ) {
      console.log('startListeningForAdvertisements');
    });
  });
});

<commit_msg>_peerAvailabilityChanged gets called too often<commit_after>'use strict';
var tape = require('../lib/thali-tape');
var express = require('express');
var crypto = require('crypto');
var sinon = require('sinon');
var Promise = require('lie');
var http = require('http');

var proxyquire = require('proxyquire').noCallThru();
var ThaliNotificationClient =
  require('thali/NextGeneration/notification/thaliNotificationClient');
var ThaliNotificationServer =
  require('thali/NextGeneration/notification/thaliNotificationServer');
var ThaliMobile =
  require('thali/NextGeneration/thaliMobile');
var ThaliPeerPoolDefault =
  require('thali/NextGeneration/thaliPeerPool/thaliPeerPoolDefault');
var makeIntoCloseAllServer =
  require('thali/NextGeneration/makeIntoCloseAllServer');
var NotificationBeacons =
  require('thali/NextGeneration/notification/thaliNotificationBeacons');

var SECP256K1 = 'secp256k1';

var globals = {};

/**
 * @classdesc This class is a container for all variables and
 * functionality that are common to most of the ThaliNoficationtests.
 */
var GlobalVariables = function () {

  this.expressApp = express();
  this.expressRouter = express.Router();

  // Creates a proxyquired ThaliNotificationServer class.
  var MockThaliMobile = { };
  this.ThaliNotificationServerProxyquired =
    proxyquire('thali/NextGeneration/notification/thaliNotificationServer',
      { '../thaliMobile':
      MockThaliMobile});

  // Mocks ThaliMobile.startUpdateAdvertisingAndListening function
  MockThaliMobile.startUpdateAdvertisingAndListening = function () {
    return Promise.resolve();
  };

  // Mocks ThaliMobile.stopAdvertisingAndListening function
  MockThaliMobile.stopAdvertisingAndListening = function () {
    return Promise.resolve();
  };

  this.TCPEvent = {
    peerIdentifier: 'id123',
    hostAddress: '127.0.0.1',
    portNumber: 0,
    connectionType: ThaliMobile.connectionTypes.TCP_NATIVE,
    suggestedTCPTimeout: 10000
  };
};

GlobalVariables.prototype.initLocal = function () {
  var self = this;
  self.createKeysForLocalTest();
  return new Promise(function (resolve, reject) {
    self.expressApp.use('/', self.expressRouter);
    self.expressServer = self.expressApp.listen(0, function (err) {
      if (err) {
        reject(err);
      } else {
        makeIntoCloseAllServer(self.expressServer);
        self.TCPEvent.portNumber = self.expressServer.address().port;
        resolve();
      }
    });
  });
};

GlobalVariables.prototype.initCoordinated = function () {
  this.expressApp.use('/', this.expressRouter);
};

/**
 * Frees GlobalVariables instance's resources.
 * @returns {Promise<?Error>} Returns a promise that will resolve when the
 * resources are released.
 */
GlobalVariables.prototype.kill = function () {
  if (this.expressServer) {
    return this.expressServer.closeAllPromise();
  }
  return Promise.resolve();
};

GlobalVariables.prototype.createKeysForLocalTest = function () {

  // These keys are for local test
  this.targetPublicKeysToNotify = [];
  this.targetDeviceKeyExchangeObjects = [];

  this.serverKeyExchangeObject = crypto.createECDH(SECP256K1);
  this.serverPublicKey = this.serverKeyExchangeObject.generateKeys();

  var device1 = crypto.createECDH(SECP256K1);
  var device1Key = device1.generateKeys();
  var device2 = crypto.createECDH(SECP256K1);
  var device2Key = device2.generateKeys();

  this.targetPublicKeysToNotify.push(device1Key, device2Key);
  this.targetDeviceKeyExchangeObjects.push(device2, device2);

};

GlobalVariables.prototype.createKeysForCoordinatedTest = function () {
  this.ecdh = crypto.createECDH(SECP256K1);
  this.myKeyExchangeObject = this.ecdh.generateKeys();
  this.myPublicBase64 = this.ecdh.getPublicKey('base64');
};

var test = tape({
  setup: function (t) {
    globals = new GlobalVariables();

    if (tape.coordinated) {
      globals.createKeysForCoordinatedTest();
      t.data = globals.myPublicBase64;
    }
    t.end();
  },

  teardown: function (t) {

    globals.kill().then(function () {
      console.log('killed properly');
      t.end();
    }).catch(function (failure) {
      t.fail('Server cleaning failed:' + failure);
      t.end();
    });
  }
});
/*
test('Client to server request locally', function (t) {

  var p = globals.initLocal();

  p.then(function () {

    var peerPool = new ThaliPeerPoolDefault();

    // Simulates how the peer pool runs actions
    var enqueue = function (action) {
      var keepAliveAgent = new http.Agent({ keepAlive: true });
      action.start(keepAliveAgent).then( function () {
      }).catch( function ( ) {
        t.fail('This action should not fail!');
      });
    };

    sinon.stub(peerPool, 'enqueue', enqueue);

    // Initialize the ThaliNotificationClient
    var notificationClient =
      new ThaliNotificationClient(peerPool,
        globals.targetDeviceKeyExchangeObjects[0]);

    notificationClient.on(ThaliNotificationClient.Events.PeerAdvertisesDataForUs,
      function ( res) {
        t.equals(
          res.hostAddress,
          globals.TCPEvent.hostAddress,
          'Host address must match');
        t.equals(
          res.suggestedTCPTimeout,
          globals.TCPEvent.suggestedTCPTimeout,
          'suggestedTCPTimeout must match');
        t.equals(
          res.connectionType,
          globals.TCPEvent.connectionType,
          'connectionType must match');
        t.equals(
          res.portNumber,
          globals.TCPEvent.portNumber,
          'portNumber must match');

        t.end();
      });

    // Initializes ThaliNotificationServer
    var notificationServer = new globals.ThaliNotificationServerProxyquired(
      globals.expressRouter, globals.serverKeyExchangeObject, 90000);

    notificationServer.start(globals.targetPublicKeysToNotify).
    then(function () {
      notificationClient.start([globals.serverPublicKey]);
      notificationClient._peerAvailabilityChanged(globals.TCPEvent);
    });

  }).catch(function (failure) {
    t.fail('Test setting up failed:' + failure);
    t.end();
  });

});
*/
if (!tape.coordinated) {
  return;
}
var NO_REPLY = 1;
var REPLY = 2;

test('Client to server request coordinated', function (t) {

  globals.initCoordinated();

  var addressBook = [];
  var replies = {};

  if (t.participants) {
    t.participants.forEach(function (participant) {
      if (participant.data !== globals.myPublicBase64) {
        var publicKey = new Buffer(participant.data, 'base64');
        addressBook.push(publicKey);
        var publicKeyHash = NotificationBeacons.createPublicKeyHash(publicKey);
        replies[publicKeyHash] = NO_REPLY;
      }
    });
  }

  if (!t.participants || addressBook.length === 0) {
    t.pass('Can\'t run the test because no participants');
    return t.end();
  }

  console.log('participants:' + addressBook.length);

  var peerPool = new ThaliPeerPoolDefault();

  // Initialize the ThaliNotificationClient
  var notificationClient =
    new ThaliNotificationClient(peerPool,
      globals.ecdh);

  // Initializes ThaliNotificationServer
  var notificationServer = new ThaliNotificationServer(
    globals.expressRouter, globals.ecdh, 90000);

  var finished = false;

  notificationClient.on(ThaliNotificationClient.Events.PeerAdvertisesDataForUs,
    function (res) {
      console.log('reply');
      /*
      replies[res.keyId] = REPLY;
      var allReplied = true;
      Object.keys(replies).forEach(function (key) {
        if (replies[key] === NO_REPLY) {
          allReplied = false;
        }
      });
      if (allReplied && !finished) {
        finished = true;
        ThaliMobile.stopListeningForAdvertisements();
        //  Kills services after 3 seconds gives all peers time to run their tests.
        setTimeout( function () {
          t.pass('We pass to any results at this point ');
          t.end();

          notificationServer.stop();
          notificationClient.stop();
        }, 3000);
      }
      */
    });

  var pThaliMobile = ThaliMobile.start(globals.expressRouter);
  pThaliMobile.then( function () {
    return notificationServer.start(addressBook).then(function () {
      console.log('server started!');
      return;
    });
  }).then( function () {
    notificationClient.start(addressBook);
    return ThaliMobile.startListeningForAdvertisements().then( function ( ) {
      console.log('startListeningForAdvertisements');
    });
  });
});

<|endoftext|>


<commit_before>var assert = require('assert');
var child_process = require('child_process');
var fs = require('fs');
var path = require('path');

var compiler = require('../../src/compiler/compiler');
var parser = require('../../src/parser');
var lexer = require('../../src/lexer');

function globEach(path_, ext, callback, doneCallback) {
    var wildcard = ext === '*';
    if (!doneCallback) {
        doneCallback = function() {};
    }

    var list = fs.readdirSync(path_);
    var pending = list.length;
    if (!pending) return doneCallback(null);
    list.forEach(function(file) {
        file = path_ + '/' + file;
        var stat = fs.statSync(file);
        if (stat && stat.isDirectory()) {
            globEach(file, ext, callback, function(err) {
                if (!--pending) doneCallback(err);
            });
        } else {
            // If it's got the right extension, add it to the list.
            if(wildcard || file.substr(file.length - ext.length) === ext)
                callback(path.normalize(file));
            if (!--pending) doneCallback(null);
        }
    });
};

describe('Parity tests', function() {

    function compile(code, format) {
        var parsed = parser(lexer(code));
        var compiled = compiler({
            filename: 'test',
            tree: parsed,
            format: format,
        });

        return compiled;
    }

    function run(code, format, expectation) {
        var compiled = compile(code, format);

        var mod;
        try {
            mod = (new Function('return ' + compiled))();
        } catch (e) {
            assert.fail('Error during initialization: ' + e.toString());
        }

        var result;
        try {
            result = mod.main();
        } catch (e) {
            console.error(compiled);
            throw e;
        }
        assert.equal(result, expectation);
    }

    var succeededLLI = 0;
    var failedLLI = 0;

    globEach(
        path.resolve(__dirname, 'tests'),
        '.bt',
        function globEachReader(btPath) {
            var read = fs.readFileSync(btPath).toString();
            var readExpectation = fs.readFileSync(btPath + '.txt').toString().trim();

            describe(btPath, function() {

                it('in JS', function jsFunctionalTestBody() {
                    run(read, 'js', readExpectation);
                });

                it('in Asm.js', function asmjsFunctionalTestBody() {
                    run(read, 'asmjs', readExpectation);
                });

                it('in LLVM IR', function llvmirFunctionalTestBody(done) {
                    this.slow(500);

                    var parsed;
                    var compiled;
                    try {
                        parsed = parser(lexer(read));
                        compiled = compiler({
                            filename: 'test',
                            tree: parsed,
                            format: 'llvmir'
                        });
                    } catch (e) {
                        done(e);
                        return;
                    }

                    child_process.exec(
                        path.resolve(process.cwd(), 'bin', 'btype') + ' ' + btPath + ' --target=llvmir | opt -S',
                        function(err, stdout, stderr) {
                            if (err) {
                                done(err);
                            } else if (stderr) {
                                done(new Error(stderr.toString()));
                            } else {
                                runLLI();
                            }
                        }
                    );

                    function runLLI() {
                        var cp = child_process.exec(
                            path.resolve(process.cwd(), 'bin', 'btype') + ' --target=llvmir --runtime --runtime-entry=testmain | opt -S | lli',
                            function(err, stdout, stderr) {
                                if (err) {
                                    failedLLI++;
                                    done(err);
                                } else if (stderr) {
                                    failedLLI++;
                                    done(stderr);
                                } else {
                                    succeededLLI++;
                                    assert.ok(JSON.parse(stdout) == JSON.parse(readExpectation), stdout + ' != ' + readExpectation);
                                    done();
                                }
                            }
                        );

                        var parsed = parser(lexer(read));
                        var env = compiler.buildEnv({filename: 'test', tree: parsed});
                        var mainFunc = env.requested.exports.main;
                        var mainFuncDef = env.requested.functionDeclarations[mainFunc];

                        var raw = 'import debug;\n';
                        raw += read + '\n';
                        switch (mainFuncDef.getType(env.requested).getReturnType().typeName) {
                            case 'int':
                                raw += 'func testmain() {\n    debug.printint(main());\n}\nexport testmain;';
                                break;
                            case 'float':
                                raw += 'func testmain() {\n    debug.printfloat(main());\n}\nexport testmain;';
                                break;
                            case 'bool':
                                raw += 'func testmain() {\n    debug.printbool(main());\n}\nexport testmain;';
                                break;
                        }

                        cp.stdin.write(raw);
                        cp.stdin.end();

                    }

                });

            });

        }

    );

});

describe('Compile tests', function() {

    globEach(
        path.resolve(__dirname, 'compiletests'),
        '.bt',
        function(btPath) {
            var read = fs.readFileSync(btPath).toString();

            describe(btPath, function() {
                it('compiles to JS', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'js'
                    });
                    assert.ok(compiled);
                });
                it('compiles to Asm.js', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'asmjs'
                    });
                    assert.ok(compiled);
                });
                it('compiles to LLVM IR', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'llvmir'
                    });
                    assert.ok(compiled);
                });

            });
        }
    );

});

describe('Failure tests', function() {

    globEach(
        path.resolve(__dirname, 'failtests'),
        '.bt',
        function(btPath) {
            var read = fs.readFileSync(btPath).toString();

            var expectedExceptionPath = path.dirname(btPath);
            expectedExceptionPath += path.sep;
            expectedExceptionPath += path.basename(btPath, '.bt') + '.txt';

            it(btPath, function failTestBody() {
                assert.throws(
                    function() {
                        compiler({
                            filename: 'test',
                            tree: parser(lexer(read)),
                            format: 'debug-tree',
                        });
                    },
                    function(err) {
                        if (fs.existsSync(expectedExceptionPath)) {
                            var exceptionText = fs.readFileSync(expectedExceptionPath).toString();
                            return exceptionText === err.toString();
                        } else {
                            fs.writeFileSync(expectedExceptionPath, err.toString());
                            return true;
                        }
                    }
                );

            });

        }
    );

});

describe('String tests', function() {

    function run(code, format, expectation) {
        var parsed = parser(lexer(code));
        var compiled = compiler({
            filename: 'test',
            tree: parsed,
            format: format
        });

        var mod;
        try {
            mod = (new Function('return ' + compiled))();
        } catch (e) {
            assert.fail('Error during initialization: ' + e.toString());
        }

        var result;
        try {
            result = mod.main();
        } catch (e) {
            console.error(compiled);
            throw e;
        }

        var converted = mod.$strings.read(result);
        assert.equal(converted, expectation);
    }

    globEach(
        path.resolve(__dirname, 'strings'),
        '.bt',
        function(btPath) {
            var read = fs.readFileSync(btPath).toString();
            var readExpectation = fs.readFileSync(btPath + '.txt').toString().trim();

            describe(btPath, function() {

                it('in JS', function jsStringTestBody() {
                    run(read, 'js', readExpectation);
                });

                it('in Asm.js', function asmjsStringTestBody() {
                    run(read, 'asmjs', readExpectation);
                });

            });

        }
    );

});
<commit_msg>Exercise debug-tree during functional tests<commit_after>var assert = require('assert');
var child_process = require('child_process');
var fs = require('fs');
var path = require('path');

var compiler = require('../../src/compiler/compiler');
var parser = require('../../src/parser');
var lexer = require('../../src/lexer');

function globEach(path_, ext, callback, doneCallback) {
    var wildcard = ext === '*';
    if (!doneCallback) {
        doneCallback = function() {};
    }

    var list = fs.readdirSync(path_);
    var pending = list.length;
    if (!pending) return doneCallback(null);
    list.forEach(function(file) {
        file = path_ + '/' + file;
        var stat = fs.statSync(file);
        if (stat && stat.isDirectory()) {
            globEach(file, ext, callback, function(err) {
                if (!--pending) doneCallback(err);
            });
        } else {
            // If it's got the right extension, add it to the list.
            if(wildcard || file.substr(file.length - ext.length) === ext)
                callback(path.normalize(file));
            if (!--pending) doneCallback(null);
        }
    });
}

function compile(code, format) {
    var parsed = parser(lexer(code));
    var compiled = compiler({
        filename: 'test',
        tree: parsed,
        format: format,
    });

    return compiled;
}

describe('Parity tests', function() {

    function run(code, format, expectation) {
        var compiled = compile(code, format);

        var mod;
        try {
            mod = (new Function('return ' + compiled))();
        } catch (e) {
            assert.fail('Error during initialization: ' + e.toString());
        }

        var result;
        try {
            result = mod.main();
        } catch (e) {
            console.error(compiled);
            throw e;
        }
        assert.equal(result, expectation);
    }

    var succeededLLI = 0;
    var failedLLI = 0;

    globEach(
        path.resolve(__dirname, 'tests'),
        '.bt',
        function globEachReader(btPath) {
            var read = fs.readFileSync(btPath).toString();
            var readExpectation = fs.readFileSync(btPath + '.txt').toString().trim();

            describe(btPath, function() {

                it('formats with debug-tree', function jsFunctionalTestBody() {
                    var output = compile(read, 'debug-tree');
                    assert.ok(output);
                });

                it('in JS', function jsFunctionalTestBody() {
                    run(read, 'js', readExpectation);
                });

                it('in Asm.js', function asmjsFunctionalTestBody() {
                    run(read, 'asmjs', readExpectation);
                });

                it('in LLVM IR', function llvmirFunctionalTestBody(done) {
                    this.slow(500);

                    var parsed;
                    var compiled;
                    try {
                        parsed = parser(lexer(read));
                        compiled = compiler({
                            filename: 'test',
                            tree: parsed,
                            format: 'llvmir'
                        });
                    } catch (e) {
                        done(e);
                        return;
                    }

                    child_process.exec(
                        path.resolve(process.cwd(), 'bin', 'btype') + ' ' + btPath + ' --target=llvmir | opt -S',
                        function(err, stdout, stderr) {
                            if (err) {
                                done(err);
                            } else if (stderr) {
                                done(new Error(stderr.toString()));
                            } else {
                                runLLI();
                            }
                        }
                    );

                    function runLLI() {
                        var cp = child_process.exec(
                            path.resolve(process.cwd(), 'bin', 'btype') + ' --target=llvmir --runtime --runtime-entry=testmain | opt -S | lli',
                            function(err, stdout, stderr) {
                                if (err) {
                                    failedLLI++;
                                    done(err);
                                } else if (stderr) {
                                    failedLLI++;
                                    done(stderr);
                                } else {
                                    succeededLLI++;
                                    assert.ok(JSON.parse(stdout) == JSON.parse(readExpectation), stdout + ' != ' + readExpectation);
                                    done();
                                }
                            }
                        );

                        var parsed = parser(lexer(read));
                        var env = compiler.buildEnv({filename: 'test', tree: parsed});
                        var mainFunc = env.requested.exports.main;
                        var mainFuncDef = env.requested.functionDeclarations[mainFunc];

                        var raw = 'import debug;\n';
                        raw += read + '\n';
                        switch (mainFuncDef.getType(env.requested).getReturnType().typeName) {
                            case 'int':
                                raw += 'func testmain() {\n    debug.printint(main());\n}\nexport testmain;';
                                break;
                            case 'float':
                                raw += 'func testmain() {\n    debug.printfloat(main());\n}\nexport testmain;';
                                break;
                            case 'bool':
                                raw += 'func testmain() {\n    debug.printbool(main());\n}\nexport testmain;';
                                break;
                        }

                        cp.stdin.write(raw);
                        cp.stdin.end();

                    }

                });

            });

        }

    );

});

describe('Compile tests', function() {

    globEach(
        path.resolve(__dirname, 'compiletests'),
        '.bt',
        function(btPath) {
            var read = fs.readFileSync(btPath).toString();

            describe(btPath, function() {
                it('compiles to JS', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'js'
                    });
                    assert.ok(compiled);
                });
                it('compiles to Asm.js', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'asmjs'
                    });
                    assert.ok(compiled);
                });
                it('compiles to LLVM IR', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'llvmir'
                    });
                    assert.ok(compiled);
                });
                it('formats with debug-tree', function compileTestBody() {
                    var parsed = parser(lexer(read));
                    var compiled = compiler({
                        filename: 'test',
                        tree: parsed,
                        format: 'debug-tree'
                    });
                    assert.ok(compiled);
                });

            });
        }
    );

});

describe('Failure tests', function() {

    globEach(
        path.resolve(__dirname, 'failtests'),
        '.bt',
        function(btPath) {
            var read = fs.readFileSync(btPath).toString();

            var expectedExceptionPath = path.dirname(btPath);
            expectedExceptionPath += path.sep;
            expectedExceptionPath += path.basename(btPath, '.bt') + '.txt';

            it(btPath, function failTestBody() {
                assert.throws(
                    function() {
                        compiler({
                            filename: 'test',
                            tree: parser(lexer(read)),
                            format: 'debug-tree',
                        });
                    },
                    function(err) {
                        if (fs.existsSync(expectedExceptionPath)) {
                            var exceptionText = fs.readFileSync(expectedExceptionPath).toString();
                            return exceptionText === err.toString();
                        } else {
                            fs.writeFileSync(expectedExceptionPath, err.toString());
                            return true;
                        }
                    }
                );

            });

        }
    );

});

describe('String tests', function() {

    function run(code, format, expectation) {
        var compiled = compile(code, format);

        var mod;
        try {
            mod = (new Function('return ' + compiled))();
        } catch (e) {
            assert.fail('Error during initialization: ' + e.toString());
        }

        var result;
        try {
            result = mod.main();
        } catch (e) {
            console.error(compiled);
            throw e;
        }

        var converted = mod.$strings.read(result);
        assert.equal(converted, expectation);
    }

    globEach(
        path.resolve(__dirname, 'strings'),
        '.bt',
        function(btPath) {
            var read = fs.readFileSync(btPath).toString();
            var readExpectation = fs.readFileSync(btPath + '.txt').toString().trim();

            describe(btPath, function() {

                it('runs in JS', function jsStringTestBody() {
                    run(read, 'js', readExpectation);
                });

                it('runs in Asm.js', function asmjsStringTestBody() {
                    run(read, 'asmjs', readExpectation);
                });

                it('formats in debug-tree', function debugTreeStringTestBody() {
                    assert.ok(compile(read, 'debug-tree'));
                });

            });

        }
    );

});
<|endoftext|>