<commit_before>import test from 'tape';
import query, { paths } from '../src';
import tokenizer from '../src/tokenizer';
import parser from '../src/parser';
import maybe from '../src/maybe';
import { isPlainObject, isObject } from '../src/utils';

const data = require('./data.json');

const getTime = () => {
  const hr = process.hrtime();
  return (hr[0] * 1e9 + hr[1]) / 1e6;
};

const measure = (name, fn, ...args) => {
  const before = getTime();
  const result = fn(...args);
  const after = getTime();
  console.log(`${name} took: ${after - before}ms`);
  return result;
};

const runQueries = (test, queries, expected, d = data) => {
  queries.forEach(q => {
    const qy = measure(`parse: '${q}'`, query, q);
    const result = measure(`query: '${q}'`, qy, d);
    test.deepEquals(result, expected, `'${q}' should return expected results`);
  });
};

const runPaths = (test, queries, expected, d = data) => {
  queries.forEach(q => {
    const result = measure(`paths: '${q}'`, paths, q, d);
    test.deepEquals(result, expected, `'${q}' should return expected paths`);
  });
};

test('tokenizer', t => {
  t.plan(1);
  t.throws(() => tokenizer('@'), /Found no matching rule: @/, 'should throw an error');
});

test('parser', t => {
  t.plan(1);
  t.throws(() => parser([ { type: 'foo' } ]), /Unknown token type: foo/, 'should throw an error');
});

test('maybe', t => {
  t.plan(6);
  const m1 = maybe(3);
  const m2 = maybe();
  const plusOne = x => x + 1;
  const timesTwo = x => x * 2;
  const or = 'foo';
  t.equal(4, m1.bind(plusOne), 'should return the value inside');
  t.equal(6, m1.map(timesTwo).get(), 'should return the value wrapped');
  t.equal(6, m1.map(timesTwo).getOr(or), 'should return the value wrapped');
  t.equal(m2, m2.bind(timesTwo), 'should return the same instance');
  t.equal(m2, m2.map(plusOne), 'should return the same instance');
  t.equal(or, m2.map(plusOne).getOr(or), 'should return the value provided');

});

test('isPlainObject - constructor not a function', t => {
  t.plan(1);
  const obj = { constructor: 'wot' };
  t.notOk(isPlainObject(obj), 'should return false');
});

test('isPlainObject - constructor null prototype', t => {
  t.plan(1);
  function f() {}
  f.prototype = null;
  const obj = { constructor: f };
  t.notOk(isPlainObject(obj), 'should return false');
});

test('isPlainObject - constructor no isPrototypeOf', t => {
  t.plan(1);
  function f() {}
  delete f.prototype.isPrototypeOf;
  const obj = { constructor: f };
  t.notOk(isPlainObject(obj), 'should return false');
});

test('isObject', t => {
  t.plan(2);
  t.notOk(isObject(2), 'should return false');
  t.ok(isObject({}), 'should return true');
});

test('cached queries', t => {
  const expected = data.store.book[3];
  const queries = [
    '$..book[(@.length-1)]',
    '$..book[(@.length-1)]'
  ];
  runQueries(t, queries, expected);
  t.end();
});

test('support chars', t => {
  const d = {
    a0: 1,
    'a-one': 2,
  };
  const q1 = [
    '$.a0',
  ];
  const q2 = [
    '$.a-one',
  ];
  runQueries(t, q1, 1, d);
  runQueries(t, [ '${"a0"}' ], { a0: 1 }, d);
  runQueries(t, [ '$["a0"]' ], [ 1 ], d);
  runPaths(t, q1, [ [ 'a0' ] ], d);
  runQueries(t, q2, 2, d);
  runQueries(t, [ '${"a-one"}' ], { 'a-one': 2 }, d);
  runQueries(t, [ '$["a-one"]' ], [ 2 ], d);
  runPaths(t, q2, [ [ 'a-one' ] ], d);
  t.end();
});

test('recurse failure', t => {
  const expected = data;
  const queries = [
    '$..'
  ];
  const paths = [];<commit_msg>add more tests<commit_after>import test from 'tape';
import query, { paths } from '../src';
import tokenizer from '../src/tokenizer';
import parser from '../src/parser';
import maybe from '../src/maybe';
import { isPlainObject, isObject } from '../src/utils';

const data = require('./data.json');

const getTime = () => {
  const hr = process.hrtime();
  return (hr[0] * 1e9 + hr[1]) / 1e6;
};

const measure = (name, fn, ...args) => {
  const before = getTime();
  const result = fn(...args);
  const after = getTime();
  console.log(`${name} took: ${after - before}ms`);
  return result;
};

const runQueries = (test, queries, expected, d = data) => {
  queries.forEach(q => {
    const qy = measure(`parse: '${q}'`, query, q);
    const result = measure(`query: '${q}'`, qy, d);
    test.deepEquals(result, expected, `'${q}' should return expected results`);
  });
};

const runPaths = (test, queries, expected, d = data) => {
  queries.forEach(q => {
    const result = measure(`paths: '${q}'`, paths, q, d);
    test.deepEquals(result, expected, `'${q}' should return expected paths`);
  });
};

test('tokenizer', t => {
  t.plan(1);
  t.throws(() => tokenizer('@'), /Found no matching rule: @/, 'should throw an error');
});

test('parser', t => {
  t.plan(1);
  t.throws(() => parser([ { type: 'foo' } ]), /Unknown token type: foo/, 'should throw an error');
});

test('maybe', t => {
  t.plan(6);
  const m1 = maybe(3);
  const m2 = maybe();
  const plusOne = x => x + 1;
  const timesTwo = x => x * 2;
  const or = 'foo';
  t.equal(4, m1.bind(plusOne), 'should return the value inside');
  t.equal(6, m1.map(timesTwo).get(), 'should return the value wrapped');
  t.equal(6, m1.map(timesTwo).getOr(or), 'should return the value wrapped');
  t.equal(m2, m2.bind(timesTwo), 'should return the same instance');
  t.equal(m2, m2.map(plusOne), 'should return the same instance');
  t.equal(or, m2.map(plusOne).getOr(or), 'should return the value provided');

});

test('isPlainObject - constructor not a function', t => {
  t.plan(1);
  const obj = { constructor: 'wot' };
  t.notOk(isPlainObject(obj), 'should return false');
});

test('isPlainObject - constructor null prototype', t => {
  t.plan(1);
  function f() {}
  f.prototype = null;
  const obj = { constructor: f };
  t.notOk(isPlainObject(obj), 'should return false');
});

test('isPlainObject - constructor no isPrototypeOf', t => {
  t.plan(1);
  function f() {}
  delete f.prototype.isPrototypeOf;
  const obj = { constructor: f };
  t.notOk(isPlainObject(obj), 'should return false');
});

test('isObject', t => {
  t.plan(2);
  t.notOk(isObject(2), 'should return false');
  t.ok(isObject({}), 'should return true');
});

test('cached queries', t => {
  const expected = data.store.book[3];
  const queries = [
    '$..book[(@.length-1)]',
    '$..book[(@.length-1)]'
  ];
  runQueries(t, queries, expected);
  t.end();
});

test('support chars', t => {
  const d = {
    a0: 1,
    'a-one': 2,
    a2: {
      a0: 3,
      'a-one': 4,
    }
  };
  runQueries(t, [ '$.a0' ], 1, d);
  runQueries(t, [ '${"a0"}' ], { a0: 1 }, d);
  runQueries(t, [ '$["a0"]' ], [ 1 ], d);
  runPaths(t, [ '$.a0' ], [ [ 'a0' ] ], d);
  runQueries(t, [ '$.a-one' ], 2, d);
  runQueries(t, [ '${"a-one"}' ], { 'a-one': 2 }, d);
  runQueries(t, [ '$["a-one"]' ], [ 2 ], d);
  runPaths(t, [ '$.a-one' ], [ [ 'a-one' ] ], d);
  runQueries(t, [ '$..a0' ], [ 1, 3 ], d);
  runPaths(t, [ '$..a0' ], [ [ 'a0' ], [ 'a2', 'a0' ] ], d);
  runQueries(t, [ '$..a-one' ], [ 2, 4 ], d);
  runPaths(t, [ '$..a-one' ], [ [ 'a-one' ], [ 'a2', 'a-one' ] ], d);
  t.end();
});

test('recurse failure', t => {
  const expected = data;
  const queries = [
    '$..'
  ];
  const paths = [];
{'fraction_non_alphanumeric': 0.23245796859802695, 'fraction_numerical': 0.01597888008892594, 'mean_word_length': 3.421375921375921, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6045813', 'n_tokens_mistral': 2745, 'n_tokens_neox': 2726, 'n_words': 695}