<commit_before>var should = require('should'),
    sinon = require('sinon'),
    moment = require('moment'),
    dino = require('../');

describe('schema', function(){

    var now = moment.utc(),
        schema,
        replySchema;

    beforeEach(function(){
        dino.connect();
        schema = dino.schema({
            table: 'forums',
            attributes: {
                name: dino.types.string,
                misc: dino.types.object,
                timestamp: dino.types.string
            },
            key: {
                hash: 'name',
                range: 'timestamp'
            }
        });
        replySchema = dino.schema({
            table: 'replies',
            attributes: {
                forum_name: dino.types.string,
                subject: dino.types.string,
                date_created: dino.types.date,
                id: dino.types.id
            },
            key: {
                hash: ['forum_name', 'subject'],
                range: ['date_created', 'id']
            }
        });
    });

    describe('constructor', function(){

        it('should set the defaults', function(){
            schema.should.have.property('table', 'forums');
            schema.should.have.property('attributes');
            schema.should.have.property('hashKeyAttributes');
            schema.hashKeyAttributes.should.eql(['name']);
            schema.should.have.property('hashKey', 'name');
            schema.should.have.property('rangeKey', 'timestamp');
            schema.should.have.property('keyDelimiter', '#');
        });

        it('should add the attributes', function(){
            dino.types.string.isPrototypeOf(schema.attributes.name).should.be.true;
            dino.types.object.isPrototypeOf(schema.attributes.misc).should.be.true;
        });

    });

    describe('createTable', function(){

        describe('arguments', function(){

            var stub,
                calledParams;

            beforeEach(function(){
                stub = sinon.stub(dino.connection.client, 'createTable', function(params, callback){
                    calledParams = params;
                    callback(null);
                });
            });

            afterEach(function(){
                dino.connection.client.createTable.restore();
            });

            it('should create a table with no arguments', function(){
                schema.createTable();
                stub.calledWith({
                    TableName: 'forums',
                    ProvisionedThroughput: {
                        ReadCapacityUnits: 1,
                        WriteCapacityUnits: 1
                    },
                    AttributeDefinitions: [
                        { AttributeName: 'name', AttributeType: 'S' },
                        { AttributeName: 'timestamp', AttributeType: 'N' }
                    ],
                    KeySchema: [
                        { AttributeName: 'name', KeyType: 'HASH' },
                        { AttributeName: 'timestamp', KeyType: 'RANGE' }
                    ]
                }).should.be.true;
            });

            it('should create a table with specified read/write throughput', function(done){
                schema.createTable({
                    readUnits: 2,
                    writeUnits: 3
                }, function(){
                    calledParams.ProvisionedThroughput.should.eql({
                        ReadCapacityUnits: 2,
                        WriteCapacityUnits: 3
                    });
                    done();
                });
            });

        });

        describe('callback', function(){

            var cannedErr = new Error('Just a normal error');

            afterEach(function(){
                dino.connection.client.createTable.restore();
            });

            it('should callback errors', function(){
                var stub = sinon.stub(dino.connection.client, 'createTable', function(params, callback){
                        callback(cannedErr);
                    }),
                    spy = sinon.spy();
                schema.createTable(spy);
                spy.calledWithExactly(cannedErr).should.be.true;
            });

        });

    });

    describe('add', function(){

        it('should add an attribute', function(){

            schema.add('newAttr', dino.types.boolean);
            dino.types.boolean.isPrototypeOf(schema.get('newAttr')).should.be.true;
        });

    });

    describe('get', function(){

        it('should get an attribute', function(){
            dino.types.string.isPrototypeOf(schema.get('name')).should.be.true;
            dino.types.object.isPrototypeOf(schema.get('misc')).should.be.true;
        });

    });

    describe('serializeHashAttribute', function(){

        it('should serialize the hash attribute', function(){
            schema.serializeHashAttribute('a').should.eql({ S: 'a' });
            replySchema.serializeHashAttribute(['a', 'b']).should.eql({ S: 'a#b' });
        });

    });

    describe('serializeRangeAttribute', function(){

        it('should serialize the range attribute', function(){
            var m = moment.utc(),
                id = '12345';
            replySchema.serializeRangeAttribute([m, id]).should.eql({ S: m.format() + '#' + id });
        });

    });

    describe('deserializeHashAttribute', function(){

        it('should deserialize the hash attribute', function(){
            var obj = schema.deserializeHashAttribute({ S: 'sometablename' });
            obj.name.should.equal('sometablename');
        });

        it('should deserialize combined hash attributes', function(){
            var obj = replySchema.deserializeHashAttribute({ S: 'what#ever' });
            obj.forum_name.should.equal('what');
            obj.subject.should.equal('ever');
        });

    });

    describe('deserializeRangeAttribute', function(){

        it('should deserialize the range attribute', function(){
            var obj = replySchema.deserializeRangeAttribute({ S: '2013-03-27T19:21:54+00:00#12345' });
            obj.id.should.equal('12345');
            moment.isMoment(obj.date_created).should.be.true;
            obj.date_created.format().should.equal('2013-03-27T19:21:54+00:00');
        });

    });

    describe('generateQueryParams', function(){

        it('should throw if undefined attributes', function(){
            (function(){
                schema.generateQueryParams();
            }).should.throw();
            (function(){
                schema.generateQueryParams({
                    asdf: 'asdf'
                });
            }).should.throw();
        });

        it('should generate params for a single hash attribute', function(){
            schema = dino.schema({
                table: 'forums',
                attributes: {
                    name: dino.types.string
                },
                key: {
                    hash: 'name'
                }
            });
            schema.generateQueryParams({
                name: 'Chris'
            }).should.eql({
                TableName: 'forums',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    name: {
                        AttributeValueList: [
                            { S: 'Chris' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for multiple hash attributes', function(){
            schema = dino.schema({
                table: 'forums',
                attributes: {
                    table_name: dino.types.string,
                    thread_name: dino.types.string
                },
                key: {
                    hash: ['table_name', 'thread_name']
                }
            });
            (function(){
                schema.generateQueryParams({
                    table_name: 'Table 1'
                });
            }).should.throw();
            schema.generateQueryParams({
                table_name: 'Table 1',
                thread_name: 'Thread 1'
            }).should.eql({
                TableName: 'forums',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    'table_name#thread_name': {
                        AttributeValueList: [
                            { S: 'Table 1#Thread 1' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for a single hash and a single range attribute', function(){
            schema = dino.schema({
                table: 'posts',
                attributes: {
                    user_id: dino.types.string,
                    date_created: dino.types.date
                },
                key: {
                    hash: 'user_id',
                    range: 'date_created'
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff'
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff',
                date_created: moment(now)
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    date_created: {
                        AttributeValueList: [
                            { S: now.format() }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for a single hash and multiple range attributes', function(){
            schema = dino.schema({
                table: 'posts',
                attributes: {
                    user_id: dino.types.string,
                    date_created: dino.types.date,
                    id: dino.types.id
                },
                key: {
                    hash: 'user_id',
                    range: ['date_created', 'id']
                }
            });
            (function(){
                schema.generateQueryParams({
                    user_id: 'ctcliff',
                    date_created: moment(now)
                });
            }).should.throw();
            schema.generateQueryParams({
                user_id: 'ctcliff',
                date_created: moment(now),
                id: '123'
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    'date_created#id': {
                        AttributeValueList: [
                            { S: now.format() + '#123' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for hash and secondary attributes', function(){
            schema = dino.schema({
                table: 'posts',
                attributes: {
                    user_id: dino.types.string,
                    date_created: dino.types.date,
                    id: dino.types.id
                },
                key: {
                    hash: 'user_id',
                    range: 'date_created',
                    secondary: 'id'
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff',
                date_created: moment(now)
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    date_created: {
                        AttributeValueList: [
                            { S: now.format() }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff',
                id: '123'
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    id: {
                        AttributeValueList: [
                            { S: '123' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                },
                IndexName: 'posts.id',
                ScanIndexForward: false,
                Select: 'ALL_ATTRIBUTES'
            });
        });

    });

});<commit_msg>Added failing hash/range key type tests.<commit_after>var should = require('should'),
    sinon = require('sinon'),
    moment = require('moment'),
    dino = require('../');

describe('schema', function(){

    var now = moment.utc(),
        schema,
        replySchema;

    beforeEach(function(){
        dino.connect();
        schema = dino.schema({
            table: 'forums',
            attributes: {
                name: dino.types.string,
                misc: dino.types.object
            },
            key: {
                hash: 'name'
            }
        });
        replySchema = dino.schema({
            table: 'replies',
            attributes: {
                forum_name: dino.types.string,
                subject: dino.types.string,
                date_created: dino.types.date,
                id: dino.types.id
            },
            key: {
                hash: ['forum_name', 'subject'],
                range: ['date_created', 'id']
            }
        });
    });

    describe('constructor', function(){

        it('should set the defaults', function(){
            schema.should.have.property('table', 'forums');
            schema.should.have.property('attributes');
            schema.should.have.property('hashKeyAttributes');
            schema.hashKeyAttributes.should.eql(['name']);
            schema.should.have.property('hashKey', 'name');
            schema.should.have.property('rangeKey', null);
            schema.should.have.property('keyDelimiter', '#');
        });

        it('should add the attributes', function(){
            dino.types.string.isPrototypeOf(schema.attributes.name).should.be.true;
            dino.types.object.isPrototypeOf(schema.attributes.misc).should.be.true;
        });

    });

    describe('createTable', function(){

        describe('arguments', function(){

            var stub,
                calledParams;

            beforeEach(function(){
                stub = sinon.stub(dino.connection.client, 'createTable', function(params, callback){
                    calledParams = params;
                    callback(null);
                });
            });

            afterEach(function(){
                dino.connection.client.createTable.restore();
            });

            it('should create a table with no arguments', function(){
                schema.createTable();
                stub.calledWith({
                    TableName: 'forums',
                    ProvisionedThroughput: {
                        ReadCapacityUnits: 1,
                        WriteCapacityUnits: 1
                    },
                    AttributeDefinitions: [
                        { AttributeName: 'name', AttributeType: 'S' }
                    ],
                    KeySchema: [
                        { AttributeName: 'name', KeyType: 'HASH' }
                    ]
                }).should.be.true;
            });

            it('should create a table with numeric hash key', function(done){
                schema = dino.schema({
                    table: 'forums',
                    attributes: {
                        numeric_id: dino.types.number
                    },
                    key: {
                        hash: 'numeric_id'
                    }
                });
                schema.createTable(function(){
                    calledParams.AttributeDefinitions.should.eql([
                        { AttributeName: 'numeric_id', AttributeType: 'N' }
                    ]);
                    calledParams.KeySchema.should.eql([
                        { AttributeName: 'numeric_id', KeyType: 'HASH' }
                    ]);
                    done();
                });
            });

            it('should create a table with string hash key', function(done){
                schema = dino.schema({
                    table: 'forums',
                    attributes: {
                        id: dino.types.id
                    },
                    key: {
                        hash: 'id'
                    }
                });
                schema.createTable(function(){
                    calledParams.AttributeDefinitions.should.eql([
                        { AttributeName: 'id', AttributeType: 'S' }
                    ]);
                    calledParams.KeySchema.should.eql([
                        { AttributeName: 'id', KeyType: 'HASH' }
                    ]);
                    done();
                });
            });

            it('should create a table with numeric range key', function(done){
                schema = dino.schema({
                    table: 'forums',
                    attributes: {
                        id: dino.types.id,
                        post_count: dino.types.number
                    },
                    key: {
                        hash: 'id',
                        range: 'post_count'
                    }
                });
                schema.createTable(function(){
                    calledParams.AttributeDefinitions.should.eql([
                        { AttributeName: 'id', AttributeType: 'S' },
                        { AttributeName: 'post_count', AttributeType: 'N' }
                    ]);
                    calledParams.KeySchema.should.eql([
                        { AttributeName: 'id', KeyType: 'HASH' },
                        { AttributeName: 'post_count', KeyType: 'RANGE' }
                    ]);
                    done();
                });
            });

            it('should create a table with string range key', function(done){
                schema = dino.schema({
                    table: 'forums',
                    attributes: {
                        id: dino.types.id,
                        created_by: dino.types.string
                    },
                    key: {
                        hash: 'id',
                        range: 'created_by'
                    }
                });
                schema.createTable(function(){
                    calledParams.AttributeDefinitions.should.eql([
                        { AttributeName: 'id', AttributeType: 'S' },
                        { AttributeName: 'created_by', AttributeType: 'S' }
                    ]);
                    calledParams.KeySchema.should.eql([
                        { AttributeName: 'id', KeyType: 'HASH' },
                        { AttributeName: 'created_by', KeyType: 'RANGE' }
                    ]);
                    done();
                });
            });

            it('should create a table with specified read/write throughput', function(done){
                schema.createTable({
                    readUnits: 2,
                    writeUnits: 3
                }, function(){
                    calledParams.ProvisionedThroughput.should.eql({
                        ReadCapacityUnits: 2,
                        WriteCapacityUnits: 3
                    });
                    done();
                });
            });

        });

        describe('callback', function(){

            var cannedErr = new Error('Just a normal error');

            afterEach(function(){
                dino.connection.client.createTable.restore();
            });

            it('should callback errors', function(){
                var stub = sinon.stub(dino.connection.client, 'createTable', function(params, callback){
                        callback(cannedErr);
                    }),
                    spy = sinon.spy();
                schema.createTable(spy);
                spy.calledWithExactly(cannedErr).should.be.true;
            });

        });

    });

    describe('add', function(){

        it('should add an attribute', function(){

            schema.add('newAttr', dino.types.boolean);
            dino.types.boolean.isPrototypeOf(schema.get('newAttr')).should.be.true;
        });

    });

    describe('get', function(){

        it('should get an attribute', function(){
            dino.types.string.isPrototypeOf(schema.get('name')).should.be.true;
            dino.types.object.isPrototypeOf(schema.get('misc')).should.be.true;
        });

    });

    describe('serializeHashAttribute', function(){

        it('should serialize the hash attribute', function(){
            schema.serializeHashAttribute('a').should.eql({ S: 'a' });
            replySchema.serializeHashAttribute(['a', 'b']).should.eql({ S: 'a#b' });
        });

    });

    describe('serializeRangeAttribute', function(){

        it('should serialize the range attribute', function(){
            var m = moment.utc(),
                id = '12345';
            replySchema.serializeRangeAttribute([m, id]).should.eql({ S: m.format() + '#' + id });
        });

    });

    describe('deserializeHashAttribute', function(){

        it('should deserialize the hash attribute', function(){
            var obj = schema.deserializeHashAttribute({ S: 'sometablename' });
            obj.name.should.equal('sometablename');
        });

        it('should deserialize combined hash attributes', function(){
            var obj = replySchema.deserializeHashAttribute({ S: 'what#ever' });
            obj.forum_name.should.equal('what');
            obj.subject.should.equal('ever');
        });

    });

    describe('deserializeRangeAttribute', function(){

        it('should deserialize the range attribute', function(){
            var obj = replySchema.deserializeRangeAttribute({ S: '2013-03-27T19:21:54+00:00#12345' });
            obj.id.should.equal('12345');
            moment.isMoment(obj.date_created).should.be.true;
            obj.date_created.format().should.equal('2013-03-27T19:21:54+00:00');
        });

    });

    describe('generateQueryParams', function(){

        it('should throw if undefined attributes', function(){
            (function(){
                schema.generateQueryParams();
            }).should.throw();
            (function(){
                schema.generateQueryParams({
                    asdf: 'asdf'
                });
            }).should.throw();
        });

        it('should generate params for a single hash attribute', function(){
            schema = dino.schema({
                table: 'forums',
                attributes: {
                    name: dino.types.string
                },
                key: {
                    hash: 'name'
                }
            });
            schema.generateQueryParams({
                name: 'Chris'
            }).should.eql({
                TableName: 'forums',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    name: {
                        AttributeValueList: [
                            { S: 'Chris' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for multiple hash attributes', function(){
            schema = dino.schema({
                table: 'forums',
                attributes: {
                    table_name: dino.types.string,
                    thread_name: dino.types.string
                },
                key: {
                    hash: ['table_name', 'thread_name']
                }
            });
            (function(){
                schema.generateQueryParams({
                    table_name: 'Table 1'
                });
            }).should.throw();
            schema.generateQueryParams({
                table_name: 'Table 1',
                thread_name: 'Thread 1'
            }).should.eql({
                TableName: 'forums',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    'table_name#thread_name': {
                        AttributeValueList: [
                            { S: 'Table 1#Thread 1' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for a single hash and a single range attribute', function(){
            schema = dino.schema({
                table: 'posts',
                attributes: {
                    user_id: dino.types.string,
                    date_created: dino.types.date
                },
                key: {
                    hash: 'user_id',
                    range: 'date_created'
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff'
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff',
                date_created: moment(now)
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    date_created: {
                        AttributeValueList: [
                            { S: now.format() }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for a single hash and multiple range attributes', function(){
            schema = dino.schema({
                table: 'posts',
                attributes: {
                    user_id: dino.types.string,
                    date_created: dino.types.date,
                    id: dino.types.id
                },
                key: {
                    hash: 'user_id',
                    range: ['date_created', 'id']
                }
            });
            (function(){
                schema.generateQueryParams({
                    user_id: 'ctcliff',
                    date_created: moment(now)
                });
            }).should.throw();
            schema.generateQueryParams({
                user_id: 'ctcliff',
                date_created: moment(now),
                id: '123'
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    'date_created#id': {
                        AttributeValueList: [
                            { S: now.format() + '#123' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
        });

        it('should generate params for hash and secondary attributes', function(){
            schema = dino.schema({
                table: 'posts',
                attributes: {
                    user_id: dino.types.string,
                    date_created: dino.types.date,
                    id: dino.types.id
                },
                key: {
                    hash: 'user_id',
                    range: 'date_created',
                    secondary: 'id'
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff',
                date_created: moment(now)
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                ScanIndexForward: false,
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    date_created: {
                        AttributeValueList: [
                            { S: now.format() }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                }
            });
            schema.generateQueryParams({
                user_id: 'ctcliff',
                id: '123'
            }).should.eql({
                TableName: 'posts',
                ReturnConsumedCapacity: 'TOTAL',
                KeyConditions: {
                    user_id: {
                        AttributeValueList: [
                            { S: 'ctcliff' }
                        ],
                        ComparisonOperator: 'EQ'
                    },
                    id: {
                        AttributeValueList: [
                            { S: '123' }
                        ],
                        ComparisonOperator: 'EQ'
                    }
                },
                IndexName: 'posts.id',
                ScanIndexForward: false,
                Select: 'ALL_ATTRIBUTES'
            });
        });

    });

});<|endoftext|>


<commit_before>/*
Copyright (c) 2014 Andrew Rea
Copyright (c) 2014 James Allen

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
 */

'use strict';

var _ = require('lodash');
var assert = require('assert');
var utils = require('./utils');
var events = require('events');
var PREFIX = 'deride';

var Expectations = function(obj, method) {
	var timesCalled = 0;
	var calledWithArgs = {};

	function checkArg(expected, values) {
		return _.any(_.where(values, expected));
	}

	function checkArgs(expectedArgs, callArgs, evaluator) {
		var values = _.values(callArgs);
		var argResults = [];
		for (var argIndex = 0; argIndex < expectedArgs.length; argIndex++) {
			var expected = expectedArgs[argIndex];
			var foundArg = checkArg(expected, values);
			argResults.push(foundArg);
		}
		return evaluator(argResults);
	}

	function checkAnyArgs(expectedArgs, callArgs) {
		return checkArgs(expectedArgs, callArgs, _.any);
	}

	function withArgs() {
		var args = _.values(arguments);
		assertArgsWithEvaluator(calledWithArgs, args, _.all);
		return self.called;
	}

	function withSingleArg(arg) {
		var args = [arg];
		assertArgsWithEvaluator(calledWithArgs, args, _.any);
		return self.called;
	}

	function assertArgsWithEvaluator(argsToCheck, args, evaluator) {
		var callResults = [];
		_.forEach(argsToCheck, function(value) {
			var argResult = checkArgs(args, value, evaluator);
			callResults.push(argResult);
		});
		var result = _.any(callResults);
		assert(result, 'Expected ' + method + ' to be called with: ' + args.join(', '));
	}

	function withArg(args) {
		return function(arg) {
			assert(checkAnyArgs([arg], args));
		};
	}

	function invocation(index) {
		if (!(index.toString() in calledWithArgs)) {
			throw new Error('invocation out of range');
		}
		var arg = calledWithArgs[index.toString()];
		return {
			withArg: withArg(arg)
		};
	}

	function times(number, err) {
		if (!err) {
			err = 'Expected ' + method + ' to be called ' + utils.humanise(number) + ' but was ' + timesCalled;
		}
		assert.equal(timesCalled, number, err);
	}

	function never(err) {
		times(0, err);
	}

	function calledOnce(err) {
		times(1, err);
	}

	function calledTwice(err) {
		times(2, err);
	}

	function reset() {
		timesCalled = 0;
		calledWithArgs = {};
	}

	function call() {
		calledWithArgs[timesCalled++] = arguments;
	}

	function negate(func) {
		return function() {
			var args = _.values(arguments);
			try {
				func.call(null, args);
			} catch (err) {
				return self;
			}
			assert(false);
		};
	}

	function addNotMethods(obj) {
		var methods = {};
		var calledMethods = _.omit(utils.methods(obj.called), 'reset');
		_.each(calledMethods, function(method) {
			methods[method] = negate(obj.called[method]);
		});
		obj.called.not = methods;
		return obj;
	}

	var self = {
		called: {
			times: times,
			never: never,
			once: calledOnce,
			twice: calledTwice,
			reset: reset,
			withArgs: withArgs,
			withArg: withSingleArg
		},
		invocation: invocation,
		call: call
	};

	return (function() {
		return Object.freeze(addNotMethods(self));
	}());
};

var Setup = function(obj, method, emitter) {
	var debug = require('debug')(PREFIX);
	var Promises = require('when');
	var originalMethod = obj[method];
	var callToInvoke = normalCall;
	var callToInvokeOnArguments = {};
	var argumentsPredicate;

	function call() {
		var key = serializeArgs(arguments);
		var callBasedOnArgs = callToInvokeOnArguments[key];
		if (callBasedOnArgs !== null && callBasedOnArgs !== undefined) {
			return callBasedOnArgs.apply(self, arguments);
		} else {
			return callToInvoke.apply(self, arguments);
		}
	}

	function toCallbackWith(args) {
		var func = function() {
			debug('toCallbackWith', args);
			for (var i = 0; i < arguments.length; i++) {
				var argType = typeof(arguments[i]);
				if (argType === 'function') {
					arguments[i].apply(null, args);
				}
			}
		};
		checkArgumentsToInvoke(func);
	}

	function toDoThis(func) {
		var wrapper = function() {
			debug('toDoThis override');
			var result = func.apply(obj, arguments);
			return result;
		};
		checkArgumentsToInvoke(wrapper);
	}

	function toEmit() {
		var args = Array.prototype.slice.call(arguments);
		var func = function() {
			emitter.emit.apply(emitter, args);
			return originalMethod.apply(obj, arguments);
		};
		checkArgumentsToInvoke(func);
	}

	function toRejectWith(arg) {
		var func = function() {
			debug('toRejectWith');
			return Promises.reject(arg);
		};
		checkArgumentsToInvoke(func);
	}

	function toResolveWith(arg) {
		var func = function() {
			debug('toResolveWith');
			return Promises.resolve(arg);
		};
		checkArgumentsToInvoke(func);
	}

	function toReturn(value) {
		var overrideReturnValue = function() {
			debug('toReturn', value);
			return value;
		};
		checkArgumentsToInvoke(overrideReturnValue);
	}

	function toThrow(message) {
		var func = function() {
			debug('toThrow', message);
			throw new Error(message);
		};
		checkArgumentsToInvoke(func);
	}

	function toTimeWarp(milliseconds) {
		var func = function() {
			debug('toTimeWarp', milliseconds);
			var originalTimeoutFunc = setTimeout;
			setTimeout = function(delegate, timeout) {
				originalTimeoutFunc(delegate, timeout - milliseconds);
			};
			var result = originalMethod.apply(obj, arguments);
			return result;
		};
		checkArgumentsToInvoke(func);
	}

	function when() {
		argumentsPredicate = arguments;
		return Object.freeze(self);
	}

	function checkArgumentsToInvoke(func) {
		if (argumentsPredicate !== null && argumentsPredicate !== undefined) {
			var key = serializeArgs(argumentsPredicate);
			callToInvokeOnArguments[key] = func;
		} else {
			callToInvoke = func;
		}
		argumentsPredicate = null;
	}

	function normalCall() {
		debug('normal call', method);
		var result = originalMethod.apply(obj, arguments);
		return result;
	}

	function serializeArgs(args) {
		return JSON.stringify(args);
	}

	var self = {
		toDoThis: toDoThis,
		toReturn: toReturn,
		toThrow: toThrow,
		toCallbackWith: toCallbackWith,
		toResolveWith: toResolveWith,
		toRejectWith: toRejectWith,
		toTimeWarp: toTimeWarp,
		toEmit: toEmit,
		when: when,
		call: call
	};

	return (function() {
		return Object.freeze(self);
	}());
};

function wrap(obj) {
	var debug = require('debug')(PREFIX + ':wrap');
	var objMethods = utils.methods(obj);
	var self = {};
	var expectMethods = {};
	var setupMethods = {};
	var eventEmitter = new events.EventEmitter();
	utils.proxyFunctions(self, eventEmitter, ['on', 'once', 'emit']);

	function setupForMethod(method) {
		debug(method);
		return function() {
			expectMethods[method].call.apply(obj, arguments);
			return setupMethods[method].call.apply(obj, arguments);
		};
	}

	for (var i = 0; i < objMethods.length; i++) {
		var method = objMethods[i];
		expectMethods[method] = new Expectations(obj, method);
		setupMethods[method] = new Setup(obj, method, eventEmitter);
		self[method] = setupForMethod(method);
	}

	self.expect = expectMethods;
	self.called = {
		reset: function() {
			_.each(expectMethods, function(method) {
				method.called.reset();
			});
		}
	};
	self.setup = setupMethods;
	return Object.freeze(_.merge({}, obj, self));
}

function func() {
	var debug = require('debug')(PREFIX + ':func');
	var objHarness = {
		value: function() {}
	};
	var wrapped = wrap(objHarness);

	function createFunc() {
		debug('harness');
		var returnVal = wrapped.value.apply(objHarness, arguments);
		return returnVal;
	}
	createFunc.expect = wrapped.expect.value;
	createFunc.setup = wrapped.setup.value;

	return Object.freeze(createFunc);
}

function stub(target) {
	var debug = require('debug')(PREFIX + ':stub');
	debug(target);
	var methods = [];
	if (_.isArray(target)) {
		methods = target;
	} else {
		methods = utils.methods(target);
	}

	var stubObj = {};
	var emptyMethod = function() {
		return function() {};
	};
	for (var i = 0; i < methods.length; i++) {
		stubObj[methods[i]] = emptyMethod();
	}
	return wrap(stubObj);
}

module.exports = {
	wrap: wrap,
	stub: stub,
	func: func
};
<commit_msg>Add setup and method to debug prefix<commit_after>/*
Copyright (c) 2014 Andrew Rea
Copyright (c) 2014 James Allen

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
 */

'use strict';

var _ = require('lodash');
var assert = require('assert');
var utils = require('./utils');
var events = require('events');
var PREFIX = 'deride';

var Expectations = function(obj, method) {
	var timesCalled = 0;
	var calledWithArgs = {};

	function checkArg(expected, values) {
		return _.any(_.where(values, expected));
	}

	function checkArgs(expectedArgs, callArgs, evaluator) {
		var values = _.values(callArgs);
		var argResults = [];
		for (var argIndex = 0; argIndex < expectedArgs.length; argIndex++) {
			var expected = expectedArgs[argIndex];
			var foundArg = checkArg(expected, values);
			argResults.push(foundArg);
		}
		return evaluator(argResults);
	}

	function checkAnyArgs(expectedArgs, callArgs) {
		return checkArgs(expectedArgs, callArgs, _.any);
	}

	function withArgs() {
		var args = _.values(arguments);
		assertArgsWithEvaluator(calledWithArgs, args, _.all);
		return self.called;
	}

	function withSingleArg(arg) {
		var args = [arg];
		assertArgsWithEvaluator(calledWithArgs, args, _.any);
		return self.called;
	}

	function assertArgsWithEvaluator(argsToCheck, args, evaluator) {
		var callResults = [];
		_.forEach(argsToCheck, function(value) {
			var argResult = checkArgs(args, value, evaluator);
			callResults.push(argResult);
		});
		var result = _.any(callResults);
		assert(result, 'Expected ' + method + ' to be called with: ' + args.join(', '));
	}

	function withArg(args) {
		return function(arg) {
			assert(checkAnyArgs([arg], args));
		};
	}

	function invocation(index) {
		if (!(index.toString() in calledWithArgs)) {
			throw new Error('invocation out of range');
		}
		var arg = calledWithArgs[index.toString()];
		return {
			withArg: withArg(arg)
		};
	}

	function times(number, err) {
		if (!err) {
			err = 'Expected ' + method + ' to be called ' + utils.humanise(number) + ' but was ' + timesCalled;
		}
		assert.equal(timesCalled, number, err);
	}

	function never(err) {
		times(0, err);
	}

	function calledOnce(err) {
		times(1, err);
	}

	function calledTwice(err) {
		times(2, err);
	}

	function reset() {
		timesCalled = 0;
		calledWithArgs = {};
	}

	function call() {
		calledWithArgs[timesCalled++] = arguments;
	}

	function negate(func) {
		return function() {
			var args = _.values(arguments);
			try {
				func.call(null, args);
			} catch (err) {
				return self;
			}
			assert(false);
		};
	}

	function addNotMethods(obj) {
		var methods = {};
		var calledMethods = _.omit(utils.methods(obj.called), 'reset');
		_.each(calledMethods, function(method) {
			methods[method] = negate(obj.called[method]);
		});
		obj.called.not = methods;
		return obj;
	}

	var self = {
		called: {
			times: times,
			never: never,
			once: calledOnce,
			twice: calledTwice,
			reset: reset,
			withArgs: withArgs,
			withArg: withSingleArg
		},
		invocation: invocation,
		call: call
	};

	return (function() {
		return Object.freeze(addNotMethods(self));
	}());
};

var Setup = function(obj, method, emitter) {
	var debug = require('debug')(PREFIX + ':setup:'+ method);
	var Promises = require('when');
	var originalMethod = obj[method];
	var callToInvoke = normalCall;
	var callToInvokeOnArguments = {};
	var argumentsPredicate;

	function call() {
		var key = serializeArgs(arguments);
		var callBasedOnArgs = callToInvokeOnArguments[key];
		if (callBasedOnArgs !== null && callBasedOnArgs !== undefined) {
			return callBasedOnArgs.apply(self, arguments);
		} else {
			return callToInvoke.apply(self, arguments);
		}
	}

	function toCallbackWith(args) {
		var func = function() {
			debug('toCallbackWith', args);
			for (var i = 0; i < arguments.length; i++) {
				var argType = typeof(arguments[i]);
				if (argType === 'function') {
					arguments[i].apply(null, args);
				}
			}
		};
		checkArgumentsToInvoke(func);
	}

	function toDoThis(func) {
		var wrapper = function() {
			debug('toDoThis override');
			var result = func.apply(obj, arguments);
			return result;
		};
		checkArgumentsToInvoke(wrapper);
	}

	function toEmit() {
		var args = Array.prototype.slice.call(arguments);
		var func = function() {
			emitter.emit.apply(emitter, args);
			return originalMethod.apply(obj, arguments);
		};
		checkArgumentsToInvoke(func);
	}

	function toRejectWith(arg) {
		var func = function() {
			debug('toRejectWith');
			return Promises.reject(arg);
		};
		checkArgumentsToInvoke(func);
	}

	function toResolveWith(arg) {
		var func = function() {
			debug('toResolveWith');
			return Promises.resolve(arg);
		};
		checkArgumentsToInvoke(func);
	}

	function toReturn(value) {
		var overrideReturnValue = function() {
			debug('toReturn', value);
			return value;
		};
		checkArgumentsToInvoke(overrideReturnValue);
	}

	function toThrow(message) {
		var func = function() {
			debug('toThrow', message);
			throw new Error(message);
		};
		checkArgumentsToInvoke(func);
	}

	function toTimeWarp(milliseconds) {
		var func = function() {
			debug('toTimeWarp', milliseconds);
			var originalTimeoutFunc = setTimeout;
			setTimeout = function(delegate, timeout) {
				originalTimeoutFunc(delegate, timeout - milliseconds);
			};
			var result = originalMethod.apply(obj, arguments);
			return result;
		};
		checkArgumentsToInvoke(func);
	}

	function when() {
		argumentsPredicate = arguments;
		return Object.freeze(self);
	}

	function checkArgumentsToInvoke(func) {
		if (argumentsPredicate !== null && argumentsPredicate !== undefined) {
			var key = serializeArgs(argumentsPredicate);
			callToInvokeOnArguments[key] = func;
		} else {
			callToInvoke = func;
		}
		argumentsPredicate = null;
	}

	function normalCall() {
		debug('normal call', method);
		var result = originalMethod.apply(obj, arguments);
		return result;
	}

	function serializeArgs(args) {
		return JSON.stringify(args);
	}

	var self = {
		toDoThis: toDoThis,
		toReturn: toReturn,
		toThrow: toThrow,
		toCallbackWith: toCallbackWith,
		toResolveWith: toResolveWith,
		toRejectWith: toRejectWith,
		toTimeWarp: toTimeWarp,
		toEmit: toEmit,
		when: when,
		call: call
	};

	return (function() {
		return Object.freeze(self);
	}());
};

function wrap(obj) {
	var debug = require('debug')(PREFIX + ':wrap');
	var objMethods = utils.methods(obj);
	var self = {};
	var expectMethods = {};
	var setupMethods = {};
	var eventEmitter = new events.EventEmitter();
	utils.proxyFunctions(self, eventEmitter, ['on', 'once', 'emit']);

	function setupForMethod(method) {
		debug(method);
		return function() {
			expectMethods[method].call.apply(obj, arguments);
			return setupMethods[method].call.apply(obj, arguments);
		};
	}

	for (var i = 0; i < objMethods.length; i++) {
		var method = objMethods[i];
		expectMethods[method] = new Expectations(obj, method);
		setupMethods[method] = new Setup(obj, method, eventEmitter);
		self[method] = setupForMethod(method);
	}

	self.expect = expectMethods;
	self.called = {
		reset: function() {
			_.each(expectMethods, function(method) {
				method.called.reset();
			});
		}
	};
	self.setup = setupMethods;
	return Object.freeze(_.merge({}, obj, self));
}

function func() {
	var debug = require('debug')(PREFIX + ':func');
	var objHarness = {
		value: function() {}
	};
	var wrapped = wrap(objHarness);

	function createFunc() {
		debug('harness');
		var returnVal = wrapped.value.apply(objHarness, arguments);
		return returnVal;
	}
	createFunc.expect = wrapped.expect.value;
	createFunc.setup = wrapped.setup.value;

	return Object.freeze(createFunc);
}

function stub(target) {
	var debug = require('debug')(PREFIX + ':stub');
	debug(target);
	var methods = [];
	if (_.isArray(target)) {
		methods = target;
	} else {
		methods = utils.methods(target);
	}

	var stubObj = {};
	var emptyMethod = function() {
		return function() {};
	};
	for (var i = 0; i < methods.length; i++) {
		stubObj[methods[i]] = emptyMethod();
	}
	return wrap(stubObj);
}

module.exports = {
	wrap: wrap,
	stub: stub,
	func: func
};
<|endoftext|>


<commit_before>
var dyncol = require( '../lib/index.js' ),
    Code = require( 'code' ),
    Lab = require( 'lab' ),
    lab = exports.lab = Lab.script();

var tests = [
  "COLUMN_CREATE('test', 'test', 'arrayone', COLUMN_CREATE('arr', " +
  "COLUMN_CREATE('0', 'arr', '1', 'imma pirate', '2', COLUMN_CREATE('yay', " +
  "'ditworks'))), 'another', COLUMN_CREATE('one', 'yey another one!'), " +
  "'qr', COLUMN_CREATE('test', 'tester', 'rofl', COLUMN_CREATE('jaja', " +
  "'neinnein', 'testagain', COLUMN_CREATE('yip', 'datworks', 'boolean', 1 " +
  "AS unsigned integer, 'emtpyone', NULL))))",

  "COLUMN_ADD(`testTable`, 'test', 'test', 'arrayone', " +
  "COLUMN_ADD(COLUMN_GET(`testTable`, 'arrayone' AS CHAR), 'arr', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(`testTable`, 'arrayone' AS CHAR), 'arr' " +
  "AS CHAR), '0', 'arr', '1', 'imma pirate', '2', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(COLUMN_GET(`testTable`, 'arrayone' " +
  "AS CHAR), 'arr' AS CHAR), '2' AS CHAR), 'yay', 'ditworks'))), 'another', " +
  "COLUMN_ADD(COLUMN_GET(`testTable`, 'another' AS CHAR), 'one', " +
  "'yey another one!'), 'qr', COLUMN_ADD(COLUMN_GET(`testTable`, 'qr' " +
  "AS CHAR), 'test', 'tester', 'rofl', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(`testTable`, 'qr' AS CHAR), 'rofl' " +
  "AS CHAR), 'jaja', 'neinnein', 'testagain', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(COLUMN_GET(`testTable`, 'qr' AS CHAR), " +
  "'rofl' AS CHAR), 'testagain' AS CHAR), 'yip', 'datworks', 'boolean', 1 " +
  "AS unsigned integer))))",

  "COLUMN_CREATE('test', 1 AS unsigned integer)",
  "COLUMN_CREATE('test', 12 AS double)",
  "COLUMN_CREATE('test', 'string')",

  "COLUMN_CREATE('test', COLUMN_CREATE('0', 1 AS double, '1', " +
  "1 AS unsigned integer, '2', 'string'))",

  "COLUMN_ADD(`testTable`, 'test', 1 AS unsigned integer)",
  "COLUMN_ADD(`testTable`, 'test', 12 AS double)",
  "COLUMN_ADD(`testTable`, 'test', 'string')",

  "COLUMN_ADD(`testTable`, 'test', " +
  "COLUMN_ADD(COLUMN_GET(`testTable`, 'test' AS CHAR), '0', 1 AS double, " +
  "'1', 1 AS unsigned integer, '2', 'string'))",

  "COLUMN_CREATE('test', 0 AS unsigned integer)",
  "COLUMN_ADD(`testTable`, 'test', 0 AS unsigned integer)",

  "COLUMN_ADD(`testTable`, 'test', 'test', 'meisnull', 'NULL', " +
  "'eq', COLUMN_ADD(COLUMN_GET(`testTable`, 'eq' AS CHAR), " +
  "'somenullvalue', 'NULL'))",

  "COLUMN_CREATE('test', 'test', 'other', " +
  "COLUMN_CREATE('nothinginhere', NULL))",

  "COLUMN_CREATE(?, ?, ?, COLUMN_CREATE(?, NULL))",
  [ 'test', 'test', 'other', 'nothinginhere' ]

];

lab.experiment( 'schema/', { parallel: true }, function () {

  lab.experiment( 'create',
  {
      parallel: true
  }, function () {

    lab.test( 'returns true if the emtpy nested schema was correctly builded',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( {
              test: 'test',
              other: {
                nothinginhere: []
              }
            } ) ).equal( tests[13] );

            done();
        } );

    lab.test( 'returns true if the emtpy nested schema was correctly builded',
        {
            parallel: true
        }, function ( done )
        {
          var array = [];

            Code.expect( dyncol.createQuery( {
              test: 'test',
              other: {
                nothinginhere: []
              }
            }, true, array ) ).equal( tests[14] );

            Code.expect( array ).deep.equal( tests[15] );

            done();
        } );

    lab.test( 'returns true if the nested schema query was correctly builded',
        {
            parallel: true
        }, function ( done )
        {

            Code.expect( dyncol.createQuery( {
              test: 'test',
              qr: {
                test: 'tester',
                rofl: {
                  jaja: 'neinnein',
                  testagain: {
                    yip: 'datworks',
                    boolean: true,
                    emtpyone: []
                  },
                  somenullvalue: null
                }
              },
              another: {
                one: 'yey another one!'
              },
              arrayone: {
                arr: [ 'arr', 'imma pirate', {
                  yay: 'ditworks'
                }]
              }
            } ) ).equal( tests[0] );

            done();
        } );

    lab.test( 'returns true if boolean builds as unsigned int 1',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: true } ) )
              .equal( tests[2] );

            done();
        } );

    lab.test( 'returns true if boolean builds as unsigned int 0',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: false } ) )
              .equal( tests[10] );

            done();
        } );

    lab.test( 'returns true if number builds as double',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: 12 } ) )
              .equal( tests[3] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: 'string' } ) )
              .equal( tests[4] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: [ 1, true, 'string' ] } ) )
              .equal( tests[5] );

            done();
        } );
  } );

  lab.experiment( 'create',
  {
      parallel: true
  }, function () {

    lab.test( 'returns true if the nested update query was correctly builded',
        {
            parallel: true
        }, function ( done )
        {

            Code.expect( dyncol.updateQuery( 'testTable', {
              test: 'test',
              qr: {
                test: 'tester',
                rofl: {
                  jaja: 'neinnein',
                  testagain: {
                    yip: 'datworks',
                    boolean: true
                  }
                }
              },
              another: {
                one: 'yey another one!'
              },
              arrayone: {
                arr: [ 'arr', 'imma pirate', {
                  yay: 'ditworks'
                }]
              }
            } ) ).equal( tests[1] );

            done();
        } );

        lab.test( 'returns true if null values are build correctly',
        {
          parallel: true
        }, function ( done )
        {

          Code.expect( dyncol.updateQuery( 'testTable', {
            test: 'test',
            eq: {
              somenullvalue: undefined
            },
            meisnull: null
          } ) ).equal( tests[12] );

          done();
        } );
    } );

    lab.test( 'returns true if boolean builds as unsigned int 1',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: true } ) ).equal( tests[6] );

            done();
        } );

    lab.test( 'returns true if boolean builds as unsigned int 0',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: false } ) ).equal( tests[11] );

            done();
        } );

    lab.test( 'returns true if number builds as double',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: 12 } ) ).equal( tests[7] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: 'string' } ) ).equal( tests[8] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: [ 1, true, 'string' ] } ) ).equal( tests[9] );

            done();
        } );
} );
<commit_msg>fix(tests): deep equals in code are now default and have been removed from the API.<commit_after>
var dyncol = require( '../lib/index.js' ),
    Code = require( 'code' ),
    Lab = require( 'lab' ),
    lab = exports.lab = Lab.script();

var tests = [
  "COLUMN_CREATE('test', 'test', 'arrayone', COLUMN_CREATE('arr', " +
  "COLUMN_CREATE('0', 'arr', '1', 'imma pirate', '2', COLUMN_CREATE('yay', " +
  "'ditworks'))), 'another', COLUMN_CREATE('one', 'yey another one!'), " +
  "'qr', COLUMN_CREATE('test', 'tester', 'rofl', COLUMN_CREATE('jaja', " +
  "'neinnein', 'testagain', COLUMN_CREATE('yip', 'datworks', 'boolean', 1 " +
  "AS unsigned integer, 'emtpyone', NULL))))",

  "COLUMN_ADD(`testTable`, 'test', 'test', 'arrayone', " +
  "COLUMN_ADD(COLUMN_GET(`testTable`, 'arrayone' AS CHAR), 'arr', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(`testTable`, 'arrayone' AS CHAR), 'arr' " +
  "AS CHAR), '0', 'arr', '1', 'imma pirate', '2', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(COLUMN_GET(`testTable`, 'arrayone' " +
  "AS CHAR), 'arr' AS CHAR), '2' AS CHAR), 'yay', 'ditworks'))), 'another', " +
  "COLUMN_ADD(COLUMN_GET(`testTable`, 'another' AS CHAR), 'one', " +
  "'yey another one!'), 'qr', COLUMN_ADD(COLUMN_GET(`testTable`, 'qr' " +
  "AS CHAR), 'test', 'tester', 'rofl', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(`testTable`, 'qr' AS CHAR), 'rofl' " +
  "AS CHAR), 'jaja', 'neinnein', 'testagain', " +
  "COLUMN_ADD(COLUMN_GET(COLUMN_GET(COLUMN_GET(`testTable`, 'qr' AS CHAR), " +
  "'rofl' AS CHAR), 'testagain' AS CHAR), 'yip', 'datworks', 'boolean', 1 " +
  "AS unsigned integer))))",

  "COLUMN_CREATE('test', 1 AS unsigned integer)",
  "COLUMN_CREATE('test', 12 AS double)",
  "COLUMN_CREATE('test', 'string')",

  "COLUMN_CREATE('test', COLUMN_CREATE('0', 1 AS double, '1', " +
  "1 AS unsigned integer, '2', 'string'))",

  "COLUMN_ADD(`testTable`, 'test', 1 AS unsigned integer)",
  "COLUMN_ADD(`testTable`, 'test', 12 AS double)",
  "COLUMN_ADD(`testTable`, 'test', 'string')",

  "COLUMN_ADD(`testTable`, 'test', " +
  "COLUMN_ADD(COLUMN_GET(`testTable`, 'test' AS CHAR), '0', 1 AS double, " +
  "'1', 1 AS unsigned integer, '2', 'string'))",

  "COLUMN_CREATE('test', 0 AS unsigned integer)",
  "COLUMN_ADD(`testTable`, 'test', 0 AS unsigned integer)",

  "COLUMN_ADD(`testTable`, 'test', 'test', 'meisnull', 'NULL', " +
  "'eq', COLUMN_ADD(COLUMN_GET(`testTable`, 'eq' AS CHAR), " +
  "'somenullvalue', 'NULL'))",

  "COLUMN_CREATE('test', 'test', 'other', " +
  "COLUMN_CREATE('nothinginhere', NULL))",

  "COLUMN_CREATE(?, ?, ?, COLUMN_CREATE(?, NULL))",
  [ 'test', 'test', 'other', 'nothinginhere' ]

];

lab.experiment( 'schema/', { parallel: true }, function () {

  lab.experiment( 'create',
  {
      parallel: true
  }, function () {

    lab.test( 'returns true if the emtpy nested schema was correctly builded',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( {
              test: 'test',
              other: {
                nothinginhere: []
              }
            } ) ).equal( tests[13] );

            done();
        } );

    lab.test( 'returns true if the emtpy nested schema was correctly builded',
        {
            parallel: true
        }, function ( done )
        {
          var array = [];

            Code.expect( dyncol.createQuery( {
              test: 'test',
              other: {
                nothinginhere: []
              }
            }, true, array ) ).equal( tests[14] );

            Code.expect( array ).to.equal( tests[15] );

            done();
        } );

    lab.test( 'returns true if the nested schema query was correctly builded',
        {
            parallel: true
        }, function ( done )
        {

            Code.expect( dyncol.createQuery( {
              test: 'test',
              qr: {
                test: 'tester',
                rofl: {
                  jaja: 'neinnein',
                  testagain: {
                    yip: 'datworks',
                    boolean: true,
                    emtpyone: []
                  },
                  somenullvalue: null
                }
              },
              another: {
                one: 'yey another one!'
              },
              arrayone: {
                arr: [ 'arr', 'imma pirate', {
                  yay: 'ditworks'
                }]
              }
            } ) ).equal( tests[0] );

            done();
        } );

    lab.test( 'returns true if boolean builds as unsigned int 1',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: true } ) )
              .equal( tests[2] );

            done();
        } );

    lab.test( 'returns true if boolean builds as unsigned int 0',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: false } ) )
              .equal( tests[10] );

            done();
        } );

    lab.test( 'returns true if number builds as double',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: 12 } ) )
              .equal( tests[3] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: 'string' } ) )
              .equal( tests[4] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.createQuery( { test: [ 1, true, 'string' ] } ) )
              .equal( tests[5] );

            done();
        } );
  } );

  lab.experiment( 'create',
  {
      parallel: true
  }, function () {

    lab.test( 'returns true if the nested update query was correctly builded',
        {
            parallel: true
        }, function ( done )
        {

            Code.expect( dyncol.updateQuery( 'testTable', {
              test: 'test',
              qr: {
                test: 'tester',
                rofl: {
                  jaja: 'neinnein',
                  testagain: {
                    yip: 'datworks',
                    boolean: true
                  }
                }
              },
              another: {
                one: 'yey another one!'
              },
              arrayone: {
                arr: [ 'arr', 'imma pirate', {
                  yay: 'ditworks'
                }]
              }
            } ) ).equal( tests[1] );

            done();
        } );

        lab.test( 'returns true if null values are build correctly',
        {
          parallel: true
        }, function ( done )
        {

          Code.expect( dyncol.updateQuery( 'testTable', {
            test: 'test',
            eq: {
              somenullvalue: undefined
            },
            meisnull: null
          } ) ).equal( tests[12] );

          done();
        } );
    } );

    lab.test( 'returns true if boolean builds as unsigned int 1',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: true } ) ).equal( tests[6] );

            done();
        } );

    lab.test( 'returns true if boolean builds as unsigned int 0',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: false } ) ).equal( tests[11] );

            done();
        } );

    lab.test( 'returns true if number builds as double',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: 12 } ) ).equal( tests[7] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: 'string' } ) ).equal( tests[8] );

            done();
        } );

    lab.test( 'returns true if string builds as nothing',
        {
            parallel: true
        }, function ( done )
        {
            Code.expect( dyncol.updateQuery( 'testTable',
              { test: [ 1, true, 'string' ] } ) ).equal( tests[9] );

            done();
        } );
} );
<|endoftext|>


<commit_before>'use strict';

/** Load Node.js modules. */
var fs = require('fs');

/** Load other modules. */
var _ = require('lodash');

/** Used to minify variables and string values to a single character. */
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
minNames.push.apply(minNames, minNames.map(function(value) {
  return value + value;
}));

/** Used to protect the specified properties from getting minified. */
var propWhitelist = _.union(
  _.keys(_),
  _.keys(_.prototype),
  _.keys(_.support),
  _.keys(_.templateSettings), [
  'BYTES_PER_ELEMENT',
  'NEGATIVE_INFINITY',
  'POSITIVE_INFINITY',
  'Array',
  'ArrayBuffer',
  'Boolean',
  'Cache',
  'Date',
  'Error',
  'Float32Array',
  'Float64Array',
  'Function',
  'Int8Array',
  'Int16Array',
  'Int32Array',
  'Math',
  'Number',
  'Object',
  'RegExp',
  'Set',
  'String',
  'TypeError',
  'Uint8Array',
  'Uint8ClampedArray',
  'Uint16Array',
  'Uint32Array',
  'WeakMap',
  'WinRTError',
  '__actions__',
  '__chain__',
  '__data__',
  '__dir__',
  '__filtered__',
  '__iteratees__',
  '__takeCount__',
  '__views__',
  '__wrapped__',
  'add',
  'args',
  'amd',
  'buffer',
  'byteLength',
  'cache',
  'cancel',
  'clearTimeout',
  'count',
  'createDocumentFragment',
  'criteria',
  'data',
  'delete',
  'document',
  'done',
  'end',
  'exports',
  'func',
  'get',
  'getOwnPropertySymbols',
  'global',
  'has',
  'hash',
  'index',
  'iteratee',
  'leading',
  'length',
  'limit',
  'maxWait',
  'name',
  'nodeType',
  'omission',
  'parseFloat',
  'placeholder',
  'self',
  'separator',
  'set',
  'setTimeout',
  'size',
  'source',
  'sourceURL',
  'start',
  'thisArg',
  'trailing',
  'type',
  'value',
  'window'
]);

/*----------------------------------------------------------------------------*/

/**
 * Pre-process a given lodash `source`, preparing it for minification.
 *
 * @param {string} [source=''] The source to process.
 * @param {Object} [options={}] The options object.
 * @returns {string} Returns the processed source.
 */
function preprocess(source, options) {
  source || (source = '');
  options || (options = {});

  // Remove unrecognized JSDoc tags so the Closure Compiler won't complain.
  source = source.replace(/@(?:alias|category)\b.*/g, '');

  if (options.isTemplate) {
    return source;
  }
  // Remove whitespace from `_.template` related regexes.
  source = source.replace(/(reEmptyString\w+\s*=)([\s\S]+?)(?=[,;]\n)/g, function(match, left, value) {
    return left + value.replace(/\s|\\n/g, '');
  });

  // Remove whitespace from `_.template`.
  source = source.replace(/^( *)function template\b[\s\S]+?\n\1}/m, function(snippet) {
    // Remove whitespace from string literals.
    snippet = snippet.replace(/^((?:[ "'$\w]+:)?\s*)"[^"\n\\]*?(?:\\.[^"\n\\]*?)*"|'[^'\n\\]*?(?:\\.[^'\n\\]*?)*'/gm, function(string, left) {
      // Clip `string` after an object literal property name or leading spaces.
      if (left) {
        string = string.slice(left.length);
      }
      // Avoids removing the '\n' of the `stringEscapes` object.
      string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+["'$\w]|throw |typeof |use strict|var |# |(["'])(?:\\n| )\1|\\\\n|\\n|\s+/g, function(match) {
        return match == false || match == '\\n' ? '' : match;
      });
      // Unclip `string`.
      return (left || '') + string;
    });

    // Remove newline from double-quoted strings.
    snippet = snippet
      .replace('"__p += \'"', '"__p+=\'"')
      .replace('"\';\\n"', '"\';"');

    // Add a newline back so "evaluate" delimiters can support single line comments.
    snippet = snippet.replace('";__p+=\'"', '";\\n__p+=\'"');

    // Remove default `sourceURL` value.
    return snippet.replace(/^( *var\s+sourceURL\s*=\s*)[\s\S]+?(?=;\n$)/m, function(match, left) {
      return left + "'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\\n' : ''";
    });
  });

  // Minify internal properties.
  (function() {
    var funcNames = [
      'baseSortBy',
      'baseSortByOrder',
      'compareAscending',
      'compareMultiple',
      'sortBy'
    ];

    var props = [
      'criteria',
      'index',
      'value'
    ];

    // Minify properties used in `funcNames` functions.
    var snippets = source.match(RegExp('^( *)(?:var|function) +(?:' + funcNames.join('|') + ')\\b[\\s\\S]+?\\n\\1}', 'gm'));
    _.each(snippets, function(snippet) {
      var modified = snippet;
      _.each(props, function(prop, index) {
        var minName = minNames[index],
            reBracketProp = RegExp("\\['(" + prop + ")'\\]", 'g'),
            reDotProp = RegExp('\\.' + prop + '\\b', 'g'),
            rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + prop + "\\2\\s*:", 'g');

        modified = modified
          .replace(reBracketProp, "['" + minName + "']")
          .replace(reDotProp, "['" + minName + "']")
          .replace(rePropColon, "$1'" + minName + "':");
      });

      // Replace with modified snippet.
      source = source.replace(snippet, function() {
        return modified;
      });
    });
  }());

  // Add brackets to whitelisted properties so the Closure Compiler won't mung them.
  // See http://code.google.com/closure/compiler/docs/api-tutorial3.html#export.
  return source.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.(' + propWhitelist.join('|') + ')\\b', 'g'), function(match, quote, prop) {
    return quote ? match : "['" + prop + "']";
  });
}

/*----------------------------------------------------------------------------*/

// Export `preprocess`.
if (module != require.main) {
  module.exports = preprocess;
}
// Read the lodash source file from the first argument if the script was invoked
// by the command-line (e.g. `node pre-compile.js source.js`) and write to the same file.
else if (_.size(process.argv) > 2) {
  (function() {
    var filePath = path.normalize(_.last(process.argv)),
        isTemplate = _.includes(process.argv, '-t') || _.includes(process.argv, '--template'),
        source = fs.readFileSync(filePath, 'utf8');

    fs.writeFileSync(filePath, preprocess(source, {
      'isTemplate': isTemplate
    }), 'utf8');
  }());
}
<commit_msg>Remove `_.support` iteration from pre-compile.js.<commit_after>'use strict';

/** Load Node.js modules. */
var fs = require('fs');

/** Load other modules. */
var _ = require('lodash');

/** Used to minify variables and string values to a single character. */
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
minNames.push.apply(minNames, minNames.map(function(value) {
  return value + value;
}));

/** Used to protect the specified properties from getting minified. */
var propWhitelist = _.union(
  _.keys(_),
  _.keys(_.prototype),
  _.keys(_.templateSettings), [
  'BYTES_PER_ELEMENT',
  'NEGATIVE_INFINITY',
  'POSITIVE_INFINITY',
  'Array',
  'ArrayBuffer',
  'Boolean',
  'Cache',
  'Date',
  'Error',
  'Float32Array',
  'Float64Array',
  'Function',
  'Int8Array',
  'Int16Array',
  'Int32Array',
  'Math',
  'Number',
  'Object',
  'RegExp',
  'Set',
  'String',
  'TypeError',
  'Uint8Array',
  'Uint8ClampedArray',
  'Uint16Array',
  'Uint32Array',
  'WeakMap',
  'WinRTError',
  '__actions__',
  '__chain__',
  '__data__',
  '__dir__',
  '__filtered__',
  '__iteratees__',
  '__takeCount__',
  '__views__',
  '__wrapped__',
  'add',
  'args',
  'amd',
  'buffer',
  'byteLength',
  'cache',
  'cancel',
  'clearTimeout',
  'count',
  'createDocumentFragment',
  'criteria',
  'data',
  'delete',
  'document',
  'done',
  'end',
  'exports',
  'func',
  'get',
  'getOwnPropertySymbols',
  'global',
  'has',
  'hash',
  'index',
  'iteratee',
  'leading',
  'length',
  'limit',
  'maxWait',
  'name',
  'nodeType',
  'omission',
  'parseFloat',
  'placeholder',
  'self',
  'separator',
  'set',
  'setTimeout',
  'size',
  'source',
  'sourceURL',
  'start',
  'thisArg',
  'trailing',
  'type',
  'value',
  'window'
]);

/*----------------------------------------------------------------------------*/

/**
 * Pre-process a given lodash `source`, preparing it for minification.
 *
 * @param {string} [source=''] The source to process.
 * @param {Object} [options={}] The options object.
 * @returns {string} Returns the processed source.
 */
function preprocess(source, options) {
  source || (source = '');
  options || (options = {});

  // Remove unrecognized JSDoc tags so the Closure Compiler won't complain.
  source = source.replace(/@(?:alias|category)\b.*/g, '');

  if (options.isTemplate) {
    return source;
  }
  // Remove whitespace from `_.template` related regexes.
  source = source.replace(/(reEmptyString\w+\s*=)([\s\S]+?)(?=[,;]\n)/g, function(match, left, value) {
    return left + value.replace(/\s|\\n/g, '');
  });

  // Remove whitespace from `_.template`.
  source = source.replace(/^( *)function template\b[\s\S]+?\n\1}/m, function(snippet) {
    // Remove whitespace from string literals.
    snippet = snippet.replace(/^((?:[ "'$\w]+:)?\s*)"[^"\n\\]*?(?:\\.[^"\n\\]*?)*"|'[^'\n\\]*?(?:\\.[^'\n\\]*?)*'/gm, function(string, left) {
      // Clip `string` after an object literal property name or leading spaces.
      if (left) {
        string = string.slice(left.length);
      }
      // Avoids removing the '\n' of the `stringEscapes` object.
      string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+["'$\w]|throw |typeof |use strict|var |# |(["'])(?:\\n| )\1|\\\\n|\\n|\s+/g, function(match) {
        return match == false || match == '\\n' ? '' : match;
      });
      // Unclip `string`.
      return (left || '') + string;
    });

    // Remove newline from double-quoted strings.
    snippet = snippet
      .replace('"__p += \'"', '"__p+=\'"')
      .replace('"\';\\n"', '"\';"');

    // Add a newline back so "evaluate" delimiters can support single line comments.
    snippet = snippet.replace('";__p+=\'"', '";\\n__p+=\'"');

    // Remove default `sourceURL` value.
    return snippet.replace(/^( *var\s+sourceURL\s*=\s*)[\s\S]+?(?=;\n$)/m, function(match, left) {
      return left + "'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\\n' : ''";
    });
  });

  // Minify internal properties.
  (function() {
    var funcNames = [
      'baseSortBy',
      'baseSortByOrder',
      'compareAscending',
      'compareMultiple',
      'sortBy'
    ];

    var props = [
      'criteria',
      'index',
      'value'
    ];

    // Minify properties used in `funcNames` functions.
    var snippets = source.match(RegExp('^( *)(?:var|function) +(?:' + funcNames.join('|') + ')\\b[\\s\\S]+?\\n\\1}', 'gm'));
    _.each(snippets, function(snippet) {
      var modified = snippet;
      _.each(props, function(prop, index) {
        var minName = minNames[index],
            reBracketProp = RegExp("\\['(" + prop + ")'\\]", 'g'),
            reDotProp = RegExp('\\.' + prop + '\\b', 'g'),
            rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + prop + "\\2\\s*:", 'g');

        modified = modified
          .replace(reBracketProp, "['" + minName + "']")
          .replace(reDotProp, "['" + minName + "']")
          .replace(rePropColon, "$1'" + minName + "':");
      });

      // Replace with modified snippet.
      source = source.replace(snippet, function() {
        return modified;
      });
    });
  }());

  // Add brackets to whitelisted properties so the Closure Compiler won't mung them.
  // See http://code.google.com/closure/compiler/docs/api-tutorial3.html#export.
  return source.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.(' + propWhitelist.join('|') + ')\\b', 'g'), function(match, quote, prop) {
    return quote ? match : "['" + prop + "']";
  });
}

/*----------------------------------------------------------------------------*/

// Export `preprocess`.
if (module != require.main) {
  module.exports = preprocess;
}
// Read the lodash source file from the first argument if the script was invoked
// by the command-line (e.g. `node pre-compile.js source.js`) and write to the same file.
else if (_.size(process.argv) > 2) {
  (function() {
    var filePath = path.normalize(_.last(process.argv)),
        isTemplate = _.includes(process.argv, '-t') || _.includes(process.argv, '--template'),
        source = fs.readFileSync(filePath, 'utf8');

    fs.writeFileSync(filePath, preprocess(source, {
      'isTemplate': isTemplate
    }), 'utf8');
  }());
}
<|endoftext|>


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

class Parser extends EventEmitter {
    parseLine(line) {
        var match = null;
        var result = null;

        if (line.match(/^Initialize engine version/)) {
            result = ["startup"];

        } else if (line.match(/\[Power\] .* Begin Spectating/)) {
            result = ["begin_spectator_mode"];

        } else if (line.match(/\[Power\] .* End Spectator/)) {
            result = ["end_spectator_mode"];

        } else if (match = line.match(/\[LoadingScreen\] LoadingScreen.OnSceneLoaded\(\) - prevMode=.* currMode=(.*)/)) {
            var mode = match[1];
            switch(mode) {
                case "DRAFT":
                    result = ["mode", "arena"];
                    break;
                case "TOURNAMENT":
                    result = ["mode", "ranked"];
                    break;
                case "ADVENTURE":
                    result = ["mode", "solo"];
                    break;
            }

        } else if (match = line.match(/\[Power\] GameState.DebugPrintPower\(\) -\s*TAG_CHANGE Entity=\[.*id=(\d*) zone=(.*) zonePos=(\d*) cardId=(.*) player=(\d)\] tag=(.*) value=(.*)/)) {
            var [, entityId, zone, zonePos, cardId, playerId, type, state] = match;
            result = this.parseTagChange(type, null, state, parseInt(playerId), parseInt(entityId), zone, parseInt(zonePos), cardId);

        } else if (match = line.match(/\[Power\] GameState.DebugPrintPower\(\) -\s*TAG_CHANGE Entity=(.*) tag=(.*) value=(.*)/)) {
            var [, player, type, state] = match;
            result = this.parseTagChange(type, player, state);

        } else if (match = line.match(/\[Zone\] ZoneChangeList\.ProcessChanges\(\) - id=(\d*) local=(.*) \[name=(.*) id=(\d*) zone=(.*) zonePos=(\d*) cardId=(.*) player=(\d*)\] zone from (.*) -> (.*)/)) {
            var [, id, local, name, entityId, zone, zonePos, cardId, playerId, fromZone, toZone] = match;
            result = this.parseZoneChange(id, local, name, parseInt(entityId), zone, parseInt(zonePos), cardId, parseInt(playerId), fromZone, toZone)

        } else if (match = line.match(/\[Zone\] ZoneChangeList\.ProcessChanges\(\) - id=(\d*) local=(.*) \[id=(\d*) cardId=(.*) type=(.*) zone=(.*) zonePos=(\d*) player=(\d*)\] zone from (.*) -> (.*)/)) {
            var [, id, local, entityId, cardId, type, zone, zonePos, playerId, fromZone, toZone] = match;
            result = this.parseZoneChange(id, local, "", parseInt(entityId), zone, parseInt(zonePos), cardId, parseInt(playerId), fromZone, toZone)

        } else if (match = line.match(/\[Zone\] ZoneChangeList\.ProcessChanges\(\) - id=(\d*) local=(.*) \[name=(.*) id=(\d*) zone=(.*) zonePos=(\d*) cardId=(.*) player=(\d*)\] pos from (\d*) -> (\d*)/)) {
            var [, id, local, name, entityId, zone, zonePos, cardId, playerId, fromPos, toPos] = match;
            result = this.parsePosChange(parseInt(entityId), zone, parseInt(zonePos), cardId, parseInt(playerId), parseInt(fromPos), parseInt(toPos));

        }

        this.emit.apply(this, result);
        return result;
    }

    parseTagChange(type, playerName, state, playerId, entityId, zone, zonePos, cardId) {
        switch(type) {
            case "PLAYER_ID":
                return ["player_id", {name: playerName, player_id: parseInt(state)}];
            case "FIRST_PLAYER":
                return ["first_player", {name: playerName}];
            case "PLAYSTATE":
                return ["game_over", {name: playerName, state: state}];
            case "TURN_START":
                if (playerName == "GameEntity") {
                    return ["game_start", {timestamp: parseInt(state)}];
                } else {
                    return ["turn_start", {name: playerName, timestamp: parseInt(state)}];
                }
            case "TURN":
                return ["turn", parseInt(state)];
            case "DAMAGE":
                return ["damage", {id: entityId, player_id: playerId, value: parseInt(state), card_id: cardId}];
            case "ATTACKING":
                return ["attacking", {id: entityId, player_id: playerId, card_id: cardId}];
            case "DEFENDING":
                return ["defending", {id: entityId, player_id: playerId, card_id: cardId}];
            case "CARD_TARGET":
                return ["card_target", {id: entityId, player_id: playerId, target_id: parseInt(state), card_id: cardId}];
        }
    }

    parseZoneChange(id, local, name, entityId, zone, zonePos, cardId, playerId, fromZone, toZone) {
        return ["zone_change", {id: entityId, player_id: playerId, card_id: cardId, from_zone: fromZone, to_zone: toZone}]
    }

    parsePosChange(entityId, zone, zonePos, cardId, playerId, fromPos, toPos) {
        return ["pos_change", {id: entityId, player_id: playerId, card_id: cardId, from_pos: fromPos, to_pos: toPos, zone: zone}]
    }
}

module.exports = Parser; <commit_msg>add resources tag change<commit_after>var EventEmitter = require('events').EventEmitter;

class Parser extends EventEmitter {
    parseLine(line) {
        var match = null;
        var result = null;

        if (line.match(/^Initialize engine version/)) {
            result = ["startup"];

        } else if (line.match(/\[Power\] .* Begin Spectating/)) {
            result = ["begin_spectator_mode"];

        } else if (line.match(/\[Power\] .* End Spectator/)) {
            result = ["end_spectator_mode"];

        } else if (match = line.match(/\[LoadingScreen\] LoadingScreen.OnSceneLoaded\(\) - prevMode=.* currMode=(.*)/)) {
            var mode = match[1];
            switch(mode) {
                case "DRAFT":
                    result = ["mode", "arena"];
                    break;
                case "TOURNAMENT":
                    result = ["mode", "ranked"];
                    break;
                case "ADVENTURE":
                    result = ["mode", "solo"];
                    break;
            }

        } else if (match = line.match(/\[Power\] GameState.DebugPrintPower\(\) -\s*TAG_CHANGE Entity=\[.*id=(\d*) zone=(.*) zonePos=(\d*) cardId=(.*) player=(\d)\] tag=(.*) value=(.*)/)) {
            var [, entityId, zone, zonePos, cardId, playerId, type, state] = match;
            result = this.parseTagChange(type, null, state, parseInt(playerId), parseInt(entityId), zone, parseInt(zonePos), cardId);

        } else if (match = line.match(/\[Power\] GameState.DebugPrintPower\(\) -\s*TAG_CHANGE Entity=(.*) tag=(.*) value=(.*)/)) {
            var [, player, type, state] = match;
            result = this.parseTagChange(type, player, state);

        } else if (match = line.match(/\[Zone\] ZoneChangeList\.ProcessChanges\(\) - id=(\d*) local=(.*) \[name=(.*) id=(\d*) zone=(.*) zonePos=(\d*) cardId=(.*) player=(\d*)\] zone from (.*) -> (.*)/)) {
            var [, id, local, name, entityId, zone, zonePos, cardId, playerId, fromZone, toZone] = match;
            result = this.parseZoneChange(id, local, name, parseInt(entityId), zone, parseInt(zonePos), cardId, parseInt(playerId), fromZone, toZone)

        } else if (match = line.match(/\[Zone\] ZoneChangeList\.ProcessChanges\(\) - id=(\d*) local=(.*) \[id=(\d*) cardId=(.*) type=(.*) zone=(.*) zonePos=(\d*) player=(\d*)\] zone from (.*) -> (.*)/)) {
            var [, id, local, entityId, cardId, type, zone, zonePos, playerId, fromZone, toZone] = match;
            result = this.parseZoneChange(id, local, "", parseInt(entityId), zone, parseInt(zonePos), cardId, parseInt(playerId), fromZone, toZone)

        } else if (match = line.match(/\[Zone\] ZoneChangeList\.ProcessChanges\(\) - id=(\d*) local=(.*) \[name=(.*) id=(\d*) zone=(.*) zonePos=(\d*) cardId=(.*) player=(\d*)\] pos from (\d*) -> (\d*)/)) {
            var [, id, local, name, entityId, zone, zonePos, cardId, playerId, fromPos, toPos] = match;
            result = this.parsePosChange(parseInt(entityId), zone, parseInt(zonePos), cardId, parseInt(playerId), parseInt(fromPos), parseInt(toPos));

        }

        this.emit.apply(this, result);
        return result;
    }

    parseTagChange(type, playerName, state, playerId, entityId, zone, zonePos, cardId) {
        switch(type) {
            case "PLAYER_ID":
                return ["player_id", {name: playerName, player_id: parseInt(state)}];
            case "FIRST_PLAYER":
                return ["first_player", {name: playerName}];
            case "PLAYSTATE":
                return ["game_over", {name: playerName, state: state}];
            case "TURN_START":
                if (playerName == "GameEntity") {
                    return ["game_start", {timestamp: parseInt(state)}];
                } else {
                    return ["turn_start", {name: playerName, timestamp: parseInt(state)}];
                }
            case "RESOURCES":
                return ["resources", {name: playerName, resources: parseInt(state)}];
            case "TURN":
                return ["turn", parseInt(state)];
            case "DAMAGE":
                return ["damage", {id: entityId, player_id: playerId, value: parseInt(state), card_id: cardId}];
            case "ATTACKING":
                return ["attacking", {id: entityId, player_id: playerId, card_id: cardId}];
            case "DEFENDING":
                return ["defending", {id: entityId, player_id: playerId, card_id: cardId}];
            case "CARD_TARGET":
                return ["card_target", {id: entityId, player_id: playerId, target_id: parseInt(state), card_id: cardId}];
        }
    }

    parseZoneChange(id, local, name, entityId, zone, zonePos, cardId, playerId, fromZone, toZone) {
        return ["zone_change", {id: entityId, player_id: playerId, card_id: cardId, from_zone: fromZone, to_zone: toZone}]
    }

    parsePosChange(entityId, zone, zonePos, cardId, playerId, fromPos, toPos) {
        return ["pos_change", {id: entityId, player_id: playerId, card_id: cardId, from_pos: fromPos, to_pos: toPos, zone: zone}]
    }
}

module.exports = Parser; <|endoftext|>