<commit_before>/*eslint-env node, mocha */
/*global $database */
import request from 'superagent'
import mkdirp from 'mkdirp'

import { getSingleton } from '../../app/app'
import { load as configLoader } from '../../config/config'
import * as funcTestHelper from './functional_test_helper'

const config = configLoader()

describe("GroupsController", function() {
  let app

  beforeEach(async () => {
    app = await getSingleton()
    await $database.flushdbAsync()
  })

  describe("#create()", function() {
    var context = {}

    beforeEach(funcTestHelper.createUserCtx(context, 'Luna', 'password'))

    it('should reject unauthenticated users', function(done) {
      request
          .post(app.config.host + '/v1/groups')
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(401)
            done()
          })
    })

    it('should create a group', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
              authToken: context.authToken })
          .end(function(err, res) {
            res.body.should.not.be.empty
            res.body.should.have.property('groups')
            res.body.groups.should.have.property('username')
            res.body.groups.should.have.property('screenName')
            res.body.groups.username.should.eql(userName)
            res.body.groups.screenName.should.eql(screenName)
            done()
          })
    })

    it('should create a private group', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName, isPrivate: '1'},
            authToken: context.authToken })
          .end(function(err, res) {
            res.body.should.not.be.empty
            res.body.should.have.property('groups')
            res.body.groups.isPrivate.should.eql('1')
            done()
          })
    })

    it('should not create a group if a user with that name already exists', function(done) {
      var userName = 'Luna';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(422)
            done()
          })
    })

    it('should not create a group with slash in its name', function(done) {
      var userName = 'Lu/na';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(422)
            err.response.error.should.have.property('text')
            JSON.parse(err.response.error.text).err.should.eql('Invalid username')
            done()
          })
    })

    it('should not create a group with an empty username', function(done) {
      var userName = '';
      var screenName = '';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(422)
            err.response.error.should.have.property('text')
            JSON.parse(err.response.error.text).err.should.eql('Invalid username')
            done()
          })
    })

    it('should add the creating user as the administrator', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            // TODO[yole] check that the user is an administrator
            done()
          })
    })

    it('should subscribe the creating user', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            var newGroupId = res.body.groups.id
            request
                .get(app.config.host + '/v1/users/Luna/subscriptions')
                .query({ authToken: context.authToken })
                .end(function(err, res) {
                  res.status.should.not.eql(404)
                  res.status.should.not.eql(422)
                  res.body.should.not.be.empty
                  res.body.should.have.property('subscribers')
                  res.body.should.have.property('subscriptions')
                  var subIds = res.body.subscriptions.map(function(sub) { return sub.user })
                  subIds.should.contain(newGroupId)
                  var users = res.body.subscribers
                  users.length.should.eql(1)
                  users[0].type.should.eql("group")
                  done()
                })
          })
    })
  })

  describe('#admin', function() {
    var adminContext = {}
      , nonAdminContext = {}

    beforeEach(funcTestHelper.createUserCtx(adminContext, 'Luna', 'password'))
    beforeEach(funcTestHelper.createUserCtx(nonAdminContext, 'yole', 'wordpass'))

    beforeEach(function(done) {
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
            authToken: adminContext.authToken })
          .end(function(err, res) {
            done()
          })

    })

    it('should reject unauthenticated users', function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/admin')
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(403)
            done()
          })
    })

    it('should reject nonexisting group', function(done) {
      request
          .post(app.config.host + '/v1/groups/foobar/subscribers/yole/admin')
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(404)
            done()
          })
    })
    it('should allow an administrator to add another administrator', function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/admin')
          .send({authToken: adminContext.authToken })
          .end(function(err, res) {
            res.status.should.eql(200)
            done()
          })
    })
  })

  describe('#update', function() {
    var context = {}
      , group

    beforeEach(funcTestHelper.createUserCtx(context, 'Luna', 'password'))

    beforeEach(function(done) {
      request
        .post(app.config.host + '/v1/groups')
        .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
                authToken: context.authToken
              })
        .end(function(err, res) {
          group = res.body.groups
          done()
        })
    })

    it('should update group settings', function(done) {
      var screenName = 'mokum-dev'
      var description = 'Mokum Developers'

      request
        .post(app.config.host + '/v1/users/' + group.id)
        .send({ authToken: context.authToken,
                user: { screenName: screenName, description: description },
                '_method': 'put' })
        .end(function(err, res) {
          res.should.not.be.empty
          res.body.should.not.be.empty
          res.body.should.have.property('groups')
          res.body.groups.should.have.property('id')
          res.body.groups.should.have.property('screenName')
          res.body.groups.screenName.should.eql(screenName)
          res.body.groups.should.have.property('description')
          res.body.groups.description.should.eql(description)
          done()
        })
    })

    it("should not reset description if it's not provided", async () => {
      var oldScreenName = group.screenName
      var newScreenName = 'vanilla-dev'
      var newDescription = 'Vanilla Developer(s)'

      // First, check screenName and description (should be the old ones)
      {
        const response = await funcTestHelper.getUserAsync({}, group.username)
        response.status.should.equal(200)

        const data = await response.json()
        data.should.have.property('users')
        data.users.should.have.property('screenName')
        data.users.screenName.should.eql(oldScreenName) // old screenName
        data.users.should.not.have.property('description') // no description property (since it's empty)
      }

      // Second, only update description (screenName shouldn't change)
      {
        const userContext = {
          user: group,
          authToken: context.authToken
        }
        await funcTestHelper.updateUserAsync(userContext, {
          description: newDescription
        })

        const response = await funcTestHelper.getUserAsync({}, group.username)
        response.status.should.equal(200)

        const data = await response.json()
        data.should.have.property('users')
        data.users.should.have.property('screenName')
        data.users.screenName.should.eql(oldScreenName) // old screenName
        data.users.should.have.property('description')
        data.users.description.should.eql(newDescription) // new description
      }

      // Third, only update screenName (description shouldn't change)
      {
        const userContext = {
          user: group,
          authToken: context.authToken
        }
        await funcTestHelper.updateUserAsync(userContext, {
          screenName: newScreenName
        })

        const response = await funcTestHelper.getUserAsync({}, group.username)
        response.status.should.equal(200)

        const data = await response.json()
        data.should.have.property('users')
        data.users.should.have.property('screenName')
        data.users.screenName.should.eql(newScreenName) // new screenName
        data.users.should.have.property('description')
        data.users.description.should.eql(newDescription) // new description
      }
    })
  })

  describe('#unadmin', function() {
    var adminContext = {}
      , nonAdminContext = {}

    beforeEach(funcTestHelper.createUserCtx(adminContext, 'Luna', 'password'))
    beforeEach(funcTestHelper.createUserCtx(nonAdminContext, 'yole', 'wordpass'))

    beforeEach(function(done) {
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
            authToken: adminContext.authToken })
          .end(function(err, res) {
            done()
          })

    })

    beforeEach(function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/admin')
          .send({ authToken: adminContext.authToken })
          .end(function(err, res) {
            done()
          })
    })

    it('should allow an administrator to remove another administrator', function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/unadmin')
          .send({ authToken: adminContext.authToken })
          .end(function(err, res) {
            res.status.should.eql(200)
            done()
          })
    })
  })

  describe('#updateProfilePicture', function() {
    var context = {}

    beforeEach(funcTestHelper.createUserCtx(context, 'Luna', 'password'))

    beforeEach(function(done){
      mkdirp.sync(config.profilePictures.storage.rootDir + config.profilePictures.path)
      done()
    })

    beforeEach(function(done) {
      request
        .post(app.config.host + '/v1/groups')
        .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
          authToken: context.authToken })
        .end(function(err, res) {
          done()
        })
    })

    it('should update the profile picture', function(done) {
      request
        .post(app.config.host + '/v1/groups/pepyatka-dev/updateProfilePicture')
        .set('X-Authentication-Token', context.authToken)
        .attach('file', 'test/fixtures/default-userpic-75.gif')
        .end(function(err, res) {
          res.status.should.eql(200)
          res.body.should.not.be.empty
          request
            .get(app.config.host + '/v1/users/pepyatka-dev')
            .query({ authToken: context.authToken })
            .end(function(err, res) {
              res.should.not.be.empty
              res.body.users.profilePictureLargeUrl.should.not.be.empty
              done()
            })
        })
    })
  })
})
<commit_msg>Remove the test for private groups<commit_after>/*eslint-env node, mocha */
/*global $database */
import request from 'superagent'
import mkdirp from 'mkdirp'

import { getSingleton } from '../../app/app'
import { load as configLoader } from '../../config/config'
import * as funcTestHelper from './functional_test_helper'

const config = configLoader()

describe("GroupsController", function() {
  let app

  beforeEach(async () => {
    app = await getSingleton()
    await $database.flushdbAsync()
  })

  describe("#create()", function() {
    var context = {}

    beforeEach(funcTestHelper.createUserCtx(context, 'Luna', 'password'))

    it('should reject unauthenticated users', function(done) {
      request
          .post(app.config.host + '/v1/groups')
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(401)
            done()
          })
    })

    it('should create a group', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
              authToken: context.authToken })
          .end(function(err, res) {
            res.body.should.not.be.empty
            res.body.should.have.property('groups')
            res.body.groups.should.have.property('username')
            res.body.groups.should.have.property('screenName')
            res.body.groups.username.should.eql(userName)
            res.body.groups.screenName.should.eql(screenName)
            done()
          })
    })

    xit('should create a private group')

    it('should not create a group if a user with that name already exists', function(done) {
      var userName = 'Luna';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(422)
            done()
          })
    })

    it('should not create a group with slash in its name', function(done) {
      var userName = 'Lu/na';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(422)
            err.response.error.should.have.property('text')
            JSON.parse(err.response.error.text).err.should.eql('Invalid username')
            done()
          })
    })

    it('should not create a group with an empty username', function(done) {
      var userName = '';
      var screenName = '';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(422)
            err.response.error.should.have.property('text')
            JSON.parse(err.response.error.text).err.should.eql('Invalid username')
            done()
          })
    })

    it('should add the creating user as the administrator', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            // TODO[yole] check that the user is an administrator
            done()
          })
    })

    it('should subscribe the creating user', function(done) {
      var userName = 'pepyatka-dev';
      var screenName = 'Pepyatka Developers';
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: userName, screenName: screenName},
            authToken: context.authToken })
          .end(function(err, res) {
            var newGroupId = res.body.groups.id
            request
                .get(app.config.host + '/v1/users/Luna/subscriptions')
                .query({ authToken: context.authToken })
                .end(function(err, res) {
                  res.status.should.not.eql(404)
                  res.status.should.not.eql(422)
                  res.body.should.not.be.empty
                  res.body.should.have.property('subscribers')
                  res.body.should.have.property('subscriptions')
                  var subIds = res.body.subscriptions.map(function(sub) { return sub.user })
                  subIds.should.contain(newGroupId)
                  var users = res.body.subscribers
                  users.length.should.eql(1)
                  users[0].type.should.eql("group")
                  done()
                })
          })
    })
  })

  describe('#admin', function() {
    var adminContext = {}
      , nonAdminContext = {}

    beforeEach(funcTestHelper.createUserCtx(adminContext, 'Luna', 'password'))
    beforeEach(funcTestHelper.createUserCtx(nonAdminContext, 'yole', 'wordpass'))

    beforeEach(function(done) {
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
            authToken: adminContext.authToken })
          .end(function(err, res) {
            done()
          })

    })

    it('should reject unauthenticated users', function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/admin')
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(403)
            done()
          })
    })

    it('should reject nonexisting group', function(done) {
      request
          .post(app.config.host + '/v1/groups/foobar/subscribers/yole/admin')
          .end(function(err, res) {
            err.should.not.be.empty
            err.status.should.eql(404)
            done()
          })
    })
    it('should allow an administrator to add another administrator', function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/admin')
          .send({authToken: adminContext.authToken })
          .end(function(err, res) {
            res.status.should.eql(200)
            done()
          })
    })
  })

  describe('#update', function() {
    var context = {}
      , group

    beforeEach(funcTestHelper.createUserCtx(context, 'Luna', 'password'))

    beforeEach(function(done) {
      request
        .post(app.config.host + '/v1/groups')
        .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
                authToken: context.authToken
              })
        .end(function(err, res) {
          group = res.body.groups
          done()
        })
    })

    it('should update group settings', function(done) {
      var screenName = 'mokum-dev'
      var description = 'Mokum Developers'

      request
        .post(app.config.host + '/v1/users/' + group.id)
        .send({ authToken: context.authToken,
                user: { screenName: screenName, description: description },
                '_method': 'put' })
        .end(function(err, res) {
          res.should.not.be.empty
          res.body.should.not.be.empty
          res.body.should.have.property('groups')
          res.body.groups.should.have.property('id')
          res.body.groups.should.have.property('screenName')
          res.body.groups.screenName.should.eql(screenName)
          res.body.groups.should.have.property('description')
          res.body.groups.description.should.eql(description)
          done()
        })
    })

    it("should not reset description if it's not provided", async () => {
      var oldScreenName = group.screenName
      var newScreenName = 'vanilla-dev'
      var newDescription = 'Vanilla Developer(s)'

      // First, check screenName and description (should be the old ones)
      {
        const response = await funcTestHelper.getUserAsync({}, group.username)
        response.status.should.equal(200)

        const data = await response.json()
        data.should.have.property('users')
        data.users.should.have.property('screenName')
        data.users.screenName.should.eql(oldScreenName) // old screenName
        data.users.should.not.have.property('description') // no description property (since it's empty)
      }

      // Second, only update description (screenName shouldn't change)
      {
        const userContext = {
          user: group,
          authToken: context.authToken
        }
        await funcTestHelper.updateUserAsync(userContext, {
          description: newDescription
        })

        const response = await funcTestHelper.getUserAsync({}, group.username)
        response.status.should.equal(200)

        const data = await response.json()
        data.should.have.property('users')
        data.users.should.have.property('screenName')
        data.users.screenName.should.eql(oldScreenName) // old screenName
        data.users.should.have.property('description')
        data.users.description.should.eql(newDescription) // new description
      }

      // Third, only update screenName (description shouldn't change)
      {
        const userContext = {
          user: group,
          authToken: context.authToken
        }
        await funcTestHelper.updateUserAsync(userContext, {
          screenName: newScreenName
        })

        const response = await funcTestHelper.getUserAsync({}, group.username)
        response.status.should.equal(200)

        const data = await response.json()
        data.should.have.property('users')
        data.users.should.have.property('screenName')
        data.users.screenName.should.eql(newScreenName) // new screenName
        data.users.should.have.property('description')
        data.users.description.should.eql(newDescription) // new description
      }
    })
  })

  describe('#unadmin', function() {
    var adminContext = {}
      , nonAdminContext = {}

    beforeEach(funcTestHelper.createUserCtx(adminContext, 'Luna', 'password'))
    beforeEach(funcTestHelper.createUserCtx(nonAdminContext, 'yole', 'wordpass'))

    beforeEach(function(done) {
      request
          .post(app.config.host + '/v1/groups')
          .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
            authToken: adminContext.authToken })
          .end(function(err, res) {
            done()
          })

    })

    beforeEach(function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/admin')
          .send({ authToken: adminContext.authToken })
          .end(function(err, res) {
            done()
          })
    })

    it('should allow an administrator to remove another administrator', function(done) {
      request
          .post(app.config.host + '/v1/groups/pepyatka-dev/subscribers/yole/unadmin')
          .send({ authToken: adminContext.authToken })
          .end(function(err, res) {
            res.status.should.eql(200)
            done()
          })
    })
  })

  describe('#updateProfilePicture', function() {
    var context = {}

    beforeEach(funcTestHelper.createUserCtx(context, 'Luna', 'password'))

    beforeEach(function(done){
      mkdirp.sync(config.profilePictures.storage.rootDir + config.profilePictures.path)
      done()
    })

    beforeEach(function(done) {
      request
        .post(app.config.host + '/v1/groups')
        .send({ group: {username: 'pepyatka-dev', screenName: 'Pepyatka Developers'},
          authToken: context.authToken })
        .end(function(err, res) {
          done()
        })
    })

    it('should update the profile picture', function(done) {
      request
        .post(app.config.host + '/v1/groups/pepyatka-dev/updateProfilePicture')
        .set('X-Authentication-Token', context.authToken)
        .attach('file', 'test/fixtures/default-userpic-75.gif')
        .end(function(err, res) {
          res.status.should.eql(200)
          res.body.should.not.be.empty
          request
            .get(app.config.host + '/v1/users/pepyatka-dev')
            .query({ authToken: context.authToken })
            .end(function(err, res) {
              res.should.not.be.empty
              res.body.users.profilePictureLargeUrl.should.not.be.empty
              done()
            })
        })
    })
  })
})
<|endoftext|>


<commit_before>var Kabam = require('./../index.js'),
  request = require('request');

var kabam = Kabam({
  'hostUrl': 'http://vvv.msk0.ru/',
  'mongoUrl': 'mongodb://localhost/mwc_dev',
  'secret': 'Long_and_hard_secret',
  'redis': 'redis://mwcKernel:@localhost:6379',
  'emailConfig': ((process.env.emailConfig) ? (process.env.emailConfig) : 'myemail@gmail.com:1234567'),
  'passport': {
    'GITHUB_CLIENT_ID': '--insert-github-client-id-here--',
    'GITHUB_CLIENT_SECRET': '--insert-github-client-secret-here--',
    'TWITTER_CONSUMER_KEY': '--insert-twitter-consumer-key-here--',
    'TWITTER_CONSUMER_SECRET': '--insert-twitter-consumer-secret-here--',
    'FACEBOOK_APP_ID': '--insert-facebook-app-id-here--',
    'FACEBOOK_APP_SECRET': '--insert-facebook-app-secret-here--'
  },
  'spine': {
    'domains': ['urgentTasks']
  }
});

kabam.extendRoutes(function(core) {
  core.app.get('/', function(request, response) {
    response.render('index', {
      userAgent: request.headers['user-agent'],
      title: 'Welcome!'
    });
  });
});

kabam.start(3008);

describe('npm can build and run this application', function() {
  var response, body;
  before(function(done) {
    request.get('http://localhost:3008/', function(err, res, b) {
      if (err) {
        throw err;
      }
      response = res;
      body = b;
      done();
    });
  });

  it('it starts HTTP server on port localhost:3008', function() {
    response.statusCode.should.equal(200); //this is ok
  });

  it('this server runs a ExpressJS application', function() {
    response.headers['x-powered-by'].should.be.equal('Express');
  });

});<commit_msg>fix(test): add require should<commit_after>var Kabam = require('./../index.js'),
  request = require('request'),
  should = require('should');

var kabam = Kabam({
  'hostUrl': 'http://vvv.msk0.ru/',
  'mongoUrl': 'mongodb://localhost/mwc_dev',
  'secret': 'Long_and_hard_secret',
  'redis': 'redis://mwcKernel:@localhost:6379',
  'emailConfig': ((process.env.emailConfig) ? (process.env.emailConfig) : 'myemail@gmail.com:1234567'),
  'passport': {
    'GITHUB_CLIENT_ID': '--insert-github-client-id-here--',
    'GITHUB_CLIENT_SECRET': '--insert-github-client-secret-here--',
    'TWITTER_CONSUMER_KEY': '--insert-twitter-consumer-key-here--',
    'TWITTER_CONSUMER_SECRET': '--insert-twitter-consumer-secret-here--',
    'FACEBOOK_APP_ID': '--insert-facebook-app-id-here--',
    'FACEBOOK_APP_SECRET': '--insert-facebook-app-secret-here--'
  },
  'spine': {
    'domains': ['urgentTasks']
  }
});

kabam.extendRoutes(function(core) {
  core.app.get('/', function(request, response) {
    response.render('index', {
      userAgent: request.headers['user-agent'],
      title: 'Welcome!'
    });
  });
});

kabam.start(3008);

describe('npm can build and run this application', function() {
  var response, body;
  before(function(done) {
    request.get('http://localhost:3008/', function(err, res, b) {
      if (err) {
        throw err;
      }
      response = res;
      body = b;
      done();
    });
  });

  it('it starts HTTP server on port localhost:3008', function() {
    response.statusCode.should.equal(200); //this is ok
  });

  it('this server runs a ExpressJS application', function() {
    response.headers['x-powered-by'].should.be.equal('Express');
  });

});
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs-extra'),
    path = require('path'),
    exec = require('child_process').exec,
    Repo = require('../lib/common/repo'),
    storage = require('../lib/storage/filesystem');

var git_folder = 'git-repo';
var jit_folder = 'jit-repo';

/**
*
* Verify git and jit agree on cat-file -p
*
**/

exports.testCatFileContent = function(test) {
  var content = 'hello boys, how are you?';

  exec('git init ' + git_folder, createObject);

  function createObject(err, stdout, stderr) {
    exec('echo "' + content + '" | git hash-object --stdin -w', readObject);
  };

  function readObject(err, stdout, stderr) {
    exec('git cat-file -p ' + stdout, continueTest);
  }

  function continueTest(err, stdout, stderr) {
    var repo = new Repo(jit_folder + '/.git', storage);
    repo.init(function(err) {
      repo.write_blob({content: content + '\n'}, function(err, blob) {
        test.equal(err, null);
        repo.read_object(blob, function(err, blob) {
          test.equal(err, null);
          test.ok(blob.content == stdout);
          fs.removeSync(git_folder);
          fs.removeSync(jit_folder);

          test.done();
        });
      });
    });
  }
}
<commit_msg>Add test for cat-file -t and -s<commit_after>'use strict';

var fs = require('fs-extra'),
    path = require('path'),
    exec = require('child_process').exec,
    Repo = require('../lib/common/repo'),
    storage = require('../lib/storage/filesystem');

var git_folder = 'git-repo';
var jit_folder = 'jit-repo';

/**
*
* Verify git and jit agree on cat-file -p
*
**/

exports.testCatFileContent = function(test) {
  var content = 'hello boys, how are you?';

  exec('git init ' + git_folder, createObject);

  function createObject(err, stdout, stderr) {
    exec('echo "' + content + '" | git hash-object --stdin -w', readObject);
  };

  function readObject(err, stdout, stderr) {
    exec('git cat-file -p ' + stdout, continueTest);
  }

  function continueTest(err, stdout, stderr) {
    var repo = new Repo(jit_folder + '/.git', storage);
    repo.init(function(err) {
      repo.write_blob({content: content + '\n'}, function(err, blob) {
        test.equal(err, null);
        repo.read_object(blob, function(err, blob) {
          test.equal(err, null);
          test.ok(blob.content == stdout);
          fs.removeSync(git_folder);
          fs.removeSync(jit_folder);

          test.done();
        });
      });
    });
  }
}

exports.testCatFileType = function(test) {
  var content = 'hello boys, how are you?';

  exec('git init ' + git_folder, createObject);

  function createObject(err, stdout, stderr) {
    exec('echo "' + content + '" | git hash-object --stdin -w', readObject);
  };

  function readObject(err, stdout, stderr) {
    exec('git cat-file -t ' + stdout, continueTest);
  }

  function continueTest(err, stdout, stderr) {
    var repo = new Repo(jit_folder + '/.git', storage);
    repo.init(function(err) {
      repo.write_blob({content: content + '\n'}, function(err, blob) {
        test.equal(err, null);
        repo.read_object(blob, function(err, blob) {
          test.equal(err, null);
          test.ok(blob.type == stdout.replace(/[\n]/g, ''));
          fs.removeSync(git_folder);
          fs.removeSync(jit_folder);

          test.done();
        });
      });
    });
  }
}

exports.testCatFileSize = function(test) {
  var content = 'hello boys, how are you?';

  exec('git init ' + git_folder, createObject);

  function createObject(err, stdout, stderr) {
    exec('echo "' + content + '" | git hash-object --stdin -w', readObject);
  };

  function readObject(err, stdout, stderr) {
    exec('git cat-file -s ' + stdout, continueTest);
  }

  function continueTest(err, stdout, stderr) {
    var repo = new Repo(jit_folder + '/.git', storage);
    repo.init(function(err) {
      repo.write_blob({content: content + '\n'}, function(err, blob) {
        test.equal(err, null);
        repo.read_object(blob, function(err, blob) {
          test.equal(err, null);
          test.ok(parseInt(blob.size) == parseInt(stdout));
          fs.removeSync(git_folder);
          fs.removeSync(jit_folder);

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


<commit_before>'use strict';

var assert                                = require('assert'),
    exec                                  = require('child_process').exec,
    logHook                               = require('../helpers/logHook.js'),
    fs                                    = require('fs'),
    path                                  = require('path'),
    async                                 = require('async'),
    generate                              = require(path.join(process.env.PWD, 'lib/generate')),
    demoAppEndDir                         = 'test/results/my_app',
    demoAppPath                           = path.join(process.env.PWD, demoAppEndDir),
    program                               = {},
    logs                                  = [],
    newProjectDirectoriesThatShouldExist  = [];

/**
 * Executes a child process to forcefully remove
 * a directory containing files
 *
 * @param  {String}   dirPath The path of the directory to remove
 * @param  {Function} cb      [The function to execute when finished
 * @return {Void}
 */
function removeForcefully (dirPath, cb) {
    exec('rm -rf '+ dirPath, function(err){
        cb(err);
    });
}

/**
 * Executes a child process to forcefully remove
 * a directory containing files
 *
 * @param  {String}   dirPath The path of the directory to remove
 * @param  {Function} cb      The function to execute when finished
 * @return {Void}
 */
function removeDirectoryIfExists (dirPath, cb) {
    fs.exists(dirPath, function (exists) {
        if (exists) {
            removeForcefully(dirPath, cb);
        } else {
            cb();
        }
    });
}

describe('lib/generate', function () {

    beforeEach(function (done) {

        logs    = [];

        program = {
          args: ['new', demoAppEndDir]
        };

        newProjectDirectoriesThatShouldExist = [
          demoAppEndDir,
          path.join(demoAppPath, '/client'),
          path.join(demoAppPath, '/client/code'),
          path.join(demoAppPath, '/client/code/app'),
          path.join(demoAppPath, '/client/code/libs'),
          path.join(demoAppPath, '/client/views'),
          path.join(demoAppPath, '/client/css'),
          path.join(demoAppPath, '/client/css/libs'),
          path.join(demoAppPath, '/client/templates'),
          path.join(demoAppPath, '/client/static'),
          path.join(demoAppPath, '/client/static/images'),
          path.join(demoAppPath, '/server'),
          path.join(demoAppPath, '/server/rpc'),
          path.join(demoAppPath, '/server/middleware')
        ];

        removeDirectoryIfExists(demoAppPath, done);

    });

    afterEach(function (done) {
        removeDirectoryIfExists(demoAppPath, done);
    });

    it('should generate an app inside of a folder with a unique name', function (done) {

        /* hide console.log output to make Mocha output clear */
        logHook.on();
        generate.generate(program);

        logs = logHook.off();

        /* Using 'async' library to check if all the required project's folders exist */
        async.reject(newProjectDirectoriesThatShouldExist, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should raise an error if the name of the app matches the name of an existing folder', function (done) {

        fs.mkdir(demoAppPath, function(err) {

            // Call for hook function for console.log
            logHook.on();
            generate.generate(program);
            logs = logHook.off();

            assert.equal(1,logs.length);
            assert.equal(
                'Sorry the \'' + demoAppEndDir + '\' directory already exists. Please choose another name for your app.',
                logs[0].toString()
            );

            if (err) {
                done(err);
            } else {
                done();
            }
        });
    });

    it('should generate an app with coffeescript files if coffeescript was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingCoffeeScript = [
            path.join(demoAppPath, '/client/code/app/app.coffee'),
            path.join(demoAppPath, '/client/code/app/entry.coffee'),
            path.join(demoAppPath, '/server/middleware/example.coffee'),
            path.join(demoAppPath, '/server/rpc/demo.coffee')
        ];

        program.coffee = true;

        /* hide console.log output to make Mocha output clear */
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's coffeescript files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingCoffeeScript, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });
    });

    it('should raise an error if no name is provided for the app', function (done) {

        program.args = ['new'];

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        assert.equal(1,logs.length);
        assert.equal(
            'Please provide a name for your application: $> socketstream new <MyAppName>',
            logs[0].toString()
        );
        done();

    });

    it('should generate an app with jade templates if jade was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingJade = [
            path.join(demoAppPath, '/client/templates/chat/message.jade'),
            path.join(demoAppPath, '/client/views/app.jade')
        ];

        program.jade = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's jade files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingJade, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with css stylesheets if css was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingCss = [
            path.join(demoAppPath, '/client/css/app.css'),
        ];

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's css files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingCss, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with less stylesheets if less was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingLess = [
            path.join(demoAppPath, '/client/css/app.less'),
        ];

        program.less = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's less files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingLess, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with stylus stylesheets if stylus was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingStylus = [
            path.join(demoAppPath, '/client/css/app.styl'),
        ];

        program.stylus = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's less files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingStylus, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with no demo code, if a minimal app was requested', function (done) {

        var newProjectFilesThatBelongToDemo = [
            path.join(demoAppPath, '/client/static/images/logo.png'),
            path.join(demoAppPath, '/server/middleware/example.js'),
            path.join(demoAppPath, '/server/rpc/demo.js'),
            path.join(demoAppPath, '/client/css/libs/reset.css'),
            path.join(demoAppPath, '/client/templates/chat/message.html')
        ];

        program.minimal = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's coffeescript files exist */
        async.reject(newProjectFilesThatBelongToDemo, fs.exists, function (result) {
            assert.equal(newProjectFilesThatBelongToDemo.length, result.length);
            done();
        });
    });

    it('should generate an app with the ss-console library, if the repl library was requested', function (done) {

        program.repl = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        fs.readFile(path.join(demoAppPath,'/app.js'), 'utf-8', function (err, appJsContents) {
            assert.notEqual(-1, appJsContents.indexOf('// Start Console Server (REPL)'));
            assert.notEqual(-1, appJsContents.indexOf('// To install client: sudo npm install -g ss-console'));
            assert.notEqual(-1, appJsContents.indexOf('// To connect: ss-console <optional_host_or_port>'));
            assert.notEqual(-1, appJsContents.indexOf('var consoleServer = require(\'ss-console\')(ss);'));
            assert.notEqual(-1, appJsContents.indexOf('consoleServer.listen(5000);'));
            done();

        });
    });
});<commit_msg>A fix<commit_after>'use strict';

var assert                                = require('assert'),
    exec                                  = require('child_process').exec,
    logHook                               = require('./../helpers/logHook.js'),
    fs                                    = require('fs'),
    path                                  = require('path'),
    async                                 = require('async'),
    generate                              = require(path.join(process.env.PWD, 'lib/generate')),
    demoAppEndDir                         = 'test/results/my_app',
    demoAppPath                           = path.join(process.env.PWD, demoAppEndDir),
    program                               = {},
    logs                                  = [],
    newProjectDirectoriesThatShouldExist  = [];

/**
 * Executes a child process to forcefully remove
 * a directory containing files
 *
 * @param  {String}   dirPath The path of the directory to remove
 * @param  {Function} cb      [The function to execute when finished
 * @return {Void}
 */
function removeForcefully (dirPath, cb) {
    exec('rm -rf '+ dirPath, function(err){
        cb(err);
    });
}

/**
 * Executes a child process to forcefully remove
 * a directory containing files
 *
 * @param  {String}   dirPath The path of the directory to remove
 * @param  {Function} cb      The function to execute when finished
 * @return {Void}
 */
function removeDirectoryIfExists (dirPath, cb) {
    fs.exists(dirPath, function (exists) {
        if (exists) {
            removeForcefully(dirPath, cb);
        } else {
            cb();
        }
    });
}

describe('lib/generate', function () {

    beforeEach(function (done) {

        logs    = [];

        program = {
          args: ['new', demoAppEndDir]
        };

        newProjectDirectoriesThatShouldExist = [
          demoAppEndDir,
          path.join(demoAppPath, '/client'),
          path.join(demoAppPath, '/client/code'),
          path.join(demoAppPath, '/client/code/app'),
          path.join(demoAppPath, '/client/code/libs'),
          path.join(demoAppPath, '/client/views'),
          path.join(demoAppPath, '/client/css'),
          path.join(demoAppPath, '/client/css/libs'),
          path.join(demoAppPath, '/client/templates'),
          path.join(demoAppPath, '/client/static'),
          path.join(demoAppPath, '/client/static/images'),
          path.join(demoAppPath, '/server'),
          path.join(demoAppPath, '/server/rpc'),
          path.join(demoAppPath, '/server/middleware')
        ];

        removeDirectoryIfExists(demoAppPath, done);

    });

    afterEach(function (done) {
        removeDirectoryIfExists(demoAppPath, done);
    });

    it('should generate an app inside of a folder with a unique name', function (done) {

        /* hide console.log output to make Mocha output clear */
        logHook.on();
        generate.generate(program);

        logs = logHook.off();

        /* Using 'async' library to check if all the required project's folders exist */
        async.reject(newProjectDirectoriesThatShouldExist, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should raise an error if the name of the app matches the name of an existing folder', function (done) {

        fs.mkdir(demoAppPath, function(err) {

            // Call for hook function for console.log
            logHook.on();
            generate.generate(program);
            logs = logHook.off();

            assert.equal(1,logs.length);
            assert.equal(
                'Sorry the \'' + demoAppEndDir + '\' directory already exists. Please choose another name for your app.',
                logs[0].toString()
            );

            if (err) {
                done(err);
            } else {
                done();
            }
        });
    });

    it('should generate an app with coffeescript files if coffeescript was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingCoffeeScript = [
            path.join(demoAppPath, '/client/code/app/app.coffee'),
            path.join(demoAppPath, '/client/code/app/entry.coffee'),
            path.join(demoAppPath, '/server/middleware/example.coffee'),
            path.join(demoAppPath, '/server/rpc/demo.coffee')
        ];

        program.coffee = true;

        /* hide console.log output to make Mocha output clear */
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's coffeescript files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingCoffeeScript, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });
    });

    it('should raise an error if no name is provided for the app', function (done) {

        program.args = ['new'];

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        assert.equal(1,logs.length);
        assert.equal(
            'Please provide a name for your application: $> socketstream new <MyAppName>',
            logs[0].toString()
        );
        done();

    });

    it('should generate an app with jade templates if jade was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingJade = [
            path.join(demoAppPath, '/client/templates/chat/message.jade'),
            path.join(demoAppPath, '/client/views/app.jade')
        ];

        program.jade = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's jade files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingJade, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with css stylesheets if css was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingCss = [
            path.join(demoAppPath, '/client/css/app.css'),
        ];

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's css files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingCss, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with less stylesheets if less was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingLess = [
            path.join(demoAppPath, '/client/css/app.less'),
        ];

        program.less = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's less files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingLess, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with stylus stylesheets if stylus was requested', function (done) {

        var newProjectFilesThatShouldExistWhenUsingStylus = [
            path.join(demoAppPath, '/client/css/app.styl'),
        ];

        program.stylus = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's less files exist */
        async.reject(newProjectFilesThatShouldExistWhenUsingStylus, fs.exists, function (result) {
            assert.equal(0,result.length);
            done();
        });

    });

    it('should generate an app with no demo code, if a minimal app was requested', function (done) {

        var newProjectFilesThatBelongToDemo = [
            path.join(demoAppPath, '/client/static/images/logo.png'),
            path.join(demoAppPath, '/server/middleware/example.js'),
            path.join(demoAppPath, '/server/rpc/demo.js'),
            path.join(demoAppPath, '/client/css/libs/reset.css'),
            path.join(demoAppPath, '/client/templates/chat/message.html')
        ];

        program.minimal = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        /* Using 'async' library to check if all the required project's coffeescript files exist */
        async.reject(newProjectFilesThatBelongToDemo, fs.exists, function (result) {
            assert.equal(newProjectFilesThatBelongToDemo.length, result.length);
            done();
        });
    });

    it('should generate an app with the ss-console library, if the repl library was requested', function (done) {

        program.repl = true;

        // Call for hook function for console.log
        logHook.on();
        generate.generate(program);
        logs = logHook.off();

        fs.readFile(path.join(demoAppPath,'/app.js'), 'utf-8', function (err, appJsContents) {
            assert.notEqual(-1, appJsContents.indexOf('// Start Console Server (REPL)'));
            assert.notEqual(-1, appJsContents.indexOf('// To install client: sudo npm install -g ss-console'));
            assert.notEqual(-1, appJsContents.indexOf('// To connect: ss-console <optional_host_or_port>'));
            assert.notEqual(-1, appJsContents.indexOf('var consoleServer = require(\'ss-console\')(ss);'));
            assert.notEqual(-1, appJsContents.indexOf('consoleServer.listen(5000);'));
            done();

        });
    });
});<|endoftext|>


<commit_before>import Random from 'random-seed'
import JSMarkerIndex from '../src/js/marker-index'
import NativeMarkerIndex from '../src/native/marker-index'
import {traverse, traversal, compare, isZero, max, format as formatPoint} from '../src/js/point-helpers'
import './helpers/add-to-html-methods'

for (let [name, MarkerIndex] of [['js', JSMarkerIndex], ['native', NativeMarkerIndex]]) {
  describe(name, () => {
    it('maintains correct marker positions during randomized insertions and mutations', function () {
      this.timeout(Infinity)

      let seed, seedMessage, random, markerIndex, markers, idCounter

      for (let i = 0; i < 1000; i++) {
        seed = Date.now()
        seedMessage = `Random Seed: ${seed}`
        random = new Random(seed)
        markerIndex = new MarkerIndex(seed)
        markers = []
        idCounter = 1

        for (let j = 0; j < 50; j++) {
          let n = random(10)
          if (n >= 4) { // 60% insert
            performInsert()
          } else if (n >= 2) { // 20% splice
            performSplice()
          } else if (markers.length > 0) {
            performDelete()
          }

          verifyRanges()
          write(() => markerIndex.toHTML())
          write(() => '
')
          verifyHighestPossiblePaths()
        }

        const verifications = [
          verifyRanges,
          testDump,
          testFindIntersecting,
          testFindContaining,
          testFindContainedIn,
          testFindStartingIn,
          testFindEndingIn,
          testFindStartingAt,
          testFindEndingAt,
        ].sort((a, b) => random.intBetween(-1, 1))

        verifications.forEach(verification => verification())
      }

      //  uncomment for debug output in electron (`npm run tdd`)
      function write (f) {
        // document.write(f())
      }

      function verifyRanges () {
        for (let marker of markers) {
          let range = markerIndex.getRange(marker.id)
          assert.deepEqual(range[0], marker.start, `Marker ${marker.id} start. ` + seedMessage)
          assert.deepEqual(range[1], marker.end, `Marker ${marker.id} end. ` + seedMessage)
        }
      }

      function testDump () {
        if (markers.length === 0) return

        let expectedSnapshot = {}

        for (let marker of markers) {
          expectedSnapshot[marker.id] = {start: marker.start, end: marker.end}
        }

        let actualSnapshot = markerIndex.dump()

        assert.deepEqual(actualSnapshot, expectedSnapshot, seedMessage)
      }

      function verifyHighestPossiblePaths (node, alreadySeen) {
        if (!node) {
          if (markerIndex.root) verifyHighestPossiblePaths(markerIndex.root, new Set())
          return
        }

        for (let markerId of node.leftMarkerIds) {
          assert(!alreadySeen.has(markerId), `Redundant path for ${markerId}. ` + seedMessage)
        }
        for (let markerId of node.rightMarkerIds) {
          assert(!alreadySeen.has(markerId), `Redundant paths for ${markerId}. ` + seedMessage)
        }

        if (node.left) {
          let alreadySeenOnLeft = new Set()
          for (let markerId of alreadySeen) {
            alreadySeenOnLeft.add(markerId)
          }
          for (let markerId of node.leftMarkerIds) {
            alreadySeenOnLeft.add(markerId)
          }
          verifyHighestPossiblePaths(node.left, alreadySeenOnLeft)
        }

        if (node.right) {
          let alreadySeenOnRight = new Set()
          for (let markerId of alreadySeen) {
            alreadySeenOnRight.add(markerId)
          }
          for (let markerId of node.rightMarkerIds) {
            alreadySeenOnRight.add(markerId)
          }
          verifyHighestPossiblePaths(node.right, alreadySeenOnRight)
        }
      }

      function verifyContinuousPaths () {
        let startedMarkers = new Set()
        let endedMarkers = new Set()

        let iterator = markerIndex.iterator
        iterator.reset()
        while (iterator.node && iterator.node.left) iterator.descendLeft()

        let node = iterator.node
        while (node) {
          for (let markerId of node.leftMarkerIds) {
            assert(!endedMarkers.has(markerId), `Marker ${markerId} in left markers, but already ended. ` + seedMessage)
            assert(startedMarkers.has(markerId), `Marker ${markerId} in left markers, but not yet started. ` + seedMessage)
          }

          for (let markerId of node.startMarkerIds) {
            assert(!endedMarkers.has(markerId), `Marker ${markerId} in start markers, but already ended. ` + seedMessage)
            assert(!startedMarkers.has(markerId), `Marker ${markerId} in start markers, but already started. ` + seedMessage)
            startedMarkers.add(markerId)
          }

          for (let markerId of node.endMarkerIds) {
            assert(startedMarkers.has(markerId), `Marker ${markerId} in end markers, but not yet started. ` + seedMessage)
            startedMarkers.delete(markerId)
            endedMarkers.add(markerId)
          }

          for (let markerId of node.rightMarkerIds) {
            assert(!endedMarkers.has(markerId), `Marker ${markerId} in right markers, but already ended. ` + seedMessage)
            assert(startedMarkers.has(markerId), `Marker ${markerId} in right markers, but not yet started. ` + seedMessage)
          }

          iterator.moveToSuccessor()
          node = iterator.node
        }
      }

      function testFindIntersecting () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.start, end) <= 0 && compare(start, marker.end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findIntersecting(start, end)

          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindContaining () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.start, start) <= 0 && compare(end, marker.end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findContaining(start, end)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindContainedIn () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(start, marker.start) <= 0 && compare(marker.end, end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findContainedIn(start, end)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindStartingIn () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(start, marker.start) <= 0 && compare(marker.start, end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findStartingIn(start, end)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to start in (${formatPoint(start)}, ${formatPoint(end)}). ` + seedMessage)
          }
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
        }
      }

      function testFindEndingIn () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(start, marker.end) <= 0 && compare(marker.end, end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findEndingIn(start, end)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
        }
      }

      function testFindStartingAt () {
        for (let i = 0; i < 10; i++) {
          let point = {row: random(100), column: random(100)}

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.start, point) === 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findStartingAt(point)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindEndingAt () {
        for (let i = 0; i < 10; i++) {
          let point = {row: random(100), column: random(100)}

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.end, point) === 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findEndingAt(point)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function performInsert () {
        let id = idCounter++
        let [start, end] = getRange()
        let exclusive = !!random(2)
        write(() => `insert ${id}, ${formatPoint(start)}, ${formatPoint(end)}, exclusive: ${exclusive}`)
        markerIndex.insert(id, start, end)
        if (exclusive) markerIndex.setExclusive(id, true)
        markers.push({id, start, end, exclusive})
      }

      function performSplice () {
        let [start, oldExtent, newExtent] = getSplice()
        write(() => `splice ${formatPoint(start)}, ${formatPoint(oldExtent)}, ${formatPoint(newExtent)}`)
        let actualInvalidatedSets = markerIndex.splice(start, oldExtent, newExtent)
        let expectedInvalidatedSets = applySplice(markers, start, oldExtent, newExtent)
        checkInvalidatedSets(actualInvalidatedSets, expectedInvalidatedSets)
      }

      function performDelete () {
        let [{id}] = markers.splice(random(markers.length), 1)
        write(() => `delete ${id}`)
        markerIndex.delete(id)
      }

      function getRange () {
        let start = {row: random(100), column: random(100)}
        let end = start
        while (random(3) > 0) {
          end = traverse(end, {row: random.intBetween(-10, 10), column: random.intBetween(-10, 10)})
        }
        end.row = Math.max(end.row, 0)
        end.column = Math.max(end.column, 0)

        if (compare(start, end) <= 0) {
          return [start, end]
        } else {
          return [end, start]
        }
      }

      function getSplice () {
        let [start, oldEnd] = getRange()
        let oldExtent = traversal(oldEnd, start)
        let newExtent = {row: 0, column: 0}
        while (random(2)) {
          newExtent = traverse(newExtent, {row: random(10), column: random(10)})
        }
        return [start, oldExtent, newExtent]
      }

      function applySplice (markers, spliceStart, oldExtent, newExtent) {
        if (isZero(oldExtent) && isZero(newExtent)) return

        let spliceOldEnd = traverse(spliceStart, oldExtent)
        let spliceNewEnd = traverse(spliceStart, newExtent)
        let spliceDelta = traversal(newExtent, oldExtent)

        let invalidated = {
          touch: new Set,
          inside: new Set,
          overlap: new Set,
          surround: new Set
        }

        for (let marker of markers) {
          if (compare(spliceStart, marker.end) <= 0 && compare(marker.start, spliceOldEnd) <= 0) {
            invalidated.touch.add(marker.id)
            if (compare(spliceStart, marker.end) !== 0 && compare(spliceOldEnd, marker.start) !== 0) {
              invalidated.inside.add(marker.id)
            }
            let markerStartsWithinSplice = compare(spliceStart, marker.start) < 0 && compare(marker.start, spliceOldEnd) < 0
            let markerEndsWithinSplice = compare(spliceStart, marker.end) < 0 && compare(marker.end, spliceOldEnd) < 0
            if (markerStartsWithinSplice || markerEndsWithinSplice) {
              invalidated.overlap.add(marker.id)
            }
            if (markerStartsWithinSplice && markerEndsWithinSplice) {
              invalidated.surround.add(marker.id)
            }
          }

          let isEmpty = compare(marker.start, marker.end) === 0

          if (compare(spliceStart, marker.start) < 0 || marker.exclusive && compare(spliceOldEnd, marker.start) === 0) {
            if (compare(spliceOldEnd, marker.start) <= 0) { // splice precedes marker start
              marker.start = traverse(spliceNewEnd, traversal(marker.start, spliceOldEnd))
            } else { // splice surrounds marker start
              marker.start = spliceNewEnd
            }
          }

          if (compare(spliceStart, marker.end) < 0 || (!marker.exclusive || isEmpty) && compare(spliceOldEnd, marker.end) === 0) {
            if (compare(spliceOldEnd, marker.end) <= 0) { // splice precedes marker end
              marker.end = traverse(spliceNewEnd, traversal(marker.end, spliceOldEnd))
            } else { // splice surrounds marker end
              marker.end = spliceNewEnd
            }
          }
        }

        return invalidated
      }

      function checkInvalidatedSets (actualSets, expectedSets) {
        for (let strategy in expectedSets) {
          let expectedSet = expectedSets[strategy]
          let actualSet = actualSets[strategy]

          assert.equal(actualSet.size, expectedSet.size)
          for (let markerId of expectedSet) {
            assert(actualSet.has(markerId), `Expected marker ${markerId} to be invalidated via ${strategy} strategy. Seed ${seed}.`)
          }
        }
      }
    })

    it('handles range queries involving Infinity', () => {
      let index = new MarkerIndex()
      index.insert(1, {row: 10, column: 10}, {row: 20, column: 20})
      let result = index.findEndingIn({row: 0, column: 0}, {row: Infinity, column: Infinity})
      assert(result.has(1))
    })
  })
}
<commit_msg>Add test for MarkerIndex.prototype.compare<commit_after>import Random from 'random-seed'
import JSMarkerIndex from '../src/js/marker-index'
import NativeMarkerIndex from '../src/native/marker-index'
import {traverse, traversal, compare, isZero, max, format as formatPoint} from '../src/js/point-helpers'
import './helpers/add-to-html-methods'

for (let [name, MarkerIndex] of [['js', JSMarkerIndex], ['native', NativeMarkerIndex]]) {
  describe(name, () => {
    it('maintains correct marker positions during randomized insertions and mutations', function () {
      this.timeout(Infinity)

      let seed, seedMessage, random, markerIndex, markers, idCounter

      for (let i = 0; i < 1000; i++) {
        seed = Date.now()
        seedMessage = `Random Seed: ${seed}`
        random = new Random(seed)
        markerIndex = new MarkerIndex(seed)
        markers = []
        idCounter = 1

        for (let j = 0; j < 50; j++) {
          let n = random(10)
          if (n >= 4) { // 60% insert
            performInsert()
          } else if (n >= 2) { // 20% splice
            performSplice()
          } else if (markers.length > 0) {
            performDelete()
          }

          verifyRanges()
          write(() => markerIndex.toHTML())
          write(() => '
')
          verifyHighestPossiblePaths()
        }

        const verifications = [
          verifyRanges,
          testDump,
          testFindIntersecting,
          testFindContaining,
          testFindContainedIn,
          testFindStartingIn,
          testFindEndingIn,
          testFindStartingAt,
          testFindEndingAt,
        ].sort((a, b) => random.intBetween(-1, 1))

        verifications.forEach(verification => verification())
      }

      //  uncomment for debug output in electron (`npm run tdd`)
      function write (f) {
        // document.write(f())
      }

      function verifyRanges () {
        for (let marker of markers) {
          let range = markerIndex.getRange(marker.id)
          assert.deepEqual(range[0], marker.start, `Marker ${marker.id} start. ` + seedMessage)
          assert.deepEqual(range[1], marker.end, `Marker ${marker.id} end. ` + seedMessage)
        }
      }

      function testDump () {
        if (markers.length === 0) return

        let expectedSnapshot = {}

        for (let marker of markers) {
          expectedSnapshot[marker.id] = {start: marker.start, end: marker.end}
        }

        let actualSnapshot = markerIndex.dump()

        assert.deepEqual(actualSnapshot, expectedSnapshot, seedMessage)
      }

      function verifyHighestPossiblePaths (node, alreadySeen) {
        if (!node) {
          if (markerIndex.root) verifyHighestPossiblePaths(markerIndex.root, new Set())
          return
        }

        for (let markerId of node.leftMarkerIds) {
          assert(!alreadySeen.has(markerId), `Redundant path for ${markerId}. ` + seedMessage)
        }
        for (let markerId of node.rightMarkerIds) {
          assert(!alreadySeen.has(markerId), `Redundant paths for ${markerId}. ` + seedMessage)
        }

        if (node.left) {
          let alreadySeenOnLeft = new Set()
          for (let markerId of alreadySeen) {
            alreadySeenOnLeft.add(markerId)
          }
          for (let markerId of node.leftMarkerIds) {
            alreadySeenOnLeft.add(markerId)
          }
          verifyHighestPossiblePaths(node.left, alreadySeenOnLeft)
        }

        if (node.right) {
          let alreadySeenOnRight = new Set()
          for (let markerId of alreadySeen) {
            alreadySeenOnRight.add(markerId)
          }
          for (let markerId of node.rightMarkerIds) {
            alreadySeenOnRight.add(markerId)
          }
          verifyHighestPossiblePaths(node.right, alreadySeenOnRight)
        }
      }

      function verifyContinuousPaths () {
        let startedMarkers = new Set()
        let endedMarkers = new Set()

        let iterator = markerIndex.iterator
        iterator.reset()
        while (iterator.node && iterator.node.left) iterator.descendLeft()

        let node = iterator.node
        while (node) {
          for (let markerId of node.leftMarkerIds) {
            assert(!endedMarkers.has(markerId), `Marker ${markerId} in left markers, but already ended. ` + seedMessage)
            assert(startedMarkers.has(markerId), `Marker ${markerId} in left markers, but not yet started. ` + seedMessage)
          }

          for (let markerId of node.startMarkerIds) {
            assert(!endedMarkers.has(markerId), `Marker ${markerId} in start markers, but already ended. ` + seedMessage)
            assert(!startedMarkers.has(markerId), `Marker ${markerId} in start markers, but already started. ` + seedMessage)
            startedMarkers.add(markerId)
          }

          for (let markerId of node.endMarkerIds) {
            assert(startedMarkers.has(markerId), `Marker ${markerId} in end markers, but not yet started. ` + seedMessage)
            startedMarkers.delete(markerId)
            endedMarkers.add(markerId)
          }

          for (let markerId of node.rightMarkerIds) {
            assert(!endedMarkers.has(markerId), `Marker ${markerId} in right markers, but already ended. ` + seedMessage)
            assert(startedMarkers.has(markerId), `Marker ${markerId} in right markers, but not yet started. ` + seedMessage)
          }

          iterator.moveToSuccessor()
          node = iterator.node
        }
      }

      function testFindIntersecting () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.start, end) <= 0 && compare(start, marker.end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findIntersecting(start, end)

          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindContaining () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.start, start) <= 0 && compare(end, marker.end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findContaining(start, end)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindContainedIn () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(start, marker.start) <= 0 && compare(marker.end, end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findContainedIn(start, end)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindStartingIn () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(start, marker.start) <= 0 && compare(marker.start, end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findStartingIn(start, end)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to start in (${formatPoint(start)}, ${formatPoint(end)}). ` + seedMessage)
          }
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
        }
      }

      function testFindEndingIn () {
        for (let i = 0; i < 10; i++) {
          let [start, end] = getRange()

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(start, marker.end) <= 0 && compare(marker.end, end) <= 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findEndingIn(start, end)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
        }
      }

      function testFindStartingAt () {
        for (let i = 0; i < 10; i++) {
          let point = {row: random(100), column: random(100)}

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.start, point) === 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findStartingAt(point)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function testFindEndingAt () {
        for (let i = 0; i < 10; i++) {
          let point = {row: random(100), column: random(100)}

          let expectedIds = new Set()
          for (let marker of markers) {
            if (compare(marker.end, point) === 0) {
              expectedIds.add(marker.id)
            }
          }

          let actualIds = markerIndex.findEndingAt(point)
          assert.equal(actualIds.size, expectedIds.size, seedMessage)
          for (let id of expectedIds) {
            assert(actualIds.has(id), `Expected ${id} to be in set. ` + seedMessage)
          }
        }
      }

      function performInsert () {
        let id = idCounter++
        let [start, end] = getRange()
        let exclusive = !!random(2)
        write(() => `insert ${id}, ${formatPoint(start)}, ${formatPoint(end)}, exclusive: ${exclusive}`)
        markerIndex.insert(id, start, end)
        if (exclusive) markerIndex.setExclusive(id, true)
        markers.push({id, start, end, exclusive})
      }

      function performSplice () {
        let [start, oldExtent, newExtent] = getSplice()
        write(() => `splice ${formatPoint(start)}, ${formatPoint(oldExtent)}, ${formatPoint(newExtent)}`)
        let actualInvalidatedSets = markerIndex.splice(start, oldExtent, newExtent)
        let expectedInvalidatedSets = applySplice(markers, start, oldExtent, newExtent)
        checkInvalidatedSets(actualInvalidatedSets, expectedInvalidatedSets)
      }

      function performDelete () {
        let [{id}] = markers.splice(random(markers.length), 1)
        write(() => `delete ${id}`)
        markerIndex.delete(id)
      }

      function getRange () {
        let start = {row: random(100), column: random(100)}
        let end = start
        while (random(3) > 0) {
          end = traverse(end, {row: random.intBetween(-10, 10), column: random.intBetween(-10, 10)})
        }
        end.row = Math.max(end.row, 0)
        end.column = Math.max(end.column, 0)

        if (compare(start, end) <= 0) {
          return [start, end]
        } else {
          return [end, start]
        }
      }

      function getSplice () {
        let [start, oldEnd] = getRange()
        let oldExtent = traversal(oldEnd, start)
        let newExtent = {row: 0, column: 0}
        while (random(2)) {
          newExtent = traverse(newExtent, {row: random(10), column: random(10)})
        }
        return [start, oldExtent, newExtent]
      }

      function applySplice (markers, spliceStart, oldExtent, newExtent) {
        if (isZero(oldExtent) && isZero(newExtent)) return

        let spliceOldEnd = traverse(spliceStart, oldExtent)
        let spliceNewEnd = traverse(spliceStart, newExtent)
        let spliceDelta = traversal(newExtent, oldExtent)

        let invalidated = {
          touch: new Set,
          inside: new Set,
          overlap: new Set,
          surround: new Set
        }

        for (let marker of markers) {
          if (compare(spliceStart, marker.end) <= 0 && compare(marker.start, spliceOldEnd) <= 0) {
            invalidated.touch.add(marker.id)
            if (compare(spliceStart, marker.end) !== 0 && compare(spliceOldEnd, marker.start) !== 0) {
              invalidated.inside.add(marker.id)
            }
            let markerStartsWithinSplice = compare(spliceStart, marker.start) < 0 && compare(marker.start, spliceOldEnd) < 0
            let markerEndsWithinSplice = compare(spliceStart, marker.end) < 0 && compare(marker.end, spliceOldEnd) < 0
            if (markerStartsWithinSplice || markerEndsWithinSplice) {
              invalidated.overlap.add(marker.id)
            }
            if (markerStartsWithinSplice && markerEndsWithinSplice) {
              invalidated.surround.add(marker.id)
            }
          }

          let isEmpty = compare(marker.start, marker.end) === 0

          if (compare(spliceStart, marker.start) < 0 || marker.exclusive && compare(spliceOldEnd, marker.start) === 0) {
            if (compare(spliceOldEnd, marker.start) <= 0) { // splice precedes marker start
              marker.start = traverse(spliceNewEnd, traversal(marker.start, spliceOldEnd))
            } else { // splice surrounds marker start
              marker.start = spliceNewEnd
            }
          }

          if (compare(spliceStart, marker.end) < 0 || (!marker.exclusive || isEmpty) && compare(spliceOldEnd, marker.end) === 0) {
            if (compare(spliceOldEnd, marker.end) <= 0) { // splice precedes marker end
              marker.end = traverse(spliceNewEnd, traversal(marker.end, spliceOldEnd))
            } else { // splice surrounds marker end
              marker.end = spliceNewEnd
            }
          }
        }

        return invalidated
      }

      function checkInvalidatedSets (actualSets, expectedSets) {
        for (let strategy in expectedSets) {
          let expectedSet = expectedSets[strategy]
          let actualSet = actualSets[strategy]

          assert.equal(actualSet.size, expectedSet.size)
          for (let markerId of expectedSet) {
            assert(actualSet.has(markerId), `Expected marker ${markerId} to be invalidated via ${strategy} strategy. Seed ${seed}.`)
          }
        }
      }
    })

    it('can compare marker ranges', function () {
      let index = new MarkerIndex()
      index.insert(1, {row: 1, column: 2}, {row: 3, column: 4})
      index.insert(2, {row: 1, column: 2}, {row: 3, column: 4})
      index.insert(3, {row: 2, column: 2}, {row: 3, column: 4})
      index.insert(4, {row: 1, column: 2}, {row: 3, column: 5})

      assert.equal(index.compare(1, 2), 0)
      assert.equal(index.compare(2, 1), 0)
      assert.equal(index.compare(1, 3), -1)
      assert.equal(index.compare(3, 1), 1)
      assert.equal(index.compare(1, 4), -1)
      assert.equal(index.compare(4, 1), 1)
    })

    it('handles range queries involving Infinity', () => {
      let index = new MarkerIndex()
      index.insert(1, {row: 10, column: 10}, {row: 20, column: 20})
      let result = index.findEndingIn({row: 0, column: 0}, {row: Infinity, column: Infinity})
      assert(result.has(1))
    })
  })
}
<|endoftext|>


<commit_before>
var FakeStorage = function(){
  this.storage = {};
};

FakeStorage.prototype.setGlobal = function (id, payload) {
  this.storage[id] = payload;
};

FakeStorage.prototype.getGlobal = function(id) {
  return this.storage[id];
}

FakeStorage.prototype.set = function (wid, id, payload) {
  this.storage[wid + '-' + id] = payload;
};

FakeStorage.prototype.get = function(wid, id) {
  return this.storage[wid + '-' +id];
}

FakeStorage.prototype.setFromObj = function(id, wallet) {
  // TODO
};

FakeStorage.prototype.clear = function() {
  delete this['storage'];
}

FakeStorage.prototype.getWalletIds = function() {
  return [];
};

FakeStorage.prototype.setFromObj = function(walletId, obj) {
  for (var i in obj) {
    this.storage[walletId + '-' + i] = obj[i];
  };
};

module.exports = require('soop')(FakeStorage);
<commit_msg>remove extra setFromObj<commit_after>
var FakeStorage = function(){
  this.storage = {};
};

FakeStorage.prototype.setGlobal = function (id, payload) {
  this.storage[id] = payload;
};

FakeStorage.prototype.getGlobal = function(id) {
  return this.storage[id];
}

FakeStorage.prototype.set = function (wid, id, payload) {
  this.storage[wid + '-' + id] = payload;
};

FakeStorage.prototype.get = function(wid, id) {
  return this.storage[wid + '-' +id];
}

FakeStorage.prototype.clear = function() {
  delete this['storage'];
}

FakeStorage.prototype.getWalletIds = function() {
  return [];
};

FakeStorage.prototype.setFromObj = function(walletId, obj) {
  for (var i in obj) {
    this.storage[walletId + '-' + i] = obj[i];
  };
};

module.exports = require('soop')(FakeStorage);
<|endoftext|>


<commit_before>'use strict';

const sinon = require('sinon');

const EventParser   = require('./../../lib/events/EventParser');
const ParserContext = require('./../../lib/events/ParseContext');

require('./../support');

describe('EventParser', () => {

    let parser, beginSpy;

    let beginObj = {
        "context":   "1337",
        "timestamp": 12345,
        "begin":     {"parent": null, "scope": {}}
    };

    let customObj = {
        "context":   "1337",
        "timestamp": 12346,
        "something": "happened"
    };

    beforeEach(() => {

        parser   = new EventParser();
        beginSpy = sinon.spy();

        parser.on('begin', beginSpy);
    });

    describe('context parsing', () => {

        it('should parse contexts when the "begin" event is fired', () => {

            parser.receive(beginObj);

            beginSpy.should.have.been.calledOnce;
            beginSpy.should.have.been.calledWithMatch(sinon.match.instanceOf(ParserContext));
        });

        it('should expose contexts via the getContext method', () => {

            parser.receive(beginObj);
            parser.getContext("1337").should.be.an.instanceOf(ParserContext);
        });
    });

    describe('.use', () => {

        it('should allow to attach reducers', () => {

            let reducer = sinon.spy();
            parser.use(data => reducer(data.get('something')));

            parser.receive(beginObj);
            parser.receive(customObj);

            reducer.should.have.been.calledOnce;
            reducer.should.have.been.calledWith('happened');
        });

        it('should not call the second reducer when the first one returned null', () => {

            let reducer = sinon.spy();
            parser.use(data => null);
            parser.use(reducer);

            parser.receive(beginObj);
            parser.receive(customObj);

            reducer.should.not.have.been.called;
        });
    });

    describe('.useCombine', () => {

        it('should allow to attach handlers for specific properties inside the event object', () => {

            let reducer = sinon.spy();
            parser.useCombine({
                something: reducer
            });

            parser.receive(beginObj);
            parser.receive(customObj);

            reducer.should.have.been.calledWith('happened');
        });
    });

    describe('strict mode (.setStrict())', () => {

        it('should throw an error if an event object goes unreduced', () => {

            parser.setStrict();

            parser.receive(beginObj);
            (() => parser.receive(customObj)).should.throw();
        });

        it('should not throw an error if an attached handler reduces the event object', () => {

            parser.setStrict();
            parser.use(data => null);

            parser.receive(beginObj);
            (() => parser.receive(customObj)).should.not.throw();
        });
    });
});
<commit_msg>Update tests<commit_after>'use strict';

const sinon = require('sinon');

const EventParser   = require('./../../lib/events/EventParser');
const ParserContext = require('./../../lib/events/ParseContext');

require('./../support');

describe('EventParser', () => {

    let parser, beginSpy;

    let beginObj = {
        "context":   "1337",
        "timestamp": 12345,
        "begin":     {"parent": null, "scope": {}}
    };

    let customObj = {
        "context":   "1337",
        "timestamp": 12346,
        "something": "happened"
    };

    beforeEach(() => {

        parser   = new EventParser();
        beginSpy = sinon.spy();

        parser.on('begin', beginSpy);
    });

    describe('context parsing', () => {

        it('should parse contexts when the "begin" event is fired', () => {

            parser.receive(beginObj);

            beginSpy.should.have.been.calledOnce;
            beginSpy.should.have.been.calledWithMatch(sinon.match.instanceOf(ParserContext));
        });

        it('should expose contexts via the getContext method', () => {

            parser.receive(beginObj);
            parser.getContext("1337").should.be.an.instanceOf(ParserContext);
        });
    });

    describe('.use', () => {

        it('should allow to attach reducers', () => {

            let reducer = sinon.spy();
            parser.use(data => reducer(data.get('something')));

            parser.receive(customObj);

            reducer.should.have.been.calledOnce;
            reducer.should.have.been.calledWith('happened');
        });

        it('should not call the second reducer when the first one returned null', () => {

            let reducer = sinon.spy();
            parser.use(data => null);
            parser.use(reducer);

            parser.receive(beginObj);
            parser.receive(customObj);

            reducer.should.not.have.been.called;
        });
    });

    describe('.useCombine', () => {

        it('should allow to attach handlers for specific properties inside the event object', () => {

            let reducer = sinon.spy();
            parser.useCombine({
                something: reducer
            });

            parser.receive(beginObj);
            parser.receive(customObj);

            reducer.should.have.been.calledWith('happened');
        });
    });

    describe('strict mode (.setStrict())', () => {

        it('should throw an error if an event object goes unreduced', () => {

            parser.setStrict();

            (() => parser.receive(customObj)).should.throw();
        });

        it('should not throw an error if an attached handler reduces the event object', () => {

            parser.setStrict();
            parser.use(data => null);

            parser.receive(beginObj);
            (() => parser.receive(customObj)).should.not.throw();
        });
    });
});
<|endoftext|>


<commit_before>// Load in dependencies
var expect = require('chai').expect;
var browserUtils = require('./utils/browser');

// Start our tests
describe('A new session with Google Music', function () {
  browserUtils.openMusic({killBrowser: false});
  browserUtils.execute(function getPlayPauseStatus () {
    return !!window.MusicAPI;
  });

  it('has a Google Music API', function () {
    expect(this.result).to.equal(true);
  });

  it.skip('is not playing any music', function () {

  });

  describe('when we are playing music', function () {
    browserUtils.execute(function setupPlaybackWatcher () {
      window.GoogleMusicApp = {
        playbackChanged: function saveMode (mode) {
          window.playbackMode = mode;
        }
      };
    });
    // before(function waitForABit (done) {
    //   setTimeout(done, 5000);
    // });
    before(function playMusic (done) {
      // Find and click the I'm Feeling Lucky mix
      var browser = this.browser;
      browser.elementByCssSelector('[data-type=imfl]', function handleElement (err, elArr) {
        // If there was an error, callback with it
        if (err) {
          return done(err);
        }

        // Otherwise, hover the element
        var el = elArr[0];
        browser.moveTo(el, 10, 10, function handleHover (err) {
          // If there was an error, callback with it
          if (err) {
            return done(err);
          }

          // Otherwise, click our element
          browser.click(el, done);
        });
      });
    });
    // TODO: Should we wait for playback to start?
    browserUtils.execute(function playMusic () {
      return window.playbackMode;
    });

    it('lists the music as playing', function () {
      console.log(this.result);
      expect(this.result).to.equal(2 /* PLAYING */);
    });

    describe.skip('and pause it', function () {
      it('lists the music as paused', function () {

      });

      describe('and when we clear the queue (aka the only way to stop)', function () {
        it('lists the music as stopped', function () {

        });
      });
    });
  });
});
<commit_msg>Added TODO for resuming<commit_after>// Load in dependencies
var expect = require('chai').expect;
var browserUtils = require('./utils/browser');

// Start our tests
describe('A new session with Google Music', function () {
  browserUtils.openMusic({killBrowser: false});
  browserUtils.execute(function getPlayPauseStatus () {
    return !!window.MusicAPI;
  });

  it('has a Google Music API', function () {
    expect(this.result).to.equal(true);
  });

  it.skip('is not playing any music', function () {

  });

  describe('when we are playing music', function () {
    browserUtils.execute(function setupPlaybackWatcher () {
      window.GoogleMusicApp = {
        playbackChanged: function saveMode (mode) {
          window.playbackMode = mode;
        }
      };
    });
    // before(function waitForABit (done) {
    //   setTimeout(done, 5000);
    // });
    before(function playMusic (done) {
      // Find and click the I'm Feeling Lucky mix
      var browser = this.browser;
      browser.elementByCssSelector('[data-type=imfl]', function handleElement (err, elArr) {
        // If there was an error, callback with it
        if (err) {
          return done(err);
        }

        // Otherwise, hover the element
        var el = elArr[0];
        browser.moveTo(el, 10, 10, function handleHover (err) {
          // If there was an error, callback with it
          if (err) {
            return done(err);
          }

          // Otherwise, click our element
          browser.click(el, done);
        });
      });
    });
    // TODO: Should we wait for playback to start?
    browserUtils.execute(function playMusic () {
      return window.playbackMode;
    });

    it('lists the music as playing', function () {
      console.log(this.result);
      // TODO: Something is borked and we need faster iteration. Take what we have gone and go to the node CLI.
      expect(this.result).to.equal(2 /* PLAYING */);
    });

    describe.skip('and pause it', function () {
      it('lists the music as paused', function () {

      });

      describe('and when we clear the queue (aka the only way to stop)', function () {
        it('lists the music as stopped', function () {

        });
      });
    });
  });
});
<|endoftext|>


<commit_before>import Zoom from '../../src/js/plugins/zoom';
import DOM from '../../src/js/utils/dom';

jest.useFakeTimers();

// Copy of DOM.fireEvent, but using keydown
const simulateKeyEvent = (el, code) => {
  const evt = new KeyboardEvent('keydown', {
    bubbles: true,
    cancelableCode: true,
    which: code,
    shiftKey: true});
  el.dispatchEvent(evt);
};

beforeAll(() => {
  const slides = '12345'.replace(/(\d)/g,
      '

Slide $1

')
      .replace('section-1" class="', 'section-1" class="current ');
  document.body.innerHTML = `<div id="webslides">${slides}</div>`;
});

test('Zoom utility', () => {
  const ws = document.getElementById('webslides');
  const slides = ws.querySelectorAll('.slide');
  const goto = jest.fn();
  const enable = jest.fn();
  const disable = jest.fn();

  const webslides = {
    el: ws,
    slides: [],
    goToSlide: goto,
    enable: enable,
    disable: disable
  };
  slides.forEach(slide => webslides.slides.push({el: slide}));
  webslides.currentSlide_ = webslides.slides[0];

  new Zoom(webslides);

  const zws = document.querySelector('#webslides-zoomed');
  const zoomSlides = zws.querySelectorAll('.slide');

  expect(zws).not.toBe(null);
  expect(zws.style.display).toBe('none');
  expect(slides.length).toBe(zoomSlides.length);
  expect(zws.childNodes[0].className).toBe('wrap');
  expect(zws.childNodes[0].childNodes[0].className).toBe('grid');

  simulateKeyEvent(document.body, 109);
  expect(zws.style.display).toBe('');

  // Wait until next execution
  jest.runTimersToTime(600);
  expect(disable.mock.calls.length).toBe(1);
  expect(enable.mock.calls.length).toBe(0);
  expect(goto.mock.calls.length).toBe(0);

  DOM.fireEvent(zws.querySelector('.zoom-layer'), 'click');

  // Wait until next execution
  jest.runTimersToTime(401);
  expect(disable.mock.calls.length).toBe(1);
  expect(enable.mock.calls.length).toBe(1);
  expect(goto.mock.calls.length).toBe(1);
});
<commit_msg>Fixing zoom test<commit_after>import Zoom from '../../src/js/plugins/zoom';
import DOM from '../../src/js/utils/dom';

jest.useFakeTimers();

// Copy of DOM.fireEvent, but using keydown
const simulateKeyEvent = (el, code) => {
  const evt = new KeyboardEvent('keydown', {
    bubbles: true,
    cancelableCode: true,
    which: code,
    shiftKey: true});
  el.dispatchEvent(evt);
};

beforeAll(() => {
  const slides = '12345'.replace(/(\d)/g,
      '

Slide $1

')
      .replace('section-1" class="', 'section-1" class="current ');
  document.body.innerHTML = `<div id="webslides">${slides}</div>`;
});

test('Zoom utility', () => {
  const ws = document.getElementById('webslides');
  const slides = ws.querySelectorAll('.slide');
  const goto = jest.fn();
  const enable = jest.fn();
  const disable = jest.fn();

  const webslides = {
    el: ws,
    slides: [],
    goToSlide: goto,
    enable: enable,
    disable: disable
  };
  slides.forEach(slide => webslides.slides.push({el: slide}));
  webslides.currentSlide_ = webslides.slides[0];

  new Zoom(webslides);

  const zws = document.querySelector('#webslides-zoomed');
  const zoomSlides = zws.querySelectorAll('.slide');

  expect(zws).not.toBe(null);
  expect(zws.className).toMatch('disable');
  expect(slides.length).toBe(zoomSlides.length);
  expect(zws.childNodes[0].className).toBe('wrap');
  expect(zws.childNodes[0].childNodes[0].className).toBe('grid');

  simulateKeyEvent(document.body, 109);
  expect(zws.className).not.toMatch('disable');

  // Wait until next execution
  jest.runTimersToTime(600);
  expect(disable.mock.calls.length).toBe(1);
  expect(enable.mock.calls.length).toBe(0);
  expect(goto.mock.calls.length).toBe(0);

  DOM.fireEvent(zws.querySelector('.zoom-layer'), 'click');

  // Wait until next execution
  jest.runTimersToTime(401);
  expect(disable.mock.calls.length).toBe(1);
  expect(enable.mock.calls.length).toBe(1);
  expect(goto.mock.calls.length).toBe(1);
});
<|endoftext|>