<commit_before>var test = require('tape')

var constructors = require('../src/inheritance.js')
var Rectangle = constructors.Rectangle
var Square = constructors.Square

test('Rectangle constructor', function (t) {
  t.plan(3)

  t.equal(typeof Rectangle, 'function', 'should be a function')
  var rec = new Rectangle(5, 10)
  t.equal(rec.width, 5, 'should set rectangle width')
  t.equal(rec.height, 10, 'should set rectangle height')
})

test('Square constructor', function (t) {
  t.plan(3)

  t.equal(typeof Square, 'function', 'should be a function')
  var squ = new Square(7)
  t.equal(squ.width, 7, 'should set square width')
  t.equal(squ.height, 7, 'should set square height')
})

test('Rectangle::area', function (t) {
  t.plan(3)

  var rec = new Rectangle(5, 10)
  t.equal(typeof rec.area, 'function', 'should be a function')
  t.equal(rec.area(), 50, 'should calculate correctly')
  t.ok(Rectangle.prototype.hasOwnProperty('area'), 'resides in prototype')
})

test('Square::area', function (t) {
  t.plan(3)

  var squ = new Square(7)
  t.equal(typeof squ.area, 'function', 'should be a function')
  t.notOk(Square.prototype.hasOwnProperty('area'), 'should not reside in prototype')
  t.equal(squ.area, Rectangle.prototype.area, 'should be inherited from Rectangle')
})

test('Rectangle/Square::description', function (t) {
  t.plan(4)

  var rec = new Rectangle(5, 10)
  t.equal(typeof rec.description, 'function', 'should be a function')
  t.equal(rec.description(), 'Rectangle of width 5, height 10 and area 50.', 'should return rectangle\'s description')

  var squ = new Square(7)
  t.equal(typeof squ.description, 'function', 'should be a function')
  t.equal(squ.description(), 'Square of side 7 and area 49.', 'should return square\'s description')
})
<commit_msg>add check for method not an instance property<commit_after>var test = require('tape')

var constructors = require('../src/inheritance.js')
var Rectangle = constructors.Rectangle
var Square = constructors.Square

test('Rectangle constructor', function (t) {
  t.plan(3)

  t.equal(typeof Rectangle, 'function', 'should be a function')
  var rec = new Rectangle(5, 10)
  t.equal(rec.width, 5, 'should set rectangle width')
  t.equal(rec.height, 10, 'should set rectangle height')
})

test('Square constructor', function (t) {
  t.plan(3)

  t.equal(typeof Square, 'function', 'should be a function')
  var squ = new Square(7)
  t.equal(squ.width, 7, 'should set square width')
  t.equal(squ.height, 7, 'should set square height')
})

test('Rectangle::area', function (t) {
  t.plan(3)

  var rec = new Rectangle(5, 10)
  t.equal(typeof rec.area, 'function', 'should be a function')
  t.equal(rec.area(), 50, 'should calculate correctly')
  t.ok(Rectangle.prototype.hasOwnProperty('area'), 'resides in prototype')
})

test('Square::area', function (t) {
  t.plan(4)

  var squ = new Square(7)
  t.equal(typeof squ.area, 'function', 'should be a function')
  t.notOk(squ.hasOwnProperty('area'), 'should not be an instance property')
  t.notOk(Square.prototype.hasOwnProperty('area'), 'should not reside in prototype')
  t.equal(squ.area, Rectangle.prototype.area, 'should be inherited from Rectangle')
})

test('Rectangle/Square::description', function (t) {
  t.plan(4)

  var rec = new Rectangle(5, 10)
  t.equal(typeof rec.description, 'function', 'should be a function')
  t.equal(rec.description(), 'Rectangle of width 5, height 10 and area 50.', 'should return rectangle\'s description')

  var squ = new Square(7)
  t.equal(typeof squ.description, 'function', 'should be a function')
  t.equal(squ.description(), 'Square of side 7 and area 49.', 'should return square\'s description')
})
<|endoftext|>


<commit_before>var injection = require('../services/injection.js');
var Q = require('q');
var mongoose = require('mongoose');

module.exports = function (test, fixtureName, testFn) {
    var dbUrl = 'mongodb://localhost:27017/' + fixtureName;

    var cleanUp = function () {
        var deferred = Q.defer();
        var connection = mongoose.createConnection(dbUrl);

        connection.on('connected', function () {
            deferred.resolve(connection.db);
        });

        return deferred.promise.then(function (db) {
            return Q.nbind(db.dropDatabase, db)().then(function () {
                return Q.nbind(mongoose.disconnect, mongoose)().then(function () {
                    mongoose.connections = [];
                })
            });
        });
    };

    cleanUp().then(function () {
        var allcountServer = require('../allcount-server.js');

        injection.resetInjection();
        injection.bindFactory('port', 9080);
        injection.bindFactory('dbUrl', dbUrl);
        injection.bindFactory('gitRepoUrl', 'test-fixtures/' + fixtureName);

        allcountServer.reconfigureAllcount();
        return allcountServer.inject('allcountServerStartup');
    }).then(function (server) {
        return Q.nbind(server.startup, server)().then(function (errors) {
            if (errors) {
                throw new Error(errors.join('\n'));
            }
            return Q(testFn()).then(function () {
                return server.stop().then(function () {
                    injection.resetInjection();
                });
            });
        });
    }).finally(cleanUp).then(function () {
        test.done();
    }, function (err) {
        test.done(err);
    })
};<commit_msg>Add logging to figure out why travis build stalled<commit_after>var injection = require('../services/injection.js');
var Q = require('q');
var mongoose = require('mongoose');

module.exports = function (test, fixtureName, testFn) {
    var dbUrl = 'mongodb://localhost:27017/' + fixtureName;

    var cleanUp = function () {
        var deferred = Q.defer();
        var connection = mongoose.createConnection(dbUrl);

        connection.on('connected', function () {
            deferred.resolve(connection.db);
        });

        console.log("Making clean up for integration tests");
        return deferred.promise.then(function (db) {
            console.log("Making clean up: connected");
            return Q.nbind(db.dropDatabase, db)().then(function () {
                console.log("Making clean up: dropped db");
                return Q.nbind(mongoose.disconnect, mongoose)().then(function () {
                    console.log("Making clean up: success");
                    mongoose.connections = [];
                })
            });
        });
    };

    cleanUp().then(function () {
        console.log("Starting server for integration tests");
        var allcountServer = require('../allcount-server.js');

        injection.resetInjection();
        injection.bindFactory('port', 9080);
        injection.bindFactory('dbUrl', dbUrl);
        injection.bindFactory('gitRepoUrl', 'test-fixtures/' + fixtureName);

        allcountServer.reconfigureAllcount();
        return allcountServer.inject('allcountServerStartup');
    }).then(function (server) {
        console.log("Starting server: injection config done");
        return Q.nbind(server.startup, server)().then(function (errors) {
            console.log("Starting server: success");
            if (errors) {
                throw new Error(errors.join('\n'));
            }
            return Q(testFn()).then(function () {
                console.log("Stopping server...");
                return server.stop().then(function () {
                    console.log("Stopping server: ok!");
                    injection.resetInjection();
                });
            });
        });
    }).finally(cleanUp).then(function () {
        test.done();
    }, function (err) {
        test.done(err);
    })
};<|endoftext|>


<commit_before>describe("Player", function() {
  var player;
  var song;

  beforeEach(function() {
    player = new Player();
    song = new Song();
  });

  it("should be able to play a Song", function() {
    player.play(song);
    expect(player.currentlyPlayingSong).toEqual(song);

    //demonstrates use of custom matcher
    expect(player).toBePlaying(song);
  });

  describe("when song has been paused", function() {
    beforeEach(function() {
      player.play(song);
      player.pause();
    });

    it("should indicate that the song is currently paused", function() {
      expect(player.isPlaying).toBeFalsy();

      // demonstrates use of 'not' with a custom matcher
      expect(player).not.toBePlaying(song);
    });

    it("should be possible to resume", function() {
      player.resume();
      expect(player.isPlaying).toBeTruthy();
      expect(player.currentlyPlayingSong).toEqual(song);
    });
  });

  // demonstrates use of spies to intercept and test method calls
  it("tells the current song if the user has made it a favorite", function() {
    spyOn(song, 'persistFavoriteStatus');

    player.play(song);
    player.makeFavorite();

    expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
  });

  //demonstrates use of expected exceptions
  describe("#resume", function() {
    it("should throw an exception if song is already playing", function() {
      player.play(song);

      expect(function() {
        player.resume();
      }).toThrow("song is already playing");
    });
  });
});<commit_msg>Failing a spec on purpose<commit_after>describe("Player", function() {
  var player;
  var song;

  beforeEach(function() {
    player = new Player();
    song = new Song();
  });

  it("should be able to play a Song", function() {
    player.play(song);
    expect(player.currentlyPlayingSong).toEqual(song);

    //demonstrates use of custom matcher
    expect(player).toBePlaying(song);
  });

  describe("when song has been paused", function() {
    beforeEach(function() {
      player.play(song);
      player.pause();
    });

    it("should indicate that the song is currently paused", function() {
      expect(player.isPlaying).toBeTruthy();

      // demonstrates use of 'not' with a custom matcher
      expect(player).not.toBePlaying(song);
    });

    it("should be possible to resume", function() {
      player.resume();
      expect(player.isPlaying).toBeTruthy();
      expect(player.currentlyPlayingSong).toEqual(song);
    });
  });

  // demonstrates use of spies to intercept and test method calls
  it("tells the current song if the user has made it a favorite", function() {
    spyOn(song, 'persistFavoriteStatus');

    player.play(song);
    player.makeFavorite();

    expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
  });

  //demonstrates use of expected exceptions
  describe("#resume", function() {
    it("should throw an exception if song is already playing", function() {
      player.play(song);

      expect(function() {
        player.resume();
      }).toThrow("song is already playing");
    });
  });
});<|endoftext|>


<commit_before>/* @flow */

import { pick } from 'lodash'
import {
  after,
  afterEach,
  before,
  beforeEach,
  suite,
  test
} from 'mocha'
import path from 'path'
import should from 'should'

import pouchdbBuilders from '../support/builders/pouchdb'
import configHelpers from '../support/helpers/config'
import * as cozyHelpers from '../support/helpers/cozy'
import pouchHelpers from '../support/helpers/pouch'
import { IntegrationTestHelpers } from '../support/helpers/integration'

suite('Move', () => {
  if (process.env.APPVEYOR) {
    test('is unstable on AppVeyor')
    return
  }

  let cozy, helpers, pouch, prep

  before(configHelpers.createConfig)
  before(configHelpers.registerClient)
  beforeEach(pouchHelpers.createDatabase)
  beforeEach(cozyHelpers.deleteAll)

  afterEach(() => helpers.local.clean())
  afterEach(pouchHelpers.cleanDatabase)
  after(configHelpers.cleanConfig)

  beforeEach(async function () {
    cozy = cozyHelpers.cozy
    helpers = new IntegrationTestHelpers(this.config, this.pouch, cozy)
    pouch = helpers._pouch
    prep = helpers.prep

    await helpers.local.setupTrash()
    await helpers.remote.ignorePreviousChanges()
  })

  suite('file', () => {
    let file, src

    beforeEach(async () => {
      await cozy.files.createDirectory({name: 'dst'})
      src = await cozy.files.createDirectory({name: 'src'})
      file = await cozy.files.create('foo', {name: 'file', dirID: src._id})

      await helpers.remote.pullChanges()
      await helpers.syncAll()
      helpers.spyPouch()
    })

    test('local', async () => {
      const oldFile = await pouch.byRemoteIdMaybeAsync(file._id)
      await prep.moveFileAsync('local', {
        path: 'dst/file',
        updated_at: '2017-06-19T08:19:26.769Z',
        ...pick(oldFile, ['docType', 'md5sum', 'mime', 'class', 'size'])
      }, oldFile)

      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        {path: path.normalize('src/file'), _deleted: true},
        {path: path.normalize('dst/file')}
      ])

      await helpers.syncAll()

      should(await helpers.remote.tree()).deepEqual([
        '.cozy_trash/',
        'dst/',
        'dst/file',
        'src/'
      ])
    })

    test('remote', async () => {
      const oldFile = await pouch.byRemoteIdMaybeAsync(file._id)
      await prep.moveFileAsync('remote', {
        ...pick(oldFile, ['docType', 'size', 'md5sum', 'class', 'mime', 'tags']),
        path: 'dst/file',
        updated_at: '2017-06-19T08:19:26.769Z',
        remote: {
          _id: file._id,
          _rev: pouchdbBuilders.rev()
        }
      }, oldFile)

      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        {path: path.normalize('src/file'), _deleted: true},
        {path: path.normalize('dst/file')}
      ])

      await helpers.syncAll()

      should(await helpers.local.tree()).deepEqual([
        'dst/',
        'dst/file',
        'src/'
      ])
    })
  })

  suite('directory', () => {
    let dir, dst, emptySubdir, file, parent, src, subdir

    beforeEach(async () => {
      parent = await cozy.files.createDirectory({name: 'parent'})
      dst = await cozy.files.createDirectory({name: 'dst', dirID: parent._id})
      src = await cozy.files.createDirectory({name: 'src', dirID: parent._id})
      dir = await cozy.files.createDirectory({name: 'dir', dirID: src._id})
      emptySubdir = await cozy.files.createDirectory({name: 'empty-subdir', dirID: dir._id})
      subdir = await cozy.files.createDirectory({name: 'subdir', dirID: dir._id})
      file = await cozy.files.create('foo', {name: 'file', dirID: subdir._id})

      await helpers.remote.pullChanges()
      await helpers.syncAll()
      helpers.spyPouch()
    })

    test('local', async () => {
      const oldFolder = await pouch.byRemoteIdMaybeAsync(dir._id)

      await prep.moveFolderAsync('local', {
        path: 'parent/dst/dir', docType: 'file'
      }, oldFolder)

      should(helpers.putDocs('path', '_deleted', 'trashed', 'childMove')).deepEqual([
        {path: path.normalize('parent/src/dir'), _deleted: true},
        {path: path.normalize('parent/dst/dir')},
        {path: path.normalize('parent/src/dir/empty-subdir'), _deleted: true, childMove: true},
        {path: path.normalize('parent/dst/dir/empty-subdir')},
        {path: path.normalize('parent/src/dir/subdir'), _deleted: true, childMove: true},
        {path: path.normalize('parent/dst/dir/subdir')},
        {path: path.normalize('parent/src/dir/subdir/file'), _deleted: true, childMove: true},
        {path: path.normalize('parent/dst/dir/subdir/file')}
      ])

      await helpers.syncAll()

      should(await helpers.remote.tree()).deepEqual([
        '.cozy_trash/',
        'parent/',
        'parent/dst/',
        'parent/dst/dir/',
        'parent/dst/dir/empty-subdir/',
        'parent/dst/dir/subdir/',
        'parent/dst/dir/subdir/file',
        'parent/src/'
      ])
    })

    test('from remote cozy', async () => {
      await cozy.files.updateAttributesById(dir._id, {dir_id: dst._id})
      await helpers.remote.pullChanges()

      /* FIXME: Nondeterministic
      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        {path: 'parent/src/dir/subdir/file', _deleted: true},
        {path: 'parent/src/dir/subdir', _deleted: true},
        {path: 'parent/src/dir/empty-subdir', _deleted: true},
        {path: 'parent/src/dir', _deleted: true},
        {path: 'parent/dst/dir'},
        {path: 'parent/dst/dir/subdir'},
        {path: 'parent/dst/dir/empty-subdir'}
      ])
      */
      await helpers.syncAll()
      should(await helpers.local.tree()).deepEqual([
        'parent/',
        'parent/dst/',
        'parent/dst/dir/',
        'parent/dst/dir/empty-subdir/',
        'parent/dst/dir/subdir/',
        'parent/dst/dir/subdir/file',
        'parent/src/'
      ])
    })

    test('from remote client', async () => {
      // FIXME: Ensure events occur in the same order as resulting from the
      // local dir test
      await helpers._remote.addFolderAsync({
        ...await pouch.byRemoteIdAsync(dir._id),
        path: path.normalize('parent/dst/dir'),
        updated_at: '2017-06-20T12:58:49.681Z'
      })
      await helpers._remote.addFolderAsync({
        ...await pouch.byRemoteIdAsync(emptySubdir._id),
        path: path.normalize('parent/dst/dir/empty-subdir'),
        updated_at: '2017-06-20T12:58:49.817Z'
      })
      await helpers._remote.addFolderAsync({
        ...await pouch.byRemoteIdAsync(subdir._id),
        path: path.normalize('parent/dst/dir/subdir'),
        updated_at: '2017-06-20T12:58:49.873Z'
      })
      const oldFileMetadata = await pouch.byRemoteIdAsync(file._id)
      await helpers._remote.moveFileAsync({
        ...oldFileMetadata,
        path: path.normalize('parent/dst/dir/subdir/file')
        // FIXME: Why does moveFileAsync({updated_at: ...}) fail?
        // updated_at: '2017-06-20T12:58:49.921Z'
      }, oldFileMetadata)
      const oldSubdirMetadata = await pouch.byRemoteIdAsync(subdir._id)
      await helpers._remote.deleteFolderAsync(oldSubdirMetadata)
      const oldEmptySubdirMetadata = await pouch.byRemoteIdAsync(emptySubdir._id)
      await helpers._remote.deleteFolderAsync(oldEmptySubdirMetadata)
      const oldDirMetadata = await pouch.byRemoteIdAsync(dir._id)
      await helpers._remote.deleteFolderAsync(oldDirMetadata)

      await helpers.remote.pullChanges()

      /* FIXME: Nondeterministic
      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        // file 1/2
        {path: path.normalize('parent/src/dir/subdir/file'), _deleted: true},
        // file 2/2
        {path: path.normalize('parent/dst/dir/subdir/file')},
        // dir 2/2
        {path: path.normalize('parent/dst/dir')},
        // empty-subdir 2/2
        {path: path.normalize('parent/dst/dir/empty-subdir')},
        // subdir 2/3
        {path: path.normalize('parent/dst/dir/subdir')},
        // subdir 1/3
        {path: path.normalize('parent/src/dir/subdir'), _deleted: true},
        {path: path.normalize('parent/src/dir/subdir'), trashed: true},
        // empty-subdir 1/2
        {path: path.normalize('parent/src/dir/empty-subdir'), _deleted: true},
        {path: path.normalize('parent/src/dir/empty-subdir'), trashed: true},
        // dir 1/2
        {path: path.normalize('parent/src/dir'), _deleted: true},
        {path: path.normalize('parent/src/dir'), trashed: true}
      ])
      */

      await helpers.syncAll()

      should((await helpers.local.tree())
        // FIXME: Sometimes a copy of the file ends up in the OS trash.
        // Issue was already occurring from time to time, even before we start
        // to permanently delete empty dirs.
        .filter(path => path !== '/Trash/file')
      ).deepEqual([
        'parent/',
        'parent/dst/',
        'parent/dst/dir/',
        'parent/dst/dir/empty-subdir/',
        'parent/dst/dir/subdir/',
        'parent/dst/dir/subdir/file',
        'parent/src/'
      ])
    })
  })
})
<commit_msg>test/integration/move: Use test/support/builders/metadata/*<commit_after>/* @flow */

import { pick } from 'lodash'
import {
  after,
  afterEach,
  before,
  beforeEach,
  suite,
  test
} from 'mocha'
import path from 'path'
import should from 'should'

import Builders from '../support/builders'
import pouchdbBuilders from '../support/builders/pouchdb'
import configHelpers from '../support/helpers/config'
import * as cozyHelpers from '../support/helpers/cozy'
import pouchHelpers from '../support/helpers/pouch'
import { IntegrationTestHelpers } from '../support/helpers/integration'

suite('Move', () => {
  if (process.env.APPVEYOR) {
    test('is unstable on AppVeyor')
    return
  }

  let builders, cozy, helpers, pouch, prep

  before(configHelpers.createConfig)
  before(configHelpers.registerClient)
  beforeEach(pouchHelpers.createDatabase)
  beforeEach(cozyHelpers.deleteAll)

  afterEach(() => helpers.local.clean())
  afterEach(pouchHelpers.cleanDatabase)
  after(configHelpers.cleanConfig)

  beforeEach(async function () {
    builders = new Builders(cozyHelpers.cozy, this.pouch)
    cozy = cozyHelpers.cozy
    helpers = new IntegrationTestHelpers(this.config, this.pouch, cozy)
    pouch = helpers._pouch
    prep = helpers.prep

    await helpers.local.setupTrash()
    await helpers.remote.ignorePreviousChanges()
  })

  suite('file', () => {
    let file, src

    beforeEach(async () => {
      await cozy.files.createDirectory({name: 'dst'})
      src = await cozy.files.createDirectory({name: 'src'})
      file = await cozy.files.create('foo', {name: 'file', dirID: src._id})

      await helpers.remote.pullChanges()
      await helpers.syncAll()
      helpers.spyPouch()
    })

    test('local', async () => {
      const oldFile = await pouch.byRemoteIdMaybeAsync(file._id)
      await prep.moveFileAsync('local', {
        path: 'dst/file',
        updated_at: '2017-06-19T08:19:26.769Z',
        ...pick(oldFile, ['docType', 'md5sum', 'mime', 'class', 'size'])
      }, oldFile)

      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        {path: path.normalize('src/file'), _deleted: true},
        {path: path.normalize('dst/file')}
      ])

      await helpers.syncAll()

      should(await helpers.remote.tree()).deepEqual([
        '.cozy_trash/',
        'dst/',
        'dst/file',
        'src/'
      ])
    })

    test('remote', async () => {
      const oldFile = await pouch.byRemoteIdMaybeAsync(file._id)
      await prep.moveFileAsync('remote', {
        ...pick(oldFile, ['docType', 'size', 'md5sum', 'class', 'mime', 'tags']),
        path: 'dst/file',
        updated_at: '2017-06-19T08:19:26.769Z',
        remote: {
          _id: file._id,
          _rev: pouchdbBuilders.rev()
        }
      }, oldFile)

      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        {path: path.normalize('src/file'), _deleted: true},
        {path: path.normalize('dst/file')}
      ])

      await helpers.syncAll()

      should(await helpers.local.tree()).deepEqual([
        'dst/',
        'dst/file',
        'src/'
      ])
    })
  })

  suite('directory', () => {
    let dir, dst, emptySubdir, file, parent, src, subdir

    beforeEach(async () => {
      parent = await cozy.files.createDirectory({name: 'parent'})
      dst = await cozy.files.createDirectory({name: 'dst', dirID: parent._id})
      src = await cozy.files.createDirectory({name: 'src', dirID: parent._id})
      dir = await cozy.files.createDirectory({name: 'dir', dirID: src._id})
      emptySubdir = await cozy.files.createDirectory({name: 'empty-subdir', dirID: dir._id})
      subdir = await cozy.files.createDirectory({name: 'subdir', dirID: dir._id})
      file = await cozy.files.create('foo', {name: 'file', dirID: subdir._id})

      await helpers.remote.pullChanges()
      await helpers.syncAll()
      helpers.spyPouch()
    })

    test('local', async () => {
      const oldFolder = await pouch.byRemoteIdMaybeAsync(dir._id)
      // FIXME: Why is this a file? And why does it break with a directory?
      const doc = builders.metadata.file().path('parent/dst/dir').build()

      await prep.moveFolderAsync('local', doc, oldFolder)

      should(helpers.putDocs('path', '_deleted', 'trashed', 'childMove')).deepEqual([
        {path: path.normalize('parent/src/dir'), _deleted: true},
        {path: path.normalize('parent/dst/dir')},
        {path: path.normalize('parent/src/dir/empty-subdir'), _deleted: true, childMove: true},
        {path: path.normalize('parent/dst/dir/empty-subdir')},
        {path: path.normalize('parent/src/dir/subdir'), _deleted: true, childMove: true},
        {path: path.normalize('parent/dst/dir/subdir')},
        {path: path.normalize('parent/src/dir/subdir/file'), _deleted: true, childMove: true},
        {path: path.normalize('parent/dst/dir/subdir/file')}
      ])

      await helpers.syncAll()

      should(await helpers.remote.tree()).deepEqual([
        '.cozy_trash/',
        'parent/',
        'parent/dst/',
        'parent/dst/dir/',
        'parent/dst/dir/empty-subdir/',
        'parent/dst/dir/subdir/',
        'parent/dst/dir/subdir/file',
        'parent/src/'
      ])
    })

    test('from remote cozy', async () => {
      await cozy.files.updateAttributesById(dir._id, {dir_id: dst._id})
      await helpers.remote.pullChanges()

      /* FIXME: Nondeterministic
      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        {path: 'parent/src/dir/subdir/file', _deleted: true},
        {path: 'parent/src/dir/subdir', _deleted: true},
        {path: 'parent/src/dir/empty-subdir', _deleted: true},
        {path: 'parent/src/dir', _deleted: true},
        {path: 'parent/dst/dir'},
        {path: 'parent/dst/dir/subdir'},
        {path: 'parent/dst/dir/empty-subdir'}
      ])
      */
      await helpers.syncAll()
      should(await helpers.local.tree()).deepEqual([
        'parent/',
        'parent/dst/',
        'parent/dst/dir/',
        'parent/dst/dir/empty-subdir/',
        'parent/dst/dir/subdir/',
        'parent/dst/dir/subdir/file',
        'parent/src/'
      ])
    })

    test('from remote client', async () => {
      // FIXME: Ensure events occur in the same order as resulting from the
      // local dir test
      await helpers._remote.addFolderAsync({
        ...await pouch.byRemoteIdAsync(dir._id),
        path: path.normalize('parent/dst/dir'),
        updated_at: '2017-06-20T12:58:49.681Z'
      })
      await helpers._remote.addFolderAsync({
        ...await pouch.byRemoteIdAsync(emptySubdir._id),
        path: path.normalize('parent/dst/dir/empty-subdir'),
        updated_at: '2017-06-20T12:58:49.817Z'
      })
      await helpers._remote.addFolderAsync({
        ...await pouch.byRemoteIdAsync(subdir._id),
        path: path.normalize('parent/dst/dir/subdir'),
        updated_at: '2017-06-20T12:58:49.873Z'
      })
      const oldFileMetadata = await pouch.byRemoteIdAsync(file._id)
      await helpers._remote.moveFileAsync({
        ...oldFileMetadata,
        path: path.normalize('parent/dst/dir/subdir/file')
        // FIXME: Why does moveFileAsync({updated_at: ...}) fail?
        // updated_at: '2017-06-20T12:58:49.921Z'
      }, oldFileMetadata)
      const oldSubdirMetadata = await pouch.byRemoteIdAsync(subdir._id)
      await helpers._remote.deleteFolderAsync(oldSubdirMetadata)
      const oldEmptySubdirMetadata = await pouch.byRemoteIdAsync(emptySubdir._id)
      await helpers._remote.deleteFolderAsync(oldEmptySubdirMetadata)
      const oldDirMetadata = await pouch.byRemoteIdAsync(dir._id)
      await helpers._remote.deleteFolderAsync(oldDirMetadata)

      await helpers.remote.pullChanges()

      /* FIXME: Nondeterministic
      should(helpers.putDocs('path', '_deleted', 'trashed')).deepEqual([
        // file 1/2
        {path: path.normalize('parent/src/dir/subdir/file'), _deleted: true},
        // file 2/2
        {path: path.normalize('parent/dst/dir/subdir/file')},
        // dir 2/2
        {path: path.normalize('parent/dst/dir')},
        // empty-subdir 2/2
        {path: path.normalize('parent/dst/dir/empty-subdir')},
        // subdir 2/3
        {path: path.normalize('parent/dst/dir/subdir')},
        // subdir 1/3
        {path: path.normalize('parent/src/dir/subdir'), _deleted: true},
        {path: path.normalize('parent/src/dir/subdir'), trashed: true},
        // empty-subdir 1/2
        {path: path.normalize('parent/src/dir/empty-subdir'), _deleted: true},
        {path: path.normalize('parent/src/dir/empty-subdir'), trashed: true},
        // dir 1/2
        {path: path.normalize('parent/src/dir'), _deleted: true},
        {path: path.normalize('parent/src/dir'), trashed: true}
      ])
      */

      await helpers.syncAll()

      should((await helpers.local.tree())
        // FIXME: Sometimes a copy of the file ends up in the OS trash.
        // Issue was already occurring from time to time, even before we start
        // to permanently delete empty dirs.
        .filter(path => path !== '/Trash/file')
      ).deepEqual([
        'parent/',
        'parent/dst/',
        'parent/dst/dir/',
        'parent/dst/dir/empty-subdir/',
        'parent/dst/dir/subdir/',
        'parent/dst/dir/subdir/file',
        'parent/src/'
      ])
    })
  })
})
<|endoftext|>


<commit_before>import request from 'superagent';
import Transport from './Transport';
import PromiseMaker from '../PromiseMaker';
import {expandResponse} from '../Utilities';
import {CLIENT_STATES, CLIENT_EVENTS} from '../Constants';

function inspect(x) {
  console.dir(x);
  return x;
}

/**
 * The long polling transport protocol
 */
export default class LongPollingTransport extends Transport {
  static supportsKeepAlive = false;

  constructor(connection) {
    super('longPolling', connection);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} That resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */
  start() {
    if(this._pollTimeoutId) {
      throw new Error('A polling session has already been initialized. Call `stop()` before attempting to `start()` again.');
    }
    this._logger.info(`*${this.constructor.name}* starting...`);
    this.connection._reconnectTries = 0;
    this.connection._reconnectTimeoutId = null;
    return this._connect()
      //.then(this._startConnection.bind(this))
      .then(() => this.connection._client.state = CLIENT_STATES.connected)
      .then(this._poll.bind(this));
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} that resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */
  _connect() {
    const url = this.connection._client.config.url + '/connect';
    this._logger.info(`Connecting to ${url}`);
    this._current = request
      .post(url)
      .query({clientProtocol: 1.5})
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .query({connectionData: this.connection._data || ''});
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this.connection._processMessages.bind(this.connection));
  }

  _startConnection() {
    this._current = request
      .post(this.connection._client.config.url + '/start')
      .query({clientProtocol: 1.5})
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .query({connectionData: this.connection._data || ''});

    return this._current
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a poll to th' ship 'n hold th' poll open 'til th' ship be able to send new information.
   * @returns {Promise} That resolves if th' client must reconnect due to bad connection.
   * Else, th' method be called recursively after it recieves new information from th' ship.
   */
  _poll() {
    this._currentTimeoutId = setTimeout(() => {
      const {messageId, groupsToken, shouldReconnect} = this.connection._lastMessages;
      this._current = request
        .post(this.connection._client.config.url + '/poll')
        .query({clientProtocol: 1.5})
        .query({connectionToken: this.connection._connectionToken})
        .query({transport: 'longPolling'})
        .query({connectionData: this.connection._data || ''});
      if(groupsToken) {
        this._current = this._current
          .send({messageId, groupsToken});
      } else {
        this._current = this._current
          .send({messageId});
      }
      this._current = this._current
        .end((err, res) => {
          if(err && shouldReconnect){
            return this._reconnect()
              .then(this._poll)
          }
          if(res) {
            if(this.connection._client.state === CLIENT_STATES.reconnecting){
              this.connection._client.state = CLIENT_STATES.connected;
              this.connection._client.emit(CLIENT_EVENTS.onReconnected);
            }
            this.connection._processMessages(res.body);
          }
          this._poll();
        });
    }, 250);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   *  @params {data} data contains th' information that th' client wishes to send to th' ship.
   *  @returns {Promise} that resolves once th' message has be sent..
   */
  _send(data) {
    return request
      .post(this.connection._client.config.url + '/send')
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .send(`data=${JSON.stringify(data)}`)
      .set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a reconnection to th' ship in th' case that th' connection be too slow or be lost completely.
   *  @returns {Promise} that resolves once th' client has be successfully reconnected.
   */
  _reconnect() {
    const url = this.connection._client.config.url + '/connect';
    this.connection.client.emit(CLIENT_EVENTS.onReconnecting);
    this.connection.client.state = CLIENT_STATES.reconnecting;
    this._logger.info(`Attempting to reconnect to ${url}`);
    this.connection._reconnectTries++;
    this._current = request
      .post(url)
      .query({clientProtocol: 1.5})
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .query({connectionData: this.connection._data || ''});
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this.connection._processMessages.bind(this.connection));
  }

  stop() {
    this.connection._client.emit(CLIENT_EVENTS.onDisconnecting);
    this._logger.info(`Disconnecting from ${this.connection.url}.`);
    this.connection.transport = null;
    delete this.connection.messageId;
    delete this.connection._connectionToken;
    delete this.connection._lastActiveAt;
    delete this.connection._lastMessageAt;
    delete this.connection._lastMessages;
    delete this.connection.config;
    delete this._current;
    this.connection._client.state = CLIENT_STATES.disconnected;
    this.connection._client.emit(CLIENT_EVENTS.onDisconnected);
    this._logger.info('Successfully disconnected.');

  }
}
<commit_msg>continued implementing disconnection functionality for long polling<commit_after>import request from 'superagent';
import Transport from './Transport';
import PromiseMaker from '../PromiseMaker';
import {expandResponse} from '../Utilities';
import {CLIENT_STATES, CLIENT_EVENTS} from '../Constants';

function inspect(x) {
  console.dir(x);
  return x;
}

/**
 * The long polling transport protocol
 */
export default class LongPollingTransport extends Transport {
  static supportsKeepAlive = false;

  constructor(connection) {
    super('longPolling', connection);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} That resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */
  start() {
    if(this._pollTimeoutId) {
      throw new Error('A polling session has already been initialized. Call `stop()` before attempting to `start()` again.');
    }
    this._logger.info(`*${this.constructor.name}* starting...`);
    this.connection._reconnectTries = 0;
    this.connection._reconnectTimeoutId = null;
    return this._connect()
      //.then(this._startConnection.bind(this))
      .then(() => this.connection._client.state = CLIENT_STATES.connected)
      .then(this._poll.bind(this));
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   * @returns {Promise} that resolves once th' long pollin' transport has started successfully 'n has begun pollin'.
   */
  _connect() {
    const url = this.connection._client.config.url + '/connect';
    this._logger.info(`Connecting to ${url}`);
    this._current = request
      .post(url)
      .query({clientProtocol: 1.5})
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .query({connectionData: this.connection._data || ''});
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this.connection._processMessages.bind(this.connection));
  }

  _startConnection() {
    this._current = request
      .post(this.connection._client.config.url + '/start')
      .query({clientProtocol: 1.5})
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .query({connectionData: this.connection._data || ''});

    return this._current
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a poll to th' ship 'n hold th' poll open 'til th' ship be able to send new information.
   * @returns {Promise} That resolves if th' client must reconnect due to bad connection.
   * Else, th' method be called recursively after it recieves new information from th' ship.
   */
  _poll() {
    this._currentTimeoutId = setTimeout(() => {
      const {messageId, groupsToken, shouldReconnect} = this.connection._lastMessages;
      this._current = request
        .post(this.connection._client.config.url + '/poll')
        .query({clientProtocol: 1.5})
        .query({connectionToken: this.connection._connectionToken})
        .query({transport: 'longPolling'})
        .query({connectionData: this.connection._data || ''});
      if(groupsToken) {
        this._current = this._current
          .send({messageId, groupsToken});
      } else {
        this._current = this._current
          .send({messageId});
      }
      this._current = this._current
        .end((err, res) => {
          if(err && shouldReconnect){
            return this._reconnect()
              .then(this._poll)
          }
          if(res) {
            if(this.connection._client.state === CLIENT_STATES.reconnecting){
              this.connection._client.state = CLIENT_STATES.connected;
              this.connection._client.emit(CLIENT_EVENTS.onReconnected);
            }
            this.connection._processMessages(res.body);
          }
          this._poll();
        });
    }, 250);
  }

  /**
   * Initiates th' long pollin' transport protocol fer th' current connection.
   *  @params {data} data contains th' information that th' client wishes to send to th' ship.
   *  @returns {Promise} that resolves once th' message has be sent..
   */
  _send(data) {
    return request
      .post(this.connection._client.config.url + '/send')
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .send(`data=${JSON.stringify(data)}`)
      .set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
      .use(PromiseMaker)
      .promise();
  }

  /**
   * Initiates a reconnection to th' ship in th' case that th' connection be too slow or be lost completely.
   *  @returns {Promise} that resolves once th' client has be successfully reconnected.
   */
  _reconnect() {
    const url = this.connection._client.config.url + '/connect';
    this.connection.client.emit(CLIENT_EVENTS.onReconnecting);
    this.connection.client.state = CLIENT_STATES.reconnecting;
    this._logger.info(`Attempting to reconnect to ${url}`);
    this.connection._reconnectTries++;
    this._current = request
      .post(url)
      .query({clientProtocol: 1.5})
      .query({connectionToken: this.connection._connectionToken})
      .query({transport: 'longPolling'})
      .query({connectionData: this.connection._data || ''});
    return this._current
      .use(PromiseMaker)
      .promise()
      .then(this.connection._processMessages.bind(this.connection));
  }

  stop() {
    this.connection._client.emit(CLIENT_EVENTS.onDisconnecting);
    this._logger.info(`Disconnecting from ${this.connection.url}.`);
    this.connection.transport = null;
    delete this.connection.messageId;
    delete this.connection._connectionToken;
    delete this.connection._lastActiveAt;
    delete this.connection._lastMessageAt;
    delete this.connection._lastMessages;
    delete this.connection.config;
    delete this._current;
    this.connection._client.state = CLIENT_STATES.disconnected;
    this.connection._client.emit(CLIENT_EVENTS.onDisconnected);
    this._logger.info('Successfully disconnected.');
    window.clearTimeout(this._currentTimeoutId);

  }
}
<|endoftext|>


<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2017-2017 Jan Dockx
 *
 * 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.
 */

/* eslint-env mocha */

const discover = require('../../lib/discover')
// noinspection JSUnresolvedVariable
const discoverContract = discover.contract

// noinspection SpellCheckingInspection
const serviceTypePostfix = '._tcp.dns-sd-lookup.toryt.org'
// noinspection SpellCheckingInspection
const serviceType = '_t1i-no-sub' + serviceTypePostfix
const manyInstanceServiceType = '_t8i-n-inst' + serviceTypePostfix
const manyInstanceCount = 12

describe('discover', function () {
  describe('#notOneOf', function () {
    const instanceName = 'candidate instance._type._tcp.dns-sd-lookup.toryt.org'

    it('works with the empty array', function () {
      const deathInstances = []
      const result = discover.notOneOf(deathInstances)
      result.must.be.a.function()
      const secondaryResult = result(instanceName)
      secondaryResult.must.be.boolean()
      secondaryResult.must.be.true()
    })
    it('works with a non-empty array, without a match', function () {
      const deathInstances = [
        'death instance 1._type._tcp.dns-sd-lookup.toryt.org',
        'death instance 2._type._tcp.dns-sd-lookup.toryt.org',
        'death instance 3._type._tcp.dns-sd-lookup.toryt.org'
      ]
      const result = discover.notOneOf(deathInstances)
      result.must.be.a.function()
      const secondaryResult = result(instanceName)
      secondaryResult.must.be.boolean()
      secondaryResult.must.be.true()
    })
    it('works with a non-empty array, with a match', function () {
      const deathInstances = [
        'death instance 1._type._tcp.dns-sd-lookup.toryt.org',
        instanceName,
        'death instance 3._type._tcp.dns-sd-lookup.toryt.org'
      ]
      const result = discover.notOneOf(deathInstances)
      result.must.be.a.function()
      const secondaryResult = result(instanceName)
      secondaryResult.must.be.boolean()
      secondaryResult.must.be.false()
    })
  })
  describe('main method', function () {
    it('works in the nominal case, without a subtype', function () {
      // noinspection JSUnresolvedVariable
      return discover(serviceType).must.fulfill(discoverContract.resolved.implementation(details => {
        details.must.be.an.array()
        details.must.have.length(1)
        console.log(details)
      }))
    })
    it('works in the nominal case, with a subtype', function () {
      const serviceType = `_subtype._sub._t7i-sub${serviceTypePostfix}`
      // noinspection JSUnresolvedVariable
      return discover(serviceType).must.fulfill(discoverContract.resolved.implementation(details => {
        details.must.be.an.array()
        details.must.have.length(1)
        console.log(details)
      }))
    })
    it(`works in the nominal case, with ${manyInstanceCount} instances`, function () {
      this.timeout(10000)

      // noinspection JSUnresolvedVariable
      return discover(manyInstanceServiceType).must.fulfill(discoverContract.resolved.implementation(details => {
        details.must.be.an.array()
        details.must.have.length(manyInstanceCount)
        console.log(details)
      }))
    })
    it('resolves to the empty array with a non-existent service type', function () {
      // noinspection JSUnresolvedVariable
      return discover('_not-exist' + serviceTypePostfix)
        .must.fulfill(discoverContract.resolved.implementation(details => {
          details.must.be.an.array()
          details.must.be.empty()
          console.log(details)
        }))
    })
    it('works with a filter in the nominal case', function () {
      const deaths = [
        `Instance 8c.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`
      ]
      // noinspection JSUnresolvedVariable
      return discover(manyInstanceServiceType, discover.notOneOf(deaths))
        .must.fulfill(discoverContract.resolved.implementation(details => {
          details.must.be.an.array()
          details.must.have.length(manyInstanceCount - deaths.length)
          details.forEach(d => deaths.must.not.contain(d.instance))
          console.log(details)
        }))
    })
    it('works with a filter in the nominal case that excludes all instances', function () {
      const deaths = [
        `Instance 8c.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8c.${manyInstanceServiceType}`,
        `Instance 8a.${manyInstanceServiceType}`,
        `Instance 8f.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8j.${manyInstanceServiceType}`,
        `Instance 8i.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8g.${manyInstanceServiceType}`,
        `Instance 8k.${manyInstanceServiceType}`,
        `Instance 8h.${manyInstanceServiceType}`,
        `Instance 8d.${manyInstanceServiceType}`,
        `Instance 8l.${manyInstanceServiceType}`,
        `Instance 8b.${manyInstanceServiceType}`
      ]
      // noinspection JSUnresolvedVariable
      return discover(manyInstanceServiceType, discover.notOneOf(deaths))
        .must.fulfill(discoverContract.resolved.implementation(details => {
          details.must.be.an.array()
          details.must.be.empty()
          console.log(details)
        }))
    })

    let failures = [
      't2i-2-txt',
      't3i-2-srv',
      't4i-2-txt-srv',
      't5i-no-txt',
      't6i-no-srv'
    ]
    failures = failures.map(f => `_${f}${serviceTypePostfix}`)
    failures.forEach(serviceType => {
      it(`fails for instance type ${serviceType}`, function () {
        // noinspection JSUnresolvedVariable
        return discover(serviceType).must.betray(discoverContract.rejected.implementation(err => {
          console.log(err)
        }))
      })
    })
  })
})
<commit_msg>tweak timeouts (i.e., have less lookups, and thus finish faster)<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2017-2017 Jan Dockx
 *
 * 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.
 */

/* eslint-env mocha */

const discover = require('../../lib/discover')
// noinspection JSUnresolvedVariable
const discoverContract = discover.contract

// noinspection SpellCheckingInspection
const serviceTypePostfix = '._tcp.dns-sd-lookup.toryt.org'
// noinspection SpellCheckingInspection
const serviceType = '_t1i-no-sub' + serviceTypePostfix
const manyInstanceServiceType = '_t8i-n-inst' + serviceTypePostfix
const manyInstanceCount = 12

describe('discover', function () {
  describe('#notOneOf', function () {
    const instanceName = 'candidate instance._type._tcp.dns-sd-lookup.toryt.org'

    it('works with the empty array', function () {
      const deathInstances = []
      const result = discover.notOneOf(deathInstances)
      result.must.be.a.function()
      const secondaryResult = result(instanceName)
      secondaryResult.must.be.boolean()
      secondaryResult.must.be.true()
    })
    it('works with a non-empty array, without a match', function () {
      const deathInstances = [
        'death instance 1._type._tcp.dns-sd-lookup.toryt.org',
        'death instance 2._type._tcp.dns-sd-lookup.toryt.org',
        'death instance 3._type._tcp.dns-sd-lookup.toryt.org'
      ]
      const result = discover.notOneOf(deathInstances)
      result.must.be.a.function()
      const secondaryResult = result(instanceName)
      secondaryResult.must.be.boolean()
      secondaryResult.must.be.true()
    })
    it('works with a non-empty array, with a match', function () {
      const deathInstances = [
        'death instance 1._type._tcp.dns-sd-lookup.toryt.org',
        instanceName,
        'death instance 3._type._tcp.dns-sd-lookup.toryt.org'
      ]
      const result = discover.notOneOf(deathInstances)
      result.must.be.a.function()
      const secondaryResult = result(instanceName)
      secondaryResult.must.be.boolean()
      secondaryResult.must.be.false()
    })
  })
  describe('main method', function () {
    it('works in the nominal case, without a subtype', function () {
      // noinspection JSUnresolvedVariable
      return discover(serviceType).must.fulfill(discoverContract.resolved.implementation(details => {
        details.must.be.an.array()
        details.must.have.length(1)
        console.log(details)
      }))
    })
    it('works in the nominal case, with a subtype', function () {
      const serviceType = `_subtype._sub._t7i-sub${serviceTypePostfix}`
      // noinspection JSUnresolvedVariable
      return discover(serviceType).must.fulfill(discoverContract.resolved.implementation(details => {
        details.must.be.an.array()
        details.must.have.length(1)
        console.log(details)
      }))
    })
    it(`works in the nominal case, with ${manyInstanceCount} instances`, function () {
      this.timeout(10000)

      // noinspection JSUnresolvedVariable
      return discover(manyInstanceServiceType).must.fulfill(discoverContract.resolved.implementation(details => {
        details.must.be.an.array()
        details.must.have.length(manyInstanceCount)
        console.log(details)
      }))
    })
    it('resolves to the empty array with a non-existent service type', function () {
      // noinspection JSUnresolvedVariable
      return discover('_not-exist' + serviceTypePostfix)
        .must.fulfill(discoverContract.resolved.implementation(details => {
          details.must.be.an.array()
          details.must.be.empty()
          console.log(details)
        }))
    })
    it('works with a filter in the nominal case', function () {
      const deaths = [
        `Instance 8c.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8g.${manyInstanceServiceType}`,
        `Instance 8h.${manyInstanceServiceType}`,
        `Instance 8i.${manyInstanceServiceType}`,
        `Instance 8k.${manyInstanceServiceType}`,
        `Instance 8l.${manyInstanceServiceType}`
      ]
      // noinspection JSUnresolvedVariable
      return discover(manyInstanceServiceType, discover.notOneOf(deaths))
        .must.fulfill(discoverContract.resolved.implementation(details => {
          details.must.be.an.array()
          details.must.have.length(manyInstanceCount - deaths.length)
          details.forEach(d => deaths.must.not.contain(d.instance))
          console.log(details)
        }))
    })
    it('works with a filter in the nominal case that excludes all instances', function () {
      const deaths = [
        `Instance 8c.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8c.${manyInstanceServiceType}`,
        `Instance 8a.${manyInstanceServiceType}`,
        `Instance 8f.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8j.${manyInstanceServiceType}`,
        `Instance 8i.${manyInstanceServiceType}`,
        `Instance 8e.${manyInstanceServiceType}`,
        `Instance 8g.${manyInstanceServiceType}`,
        `Instance 8k.${manyInstanceServiceType}`,
        `Instance 8h.${manyInstanceServiceType}`,
        `Instance 8d.${manyInstanceServiceType}`,
        `Instance 8l.${manyInstanceServiceType}`,
        `Instance 8b.${manyInstanceServiceType}`
      ]
      // noinspection JSUnresolvedVariable
      return discover(manyInstanceServiceType, discover.notOneOf(deaths))
        .must.fulfill(discoverContract.resolved.implementation(details => {
          details.must.be.an.array()
          details.must.be.empty()
          console.log(details)
        }))
    })

    let failures = [
      't2i-2-txt',
      't3i-2-srv',
      't4i-2-txt-srv',
      't5i-no-txt',
      't6i-no-srv'
    ]
    failures = failures.map(f => `_${f}${serviceTypePostfix}`)
    failures.forEach(serviceType => {
      it(`fails for instance type ${serviceType}`, function () {
        // noinspection JSUnresolvedVariable
        return discover(serviceType).must.betray(discoverContract.rejected.implementation(err => {
          console.log(err)
        }))
      })
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

var xinput = require('../../lib/xinput');

function getTouchpad(cb){
  xinput.list(function(err, devices){
    var touchpad = devices.filter(function(device){
      return device.name.toLowerCase().indexOf('touchpad') !== -1;
    })[0];
    cb(err, touchpad);
  });
}

describe('xinput', function(){
  var touchpad;

  before(function(done){
    getTouchpad(function(err, device){
      touchpad = device;
      done(err);
    });
  });

  describe('.list(cb)', function(){
    it('should return JSON', function(done){
      xinput.list(function(err, devices){
        devices.should.be.an.instanceOf(Array);
        done();
      });
    });
  });

  describe('.listProps(id, cb)', function(){
    it('should require an id', function(done){
      xinput.listProps(null, function(err){
        err.message.should.equal('id is required');
        done();
      });
    });

    it('should return JSON', function(done){
      xinput.listProps(touchpad.id, function(err, properties){
        properties.should.be.an.instanceOf(Array);
        done();
      });
    });
  });

  describe('.setProp(id, name, value)', function(){
    var name = 'Device Enabled';

    after(function(done){
      xinput.setProp(touchpad.id, name, '1', function(err){
        done(err);
      });
    });

    it('should require id', function(done){
      xinput.setProp(null, name, 1, function(err){
        err.message.should.equal('id is required');
        done();
      });
    });

    it('should require name', function(done){
      xinput.setProp(touchpad.id, null, 1, function(err){
        err.message.should.equal('name is required');
        done();
      });
    });

    it('should require value', function(done){
      xinput.setProp(touchpad.id, name, null, function(err){
        err.message.should.equal('value is required');
        done();
      });
    });

    it('should set properties', function(done){
      xinput.setProp(touchpad.id, name, '0', function(err){
        console.log('Your touchpad should be disabled for 1.5 seconds.');
        setTimeout(function(){
          done(err);
        }, 1500);
      });
    });
  });
});
<commit_msg>Adding travis logic to test.<commit_after>'use strict';

var xinput = require('../../lib/xinput');

function getTouchpad(cb){
  xinput.list(function(err, devices){
    var touchpad = devices.filter(function(device){
      return device.name.toLowerCase().indexOf('touchpad') !== -1;
    })[0];
    cb(err, process.env.TRAVIS ? devices[devices.length - 1] : touchpad);
  });
}

describe('xinput', function(){
  var touchpad;

  before(function(done){
    getTouchpad(function(err, device){
      touchpad = device;
      done(err);
    });
  });

  describe('.list(cb)', function(){
    it('should return JSON', function(done){
      xinput.list(function(err, devices){
        devices.should.be.an.instanceOf(Array);
        done();
      });
    });
  });

  describe('.listProps(id, cb)', function(){
    it('should require an id', function(done){
      xinput.listProps(null, function(err){
        err.message.should.equal('id is required');
        done();
      });
    });

    it('should return JSON', function(done){
      xinput.listProps(touchpad.id, function(err, properties){
        properties.should.be.an.instanceOf(Array);
        done();
      });
    });
  });

  describe('.setProp(id, name, value)', function(){
    var name = 'Device Enabled';

    after(function(done){
      xinput.setProp(touchpad.id, name, '1', function(err){
        done(err);
      });
    });

    it('should require id', function(done){
      xinput.setProp(null, name, 1, function(err){
        err.message.should.equal('id is required');
        done();
      });
    });

    it('should require name', function(done){
      xinput.setProp(touchpad.id, null, 1, function(err){
        err.message.should.equal('name is required');
        done();
      });
    });

    it('should require value', function(done){
      xinput.setProp(touchpad.id, name, null, function(err){
        err.message.should.equal('value is required');
        done();
      });
    });

    it('should set properties', function(done){
      xinput.setProp(touchpad.id, name, '0', function(err){
        console.log('Your touchpad should be disabled for 1.5 seconds.');
        setTimeout(function(){
          done(err);
        }, 1500);
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var http = require('http'),
    formidable = require('formidable'),
    fs = require('fs'),
    _ = require('lodash');

var options = {
  host: 'localhost',
  port: 8989
};

var server = http.createServer(function(req,res) {

  console.log('POST Detected with incoming Form-data...');

  var form = new formidable.IncomingForm();

  form.parse(req, function(err, fields, files) {
    console.log('POST Finished and publishing object back to browser...');

    var headers = {};
    headers['Content-Type'] = 'application/json';
    headers["Access-Control-Allow-Origin"] = req.headers.origin;
    headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
    headers["Access-Control-Allow-Credentials"] = true;
    headers["Access-Control-Max-Age"] = '86400'; // 24 hours
    headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Access-Control-Allow-Origin, Content-Type, Accept";

    res.writeHead(200, headers);

    var output = {};

    _.extend(output, unflatten(fields));

    if (!_.isEmpty(files)) {

      for (var i in files) {
        if (files.hasOwnProperty(i)) {

          output[i] = {};

          fs.readFile(files[i].path, function (err, data) {

            output[i].type = files[i].type;
            output[i].size = files[i].size;
            output[i].name = files[i].name;
            output[i].lastModifiedDate = files[i].lastModifiedDate;
            output[i].data = 'data:' + files[i].type + ';base64,' + data.toString('base64');

          });

        }
      }

    }

    console.info(output);

    res.end(JSON.stringify(output));

  });

});

function unflatten(obj, output) {
  var re = /^([^\[\]]+)\[(.+)\]$/g;
  output = output || {};
  for (var key in obj) {
    var value = obj[key];
    if (!key.toString().match(re)) {
      var tempOut = {};
      tempOut[key] = value;
      _.extend(output, tempOut);
    } else {
      var keys = _.compact(key.split(re)), tempOut = {};
      tempOut[keys[1]] = value;
      output[keys[0]] = unflatten( tempOut, output[keys[0]] )
    }
  }
  return output;
}

server.listen(options.port, options.host);
console.log("listening on " + options.host + ':' + options.port);
<commit_msg>Updated mock file server to allow multiple file echo. Still does not pass, probably because formidable fails to read the files correctly, but the logic is sound.<commit_after>'use strict';

var http = require('http'),
    formidable = require('formidable'),
    fs = require('fs'),
    _ = require('lodash');

var options = {
  host: 'localhost',
  port: 8989
};

var server = http.createServer(function(req,res) {

  console.log('POST Detected with incoming Form-data...');

  var form = new formidable.IncomingForm(),
      files = {},
      fields = {};

  form.on('file', function(field, file) {
    files[field] = (files[field] || []).concat([file]);
  });
  form.on('field', function(field, value) {
    fields[field] = value;
  });
  form.on('end',  function(err) {
    console.log('POST Finished and publishing object back to browser...');

    var headers = {};
    headers['Content-Type'] = 'application/json';
    headers["Access-Control-Allow-Origin"] = req.headers.origin;
    headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
    headers["Access-Control-Allow-Credentials"] = true;
    headers["Access-Control-Max-Age"] = '86400'; // 24 hours
    headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Access-Control-Allow-Origin, Content-Type, Accept";

    res.writeHead(200, headers);

    var output = {};

    _.extend(output, unflatten(fields));
    var fileOutputs = {};
    _.each(files, function(files, filename){
      var loopOutputs = [];
      _.each(files, function(file) {
        var fileOutput = {},
            data = fs.readFileSync(file.path);
        fileOutput.type = file.type;
        fileOutput.size = data.length;
        fileOutput.name = file.name;
        fileOutput.lastModifiedDate = file.lastModifiedDate;
        fileOutput.data = 'data:' + file.type + ';base64,' + data.toString('base64');
        loopOutputs.push(fileOutput);
      });
      loopOutputs = loopOutputs.length > 1 ? loopOutputs : loopOutputs[0];
      fileOutputs[filename] = loopOutputs;
    });
    output = _.merge(output, fileOutputs);

    console.info(output);

    res.end(JSON.stringify(output));

  });

  form.parse(req)

});

function unflatten(obj, output) {
  var re = /^([^\[\]]+)\[(.+)\]$/g;
  output = output || {};
  for (var key in obj) {
    var value = obj[key];
    if (!key.toString().match(re)) {
      var tempOut = {};
      tempOut[key] = value;
      _.extend(output, tempOut);
    } else {
      var keys = _.compact(key.split(re)), tempOut = {};
      tempOut[keys[1]] = value;
      output[keys[0]] = unflatten( tempOut, output[keys[0]] )
    }
  }
  return output;
}

server.listen(options.port, options.host);
console.log("listening on " + options.host + ':' + options.port);
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core.internal',
  name: 'InterfaceMethod',
  extends: 'foam.core.Method',
  properties: [
    {
      name: 'code',
      required: false
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Interface',
  properties: [
    {
      class: 'String',
      name: 'package'
    },
    {
      class: 'String',
      name: 'name'
    },
    {
      class: 'String',
      name: 'extends'
    },
    {
      class: 'String',
      name: 'id',
      expression: function(package, name) {
        return package + '.' + name;
      }
    },
    {
      class: 'AxiomArray',
      name: 'methods',
      of: 'foam.core.internal.InterfaceMethod'
    },
    {
      class: 'AxiomArray',
      name: 'properties',
      // TODO: Should this be a type of property that defines
      // nothing beyond name and type information?
      of: 'foam.core.Property'
    },
    {
      name: 'axioms_',
      factory: function() { return []; }
    }
  ],
  methods: [
    function getAxiomByName(name) {
      return this.axioms_.filter(function(a) {
        return a.name === name;
      })[0];
    },
    function getAxiomsByClass(cls) {
      return this.axioms_.filter(function(a) {
        return cls.isInstance(a);
      });
    },
    function getOwnAxiomsByClass(cls) {
      return this.getAxiomsByClass(cls);
    },
    function hasOwnAxiom(name) {
      return this.axioms_.some(function(a) { return a.name === name; });
    },
    function isInstance(o) {
      return !! ( o && o.cls_ && o.cls_.getAxiomByName('implements_' + this.id) );
    }
  ]
});

foam.LIB({
  name: 'foam',
  methods: [
    function INTERFACE(m) {
      var model = foam.core.Interface.create(m);
      foam.register(model);
      foam.package.registerClass(model);
    }
  ]
});
<commit_msg>Update Interface model.  Mark methods as abstract and make extends a StringArray.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core.internal',
  name: 'InterfaceMethod',
  extends: 'foam.core.Method',
  properties: [
    {
      name: 'code',
      required: false
    },
    {
      class: 'Boolean',
      name: 'abstract',
      value: true
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Interface',
  properties: [
    {
      class: 'String',
      name: 'package'
    },
    {
      class: 'String',
      name: 'name'
    },
    {
      class: 'StringArray',
      name: 'extends'
    },
    {
      class: 'String',
      name: 'id',
      expression: function(package, name) {
        return package + '.' + name;
      }
    },
    {
      class: 'AxiomArray',
      name: 'methods',
      of: 'foam.core.internal.InterfaceMethod'
    },
    {
      class: 'AxiomArray',
      name: 'properties',
      // TODO: Should this be a type of property that defines
      // nothing beyond name and type information?
      of: 'foam.core.Property'
    },
    {
      name: 'axioms_',
      factory: function() { return []; }
    }
  ],
  methods: [
    function getAxiomByName(name) {
      return this.axioms_.filter(function(a) {
        return a.name === name;
      })[0];
    },
    function getAxiomsByClass(cls) {
      return this.axioms_.filter(function(a) {
        return cls.isInstance(a);
      });
    },
    function getOwnAxiomsByClass(cls) {
      return this.getAxiomsByClass(cls);
    },
    function hasOwnAxiom(name) {
      return this.axioms_.some(function(a) { return a.name === name; });
    },
    function isInstance(o) {
      return !! ( o && o.cls_ && o.cls_.getAxiomByName('implements_' + this.id) );
    }
  ]
});

foam.LIB({
  name: 'foam',
  methods: [
    function INTERFACE(m) {
      var model = foam.core.Interface.create(m);
      foam.register(model);
      foam.package.registerClass(model);
    }
  ]
});
<|endoftext|>


<commit_before>(function() {
    'use strict';

    angular.module('ng-geotooltip', [])
        .directive('geotooltip', ['$timeout', function ($timeout) {
            // The container is shared between directives to avoid performance issues
            var container = angular.element('

');
            var map = null;
            var layerGroup = null;

            var displayTooltip = function(tippedElement, width, height, coords, geoJson) {
                // Make the container the right size
                var resized = false;
                if (width !== container.css('width') || height !== container.css('height')) {
                    resized = true;
                }
                container.css('width', width);
                container.css('height', height);

                // Position it at the right place
                container.css('top', tippedElement.prop('offsetHeight')+'px');
                container.css('left', tippedElement.prop('offsetWidth')+'px');
                tippedElement.append(container);

                if (map === null) {
                    map = new L.map(container[0], {zoomControl: false});
                    var tilesUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png';
                    var attrib = 'Tiles Courtesy of MapQuest  - Map data © OpenStreetMap contributors';
                    var tileLayer = new L.TileLayer(tilesUrl, {minZoom: 1, maxZoom: 18, attribution: attrib, subdomains: '1234'});
                    map.addLayer(tileLayer);
                } else if (resized) {
                    map.invalidateSize();
                }

                if (layerGroup !== null) {
                    map.removeLayer(layerGroup);
                }
                layerGroup = L.layerGroup();
                var bounds = new L.LatLngBounds();

                if (coords) {
                    var point = new L.LatLng(coords[0], coords[1]);
                    var pointLayer = L.marker(point);
                    layerGroup.addLayer(pointLayer);
                    bounds.extend(point);
                }

                if (geoJson) {
                    var geoJsonLayer = L.geoJson(geoJson);
                    layerGroup.addLayer(geoJsonLayer);
                    bounds.extend(geoJsonLayer.getBounds());
                }
                //map.setView(point, 12);
                layerGroup.addTo(map);
                map.fitBounds(bounds);
                container.css('opacity', '1');
            };

            var hideTooltip = function() {
                container.css('opacity', '0');
            };

            return {
                template: '',
                replace: true,
                restrict: 'E',
                transclude: true,
                scope: {
                    'coords': '=',
                    'width': '@',
                    'height': '@',
                    'delay': '@',
                    'geojson': '='
                },
                link: function(scope, element, attrs) {
                    var tooltipWidth = '200px';
                    var tooltipHeight = '200px';
                    var tooltipPop = null;

                    var delay = attrs.delay || 1000;
                    if (attrs.height) {
                        tooltipHeight = attrs.height+'px';
                    }
                    if (attrs.width) {
                        tooltipWidth = attrs.width+'px';
                    }

                    // Events
                    element.bind('mouseover', function() {
                        tooltipPop = $timeout(function() {
                            displayTooltip(element, tooltipWidth, tooltipHeight, scope.coords, scope.geojson);
                            tooltipPop = null;
                        }, delay);
                    });
                    element.bind('click', function() {
                        displayTooltip(element, tooltipWidth, tooltipHeight, scope.coords, scope.geojson);
                        if (tooltipPop !== null) {
                            // Chances are we triggered the original timer
                            $timeout.cancel(tooltipPop);
                            tooltipPop = null;
                        }
                    });
                    element.bind('mouseout', function() {
                        hideTooltip();
                        if (tooltipPop !== null) {
                            // We are currently counting down until the tooltip appearance, let's forget it
                            $timeout.cancel(tooltipPop);
                            tooltipPop = null;
                        }

                    });
                }
            };
        }]);
}());<commit_msg>Higher z-index<commit_after>(function() {
    'use strict';

    angular.module('ng-geotooltip', [])
        .directive('geotooltip', ['$timeout', function ($timeout) {
            // The container is shared between directives to avoid performance issues
            var container = angular.element('

');
            var map = null;
            var layerGroup = null;

            var displayTooltip = function(tippedElement, width, height, coords, geoJson) {
                // Make the container the right size
                var resized = false;
                if (width !== container.css('width') || height !== container.css('height')) {
                    resized = true;
                }
                container.css('width', width);
                container.css('height', height);

                // Position it at the right place
                container.css('top', tippedElement.prop('offsetHeight')+'px');
                container.css('left', tippedElement.prop('offsetWidth')+'px');
                tippedElement.append(container);

                if (map === null) {
                    map = new L.map(container[0], {zoomControl: false});
                    var tilesUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png';
                    var attrib = 'Tiles Courtesy of MapQuest  - Map data © OpenStreetMap contributors';
                    var tileLayer = new L.TileLayer(tilesUrl, {minZoom: 1, maxZoom: 18, attribution: attrib, subdomains: '1234'});
                    map.addLayer(tileLayer);
                } else if (resized) {
                    map.invalidateSize();
                }

                if (layerGroup !== null) {
                    map.removeLayer(layerGroup);
                }
                layerGroup = L.layerGroup();
                var bounds = new L.LatLngBounds();

                if (coords) {
                    var point = new L.LatLng(coords[0], coords[1]);
                    var pointLayer = L.marker(point);
                    layerGroup.addLayer(pointLayer);
                    bounds.extend(point);
                }

                if (geoJson) {
                    var geoJsonLayer = L.geoJson(geoJson);
                    layerGroup.addLayer(geoJsonLayer);
                    bounds.extend(geoJsonLayer.getBounds());
                }
                //map.setView(point, 12);
                layerGroup.addTo(map);
                map.fitBounds(bounds);
                container.css('opacity', '1');
            };

            var hideTooltip = function() {
                container.css('opacity', '0');
            };

            return {
                template: '',
                replace: true,
                restrict: 'E',
                transclude: true,
                scope: {
                    'coords': '=',
                    'width': '@',
                    'height': '@',
                    'delay': '@',
                    'geojson': '='
                },
                link: function(scope, element, attrs) {
                    var tooltipWidth = '200px';
                    var tooltipHeight = '200px';
                    var tooltipPop = null;

                    var delay = attrs.delay || 1000;
                    if (attrs.height) {
                        tooltipHeight = attrs.height+'px';
                    }
                    if (attrs.width) {
                        tooltipWidth = attrs.width+'px';
                    }

                    // Events
                    element.bind('mouseover', function() {
                        tooltipPop = $timeout(function() {
                            displayTooltip(element, tooltipWidth, tooltipHeight, scope.coords, scope.geojson);
                            tooltipPop = null;
                        }, delay);
                    });
                    element.bind('click', function() {
                        displayTooltip(element, tooltipWidth, tooltipHeight, scope.coords, scope.geojson);
                        if (tooltipPop !== null) {
                            // Chances are we triggered the original timer
                            $timeout.cancel(tooltipPop);
                            tooltipPop = null;
                        }
                    });
                    element.bind('mouseout', function() {
                        hideTooltip();
                        if (tooltipPop !== null) {
                            // We are currently counting down until the tooltip appearance, let's forget it
                            $timeout.cancel(tooltipPop);
                            tooltipPop = null;
                        }

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


<commit_before>/*globals module:true*/
module.exports = function(grunt) {
    'use strict';
    grunt.config('shell', {
        'testPhantom' : {
            options : {
                stdout : true,
                stderr : true,
                failOnError : true
            },
            command : 'mocha-phantomjs tests/index.html'
        },
        'bower'  : {
            options : {
                stdout : true,
                stderr : true,
                failOnError : true
            },
            command : 'bower install'
        },
        'commitJsdoc' : {
            options : {
                stdout : true,
                stderr : true,
                failOnError : true
            },
            command : 'git add -A && git commit docs -am "jsdoc update"'
        }
    });
};
<commit_msg>handling case of new files created during jsdoc run during deploy<commit_after>/*globals module:true*/
module.exports = function(grunt) {
    'use strict';
    grunt.config('shell', {
        'testPhantom' : {
            options : {
                stdout : true,
                stderr : true,
                failOnError : true
            },
            command : 'mocha-phantomjs tests/index.html'
        },
        'bower'  : {
            options : {
                stdout : true,
                stderr : true,
                failOnError : true
            },
            command : 'bower install'
        },
        'commitJsdoc' : {
            options : {
                stdout : true,
                stderr : true,
                failOnError : true
            },
            command : 'git add docs && git commit docs -m "jsdoc update"'
        }
    });
};
<|endoftext|>


<commit_before>var fs  = require('fs'),
		dsv = require('dsv');

function callMeMaybe(cb) {
  return util.isFunction(cb) ? cb : rethrow();
}

var formatters = {
  json: function(file){
    return JSON.stringify(file)
  },
  csv: function(file){
    return dsv.csv.format(file)
  },
  tsv: function(file){
    return dsv.tsv.format(file)
  },
  psv: function(file){
    return dsv.dsv('|').format(file)
  }
}

var parsers = {
  json: JSON,
  csv: dsv.csv,
  tsv: dsv.tsv,
  psv: dsv.dsv('|')
  // Dbf_Parser: require('node-dbf')
}

var helpers = {};

// Given a file name, determine its extension
// Used by: discernParser, discernFileFormatter
helpers.discernFormat = function(file_name) {
  var name_arr = file_name.split('\.')
  format_name  = name_arr[name_arr.length - 1];
  return format_name
}

// Given a file name, optionally a delimiter, return a parser that will turn that file into json
helpers.discernParser = function(file_name, delimiter){
  if (delimiter) return dsv(delimiter)
  var format = discernFormat(file_name);
  return parsers[format]
}

// Given a file name, return a parser that will convert that json object to its extension
helpers.discernFileFormatter = function(file_name){
  var format   = discernFormat(file_name);
  return formatters[format]
}

var readers = {}

// Figure out what the format is based on its file name
readers.readData = function(path, delimiter, cb_){
  var cb = callMeMaybe(arguments[arguments.length - 1]);
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, discernParser(path, delimiter).parse(data));
  })
}
readers.readDataSync = function(path, delimiter){
  return discernParser(path, delimiter).parse(fs.readFileSync(path, 'utf8'));
}

readers.readCsv = function(path, cb){
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, parsers.csv.parse(data));
  })
}
readers.readCsvSync = function(path){
  return parsers.csv.parse(fs.readFileSync(path, 'utf8'));
}

readers.readJson = function(path, cb){
  fs.readFile(path, function(err, data){
    cb(err, JSON.parse(data));
  })
}
readers.readJsonSync = function(path){
  return parsers.JSON.parse(fs.readFileSync(path));
}

readers.readTsv = function(path, cb){
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, parsers.tsv.parse(data));
  })
}
readers.readTsvSync = function(path){
  return parsers.tsv.parse(fs.readFileSync(path, 'utf8'));
}

readers.readPsv = function(path, cb){
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, parsers.psv.parse(data));
  })
}
readers.readPsvSync = function(path){
  return parsers.psv.parse(fs.readFileSync(path, 'utf8'));
}

// readDbf: function(path){
  //   var dbf_parser = new parsers.Dbf_Parser(path),
  //       rows = [];
  //   dbf_parser.on('record', function(p) {
  //       rows.push(p)
  //   });
  //   dbf_parser.on('end', function(p) {
  //       // console.log(rows)
  //   });
  //   dbf_parser.parse();

  // }
//}

var writers = {};

// Given a file path and json data, convert it to that format and write it
writers.writeData = function(path, data, cb){
  var fileFormatter = discernFileFormatter(file_path);
  fs.WriteFile(file_path, fileFormatter(data), function(err){
    cb(err)
  })
}
writers.writeDataSync = function(path, data){
  var fileFormatter = discernFileFormatter(file_path);
  fs.WriteFileSync(file_path, fileFormatter(data))
}

module.exports = {
  readData:             readers.readData,
  readDataSync:         readers.readDataSync,
  readCsv:              readers.readCsv,
  readCsvSync:          readers.readCsvSync,
  readJson:             readers.readJson,
  readJsonSync:         readers.readJsonSync,
  readTsv:              readers.readTsv,
  readTsvSync:          readers.readTsvSync,
  readPsv:              readers.readPsv,
  readPsvSync:          readers.readPsvSync,

  writeData:            writers.writeData,
  writeDataSync:        writers.writeDataSync,

  discernFormat:        helpers.discernFormat,
  discernParser:        helpers.discernParser,
  discernFileFormatter: helpers.discernFileFormatter,
}<commit_msg>fix syntax<commit_after>var fs  = require('fs'),
		dsv = require('dsv');

function callMeMaybe(cb) {
  return util.isFunction(cb) ? cb : rethrow();
}

var formatters = {
  json: function(file){
    return JSON.stringify(file)
  },
  csv: function(file){
    return dsv.csv.format(file)
  },
  tsv: function(file){
    return dsv.tsv.format(file)
  },
  psv: function(file){
    return dsv('|').format(file)
  }
}

var parsers = {
  json: JSON,
  csv: dsv.csv,
  tsv: dsv.tsv,
  psv: dsv('|')
  // Dbf_Parser: require('node-dbf')
}

var helpers = {};

// Given a file name, determine its extension
// Used by: discernParser, discernFileFormatter
helpers.discernFormat = function(file_name) {
  var name_arr = file_name.split('\.')
  format_name  = name_arr[name_arr.length - 1];
  return format_name
}

// Given a file name, optionally a delimiter, return a parser that will turn that file into json
helpers.discernParser = function(file_name, delimiter){
  if (delimiter) return dsv(delimiter)
  var format = helpers.discernFormat(file_name);
  return parsers[format]
}

// Given a file name, return a parser that will convert that json object to its extension
helpers.discernFileFormatter = function(file_name){
  var format   = helpers.discernFormat(file_name);
  return formatters[format]
}

var readers = {}

// Figure out what the format is based on its file name
readers.readData = function(path, delimiter, cb_){
  var cb = callMeMaybe(arguments[arguments.length - 1]);
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, helpers.discernParser(path, delimiter).parse(data));
  })
}
readers.readDataSync = function(path, delimiter){
  return helpers.discernParser(path, delimiter).parse(fs.readFileSync(path, 'utf8'));
}

readers.readCsv = function(path, cb){
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, parsers.csv.parse(data));
  })
}
readers.readCsvSync = function(path){
  return parsers.csv.parse(fs.readFileSync(path, 'utf8'));
}

readers.readJson = function(path, cb){
  fs.readFile(path, function(err, data){
    cb(err, JSON.parse(data));
  })
}
readers.readJsonSync = function(path){
  return parsers.JSON.parse(fs.readFileSync(path));
}

readers.readTsv = function(path, cb){
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, parsers.tsv.parse(data));
  })
}
readers.readTsvSync = function(path){
  return parsers.tsv.parse(fs.readFileSync(path, 'utf8'));
}

readers.readPsv = function(path, cb){
  fs.readFile(path, 'utf8', function(err, data){
    cb(err, parsers.psv.parse(data));
  })
}
readers.readPsvSync = function(path){
  return parsers.psv.parse(fs.readFileSync(path, 'utf8'));
}

// readDbf: function(path){
  //   var dbf_parser = new parsers.Dbf_Parser(path),
  //       rows = [];
  //   dbf_parser.on('record', function(p) {
  //       rows.push(p)
  //   });
  //   dbf_parser.on('end', function(p) {
  //       // console.log(rows)
  //   });
  //   dbf_parser.parse();

  // }
//}

var writers = {};

// Given a file path and json data, convert it to that format and write it
writers.writeData = function(path, data, cb){
  var fileFormatter = discernFileFormatter(file_path);
  fs.WriteFile(file_path, fileFormatter(data), function(err){
    cb(err)
  })
}
writers.writeDataSync = function(path, data){
  var fileFormatter = discernFileFormatter(file_path);
  fs.WriteFileSync(file_path, fileFormatter(data))
}

module.exports = {
  readData:             readers.readData,
  readDataSync:         readers.readDataSync,
  readCsv:              readers.readCsv,
  readCsvSync:          readers.readCsvSync,
  readJson:             readers.readJson,
  readJsonSync:         readers.readJsonSync,
  readTsv:              readers.readTsv,
  readTsvSync:          readers.readTsvSync,
  readPsv:              readers.readPsv,
  readPsvSync:          readers.readPsvSync,

  writeData:            writers.writeData,
  writeDataSync:        writers.writeDataSync,

  discernFormat:        helpers.discernFormat,
  discernParser:        helpers.discernParser,
  discernFileFormatter: helpers.discernFileFormatter,
}<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

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

const assert = require('assert');
const acceptInvite = require("./accept-invite")
module.exports = async function acceptServerNoticesInviteAndConsent(session) {
    await acceptInvite(session, "Server Notices");
    session.log.step(`accepts terms & conditions`);
    const consentLink = await session.waitAndQuery(".mx_EventTile_body a");
    const termsPagePromise = session.waitForNewPage();
    await consentLink.click();
    const termsPage = await termsPagePromise;
    const acceptButton = await termsPage.$('input[type=submit]');
    await acceptButton.click();
    await session.delay(1000); //TODO yuck, timers
    await termsPage.close();
    session.log.done();
}
<commit_msg>increase timeout for server notices room<commit_after>/*
Copyright 2018 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

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

const assert = require('assert');
const acceptInvite = require("./accept-invite")
module.exports = async function acceptServerNoticesInviteAndConsent(session) {
    await acceptInvite(session, "Server Notices");
    session.log.step(`accepts terms & conditions`);
    const consentLink = await session.waitAndQuery(".mx_EventTile_body a", 10000);
    const termsPagePromise = session.waitForNewPage();
    await consentLink.click();
    const termsPage = await termsPagePromise;
    const acceptButton = await termsPage.$('input[type=submit]');
    await acceptButton.click();
    await session.delay(1000); //TODO yuck, timers
    await termsPage.close();
    session.log.done();
}
<|endoftext|>


<commit_before>import { sym } from './utils';

export default {
  _null: value => value === null,
  _undefined: value => value === undefined,
  func: value => typeof value === 'function',
  promise: value => value && typeof value.then === 'function',
  list: value => Array.isArray(value),
  number: value => typeof value === 'number',
  boolean: value => typeof value === 'boolean',
  string: value => typeof value === 'string',
  map: value => !(value === null) && !Array.isArray(value) && (typeof value === 'object'),
  factory: value => value[sym('factory')],
  node: value => value[sym('node')],
  schema: value => value[sym('schema')],
  type: value => value[sym('type')],
};
<commit_msg>minor "is" fix<commit_after>import { sym } from './utils';

export default {
  _null: value => value === null,
  _undefined: value => value === undefined,
  func: value => typeof value === 'function',
  promise: value => value && typeof value.then === 'function',
  list: value => Array.isArray(value),
  number: value => typeof value === 'number',
  boolean: value => typeof value === 'boolean',
  string: value => typeof value === 'string',
  map: value => !(value === null) && !Array.isArray(value) && (typeof value === 'object'),
  factory: value => value[sym('factory')],
  node: value => !!value[sym('node')],
  schema: value => !!value[sym('schema')],
  type: value => !!value[sym('type')],
};
<|endoftext|>