text:
var vows = require('vows'),
    assert = require('assert'),
    comb = require("comb"),
    hitch = comb.hitch,
    patio = require("index");

/*options : Object
 *  options.connection : @see moose.createConnection
 *  options.dir : name of directory where migrations are located
 *  options.up : boolen, if true will migrate up otherwise down
 *  options.start : the migration to start at
 *  options.end : the migration to end at*/

var ret = exports = module.exports = new comb.Promise();
var suite = vows.describe('Migrations');
var patioMigrationVersion = 0, patioMigrationFiles = [];

var getFileVersion = function(file){
    return parseInt(file.split(".")[1], 10);
}

var sortMigrationFiles = function(){
    patioMigrationFiles.sort(function(f1, f2){
        return getFileVersion(f1) - getFileVersion(f2);
    });
};

var MockDS = comb.define(patio.Dataset, {
    instance:{

        fetchRows:function(sql, cb){
            var from = this.__opts.from[0], ret = new comb.Promise();
            ret.callback(cb({version:patioMigrationVersion}));
            return ret;
        },

        insert:function(values){
            var from = this.__opts.from[0], ret = new comb.Promise().callback(0);
            if (from.toString() == "schema_info") {
                patioMigrationVersion = values[Object.keys(values)[0]];
            }
            return ret;
        },

        update:function(values){
            var from = this.__opts.from[0], ret = new comb.Promise().callback(1);
            if (from.toString() == "schema_info") {
                patioMigrationVersion = values[Object.keys(values)[0]];
            }
            return ret;
        },

        count:function(){
            return new comb.Promise().callback(1);
        },

        getters:{
            columns:function(){
                var from = this.__opts.from[0], ret = new comb.Promise();
                ret.callback(this.db.columnsCreated);
                return ret;
            }
        }
    }
});

var MockDB = comb.define(patio.Database, {

    instance:{

        constructor:function(){
            this._super(arguments);
            this.type = this._static.type;
            this.quoteIdentifiers = false;
            this.identifierInputMethod = null;
            this.identifierOutputMethod = null;
            this.connectionExecuteMethod = "query";
            this.sqls = [];
            this.tables = {};
            this.alteredTables = {};
            this.closedCount = 0;
            this.createdCount = 0;
            this.columnsCreated = [];
            this.columnsAltered = {};
            this.droppedTables = [];
        },

        createConnection:function(){
            this.createdCount++;
            return {
                query:function(sql){
                    DB.sqls.push(sql);
                    return new comb.Promise().callback(sql);
                }
            }
        },

        closeConnection:function(){
            this.closedCount++;
            return new comb.Promise().callback();
        },

        validate:function(){
            return new comb.Promise().callback(true);
        },

        execute:function(sql, opts){
            var ret = new comb.Promise();
            this.sqls.push(sql);
            ret.callback();
            return ret;
        },

        createTable:function(name, args){
            this.tables[name] = true;
            this._super(arguments);
            var match = this.sqls[this.sqls.length - 1].match(/ \(?(\w+) integer.*\)?$/);
            if (match != null) {
                this.columnsCreated.push(match[1]);
            }
            return new comb.Promise().callback();
        },

        dropTable:function(name){
            comb.argsToArray(arguments).forEach(function(name){
                this.droppedTables.push(name);
                this.tables[name] = null;
            }, this);
            return new comb.Promise().callback();
        },

        tableExists:function(name){
            return new comb.Promise().callback(!comb.isUndefinedOrNull(this.tables[name]));
        },

        alterTable:function(name){
            this.alteredTables[name] = true;
            this._super(arguments);
            var sql = this.sqls[this.sqls.length - 1]
            var match = sql.match(/ \(?(\w+) integer.*\)?$/);
            var alterMatch = sql.match(/(\w+) TO (\w+)$/);
            if (match != null) {
                this.columnsCreated.push(match[1]);
            }
            if (alterMatch != null) {
                this.columnsAltered[alterMatch[1]] = alterMatch[2];
            }
            return new comb.Promise().callback(1);
        },

        reset:function(){
            this.sqls = [];
            this.columnsCreated = [];
            this.droppedTables = [];
            this.columnsAltered = {};
            this.tables = {};
            this.alteredTables = {};
            patioMigrationVersion = 0;
            patioMigrationFiles = [];
        },

        getters:{
            dataset:function(){
                return new MockDS(this);
            }
        }
    }

});

var DB = new MockDB();

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        " raise and error if there is a missing integer migration version":{
            topic:function(){
                DB.reset();
                patio.migrate(DB, __dirname + "/migrations/files/missing_migration_file").then(hitch(this, "callback"), hitch(this, "callback", null));
            },

            " ":function(err){
                assert.deepEqual(err[0].message, "Migration error : Missing migration for 1");

            }
        },

        " raise and error if there is a duplicate integer migration version":{
            topic:function(){
                DB.reset();
                patio.migrate(DB, __dirname + "/migrations/files/duplicate_migration_file").then(hitch(this, "callback"), hitch(this, "callback", null));
            },

            " ":function(err){
                assert.deepEqual(err[0].message, "Migration error : Duplicate migration number 0");

            }
        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "add a column name if it doesn't already exist in the schemaInfo table":{
            topic:function(){
                DB.reset();
                DB.createTable("schema_info", function(){});
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration").then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(DB.alteredTables["schema_info"]);
                assert.isTrue(DB.columnsCreated.indexOf("version") != -1);
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "add a create a schemaInfoTable if it doesn't already exist":{
            topic:function(){
                DB.reset();
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration").then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(DB.tables["schema_info"])
                assert.isTrue(DB.columnsCreated.indexOf("version") != -1);
                DB.reset();
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "add a allow one to specify the schema and column":{
            topic:function(){
                DB.reset();
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration", {table:"migration_info", column:"mi"}).then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(DB.tables["migration_info"])
                assert.isTrue(DB.columnsCreated.indexOf("mi") != -1);
                DB.reset();
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "apply a migration correctly if no target is given":{
            topic:function(){
                DB.reset();
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration").then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(DB.tables["test1"]);
                assert.isTrue(DB.tables["test2"]);
                assert.isTrue(DB.tables["test3"]);
                assert.isTrue(DB.tables["test4"]);
                assert.isTrue(DB.alteredTables["test1"]);
                assert.isTrue(DB.alteredTables["test2"]);
                assert.isTrue(DB.alteredTables["test3"]);
                assert.isTrue(DB.alteredTables["test4"]);
                assert.deepEqual(DB.columnsAltered, {
                    column1:"column2",
                    column2:"column3",
                    column3:"column4",
                    column4:"column5"
                })

                DB.reset();
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "apply a migration correctly in the up direction if a target is given":{
            topic:function(){
                DB.reset();
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration", {target:2}).then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(DB.tables["test1"]);
                assert.isTrue(DB.tables["test2"]);
                assert.isTrue(DB.tables["test3"]);
                assert.isTrue(comb.isEmpty(DB.alteredTables));
                assert.isTrue(comb.isEmpty(DB.columnsAltered));
                assert.equal(patioMigrationVersion, 2);
                DB.reset();
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "apply a migration correctly in the down direction if a target is given":{
            topic:function(){
                DB.reset();
                DB.createTable("schema_info", function(){
                    this.version("integer", {"default":0});
                });
                DB.from("schema_info").update({version:3});
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration", {target:0}).then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.deepEqual(DB.droppedTables, ["test4", "test3", "test2", "test1"])
                assert.equal(patioMigrationVersion, 0);
                assert.isTrue(comb.isEmpty(DB.alteredTables));
                assert.isTrue(comb.isEmpty(DB.columnsAltered))
                DB.reset();
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "apply a migration correctly in the down direction if a target and current is given":{
            topic:function(){
                DB.reset();
                DB.createTable("schema_info", function(){
                    this.version("integer", {"default":0});
                });
                DB.from("schema_info").update({version:3});
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration", {target:0, current:4}).then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.deepEqual(DB.droppedTables, ["test4", "test3", "test2", "test1"])
                assert.equal(patioMigrationVersion, 0);
                assert.isTrue(DB.alteredTables["test1"]);
                assert.isTrue(DB.alteredTables["test2"]);
                assert.isTrue(DB.alteredTables["test3"]);
                assert.isTrue(DB.alteredTables["test4"]);
                assert.deepEqual(DB.columnsAltered, {
                    column2:"column1",
                    column3:"column2",
                    column4:"column3",
                    column5:"column4"
                })

                DB.reset();
            }

        }
    }
});

suite.addBatch({
    "An Integer migrator should ":{
        topic:DB,

        "apply return the correct target number":{
            topic:function(){
                DB.reset();
                var ret = [];
                patio.migrate(DB, __dirname + "/migrations/files/basic_integer_migration", {target:4, current:2})
                    .addCallback(comb.hitch(ret, "push"))
                    .chain(comb.hitch(patio, "migrate", DB, __dirname + "/migrations/files/basic_integer_migration", {target:0}), hitch(this, "callback"))
                    .addCallback(comb.hitch(ret, "push"))
                    .chain(comb.hitch(patio, "migrate", DB, __dirname + "/migrations/files/basic_integer_migration"), hitch(this, "callback"))
                    .addCallback(comb.hitch(ret, "push"))
                    .then(hitch(this, "callback", null, ret), hitch(this, "callback"));

            },

            "":function(res){
                assert.deepEqual(res, [4, 0, 4]);
                DB.reset();
            }

        }
    }
});

var MockTimestampDs = comb.define(MockDS, {
    instance:{

        fetchRows:function(sql, cb){
            var from = this.__opts.from[0], ret = new comb.Promise();
            if (from.toString() === "schema_info") {
                ret.callback(cb({version:patioMigrationVersion}));
            } else if (from.toString() === "schema_migrations") {
                sortMigrationFiles();
                ret.callback(patioMigrationFiles.forEach(function(f){
                    cb({filename:f});
                }));
            } else if (from.toString() === "sm") {
                ret.callback(patioMigrationFiles.forEach(function(f){
                    cb({fn:f});
                }));
            }
            return ret;
        },

        insert:function(values){
            var from = this.__opts.from[0].toString(), ret = new comb.Promise().callback(0);
            if (from == "schema_info") {
                patioMigrationVersion = values[Object.keys(values)[0]];
            } else if (from == "schema_migrations" || from === "sm") {
                patioMigrationFiles.push(values[Object.keys(values)[0]])
            }
            return ret;
        },

        remove:function(){
            var from = this.__opts.from[0].toString(), ret = new comb.Promise().callback(1);
            if (from == "schema_migrations" || from === "sm") {
                var where = this.__opts.where.args, index = patioMigrationFiles.indexOf(where[where.length - 1]);
                if (index > -1) {
                    patioMigrationFiles.splice(index, 1);
                }
            }
            return ret;
        },

        getters:{
            columns:function(){
                var from = this.__opts.from[0].toString(), ret = new comb.Promise();
                if (from === "schema_info") {
                    ret.callback(["version"]);
                } else if (from === "schema_migrations") {
                    ret.callback(["filename"]);
                } else if (from === "sm") {
                    ret.callback(["fn"]);
                }
                return ret;
            }
        }
    }
});

var MockTimestampDB = comb.define(MockDB, {
    instance:{
        getters:{
            dataset:function(){
                return new MockTimestampDs(this);
            }
        }
    }
});

var TSDB = new MockTimestampDB();
suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        "migrate all the way up":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration").then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.isTrue(TSDB.tables["test4"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3", "column4"]);
                assert.lengthOf(patioMigrationFiles, 4);
                assert.deepEqual(patioMigrationFiles, ["create_table.1327997153.js", "create_table.1327997224.js", "migration.1327997243.js", "migration.1327997262.js"]);
            },

            " and migrate all the way down":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration", {target:0}).then(hitch(this, "callback", null), hitch(this, "callback"));

                },

                "":function(res){
                    assert.isNull(TSDB.tables["test1"]);
                    assert.isNull(TSDB.tables["test2"]);
                    assert.isNull(TSDB.tables["test3"]);
                    assert.isNull(TSDB.tables["test4"]);
                    assert.deepEqual(TSDB.droppedTables, ["test4", "test3", "test2", "test1"]);
                    assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3", "column4"]);
                    assert.lengthOf(patioMigrationFiles, 0)
                    TSDB.reset();
                }

            }

        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        "migrate all the way up to a timestamp":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration", {target:1327997243}).then(hitch(this, "callback", null), hitch(this, "callback"));

            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3"]);
                assert.lengthOf(patioMigrationFiles, 3);
                assert.deepEqual(patioMigrationFiles, ["create_table.1327997153.js", "create_table.1327997224.js", "migration.1327997243.js"]);
            },

            " and migrate all the way down to a timestamp":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration", {target:0}).then(hitch(this, "callback", null), hitch(this, "callback"));

                },

                "":function(res){
                    assert.isNull(TSDB.tables["test1"]);
                    assert.isNull(TSDB.tables["test2"]);
                    assert.isNull(TSDB.tables["test3"]);
                    assert.deepEqual(TSDB.droppedTables, ["test3", "test2", "test1"]);
                    assert.lengthOf(patioMigrationFiles, 0)
                    TSDB.reset();
                }

            }

        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        "migrate all the way up ":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration").then(hitch(this, "callback", null), hitch(this, "callback"));
            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3", "column4"]);
                assert.lengthOf(patioMigrationFiles, 4);
                assert.deepEqual(patioMigrationFiles, ["create_table.1327997153.js", "create_table.1327997224.js", "migration.1327997243.js", 'migration.1327997262.js']);
            },

            " and apply missing files":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/interleaved_timestamp_migrations").then(hitch(this, "callback", null), hitch(this, "callback"));

                },

                "":function(res){
                    assert.isTrue(TSDB.tables["test1"]);
                    assert.isTrue(TSDB.tables["test2"]);
                    assert.isTrue(TSDB.tables["test3"]);
                    assert.lengthOf(TSDB.droppedTables, 0);
                    assert.isTrue(TSDB.alteredTables["test1"]);
                    assert.isTrue(TSDB.alteredTables["test2"]);
                    assert.isTrue(TSDB.alteredTables["test3"]);
                    assert.isTrue(TSDB.alteredTables["test4"]);
                    assert.deepEqual(TSDB.columnsAltered, {
                        column1:"column2",
                        column2:"column3",
                        column3:"column4",
                        column4:"column5"
                    })
                    assert.lengthOf(patioMigrationFiles, 8);
                    assert.deepEqual(patioMigrationFiles, ['create_table.1327997153.js',
                        'create_table.1327997224.js',
                        'migration.1327997243.js',
                        'migration.1327997262.js',
                        'create_table.1327997155.js',
                        'create_table.1327997230.js',
                        'migration.1327997250.js',
                        'migration.1327997265.js']);
                    TSDB.reset();
                }

            }

        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        "migrate all the way up ":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration").then(hitch(this, "callback", null), hitch(this, "callback"));
            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3", "column4"]);
                assert.lengthOf(patioMigrationFiles, 4);
                assert.deepEqual(patioMigrationFiles, ["create_table.1327997153.js", "create_table.1327997224.js", "migration.1327997243.js", 'migration.1327997262.js']);
            },

            " and not apply down action when up action has not been called":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/interleaved_timestamp_migrations", {target:0}).then(hitch(this, "callback", null), hitch(this, "callback"));

                },

                "":function(res){
                    assert.lengthOf(TSDB.droppedTables, 4);
                    assert.deepEqual(TSDB.droppedTables, ["test4", "test3", "test2", "test1"]);
                    assert.isTrue(comb.isEmpty(TSDB.alteredTables));
                    assert.deepEqual(TSDB.columnsAltered, {})
                    assert.lengthOf(patioMigrationFiles, 0);
                    TSDB.reset();
                }

            }

        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        "migrate all the way up ":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/timestamp_migration").then(hitch(this, "callback", null), hitch(this, "callback"));
            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3", "column4"]);
                assert.lengthOf(patioMigrationFiles, 4);
                assert.deepEqual(patioMigrationFiles, ["create_table.1327997153.js", "create_table.1327997224.js", "migration.1327997243.js", 'migration.1327997262.js']);
            },

            " and apply missing files up to a certain timestamp":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/interleaved_timestamp_migrations", {target:1327997262}).then(hitch(this, "callback", null), hitch(this, "callback"));

                },

                "":function(res){
                    assert.isTrue(TSDB.tables["test1"]);
                    assert.isTrue(TSDB.tables["test2"]);
                    assert.isTrue(TSDB.tables["test3"]);
                    assert.lengthOf(TSDB.droppedTables, 0);
                    assert.isTrue(TSDB.alteredTables["test1"]);
                    assert.isTrue(TSDB.alteredTables["test2"]);
                    assert.isTrue(TSDB.alteredTables["test3"]);
                    assert.isUndefined(TSDB.alteredTables["test4"]);
                    assert.deepEqual(TSDB.columnsAltered, {
                        column1:"column2",
                        column2:"column3",
                        column3:"column4"
                    });
                    assert.lengthOf(patioMigrationFiles, 7);
                    sortMigrationFiles();
                    assert.deepEqual(patioMigrationFiles, [
                        'create_table.1327997153.js',
                        'create_table.1327997155.js',
                        'create_table.1327997224.js',
                        'create_table.1327997230.js',
                        'migration.1327997243.js',
                        'migration.1327997250.js',
                        'migration.1327997262.js']);
                    TSDB.reset();
                }

            }

        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        " handle a bad migration file when migrating up":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/bad_timestamp_migration").then(hitch(this, "callback"), hitch(this, "callback", null));
            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column2", "column3"]);
                assert.lengthOf(patioMigrationFiles, 3);
                sortMigrationFiles();
                assert.deepEqual(patioMigrationFiles, ['create_table.1327997153.js', 'create_table.1327997224.js', 'migration.1327997243.js']);
            },

            " and down ":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/bad_timestamp_migration", {target:0}).then(hitch(this, "callback"), hitch(this, "callback", null));
                },

                "":function(res){
                    assert.isTrue(TSDB.tables["test1"]);
                    assert.isNull(TSDB.tables["test2"]);
                    assert.isNull(TSDB.tables["test3"]);
                    assert.lengthOf(patioMigrationFiles, 1);
                    sortMigrationFiles();
                    assert.deepEqual(patioMigrationFiles, ['create_table.1327997153.js']);
                }
            }
        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        " handle a duplicate timestamps when migrating up ":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/duplicate_timestamp_migration").then(hitch(this, "callback"), hitch(this, "callback", null));
            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.isTrue(TSDB.tables["test4"]);
                assert.isTrue(TSDB.tables["test5"]);
                assert.deepEqual(TSDB.columnsCreated, ["column1", "column5", "column2", "column3", "column4"]);
                assert.lengthOf(patioMigrationFiles, 5);
                sortMigrationFiles();
                assert.deepEqual(patioMigrationFiles, [
                    'create_table.1327997153.js',
                    'migration.1327997153.js',
                    'create_table.1327997224.js',
                    'migration.1327997243.js',
                    'migration.1327997262.js'
                ]);
            },

            " and down ":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/duplicate_timestamp_migration", {target:0}).then(hitch(this, "callback"), hitch(this, "callback", null));
                },

                "":function(res){
                    assert.isNull(TSDB.tables["test1"]);
                    assert.isNull(TSDB.tables["test2"]);
                    assert.isNull(TSDB.tables["test3"]);
                    assert.isNull(TSDB.tables["test4"]);
                    assert.isNull(TSDB.tables["test5"]);
                    assert.lengthOf(patioMigrationFiles, 0);
                }
            }
        }
    }
});

suite.addBatch({
    "An Timestamp migrator should ":{
        topic:DB,

        " convert integer migrations when migrating up ":{
            topic:function(){
                TSDB.reset();
                var ret = [];
                patio.migrate(TSDB, __dirname + "/migrations/files/basic_integer_migration")
                    .chain(comb.hitch(patio, "migrate", TSDB, __dirname + "/migrations/files/both_migration"), hitch(this, "callback", null))
                    .then(hitch(this, "callback"), hitch(this, "callback", null));
            },

            "":function(res){
                assert.isTrue(TSDB.tables["test1"]);
                assert.isTrue(TSDB.tables["test2"]);
                assert.isTrue(TSDB.tables["test3"]);
                assert.isTrue(TSDB.tables["test4"]);
                assert.isTrue(TSDB.tables["test5"]);
                assert.deepEqual(TSDB.columnsCreated, ["version", "column1", "column2", "column3", "column4", "column5"]);
                assert.deepEqual(TSDB.columnsAltered, {
                    column1:"column2",
                    column2:"column3",
                    column3:"column4",
                    column4:"column5",
                    column5:"column6"
                });
                assert.lengthOf(patioMigrationFiles, 7);
                sortMigrationFiles();
                assert.deepEqual(patioMigrationFiles, [
                    'create_tables.0.js',
                    'create_2.1.js',
                    'create_table.2.js',
                    'create_3.3.js',
                    'alter_tables.4.js',
                    'create_table.1327997153.js',
                    'create_table.1327997224.js']);
            },

            " and down ":{
                topic:function(){
                    var ret = [];
                    patio.migrate(TSDB, __dirname + "/migrations/files/both_migration", {target:0}).then(hitch(this, "callback"), hitch(this, "callback", null));
                },

                "":function(res){
                    assert.isNull(TSDB.tables["test1"]);
                    assert.isNull(TSDB.tables["test2"]);
                    assert.isNull(TSDB.tables["test3"]);
                    assert.isNull(TSDB.tables["test4"]);
                    assert.isNull(TSDB.tables["test5"]);
                    assert.lengthOf(patioMigrationFiles, 0);
                }
            }
        }
    }
});

suite.run({reporter:require("vows").reporter.spec}, function(){
    ret.callback();
});


text:
casper.test.begin('grid', 73, function (test) {

  casper
  .start('examples/grid/index.html')
  .then(function () {
    // headers
    test.assertElementCount('th', 2)
    test.assertElementCount('th.active', 0)
    test.assertSelectorHasText('th:nth-child(1)', 'Name')
    test.assertSelectorHasText('th:nth-child(2)', 'Power')
    assertTable(test, ['name', 'power'], [
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 }
    ])
  })
  // test sorting
  .thenClick('th:nth-child(1)', function () {
    test.assertElementCount('th.active:nth-child(1)', 1)
    test.assertElementCount('th.active:nth-child(2)', 0)
    test.assertElementCount('th:nth-child(1) .arrow.dsc', 1)
    test.assertElementCount('th:nth-child(2) .arrow.dsc', 0)
    assertTable(test, ['name', 'power'], [
      { name: 'Jet Li', power: 8000 },
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Bruce Lee', power: 9000 }
    ])
  })
  .thenClick('th:nth-child(2)', function () {
    test.assertElementCount('th.active:nth-child(1)', 0)
    test.assertElementCount('th.active:nth-child(2)', 1)
    test.assertElementCount('th:nth-child(1) .arrow.dsc', 1)
    test.assertElementCount('th:nth-child(2) .arrow.dsc', 1)
    assertTable(test, ['name', 'power'], [
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Jet Li', power: 8000 },
      { name: 'Jackie Chan', power: 7000 }
    ])
  })
  .thenClick('th:nth-child(2)', function () {
    test.assertElementCount('th.active:nth-child(1)', 0)
    test.assertElementCount('th.active:nth-child(2)', 1)
    test.assertElementCount('th:nth-child(1) .arrow.dsc', 1)
    test.assertElementCount('th:nth-child(2) .arrow.asc', 1)
    assertTable(test, ['name', 'power'], [
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 },
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Chuck Norris', power: Infinity }
    ])
  })
  .thenClick('th:nth-child(1)', function () {
    test.assertElementCount('th.active:nth-child(1)', 1)
    test.assertElementCount('th.active:nth-child(2)', 0)
    test.assertElementCount('th:nth-child(1) .arrow.asc', 1)
    test.assertElementCount('th:nth-child(2) .arrow.asc', 1)
    assertTable(test, ['name', 'power'], [
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 }
    ])
  })
  // test search
  .then(function () {
    this.fill('#search', {
      query: 'j'
    })
  })
  .then(function () {
    assertTable(test, ['name', 'power'], [
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 }
    ])
  })
  .then(function () {
    this.fill('#search', {
      query: 'infinity'
    })
  })
  .then(function () {
    assertTable(test, ['name', 'power'], [
      { name: 'Chuck Norris', power: Infinity }
    ])
  })
  // run
  .run(function () {
    test.done()
  })

  /**
   * Helper to assert the table data is rendered correctly.
   *
   * @param {CasperTester} test
   * @param {Array} columns
   * @param {Array} data
   */

  function assertTable (test, columns, data) {
    test.assertElementCount('td', data.length * columns.length)
    for (var i = 0; i < data.length; i++) {
      for (var j = 0; j < columns.length; j++) {
        test.assertSelectorHasText(
          'tr:nth-child(' + (i + 1) + ') td:nth-child(' + (j + 1) + ')',
          data[i][columns[j]]
        )
      }
    }
  }

})

redpajama_set_name: RedPajamaGithub


text:
Tracker.autorun(function(tracker) {
	try {
		UserStatus.startMonitor({
			idleOnBlur: true
		});
		return tracker.stop();
	} catch(error) {
		console.log(error);
	}
});

Template.registerHelper("gameNameFromKey", function(gameKey) {
	var definition = GameDefinitions.findOne({"gameKey": gameKey});
	if(definition) {
		return definition.gameName;
	}
	return "";
});

Template.entry.events({
	"click #loginFacebook": function(e) {
		Meteor.loginWithFacebook({
			requestPermissions: ['email', 'public_profile', 'user_friends']
		}, function(error) {
			if(error) {
				console.log(error);
			}
		});
	}
});

Template.navigation.helpers({
	"username": function() {
		if(Meteor.user().username) {
			return Meteor.user().username;
		}
		return Meteor.user().profile.name;
	}
});

Template.navigation.events({
	"click #logout": function() {
		Meteor.logout();
	}
});

Template.createGame.helpers({
	"gameDefinitions": function() {
		return GameDefinitions.find();
	}
});

Template.createGame.events({
	"submit form": function(e) {
		e.preventDefault();
		var gameType = e.target.gameType.value.trim();
		var lobbyName = e.target.lobbyName.value.trim();
		var lobbyPassword = e.target.lobbyPassword.value.trim();
		var callback = function(error, data) {
			if(error) {
				console.log(error);
			}
			else {
				console.log(data);
			}
		};

		if(lobbyPassword) {
			Meteor.call("createGame", gameType, lobbyName, lobbyPassword, callback);
		}
		else {
			Meteor.call("createGame", gameType, lobbyName, callback);
		}
	}
});

Template.activeGames.onCreated(function() {
	this.subscribe("gameList");
});

Template.activeGames.helpers({
	"games": function() {
		return Games.find({"players": {$elemMatch: {"_id": Meteor.userId()}}}, {
			sort: {
				"gameName": 1,
				"lobbyData.lobbyName": 1
			}
		});
	},
	"creator": function() {
		return this.players[0]._id;
	},
	"playerCount": function() {
		return this.players.length;
	},
	"maxPlayers": function(gameKey) {
		var definition = GameDefinitions.findOne({"gameKey": gameKey});
		if(definition.maxPlayers) {
			return definition.maxPlayers;
		}
		return "∞";
	}
});

Template.searchGames.onCreated(function() {
	var instance = this;

	instance.searchLobbyName = new ReactiveVar("");
	instance.searchPassword = new ReactiveVar("");
	instance.autorun(function() {
		instance.subscribe("gameList", instance.searchLobbyName.get(), instance.searchPassword.get());
	});
});

Template.searchGames.helpers({
	"games": function() {
		return Games.find({"players": {$not: {$elemMatch: {"_id": Meteor.userId()}}}}, {
			sort: {
				"gameName": 1,
				"lobbyData.lobbyName": 1
			}
		});
	},
	"creator": function() {
		return this.players[0]._id;
	},
	"playerCount": function() {
		return this.players.length;
	},
	"maxPlayers": function(gameKey) {
		var definition = GameDefinitions.findOne({"gameKey": gameKey});
		if(definition.maxPlayers) {
			return definition.maxPlayers;
		}
		return "∞";
	}
});

Template.searchGames.events({
	"submit form": function(e) {
		e.preventDefault();
		Template.instance().searchLobbyName.set(e.target.gameName.value);
		Template.instance().searchPassword.set(e.target.password.value);
	}
});

Template.gamelist.helpers({
	"users": function() {
		return Meteor.users.find();
	}
});

Template.gamelist.events({
	"click .cover": function(e) {

	}
});


text:
package com.riversoforion.orinoco.core.convert;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import org.junit.Test;

import com.riversoforion.acheron.patterns.ConversionException;

public class ByteConverterTest {

    private ByteConverter testConverter = new ByteConverter();

    @Test
    public void testUnconvert() {

        String s = this.testConverter.unconvert((byte) 123);
        assertEquals("123", s);
    }

    @Test
    public void testUnconvert_NullValue() {

        String s = this.testConverter.unconvert(null);
        assertNull(s);
    }

    @Test
    public void testConvert() {

        Byte b = this.testConverter.convert("123");
        assertEquals((byte) 123, b.byteValue());
    }

    @Test
    public void testConvert_NullValue() {

        Byte b = this.testConverter.convert(null);
        assertNull(b);
    }

    @Test(expected = ConversionException.class)
    public void testConvert_NonNumeric() {

        this.testConverter.convert("abc");
    }
}