gradio / node_modules /oboe /test /specs /jsonPath.unit.spec.js
reisarod's picture
Upload folder using huggingface_hub
5fae594 verified
describe('jsonPath', function(){
describe('compiles valid syntax while rejecting invalid', function() {
it("compiles a basic pattern without throwing", function(){
expect(compiling('!')).not.toThrow();
});
describe("syntactically invalid patterns", function() {
it("fail on single invalid token", function(){
expect(compiling('/')).toThrow();
});
it("fail on invalid pattern with some valid tokens", function(){
expect(compiling('foo/')).toThrow();
});
it("fail on unclosed duck clause", function(){
expect(compiling('{foo')).toThrow();
});
it("fail on token with capture alone", function(){
expect(compiling('foo$')).toThrow();
});
});
});
describe('patterns match correct paths', function() {
describe('when pattern has only bang', function() {
it("should match root", function(){
expect('!').toMatchPath([]);
});
it("should miss non-root", function(){
expect('!').not.toMatchPath(['a']);
expect('!').not.toMatchPath(['a', 'b']);
});
});
it('should match * universally', function() {
expect('*').toMatchPath( [] );
expect('*').toMatchPath( ['a'] );
expect('*').toMatchPath( ['a', 2] );
expect('*').toMatchPath( ['a','b'] );
});
it('should match empty pattern universally', function() {
expect('').toMatchPath( [] );
expect('').toMatchPath( ['a'] );
expect('').toMatchPath( ['a', 2] );
expect('').toMatchPath( ['a','b'] );
});
it('should match !.* against any top-level path node', function() {
expect('!.*').toMatchPath( ['foo'])
expect('!.*').toMatchPath( ['bar'])
expect('!.*').not.toMatchPath( [])
expect('!.*').not.toMatchPath( ['foo', 'bar'])
});
it('should match !..* against anything but the root', function() {
expect('!..*').not.toMatchPath( [] );
expect('!..*').toMatchPath( ['a'] );
expect('!..*').toMatchPath( ['a','b'] );
});
it('should match *..* against anything except the root since it requires a decendant ' +
'which the root will never satisfy because it cannot have an ancestor', function() {
expect('*..*').not.toMatchPath( [] );
expect('*..*').toMatchPath( ['a'] );
expect('*..*').toMatchPath( ['a','b'] );
});
it('should match !.foo against foo node at first level only', function(){
expect('!.foo').toMatchPath( ['foo'] );
expect('!.foo').not.toMatchPath( [] );
expect('!.foo').not.toMatchPath( ['foo', 'bar']);
expect('!.foo').not.toMatchPath( ['bar'] );
});
it('should match !.foo.bar against paths with foo as first node and bar as second', function() {
expect('!.a.b').toMatchPath( ['a', 'b'])
expect('!.a.b').not.toMatchPath( [])
expect('!.a.b').not.toMatchPath( ['a'])
});
it('should match !..foo against any path ending in foo', function(){
expect('!..foo').not.toMatchPath( []);
expect('!..foo').toMatchPath( ['foo']);
expect('!..foo').toMatchPath( ['a', 'foo']);
expect('!..foo').not.toMatchPath( ['a', 'foo', 'a']);
expect('!..foo').toMatchPath( ['a', 'foo', 'foo']);
expect('!..foo').toMatchPath( ['a', 'a', 'foo']);
expect('!..foo').not.toMatchPath( ['a', 'a', 'foot']);
expect('!..foo').not.toMatchPath( ['a', 'foo', 'foo', 'a']);
});
it('should match ..foo like !..foo', function() {
expect('..foo').not.toMatchPath( []);
expect('..foo').toMatchPath( ['foo']);
expect('..foo').toMatchPath( ['a', 'foo']);
expect('..foo').not.toMatchPath( ['a', 'foo', 'a']);
expect('..foo').toMatchPath( ['a', 'foo', 'foo']);
expect('..foo').toMatchPath( ['a', 'a', 'foo']);
expect('..foo').not.toMatchPath( ['a', 'a', 'foot']);
expect('..foo').not.toMatchPath( ['a', 'foo', 'foo', 'a']);
});
it('should match foo like !..foo or ..foo', function() {
expect('foo').not.toMatchPath( []);
expect('foo').toMatchPath( ['foo']);
expect('foo').toMatchPath( ['a', 'foo']);
expect('foo').not.toMatchPath( ['a', 'foo', 'a']);
expect('foo').toMatchPath( ['a', 'foo', 'foo']);
expect('foo').toMatchPath( ['a', 'a', 'foo']);
expect('foo').not.toMatchPath( ['a', 'a', 'foot']);
expect('foo').not.toMatchPath( ['a', 'foo', 'foo', 'a']);
});
it('is not fooled by substrings in path nodes', function(){
expect('!.foo').not.toMatchPath( ['foot'])
});
it('matches !..foo.bar against bars which are direct children of a foo anywhere in the document', function() {
expect('!..foo.bar').not.toMatchPath( []);
expect('!..foo.bar').not.toMatchPath( ['foo']);
expect('!..foo.bar').not.toMatchPath( ['a', 'foo']);
expect('!..foo.bar').toMatchPath( ['a', 'foo', 'bar']);
expect('!..foo.bar').not.toMatchPath( ['a', 'foo', 'foo']);
expect('!..foo.bar').toMatchPath( ['a', 'a', 'a', 'foo', 'bar']);
expect('!..foo.bar').not.toMatchPath( ['a', 'a', 'a', 'foo', 'bar', 'a']);
});
it('matches foo.bar like !..foo.bar', function() {
expect('foo.bar').not.toMatchPath( [])
expect('foo.bar').not.toMatchPath( ['foo'])
expect('foo.bar').not.toMatchPath( ['a', 'foo'])
expect('foo.bar').toMatchPath( ['a', 'foo', 'bar'])
expect('foo.bar').not.toMatchPath( ['a', 'foo', 'foo'])
expect('foo.bar').toMatchPath( ['a', 'a', 'a', 'foo', 'bar'])
expect('foo.bar').not.toMatchPath( ['a', 'a', 'a', 'foo', 'bar', 'a'])
});
it('matches !..foo.*.bar only if there is an intermediate node between foo and bar', function(){
expect('!..foo.*.bar').not.toMatchPath( [])
expect('!..foo.*.bar').not.toMatchPath( ['foo'])
expect('!..foo.*.bar').not.toMatchPath( ['a', 'foo'])
expect('!..foo.*.bar').not.toMatchPath( ['a', 'foo', 'bar'])
expect('!..foo.*.bar').toMatchPath( ['a', 'foo', 'a', 'bar'])
expect('!..foo.*.bar').not.toMatchPath( ['a', 'foo', 'foo'])
expect('!..foo.*.bar').not.toMatchPath( ['a', 'a', 'a', 'foo', 'bar'])
expect('!..foo.*.bar').toMatchPath( ['a', 'a', 'a', 'foo', 'a', 'bar'])
expect('!..foo.*.bar').not.toMatchPath( ['a', 'a', 'a', 'foo', 'bar', 'a'])
expect('!..foo.*.bar').not.toMatchPath( ['a', 'a', 'a', 'foo', 'a', 'bar', 'a'])
});
describe('with numeric path nodes in the pattern', function() {
it('should be able to handle numeric nodes in object notation', function(){
expect('!.a.2').toMatchPath( ['a', 2])
expect('!.a.2').toMatchPath( ['a', '2'])
expect('!.a.2').not.toMatchPath( [])
expect('!.a.2').not.toMatchPath( ['a'])
});
it('should be able to handle numberic nodes in array notation', function(){
expect('!.a[2]').toMatchPath( ['a', 2])
expect('!.a[2]').toMatchPath( ['a', '2'])
expect('!.a[2]').not.toMatchPath( [])
expect('!.a[2]').not.toMatchPath( ['a'])
});
});
describe('with array notation', function() {
it('should handle adjacent array notations', function(){
expect('!["a"][2]').toMatchPath( ['a', 2])
expect('!["a"][2]').toMatchPath( ['a', '2'])
expect('!["a"][2]').not.toMatchPath( [])
expect('!["a"][2]').not.toMatchPath( ['a'])
});
it('should allow to specify child of root', function(){
expect('![2]').toMatchPath( [2])
expect('![2]').toMatchPath( ['2'])
expect('![2]').not.toMatchPath( [])
expect('![2]').not.toMatchPath( ['a'])
});
it('should be allowed to contain a star', function(){
expect('![*]').toMatchPath( [2])
expect('![*]').toMatchPath( ['2'])
expect('![*]').toMatchPath( ['a'])
expect('![*]').not.toMatchPath( [])
});
});
describe('composition of several tokens into complex patterns', function() {
it('should be able to handle more than one double dot', function() {
expect('!..foods..fr')
.toMatchPath( ['foods', 2, 'name', 'fr']);
});
it('should be able to match ..* or ..[*] as if it were * because .. matches zero nodes', function(){
expect('!..*.bar')
.toMatchPath(['anything', 'bar']);
expect('!..[*].bar')
.toMatchPath(['anything', 'bar']);
});
});
describe('using css4-style syntax', function() {
it('returns deepest node when no css4-style syntax is used', function(){
expect( matchOf( 'l2.*' ).against(
ascentFrom({ l1: {l2: {l3:'leaf'}}})
)).toSpecifyNode('leaf');
});
it('returns correct named node', function(){
expect( matchOf( '$l2.*' ).against(
ascentFrom({ l1: {l2: {l3:'leaf'}}})
)).toSpecifyNode({l3:'leaf'});
});
it('returns correct node when css4-style pattern is followed by double dot', function() {
expect( matchOf( '!..$foo..bar' ).against(
ascentFrom({ l1: {foo: {l3: {bar: 'leaf'}}}})
)).toSpecifyNode({l3: {bar: 'leaf'}});
});
it('can match children of root while capturing the root', function() {
expect( matchOf( '$!.*' ).against(
ascentFrom({ l1: 'leaf' })
)).toSpecifyNode({ l1: 'leaf' });
});
it('returns captured node with array notation', function() {
expect( matchOf( '$["l1"].l2' ).against(
ascentFrom({ l1: {l2:'leaf'} })
)).toSpecifyNode({ l2: 'leaf' });
});
it('returns captured node with array numbered notation', function() {
expect( matchOf( '$["2"].l2' ).against(
ascentFrom({ '2': {l2:'leaf'} })
)).toSpecifyNode({ l2: 'leaf' });
});
it('returns captured node with star notation', function() {
expect( matchOf( '!..$*.l3' ).against(
ascentFrom({ l1: {l2:{l3:'leaf'}} })
)).toSpecifyNode({ l3: 'leaf' });
});
it('returns captured node with array star notation', function(){
expect( matchOf( '!..$[*].l3' ).against(
ascentFrom({ l1: {l2:{l3:'leaf'}} })
)).toSpecifyNode({ l3: 'leaf' });
});
});
describe('with duck matching', function() {
it('can do basic ducking', function(){
var rootJson = {
people:{
jack:{
name: 'Jack'
, email: '[email protected]'
}
}
};
expect( matchOf( '{name email}' ).against(
asAscent(
[ 'people', 'jack' ],
[rootJson, rootJson.people, rootJson.people.jack ]
)
)).toSpecifyNode({name: 'Jack', email: '[email protected]'});
});
it('can duck on two levels of a path', function(){
var rootJson = {
people:{
jack:{
name: 'Jack'
, email: '[email protected]'
}
}
};
expect( matchOf( '{people}.{jack}.{name email}' ).against(
asAscent(
[ 'people', 'jack' ],
[rootJson, rootJson.people, rootJson.people.jack ]
)
)).toSpecifyNode({name: 'Jack', email: '[email protected]'});
});
it('fails if one duck is unsatisfied', function(){
var rootJson = {
people:{
jack:{
name: 'Jack'
, email: '[email protected]'
}
}
};
expect( matchOf( '{people}.{alberto}.{name email}' ).against(
asAscent(
[ 'people', 'jack' ],
[rootJson, rootJson.people, rootJson.people.jack ]
)
)).not.toSpecifyNode({name: 'Jack', email: '[email protected]'});
});
it('can construct the root duck type', function(){
var rootJson = {
people:{
jack:{
name: 'Jack'
, email: '[email protected]'
}
}
};
expect( matchOf( '{}' ).against(
asAscent(
[ 'people', 'jack' ],
[rootJson, rootJson.people, rootJson.people.jack ]
)
)).toSpecifyNode({name: 'Jack', email: '[email protected]'});
});
it('does not match if not all fields are there', function(){
var rootJson = {
people:{
jack:{
// no name here!
email: '[email protected]'
}
}
};
expect( matchOf( '{name email}' ).against(
asAscent(
[ 'people', 'jack' ],
[rootJson, rootJson.people, rootJson.people.jack ]
)
)).not.toSpecifyNode({name: 'Jack', email: '[email protected]'});
});
it('fails if something upstream fails', function(){
var rootJson = {
women:{
betty:{
name:'Betty'
, email: '[email protected]'
}
},
men:{
// we don't have no menz!
}
};
expect( matchOf( 'men.{name email}' ).against(
asAscent(
[ 'women', 'betty' ],
[rootJson, rootJson.women, rootJson.women.betty ]
)
)).not.toSpecifyNode({name: 'Jack', email: '[email protected]'});
});
it('does not crash given ascent starting from non-objects', function(){
var rootJson = [ 1, 2, 3 ];
expect( function(){ matchOf( '{spin taste}' ).against(
asAscent(
[ '0' ],
[rootJson, rootJson[0] ]
)
)}).not.toThrow();
});
it('does not match when given non-object', function(){
var rootJson = [ 1, 2, 3 ];
expect( matchOf( '{spin taste}' ).against(
asAscent(
[ '0' ],
[rootJson, rootJson[0] ]
)
)).toBeFalsy();
});
});
});
beforeEach(function(){
this.addMatchers({
toSpecifyNode: function( expectedNode ){
function jsonSame(a,b) {
return JSON.stringify(a) == JSON.stringify(b);
}
var match = this.actual;
var notClause = this.isNot? ' any node except ' : 'node';
this.message = function () {
return "Expected " + notClause + ' ' + JSON.stringify(expectedNode) + " but got " +
(match.node? JSON.stringify(match.node) : 'no match');
}
return jsonSame( expectedNode, match.node );
}
, toMatchPath:function( pathStack ) {
var pattern = this.actual;
try{
return !!matchOf(pattern).against(asAscent(pathStack));
} catch( e ) {
this.message = function(){
return 'Error thrown running pattern "' + pattern +
'" against path [' + pathStack.join(',') + ']' + "\n" + (e.stack || e.message)
};
return false;
}
}
});
});
function compiling(pattern) {
return function(){
jsonPathCompiler(pattern);
}
}
function matchOf(pattern) {
var compiledPattern = jsonPathCompiler(pattern);
return {
against:function(ascent) {
return compiledPattern(ascent);
}
};
}
// for the given pattern, return an array of empty objects of the one greater length to
// stand in for the nodestack in the cases where we only care about match or not match.
// one greater because the root node doesnt have a name
function fakeNodeStack(path){
var rtn = path.map(function(){return {}});
rtn.unshift({iAm:'root'});
return rtn;
}
function asAscent(pathStack, nodeStack){
// first, make a defensive copy of the vars so that we can mutate them at will:
pathStack = pathStack && JSON.parse(JSON.stringify(pathStack));
nodeStack = nodeStack && JSON.parse(JSON.stringify(nodeStack));
// change the two parameters into the test from arrays (which are easy to write as in-line js) to
// lists (which is what the code under test needs)
nodeStack = nodeStack || fakeNodeStack(pathStack);
pathStack.unshift(ROOT_PATH);
// NB: can't use the more functional Array.prototype.reduce here, IE8 doesn't have it and might not
// be polyfilled
var ascent = emptyList;
for (var i = 0; i < pathStack.length; i++) {
var mapping = {key: pathStack[i], node:nodeStack[i]};
ascent = cons( mapping, ascent );
}
return ascent;
}
});