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

const moo = require('../moo')
const compile = moo.compile
const python = require('./python')

describe('moo compiler', () => {

  test("warns for /g, /y, /i, /m", () => {
    expect(() => compile({ word: /foo/ })).not.toThrow()
    expect(() => compile({ word: /foo/g })).toThrow()
    expect(() => compile({ word: /foo/i })).toThrow()
    expect(() => compile({ word: /foo/y })).toThrow()
    expect(() => compile({ word: /foo/m })).toThrow()
  })

  // TODO warns for multiple capture groups

  // TODO wraps zero capture groups

  // TODO warns if no lineBreaks: true

  test('sorts regexps and strings', () => {
    let lexer = moo.compile({
      tok: [/t[ok]+/, /\w/, 'tok', 'token']
    })
    expect(lexer.re.source.replace(/[(?:)]/g, '')).toBe('token|tok|t[ok]+|\\w')
  })

})

describe('moo lexer', () => {

  var simpleLexer = compile({
    word: /[a-z]+/,
    number: /[0-9]+/,
    ws: / +/,
  })

  test('vaguely works', () => {
    simpleLexer.reset('ducks are 123 bad')
    expect(simpleLexer.lex()).toMatchObject({ type: 'word', value: 'ducks' })
    expect(simpleLexer.lex()).toMatchObject({ type: 'ws', value: ' ' })
    expect(simpleLexer.lex()).toMatchObject({ type: 'word', value: 'are' })
  })

  test('accepts rules in an object', () => {
    const lexer = compile({
      word: /[a-z]+/,
      number: /[0-9]+/,
      space: / +/,
    })
    lexer.reset('ducks are 123 bad')
    expect(lexer.lex()).toMatchObject({type: 'word', value: 'ducks'})
    expect(lexer.lex()).toMatchObject({type: 'space', value: ' '})
  })

  test('accepts a list of regexps', () => {
    const lexer = compile({
      number: [
        /[0-9]+\.[0-9]+/,
        /[0-9]+/,
      ],
      space: / +/,
    })
    lexer.reset('12.04 123 3.14')
    var tokens = lexer.lexAll().filter(t => t.type !== 'space')
    expect(tokens.shift()).toMatchObject({type: 'number', value: '12.04'})
    expect(tokens.shift()).toMatchObject({type: 'number', value: '123'})
    expect(tokens.shift()).toMatchObject({type: 'number', value: '3.14'})
  })

  test('no capture groups', () => {
    let lexer = compile({
      a: /a+/,
      b: /b|c/,
    })
    lexer.reset('aaaaabcbcbcbc')
    expect(lexer.lex().value).toEqual('aaaaa')
    expect(lexer.lex().value).toEqual('b')
    expect(lexer.lex().value).toEqual('c')
    expect(lexer.lex().value).toEqual('b')
  })

  test('multiline', () => {
    var lexer = compile({
      file: { match: /([^]+)/, lineBreaks: true },
    }).reset('I like to moo\na lot')
    expect(lexer.lex().value).toBe('I like to moo\na lot')
  })

  test('match EOL $', () => {
    var lexer = compile({
      x_eol: /x$/,
      x: /x/,
      WS: / +/,
      NL: { match: /\n/, lineBreaks: true },
      other: /[^ \n]+/,
    }).reset('x \n x\n yz x')
    let tokens = lexer.lexAll().filter(t => t.type !== 'WS')
    expect(tokens.map(t => [t.type, t.value])).toEqual([
      ['x', 'x'],
      ['NL', '\n'],
      ['x_eol', 'x'],
      ['NL', '\n'],
      ['other', 'yz'],
      ['x_eol', 'x'],
    ])
  })

  test('match BOL ^', () => {
    var lexer = compile({
      x_bol: /^x/,
      x: /x/,
      WS: / +/,
      NL: { match: /\n/, lineBreaks: true },
      other: /[^ \n]+/,
    }).reset('x \n x\nx yz')
    let tokens = lexer.lexAll().filter(t => t.type !== 'WS')
    expect(tokens.map(t => [t.type, t.value])).toEqual([
      ['x_bol', 'x'],
      ['NL', '\n'],
      ['x', 'x'],
      ['NL', '\n'],
      ['x_bol', 'x'],
      ['other', 'yz'],
    ])
  })

  // TODO test / design API for errors
  // - check the reported error location

  test('kurt tokens', () => {
    let pythonLexer = compile(python.rules)
    let tokens = pythonLexer.reset(fs.readFileSync('test/kurt.py', 'utf-8')).lexAll()
    expect(tokens.length).toBe(14513)
  })

  // TODO test clone()
})

describe('moo stateful lexer', () => {

  test('switches states', () => {
    const lexer = moo.states({
      start: {
        word: /\w+/,
        eq: {match: '=', next: 'ab'},
      },
      ab: {
        a: 'a',
        b: 'b',
        semi: {match: ';', next: 'start'},
      },
    })

    lexer.reset('one=ab;two=')
    expect(lexer.lexAll().map(({type, value}) => [type, value])).toEqual([
      ['word', 'one'],
      ['eq', '='],
      ['a', 'a'],
      ['b', 'b'],
      ['semi', ';'],
      ['word', 'two'],
      ['eq', '='],
    ])
  })

  test('maintains a stack', () => {
    const lexer = moo.states({
      start: {
        word: /\w+/,
        lpar: {match: '(', push: 'inner'},
        rpar: ')',
      },
      inner: {
        thing: /\w+/,
        lpar: {match: '(', push: 'inner'},
        rpar: {match: ')', pop: true},
      },
    })

    lexer.reset('a(b(c)d)e')
    expect(lexer.lexAll().map(({type, value}) => [type, value])).toEqual([
      ['word', 'a'],
      ['lpar', '('],
      ['thing', 'b'],
      ['lpar', '('],
      ['thing', 'c'],
      ['rpar', ')'],
      ['thing', 'd'],
      ['rpar', ')'],
      ['word', 'e'],
    ])
  })
})

describe('line numbers', () => {

  var testLexer = compile({
    WS: / +/,
    word: /[a-z]+/,
    NL: { match: /\n/, lineBreaks: true },
  })

  test('counts line numbers', () => {
    var tokens = testLexer.reset('cow\nfarm\ngrass').lexAll()
    expect(tokens.map(t => t.value)).toEqual(['cow', '\n', 'farm', '\n', 'grass'])
    expect(tokens.map(t => t.lineBreaks)).toEqual([0, 1, 0, 1, 0])
    expect(tokens.map(t => t.size)).toEqual([3, 1, 4, 1, 5])
    expect(tokens.map(t => t.line)).toEqual([1, 1, 2, 2, 3])
    expect(tokens.map(t => t.col)).toEqual([1, 4, 1, 5, 1])
  })

  test('tracks columns', () => {
    var lexer = compile({
      WS: / +/,
      thing: { match: /[a-z\n]+/, lineBreaks: true },
    })
    lexer.reset('pie cheese\nsalad what\n ')
    expect(lexer.lex()).toMatchObject({ value: 'pie', col: 1 })
    expect(lexer.lex()).toMatchObject({ value: ' ', col: 4 })
    expect(lexer.lex()).toMatchObject({ value: 'cheese\nsalad', col: 5, line: 1 })
    expect(lexer.lex()).toMatchObject({ value: ' ', col: 6, line: 2 })
    expect(lexer.lex()).toMatchObject({ value: 'what\n', col: 7, line: 2 })
    expect(lexer.lex()).toMatchObject({ value: ' ', col: 1, line: 3 })
  })

  test('tries to warn if rule matches \\n', () => {
    expect(() => compile([['whitespace', /\s+/]])).toThrow()
    expect(() => compile([['multiline', /q[^]*/]])).not.toThrow()
  })

  test('resets state', () => {
    var lexer = compile({
      WS: / +/,
      word: /[a-z]+/,
    })
    lexer.reset('potatoes\nsalad')
    expect(lexer).toMatchObject({buffer: 'potatoes\nsalad', line: 1, col: 1})
    lexer.lexAll()
    expect(lexer).toMatchObject({line: 2, col: 6})
    lexer.reset('cheesecake')
    expect(lexer).toMatchObject({buffer: 'cheesecake', line: 1, col: 1})
  })

  // TODO test clone()
})

describe('state', () => {

  const testLexer = compile({
    word: /[a-z]+/,
    NL: { match: '\n', lineBreaks: true },
  })

  test('can be saved', () => {
    testLexer.reset('one\ntwo')
    testLexer.lexAll()
    expect(testLexer.save()).toEqual({line: 2, col: 4})
  })

  test('can be restored', () => {
    testLexer.reset('\nthree', {line: 2, col: 4})
    expect(testLexer).toMatchObject({line: 2, col: 4, buffer: '\nthree'})
  })

})

describe('python tokenizer', () => {

  test("1 + 2", () => {
    expect(python.outputTokens("1 + 2")).toEqual([
      'NUMBER "1"',
      'OP "+"',
      'NUMBER "2"',
      'ENDMARKER ""',
    ])
  })

  // use non-greedy matching
  test('triple-quoted strings', () => {
    let example = '"""abc""" 1+1 """def"""'
    let pythonLexer = compile(python.rules)
    expect(pythonLexer.reset(example).lexAll().map(t => t.value)).toEqual(
      ['"""abc"""', " ", "1", "+", "1", " ", '"""def"""']
    )
  })

  test('example python file', () => {
    expect(python.outputTokens(python.pythonFile)).toEqual([
      // 'ENCODING "utf-8"',
      'COMMENT "#!/usr/local/bin/python3"',
      'NL "\\n"',
      'NAME "import"',
      'NAME "sys"',
      'NEWLINE "\\n"',
      'NAME "from"',
      'NAME "tokenize"',
      'NAME "import"',
      'NAME "tokenize"',
      'OP ","',
      'NAME "tok_name"',
      'NEWLINE "\\n"',
      'NAME "import"',
      'NAME "json"',
      'NEWLINE "\\n"',
      'NAME "from"',
      'NAME "io"',
      'NAME "import"',
      'NAME "BytesIO"',
      'NEWLINE "\\n"',
      'NL "\\n"',
      'NAME "path"',
      'OP "="',
      'NAME "sys"',
      'OP "."',
      'NAME "argv"',
      'OP "["',
      'NUMBER "1"',
      'OP "]"',
      'NEWLINE "\\n"',
      'NAME "for"',
      'NAME "info"',
      'NAME "in"',
      'NAME "tokenize"',
      'OP "("',
      'NAME "open"',
      'OP "("',
      'NAME "path"',
      'OP ","',
      'STRING "rb"',
      'OP ")"',
      'OP "."',
      'NAME "readline"',
      'OP ")"',
      'OP ":"',
      'NEWLINE "\\n"',
      'INDENT "    "',
      'NAME "print"',
      'OP "("',
      'NAME "tok_name"',
      'OP "["',
      'NAME "info"',
      'OP "."',
      'NAME "type"',
      'OP "]"',
      'OP ","',
      'NAME "json"',
      'OP "."',
      'NAME "dumps"',
      'OP "("',
      'NAME "info"',
      'OP "."',
      'NAME "string"',
      'OP ")"',
      'OP ")"',
      'NEWLINE "\\n"',
      // 'NL "\\n"',
      'DEDENT ""',
      'ENDMARKER ""',
    ])
  })

  test("kurt python", () => {
    let tokens = python.outputTokens(fs.readFileSync('test/kurt.py', 'utf-8'))
    expect(tokens[100]).toBe('NAME "def"')
    expect(tokens.pop()).toBe('ENDMARKER ""')
    tokens.pop()
    expect(tokens.pop()).not.toBe('ERRORTOKEN ""')
    expect(tokens.length).toBe(11616)

    // let expected = fs.readFileSync('test/kurt-tokens.txt', 'utf-8').split('\n')
    // expect(tokens).toEqual(expected)
  })

})

describe('tosh tokenizer', () => {

  const tosh = require('./tosh')

  test('tosh', () => {
    let oldTokens = tosh.oldTokenizer(tosh.exampleFile)
    expect(tosh.tokenize(tosh.exampleFile)).toEqual(oldTokens)
  })

})
<commit_msg>Test that compiler warns about missing statets<commit_after>
const fs = require('fs')

const moo = require('../moo')
const compile = moo.compile
const python = require('./python')

describe('moo compiler', () => {

  test("warns for /g, /y, /i, /m", () => {
    expect(() => compile({ word: /foo/ })).not.toThrow()
    expect(() => compile({ word: /foo/g })).toThrow()
    expect(() => compile({ word: /foo/i })).toThrow()
    expect(() => compile({ word: /foo/y })).toThrow()
    expect(() => compile({ word: /foo/m })).toThrow()
  })

  // TODO warns for multiple capture groups

  // TODO wraps zero capture groups

  // TODO warns if no lineBreaks: true

  test('sorts regexps and strings', () => {
    let lexer = moo.compile({
      tok: [/t[ok]+/, /\w/, 'tok', 'token']
    })
    expect(lexer.re.source.replace(/[(?:)]/g, '')).toBe('token|tok|t[ok]+|\\w')
  })

  test('warns about missing states', () => {
    expect(() => moo.states({start: {
      thing: {match: '=', next: 'missing'},
    }})).toThrow()
    expect(() => moo.states({start:
      {thing: {match: '=', push: 'missing'}},
    })).toThrow()
  })

})

describe('moo lexer', () => {

  var simpleLexer = compile({
    word: /[a-z]+/,
    number: /[0-9]+/,
    ws: / +/,
  })

  test('vaguely works', () => {
    simpleLexer.reset('ducks are 123 bad')
    expect(simpleLexer.lex()).toMatchObject({ type: 'word', value: 'ducks' })
    expect(simpleLexer.lex()).toMatchObject({ type: 'ws', value: ' ' })
    expect(simpleLexer.lex()).toMatchObject({ type: 'word', value: 'are' })
  })

  test('accepts rules in an object', () => {
    const lexer = compile({
      word: /[a-z]+/,
      number: /[0-9]+/,
      space: / +/,
    })
    lexer.reset('ducks are 123 bad')
    expect(lexer.lex()).toMatchObject({type: 'word', value: 'ducks'})
    expect(lexer.lex()).toMatchObject({type: 'space', value: ' '})
  })

  test('accepts a list of regexps', () => {
    const lexer = compile({
      number: [
        /[0-9]+\.[0-9]+/,
        /[0-9]+/,
      ],
      space: / +/,
    })
    lexer.reset('12.04 123 3.14')
    var tokens = lexer.lexAll().filter(t => t.type !== 'space')
    expect(tokens.shift()).toMatchObject({type: 'number', value: '12.04'})
    expect(tokens.shift()).toMatchObject({type: 'number', value: '123'})
    expect(tokens.shift()).toMatchObject({type: 'number', value: '3.14'})
  })

  test('no capture groups', () => {
    let lexer = compile({
      a: /a+/,
      b: /b|c/,
    })
    lexer.reset('aaaaabcbcbcbc')
    expect(lexer.lex().value).toEqual('aaaaa')
    expect(lexer.lex().value).toEqual('b')
    expect(lexer.lex().value).toEqual('c')
    expect(lexer.lex().value).toEqual('b')
  })

  test('multiline', () => {
    var lexer = compile({
      file: { match: /([^]+)/, lineBreaks: true },
    }).reset('I like to moo\na lot')
    expect(lexer.lex().value).toBe('I like to moo\na lot')
  })

  test('match EOL $', () => {
    var lexer = compile({
      x_eol: /x$/,
      x: /x/,
      WS: / +/,
      NL: { match: /\n/, lineBreaks: true },
      other: /[^ \n]+/,
    }).reset('x \n x\n yz x')
    let tokens = lexer.lexAll().filter(t => t.type !== 'WS')
    expect(tokens.map(t => [t.type, t.value])).toEqual([
      ['x', 'x'],
      ['NL', '\n'],
      ['x_eol', 'x'],
      ['NL', '\n'],
      ['other', 'yz'],
      ['x_eol', 'x'],
    ])
  })

  test('match BOL ^', () => {
    var lexer = compile({
      x_bol: /^x/,
      x: /x/,
      WS: / +/,
      NL: { match: /\n/, lineBreaks: true },
      other: /[^ \n]+/,
    }).reset('x \n x\nx yz')
    let tokens = lexer.lexAll().filter(t => t.type !== 'WS')
    expect(tokens.map(t => [t.type, t.value])).toEqual([
      ['x_bol', 'x'],
      ['NL', '\n'],
      ['x', 'x'],
      ['NL', '\n'],
      ['x_bol', 'x'],
      ['other', 'yz'],
    ])
  })

  // TODO test / design API for errors
  // - check the reported error location

  test('kurt tokens', () => {
    let pythonLexer = compile(python.rules)
    let tokens = pythonLexer.reset(fs.readFileSync('test/kurt.py', 'utf-8')).lexAll()
    expect(tokens.length).toBe(14513)
  })

  // TODO test clone()
})

describe('moo stateful lexer', () => {

  test('switches states', () => {
    const lexer = moo.states({
      start: {
        word: /\w+/,
        eq: {match: '=', next: 'ab'},
      },
      ab: {
        a: 'a',
        b: 'b',
        semi: {match: ';', next: 'start'},
      },
    })

    lexer.reset('one=ab;two=')
    expect(lexer.lexAll().map(({type, value}) => [type, value])).toEqual([
      ['word', 'one'],
      ['eq', '='],
      ['a', 'a'],
      ['b', 'b'],
      ['semi', ';'],
      ['word', 'two'],
      ['eq', '='],
    ])
  })

  test('maintains a stack', () => {
    const lexer = moo.states({
      start: {
        word: /\w+/,
        lpar: {match: '(', push: 'inner'},
        rpar: ')',
      },
      inner: {
        thing: /\w+/,
        lpar: {match: '(', push: 'inner'},
        rpar: {match: ')', pop: true},
      },
    })

    lexer.reset('a(b(c)d)e')
    expect(lexer.lexAll().map(({type, value}) => [type, value])).toEqual([
      ['word', 'a'],
      ['lpar', '('],
      ['thing', 'b'],
      ['lpar', '('],
      ['thing', 'c'],
      ['rpar', ')'],
      ['thing', 'd'],
      ['rpar', ')'],
      ['word', 'e'],
    ])
  })
})

describe('line numbers', () => {

  var testLexer = compile({
    WS: / +/,
    word: /[a-z]+/,
    NL: { match: /\n/, lineBreaks: true },
  })

  test('counts line numbers', () => {
    var tokens = testLexer.reset('cow\nfarm\ngrass').lexAll()
    expect(tokens.map(t => t.value)).toEqual(['cow', '\n', 'farm', '\n', 'grass'])
    expect(tokens.map(t => t.lineBreaks)).toEqual([0, 1, 0, 1, 0])
    expect(tokens.map(t => t.size)).toEqual([3, 1, 4, 1, 5])
    expect(tokens.map(t => t.line)).toEqual([1, 1, 2, 2, 3])
    expect(tokens.map(t => t.col)).toEqual([1, 4, 1, 5, 1])
  })

  test('tracks columns', () => {
    var lexer = compile({
      WS: / +/,
      thing: { match: /[a-z\n]+/, lineBreaks: true },
    })
    lexer.reset('pie cheese\nsalad what\n ')
    expect(lexer.lex()).toMatchObject({ value: 'pie', col: 1 })
    expect(lexer.lex()).toMatchObject({ value: ' ', col: 4 })
    expect(lexer.lex()).toMatchObject({ value: 'cheese\nsalad', col: 5, line: 1 })
    expect(lexer.lex()).toMatchObject({ value: ' ', col: 6, line: 2 })
    expect(lexer.lex()).toMatchObject({ value: 'what\n', col: 7, line: 2 })
    expect(lexer.lex()).toMatchObject({ value: ' ', col: 1, line: 3 })
  })

  test('tries to warn if rule matches \\n', () => {
    expect(() => compile([['whitespace', /\s+/]])).toThrow()
    expect(() => compile([['multiline', /q[^]*/]])).not.toThrow()
  })

  test('resets state', () => {
    var lexer = compile({
      WS: / +/,
      word: /[a-z]+/,
    })
    lexer.reset('potatoes\nsalad')
    expect(lexer).toMatchObject({buffer: 'potatoes\nsalad', line: 1, col: 1})
    lexer.lexAll()
    expect(lexer).toMatchObject({line: 2, col: 6})
    lexer.reset('cheesecake')
    expect(lexer).toMatchObject({buffer: 'cheesecake', line: 1, col: 1})
  })

  // TODO test clone()
})

describe('state', () => {

  const testLexer = compile({
    word: /[a-z]+/,
    NL: { match: '\n', lineBreaks: true },
  })

  test('can be saved', () => {
    testLexer.reset('one\ntwo')
    testLexer.lexAll()
    expect(testLexer.save()).toEqual({line: 2, col: 4})
  })

  test('can be restored', () => {
    testLexer.reset('\nthree', {line: 2, col: 4})
    expect(testLexer).toMatchObject({line: 2, col: 4, buffer: '\nthree'})
  })

})

describe('python tokenizer', () => {

  test("1 + 2", () => {
    expect(python.outputTokens("1 + 2")).toEqual([
      'NUMBER "1"',
      'OP "+"',
      'NUMBER "2"',
      'ENDMARKER ""',
    ])
  })

  // use non-greedy matching
  test('triple-quoted strings', () => {
    let example = '"""abc""" 1+1 """def"""'
    let pythonLexer = compile(python.rules)
    expect(pythonLexer.reset(example).lexAll().map(t => t.value)).toEqual(
      ['"""abc"""', " ", "1", "+", "1", " ", '"""def"""']
    )
  })

  test('example python file', () => {
    expect(python.outputTokens(python.pythonFile)).toEqual([
      // 'ENCODING "utf-8"',
      'COMMENT "#!/usr/local/bin/python3"',
      'NL "\\n"',
      'NAME "import"',
      'NAME "sys"',
      'NEWLINE "\\n"',
      'NAME "from"',
      'NAME "tokenize"',
      'NAME "import"',
      'NAME "tokenize"',
      'OP ","',
      'NAME "tok_name"',
      'NEWLINE "\\n"',
      'NAME "import"',
      'NAME "json"',
      'NEWLINE "\\n"',
      'NAME "from"',
      'NAME "io"',
      'NAME "import"',
      'NAME "BytesIO"',
      'NEWLINE "\\n"',
      'NL "\\n"',
      'NAME "path"',
      'OP "="',
      'NAME "sys"',
      'OP "."',
      'NAME "argv"',
      'OP "["',
      'NUMBER "1"',
      'OP "]"',
      'NEWLINE "\\n"',
      'NAME "for"',
      'NAME "info"',
      'NAME "in"',
      'NAME "tokenize"',
      'OP "("',
      'NAME "open"',
      'OP "("',
      'NAME "path"',
      'OP ","',
      'STRING "rb"',
      'OP ")"',
      'OP "."',
      'NAME "readline"',
      'OP ")"',
      'OP ":"',
      'NEWLINE "\\n"',
      'INDENT "    "',
      'NAME "print"',
      'OP "("',
      'NAME "tok_name"',
      'OP "["',
      'NAME "info"',
      'OP "."',
      'NAME "type"',
      'OP "]"',
      'OP ","',
      'NAME "json"',
      'OP "."',
      'NAME "dumps"',
      'OP "("',
      'NAME "info"',
      'OP "."',
      'NAME "string"',
      'OP ")"',
      'OP ")"',
      'NEWLINE "\\n"',
      // 'NL "\\n"',
      'DEDENT ""',
      'ENDMARKER ""',
    ])
  })

  test("kurt python", () => {
    let tokens = python.outputTokens(fs.readFileSync('test/kurt.py', 'utf-8'))
    expect(tokens[100]).toBe('NAME "def"')
    expect(tokens.pop()).toBe('ENDMARKER ""')
    tokens.pop()
    expect(tokens.pop()).not.toBe('ERRORTOKEN ""')
    expect(tokens.length).toBe(11616)

    // let expected = fs.readFileSync('test/kurt-tokens.txt', 'utf-8').split('\n')
    // expect(tokens).toEqual(expected)
  })

})

describe('tosh tokenizer', () => {

  const tosh = require('./tosh')

  test('tosh', () => {
    let oldTokens = tosh.oldTokenizer(tosh.exampleFile)
    expect(tosh.tokenize(tosh.exampleFile)).toEqual(oldTokens)
  })

})
<|endoftext|>


<commit_before>pp.views.Notify = pp.View.Base.extend({

    template: _.template($('#template-notify').text()),

    render: function () {
        this.$el.html(this.template({text: this.options.text }));
        return this;
    }
});
<commit_msg>remove views/notify, nobody uses it<commit_after><|endoftext|>


<commit_before>var path = require('path');
var should = require('chai').should();
var Animal = require(path.join(process.cwd() + '/lib/Animal'));
var cp = require('child_process');
//process.cwd goes to the root dir, so it can go to any directory from the root
//path.join gives you a proper path, but need to be defined
describe('Tests', function () {
  it('truthyness', function () {
    true.should.equal(true);
  });
});

describe.only('CLI', function(){
  it('should thank me for downloading', function (done){
    console.log('childprocess');
    cp.execFile('./app.js', function (err, stdout) {
      console.log('err', err);
      console.log('stdout', stdout);
      stdout.should.equal('Thanks for downloading my app!\n');
      //fails when console.log() from app.js has different output
      done();
    });
  })
});

describe('Animal', function () {
  describe('constructor', function () {
    it('should return an animal object', function () {
      var animal = new Animal();
      animal.should.be.an('object');
      animal.should.be.an.instanceOf(Animal);
    });
    it('should be alive', function () {
      var animal = new Animal();
      animal.isAlive.should.be.true;
      //defined in Animal.js
    });
    it('should have 100% health', function () {
      var animal = new Animal();
      animal.health.should.equal(1);
    });
    it('should accept a type', function () {
      var cat = new Animal('cat');
      var dog = new Animal('dog');
      cat.type.should.equal('cat');
      dog.type.should.equal('dog');
    })
  });
  describe('#updateHealthStats', function () {
    it('should change the health', function (done) {
     //need done agrument passed into the it block so that it waits on timeout
      var animal = new Animal();
      animal.updateHealthStats(function () {
        animal.health.should.not.equal(1);
        done();
      });
    })
  })
  describe('#beCute()', function () {
    it('should be a prototype method', function () {
      var animal = new Animal();
      animal.should.respondTo('beCute');
      animal.should.not.have.ownProperty('beCute');
    });
    it('should make the animal cute', function () {
      var animal = new Animal();
      should.not.exist(animal.isCute);
      //no cute animals until beCute
      animal.beCute();
      animal.isCute.should.be.true;
    });
  });
});
describe('Array', function () {
  describe('#filter()', function () {
    it('should return an array of items that return truthy in the innner fn', function () {
      var array = [1, 2, 3, 4, 5];
      var output = array.filter(function (item) {
        return item % 2;
        //filter out even numbers
      });
      output.should.eql([1, 3, 5]);
    });
  });
  describe('#map()', function () {
    it('should create an array with the return value of the inner fn', function () {
      var array = [1, 2, 3, 4, 5];
      var output = array.map(function (item) {
        return item * item;
      });
      output.should.eql([1, 4, 9, 16, 25]);
    });
    it('should keep the same length', function () {
      var array = [1, 2, 3, 4, 5];
      var length = array.map(function (item) {
        return false;
      }).length;
      length.should.equal(array.length);
    });
    it('should not mutate the original array', function () {
      var array = [1, 2, 3, 4, 5];
      array.map(function () {
        return false;
      });
      array.should.eql([1, 2, 3, 4, 5]);
    });
  });
});
<commit_msg>all the tests<commit_after>var path = require('path');
var should = require('chai').should();
var Animal = require(path.join(process.cwd() + '/lib/Animal'));
var cp = require('child_process');
//process.cwd goes to the root dir, so it can go to any directory from the root
//path.join gives you a proper path, but need to be defined
describe('Tests', function () {
  it('truthyness', function () {
    true.should.equal(true);
  });
});

describe('CLI', function(){
  it('should thank me for downloading', function (done){
    console.log('childprocess');
    cp.execFile('./app.js', function (err, stdout) {
      console.log('err', err);
      console.log('stdout', stdout);
      stdout.should.equal('Thanks for downloading my app!\n');
      //fails when console.log() from app.js has different output
      done();
    });
  })
});

describe('Animal', function () {
  describe('constructor', function () {
    it('should return an animal object', function () {
      var animal = new Animal();
      animal.should.be.an('object');
      animal.should.be.an.instanceOf(Animal);
    });
    it('should be alive', function () {
      var animal = new Animal();
      animal.isAlive.should.be.true;
      //defined in Animal.js
    });
    it('should have 100% health', function () {
      var animal = new Animal();
      animal.health.should.equal(1);
    });
    it('should accept a type', function () {
      var cat = new Animal('cat');
      var dog = new Animal('dog');
      cat.type.should.equal('cat');
      dog.type.should.equal('dog');
    })
  });
  describe('#updateHealthStats', function () {
    it('should change the health', function (done) {
     //need done agrument passed into the it block so that it waits on timeout
      var animal = new Animal();
      animal.updateHealthStats(function () {
        animal.health.should.not.equal(1);
        done();
      });
    })
  })
  describe('#beCute()', function () {
    it('should be a prototype method', function () {
      var animal = new Animal();
      animal.should.respondTo('beCute');
      animal.should.not.have.ownProperty('beCute');
    });
    it('should make the animal cute', function () {
      var animal = new Animal();
      should.not.exist(animal.isCute);
      //no cute animals until beCute
      animal.beCute();
      animal.isCute.should.be.true;
    });
  });
});
describe('Array', function () {
  describe('#filter()', function () {
    it('should return an array of items that return truthy in the innner fn', function () {
      var array = [1, 2, 3, 4, 5];
      var output = array.filter(function (item) {
        return item % 2;
        //filter out even numbers
      });
      output.should.eql([1, 3, 5]);
    });
  });
  describe('#map()', function () {
    it('should create an array with the return value of the inner fn', function () {
      var array = [1, 2, 3, 4, 5];
      var output = array.map(function (item) {
        return item * item;
      });
      output.should.eql([1, 4, 9, 16, 25]);
    });
    it('should keep the same length', function () {
      var array = [1, 2, 3, 4, 5];
      var length = array.map(function (item) {
        return false;
      }).length;
      length.should.equal(array.length);
    });
    it('should not mutate the original array', function () {
      var array = [1, 2, 3, 4, 5];
      array.map(function () {
        return false;
      });
      array.should.eql([1, 2, 3, 4, 5]);
    });
  });
});
<|endoftext|>


<commit_before>var test = require('assert');

var csv = require('csv');
var fs = require('fs');

var redis = require('redis');
var client = redis.createClient();

var proximity = require('../main.js');
proximity.initialize(client, "redisproximityzset");

var lat = 43.646838,
    lon = -79.403723;

var oneToDelete = "";
var arrayToDelete = [];
var addArray = [];

exports.basicQuery = function(test){

  proximity.query(lat, lon, 50000, function(err, replies){
    if(err) throw err;
    console.log("NUMBER OF GEOHASH MATCHES", replies.length);
    test.equal(replies.length, 13260);
    test.done();
  });
};

exports.performantQuery = function(test){
  var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

  proximity.queryByRanges(ranges, function(err, replies){
    if(err) throw err;
    test.equal(replies.length, 13260);
    test.done();
  });

};

exports.deleteOne = function(test){
  var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

  proximity.queryByRanges(ranges, function(err, replies){
    if(err) throw err;
    oneToDelete = replies[replies.length-1];

    proximity.removeCoordinate(oneToDelete, function(err, reply){
      if(err) throw err;
      // console.log("TIMESTAMP Delete One", new Date().getTime()-startTime);
      // console.log(JSON.stringify(reply));
      test.equal(reply, 1);
      test.done();
    });
  });
};

exports.deleteMany = function(test){

  var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

  proximity.queryByRanges(ranges, function(err, replies){

    if(err) throw err;
    arrayToDelete = replies;

    proximity.removeCoordinates(arrayToDelete, function(err, reply){
      if(err) throw err;

      test.equal(reply, 13259);
      test.done();
    });
  });
};

exports.addFromCSV = function(){

  startTime = new Date().getTime();
  var i = 0;

  var lat, lon;

  csv()
  .from.path(__dirname+'/GeoLiteCity-Location.csv', { delimiter: ',', escape: '"' })
  .on('record', function(row,index){

    lat = Number(row[5]);
    lon = Number(row[6]);
    name = row[3]+row[4];

    proximity.addNewCoordinate(lat, lon, name, function(err, reply){
      if(err) throw err;
      if(i%1000 === 0){
        console.log(i, ":", name, lat, lon, reply, err);
      }
    });

    i++;

  })
  .on('close', function(count){
    // when writing to a file, use the 'close' event
    // the 'end' event may fire before the file has been written
    console.log('CLOSE Number of lines: '+count);
    console.log('CLOSE Time: '+ (new Date().getTime()-startTime) );

  }).on('end', function(end){

    console.log('END Number of lines: '+end);
    console.log('END Time: '+ (new Date().getTime()-startTime-3224) );

    test.equal(end, 509068);
    test.done();

  })
  .on('error', function(error){
    console.log(error.message);
  });
};

exports.addFromCSVMulti = function(){

  client.flushall();

  startTime = new Date().getTime();
  var i = 0;

  var lat, lon;

  csv()
  .from.path(__dirname+'/GeoLiteCity-Location.csv', { delimiter: ',', escape: '"' })
  .on('record', function(row,index){

    lat = Number(row[5]);
    lon = Number(row[6]);
    name = row[3]+row[4];
    addArray.push([lat, lon, name]);

    if(i%1000 === 0){
      console.log(i, ":", name, lat, lon);
    }
    i++;

  })
  .on('close', function(count){
    // when writing to a file, use the 'close' event
    // the 'end' event may fire before the file has been written
    console.log('CLOSE Number of lines: '+count);
    console.log('CLOSE Time: '+ (new Date().getTime()-startTime) );

  }).on('end', function(end){

    console.log('END Number of lines: '+end);

    proximity.addCoordinates(addArray, function(err, reply){
      if(err) throw err;
      // console.log('END Time: '+ (new Date().getTime()-startTime-3224) );
      // console.log('Add Coordinates Multi Reply ', err, reply);
      test.equal(err, null);
      test.equal(reply, 432346);
      test.done();
    });

  })
  .on('error', function(error){
    console.log(error.message);
  });
};

return exports;<commit_msg>updating tests to work with travis<commit_after>var test = require('assert');

var csv = require('csv');
var fs = require('fs');

var redis = require('redis');
var client = redis.createClient();

var proximity = require('../main.js');
proximity.initialize(client, "redisproximityzset");

var lat = 43.646838,
    lon = -79.403723;

var oneToDelete = "";
var arrayToDelete = [];
var addArray = [];

exports.addFromCSV = function(){

  startTime = new Date().getTime();
  var i = 0;

  var lat, lon;

  csv()
  .from.path(__dirname+'/GeoLiteCity-Location.csv', { delimiter: ',', escape: '"' })
  .on('record', function(row,index){

    lat = Number(row[5]);
    lon = Number(row[6]);
    name = row[3]+row[4];

    proximity.addNewCoordinate(lat, lon, name, function(err, reply){
      if(err) throw err;
      if(i%1000 === 0){
        console.log(i, ":", name, lat, lon, reply, err);
      }
    });

    i++;

  })
  .on('close', function(count){
    // when writing to a file, use the 'close' event
    // the 'end' event may fire before the file has been written
    console.log('CLOSE Number of lines: '+count);
    console.log('CLOSE Time: '+ (new Date().getTime()-startTime) );

  }).on('end', function(end){

    console.log('END Number of lines: '+end);
    console.log('END Time: '+ (new Date().getTime()-startTime-3224) );

    test.equal(end, 509068);
    test.done();

  })
  .on('error', function(error){
    console.log(error.message);
  });
};

exports.addFromCSVMulti = function(){

  client.flushall();

  startTime = new Date().getTime();
  var i = 0;

  var lat, lon;

  csv()
  .from.path(__dirname+'/GeoLiteCity-Location.csv', { delimiter: ',', escape: '"' })
  .on('record', function(row,index){

    lat = Number(row[5]);
    lon = Number(row[6]);
    name = row[3]+row[4];
    addArray.push([lat, lon, name]);

    if(i%1000 === 0){
      console.log(i, ":", name, lat, lon);
    }
    i++;

  })
  .on('close', function(count){
    // when writing to a file, use the 'close' event
    // the 'end' event may fire before the file has been written
    console.log('CLOSE Number of lines: '+count);
    console.log('CLOSE Time: '+ (new Date().getTime()-startTime) );

  }).on('end', function(end){

    console.log('END Number of lines: '+end);

    proximity.addCoordinates(addArray, function(err, reply){
      if(err) throw err;
      // console.log('END Time: '+ (new Date().getTime()-startTime-3224) );
      // console.log('Add Coordinates Multi Reply ', err, reply);
      test.equal(err, null);
      test.equal(reply, 432346);
      test.done();
    });

  })
  .on('error', function(error){
    console.log(error.message);
  });
};

exports.basicQuery = function(test){

  proximity.query(lat, lon, 50000, function(err, replies){
    if(err) throw err;
    console.log("NUMBER OF GEOHASH MATCHES", replies.length);
    test.equal(replies.length, 13260);
    test.done();
  });
};

exports.performantQuery = function(test){
  var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

  proximity.queryByRanges(ranges, function(err, replies){
    if(err) throw err;
    test.equal(replies.length, 13260);
    test.done();
  });

};

exports.deleteOne = function(test){
  var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

  proximity.queryByRanges(ranges, function(err, replies){
    if(err) throw err;
    oneToDelete = replies[replies.length-1];

    proximity.removeCoordinate(oneToDelete, function(err, reply){
      if(err) throw err;
      // console.log("TIMESTAMP Delete One", new Date().getTime()-startTime);
      // console.log(JSON.stringify(reply));
      test.equal(reply, 1);
      test.done();
    });
  });
};

exports.deleteMany = function(test){

  var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

  proximity.queryByRanges(ranges, function(err, replies){

    if(err) throw err;
    arrayToDelete = replies;

    proximity.removeCoordinates(arrayToDelete, function(err, reply){
      if(err) throw err;

      test.equal(reply, 13259);
      test.done();
    });
  });
};

return exports;<|endoftext|>


<commit_before>const utilities = require('../lib/utilities.js')
const rules = require('../lib/loading.js')

const TIMEZONE = utilities.getCurrentTimeZone()
const _ = require('lodash')
const logging = require('homeautomation-js-lib/logging.js')
const read_directory = require('read-directory')

console.log('Running in timezone: ' + TIMEZONE)

process.env.TEST_MODE = true
const testYAMLPath = process.env.TEST_YAML_PATH
const yaml = require('js-yaml')

require('../mqtt-rules.js')
const variables = require('../lib/variables.js')

var targetTestActions = null
var targetCallback = null
var targetEarliestDate = null
var targetStartDate = null

var clearState = function() {
	targetTestActions = null
	targetCallback = null
	targetEarliestDate = null
	targetStartDate = null
}

var setupTest = function(actions, callback, minimumTime) {
	clearState()

	targetTestActions = actions
	targetCallback = callback
	if ((minimumTime != null) && minimumTime > 0) {
		targetEarliestDate = new Date(new Date().getTime() + (minimumTime * 1000))
		targetStartDate = new Date().getTime()
		// console.log('minimum fire date: ' + targetEarliestDate)
	}
}

global.publish = function(rule_name, expression, valueOrExpression, topic, message, options) {
	if (topic.startsWith('happy')) {
		return
	}

	// console.log('incoming: ' + topic + ':' + message)

	if ( _.isNil(targetTestActions)) {
		logging.error('fail, I was not expecting anything and I got: ' + topic + ' message: ' + message)
		return
	}

	const targetTestMessage = targetTestActions[topic]

	if (!_.isNil(targetTestMessage) && message == targetTestMessage) {
		delete(targetTestActions[topic])
		// console.log('clearing: ' + topic)

		if (Object.keys(targetTestActions).length == 0) {
			// console.log('all clear!')

			if ((targetCallback != null)) {
				//  console.log('incoming: ' + topic + ' : ' + message + '   (time: ' + (new Date().getTime()) / 1000 + ')')
				var tooEarly = false
				var howEarly = 0
				var desiredMinimum = 0
				if (targetEarliestDate != null) {
					const now = new Date()
					// console.log('minimum fire date: ' + targetEarliestDate + '   now: ' + now)

					// Fudge half a second, as sometimes timers early fire a little bit...
					if (now + 0.5 < targetEarliestDate) {
						tooEarly = true
						howEarly = targetEarliestDate - now
						desiredMinimum = (targetEarliestDate - targetStartDate) / 1000
					}
				}
				var oldCallBack = targetCallback

				clearState()

				setTimeout(function cb() {
					if (tooEarly) {
						oldCallBack('test finished too early (' + howEarly + 's vs ' + desiredMinimum + 's)')
					} else {
						oldCallBack()
					}
				})
			}
		} else {
			// console.log('remaining: ' + Object.keys(targetTestActions))
		}
	} else {
		logging.error('fail, I got: ' + topic + ' message: ' + message)
	}
}

const msForProcessing = 15

const testProcessor = function(rule, rule_name, test, test_name) {
	var test_timeout = test.timeout
	const context = test.context
	const input = test.input
	const target = test.target

	if (_.isNil(test_timeout)) {
		test_timeout = msForProcessing
	} else {
		test_timeout = test_timeout + msForProcessing
	}

	const inputTopic = Object.keys(input)[0]
	const inputValue = input[inputTopic]

	var formattedRule = {}
	formattedRule[rule_name] = rule

	var allTopics = []

	if (!_.isNil(context)) {
		allTopics = allTopics.concat(Object.keys(context))
	}

	if (!_.isNil(inputTopic)) {
		allTopics.push(inputTopic)
	}

	it(test_name, function(done) {
		this.slow(Number(test_timeout * 2))
		this.timeout(Number(test_timeout * 3))

		variables.clearState()
		variables.updateObservedTopics(allTopics, function() {
			global.devices_to_monitor = allTopics

			if (!_.isNil(context)) {
				Object.keys(context).forEach(topic => {
					variables.update(topic, context[topic])
				})
			}

			global.clearRuleMapCache()

			rules.set_override_configs([formattedRule])
			setupTest(target, done)

			global.generateContext(inputTopic, inputValue, function(outTopic, outMessage, generatedContext) {
				global.changeProcessor(null, generatedContext, outTopic, outMessage)
			})
		})
	})
}

const processRuleFile = function(doc) {
	if (_.isNil(doc)) {
		return
	}

	Object.keys(doc).forEach(rule_name => {
		const rule = doc[rule_name]

		const test = rule.test
		const tests = rule.tests

		if (_.isNil(test) && _.isNil(tests)) {
			return
		}

		var testsToRun = {}

		if (!_.isNil(test)) {
			testsToRun[rule_name] = test
		}

		if (!_.isNil(tests)) {
			Object.keys(tests).forEach(innerTest => {
				const key = rule_name + '_' + innerTest
				testsToRun[key] = tests[innerTest]
			})
		}

		Object.keys(testsToRun).forEach(testName => {
			testProcessor(rule, rule_name, testsToRun[testName], testName)
		})

	})
}

describe('quick trigger tests', function() {
	before(function() {
		// runs before all tests in this block
		global.clearQueues()
	})

	var documents = []
	const yamlPath = !_.isNil(testYAMLPath) ? testYAMLPath : './test/yaml'
	const files = read_directory.sync(yamlPath, {})

	const fileNames = Object.keys(files)

	fileNames.forEach(file => {
		if (file.includes('._')) {
			return
		}

		if (file.includes('.yml') || file.includes('.yaml')) {
			const doc = yaml.safeLoad(files[file])

			documents.push(doc)
		}
	})

	documents.forEach(doc => {
		processRuleFile(doc)
	})

})
<commit_msg>Fixing unit tests<commit_after>const utilities = require('../lib/utilities.js')
const rules = require('../lib/loading.js')

const TIMEZONE = utilities.getCurrentTimeZone()
const _ = require('lodash')
const logging = require('homeautomation-js-lib/logging.js')
const read_directory = require('read-directory')

console.log('Running in timezone: ' + TIMEZONE)

process.env.TEST_MODE = true
const testYAMLPath = process.env.TEST_YAML_PATH
const yaml = require('js-yaml')

require('../mqtt-rules.js')
const variables = require('../lib/variables.js')

var targetTestActions = null
var targetCallback = null
var targetEarliestDate = null
var targetStartDate = null

var clearState = function() {
	targetTestActions = null
	targetCallback = null
	targetEarliestDate = null
	targetStartDate = null
}

var setupTest = function(actions, callback, minimumTime) {
	clearState()

	targetTestActions = actions
	targetCallback = callback
	if ((minimumTime != null) && minimumTime > 0) {
		targetEarliestDate = new Date(new Date().getTime() + (minimumTime * 1000))
		targetStartDate = new Date().getTime()
		// console.log('minimum fire date: ' + targetEarliestDate)
	}
}

global.publish = function(rule_name, expression, valueOrExpression, topic, message, options) {
	if (topic.startsWith('happy')) {
		return
	}

	// console.log('incoming: ' + topic + ':' + message)

	if ( _.isNil(targetTestActions)) {
		logging.error('fail, I was not expecting anything and I got: ' + topic + ' message: ' + message)
		return
	}

	const targetTestMessage = targetTestActions[topic]

	if (!_.isNil(targetTestMessage) && message == targetTestMessage) {
		delete(targetTestActions[topic])
		// console.log('clearing: ' + topic)

		if (Object.keys(targetTestActions).length == 0) {
			// console.log('all clear!')

			if ((targetCallback != null)) {
				//  console.log('incoming: ' + topic + ' : ' + message + '   (time: ' + (new Date().getTime()) / 1000 + ')')
				var tooEarly = false
				var howEarly = 0
				var desiredMinimum = 0
				if (targetEarliestDate != null) {
					const now = new Date()
					// console.log('minimum fire date: ' + targetEarliestDate + '   now: ' + now)

					// Fudge half a second, as sometimes timers early fire a little bit...
					if (now + 0.5 < targetEarliestDate) {
						tooEarly = true
						howEarly = targetEarliestDate - now
						desiredMinimum = (targetEarliestDate - targetStartDate) / 1000
					}
				}
				var oldCallBack = targetCallback

				clearState()

				setTimeout(function cb() {
					if (tooEarly) {
						oldCallBack('test finished too early (' + howEarly + 's vs ' + desiredMinimum + 's)')
					} else {
						oldCallBack()
					}
				})
			}
		} else {
			// console.log('remaining: ' + Object.keys(targetTestActions))
		}
	} else {
		logging.error('fail, I got: ' + topic + ' message: ' + message)
	}
}

const msForProcessing = 15

const testProcessor = function(rule, rule_name, test, test_name) {
	var test_timeout = test.timeout
	const context = test.context
	const input = test.input
	const target = test.target

	if (_.isNil(test_timeout)) {
		test_timeout = msForProcessing
	} else {
		test_timeout = test_timeout + msForProcessing
	}

	const inputTopic = Object.keys(input)[0]
	const inputValue = input[inputTopic]

	var formattedRule = {}
	formattedRule[rule_name] = rule

	var allTopics = []

	if (!_.isNil(context)) {
		allTopics = allTopics.concat(Object.keys(context))
	}

	if (!_.isNil(inputTopic)) {
		allTopics.push(inputTopic)
	}

	it(test_name, function(done) {
		this.slow(Number(test_timeout * 2))
		this.timeout(Number(test_timeout * 3))

		variables.clearState()
		variables.updateObservedTopics(allTopics, function() {
			global.devices_to_monitor = allTopics

			if (!_.isNil(context)) {
				Object.keys(context).forEach(topic => {
					variables.update(topic, context[topic])
				})
			}

			global.clearRuleMapCache()

			rules.set_override_configs([{test: formattedRule}])
			setupTest(target, done)

			global.generateContext(inputTopic, inputValue, function(outTopic, outMessage, generatedContext) {
				global.changeProcessor(null, generatedContext, outTopic, outMessage)
			})
		})
	})
}

const processRuleFile = function(doc) {
	if (_.isNil(doc)) {
		return
	}

	Object.keys(doc).forEach(rule_name => {
		const rule = doc[rule_name]

		const test = rule.test
		const tests = rule.tests

		if (_.isNil(test) && _.isNil(tests)) {
			return
		}

		var testsToRun = {}

		if (!_.isNil(test)) {
			testsToRun[rule_name] = test
		}

		if (!_.isNil(tests)) {
			Object.keys(tests).forEach(innerTest => {
				const key = rule_name + '_' + innerTest
				testsToRun[key] = tests[innerTest]
			})
		}

		Object.keys(testsToRun).forEach(testName => {
			testProcessor(rule, rule_name, testsToRun[testName], testName)
		})

	})
}

describe('quick trigger tests', function() {
	before(function() {
		// runs before all tests in this block
		global.clearQueues()
	})

	var documents = []
	const yamlPath = !_.isNil(testYAMLPath) ? testYAMLPath : './test/yaml'
	const files = read_directory.sync(yamlPath, {})

	const fileNames = Object.keys(files)

	fileNames.forEach(file => {
		if (file.includes('._')) {
			return
		}

		if (file.includes('.yml') || file.includes('.yaml')) {
			const doc = yaml.safeLoad(files[file])

			documents.push(doc)
		}
	})

	documents.forEach(doc => {
		processRuleFile(doc)
	})

})
<|endoftext|>


<commit_before>/* globals suite test */

var assert = require('assert')
var flat = require('../index')
var flatten = flat.flatten
var unflatten = flat.unflatten

var primitives = {
  String: 'good morning',
  Number: 1234.99,
  Boolean: true,
  Date: new Date(),
  null: null,
  undefined: undefined
}

suite('Flatten Primitives', function () {
  Object.keys(primitives).forEach(function (key) {
    var value = primitives[key]

    test(key, function () {
      assert.deepEqual(flatten({
        hello: {
          world: value
        }
      }), {
        'hello.world': value
      })
    })
  })
})

suite('Unflatten Primitives', function () {
  Object.keys(primitives).forEach(function (key) {
    var value = primitives[key]

    test(key, function () {
      assert.deepEqual(unflatten({
        'hello.world': value
      }), {
        hello: {
          world: value
        }
      })
    })
  })
})

suite('Flatten', function () {
  test('Nested once', function () {
    assert.deepEqual(flatten({
      hello: {
        world: 'good morning'
      }
    }), {
      'hello.world': 'good morning'
    })
  })

  test('Nested twice', function () {
    assert.deepEqual(flatten({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }), {
      'hello.world.again': 'good morning'
    })
  })

  test('Multiple Keys', function () {
    assert.deepEqual(flatten({
      hello: {
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      },
      world: {
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      }
    }), {
      'hello.lorem.ipsum': 'again',
      'hello.lorem.dolor': 'sit',
      'world.lorem.ipsum': 'again',
      'world.lorem.dolor': 'sit'
    })
  })

  test('Custom Delimiter', function () {
    assert.deepEqual(flatten({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }, {
      delimiter: ':'
    }), {
      'hello:world:again': 'good morning'
    })
  })

  test('Empty Objects', function () {
    assert.deepEqual(flatten({
      hello: {
        empty: {
          nested: { }
        }
      }
    }), {
      'hello.empty.nested': { }
    })
  })

  if (typeof Buffer !== 'undefined') {
    test('Buffer', function () {
      assert.deepEqual(flatten({
        hello: {
          empty: {
            nested: Buffer.from('test')
          }
        }
      }), {
        'hello.empty.nested': Buffer.from('test')
      })
    })
  }

  if (typeof Uint8Array !== 'undefined') {
    test('typed arrays', function () {
      assert.deepEqual(flatten({
        hello: {
          empty: {
            nested: new Uint8Array([1, 2, 3, 4])
          }
        }
      }), {
        'hello.empty.nested': new Uint8Array([1, 2, 3, 4])
      })
    })
  }

  test('Custom Depth', function () {
    assert.deepEqual(flatten({
      hello: {
        world: {
          again: 'good morning'
        }
      },
      lorem: {
        ipsum: {
          dolor: 'good evening'
        }
      }
    }, {
      maxDepth: 2
    }), {
      'hello.world': {
        again: 'good morning'
      },
      'lorem.ipsum': {
        dolor: 'good evening'
      }
    })
  })

  test('Should keep number in the left when object', function () {
    assert.deepEqual(flatten({
      hello: {
        '0200': 'world',
        '0500': 'darkness my old friend'
      }
    }), {
      'hello.0200': 'world',
      'hello.0500': 'darkness my old friend'
    })
  })
})

suite('Unflatten', function () {
  test('Nested once', function () {
    assert.deepEqual({
      hello: {
        world: 'good morning'
      }
    }, unflatten({
      'hello.world': 'good morning'
    }))
  })

  test('Nested twice', function () {
    assert.deepEqual({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }, unflatten({
      'hello.world.again': 'good morning'
    }))
  })

  test('Multiple Keys', function () {
    assert.deepEqual({
      hello: {
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      },
      world: {
        greet: 'hello',
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      }
    }, unflatten({
      'hello.lorem.ipsum': 'again',
      'hello.lorem.dolor': 'sit',
      'world.lorem.ipsum': 'again',
      'world.lorem.dolor': 'sit',
      'world': {greet: 'hello'}
    }))
  })

  test('Custom Delimiter', function () {
    assert.deepEqual({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }, unflatten({
      'hello world again': 'good morning'
    }, {
      delimiter: ' '
    }))
  })

  test('Overwrite', function () {
    assert.deepEqual({
      travis: {
        build: {
          dir: '/home/travis/build/kvz/environmental'
        }
      }
    }, unflatten({
      travis: 'true',
      travis_build_dir: '/home/travis/build/kvz/environmental'
    }, {
      delimiter: '_',
      overwrite: true
    }))
  })

  test('Messy', function () {
    assert.deepEqual({
      hello: { world: 'again' },
      lorem: { ipsum: 'another' },
      good: {
        morning: {
          hash: {
            key: { nested: {
              deep: { and: { even: {
                deeper: { still: 'hello' }
              } } }
            } }
          },
          again: { testing: { 'this': 'out' } }
        }
      }
    }, unflatten({
      'hello.world': 'again',
      'lorem.ipsum': 'another',
      'good.morning': {
        'hash.key': {
          'nested.deep': {
            'and.even.deeper.still': 'hello'
          }
        }
      },
      'good.morning.again': {
        'testing.this': 'out'
      }
    }))
  })

  suite('Overwrite + non-object values in key positions', function () {
    test('non-object keys + overwrite should be overwritten', function () {
      assert.deepEqual(flat.unflatten({ a: null, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: 0, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: 1, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: '', 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
    })

    test('overwrite value should not affect undefined keys', function () {
      assert.deepEqual(flat.unflatten({ a: undefined, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: undefined, 'a.b': 'c' }, {overwrite: false}), { a: { b: 'c' } })
    })

    test('if no overwrite, should ignore nested values under non-object key', function () {
      assert.deepEqual(flat.unflatten({ a: null, 'a.b': 'c' }), { a: null })
      assert.deepEqual(flat.unflatten({ a: 0, 'a.b': 'c' }), { a: 0 })
      assert.deepEqual(flat.unflatten({ a: 1, 'a.b': 'c' }), { a: 1 })
      assert.deepEqual(flat.unflatten({ a: '', 'a.b': 'c' }), { a: '' })
    })
  })

  suite('.safe', function () {
    test('Should protect arrays when true', function () {
      assert.deepEqual(flatten({
        hello: [
            { world: { again: 'foo' } },
           { lorem: 'ipsum' }
        ],
        another: {
          nested: [{ array: { too: 'deep' } }]
        },
        lorem: {
          ipsum: 'whoop'
        }
      }, {
        safe: true
      }), {
        hello: [
            { world: { again: 'foo' } },
           { lorem: 'ipsum' }
        ],
        'lorem.ipsum': 'whoop',
        'another.nested': [{ array: { too: 'deep' } }]
      })
    })

    test('Should not protect arrays when false', function () {
      assert.deepEqual(flatten({
        hello: [
            { world: { again: 'foo' } },
           { lorem: 'ipsum' }
        ]
      }, {
        safe: false
      }), {
        'hello.0.world.again': 'foo',
        'hello.1.lorem': 'ipsum'
      })
    })
  })

  suite('.object', function () {
    test('Should create object instead of array when true', function () {
      var unflattened = unflatten({
        'hello.you.0': 'ipsum',
        'hello.you.1': 'lorem',
        'hello.other.world': 'foo'
      }, {
        object: true
      })
      assert.deepEqual({
        hello: {
          you: {
            0: 'ipsum',
            1: 'lorem'
          },
          other: { world: 'foo' }
        }
      }, unflattened)
      assert(!Array.isArray(unflattened.hello.you))
    })

    test('Should create object instead of array when nested', function () {
      var unflattened = unflatten({
        'hello': {
          'you.0': 'ipsum',
          'you.1': 'lorem',
          'other.world': 'foo'
        }
      }, {
        object: true
      })
      assert.deepEqual({
        hello: {
          you: {
            0: 'ipsum',
            1: 'lorem'
          },
          other: { world: 'foo' }
        }
      }, unflattened)
      assert(!Array.isArray(unflattened.hello.you))
    })

    test('Should keep the zero in the left when object is true', function () {
      var unflattened = unflatten({
        'hello.0200': 'world',
        'hello.0500': 'darkness my old friend'
      }, {
        object: true
      })

      assert.deepEqual({
        hello: {
          '0200': 'world',
          '0500': 'darkness my old friend'
        }
      }, unflattened)
    })

    test('Should not create object when false', function () {
      var unflattened = unflatten({
        'hello.you.0': 'ipsum',
        'hello.you.1': 'lorem',
        'hello.other.world': 'foo'
      }, {
        object: false
      })
      assert.deepEqual({
        hello: {
          you: ['ipsum', 'lorem'],
          other: { world: 'foo' }
        }
      }, unflattened)
      assert(Array.isArray(unflattened.hello.you))
    })
  })

  if (typeof Buffer !== 'undefined') {
    test('Buffer', function () {
      assert.deepEqual(unflatten({
        'hello.empty.nested': Buffer.from('test')
      }), {
        hello: {
          empty: {
            nested: Buffer.from('test')
          }
        }
      })
    })
  }

  if (typeof Uint8Array !== 'undefined') {
    test('typed arrays', function () {
      assert.deepEqual(unflatten({
        'hello.empty.nested': new Uint8Array([1, 2, 3, 4])
      }), {
        hello: {
          empty: {
            nested: new Uint8Array([1, 2, 3, 4])
          }
        }
      })
    })
  }
})

suite('Arrays', function () {
  test('Should be able to flatten arrays properly', function () {
    assert.deepEqual({
      'a.0': 'foo',
      'a.1': 'bar'
    }, flatten({
      a: ['foo', 'bar']
    }))
  })

  test('Should be able to revert and reverse array serialization via unflatten', function () {
    assert.deepEqual({
      a: ['foo', 'bar']
    }, unflatten({
      'a.0': 'foo',
      'a.1': 'bar'
    }))
  })

  test('Array typed objects should be restored by unflatten', function () {
    assert.equal(
        Object.prototype.toString.call(['foo', 'bar'])
      , Object.prototype.toString.call(unflatten({
        'a.0': 'foo',
        'a.1': 'bar'
      }).a)
    )
  })

  test('Do not include keys with numbers inside them', function () {
    assert.deepEqual(unflatten({
      '1key.2_key': 'ok'
    }), {
      '1key': {
        '2_key': 'ok'
      }
    })
  })
})
<commit_msg>Add explicit test for sorted keys.<commit_after>/* globals suite test */

var assert = require('assert')
var flat = require('../index')
var flatten = flat.flatten
var unflatten = flat.unflatten

var primitives = {
  String: 'good morning',
  Number: 1234.99,
  Boolean: true,
  Date: new Date(),
  null: null,
  undefined: undefined
}

suite('Flatten Primitives', function () {
  Object.keys(primitives).forEach(function (key) {
    var value = primitives[key]

    test(key, function () {
      assert.deepEqual(flatten({
        hello: {
          world: value
        }
      }), {
        'hello.world': value
      })
    })
  })
})

suite('Unflatten Primitives', function () {
  Object.keys(primitives).forEach(function (key) {
    var value = primitives[key]

    test(key, function () {
      assert.deepEqual(unflatten({
        'hello.world': value
      }), {
        hello: {
          world: value
        }
      })
    })
  })
})

suite('Flatten', function () {
  test('Nested once', function () {
    assert.deepEqual(flatten({
      hello: {
        world: 'good morning'
      }
    }), {
      'hello.world': 'good morning'
    })
  })

  test('Nested twice', function () {
    assert.deepEqual(flatten({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }), {
      'hello.world.again': 'good morning'
    })
  })

  test('Multiple Keys', function () {
    assert.deepEqual(flatten({
      hello: {
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      },
      world: {
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      }
    }), {
      'hello.lorem.ipsum': 'again',
      'hello.lorem.dolor': 'sit',
      'world.lorem.ipsum': 'again',
      'world.lorem.dolor': 'sit'
    })
  })

  test('Custom Delimiter', function () {
    assert.deepEqual(flatten({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }, {
      delimiter: ':'
    }), {
      'hello:world:again': 'good morning'
    })
  })

  test('Empty Objects', function () {
    assert.deepEqual(flatten({
      hello: {
        empty: {
          nested: { }
        }
      }
    }), {
      'hello.empty.nested': { }
    })
  })

  if (typeof Buffer !== 'undefined') {
    test('Buffer', function () {
      assert.deepEqual(flatten({
        hello: {
          empty: {
            nested: Buffer.from('test')
          }
        }
      }), {
        'hello.empty.nested': Buffer.from('test')
      })
    })
  }

  if (typeof Uint8Array !== 'undefined') {
    test('typed arrays', function () {
      assert.deepEqual(flatten({
        hello: {
          empty: {
            nested: new Uint8Array([1, 2, 3, 4])
          }
        }
      }), {
        'hello.empty.nested': new Uint8Array([1, 2, 3, 4])
      })
    })
  }

  test('Custom Depth', function () {
    assert.deepEqual(flatten({
      hello: {
        world: {
          again: 'good morning'
        }
      },
      lorem: {
        ipsum: {
          dolor: 'good evening'
        }
      }
    }, {
      maxDepth: 2
    }), {
      'hello.world': {
        again: 'good morning'
      },
      'lorem.ipsum': {
        dolor: 'good evening'
      }
    })
  })

  test('Should keep number in the left when object', function () {
    assert.deepEqual(flatten({
      hello: {
        '0200': 'world',
        '0500': 'darkness my old friend'
      }
    }), {
      'hello.0200': 'world',
      'hello.0500': 'darkness my old friend'
    })
  })
})

suite('Unflatten', function () {
  test('Nested once', function () {
    assert.deepEqual({
      hello: {
        world: 'good morning'
      }
    }, unflatten({
      'hello.world': 'good morning'
    }))
  })

  test('Nested twice', function () {
    assert.deepEqual({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }, unflatten({
      'hello.world.again': 'good morning'
    }))
  })

  test('Multiple Keys', function () {
    assert.deepEqual({
      hello: {
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      },
      world: {
        greet: 'hello',
        lorem: {
          ipsum: 'again',
          dolor: 'sit'
        }
      }
    }, unflatten({
      'hello.lorem.ipsum': 'again',
      'hello.lorem.dolor': 'sit',
      'world.lorem.ipsum': 'again',
      'world.lorem.dolor': 'sit',
      'world': {greet: 'hello'}
    }))
  })

  test('nested objects do not clobber each other when a.b inserted before a', function () {
    var x = {}
    x['foo.bar'] = {t: 123}
    x['foo'] = {p: 333}
    assert.deepEqual(unflatten(x), {
      foo: {
        bar: {
          t: 123
        },
        p: 333
      }
    })
  })

  test('Custom Delimiter', function () {
    assert.deepEqual({
      hello: {
        world: {
          again: 'good morning'
        }
      }
    }, unflatten({
      'hello world again': 'good morning'
    }, {
      delimiter: ' '
    }))
  })

  test('Overwrite', function () {
    assert.deepEqual({
      travis: {
        build: {
          dir: '/home/travis/build/kvz/environmental'
        }
      }
    }, unflatten({
      travis: 'true',
      travis_build_dir: '/home/travis/build/kvz/environmental'
    }, {
      delimiter: '_',
      overwrite: true
    }))
  })

  test('Messy', function () {
    assert.deepEqual({
      hello: { world: 'again' },
      lorem: { ipsum: 'another' },
      good: {
        morning: {
          hash: {
            key: { nested: {
              deep: { and: { even: {
                deeper: { still: 'hello' }
              } } }
            } }
          },
          again: { testing: { 'this': 'out' } }
        }
      }
    }, unflatten({
      'hello.world': 'again',
      'lorem.ipsum': 'another',
      'good.morning': {
        'hash.key': {
          'nested.deep': {
            'and.even.deeper.still': 'hello'
          }
        }
      },
      'good.morning.again': {
        'testing.this': 'out'
      }
    }))
  })

  suite('Overwrite + non-object values in key positions', function () {
    test('non-object keys + overwrite should be overwritten', function () {
      assert.deepEqual(flat.unflatten({ a: null, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: 0, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: 1, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: '', 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
    })

    test('overwrite value should not affect undefined keys', function () {
      assert.deepEqual(flat.unflatten({ a: undefined, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } })
      assert.deepEqual(flat.unflatten({ a: undefined, 'a.b': 'c' }, {overwrite: false}), { a: { b: 'c' } })
    })

    test('if no overwrite, should ignore nested values under non-object key', function () {
      assert.deepEqual(flat.unflatten({ a: null, 'a.b': 'c' }), { a: null })
      assert.deepEqual(flat.unflatten({ a: 0, 'a.b': 'c' }), { a: 0 })
      assert.deepEqual(flat.unflatten({ a: 1, 'a.b': 'c' }), { a: 1 })
      assert.deepEqual(flat.unflatten({ a: '', 'a.b': 'c' }), { a: '' })
    })
  })

  suite('.safe', function () {
    test('Should protect arrays when true', function () {
      assert.deepEqual(flatten({
        hello: [
            { world: { again: 'foo' } },
           { lorem: 'ipsum' }
        ],
        another: {
          nested: [{ array: { too: 'deep' } }]
        },
        lorem: {
          ipsum: 'whoop'
        }
      }, {
        safe: true
      }), {
        hello: [
            { world: { again: 'foo' } },
           { lorem: 'ipsum' }
        ],
        'lorem.ipsum': 'whoop',
        'another.nested': [{ array: { too: 'deep' } }]
      })
    })

    test('Should not protect arrays when false', function () {
      assert.deepEqual(flatten({
        hello: [
            { world: { again: 'foo' } },
           { lorem: 'ipsum' }
        ]
      }, {
        safe: false
      }), {
        'hello.0.world.again': 'foo',
        'hello.1.lorem': 'ipsum'
      })
    })
  })

  suite('.object', function () {
    test('Should create object instead of array when true', function () {
      var unflattened = unflatten({
        'hello.you.0': 'ipsum',
        'hello.you.1': 'lorem',
        'hello.other.world': 'foo'
      }, {
        object: true
      })
      assert.deepEqual({
        hello: {
          you: {
            0: 'ipsum',
            1: 'lorem'
          },
          other: { world: 'foo' }
        }
      }, unflattened)
      assert(!Array.isArray(unflattened.hello.you))
    })

    test('Should create object instead of array when nested', function () {
      var unflattened = unflatten({
        'hello': {
          'you.0': 'ipsum',
          'you.1': 'lorem',
          'other.world': 'foo'
        }
      }, {
        object: true
      })
      assert.deepEqual({
        hello: {
          you: {
            0: 'ipsum',
            1: 'lorem'
          },
          other: { world: 'foo' }
        }
      }, unflattened)
      assert(!Array.isArray(unflattened.hello.you))
    })

    test('Should keep the zero in the left when object is true', function () {
      var unflattened = unflatten({
        'hello.0200': 'world',
        'hello.0500': 'darkness my old friend'
      }, {
        object: true
      })

      assert.deepEqual({
        hello: {
          '0200': 'world',
          '0500': 'darkness my old friend'
        }
      }, unflattened)
    })

    test('Should not create object when false', function () {
      var unflattened = unflatten({
        'hello.you.0': 'ipsum',
        'hello.you.1': 'lorem',
        'hello.other.world': 'foo'
      }, {
        object: false
      })
      assert.deepEqual({
        hello: {
          you: ['ipsum', 'lorem'],
          other: { world: 'foo' }
        }
      }, unflattened)
      assert(Array.isArray(unflattened.hello.you))
    })
  })

  if (typeof Buffer !== 'undefined') {
    test('Buffer', function () {
      assert.deepEqual(unflatten({
        'hello.empty.nested': Buffer.from('test')
      }), {
        hello: {
          empty: {
            nested: Buffer.from('test')
          }
        }
      })
    })
  }

  if (typeof Uint8Array !== 'undefined') {
    test('typed arrays', function () {
      assert.deepEqual(unflatten({
        'hello.empty.nested': new Uint8Array([1, 2, 3, 4])
      }), {
        hello: {
          empty: {
            nested: new Uint8Array([1, 2, 3, 4])
          }
        }
      })
    })
  }
})

suite('Arrays', function () {
  test('Should be able to flatten arrays properly', function () {
    assert.deepEqual({
      'a.0': 'foo',
      'a.1': 'bar'
    }, flatten({
      a: ['foo', 'bar']
    }))
  })

  test('Should be able to revert and reverse array serialization via unflatten', function () {
    assert.deepEqual({
      a: ['foo', 'bar']
    }, unflatten({
      'a.0': 'foo',
      'a.1': 'bar'
    }))
  })

  test('Array typed objects should be restored by unflatten', function () {
    assert.equal(
        Object.prototype.toString.call(['foo', 'bar'])
      , Object.prototype.toString.call(unflatten({
        'a.0': 'foo',
        'a.1': 'bar'
      }).a)
    )
  })

  test('Do not include keys with numbers inside them', function () {
    assert.deepEqual(unflatten({
      '1key.2_key': 'ok'
    }), {
      '1key': {
        '2_key': 'ok'
      }
    })
  })
})
<|endoftext|>


<commit_before>/* global describe, it, before */
const path = require('path');
const should = require('should');
const session = require('express-session');
const FirebaseStore = require(path.normalize(`${__dirname}/../lib/connect-session-firebase.js`))(session);

require('dotenv').config({ silent: true });

const store = new FirebaseStore({
  database: {
    serviceAccount: process.env.FIREBASE_SERVICE_ACCOUNT,
    databaseURL: process.env.FIREBASE_DATABASE_URL
  }
});

describe('FirebaseStore', function () {
  this.timeout(10000);

  describe('Instantiation', () => {
    it('should be able to be created', () => {
      store.should.be.an.instanceOf(FirebaseStore);
    });
  });

  describe('Setting', () => {
    it('should set data correctly', done => {
      store.set('1234_#$[]', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, (err, res) => {
        if (err) throw err;

        done();
      });
    });
  });

  describe('Getting', () => {
    before(() => {
      store.set('1234', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});
    });

    it('should get data correctly', done => {
      store.get('1234', (err, res) => {
        if (err) throw err;

        res.name.should.eql('tj');
        res.cookie.should.eql({
          maxAge: 2000
        });

        done();
      });
    });
  });

  describe('Destroying', () => {
    before(() => {
      store.set('12345', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});
    });

    it('should destroy data correctly', done => {
      store.destroy('12345', (err, res) => {
        if (err) throw err;

        store.get('12345', (err, res) => {
          if (err) throw err;

          should.not.exist(res);

          done();
        });
      });
    });
  });

  describe('Clearing', () => {
    before(() => {
      store.set('abcd', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});

      store.set('abcdef', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});
    });

    it('should clear sessions correctly', done => {
      store.clear((err, res) => {
        if (err) throw err;

        store.get('abcd', (err, res) => {
          if (err) throw err;

          should.not.exist(res);

          store.get('abcdef', (err, res) => {
            if (err) throw err;

            should.not.exist(res);

            done();
          });
        });
      });
    });
  });

  describe('Reaping', () => {
    before(done => {
      store.set('abcd', {
        name: 'tj',
        cookie: {
          maxAge: -2000
        }
      }, done);
    });

    it('should reap data correctly', done => {
      store.reap((err, res) => {
        if (err) throw err;

        store.get('abcd', (err, res) => {
          if (err) throw err;

          should.not.exist(res);

          done();
        });
      });
    });
  });

  describe('Touching', () => {
    before(done => {
      store.set('abcd', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, done);
    });

    it('should touch data correctly', done => {
      store.touch('abcd', {
        name: 'bn',
        cookie: {
          maxAge: 3000
        }
      }, function (err) {
        if (err) throw err;

        store.get('abcd', (err, res) => {
          if (err) throw err;

          res.name.should.eql('tj');
          res.cookie.should.eql({
            maxAge: 3000
          });

          done();
        });
      });
    });
  });
});
<commit_msg>Use file or env var to allow different test environments<commit_after>/* global describe, it, before */
const fs = require('fs');
const path = require('path');
const should = require('should');
const session = require('express-session');
const FirebaseStore = require(path.normalize(`${__dirname}/../lib/connect-session-firebase.js`))(session);

require('dotenv').config({ silent: true });

const fileExists = function fileExists (path) {
  try {
    fs.statSync(path);
    return true;
  }
  catch (e) {
    return false;
  }
};

const serviceAccountCredentials = (fileExists(process.env.FIREBASE_SERVICE_ACCOUNT)) ? process.env.FIREBASE_SERVICE_ACCOUNT : JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);

const store = new FirebaseStore({
  database: {
    serviceAccount: serviceAccountCredentials,
    databaseURL: process.env.FIREBASE_DATABASE_URL
  }
});

describe('FirebaseStore', function () {
  this.timeout(10000);

  describe('Instantiation', () => {
    it('should be able to be created', () => {
      store.should.be.an.instanceOf(FirebaseStore);
    });
  });

  describe('Setting', () => {
    it('should set data correctly', done => {
      store.set('1234_#$[]', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, (err, res) => {
        if (err) throw err;

        done();
      });
    });
  });

  describe('Getting', () => {
    before(() => {
      store.set('1234', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});
    });

    it('should get data correctly', done => {
      store.get('1234', (err, res) => {
        if (err) throw err;

        res.name.should.eql('tj');
        res.cookie.should.eql({
          maxAge: 2000
        });

        done();
      });
    });
  });

  describe('Destroying', () => {
    before(() => {
      store.set('12345', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});
    });

    it('should destroy data correctly', done => {
      store.destroy('12345', (err, res) => {
        if (err) throw err;

        store.get('12345', (err, res) => {
          if (err) throw err;

          should.not.exist(res);

          done();
        });
      });
    });
  });

  describe('Clearing', () => {
    before(() => {
      store.set('abcd', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});

      store.set('abcdef', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, () => {});
    });

    it('should clear sessions correctly', done => {
      store.clear((err, res) => {
        if (err) throw err;

        store.get('abcd', (err, res) => {
          if (err) throw err;

          should.not.exist(res);

          store.get('abcdef', (err, res) => {
            if (err) throw err;

            should.not.exist(res);

            done();
          });
        });
      });
    });
  });

  describe('Reaping', () => {
    before(done => {
      store.set('abcd', {
        name: 'tj',
        cookie: {
          maxAge: -2000
        }
      }, done);
    });

    it('should reap data correctly', done => {
      store.reap((err, res) => {
        if (err) throw err;

        store.get('abcd', (err, res) => {
          if (err) throw err;

          should.not.exist(res);

          done();
        });
      });
    });
  });

  describe('Touching', () => {
    before(done => {
      store.set('abcd', {
        name: 'tj',
        cookie: {
          maxAge: 2000
        }
      }, done);
    });

    it('should touch data correctly', done => {
      store.touch('abcd', {
        name: 'bn',
        cookie: {
          maxAge: 3000
        }
      }, function (err) {
        if (err) throw err;

        store.get('abcd', (err, res) => {
          if (err) throw err;

          res.name.should.eql('tj');
          res.cookie.should.eql({
            maxAge: 3000
          });

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


<commit_before>/**
 * Based on the Shunting-yard algorithm.
 */

import List from './list';
let { last } = List();

const default_context = {
  'π': Math.PI,
  '∏': Math.PI
}

export default function(input, context) {
  const expr = infix_to_postfix(input);
  return calc(expr, Object.assign(default_context, context));
}

const operator = {
  '*': 3, '/': 3, '%': 3,
  '+': 2, '-': 2,
  '(': 1, ')': 1
}

function calc(expr, context, repeat = []) {
  let stack = [];
  while (expr.length) {
    let { name, value, type } = expr.shift();
    if (type === 'variable') {
      let result = context[value];
      if (typeof result === 'undefined') {
        result = Math[value];
      }
      if (typeof result === 'undefined') {
        result = expand(value, context);
      }
      if (typeof result === 'undefined') {
        result = 0;
      }
      if (typeof result !== 'number') {
        repeat.push(result);
        if (is_cycle(repeat)) {
          result = 0;
          repeat = [];
        } else {
          result = calc(infix_to_postfix(result), context, repeat)
        }
      }
      stack.push(result);
    }
    else if (type === 'function') {
      let args = value.map(v => calc(v, context));
      let fn = context[name] || Math[name];
      if (typeof fn === 'function') {
        stack.push(fn(...args));
      } else {
        stack.push(0);
      }
    } else {
      if (/\d+/.test(value)) stack.push(value);
      else {
        let right = stack.pop();
        let left = stack.pop();
        stack.push(compute(
          value, Number(left), Number(right)
        ));
      }
    }
  }
  return stack[0];
}

function get_tokens(input) {
  let expr = String(input);
  let tokens = [], num = '';

  for (let i = 0; i < expr.length; ++i) {
    let c = expr[i];
    if (operator[c]) {
      if (c == '-' && expr[i - 1] == 'e') {
        num += c;
      }
      else if (!tokens.length && !num.length && /[+-]/.test(c)) {
        num += c;
      } else {
        let { type, value } = last(tokens) || {};
        if (type == 'operator'
            && !num.length
            && /[^()]/.test(c)
            && /[^()]/.test(value)) {
          num += c;
        } else {
          if (num.length) {
            tokens.push({ type: 'number', value: num });
            num = '';
          }
          tokens.push({ type: 'operator', value: c });
        }
      }
    }
    else if (/\S/.test(c)) {
      if (c == ',') {
        tokens.push({ type: 'number', value: num });
        num = '';
        tokens.push({ type: 'comma', value: c });
      } else {
        num += c;
      }
    }
  }

  if (num.length) {
    tokens.push({ type: 'number', value: num });
  }
  return tokens;
}

function infix_to_postfix(input) {
  let tokens = get_tokens(input);
  const op_stack = [], expr = [];

  for (let i = 0; i < tokens.length; ++i) {
    let { type, value } = tokens[i];
    let next = tokens[i + 1] || {};
    if (type == 'number') {
      if (next.value == '(' && /[^\d.]/.test(value)) {
        let func_body = '';
        let stack = [];
        let values = [];

        i += 1;
        while (tokens[i++] !== undefined) {
          let token = tokens[i];
          if (token === undefined) break;
          let c = token.value;
          if (c == ')') {
            if (!stack.length) break;
            stack.pop();
            func_body += c;
          }
          else {
            if (c == '(') stack.push(c);
            if (c == ',') {
              let arg = infix_to_postfix(func_body);
              if (arg.length) values.push(arg);
              func_body = '';
            } else {
              func_body += c
            }
          }
        }

        if (func_body.length) {
          values.push(infix_to_postfix(func_body));
        }

        expr.push({
          type: 'function',
          name: value,
          value: values
        });
      }
      else if (/[^\d.]/.test(value)) {
        expr.push({ type: 'variable', value });
      }
      else {
        expr.push({ type: 'number', value });
      }
    }

    else if (type == 'operator') {
      if (value == '(') {
        op_stack.push(value);
      }

      else if (value == ')') {
        while (op_stack.length && last(op_stack) != '(') {
          expr.push({ type: 'operator', value: op_stack.pop() });
        }
        op_stack.pop();
      }

      else {
        while (op_stack.length && operator[last(op_stack)] >= operator[value]) {
          let op = op_stack.pop();
          if (!/[()]/.test(op)) expr.push({ type: 'operator', value: op });
        }
        op_stack.push(value);
      }
    }
  }

  while (op_stack.length) {
    expr.push({ type: 'operator', value: op_stack.pop() });
  }

  return expr;
}

function compute(op, a, b) {
  switch (op) {
    case '+': return a + b;
    case '-': return a - b;
    case '*': return a * b;
    case '/': return a / b;
    case '%': return a % b;
  }
}

function expand(value, context) {
  let [_, num, variable] = value.match(/([\d.]+)(.*)/) || [];
  let v = context[variable];
  if (v === undefined) {
    return v;
  }
  if (typeof v === 'number') {
    return Number(num) * v;
  } else {
    return num * calc(infix_to_postfix(v), context);
  }
}

function is_cycle(array) {
  return (array[0] == array[2] && array[1] == array[3]);
}
<commit_msg>Support exponent operator<commit_after>/**
 * Based on the Shunting-yard algorithm.
 */

import List from './list';
let { last } = List();

const default_context = {
  'π': Math.PI,
  '∏': Math.PI
}

export default function(input, context) {
  const expr = infix_to_postfix(input);
  return calc(expr, Object.assign(default_context, context));
}

const operator = {
  '*': 3, '/': 3, '%': 3, '^' : 3,
  '+': 2, '-': 2,
  '(': 1, ')': 1
}

function calc(expr, context, repeat = []) {
  let stack = [];
  while (expr.length) {
    let { name, value, type } = expr.shift();
    if (type === 'variable') {
      let result = context[value];
      if (typeof result === 'undefined') {
        result = Math[value];
      }
      if (typeof result === 'undefined') {
        result = expand(value, context);
      }
      if (typeof result === 'undefined') {
        result = 0;
      }
      if (typeof result !== 'number') {
        repeat.push(result);
        if (is_cycle(repeat)) {
          result = 0;
          repeat = [];
        } else {
          result = calc(infix_to_postfix(result), context, repeat)
        }
      }
      stack.push(result);
    }
    else if (type === 'function') {
      let args = value.map(v => calc(v, context));
      let fn = context[name] || Math[name];
      if (typeof fn === 'function') {
        stack.push(fn(...args));
      } else {
        stack.push(0);
      }
    } else {
      if (/\d+/.test(value)) stack.push(value);
      else {
        let right = stack.pop();
        let left = stack.pop();
        stack.push(compute(
          value, Number(left), Number(right)
        ));
      }
    }
  }
  return stack[0];
}

function get_tokens(input) {
  let expr = String(input);
  let tokens = [], num = '';

  for (let i = 0; i < expr.length; ++i) {
    let c = expr[i];
    if (operator[c]) {
      if (c == '-' && expr[i - 1] == 'e') {
        num += c;
      }
      else if (!tokens.length && !num.length && /[+-]/.test(c)) {
        num += c;
      } else {
        let { type, value } = last(tokens) || {};
        if (type == 'operator'
            && !num.length
            && /[^()]/.test(c)
            && /[^()]/.test(value)) {
          num += c;
        } else {
          if (num.length) {
            tokens.push({ type: 'number', value: num });
            num = '';
          }
          tokens.push({ type: 'operator', value: c });
        }
      }
    }
    else if (/\S/.test(c)) {
      if (c == ',') {
        tokens.push({ type: 'number', value: num });
        num = '';
        tokens.push({ type: 'comma', value: c });
      } else {
        num += c;
      }
    }
  }

  if (num.length) {
    tokens.push({ type: 'number', value: num });
  }
  return tokens;
}

function infix_to_postfix(input) {
  let tokens = get_tokens(input);
  const op_stack = [], expr = [];

  for (let i = 0; i < tokens.length; ++i) {
    let { type, value } = tokens[i];
    let next = tokens[i + 1] || {};
    if (type == 'number') {
      if (next.value == '(' && /[^\d.]/.test(value)) {
        let func_body = '';
        let stack = [];
        let values = [];

        i += 1;
        while (tokens[i++] !== undefined) {
          let token = tokens[i];
          if (token === undefined) break;
          let c = token.value;
          if (c == ')') {
            if (!stack.length) break;
            stack.pop();
            func_body += c;
          }
          else {
            if (c == '(') stack.push(c);
            if (c == ',') {
              let arg = infix_to_postfix(func_body);
              if (arg.length) values.push(arg);
              func_body = '';
            } else {
              func_body += c
            }
          }
        }

        if (func_body.length) {
          values.push(infix_to_postfix(func_body));
        }

        expr.push({
          type: 'function',
          name: value,
          value: values
        });
      }
      else if (/[^\d.]/.test(value)) {
        expr.push({ type: 'variable', value });
      }
      else {
        expr.push({ type: 'number', value });
      }
    }

    else if (type == 'operator') {
      if (value == '(') {
        op_stack.push(value);
      }

      else if (value == ')') {
        while (op_stack.length && last(op_stack) != '(') {
          expr.push({ type: 'operator', value: op_stack.pop() });
        }
        op_stack.pop();
      }

      else {
        while (op_stack.length && operator[last(op_stack)] >= operator[value]) {
          let op = op_stack.pop();
          if (!/[()]/.test(op)) expr.push({ type: 'operator', value: op });
        }
        op_stack.push(value);
      }
    }
  }

  while (op_stack.length) {
    expr.push({ type: 'operator', value: op_stack.pop() });
  }

  return expr;
}

function compute(op, a, b) {
  switch (op) {
    case '+': return a + b;
    case '-': return a - b;
    case '*': return a * b;
    case '/': return a / b;
    case '%': return a % b;
    case '^': return Math.pow(a, b);
  }
}

function expand(value, context) {
  let [_, num, variable] = value.match(/([\d.]+)(.*)/) || [];
  let v = context[variable];
  if (v === undefined) {
    return v;
  }
  if (typeof v === 'number') {
    return Number(num) * v;
  } else {
    return num * calc(infix_to_postfix(v), context);
  }
}

function is_cycle(array) {
  return (array[0] == array[2] && array[1] == array[3]);
}
<|endoftext|>


<commit_before>var flic = require("../");
var Bridge = flic.bridge;
var Node = flic.node;

var test_bridge;

exports["Bridge construct - nominal"] = function(test){
  test.expect(2);
  test_bridge = new Bridge();
  test.ok(test_bridge instanceof Bridge);
  test.strictEqual(test_bridge.port, 8221);
  test.done();
}

exports["Bridge construct - invalid port number (too low)"] = function(test){
  test.expect(1);
  test.throws(function(){
    var a = new Bridge(1);
  });
  test.done();
}

exports["Bridge construct - invalid port number (too high)"] = function(test){
  test.expect(1);
  test.throws(function(){
    var a = new Bridge(85668);
  });
  test.done();
}

exports["Node construct - nominal"] = function(test){
  test.expect(1);
  var node = new Node("node", function(err){
    test.equal(err, null, "Callback returned an unexpected error.");
    test.done();
  });
}

exports["Node construct - name taken"] = function(test){
  test.expect(1);
  var node = new Node("node", function(err){
    test.equal(err, "Error: Duplicate node name!", "Callback returned a different error than anticipated: '%s'", err);
    test.done();
  });
}

exports["Node construct - invalid name"] = function(test){
  test.expect(1);
  test.throws(function(){
    var node = new Node("&*@dddd", function(){});
  });
  test.done();
}

exports["Node construct - no bridge present"] = function(test){
  test.expect(1);
  var node = new Node("no_bridge", 9887, function(err){
    test.equal(err, "Error: Node could not connect to Bridge!", "Callback returned a different error than anticipated: '%s'", err);
    test.done();
  });
}

var node1, node2;

exports["Node tell - nominal (receiving events)"] = function(test){
  test.expect(1);
  node2 = new Node("node2", function(){});
  node1 = new Node("node1", function(){});
  node1.on("test_event", function(param1){
    test.equal(param1, "testParam", "param1 is not right: %s", param1);
    test.done();
  });

  setTimeout(function() {
    node2.tell("node1:test_event", "testParam");
  }, 25);
}

exports["Node tell - nominal (receiving events and sending callbacks)"] = function(test){
  test.expect(2);
  node1.on("test_event2", function(param1, callback){
    test.equal(param1, "testParam", "param1 is not right: %s", param1);
    callback(null, param1);
  });

  setTimeout(function() {
    node2.tell("node1:test_event2", "testParam", function(err, param2){
      test.equal(param2, "testParam", "param2 is not right: %s", param2);
      test.done();
    });
  }, 25);
}

exports["Node tell - non-existent node"] = function(test){
  test.expect(1);
  node2.tell("i_dont_exist:who_cares", function(err){
    test.equal(err, "Error: Attempting to tell non-existent node!", "Callback returned a different error than anticipated: '%s'", err);
    test.done();
  });
};

exports["Node shout - nominal"] = function(test){
  test.expect(1);
  node1.on("shout1", function(param1){
    test.equal(param1, "ilovenodejs", "Shout recipients received an unexpected value from the shouter: %s", param1);
    test.done();
  });
  node2.shout("shout1", "ilovenodejs");
}

exports["Bridge close"] = function(test){
  test.expect(1);
  node1.on("$CLOSE", function(param1){
    test.equal(param1, "ilovenodejs", "Bridge close event recipients received an unexpected value from the shouter: %s", param1);
    test.done();
  });
  test_bridge.close(["ilovenodejs"]);
}
<commit_msg>new test<commit_after>var flic = require("../");
var Bridge = flic.bridge;
var Node = flic.node;

var test_bridge;

exports["Bridge construct - nominal"] = function(test){
  test.expect(2);
  test_bridge = new Bridge();
  test.ok(test_bridge instanceof Bridge);
  test.strictEqual(test_bridge.port, 8221);
  test.done();
}

exports["Bridge construct - invalid port number (too low)"] = function(test){
  test.expect(1);
  test.throws(function(){
    var a = new Bridge(1);
  });
  test.done();
}

exports["Bridge construct - invalid port number (too high)"] = function(test){
  test.expect(1);
  test.throws(function(){
    var a = new Bridge(85668);
  });
  test.done();
}

exports["Node construct - nominal"] = function(test){
  test.expect(1);
  var node = new Node("node", function(err){
    test.equal(err, null, "Callback returned an unexpected error.");
    test.done();
  });
}

exports["Node construct - name taken"] = function(test){
  test.expect(1);
  var node = new Node("node", function(err){
    test.equal(err, "Error: Duplicate node name!", "Callback returned a different error than anticipated: '%s'", err);
    test.done();
  });
}

exports["Node construct - invalid name"] = function(test){
  test.expect(1);
  test.throws(function(){
    var node = new Node("&*@dddd", function(){});
  });
  test.done();
}

exports["Node construct - no bridge present"] = function(test){
  test.expect(1);
  var node = new Node("no_bridge", 9887, function(err){
    test.equal(err, "Error: Node could not connect to Bridge!", "Callback returned a different error than anticipated: '%s'", err);
    test.done();
  });
}

var node1, node2;

exports["Node tell - nominal (receiving events)"] = function(test){
  test.expect(1);
  node2 = new Node("node2", function(){});
  node1 = new Node("node1", function(){});
  node1.on("test_event", function(param1){
    test.equal(param1, "testParam", "param1 is not right: %s", param1);
    test.done();
  });

  setTimeout(function() {
    node2.tell("node1:test_event", "testParam");
  }, 25);
}

exports["Node tell - nominal (receiving events and sending callbacks)"] = function(test){
  test.expect(2);
  node1.on("test_event2", function(param1, callback){
    test.equal(param1, "testParam", "param1 is not right: %s", param1);
    callback(null, param1);
  });

  setTimeout(function() {
    node2.tell("node1:test_event2", "testParam", function(err, param2){
      test.equal(param2, "testParam", "param2 is not right: %s", param2);
      test.done();
    });
  }, 25);
}

exports["Node tell - invalid who and what parameter"] = function(test){
  test.expect(1);
  test.throws(function(){
    node1.tell("iaminvalid", "blabla", function(err){});
  });
  test.done();
}

exports["Node tell - non-existent node"] = function(test){
  test.expect(1);
  node2.tell("i_dont_exist:who_cares", function(err){
    test.equal(err, "Error: Attempting to tell non-existent node!", "Callback returned a different error than anticipated: '%s'", err);
    test.done();
  });
};

exports["Node shout - nominal"] = function(test){
  test.expect(1);
  node1.on("shout1", function(param1){
    test.equal(param1, "ilovenodejs", "Shout recipients received an unexpected value from the shouter: %s", param1);
    test.done();
  });
  node2.shout("shout1", "ilovenodejs");
}

exports["Bridge close"] = function(test){
  test.expect(1);
  node1.on("$CLOSE", function(param1){
    test.equal(param1, "ilovenodejs", "Bridge close event recipients received an unexpected value from the shouter: %s", param1);
    test.done();
  });
  test_bridge.close(["ilovenodejs"]);
}
<|endoftext|>


<commit_before>describe('breeze-json-api-uribuilder', function() {

	let uriBuilder = {};
	let manager = {};

	let executeQuery = function(query){
		return uriBuilder.buildUri(query, manager.metadataStore)
	}

	before(function() {
		breeze.config.initializeAdapterInstances({
			uriBuilder: "json-api"
		});
		const ds = new breeze.DataService({
			serviceName: 'http://localhost:9000',
			hasServerMetadata: false
		});

		manager = new breeze.EntityManager({
			dataService: ds
		});

		uriBuilder = breeze.config.getAdapterInstance("uriBuilder", 'json-api');
	});

	describe('breeze.EntityQuery().from("persons")', function() {
		it('should return the URI for the persons endpoint', function() {

			const expectedURI = 'persons';
			const query = new breeze.EntityQuery().from("persons");

			expect(executeQuery(query), 'Get all Persons').equal(expectedURI);
		});
	});

	describe('breeze.EntityQuery().from("persons").where("ID", "==", "12345");', function() {
		it('should return the URI for a specific person', function() {

			const expectedURI = 'persons/12345';
			const query = new breeze.EntityQuery().from("persons").where("ID", "==", "12345");

			expect(executeQuery(query), "Get specific person").equal(expectedURI);
		});
	});

});
<commit_msg>Added additional test cases<commit_after>describe('breeze-json-api-uribuilder', function() {

	let uriBuilder = {};
	let manager = {};

	let executeQuery = function(query) {
		return uriBuilder.buildUri(query, manager.metadataStore)
	}

	before(function() {
		breeze.config.initializeAdapterInstances({
			uriBuilder: "json-api"
		});
		const ds = new breeze.DataService({
			serviceName: 'http://localhost:9000',
			hasServerMetadata: false
		});

		manager = new breeze.EntityManager({
			dataService: ds
		});

		uriBuilder = breeze.config.getAdapterInstance("uriBuilder", 'json-api');
	});

	describe('breeze.EntityQuery().from("persons")', function() {
		it('should return the URI for the persons endpoint', function() {

			const expectedURI = 'persons';
			const query = new breeze.EntityQuery().from("persons");

			expect(executeQuery(query), 'Get all Persons').equal(expectedURI);
		});
	});

	describe('breeze.EntityQuery().from("persons").where("ID", "==", "12345");', function() {
		it('should return the URI for a specific person', function() {

			const expectedURI = 'persons/12345';
			const query = new breeze.EntityQuery().from("persons").where("ID", "==", "12345");

			expect(executeQuery(query), "Get specific person").equal(expectedURI);
		});
	});

	describe('breeze.EntityQuery().from("persons").where("name", "startsWith", "A")', function() {
		it('should throw an error: startsWith isnt supported', function() {

			const query = new breeze.EntityQuery().from("persons").where('name', 'startsWith', 'A');
			expect(executeQuery(query)).to.throw(new Error('startsWith is not supported by JSON-API'));

		});
	});

});<|endoftext|>


<commit_before>class None {
}

export default new None();

export const isNone = (value) =>
  value instanceof None;
<commit_msg>make none safe across multiple classes<commit_after>class None {
  constructor() {
    this['@@qim/isNone'] = true;
  }
}

export default new None();

export const isNone = (value) =>
  value && value['@@qim/isNone'];
<|endoftext|>