<commit_before>var t = require('../')
var spawn = require('child_process').spawn
var node = process.execPath
var run = require.resolve('../bin/run.js')
var ok = require.resolve('./test/ok.js')
var notok = require.resolve('./test/not-ok.js')
var colorRe = new RegExp('\u001b\\[[0-9;]+m')
var bailRe = new RegExp('^Bail out! # this is not ok$', 'm')
var okre = new RegExp('test[\\\\/]test[/\\\\]ok\\.js \\.+ 10/10( [0-9\.]+ms)?$', 'm')
var notokre = new RegExp('test[\\\\/]test[/\\\\]not-ok\\.js \\.+ 0/1( [0-9\.]+ms)?$', 'm')
var fs = require('fs')

t.test('usage', function (t) {
  function usageTest (t, child, c) {
    var out = ''
    var std = c === 0 ? 'stdout' : 'stderr'
    child[std].on('data', function (o) {
      out += o
    })
    child.on('close', function (code) {
      t.equal(code, c, 'code should be '+c)
      t.match(out, /^Usage:\n/, 'should print usage')
      t.end()
    })
  }

  var stdin = 0
  if (!process.stdin.isTTY) {
    try {
      stdin = fs.openSync('/dev/tty', 'r')
    } catch (er) {
      stdin = null
    }
  }
  var opt = { skip: stdin === null ? 'could not load tty' : false }
  t.test('shows usage when stdin is a tty', opt, function (t) {
    var child = spawn(node, [run], { stdio: [ stdin, 'pipe', 'pipe' ] })
    usageTest(t, child, 1)
  })

  t.test('shows usage with -h (even with file)', function (t) {
    var child = spawn(node, [run, '-h', __filename])
    usageTest(t, child, 0)
  })

  t.test('shows usage with --help (even with file)', function (t) {
    var child = spawn(node, [run, '--help', __filename])
    usageTest(t, child, 0)
  })

  t.end()
})

t.test('colors', function (t) {
  function colorTest(args, env, hasColor) { return function (t) {
    var out = ''
    env = env || {}
    env.TAP = 0
    args = [run, ok].concat(args || [])
    var child = spawn(node, args, { env: env })
    child.stdout.on('data', function (o) {
      out += o
    })
    child.on('close', function (code) {
      t.equal(code, 0, 'code should be 0')
      if (hasColor)
        t.match(out, colorRe)
      else
        t.notMatch(out, colorRe)
      t.end()
    })
  }}

  t.test('no colors by default for non-TTY',
         colorTest([], {}, false))

  t.test('force colors with -c or --color', function (t) {
    ;[ '-c', '--color' ].forEach(function (c) {
      t.test(c, colorTest([c], {}, true))
    })
    t.end()
  })

  t.test('force no colors with -C or --no-color', function (t) {
    ;[ '-C', '--no-color' ].forEach(function (c) {
      t.test(c, colorTest([c], {}, false))
    })
    t.end()
  })

  t.test('env.TAP_COLORS', function (t) {
    t.test('0', colorTest([], { TAP_COLORS: 0 }, false))
    t.test('1', colorTest([], { TAP_COLORS: 1 }, true))
    t.end()
  })

  t.end()
})

t.test('bailout args', function (t) {
  function bailTest(args, env, bail) { return function (t) {
    var out = ''
    env = env || {}
    env.TAP = 0
    env.TAP_COLORS = 0
    args = [run, notok, ok, '-C', '-Rclassic'].concat(args || [])
    var child = spawn(node, args, { env: env })
    child.stdout.on('data', function (o) {
      out += o
    })
    child.on('close', function (code) {
      t.equal(code, 1, 'code should be 1')
      if (bail) {
        t.match(out, bailRe, 'should show bail out')
        t.notMatch(out, okre, 'should not run second test')
      } else {
        t.notMatch(out, bailRe, 'should not bail out')
        t.match(out, okre, 'should run second test')
      }
      t.end()
    })
  }}

  t.test('force bailout with -b or --bail', function (t) {
    t.test('-b', bailTest(['-b'], {}, true))
    t.test('-Bb', bailTest(['-Bb'], {}, true))
    t.test('--bail', bailTest(['--bail'], {}, true))
    t.test('--no-bail --bail', bailTest(['--no-bail', '--bail'], {}, true))
    t.test('TAP_BAIL=1', bailTest([], { TAP_BAIL: 1 }, true))
    t.end()
  })

  t.test('do not bail out with -B or --no-bail', function (t) {
    t.test('-B', bailTest(['-B'], {}, false))
    t.test('-bB', bailTest(['-bB'], {}, false))
    t.test('--no-bail', bailTest(['--no-bail'], {}, false))
    t.test('--bail --no-bail', bailTest(['--bail', '--no-bail'], {}, false))
    t.test('TAP_BAIL=0', bailTest([], { TAP_BAIL: 0 }, false))
    t.end()
  })

  t.end()
})

t.test('path globbing', function (t) {
  var glob = 'fixtures/*-success.js'
  var opt = { env: { TAP: 1 }, cwd: __dirname }
  var child = spawn(node, [run, glob], opt)
  var out = ''
  child.stdout.on('data', function (c) {
    out += c
  })
  child.on('close', function (code) {
    t.equal(code, 0, 'exits successfully')
    t.match(out, /trivial-success.js/g, 'includes a matched file')
    t.end()
  })
})

t.test('save-file', function (t) {
  var saveFile = 'runner-save-test'
  function saveFileTest(cb) {
    var args = [run, '-s' + saveFile, ok, notok, '-CRclassic']
    var child = spawn(node, args, { env: { TAP: 0 } })
    var out = ''
    child.stdout.on('data', function (c) {
      out += c
    })
    child.on('close', function (code) {
      cb(code, out)
    })
  }

  t.test('run with "ok.js" in save file', function (t) {
    fs.writeFileSync(saveFile, ok + '\n')
    saveFileTest(function (code, out) {
      t.equal(code, 0, 'should exit successfully')
      t.match(out, okre, 'should run ok.js test')
      t.notMatch(out, notokre, 'should not run not-ok.js test')
      t.throws(function () {
        fs.statSync(saveFile)
      }, 'should delete save file')
      t.end()
    })
  })

  t.test('run with empty save file', function (t) {
    saveFileTest(function (code, out) {
      t.equal(code, 1, 'should fail test')
      t.match(out, okre, 'should run ok.js test')
      t.match(out, notokre, 'should run not-ok.js test')
      t.equal(fs.readFileSync(saveFile, 'utf8'), notok + '\n',
              'should save not-ok.js')
      t.end()
    })
  })

  t.test('run with "not-ok.js" in save file', function (t) {
    saveFileTest(function (code, out) {
      t.equal(code, 1, 'should fail test')
      t.notMatch(out, okre, 'should not run ok.js test')
      t.match(out, notokre, 'should run not-ok.js test')
      t.equal(fs.readFileSync(saveFile, 'utf8'), notok + '\n',
              'should save not-ok.js')
      t.end()
    })
  })

  t.test('cleanup', function (t) {
    fs.unlinkSync(saveFile)
    t.end()
  })

  t.end()
})
<commit_msg>test of --version<commit_after>var t = require('../')
var spawn = require('child_process').spawn
var node = process.execPath
var run = require.resolve('../bin/run.js')
var ok = require.resolve('./test/ok.js')
var notok = require.resolve('./test/not-ok.js')
var colorRe = new RegExp('\u001b\\[[0-9;]+m')
var bailRe = new RegExp('^Bail out! # this is not ok$', 'm')
var okre = new RegExp('test[\\\\/]test[/\\\\]ok\\.js \\.+ 10/10( [0-9\.]+ms)?$', 'm')
var notokre = new RegExp('test[\\\\/]test[/\\\\]not-ok\\.js \\.+ 0/1( [0-9\.]+ms)?$', 'm')
var fs = require('fs')

t.test('usage', function (t) {
  function usageTest (t, child, c) {
    var out = ''
    var std = c === 0 ? 'stdout' : 'stderr'
    child[std].on('data', function (o) {
      out += o
    })
    child.on('close', function (code) {
      t.equal(code, c, 'code should be '+c)
      t.match(out, /^Usage:\n/, 'should print usage')
      t.end()
    })
  }

  var stdin = 0
  if (!process.stdin.isTTY) {
    try {
      stdin = fs.openSync('/dev/tty', 'r')
    } catch (er) {
      stdin = null
    }
  }
  var opt = { skip: stdin === null ? 'could not load tty' : false }
  t.test('shows usage when stdin is a tty', opt, function (t) {
    var child = spawn(node, [run], { stdio: [ stdin, 'pipe', 'pipe' ] })
    usageTest(t, child, 1)
  })

  t.test('shows usage with -h (even with file)', function (t) {
    var child = spawn(node, [run, '-h', __filename])
    usageTest(t, child, 0)
  })

  t.test('shows usage with --help (even with file)', function (t) {
    var child = spawn(node, [run, '--help', __filename])
    usageTest(t, child, 0)
  })

  t.end()
})

t.test('colors', function (t) {
  function colorTest(args, env, hasColor) { return function (t) {
    var out = ''
    env = env || {}
    env.TAP = 0
    args = [run, ok].concat(args || [])
    var child = spawn(node, args, { env: env })
    child.stdout.on('data', function (o) {
      out += o
    })
    child.on('close', function (code) {
      t.equal(code, 0, 'code should be 0')
      if (hasColor)
        t.match(out, colorRe)
      else
        t.notMatch(out, colorRe)
      t.end()
    })
  }}

  t.test('no colors by default for non-TTY',
         colorTest([], {}, false))

  t.test('force colors with -c or --color', function (t) {
    ;[ '-c', '--color' ].forEach(function (c) {
      t.test(c, colorTest([c], {}, true))
    })
    t.end()
  })

  t.test('force no colors with -C or --no-color', function (t) {
    ;[ '-C', '--no-color' ].forEach(function (c) {
      t.test(c, colorTest([c], {}, false))
    })
    t.end()
  })

  t.test('env.TAP_COLORS', function (t) {
    t.test('0', colorTest([], { TAP_COLORS: 0 }, false))
    t.test('1', colorTest([], { TAP_COLORS: 1 }, true))
    t.end()
  })

  t.end()
})

t.test('bailout args', function (t) {
  function bailTest(args, env, bail) { return function (t) {
    var out = ''
    env = env || {}
    env.TAP = 0
    env.TAP_COLORS = 0
    args = [run, notok, ok, '-C', '-Rclassic'].concat(args || [])
    var child = spawn(node, args, { env: env })
    child.stdout.on('data', function (o) {
      out += o
    })
    child.on('close', function (code) {
      t.equal(code, 1, 'code should be 1')
      if (bail) {
        t.match(out, bailRe, 'should show bail out')
        t.notMatch(out, okre, 'should not run second test')
      } else {
        t.notMatch(out, bailRe, 'should not bail out')
        t.match(out, okre, 'should run second test')
      }
      t.end()
    })
  }}

  t.test('force bailout with -b or --bail', function (t) {
    t.test('-b', bailTest(['-b'], {}, true))
    t.test('-Bb', bailTest(['-Bb'], {}, true))
    t.test('--bail', bailTest(['--bail'], {}, true))
    t.test('--no-bail --bail', bailTest(['--no-bail', '--bail'], {}, true))
    t.test('TAP_BAIL=1', bailTest([], { TAP_BAIL: 1 }, true))
    t.end()
  })

  t.test('do not bail out with -B or --no-bail', function (t) {
    t.test('-B', bailTest(['-B'], {}, false))
    t.test('-bB', bailTest(['-bB'], {}, false))
    t.test('--no-bail', bailTest(['--no-bail'], {}, false))
    t.test('--bail --no-bail', bailTest(['--bail', '--no-bail'], {}, false))
    t.test('TAP_BAIL=0', bailTest([], { TAP_BAIL: 0 }, false))
    t.end()
  })

  t.end()
})

t.test('path globbing', function (t) {
  var glob = 'fixtures/*-success.js'
  var opt = { env: { TAP: 1 }, cwd: __dirname }
  var child = spawn(node, [run, glob], opt)
  var out = ''
  child.stdout.on('data', function (c) {
    out += c
  })
  child.on('close', function (code) {
    t.equal(code, 0, 'exits successfully')
    t.match(out, /trivial-success.js/g, 'includes a matched file')
    t.end()
  })
})

t.test('save-file', function (t) {
  var saveFile = 'runner-save-test'
  function saveFileTest(cb) {
    var args = [run, '-s' + saveFile, ok, notok, '-CRclassic']
    var child = spawn(node, args, { env: { TAP: 0 } })
    var out = ''
    child.stdout.on('data', function (c) {
      out += c
    })
    child.on('close', function (code) {
      cb(code, out)
    })
  }

  t.test('run with "ok.js" in save file', function (t) {
    fs.writeFileSync(saveFile, ok + '\n')
    saveFileTest(function (code, out) {
      t.equal(code, 0, 'should exit successfully')
      t.match(out, okre, 'should run ok.js test')
      t.notMatch(out, notokre, 'should not run not-ok.js test')
      t.throws(function () {
        fs.statSync(saveFile)
      }, 'should delete save file')
      t.end()
    })
  })

  t.test('run with empty save file', function (t) {
    saveFileTest(function (code, out) {
      t.equal(code, 1, 'should fail test')
      t.match(out, okre, 'should run ok.js test')
      t.match(out, notokre, 'should run not-ok.js test')
      t.equal(fs.readFileSync(saveFile, 'utf8'), notok + '\n',
              'should save not-ok.js')
      t.end()
    })
  })

  t.test('run with "not-ok.js" in save file', function (t) {
    saveFileTest(function (code, out) {
      t.equal(code, 1, 'should fail test')
      t.notMatch(out, okre, 'should not run ok.js test')
      t.match(out, notokre, 'should run not-ok.js test')
      t.equal(fs.readFileSync(saveFile, 'utf8'), notok + '\n',
              'should save not-ok.js')
      t.end()
    })
  })

  t.test('cleanup', function (t) {
    fs.unlinkSync(saveFile)
    t.end()
  })

  t.end()
})

t.test('version', function (t) {
  var version = require('../package.json').version
  function versionTest (arg) { return function (t) {
    var child = spawn(node, [run].concat(arg))
    var out = ''
    child.stdout.on('data', function (o) {
      out += o
    })
    child.on('close', function (code, signal) {
      t.equal(code, 0)
      t.equal(signal, null)
      t.equal(out, version + '\n')
      t.end()
    })
  }}
  t.test('-v', versionTest('-v'))
  t.test('--version', versionTest('--version'))
  t.test('--version', versionTest(['--version', __filename]))
  t.end()
})
<|endoftext|>


<commit_before>const dns = require('dns')

const localIP = '192.168.178.0'
// TODO: make local IP a variable or in config file

function getRoutesFromPacketArray (packetArray) {
    var routesArray = []
    for (var packet in packetArray) {
        try {
            routesArray.push(getRouteFromPacket(packet))
        } catch (exception) {
            console.log(exception)
        }
    }
}

function getRouteFromPacket (packet) {
    switch (packet.payload.ethertype) {
        case 0x800:
            // console.log('Ipv4')
            // use module.exports.function for testability
            return module.exports.handleIPv4Packet(packet.payload.payload)
        case 0x86dd:
            // console.log('Ipv6')
            return module.exports.handleIPv6Packet(packet.payload.payload)
        default:
            throw new Error('Don\'t know how to handle this packet of ethertype ' + packet.payload.ethertype)
    }
}

// TODO: check if packet is valid, check if IPs are valid
function handleIPv4Packet (packet) {
    var route = {
        senderIP: packet.saddr.toString(),
        receiverIP: packet.daddr.toString()
    }
    // console.log('IPv4: ', result)
    return route
}

// TODO: same as IPv4
function handleIPv6Packet (packet) {
    console.log('Ipv6 in function')
    return 'IPv6 Packet'
}

// TODO: check if IP valid, return ipAddress if dns.reverse fails
function reverseLookupOfIP (ipAddress) {
    // console.log(ipAddress)
    return new Promise((resolve, reject) => {
        dns.reverse(ipAddress, (err, domains) => {
            if (err) {
                reject(err)
            }
            // console.log('reverse for ' + ipAddress + ': ' + domains)
            resolve(domains)
        })
    })
}

// TODO: check if IPs valid
function getLocalAddress (sender, receiver) {
    if (getNetworkPartOfIP(sender) === getNetworkPartOfIP(localIP)) {
        return {local: sender, receiver}
    } else {
        // if sender is not local, then receiver must be local
        return {local: receiver, receiver: sender}
    }
}

// TODO: check if IP valid
function getNetworkPartOfIP (ipAddress) {
    return ipAddress.substring(0, ipAddress.lastIndexOf('.'))
}

module.exports = {
    reverseLookupOfIP,
    handleIPv4Packet,
    handleIPv6Packet,
    getRoutesFromPacketArray,
    getRouteFromPacket,
    getLocalAddress
}
<commit_msg>Remove surplus exports<commit_after>const dns = require('dns')

const localIP = '192.168.178.0'
// TODO: make local IP a variable or in config file

function getRoutesFromPacketArray (packetArray) {
    var routesArray = []
    for (var packet in packetArray) {
        try {
            routesArray.push(getRouteFromPacket(packet))
        } catch (exception) {
            console.log(exception)
        }
    }
}

function getRouteFromPacket (packet) {
    switch (packet.payload.ethertype) {
        case 0x800:
            // console.log('Ipv4')
            return handleIPv4Packet(packet.payload.payload)
        case 0x86dd:
            // console.log('Ipv6')
            return handleIPv6Packet(packet.payload.payload)
        default:
            throw new Error('Don\'t know how to handle this packet of ethertype ' + packet.payload.ethertype)
    }
}

// TODO: check if packet is valid, check if IPs are valid
function handleIPv4Packet (packet) {
    var route = {
        senderIP: packet.saddr.toString(),
        receiverIP: packet.daddr.toString()
    }
    // console.log('IPv4: ', result)
    return route
}

// TODO: same as IPv4
function handleIPv6Packet (packet) {
    console.log('Ipv6 in function')
    return 'IPv6 Packet'
}

// TODO: check if IP valid, return ipAddress if dns.reverse fails
function reverseLookupOfIP (ipAddress) {
    // console.log(ipAddress)
    return new Promise((resolve, reject) => {
        dns.reverse(ipAddress, (err, domains) => {
            if (err) {
                reject(err)
            }
            // console.log('reverse for ' + ipAddress + ': ' + domains)
            resolve(domains)
        })
    })
}

// TODO: check if IPs valid
function getLocalAddress (sender, receiver) {
    if (getNetworkPartOfIP(sender) === getNetworkPartOfIP(localIP)) {
        return {local: sender, receiver}
    } else {
        // if sender is not local, then receiver must be local
        return {local: receiver, receiver: sender}
    }
}

// TODO: check if IP valid
function getNetworkPartOfIP (ipAddress) {
    return ipAddress.substring(0, ipAddress.lastIndexOf('.'))
}

module.exports = {
    reverseLookupOfIP,
    getRoutesFromPacketArray,
    getRouteFromPacket,
    getLocalAddress
}
<|endoftext|>


<commit_before>require('chai').should();
global.window = global;
// TODO: simulate browser env here

var Manager = require('../../lib').Manager;
var State = require('../../lib').State;
var Transition = require('../../lib').Transition;
var Interpolation = require('../../lib/transition/interpolation').Interpolation;

describe('Manager', function() {
	describe('#push', function() {
		var shared = new Manager();

		it('should push a new state given its name', function() {
			shared.push('test');
			shared._states.should.have.deep.property('test.state').be.instanceof(State);
			shared._states.test.flag = 42;
		});

		it('should not override an existing state', function() {
			shared.push('test');
			shared._states.test.should.have.property('flag', 42);
		});

		it('should push a state given a name and its instance', function() {
			var manager = new Manager();
			var state = new State();
			manager.push('test', state);
			manager._states.test.state.should.be.eql(state);
		});

		it('should push a new state given its name and a transition name', function() {
			var manager = new Manager();
			manager.push('test', 'interpolation');
			manager._states.should.have.deep.property('test.state').be.instanceof(State);
			manager._states.test.trans.should.be.instanceof(Transition);
		});

		it('should push a new state given its name and a transition description', function() {
			var manager = new Manager();
			manager.push('test', 'interpolation', { from: 42, to: 1337, duration: 666 });
			manager._states.test.trans.should.be.instanceof(Transition);
			manager._states.test.trans.should.have.property('from', 42);
			manager._states.test.trans.should.have.property('to', 1337);
			manager._states.test.trans.should.have.property('duration', 666);
		});

		it('should push a new state given its name and a transition instance', function() {
			var manager = new Manager();
			var interpolation = new Interpolation({ to: 42 });
			manager.push('test', interpolation);
			manager._states.test.trans.should.have.property('from', 0);
		});

		it('should push a new state without transition given its name and a invalid transition name', function() {
			var manager = new Manager();
			manager.push('test', 'wombat');
			manager._states.test.should.have.property('trans', undefined);
		});

		it('should push a new parent and then a child state given a state compouned name', function() {
			var manager = new Manager();
			manager.push('parent:child');
			manager._states.should.have.deep.property('parent.state').be.instanceof(State);
			manager._states.should.have.deep.property('parent:child.state').be.instanceof(State);
			manager._states.should.have.deep.property('parent:child.parent').eql(manager._states.parent);
		});

		it('should push as many childs as specified', function() {
			var manager = new Manager();
			manager.push('I:am:a:deep:hierarchy');
			manager._states.should.have.deep.property('I.state');
			manager._states.should.have.deep.property('I:am.state');
			manager._states.should.have.deep.property('I:am.parent').eql(manager._states['I']);
			manager._states.should.have.deep.property('I:am:a.state');
			manager._states.should.have.deep.property('I:am:a.parent').eql(manager._states['I:am']);
			manager._states.should.have.deep.property('I:am:a:deep.state');
			manager._states.should.have.deep.property('I:am:a:deep.parent').eql(manager._states['I:am:a']);
			manager._states.should.have.deep.property('I:am:a:deep:hierarchy.state');
			manager._states.should.have.deep.property('I:am:a:deep:hierarchy.parent').eql(manager._states['I:am:a:deep']);
		});

		it('should push a child of an existing state', function() {
			shared.push('test:child');
			shared._states.should.have.deep.property('test:child');
			shared._states.should.have.deep.property('test:child.parent').eql(shared._states.test);
		});

		it('should inherit parent transition', function() {
			var manager = new Manager();
			var interpolation = new Interpolation();
			manager.push('parent:child', interpolation);
			manager._states.should.have.deep.property('parent.trans', interpolation);
			manager._states.should.have.deep.property('parent:child.trans', interpolation);
		});

		it('should do nothing given no params', function() {
			shared.push();
			shared._states.should.not.have.keys('undefined');
		});
	});

	describe('#change', function() {
		var shared = new Manager();

		it('should change to the given state', function(done) {
			shared.push('test');
			shared.change('test', function() {
				shared._current.name.should.equal('test');
				shared._states.test.should.have.property('active', true);
				done();
			});
		});

		it('should change to the given new state', function(done) {
			shared.push('vadrouille');
			shared.change('vadrouille', function() {
				shared._current.name.should.equal('vadrouille');
				shared._states.vadrouille.should.have.property('active', true);
				shared._states.test.should.have.property('active', false);
				done();
			});
		});

		it('should change to a child state, activating parents', function(done) {
			shared.push('test:child:of');
			shared.change('test:child:of', function() {
				shared._current.name.should.equal('test:child:of');
				shared._states.test.should.have.property('active', true);
				shared._states['test:child'].should.have.property('active', true);
				shared._states['test:child:of'].should.have.property('active', true);
				done();
			});
		});

		it('should change to a other hierarchy, setting active state correctly', function(done) {
			shared.push('love:loopjs');
			shared.change('love:loopjs', function() {
				shared._current.name.should.equal('love:loopjs');
				shared._states.love.should.have.property('active', true);
				shared._states['love:loopjs'].should.have.property('active', true);
				shared._states.test.should.have.property('active', false);
				shared._states['test:child'].should.have.property('active', false);
				shared._states['test:child:of'].should.have.property('active', false);
				done();
			});
		});

		it('should change to an other child, setting active state correctly', function(done) {
			shared.push('love:sarah:brian');
			shared._states.love.should.have.property('active', true);
			shared.change('love:sarah:brian', function() {
				shared._current.name.should.equal('love:sarah:brian');
				shared._states.love.should.have.property('active', true);
				shared._states['love:sarah'].should.have.property('active', true);
				shared._states['love:sarah:brian'].should.have.property('active', true);
				shared._states['love:loopjs'].should.have.property('active', false);
				done();
			});
		});

		it('should change back to parent, setting active state correctly', function(done) {
			var manager = new Manager();
			manager.push('parent:child:of:mine');
			manager.change('parent:child:of:mine');
			manager.change('parent', function() {
				manager._current.name.should.equal('parent');
				manager._states.parent.should.have.property('active', true);
				manager._states['parent:child'].should.have.property('active', false);
				manager._states['parent:child:of'].should.have.property('active', false);
				manager._states['parent:child:of:mine'].should.have.property('active', false);
				done();
			});
		});

		it('should call enter/exit events when changing states', function(done) {
			var count = 0;
			var cb = function() { count++; if (count == 2) done(); };
			var manager = new Manager();
			manager.push('test');
			manager.push('test2');
			manager._states.test.state.exit = cb;
			manager._states.test2.state.enter = cb;
			manager.change('test');
			manager.change('test2');
		});

		it('should call init event when it is the first time the state is entered', function(done) {
			var manager = new Manager();
			manager.push('test');
			manager._states.test.state.init = function() {
				manager._states.test.init.should.be.true;
				done();
			};
			manager.change('test');
		});

		it('should call focus/blur event when changing states', function(done) {
			var count = 0;
			var cb = function() { count++; if (count == 2) done(); };
			var manager = new Manager();
			manager.push('test');
			manager.push('test2');
			manager._states.test.state.blur = cb;
			manager._states.test2.state.focus = cb;
			manager.change('test');
			manager.change('test2');
		});

		it('should call focus/blur correctly when switching states of the same hierarchy', function(done) {
			var gameFocus = 0;
			var gameBlur = 0;
			var menuFocus = 0;
			var menuBlur = 0;
			var cb = function() {
				if (2 == gameFocus && 1 == gameBlur && 1 == menuFocus && 1 == menuBlur) done();
			};
			var manager = new Manager();
			manager.push('game:menu');
			manager._states.game.state.focus = function() { gameFocus++; cb(); };
			manager._states.game.state.blur = function() { gameBlur++; cb(); };
			manager._states['game:menu'].state.focus = function() { menuFocus++; cb(); };
			manager._states['game:menu'].state.blur = function() { menuBlur++; cb(); };
			manager.change('game');
			manager.change('game:menu');
			manager.change('game');
		});
	});

	describe('#fire', function() {
		it('should fire current state event given a event name', function(done) {
			var manager = new Manager();
			var state = new State();
			state.pause = function() { done() };
			manager.push('test', state);
			manager.change('test');
			manager.fire('pause');
		});

		it('should do nothing when there is no current state', function() {
			var manager = new Manager();
			manager.push('test');
			manager.fire('init');
		});

		it('should fire current state with itself as context', function(done) {
			var manager = new Manager();
			var state = new State();
			state.pause = function() {
				this.should.eql(state);
				done();
			};
			manager.push('test', state);
			manager.change('test');
			manager.fire('pause');
		});

		it('should do nothing when the event is unknown', function() {
			var manager = new Manager();
			manager.push('test');
			manager.fire('42');
		});
	});
});
<commit_msg>fixed broken tests.<commit_after>require('chai').should();
global.window = global;
// TODO: simulate browser env here

var Machine = require('../../lib').Machine;
var State = require('../../lib').State;
var Transition = require('../../lib').Transition;
var Interpolation = require('../../lib/transition/interpolation').Interpolation;

describe('Machine', function() {
	describe('#push', function() {
		var shared = new Machine();

		it('should push a new state given its name', function() {
			shared.push('test');
			shared._states.should.have.deep.property('test.state').be.instanceof(State);
			shared._states.test.flag = 42;
		});

		it('should not override an existing state', function() {
			shared.push('test');
			shared._states.test.should.have.property('flag', 42);
		});

		it('should push a state given a name and its instance', function() {
			var machine = new Machine();
			var state = new State();
			machine.push('test', state);
			machine._states.test.state.should.be.eql(state);
		});

		it('should push a new state given its name and a transition name', function() {
			var machine = new Machine();
			machine.push('test', 'interpolation');
			machine._states.should.have.deep.property('test.state').be.instanceof(State);
			machine._states.test.trans.should.be.instanceof(Transition);
		});

		it('should push a new state given its name and a transition description', function() {
			var machine = new Machine();
			machine.push('test', 'interpolation', { from: 42, to: 1337, duration: 666 });
			machine._states.test.trans.should.be.instanceof(Transition);
			machine._states.test.trans.should.have.property('from', 42);
			machine._states.test.trans.should.have.property('to', 1337);
			machine._states.test.trans.should.have.property('duration', 666);
		});

		it('should push a new state given its name and a transition instance', function() {
			var machine = new Machine();
			var interpolation = new Interpolation({ to: 42 });
			machine.push('test', interpolation);
			machine._states.test.trans.should.have.property('from', 0);
		});

		it('should push a new state without transition given its name and a invalid transition name', function() {
			var machine = new Machine();
			machine.push('test', 'wombat');
			machine._states.test.should.have.property('trans', undefined);
		});

		it('should push a new parent and then a child state given a state compouned name', function() {
			var machine = new Machine();
			machine.push('parent:child');
			machine._states.should.have.deep.property('parent.state').be.instanceof(State);
			machine._states.should.have.deep.property('parent:child.state').be.instanceof(State);
			machine._states.should.have.deep.property('parent:child.parent').eql(machine._states.parent);
		});

		it('should push as many childs as specified', function() {
			var machine = new Machine();
			machine.push('I:am:a:deep:hierarchy');
			machine._states.should.have.deep.property('I.state');
			machine._states.should.have.deep.property('I:am.state');
			machine._states.should.have.deep.property('I:am.parent').eql(machine._states['I']);
			machine._states.should.have.deep.property('I:am:a.state');
			machine._states.should.have.deep.property('I:am:a.parent').eql(machine._states['I:am']);
			machine._states.should.have.deep.property('I:am:a:deep.state');
			machine._states.should.have.deep.property('I:am:a:deep.parent').eql(machine._states['I:am:a']);
			machine._states.should.have.deep.property('I:am:a:deep:hierarchy.state');
			machine._states.should.have.deep.property('I:am:a:deep:hierarchy.parent').eql(machine._states['I:am:a:deep']);
		});

		it('should push a child of an existing state', function() {
			shared.push('test:child');
			shared._states.should.have.deep.property('test:child');
			shared._states.should.have.deep.property('test:child.parent').eql(shared._states.test);
		});

		it('should inherit parent transition', function() {
			var machine = new Machine();
			var interpolation = new Interpolation();
			machine.push('parent:child', interpolation);
			machine._states.should.have.deep.property('parent.trans', interpolation);
			machine._states.should.have.deep.property('parent:child.trans', interpolation);
		});

		it('should do nothing given no params', function() {
			shared.push();
			shared._states.should.not.have.keys('undefined');
		});
	});

	describe('#change', function() {
		var shared = new Machine();

		it('should change to the given state', function(done) {
			shared.push('test');
			shared.change('test', function() {
				shared._current.name.should.equal('test');
				shared._states.test.should.have.property('active', true);
				done();
			});
		});

		it('should change to the given new state', function(done) {
			shared.push('vadrouille');
			shared.change('vadrouille', function() {
				shared._current.name.should.equal('vadrouille');
				shared._states.vadrouille.should.have.property('active', true);
				shared._states.test.should.have.property('active', false);
				done();
			});
		});

		it('should change to a child state, activating parents', function(done) {
			shared.push('test:child:of');
			shared.change('test:child:of', function() {
				shared._current.name.should.equal('test:child:of');
				shared._states.test.should.have.property('active', true);
				shared._states['test:child'].should.have.property('active', true);
				shared._states['test:child:of'].should.have.property('active', true);
				done();
			});
		});

		it('should change to a other hierarchy, setting active state correctly', function(done) {
			shared.push('love:loopjs');
			shared.change('love:loopjs', function() {
				shared._current.name.should.equal('love:loopjs');
				shared._states.love.should.have.property('active', true);
				shared._states['love:loopjs'].should.have.property('active', true);
				shared._states.test.should.have.property('active', false);
				shared._states['test:child'].should.have.property('active', false);
				shared._states['test:child:of'].should.have.property('active', false);
				done();
			});
		});

		it('should change to an other child, setting active state correctly', function(done) {
			shared.push('love:sarah:brian');
			shared._states.love.should.have.property('active', true);
			shared.change('love:sarah:brian', function() {
				shared._current.name.should.equal('love:sarah:brian');
				shared._states.love.should.have.property('active', true);
				shared._states['love:sarah'].should.have.property('active', true);
				shared._states['love:sarah:brian'].should.have.property('active', true);
				shared._states['love:loopjs'].should.have.property('active', false);
				done();
			});
		});

		it('should change back to parent, setting active state correctly', function(done) {
			var machine = new Machine();
			machine.push('parent:child:of:mine');
			machine.change('parent:child:of:mine');
			machine.change('parent', function() {
				machine._current.name.should.equal('parent');
				machine._states.parent.should.have.property('active', true);
				machine._states['parent:child'].should.have.property('active', false);
				machine._states['parent:child:of'].should.have.property('active', false);
				machine._states['parent:child:of:mine'].should.have.property('active', false);
				done();
			});
		});

		it('should call enter/exit events when changing states', function(done) {
			var count = 0;
			var cb = function() { count++; if (count == 2) done(); };
			var machine = new Machine();
			machine.push('test');
			machine.push('test2');
			machine._states.test.state.exit = cb;
			machine._states.test2.state.enter = cb;
			machine.change('test');
			machine.change('test2');
		});

		it('should call init event when it is the first time the state is entered', function(done) {
			var machine = new Machine();
			machine.push('test');
			machine._states.test.state.init = function() {
				machine._states.test.init.should.be.true;
				done();
			};
			machine.change('test');
		});

		it('should call focus/blur event when changing states', function(done) {
			var count = 0;
			var cb = function() { count++; if (count == 2) done(); };
			var machine = new Machine();
			machine.push('test');
			machine.push('test2');
			machine._states.test.state.blur = cb;
			machine._states.test2.state.focus = cb;
			machine.change('test');
			machine.change('test2');
		});

		it('should call focus/blur correctly when switching states of the same hierarchy', function(done) {
			var gameFocus = 0;
			var gameBlur = 0;
			var menuFocus = 0;
			var menuBlur = 0;
			var cb = function() {
				if (2 == gameFocus && 1 == gameBlur && 1 == menuFocus && 1 == menuBlur) done();
			};
			var machine = new Machine();
			machine.push('game:menu');
			machine._states.game.state.focus = function() { gameFocus++; cb(); };
			machine._states.game.state.blur = function() { gameBlur++; cb(); };
			machine._states['game:menu'].state.focus = function() { menuFocus++; cb(); };
			machine._states['game:menu'].state.blur = function() { menuBlur++; cb(); };
			machine.change('game');
			machine.change('game:menu');
			machine.change('game');
		});
	});

	describe('#fire', function() {
		it('should fire current state event given a event name', function(done) {
			var machine = new Machine();
			var state = new State();
			state.pause = function() { done() };
			machine.push('test', state);
			machine.change('test');
			machine.fire('pause');
		});

		it('should do nothing when there is no current state', function() {
			var machine = new Machine();
			machine.push('test');
			machine.fire('init');
		});

		it('should fire current state with itself as context', function(done) {
			var machine = new Machine();
			var state = new State();
			state.pause = function() {
				this.should.eql(state);
				done();
			};
			machine.push('test', state);
			machine.change('test');
			machine.fire('pause');
		});

		it('should do nothing when the event is unknown', function() {
			var machine = new Machine();
			machine.push('test');
			machine.fire('42');
		});
	});
});
<|endoftext|>


<commit_before>var Field = require('./fields').Field;

exports.validate = function (types, doc) {
    if (!doc.type) {
        return; // unknown document type
    }
    var type;
    for (var k in types) {
        if (types.hasOwnProperty(k) && k === doc.type) {
            type = types[k];
            break;
        }
    }
    return exports.validateFields(type.fields, doc, doc);
};

exports.validateFields = function (fields, values, doc) {
    var errors = [];

    for (var k in fields) {
        if (fields.hasOwnProperty(k)) {
            var f = fields[k];
            if (f instanceof Field) {
                // its a field, parse raw value and validate
                var value = f.parse(values[k]);
                try {
                    f.validate(doc, value, values[k]);
                }
                catch (e) {
                    errors.push(e);
                }
            }
            else {
                // recurse through sub-objects in the type's schema to find
                // more fields
                errors = errors.concat(
                    exports.validateFields(fields[k], values[k], doc)
                );
            }
        }
    }

    return errors;
};
<commit_msg>don't parse field values when doing validate on a document<commit_after>var Field = require('./fields').Field;

exports.validate = function (types, doc) {
    if (!doc.type) {
        return; // unknown document type
    }
    var type;
    for (var k in types) {
        if (types.hasOwnProperty(k) && k === doc.type) {
            type = types[k];
            break;
        }
    }
    return exports.validateFields(type.fields, doc, doc);
};

exports.validateFields = function (fields, values, doc) {
    var errors = [];

    for (var k in fields) {
        if (fields.hasOwnProperty(k)) {
            var f = fields[k];
            if (f instanceof Field) {
                // its a field, validate it
                try {
                    f.validate(doc, values[k], values[k]);
                }
                catch (e) {
                    errors.push(e);
                }
            }
            else {
                // recurse through sub-objects in the type's schema to find
                // more fields
                errors = errors.concat(
                    exports.validateFields(fields[k], values[k], doc)
                );
            }
        }
    }

    return errors;
};
<|endoftext|>


<commit_before>var assert = require('chai').assert,
    fs = require('fs'),
    path = require('path'),
    requirejs = require('requirejs');

requirejs.config({
    baseUrl: __dirname,
    paths: {
        'js': '../http-pub/js'
    }
});

describe('Search', function () {
    var Search;

    before(function (done) {
        requirejs(['js/search'], function (RequireSearch) {
            Search = RequireSearch;
            done();
        });
    });

    it('Should be a function', function () {
        assert.isFunction(Search);
    });

    // {{{ Lipsum
    describe('Loaded with Lipsum', function () {
        var s,
            data = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.split(" ");

        before(function () {
            s = new Search();

            data.forEach(function (word) {
                s.addTerm([word], word);
            });
        });

        data.forEach(function (word) {
            it("Search for " + word + " returns " + word, function () {
                var res = s.search(word);
                assert.include(res, word);
            });

            var firstTrigram = word.substr(0, 3);

            it("Search for " + firstTrigram + " returns " + word, function () {
                var res = s.search(firstTrigram);
                assert.include(res, word);
            });
        });

    });
    // }}}

    // {{{ Unicode
    describe('Read data.json', function () {
        var s,
            dataFile = fs.readFileSync(path.join(__dirname, '../http-pub/data.json'), 'utf-8'),
            data;

        it('data.json is an JSON-file with an object', function () {
            try {
                data = JSON.parse(dataFile);
            } catch (e) {
                assert(false, "Couldn't parse data.json...");
            }
            assert.isArray(data);
        });

        it.skip("Has n (name) on objects", function () {
            data.forEach(function (datum) { assert.property(datum, 'n'); });
        });

        describe('Load the search index', function () {
            var s;

            before(function () {
                s = new Search();

                data.forEach(function (code) {
                    var words = code.n.split();
                    if ('a' in code) {
                        words = words.concat(code.a);
                    }

                    s.addTerm(words, code);
                });
            });

            it.skip('Search for "hammer" returns data', function () {
                var res = s.search('hammer');
                assert.isArray(res);
            });

            it('Search for "TOMATO" returns "tomato"-char', function () {
                var res = s.search('TOMATO'),
                    found = false;
                assert.isArray(res);
                res.forEach(function (code) {
                    if (code.n === 'tomato') { found = true; }
                });
                assert(found, "{n: tomato ...} not found");
            });

        });
    });
    // }}}
});
<commit_msg>Speed up slow unit-test.<commit_after>var assert = require('chai').assert,
    fs = require('fs'),
    path = require('path'),
    requirejs = require('requirejs');

requirejs.config({
    baseUrl: __dirname,
    paths: {
        'js': '../http-pub/js'
    }
});

describe('Search', function () {
    var Search;

    before(function (done) {
        requirejs(['js/search'], function (RequireSearch) {
            Search = RequireSearch;
            done();
        });
    });

    it('Should be a function', function () {
        assert.isFunction(Search);
    });

    // {{{ Lipsum
    describe('Loaded with Lipsum', function () {
        var s,
            data = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.split(" ");

        before(function () {
            s = new Search();

            data.forEach(function (word) {
                s.addTerm([word], word);
            });
        });

        data.forEach(function (word) {
            it("Search for " + word + " returns " + word, function () {
                var res = s.search(word);
                assert.include(res, word);
            });

            var firstTrigram = word.substr(0, 3);

            it("Search for " + firstTrigram + " returns " + word, function () {
                var res = s.search(firstTrigram);
                assert.include(res, word);
            });
        });

    });
    // }}}

    // {{{ Unicode
    describe('Read data.json', function () {
        var s,
            dataFile = fs.readFileSync(path.join(__dirname, '../http-pub/data.json'), 'utf-8'),
            data;

        it('data.json is an JSON-file with an object', function () {
            try {
                data = JSON.parse(dataFile);
            } catch (e) {
                assert(false, "Couldn't parse data.json...");
            }
            assert.isArray(data);
        });

        it("Has n (name) on objects", function () {
            for(var i = 0; i < data.length; i += 1) {
                assert('n' in data[i]);
            }
        });

        describe('Load the search index', function () {
            var s;

            before(function () {
                s = new Search();

                data.forEach(function (code) {
                    var words = code.n.split();
                    if ('a' in code) {
                        words = words.concat(code.a);
                    }

                    s.addTerm(words, code);
                });
            });

            it.skip('Search for "hammer" returns data', function () {
                var res = s.search('hammer');
                assert.isArray(res);
            });

            it('Search for "TOMATO" returns "tomato"-char', function () {
                var res = s.search('TOMATO'),
                    found = false;
                assert.isArray(res);
                res.forEach(function (code) {
                    if (code.n === 'tomato') { found = true; }
                });
                assert(found, "{n: tomato ...} not found");
            });

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


<commit_before>const Promise = require('bluebird');
const assert = require('chai').assert;
const helper = require('./testHelper');

describe('subscribe', function(){

  this.timeout(10000);

  let boss;

  before(function(finished){
    helper.start()
      .then(dabauce => {
        boss = dabauce;
        finished();
      });
  });

  after(function(finished){
    boss.stop()
      .then(() => finished());
  });

  it('should fail with no arguments', function(finished) {
    boss.subscribe()
      .catch(error => finished());
  });

  it('should fail if no callback provided', function(finished) {
    boss.subscribe('foo')
      .catch(error => finished());
  });

  it('should fail if options is not an object', function(finished) {
    boss.subscribe('foo', () => {}, 'nope')
      .catch(error => finished());
  });

  it('should honor a custom new job check interval', function(finished){

    let startTime = new Date();
    const queue = 'customJobCheckInterval';
    const newJobCheckIntervalSeconds = 3;
    const timeout = 9000;
    let subscribeCount = 0;

    boss.subscribe(queue, {newJobCheckIntervalSeconds}, () => subscribeCount++)
      .then(() => Promise.join(
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue)
      ));

    setTimeout(() => {
      assert.isAtMost(subscribeCount, timeout / 1000 / newJobCheckIntervalSeconds);
      finished();
    }, timeout);

  });

  it('should unsubscribe a subscription', function(finished){
    this.timeout(4000);

    const jobName = 'temp';

    let receivedCount = 0;

    boss.subscribe(jobName, job => {
      receivedCount++;

      job.done()
        .then(() => boss.unsubscribe(jobName))
        .then(() => boss.publish(jobName))
    });

    boss.publish(jobName)
      .then(() => {

        setTimeout(() => {
          assert.isAtMost(receivedCount, 1);
          finished();
        }, 2000);

      });

  });

  it('unsubscribe should fail without a name', function(finished){
    boss.unsubscribe().catch(() => finished());
  });

  it('should handle a batch of jobs via teamSize', function(finished){
    const jobName = 'subscribe-teamSize';
    const teamSize = 4;
    let subscribeCount = 0;

    Promise.all([
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName)
    ])
      .then(() => boss.subscribe(jobName, {teamSize}, job =>
        job.done()
          .then(() => {
            subscribeCount++;

            // idea here is that the test would time out if it had to wait for 4 intervals
            if(subscribeCount === teamSize)
              finished();
          })
        )
      );
  });

  it('should apply teamConcurrency option', function(finished){
    const jobName = 'subscribe-teamConcurrency';
    const teamSize = 4;
    const teamConcurrency = 4;
    let subscribeCount = 0;

    Promise.all([
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName)
    ])
      .then(() => boss.subscribe(jobName, {teamSize, teamConcurrency}, job => {
        subscribeCount++;

        // idea here is that the test would time out if it had to wait for 4 intervals
        if (subscribeCount === teamSize)
          finished();

        return Promise.delay(4000);
      }));

  });

  it('should handle a batch of jobs via batchSize', function(finished){
    const jobName = 'subscribe-batchSize';
    const batchSize = 4;
    let subscribeCount = 0;

    Promise.all([
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName)
    ])
      .then(() => boss.subscribe(jobName, {batchSize}, jobs =>
        boss.complete(jobs.map(job => job.id))
          .then(() => {
            assert.equal(jobs.length, batchSize);
            finished();
          })
        )
      );
  });

  it('returning promise applies backpressure', function(finished){

    const queue = 'backpressure';
    let subscribeCount = 0;

    let jobs = [
      boss.publish(queue),
      boss.publish(queue),
      boss.publish(queue),
      boss.publish(queue)
    ];

    Promise.all(jobs)
      .then(() => boss.subscribe(queue, job => Promise.delay(2000).then(() => subscribeCount++)))
      .then(() => setTimeout(() => {
        assert.isBelow(subscribeCount, jobs.length);
        finished();
      }, 7000));

  });

  it('should have a done callback for single job subscriptions', function(finished){
    const name = 'subscribe-single';

    boss.subscribe(name, job=> {
        return job.done().then(() => finished());
      })
      .then(() => boss.publish(name));

  });

  it('subscribe completion via Promise resolve() should pass string wrapped in value prop', function(finished){
    const queue = 'subscribeCompletionViaResolveString';
    const result = 'success';

    boss.publish(queue)
      .then(() => boss.subscribe(queue, job => Promise.resolve(result)));

    boss.onComplete(queue, job => {
      assert.strictEqual(job.data.state, 'completed');
      assert.strictEqual(job.data.response.value, result);
      finished();
    });

  });

  it('subscribe completion via Promise resolve() should pass object payload', function(finished){
    const queue = 'subscribeCompletionViaResolveObject';
    const something = 'clever';

    boss.publish(queue)
      .then(() => boss.subscribe(queue, job => Promise.resolve({something})));

    boss.onComplete(queue, job => {
      assert.strictEqual(job.data.state, 'completed');
      assert.strictEqual(job.data.response.something, something);
      finished();
    });

  });

});

<commit_msg>added test for multiple subscriptions per queue<commit_after>const Promise = require('bluebird');
const assert = require('chai').assert;
const helper = require('./testHelper');

describe('subscribe', function(){

  this.timeout(10000);

  let boss;

  before(function(finished){
    helper.start()
      .then(dabauce => {
        boss = dabauce;
        finished();
      });
  });

  after(function(finished){
    boss.stop()
      .then(() => finished());
  });

  it('should fail with no arguments', function(finished) {
    boss.subscribe()
      .catch(error => finished());
  });

  it('should fail if no callback provided', function(finished) {
    boss.subscribe('foo')
      .catch(error => finished());
  });

  it('should fail if options is not an object', function(finished) {
    boss.subscribe('foo', () => {}, 'nope')
      .catch(error => finished());
  });

  it('should honor a custom new job check interval', function(finished){

    let startTime = new Date();
    const queue = 'customJobCheckInterval';
    const newJobCheckIntervalSeconds = 3;
    const timeout = 9000;
    let subscribeCount = 0;

    boss.subscribe(queue, {newJobCheckIntervalSeconds}, () => subscribeCount++)
      .then(() => Promise.join(
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue),
        boss.publish(queue)
      ));

    setTimeout(() => {
      assert.isAtMost(subscribeCount, timeout / 1000 / newJobCheckIntervalSeconds);
      finished();
    }, timeout);

  });

  it('should unsubscribe a subscription', function(finished){
    this.timeout(4000);

    const jobName = 'temp';

    let receivedCount = 0;

    boss.subscribe(jobName, job => {
      receivedCount++;

      job.done()
        .then(() => boss.unsubscribe(jobName))
        .then(() => boss.publish(jobName))
    });

    boss.publish(jobName)
      .then(() => {

        setTimeout(() => {
          assert.isAtMost(receivedCount, 1);
          finished();
        }, 2000);

      });

  });

  it('unsubscribe should fail without a name', function(finished){
    boss.unsubscribe().catch(() => finished());
  });

  it('should handle a batch of jobs via teamSize', function(finished){
    const jobName = 'subscribe-teamSize';
    const teamSize = 4;
    let subscribeCount = 0;

    Promise.all([
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName)
    ])
      .then(() => boss.subscribe(jobName, {teamSize}, job =>
        job.done()
          .then(() => {
            subscribeCount++;

            // idea here is that the test would time out if it had to wait for 4 intervals
            if(subscribeCount === teamSize)
              finished();
          })
        )
      );
  });

  it('should apply teamConcurrency option', function(finished){
    const jobName = 'subscribe-teamConcurrency';
    const teamSize = 4;
    const teamConcurrency = 4;
    let subscribeCount = 0;

    Promise.all([
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName)
    ])
      .then(() => boss.subscribe(jobName, {teamSize, teamConcurrency}, job => {
        subscribeCount++;

        // idea here is that the test would time out if it had to wait for 4 intervals
        if (subscribeCount === teamSize)
          finished();

        return Promise.delay(4000);
      }));

  });

  it('should handle a batch of jobs via batchSize', function(finished){
    const jobName = 'subscribe-batchSize';
    const batchSize = 4;
    let subscribeCount = 0;

    Promise.all([
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName),
      boss.publish(jobName)
    ])
      .then(() => boss.subscribe(jobName, {batchSize}, jobs =>
        boss.complete(jobs.map(job => job.id))
          .then(() => {
            assert.equal(jobs.length, batchSize);
            finished();
          })
        )
      );
  });

  it('returning promise applies backpressure', function(finished){

    const queue = 'backpressure';
    let subscribeCount = 0;

    let jobs = [
      boss.publish(queue),
      boss.publish(queue),
      boss.publish(queue),
      boss.publish(queue)
    ];

    Promise.all(jobs)
      .then(() => boss.subscribe(queue, job => Promise.delay(2000).then(() => subscribeCount++)))
      .then(() => setTimeout(() => {
        assert.isBelow(subscribeCount, jobs.length);
        finished();
      }, 7000));

  });

  it('should have a done callback for single job subscriptions', function(finished){
    const name = 'subscribe-single';

    boss.subscribe(name, job=> {
        return job.done().then(() => finished());
      })
      .then(() => boss.publish(name));

  });

  it('subscribe completion via Promise resolve() should pass string wrapped in value prop', function(finished){
    const queue = 'subscribeCompletionViaResolveString';
    const result = 'success';

    boss.publish(queue)
      .then(() => boss.subscribe(queue, job => Promise.resolve(result)));

    boss.onComplete(queue, job => {
      assert.strictEqual(job.data.state, 'completed');
      assert.strictEqual(job.data.response.value, result);
      finished();
    });

  });

  it('subscribe completion via Promise resolve() should pass object payload', function(finished){
    const queue = 'subscribeCompletionViaResolveObject';
    const something = 'clever';

    boss.publish(queue)
      .then(() => boss.subscribe(queue, job => Promise.resolve({something})));

    boss.onComplete(queue, job => {
      assert.strictEqual(job.data.state, 'completed');
      assert.strictEqual(job.data.response.something, something);
      finished();
    });

  });

  it('should allow multiple subscriptions to the same queue per instance', function(finished){
    const queue = 'multiple-subscriptions'

    boss.subscribe(queue, ()=>{})
      .then(() => boss.subscribe(queue, ()=>{}))
      .then(() => finished());

  });

});

<|endoftext|>


<commit_before>var agml={};

/*
  agml parse takes three arguments
    a string to parse
    an object in which results will be accumulated
    another object in which options can be passed
      and returns an object or results
*/

agml.parse=function(text,results,options){
  // objects are passed by reference in javascript
  // so you can pass an object like a pointer in C
  // and agml.parse will load the results into that
  results=results||{};
  options=options||{};

  // split into individual lines
  // agml can't split key-value pairs across lines
  text.split('\n')
    // throw away empty lines, or lines with whitespace as keys
    .filter(function(line){
      return (!line || /^\s*:/.test(line))?false:true;
    })
    // parse each line
    .forEach(function(line){
      // a line is only relevant if it contains a colon
      if(/:/.test(line)){
        var key,val;
        // extract the key, assign the remainder to the value
        val=line.replace(/.*?:/,function(k){
          // but don't keep the colon
          key=k.slice(0,-1);
          return '';
          // also, throw away anything after a semicolon
        }).replace(/;.*$/,'');
        // add your results to a dictionary
        results[key.trim()]=val.trim();
      }
    });
  return results;
};

/*
  agml.encode takes a dictionary, and an object of options
    and returns a string
*/

agml.encode=function(dict,options){
  options=options||{};
  return Object.keys(dict)
    .map(function(key){
      return key+':'+dict[key];
    }).join('\n');
};

/*
  agml.head takes a string, a results object, and an options object
    and returns an array
*/

agml.head=function(text,results,options){
  /*
      parse a section of text
      filter out bits contained in '---' blocks
      extract the data, return the text
  */
  var results=[];
  return text.replace(/\-{3}(.|\s)*?\-{3}/mg,function(head){
    results.push(head.slice(3,-3));
    return '';
  });
  return results;
};

module.exports=agml;
<commit_msg>agml.js : alternative characters<commit_after>var agml={};

/*
  agml parse takes three arguments
    a string to parse
    an object in which results will be accumulated
    another object in which options can be passed
      and returns an object or results

    the options object can include:
      an alternative key-value delimiter
      an alternative trailing comment character
*/

agml.parse=function(text,results,opt){
  // objects are passed by reference in javascript
  // so you can pass an object like a pointer in C
  // and agml.parse will load the results into that
  results=results||{};
  opt=opt||{};
  opt.delim=opt.delim||':';
  opt.trail=opt.trail||';';

  var leadingComment=new RegExp('^\\s*'+opt.delim);
  var keyPattern=new RegExp('.*?'+opt.delim);
  var trailingComment=new RegExp(opt.trail+'.*$');

  // split into individual lines
  // agml can't split key-value pairs across lines
  text.split('\n')
    // throw away empty lines, or lines with whitespace as keys
    .filter(function(line){
      return (!line || leadingComment.test(line))?false:true;
    })
    // parse each line
    .forEach(function(line){
      // a line is only relevant if it contains a colon
      if(/:/.test(line)){
        var key,val;
        // extract the key, assign the remainder to the value
        val=line.replace(keyPattern,function(k){
          // but don't keep the colon
          key=k.slice(0,-1);
          return '';
          // also, throw away anything after a semicolon
        }).replace(trailingComment,'');
        // add your results to a dictionary
        results[key.trim()]=val.trim();
      }
    });
  return results;
};

/*
  agml.encode takes a dictionary, and an object of options
    and returns a string

  the options object can include an alternate delimiter
    instead of the default colon
*/

agml.encode=function(dict,opt){
  opt=opt||{};
  opt.delim=opt.delim||':';
  return Object.keys(dict)
    .map(function(key){
      return key+opt.delim+dict[key];
    }).join('\n');
};

/*
  agml.head takes a string, a results object, and an options object
    and returns an array
*/

agml.head=function(text,results,opt){
  /*
      parse a section of text
      filter out bits contained in '---' blocks
      extract the data, return the text
  */
  opt.delim=opt.delim||'-';

  var results=[];
  return text.replace(new RegExp('\\'+opt.delim+'{3}(.|\s)*?\\'+opt.delim+'{3}','mg'),function(head){
    results.push(head.slice(3,-3));
    return '';
  });
  return results;
};

module.exports=agml;
<|endoftext|>


<commit_before>#!/usr/bin/env node

const { version } = require('./package');

const childProcess = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const extract = require('extract-zip');
const { downloadArtifact } = require('@electron/get');

if (process.env.ELECTRON_SKIP_BINARY_DOWNLOAD) {
  process.exit(0);
}

const platformPath = getPlatformPath();

if (isInstalled()) {
  process.exit(0);
}

const platform = process.env.npm_config_platform || process.platform;
let arch = process.env.npm_config_arch || process.arch;

if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64') {
  // When downloading for macOS ON macOS and we think we need x64 we should
  // check if we're running under rosetta and download the arm64 version if appropriate
  try {
    const output = childProcess.execSync('sysctl -in sysctl.proc_translated');
    if (output.toString().trim() === '1') {
      arch = 'arm64';
    }
  } catch {
    // Ignore failure
  }
}

// downloads if not cached
downloadArtifact({
  version,
  artifactName: 'electron',
  force: process.env.force_no_cache === 'true',
  cacheRoot: process.env.electron_config_cache,
  checksums: process.env.electron_use_remote_checksums ? undefined : require('./checksums.json'),
  platform,
  arch
}).then(extractFile).catch(err => {
  console.error(err.stack);
  process.exit(1);
});

function isInstalled () {
  try {
    if (fs.readFileSync(path.join(__dirname, 'dist', 'version'), 'utf-8').replace(/^v/, '') !== version) {
      return false;
    }

    if (fs.readFileSync(path.join(__dirname, 'path.txt'), 'utf-8') !== platformPath) {
      return false;
    }
  } catch (ignored) {
    return false;
  }

  const electronPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist', platformPath);

  return fs.existsSync(electronPath);
}

// unzips and makes path.txt point at the correct executable
function extractFile (zipPath) {
  return new Promise((resolve, reject) => {
    extract(zipPath, { dir: path.join(__dirname, 'dist') }, err => {
      if (err) return reject(err);

      fs.writeFile(path.join(__dirname, 'path.txt'), platformPath, err => {
        if (err) return reject(err);

        resolve();
      });
    });
  });
}

function getPlatformPath () {
  const platform = process.env.npm_config_platform || os.platform();

  switch (platform) {
    case 'mas':
    case 'darwin':
      return 'Electron.app/Contents/MacOS/Electron';
    case 'freebsd':
    case 'openbsd':
    case 'linux':
      return 'electron';
    case 'win32':
      return 'electron.exe';
    default:
      throw new Error('Electron builds are not available on platform: ' + platform);
  }
}
<commit_msg>fix: Allow npm_config_arch override on mac (#32266)<commit_after>#!/usr/bin/env node

const { version } = require('./package');

const childProcess = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const extract = require('extract-zip');
const { downloadArtifact } = require('@electron/get');

if (process.env.ELECTRON_SKIP_BINARY_DOWNLOAD) {
  process.exit(0);
}

const platformPath = getPlatformPath();

if (isInstalled()) {
  process.exit(0);
}

const platform = process.env.npm_config_platform || process.platform;
let arch = process.env.npm_config_arch || process.arch;

if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64' &&
    process.env.npm_config_arch === undefined) {
  // When downloading for macOS ON macOS and we think we need x64 we should
  // check if we're running under rosetta and download the arm64 version if appropriate
  try {
    const output = childProcess.execSync('sysctl -in sysctl.proc_translated');
    if (output.toString().trim() === '1') {
      arch = 'arm64';
    }
  } catch {
    // Ignore failure
  }
}

// downloads if not cached
downloadArtifact({
  version,
  artifactName: 'electron',
  force: process.env.force_no_cache === 'true',
  cacheRoot: process.env.electron_config_cache,
  checksums: process.env.electron_use_remote_checksums ? undefined : require('./checksums.json'),
  platform,
  arch
}).then(extractFile).catch(err => {
  console.error(err.stack);
  process.exit(1);
});

function isInstalled () {
  try {
    if (fs.readFileSync(path.join(__dirname, 'dist', 'version'), 'utf-8').replace(/^v/, '') !== version) {
      return false;
    }

    if (fs.readFileSync(path.join(__dirname, 'path.txt'), 'utf-8') !== platformPath) {
      return false;
    }
  } catch (ignored) {
    return false;
  }

  const electronPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist', platformPath);

  return fs.existsSync(electronPath);
}

// unzips and makes path.txt point at the correct executable
function extractFile (zipPath) {
  return new Promise((resolve, reject) => {
    extract(zipPath, { dir: path.join(__dirname, 'dist') }, err => {
      if (err) return reject(err);

      fs.writeFile(path.join(__dirname, 'path.txt'), platformPath, err => {
        if (err) return reject(err);

        resolve();
      });
    });
  });
}

function getPlatformPath () {
  const platform = process.env.npm_config_platform || os.platform();

  switch (platform) {
    case 'mas':
    case 'darwin':
      return 'Electron.app/Contents/MacOS/Electron';
    case 'freebsd':
    case 'openbsd':
    case 'linux':
      return 'electron';
    case 'win32':
      return 'electron.exe';
    default:
      throw new Error('Electron builds are not available on platform: ' + platform);
  }
}
<|endoftext|>


<commit_before>
['info','error','debug','trace','repl','warn','pass','fail','test'].forEach(function(level){
  exports[level] = function(message) {
    require("/api/TiShadow").emitLog({
      level: level.toUpperCase(),
      message: message
    });
  };
});

<commit_msg>Support to re-route Ti.API.log<commit_after>
['info','error','debug','trace','repl','warn','pass','fail','test'].forEach(function(level){
  exports[level] = function(message) {
    require("/api/TiShadow").emitLog({
      level: level.toUpperCase(),
      message: message
    });
  };
});

exports.log = function(level,message) {
  if (exports[level]) {
    exports[level](message);
  }
}

<|endoftext|>


<commit_before>'use strict';

var select = require('..'),
    ast = require('./lib/ast'),
    path = require('./lib/path');

var test = require('tape');

test('edge cases', function (t) {
  t.deepEqual(select(ast, ''), []);
  t.deepEqual(select(ast, '\t '), []);
  t.end();
});

test('type selector', function (t) {
  t.deepEqual(select(ast, 'root'), [ast]);
  t.equal(select(ast, 'text').length, 39);
  t.equal(select(ast, 'text')[1], ast.children[1].children[0]);
  t.equal(select(ast, 'tableRow').length, 2);
  t.equal(select(ast, 'heading').length, 5);

  t.deepEqual(select(ast, 'list'), [
    path(ast, [4]),
    path(ast, [4, 1, 1]),
    path(ast, [4, 1, 1, 0, 1]),
    path(ast, [6])
  ]);

  t.end();
});

test('nesting', function (t) {
  t.deepEqual(select(ast, 'root heading'), select(ast, 'heading'));
  t.deepEqual(select(ast, 'paragraph emphasis'), [
    path(ast, [2, 0, 1]),
    path(ast, [3, 1]),
    path(ast, [4, 1, 1, 1, 0, 0, 1])
  ]);
  t.deepEqual(select(ast, 'paragraph > emphasis'), [
    path(ast, [2, 0, 1]),
    path(ast, [3, 1])
  ]);
  t.deepEqual(select(ast, 'paragraph emphasis > text'), [
    path(ast, [2, 0, 1, 0]),
    path(ast, [3, 1, 0]),
    path(ast, [4, 1, 1, 1, 0, 0, 1, 0])
  ]);
  t.deepEqual(select(ast, 'paragraph > emphasis text'), [
    path(ast, [2, 0, 1, 0]),
    path(ast, [3, 1, 0]),
    path(ast, [3, 1, 1, 0])
  ]);
  t.end();
});

test('siblings', function (t) {
  t.deepEqual(select(ast, 'root ~ heading'), []);
  t.deepEqual(select(ast, 'heading ~ heading'), [
    path(ast, [1]),
    path(ast, [7]),
    path(ast, [12]),
    path(ast, [16])
  ]);
  t.deepEqual(select(ast, 'heading + heading'), [
    path(ast, [1])
  ]);
  t.end();
});

test('grouping', function (t) {
  t.deepEqual(select(ast, 'list, heading + heading'), [
    path(ast, [4]),
    path(ast, [4, 1, 1]),
    path(ast, [4, 1, 1, 0, 1]),
    path(ast, [6]),
    path(ast, [1])
  ]);
  t.end();
});

test('universal selector', function (t) {
  t.equal(select(ast, '*').length, totalNodes(ast));
  t.deepEqual(select(ast, '* ~ heading'), select(ast, 'heading ~ heading'));
  t.true(select(ast, 'list > *').every(function (listItem) {
    return listItem.type == 'listItem';
  }));
  t.end();

  function totalNodes (ast) {
    return 1 + (ast.children || []).map(totalNodes).reduce(function (a, b) {
      return a + b;
    }, 0);
  }
});

test('attribute selectors', function (t) {
  t.comment('existence');
  t.deepEqual(select(ast, '[depth]'), select(ast, 'heading'));
  t.deepEqual(select(ast, '[start][ordered]'), select(ast, 'list'));

  t.comment('equality');
  t.deepEqual(select(ast, 'heading[depth=1], [depth=3]'), [
    path(ast, [0]),
    path(ast, [7])
  ]);
  t.deepEqual(select(ast, 'paragraph [type="text"]'),
              select(ast, 'paragraph text'));
  t.deepEqual(select(ast, '[start=null]'), select(ast, 'list').slice(0, 3));
  t.deepEqual(select(ast, '[ordered=true]'), [ast.children[6]]);
  t.deepEqual(select(ast, 'list[loose=false]'), select(ast, 'list'));

  t.comment('string operators');
  t.deepEqual(select(ast, '[link^="http://"]'), select(ast, 'definition'));
  t.deepEqual(select(ast, '[value*=reduce]'),
              select(ast, 'root > code[lang=js]'));
  t.deepEqual(select(ast, '[type$=Cell]'), select(ast, 'tableCell'));

  t.end();
});

test('structural pseudo-classes', function (t) {
  t.test(':root', function (t) {
    t.deepEqual(select(ast, ':root'), [ast]);
    t.deepEqual(select(ast, ':root:root'), [ast]);
    t.deepEqual(select(ast, '* :root'), []);
    t.deepEqual(select(ast, 'text:not(:root)'), select(ast, 'text'));
    t.deepEqual(select(ast, ':root > list'), [
      path(ast, [4]),
      path(ast, [6])
    ]);
    t.end();
  });

  t.test(':nth-child', function (t) {
    // 6.6.5.2 explicitly states that matching element must have a parent.
    t.deepEqual(select(ast, ':root:nth-child(0)'), []);
    t.deepEqual(select(ast, ':root:nth-child(n)'), []);
    t.deepEqual(select(ast, 'root > list:nth-child(2n+5)'),
                select(ast, 'root > list'));
    t.deepEqual(select(ast, 'heading:nth-child(even)'), [
      path(ast, [1]),
      path(ast, [7])
    ]);
    t.deepEqual(select(ast, ':nth-child(3n+2)[type=inlineCode]')
                .map(function (node) { return node.value }),
                ['integer', 'proin', 'tan']);
    t.end();
  });

  t.test(':nth-last-child', function (t) {
    t.deepEqual(select(ast, ':root:nth-last-child(n)'), []);
    t.deepEqual(select(ast, 'tableCell:nth-last-child(-n+2)'), [
      path(ast, [10, 0, 1]),
      path(ast, [10, 0, 2]),
      path(ast, [10, 1, 1]),
      path(ast, [10, 1, 2]),
      path(ast, [10, 2, 1]),
      path(ast, [10, 2, 2])
    ]);
    t.deepEqual(select(ast, 'definition:nth-last-child(even)')
                .map(function (node) { return node.identifier }),
                ['viverra', 'interdum']);
    t.deepEqual(select(ast,
                       ':root > :nth-last-child(n+2):nth-last-child(-n+3)'), [
                         path(ast, [16]),
                         path(ast, [17])
                       ]);
    t.end();
  });

  t.test(':first-child', function (t) {
    t.deepEqual(select(ast, ':root:first-child'), []);
    t.deepEqual(select(ast, 'heading:first-child'), [path(ast, [0])]);
    t.deepEqual(select(ast, 'list listItem:first-child [value]:first-child'), [
      path(ast, [4, 0, 0, 0]),
      path(ast, [4, 1, 1, 0, 0, 0]),
      path(ast, [4, 1, 1, 0, 1, 0, 0, 0]),
      path(ast, [6, 0, 0, 0])
    ]);
    t.end();
  });

  t.test(':last-child', function (t) {
    t.deepEqual(select(ast, ':root:last-child'), []);
    t.deepEqual(select(ast, 'tableCell:last-child *')
                .map(function (node) { return node.value }),
                ['mi', 'dolor', '15000']);
    t.end();
  });

  t.test(':only-child', function (t) {
    t.deepEqual(select(ast, ':root:only-child'), []);
    t.deepEqual(select(ast, 'table:only-child'), []);
    t.deepEqual(select(ast, ':root > *:not(paragraph) > text:only-child')
                .map(function (node) { return node.value }),
                ['Risus pretium quam!', 'Vitae', 'References', 'License']);
    t.end();
  });

  t.test(':empty', function (t) {
    t.deepEqual(select(ast, ':root:empty'), []);
    t.deepEqual(select(ast, 'text:empty'), []);
    t.deepEqual(select(ast, 'list:not(:empty)'), select(ast, 'list'));
    t.deepEqual(select(ast, ':empty'), select(ast, 'div > div'));
    t.end();
  });

  t.end();
});

test('negation pseudo-class', function (t) {
  t.deepEqual(select(ast, 'list:not([nonexistent])'), select(ast, 'list'));
  t.deepEqual(select(ast, 'list:not([start=null])'),
              select(ast, 'list[start=1]'));
  t.deepEqual(select(ast, 'heading text:not([value*=" "])')
              .map(function (node) { return node.value }),
              ['Vitae', 'References', 'License']);
  t.deepEqual(select(ast, [
    'list:not([ordered=true])',
    '*:not(listItem):not(paragraph)[children]:not(list)'
  ].join(' ')), [
    path(ast, [4, 1, 1, 1, 0, 0]),
    path(ast, [4, 1, 1, 1, 0, 0, 1])
  ]);
  t.end();
});
<commit_msg>test: add definitions of :first-child, :last-child, :only-child<commit_after>'use strict';

var select = require('..'),
    ast = require('./lib/ast'),
    path = require('./lib/path');

var test = require('tape');

test('edge cases', function (t) {
  t.deepEqual(select(ast, ''), []);
  t.deepEqual(select(ast, '\t '), []);
  t.end();
});

test('type selector', function (t) {
  t.deepEqual(select(ast, 'root'), [ast]);
  t.equal(select(ast, 'text').length, 39);
  t.equal(select(ast, 'text')[1], ast.children[1].children[0]);
  t.equal(select(ast, 'tableRow').length, 2);
  t.equal(select(ast, 'heading').length, 5);

  t.deepEqual(select(ast, 'list'), [
    path(ast, [4]),
    path(ast, [4, 1, 1]),
    path(ast, [4, 1, 1, 0, 1]),
    path(ast, [6])
  ]);

  t.end();
});

test('nesting', function (t) {
  t.deepEqual(select(ast, 'root heading'), select(ast, 'heading'));
  t.deepEqual(select(ast, 'paragraph emphasis'), [
    path(ast, [2, 0, 1]),
    path(ast, [3, 1]),
    path(ast, [4, 1, 1, 1, 0, 0, 1])
  ]);
  t.deepEqual(select(ast, 'paragraph > emphasis'), [
    path(ast, [2, 0, 1]),
    path(ast, [3, 1])
  ]);
  t.deepEqual(select(ast, 'paragraph emphasis > text'), [
    path(ast, [2, 0, 1, 0]),
    path(ast, [3, 1, 0]),
    path(ast, [4, 1, 1, 1, 0, 0, 1, 0])
  ]);
  t.deepEqual(select(ast, 'paragraph > emphasis text'), [
    path(ast, [2, 0, 1, 0]),
    path(ast, [3, 1, 0]),
    path(ast, [3, 1, 1, 0])
  ]);
  t.end();
});

test('siblings', function (t) {
  t.deepEqual(select(ast, 'root ~ heading'), []);
  t.deepEqual(select(ast, 'heading ~ heading'), [
    path(ast, [1]),
    path(ast, [7]),
    path(ast, [12]),
    path(ast, [16])
  ]);
  t.deepEqual(select(ast, 'heading + heading'), [
    path(ast, [1])
  ]);
  t.end();
});

test('grouping', function (t) {
  t.deepEqual(select(ast, 'list, heading + heading'), [
    path(ast, [4]),
    path(ast, [4, 1, 1]),
    path(ast, [4, 1, 1, 0, 1]),
    path(ast, [6]),
    path(ast, [1])
  ]);
  t.end();
});

test('universal selector', function (t) {
  t.equal(select(ast, '*').length, totalNodes(ast));
  t.deepEqual(select(ast, '* ~ heading'), select(ast, 'heading ~ heading'));
  t.true(select(ast, 'list > *').every(function (listItem) {
    return listItem.type == 'listItem';
  }));
  t.end();

  function totalNodes (ast) {
    return 1 + (ast.children || []).map(totalNodes).reduce(function (a, b) {
      return a + b;
    }, 0);
  }
});

test('attribute selectors', function (t) {
  t.comment('existence');
  t.deepEqual(select(ast, '[depth]'), select(ast, 'heading'));
  t.deepEqual(select(ast, '[start][ordered]'), select(ast, 'list'));

  t.comment('equality');
  t.deepEqual(select(ast, 'heading[depth=1], [depth=3]'), [
    path(ast, [0]),
    path(ast, [7])
  ]);
  t.deepEqual(select(ast, 'paragraph [type="text"]'),
              select(ast, 'paragraph text'));
  t.deepEqual(select(ast, '[start=null]'), select(ast, 'list').slice(0, 3));
  t.deepEqual(select(ast, '[ordered=true]'), [ast.children[6]]);
  t.deepEqual(select(ast, 'list[loose=false]'), select(ast, 'list'));

  t.comment('string operators');
  t.deepEqual(select(ast, '[link^="http://"]'), select(ast, 'definition'));
  t.deepEqual(select(ast, '[value*=reduce]'),
              select(ast, 'root > code[lang=js]'));
  t.deepEqual(select(ast, '[type$=Cell]'), select(ast, 'tableCell'));

  t.end();
});

test('structural pseudo-classes', function (t) {
  t.test(':root', function (t) {
    t.deepEqual(select(ast, ':root'), [ast]);
    t.deepEqual(select(ast, ':root:root'), [ast]);
    t.deepEqual(select(ast, '* :root'), []);
    t.deepEqual(select(ast, 'text:not(:root)'), select(ast, 'text'));
    t.deepEqual(select(ast, ':root > list'), [
      path(ast, [4]),
      path(ast, [6])
    ]);
    t.end();
  });

  t.test(':nth-child', function (t) {
    // 6.6.5.2 explicitly states that matching element must have a parent.
    t.deepEqual(select(ast, ':root:nth-child(0)'), []);
    t.deepEqual(select(ast, ':root:nth-child(n)'), []);
    t.deepEqual(select(ast, 'root > list:nth-child(2n+5)'),
                select(ast, 'root > list'));
    t.deepEqual(select(ast, 'heading:nth-child(even)'), [
      path(ast, [1]),
      path(ast, [7])
    ]);
    t.deepEqual(select(ast, ':nth-child(3n+2)[type=inlineCode]')
                .map(function (node) { return node.value }),
                ['integer', 'proin', 'tan']);
    t.end();
  });

  t.test(':nth-last-child', function (t) {
    t.deepEqual(select(ast, ':root:nth-last-child(n)'), []);
    t.deepEqual(select(ast, 'tableCell:nth-last-child(-n+2)'), [
      path(ast, [10, 0, 1]),
      path(ast, [10, 0, 2]),
      path(ast, [10, 1, 1]),
      path(ast, [10, 1, 2]),
      path(ast, [10, 2, 1]),
      path(ast, [10, 2, 2])
    ]);
    t.deepEqual(select(ast, 'definition:nth-last-child(even)')
                .map(function (node) { return node.identifier }),
                ['viverra', 'interdum']);
    t.deepEqual(select(ast,
                       ':root > :nth-last-child(n+2):nth-last-child(-n+3)'), [
                         path(ast, [16]),
                         path(ast, [17])
                       ]);
    t.end();
  });

  t.test(':first-child', function (t) {
    t.deepEqual(select(ast, ':first-child'), select(ast, ':nth-child(1)'));
    t.deepEqual(select(ast, ':root:first-child'), []);
    t.deepEqual(select(ast, 'heading:first-child'), [path(ast, [0])]);
    t.deepEqual(select(ast, 'list listItem:first-child [value]:first-child'), [
      path(ast, [4, 0, 0, 0]),
      path(ast, [4, 1, 1, 0, 0, 0]),
      path(ast, [4, 1, 1, 0, 1, 0, 0, 0]),
      path(ast, [6, 0, 0, 0])
    ]);
    t.end();
  });

  t.test(':last-child', function (t) {
    t.deepEqual(select(ast, ':last-child'), select(ast, ':nth-last-child(1)'));
    t.deepEqual(select(ast, ':root:last-child'), []);
    t.deepEqual(select(ast, 'tableCell:last-child *')
                .map(function (node) { return node.value }),
                ['mi', 'dolor', '15000']);
    t.end();
  });

  t.test(':only-child', function (t) {
    t.deepEqual(select(ast, ':only-child'),
                select(ast, ':first-child:last-child'));
    t.deepEqual(select(ast, ':root:only-child'), []);
    t.deepEqual(select(ast, 'table:only-child'), []);
    t.deepEqual(select(ast, ':root > *:not(paragraph) > text:only-child')
                .map(function (node) { return node.value }),
                ['Risus pretium quam!', 'Vitae', 'References', 'License']);
    t.end();
  });

  t.test(':empty', function (t) {
    t.deepEqual(select(ast, ':root:empty'), []);
    t.deepEqual(select(ast, 'text:empty'), []);
    t.deepEqual(select(ast, 'list:not(:empty)'), select(ast, 'list'));
    t.deepEqual(select(ast, ':empty'), select(ast, 'div > div'));
    t.end();
  });

  t.end();
});

test('negation pseudo-class', function (t) {
  t.deepEqual(select(ast, 'list:not([nonexistent])'), select(ast, 'list'));
  t.deepEqual(select(ast, 'list:not([start=null])'),
              select(ast, 'list[start=1]'));
  t.deepEqual(select(ast, 'heading text:not([value*=" "])')
              .map(function (node) { return node.value }),
              ['Vitae', 'References', 'License']);
  t.deepEqual(select(ast, [
    'list:not([ordered=true])',
    '*:not(listItem):not(paragraph)[children]:not(list)'
  ].join(' ')), [
    path(ast, [4, 1, 1, 1, 0, 0]),
    path(ast, [4, 1, 1, 1, 0, 0, 1])
  ]);
  t.end();
});
<|endoftext|>