<commit_before>let assert = require( 'assert' );
let collections = require( '../index' );
let chai = require( 'chai' );
let dirtyChai = require( 'dirty-chai' );
let Metalsmith = require( 'metalsmith' );
let path = require( 'path' );
let rimraf = require( 'rimraf' );

let metalsmithReplacer = require( '../lib/utilities/metalsmithReplacer' );
let saveMetadata = require( '../lib/utilities/saveMetadata' );

chai.use( dirtyChai );
let expect = chai.expect;

describe( 'metalsmith-nested-collections', function() {

    context( 'is a drop-in replacement for `metalsmith-collections`, so this plugin', function() {
        const fixturePath = 'test/collection-fixtures';

        before( function( done ) {
            rimraf( fixturePath + '/*/build', done );
        } );

        it( 'should add collections to metadata', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( m.collections.articles, m.articles );
                    done();
                } );
        } );

        it( 'should match collections by pattern', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: {
                        pattern: '*.md'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take a pattern shorthand string', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take an array of patterns', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    blogs: [ '*.md', '!one.md', '!two.md', '!four.md' ],
                    pages: { pattern: [ 'four.md' ] }
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( 1, metalsmith.metadata().blogs.length, 'length blogs' );
                    assert.equal( 1, metalsmith.metadata().pages.length, 'length page' );
                    assert.equal( files[ 'three.md' ].collection, 'blogs', 'collection blogs' );
                    assert.equal( files[ 'four.md' ].collection, 'pages', 'collection page' );
                    done();
                } );
        } );

        it( 'should add the collection property to a file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( files[ 'three.md' ].collection, 'articles' );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: 'title' } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" function', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: sort } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    done();
                } );

            function sort( a, b ) {
                a = a.title.slice( 1 );
                b = b.title.slice( 1 );
                return a > b ? 1 : -1;
            }
        } );

        it( 'should accept a "reverse" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' ),
                limit = 2;
            metalsmith
                .use( collections( {
                    articles: {
                        limit: limit,
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( limit, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" higher than the collection length', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        limit: 25
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 3, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should add next and previous references', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert.equal( articles[ 0 ].next, articles[ 1 ] );
                    assert.equal( articles[ 1 ].previous, articles[ 0 ] );
                    assert.equal( articles[ 1 ].next, articles[ 2 ] );
                    debugger;
                    assert.equal( articles[ 2 ].previous, articles[ 1 ] );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not add references if opts[key].refer === false', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references-off' );
            metalsmith
                .use( collections( { articles: { refer: false } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert( !articles[ 0 ].next );
                    assert( !articles[ 1 ].previous );
                    assert( !articles[ 1 ].next );
                    assert( !articles[ 2 ].previous );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not fail with empty collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/empty' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'date',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( articles.length, 0 );
                    done();
                } );
        } );

        it( 'should add metadata objects to collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: { name: 'Batman' }
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a JSON file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.json'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a YAML file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.yaml'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should allow multiple collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( { articles: {}, posts: {}, drafts: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should allow collections through metadata alone', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/noconfig' );
            metalsmith
                .use( collections( { movies: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.books.length );
                    assert.equal( 1, m.movies.length );
                    assert.equal( m.collections.books, m.books );
                    assert.equal( m.collections.movies, m.movies );
                    done();
                } );
        } );

        it( 'should allow collections by pattern and front matter', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( {
                    articles: {},
                    posts: {},
                    drafts: {},
                    blog: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 3, m.blog.length );
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.blog, m.blog );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should add file path', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( articles[ 0 ].path );
                    assert.equal( articles[ 0 ].path, 'one.md' );
                    done();
                } );
        } );

    } );

    context( 'provides functionality that', function() {
        const fixtureRoot = path.resolve( __dirname, 'nested-fixtures' );
        const collectionsConfig = {
            posts: {
                pattern: 'posts/**/*.md',
                sortBy: 'date',
                reverse: true
            },
            'metalsmith-tutorial': {
                pattern: 'posts/metalsmith-tutorial/*.md',
                sortBy: 'date',
                reverse: true
            },
            'shocking-secret': {
                pattern: 'posts/shocking-secret/*.md',
                sortBy: 'date',
                reverse: true
            }
        };

        before( function( done ) {
            rimraf( fixtureRoot + '/*/build', done );
        } );

        it( 'adds "nextInCollection" and "prevInCollection" to file metadata', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Save file and collection metadata to JSON files
                    let metadataCollection = {
                        files: files,
                        collections: metadata
                    };
                    saveMetadata( fixturePath, metadataCollection );

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                expect( file ).to.have.ownProperty( 'prevInCollection' );
                            }
                            if ( index < ( array.length - 1 ) ) {
                                expect( file ).to.have.ownProperty( 'nextInCollection' );
                            }
                        } );
                    }

                    done();
                } );
        } );

        it( 'adds links by collection to each file', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();
                    let thereIsMoreToDo = true;

                    // Test using the `collections` group in the global metadata
                    let collection = metadata.collections[ 'posts' ];
                    expect( Array.isArray( collection ) ).to.be.true();
                    collection.forEach( ( file, index, array ) => {
                        if ( index < ( array.length - 1) ) {
                            let nextLinks = file.nextInCollection;
                            expect( nextLinks ).to.be.ok();
                            expect( nextLinks ).to.have.ownProperty( 'posts' );
                        }
                    } );
                    expect( thereIsMoreToDo, '**There is more to do!** ' ).to.be.false();
                    done();
                } );
        } );

    } );

} );
<commit_msg>Test links by collection for all collections and files<commit_after>let assert = require( 'assert' );
let collections = require( '../index' );
let chai = require( 'chai' );
let dirtyChai = require( 'dirty-chai' );
let Metalsmith = require( 'metalsmith' );
let path = require( 'path' );
let rimraf = require( 'rimraf' );

let metalsmithReplacer = require( '../lib/utilities/metalsmithReplacer' );
let saveMetadata = require( '../lib/utilities/saveMetadata' );

chai.use( dirtyChai );
let expect = chai.expect;

describe( 'metalsmith-nested-collections', function() {

    context( 'is a drop-in replacement for `metalsmith-collections`, so this plugin', function() {
        const fixturePath = 'test/collection-fixtures';

        before( function( done ) {
            rimraf( fixturePath + '/*/build', done );
        } );

        it( 'should add collections to metadata', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( m.collections.articles, m.articles );
                    done();
                } );
        } );

        it( 'should match collections by pattern', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: {
                        pattern: '*.md'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take a pattern shorthand string', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take an array of patterns', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    blogs: [ '*.md', '!one.md', '!two.md', '!four.md' ],
                    pages: { pattern: [ 'four.md' ] }
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( 1, metalsmith.metadata().blogs.length, 'length blogs' );
                    assert.equal( 1, metalsmith.metadata().pages.length, 'length page' );
                    assert.equal( files[ 'three.md' ].collection, 'blogs', 'collection blogs' );
                    assert.equal( files[ 'four.md' ].collection, 'pages', 'collection page' );
                    done();
                } );
        } );

        it( 'should add the collection property to a file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( files[ 'three.md' ].collection, 'articles' );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: 'title' } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" function', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: sort } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    done();
                } );

            function sort( a, b ) {
                a = a.title.slice( 1 );
                b = b.title.slice( 1 );
                return a > b ? 1 : -1;
            }
        } );

        it( 'should accept a "reverse" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' ),
                limit = 2;
            metalsmith
                .use( collections( {
                    articles: {
                        limit: limit,
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( limit, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" higher than the collection length', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        limit: 25
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 3, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should add next and previous references', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert.equal( articles[ 0 ].next, articles[ 1 ] );
                    assert.equal( articles[ 1 ].previous, articles[ 0 ] );
                    assert.equal( articles[ 1 ].next, articles[ 2 ] );
                    debugger;
                    assert.equal( articles[ 2 ].previous, articles[ 1 ] );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not add references if opts[key].refer === false', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references-off' );
            metalsmith
                .use( collections( { articles: { refer: false } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert( !articles[ 0 ].next );
                    assert( !articles[ 1 ].previous );
                    assert( !articles[ 1 ].next );
                    assert( !articles[ 2 ].previous );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not fail with empty collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/empty' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'date',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( articles.length, 0 );
                    done();
                } );
        } );

        it( 'should add metadata objects to collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: { name: 'Batman' }
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a JSON file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.json'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a YAML file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.yaml'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should allow multiple collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( { articles: {}, posts: {}, drafts: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should allow collections through metadata alone', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/noconfig' );
            metalsmith
                .use( collections( { movies: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.books.length );
                    assert.equal( 1, m.movies.length );
                    assert.equal( m.collections.books, m.books );
                    assert.equal( m.collections.movies, m.movies );
                    done();
                } );
        } );

        it( 'should allow collections by pattern and front matter', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( {
                    articles: {},
                    posts: {},
                    drafts: {},
                    blog: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 3, m.blog.length );
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.blog, m.blog );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should add file path', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( articles[ 0 ].path );
                    assert.equal( articles[ 0 ].path, 'one.md' );
                    done();
                } );
        } );

    } );

    context( 'provides functionality that', function() {
        const fixtureRoot = path.resolve( __dirname, 'nested-fixtures' );
        const collectionsConfig = {
            posts: {
                pattern: 'posts/**/*.md',
                sortBy: 'date',
                reverse: true
            },
            'metalsmith-tutorial': {
                pattern: 'posts/metalsmith-tutorial/*.md',
                sortBy: 'date',
                reverse: true
            },
            'shocking-secret': {
                pattern: 'posts/shocking-secret/*.md',
                sortBy: 'date',
                reverse: true
            }
        };

        before( function( done ) {
            rimraf( fixtureRoot + '/*/build', done );
        } );

        it( 'adds "nextInCollection" and "prevInCollection" to file metadata', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Save file and collection metadata to JSON files
                    let metadataCollection = {
                        files: files,
                        collections: metadata
                    };
                    saveMetadata( fixturePath, metadataCollection );

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                expect( file ).to.have.ownProperty( 'prevInCollection' );
                            }
                            if ( index < ( array.length - 1 ) ) {
                                expect( file ).to.have.ownProperty( 'nextInCollection' );
                            }
                        } );
                    }

                    done();
                } );
        } );

        it( 'adds links by collection to each file', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata.collections[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                let prevLinks = file.prevInCollection;
                                expect( prevLinks ).to.be.ok();
                                expect( prevLinks ).to.have.ownProperty( name );
                            }

                            if ( index < ( array.length - 1) ) {
                                let nextLinks = file.nextInCollection;
                                expect( nextLinks ).to.be.ok();
                                expect( nextLinks ).to.have.ownProperty( name );
                            }
                        } );
                    }

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

    } );

} );
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert')
var namer = require('..')

suite('namer', function () {

  test('is a function', function() {
    assert.equal('function', typeof(namer))
  })

  test('returns an object containing named sorted arrays', function() {
    var names = namer('#ffa500')
    assert(!Array.isArray(names))
    assert(names.basic)
    assert(names.html)
    assert(names.ntc)
    assert(names.pantone)
    assert(names.roygbiv)
    assert(names.x11)
    assert.equal(names.basic[0].distance, 0)
  })

  test('matches inexact colors with deltaE', function() {
    var names = namer('FF0001', { distance: 'deltaE' })
    assert.equal(names.basic[0].hex, '#FF0000')
    assert.equal(names.basic[0].name, 'red')
    assert.equal(Math.floor(names.basic[0].distance*100), 13)
  })

  test('matches inexact colors with deltaE', function() {
    var names = namer('FF0001')
    assert.equal(names.basic[0].hex, '#FF0000')
    assert.equal(names.basic[0].name, 'red')
    assert.equal(Math.floor(names.basic[0].distance*100), 25)
  })

  test('matches exact colors', function() {
    var names = namer('0000FF')
    assert.equal(names.basic[0].hex, '#0000FF')
    assert.equal(names.basic[0].name, 'blue')
    assert.equal(names.basic[0].distance, 0)
  })

  test('accepts hex strings that include a hash symbol', function() {
    var names = namer('#0000FF')
    assert.equal(names.basic[0].hex, '#0000FF')
    assert.equal(names.basic[0].name, 'blue')
    assert.equal(names.basic[0].distance, 0)
  })

  test('accepts HSL input', function() {
    var names = namer("hsl(50,100%,50%)")
    assert.equal(names.basic[0].name, 'gold')
  })

  suite('lists', function() {

    test('are available as a property of the exported module', function() {
      assert(namer.lists)
    })

    test('are arrays of objects with keys `name` and `hex`', function() {
      for (var list in namer.lists) {
        namer.lists[list].forEach(function(color){
          assert(color.name);
          assert(color.hex);
        })
      }
    })

  })

  suite('options', function() {

    test('can receive an empty object', function() {
      var names = namer("hsl(50,100%,50%)", {})
      assert.equal(names.basic[0].name, 'gold')
    })

    test('can receive `pick` option', function() {
      var names = namer("hsl(50,100%,50%)", { pick: ['basic', 'pantone'] })
      assert(Array.isArray(names.basic))
      assert(Array.isArray(names.pantone))
      assert.equal(Object.keys(names).length, 2)
      assert.equal(names.html, undefined)
      assert.equal(names.roygbiv, undefined)
    })

    test('can receive `omit` option', function() {
      var names = namer("hsl(50,100%,50%)", { omit: ['basic', 'pantone'] })
      assert(Array.isArray(names.html))
      assert(Array.isArray(names.roygbiv))
      assert.equal(Object.keys(names).length, Object.keys(namer.lists).length - 2)
      assert.equal(names.basic, undefined)
      assert.equal(names.pantone, undefined)
    })
  })

})
<commit_msg>Fix test<commit_after>"use strict";

var assert = require('assert')
var namer = require('..')

suite('namer', function () {

  test('is a function', function() {
    assert.equal('function', typeof(namer))
  })

  test('returns an object containing named sorted arrays', function() {
    var names = namer('#ffa500')
    assert(!Array.isArray(names))
    assert(names.basic)
    assert(names.html)
    assert(names.ntc)
    assert(names.pantone)
    assert(names.roygbiv)
    assert(names.x11)
    assert.equal(names.basic[0].distance, 0)
  })

  test('matches inexact colors with deltaE', function() {
    var names = namer('FF0001', { distance: 'deltaE' })
    assert.equal(names.basic[0].hex, '#FF0000')
    assert.equal(names.basic[0].name, 'red')
    assert.equal(Math.floor(names.basic[0].distance*100), 13)
  })

  test('matches inexact colors', function() {
    var names = namer('FF0001')
    assert.equal(names.basic[0].hex, '#FF0000')
    assert.equal(names.basic[0].name, 'red')
    assert.equal(Math.floor(names.basic[0].distance*100), 25)
  })

  test('matches exact colors', function() {
    var names = namer('0000FF')
    assert.equal(names.basic[0].hex, '#0000FF')
    assert.equal(names.basic[0].name, 'blue')
    assert.equal(names.basic[0].distance, 0)
  })

  test('accepts hex strings that include a hash symbol', function() {
    var names = namer('#0000FF')
    assert.equal(names.basic[0].hex, '#0000FF')
    assert.equal(names.basic[0].name, 'blue')
    assert.equal(names.basic[0].distance, 0)
  })

  test('accepts HSL input', function() {
    var names = namer("hsl(50,100%,50%)")
    assert.equal(names.basic[0].name, 'gold')
  })

  suite('lists', function() {

    test('are available as a property of the exported module', function() {
      assert(namer.lists)
    })

    test('are arrays of objects with keys `name` and `hex`', function() {
      for (var list in namer.lists) {
        namer.lists[list].forEach(function(color){
          assert(color.name);
          assert(color.hex);
        })
      }
    })

  })

  suite('options', function() {

    test('can receive an empty object', function() {
      var names = namer("hsl(50,100%,50%)", {})
      assert.equal(names.basic[0].name, 'gold')
    })

    test('can receive `pick` option', function() {
      var names = namer("hsl(50,100%,50%)", { pick: ['basic', 'pantone'] })
      assert(Array.isArray(names.basic))
      assert(Array.isArray(names.pantone))
      assert.equal(Object.keys(names).length, 2)
      assert.equal(names.html, undefined)
      assert.equal(names.roygbiv, undefined)
    })

    test('can receive `omit` option', function() {
      var names = namer("hsl(50,100%,50%)", { omit: ['basic', 'pantone'] })
      assert(Array.isArray(names.html))
      assert(Array.isArray(names.roygbiv))
      assert.equal(Object.keys(names).length, Object.keys(namer.lists).length - 2)
      assert.equal(names.basic, undefined)
      assert.equal(names.pantone, undefined)
    })
  })

})
<|endoftext|>


<commit_before>const domains = [
  '247realmedia.com',
  '2mdn.net',
  'adadviser.net',
  'adblade.com',
  'adkengage.com',
  'adnxs.com',
  'adsonar.com',
  'adspeed.net',
  'adtechus.com',
  'advertising.com',
  'adzerk.net',
  'afy11.net',
  'agilone.com',
  'amazon-adsystem.com',
  'ads.yahoo.com',
  'adserver.yahoo.com',
  'adsrvr.org',
  'adtech.de',
  'analytics.yahoo.com',
  'backbeatmedia.com',
  'bc.yahoo.com',
  'bkrtx.com',
  'gemini.yahoo.com',
  'ysm.yahoo.com',
  'atdmt.com',
  'atwola.com',
  'betrad.com',
  'bizographics.com',
  'bizrate.com',
  'blogads.com',
  'bluekai.com',
  'bounceexchange.com',
  'brcdn.com',
  'buysellads.com',
  'captifymedia.com',
  'carbonads.net',
  'casalemedia.com',
  'caspion.com',
  'channeladvisor.com',
  'chartbeat.com',
  'chartbeat.net',
  'chitika.net',
  'clicktale.net',
  'content.ad',
  'convertro.com',
  'crsspxl.com',
  'crwdcntrl.net',
  'demdex.net',
  'dotomi.com',
  'doubleclick.net',
  'doubleverify.com',
  'dwin1.com',
  'dynamicyield.com',
  'effectivemeasure.net',
  'en25.com',
  'eproof.com',
  'everestjs.net',
  'everesttech.net',
  'exelator.com',
  'exponential.com',
  'fastclick.net',
  'fetchback.com',
  'fmpub.net',
  'ftjcfx.com',
  'getclicky.com',
  'go-mpulse.net',
  'google-analytics.com',
  'googleadservices.com',
  'googlesyndication.com',
  'googletagmanager.com',
  'googletagservices.com',
  'gscounters.eu1.gigya.com',
  'gscounters.gigya.com',
  'gscounters.us1.gigya.com',
  'hit-counts.com',
  'hs-analytics.net',
  'hubspot.com',
  'imrworldwide.com',
  'intellitxt.com',
  'intermarkets.net',
  'korrelate.net',
  'krxd.net',
  'lexity.com',
  'linkconnector.com',
  'linksynergy.com',
  'mathtag.com',
  'media.net',
  'media6degrees.com',
  'mediaforge.com',
  'mediaplex.com',
  'mercent.com',
  'moatads.com',
  'monitus.net',
  'mookie1.com',
  'msads.net',
  'neodatagroup.com',
  'netseer.com',
  'netshelter.net',
  'newscred.com',
  'nexac.com',
  'omtrdc.net',
  'opbandit.com',
  'outbrain.com',
  'pictela.net',
  'pixel.wp.com',
  'pixel.yabidos.com',
  'postrelease.com',
  'pro-market.net',
  'pzkysq.pink',
  'qualtrics.com',
  'quantcast.com',
  'quantserve.com',
  'revsci.net',
  'rlcdn.com',
  'rubiconproject.com',
  'scorecardresearch.com',
  'servebom.com',
  'serving-sys.com',
  'simplereach.com',
  'sitescout.com',
  'skimlinks.com',
  'skimresources.com',
  'stats.wordpress.com',
  'stats.wp.com',
  'streamads.yahoo.com',
  'taboola.com',
  'tribalfusion.com',
  'trove.com',
  'turn.com',
  'tynt.com',
  'veinteractive.com',
  'verticalscope.com',
  'viglink.com',
  'visualrevenue.com',
  'yldbt.com',
  'zedo.com',
  'zergnet.com',
  'zqtk.net'
]
<commit_msg>Add tracker.<commit_after>const domains = [
  '247realmedia.com',
  '2mdn.net',
  'adadviser.net',
  'adblade.com',
  'adkengage.com',
  'adnxs.com',
  'adsonar.com',
  'adspeed.net',
  'adtechus.com',
  'advertising.com',
  'adzerk.net',
  'afy11.net',
  'agilone.com',
  'amazon-adsystem.com',
  'ads.yahoo.com',
  'adserver.yahoo.com',
  'adsrvr.org',
  'adtech.de',
  'analytics.yahoo.com',
  'backbeatmedia.com',
  'bc.yahoo.com',
  'bkrtx.com',
  'gemini.yahoo.com',
  'ysm.yahoo.com',
  'atdmt.com',
  'atwola.com',
  'betrad.com',
  'bizographics.com',
  'bizrate.com',
  'blogads.com',
  'bluekai.com',
  'bounceexchange.com',
  'brcdn.com',
  'buysellads.com',
  'captifymedia.com',
  'carbonads.net',
  'casalemedia.com',
  'caspion.com',
  'channeladvisor.com',
  'chartbeat.com',
  'chartbeat.net',
  'chitika.net',
  'clicktale.net',
  'content.ad',
  'convertro.com',
  'crsspxl.com',
  'crwdcntrl.net',
  'demdex.net',
  'dotomi.com',
  'doubleclick.net',
  'doubleverify.com',
  'dwin1.com',
  'dynamicyield.com',
  'effectivemeasure.net',
  'en25.com',
  'eproof.com',
  'everestjs.net',
  'everesttech.net',
  'exelator.com',
  'exponential.com',
  'fastclick.net',
  'fetchback.com',
  'fmpub.net',
  'ftjcfx.com',
  'getclicky.com',
  'go-mpulse.net',
  'google-analytics.com',
  'googleadservices.com',
  'googlesyndication.com',
  'googletagmanager.com',
  'googletagservices.com',
  'gscounters.eu1.gigya.com',
  'gscounters.gigya.com',
  'gscounters.us1.gigya.com',
  'hit-counts.com',
  'hs-analytics.net',
  'hubspot.com',
  'imrworldwide.com',
  'intellitxt.com',
  'intermarkets.net',
  'korrelate.net',
  'krxd.net',
  'lexity.com',
  'linkconnector.com',
  'linksynergy.com',
  'listrakbi.com',
  'mathtag.com',
  'media.net',
  'media6degrees.com',
  'mediaforge.com',
  'mediaplex.com',
  'mercent.com',
  'moatads.com',
  'monitus.net',
  'mookie1.com',
  'msads.net',
  'neodatagroup.com',
  'netseer.com',
  'netshelter.net',
  'newscred.com',
  'nexac.com',
  'omtrdc.net',
  'opbandit.com',
  'outbrain.com',
  'pictela.net',
  'pixel.wp.com',
  'pixel.yabidos.com',
  'postrelease.com',
  'pro-market.net',
  'pzkysq.pink',
  'qualtrics.com',
  'quantcast.com',
  'quantserve.com',
  'revsci.net',
  'rlcdn.com',
  'rubiconproject.com',
  'scorecardresearch.com',
  'servebom.com',
  'serving-sys.com',
  'simplereach.com',
  'sitescout.com',
  'skimlinks.com',
  'skimresources.com',
  'stats.wordpress.com',
  'stats.wp.com',
  'streamads.yahoo.com',
  'taboola.com',
  'tribalfusion.com',
  'trove.com',
  'turn.com',
  'tynt.com',
  'veinteractive.com',
  'verticalscope.com',
  'viglink.com',
  'visualrevenue.com',
  'yldbt.com',
  'zedo.com',
  'zergnet.com',
  'zqtk.net'
]
<|endoftext|>


<commit_before>/**
 * Created by Bean Li on 2016/6/6.
 */
var fs = require('fs');
var AsynLoop = require('../index');

var fileArr = ['./1', './2', './3'];
var iterator = function (index, item, continueCallback, quitCallback) {
    fs.readFile(item, function (err, data) {
        if (err) {
            quitCallback && quitCallback();
        }else{
            console.log('execute loop ' + index + ';');
            continueCallback && continueCallback();
        }
    });
};
var callback = function () {
    console.log('fulfil work.')
};
AsynLoop(fileArr, iterator, callback).start();
<commit_msg>change test<commit_after>/**
 * Created by Bean Li on 2016/6/6.
 */
var fs = require('fs');
var AsynLoop = require('../index');

var fileArr = ['./1', './2', './3'];
var iterator = function (index, item, continueCallback, quitCallback) {
    fs.readFile(item, function (err, data) {
        if (err) {
            quitCallback && quitCallback();
        }else{
            console.log('execute loop ' + index + ';');
            console.log('    file'+ index +' content is ' + data + ';');
            continueCallback && continueCallback();
        }
    });
};
var callback = function () {
    console.log('fulfil work.')
};
AsynLoop(fileArr, iterator, callback).start();
<|endoftext|>


<commit_before>function test(name, path) {
    describe(name, function() {
        require(path);
    })
}

describe('#bateeq-module', function(done) {
    this.timeout(2 * 6000);
    // test('@manager/article-brand-manager', './managers/article-brand-manager-test');
    // test('@manager/article-category-manager', './managers/article-category-manager-test');
    // test('@manager/article-counter-manager', './managers/article-counter-manager-test');
    // test('@manager/article-material-manager', './managers/article-material-manager-test');
    // test('@manager/article-motif-manager', './managers/article-motif-manager-test');
    // test('@manager/article-origin-manager', './managers/article-origin-manager-test');
    // test('@manager/article-season-manager', './managers/article-season-manager-test');
    // test('@manager/article-sub-counter-manager', './managers/article-sub-counter-manager-test');
    // test('@manager/article-theme-manager', './managers/article-theme-manager-test');
    // test('@manager/article-type-manager', './managers/article-type-manager-test');
    // test('@manager/article-manager', './managers/article-manager-test');
    // test('@manager/article-variant-manager', './managers/article-variant-manager-test');
    // test('@manager/storage-manager', './managers/storage-manager-test');
    // test('@manager/transfer-in-doc-manager', './managers/transfer-in-doc-manager-test');
    // test('@manager/transfer-out-doc-manager', './managers/transfer-out-doc-manager-test');
    // test('@manager/inventory-manager', './managers/inventory-manager-test');
     test('@manager/inventory-movement-manager', './managers/inventory-movement-manager-test');
})<commit_msg>update index<commit_after>function test(name, path) {
    describe(name, function() {
        require(path);
    })
}

describe('#bateeq-module', function(done) {
    this.timeout(2 * 6000);
    // test('@manager/article-brand-manager', './managers/article-brand-manager-test');
    // test('@manager/article-category-manager', './managers/article-category-manager-test');
    // test('@manager/article-counter-manager', './managers/article-counter-manager-test');
    // test('@manager/article-material-manager', './managers/article-material-manager-test');
    // test('@manager/article-motif-manager', './managers/article-motif-manager-test');
    // test('@manager/article-origin-manager', './managers/article-origin-manager-test');
    // test('@manager/article-season-manager', './managers/article-season-manager-test');
    // test('@manager/article-sub-counter-manager', './managers/article-sub-counter-manager-test');
    // test('@manager/article-theme-manager', './managers/article-theme-manager-test');
    // test('@manager/article-type-manager', './managers/article-type-manager-test');
    // test('@manager/article-manager', './managers/article-manager-test');
    // test('@manager/article-variant-manager', './managers/article-variant-manager-test');
    // test('@manager/storage-manager', './managers/storage-manager-test');
    // test('@manager/transfer-in-doc-manager', './managers/transfer-in-doc-manager-test');
    // test('@manager/transfer-out-doc-manager', './managers/transfer-out-doc-manager-test');
     test('@manager/inventory-manager', './managers/inventory-manager-test');

})<|endoftext|>


<commit_before>import {POS, VALUE} from './names';

export const X = {};
export const Y = {};
export const Length = {};
export const SinX = {
    scale: 16
};
export const SinY = {
    scale: 16
};
export const SinXY = {
    scale: 16
};

export const Xor = {
    scale: 256
};

// export const Color = {
//     glsl: 'vec3',
//     color: true,
//     position: false,
//     params: ['vec3', 'color', [1, 1, 1]]
// };

export const Value = {
    glsl: 'float',
    position: false,
    params: [['float', 'value', 1, [-1, 1]]]
};

export const SimplexNoise = {
    glsl: 'snoise',
    normalized: false
};

export const Checker = {
    glsl: 'checker',
    params: [['float', 'repeats', 2, [1, 128]]]
};

export const PerlinNoise = {
    glsl: 'cnoise',
    normalized: false,
    scale: 4
};

export const PeriodicNoise = {
    glsl: 'pnoise',
    params: [['vec2', 'size', [16, 16], [1, 128]]],
    normalized: false,
    scale: 4
};

export const WorleyF1 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1]
    ]
};

export const WorleyF2 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1]
    ]
};

export const WorleyF1F2 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1],
        [0, 1]
    ]
};

export const WorleyF2F1 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1]
    ]
};

export const WorleyCrackle = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]], ['float', 'multiply', 8, [1, 32]], ['float', 'divide', 2, [1, 32]], ['float', 'offset', 0.5, [0, 8]]],
    scale: 2,
    examples: [
        [0.5, 0, 8, 2, 0.5],
        [0, 0, 8, 2, 0.5],
        [1, 1, 8, 2, 0.5],
        [1, 0, 32, 2, 0.5],
        [1, 0, 32, 1, 2],
        [1, 0, 32, 1, 4],
        [1, 1, 32, 1, 4],
        [0.25, 1, 32, 1, 4]
    ]
};

export const RidgedMultiFractal = {
    glsl: 'ridgedMultiFractal',
    params: [['float', 'H', 0.25, [0, 8]], ['float', 'lacunarity', 2, [0, 8]], ['float', 'frequency', 2, [0, 8]], ['float', 'octaves', 6, [1, 12]], ['float', 'offset', .9, [-2, 2]], ['float', 'gain', 1.5, [-8, 8]]],
    scale: 1,
    examples: [
        [0.25, 1, 1, 1, 1.01, 1],
        [0.25, 3, 1, 6, 1.01, 1]
    ]
};

export const HybridMultiFractal = {
    glsl: 'hybridMultiFractal',
    params: [['float', 'H', 0.25, [0, 8]], ['float', 'lacunarity', 3, [0, 8]], ['float', 'frequency', 2, [0, 8]], ['float', 'octaves', 6, [1, 12]], ['float', 'offset', .05, [-2, 2]]],
    normalized: false,
    scale: 1,
    examples: [
        [0.1, 1.5, 3, 6, 0]
    ]
};

export const HeteroTerrain = {
    glsl: 'heteroTerrainA',
    params: [['float', 'H', 0.5, [0.01, 3]], ['float', 'lacunarity', 2, [1, 3]], ['float', 'frequency', 2, [1, 8]], ['float', 'octaves', 6, [1, 8]], ['float', 'offset', .05, [-1, 1]]],
    normalized: false,
    scale: 1,
    examples: [
        [2, 1.5, 3, 2, 0]
    ]
};

export const MultiFractal = {
    glsl: 'multifractalA',
    params: [
        ['float', 'H', 0.5, [0.01, 2]],
        ['float', 'lacunarity', 2, [1, 2]],
        ['float', 'frequency', 2, [1, 8]],
        ['float', 'octaves', 6, [1, 8]],
        ['float', 'offset', .8, [-1, 1]],
        ['float', 'noise', null, null, 'snoise', [['vec2', POS]]]
    ],
    scale: 1,
    examples: [
        [1.5, 1.5, 4, 6, 0.85]
    ]
};

export const FBm = {
    glsl: 'fBmA',
    params: [['float', 'H', 0.5, [0, 8]], ['float', 'lacunarity', 2, [0, 8]], ['float', 'frequency', 2, [0, 8]], ['float', 'octaves', 6, [1, 12]]],
    normalized: false,
    scale: 1,
    examples: [
        [0.85, 2.5, 4, 6]
    ]
};

export let RGB = {
    glsl: 'vec3',
    color: true,
    position: false,
    params: [['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]]]
};

export let HSV = {
    glsl: 'HSV',
    color: true,
    position: false,
    params: [['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]]],
};
<commit_msg>default value 0.5<commit_after>import {POS, VALUE} from './names';

export const X = {};
export const Y = {};
export const Length = {};
export const SinX = {
    scale: 16
};
export const SinY = {
    scale: 16
};
export const SinXY = {
    scale: 16
};

export const Xor = {
    scale: 256
};

// export const Color = {
//     glsl: 'vec3',
//     color: true,
//     position: false,
//     params: ['vec3', 'color', [1, 1, 1]]
// };

export const Value = {
    glsl: 'float',
    position: false,
    params: [['float', 'value', 0.5, [-1, 1]]]
};

export const SimplexNoise = {
    glsl: 'snoise',
    normalized: false
};

export const Checker = {
    glsl: 'checker',
    params: [['float', 'repeats', 2, [1, 128]]]
};

export const PerlinNoise = {
    glsl: 'cnoise',
    normalized: false,
    scale: 4
};

export const PeriodicNoise = {
    glsl: 'pnoise',
    params: [['vec2', 'size', [16, 16], [1, 128]]],
    normalized: false,
    scale: 4
};

export const WorleyF1 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1]
    ]
};

export const WorleyF2 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1]
    ]
};

export const WorleyF1F2 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1],
        [0, 1]
    ]
};

export const WorleyF2F1 = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]]],
    scale: 2,
    examples: [
        [0.5, 0],
        [0, 0],
        [1, 1]
    ]
};

export const WorleyCrackle = {
    params: [['float', 'jitter', 1, [0, 1]], ['float', 'manhattanDistance', 0, [0, 1]], ['float', 'multiply', 8, [1, 32]], ['float', 'divide', 2, [1, 32]], ['float', 'offset', 0.5, [0, 8]]],
    scale: 2,
    examples: [
        [0.5, 0, 8, 2, 0.5],
        [0, 0, 8, 2, 0.5],
        [1, 1, 8, 2, 0.5],
        [1, 0, 32, 2, 0.5],
        [1, 0, 32, 1, 2],
        [1, 0, 32, 1, 4],
        [1, 1, 32, 1, 4],
        [0.25, 1, 32, 1, 4]
    ]
};

export const RidgedMultiFractal = {
    glsl: 'ridgedMultiFractal',
    params: [['float', 'H', 0.25, [0, 8]], ['float', 'lacunarity', 2, [0, 8]], ['float', 'frequency', 2, [0, 8]], ['float', 'octaves', 6, [1, 12]], ['float', 'offset', .9, [-2, 2]], ['float', 'gain', 1.5, [-8, 8]]],
    scale: 1,
    examples: [
        [0.25, 1, 1, 1, 1.01, 1],
        [0.25, 3, 1, 6, 1.01, 1]
    ]
};

export const HybridMultiFractal = {
    glsl: 'hybridMultiFractal',
    params: [['float', 'H', 0.25, [0, 8]], ['float', 'lacunarity', 3, [0, 8]], ['float', 'frequency', 2, [0, 8]], ['float', 'octaves', 6, [1, 12]], ['float', 'offset', .05, [-2, 2]]],
    normalized: false,
    scale: 1,
    examples: [
        [0.1, 1.5, 3, 6, 0]
    ]
};

export const HeteroTerrain = {
    glsl: 'heteroTerrainA',
    params: [['float', 'H', 0.5, [0.01, 3]], ['float', 'lacunarity', 2, [1, 3]], ['float', 'frequency', 2, [1, 8]], ['float', 'octaves', 6, [1, 8]], ['float', 'offset', .05, [-1, 1]]],
    normalized: false,
    scale: 1,
    examples: [
        [2, 1.5, 3, 2, 0]
    ]
};

export const MultiFractal = {
    glsl: 'multifractalA',
    params: [
        ['float', 'H', 0.5, [0.01, 2]],
        ['float', 'lacunarity', 2, [1, 2]],
        ['float', 'frequency', 2, [1, 8]],
        ['float', 'octaves', 6, [1, 8]],
        ['float', 'offset', .8, [-1, 1]],
        ['float', 'noise', null, null, 'snoise', [['vec2', POS]]]
    ],
    scale: 1,
    examples: [
        [1.5, 1.5, 4, 6, 0.85]
    ]
};

export const FBm = {
    glsl: 'fBmA',
    params: [['float', 'H', 0.5, [0, 8]], ['float', 'lacunarity', 2, [0, 8]], ['float', 'frequency', 2, [0, 8]], ['float', 'octaves', 6, [1, 12]]],
    normalized: false,
    scale: 1,
    examples: [
        [0.85, 2.5, 4, 6]
    ]
};

export let RGB = {
    glsl: 'vec3',
    color: true,
    position: false,
    params: [['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]]]
};

export let HSV = {
    glsl: 'HSV',
    color: true,
    position: false,
    params: [['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]], ['float', VALUE, 1, [0, 1]]],
};
<|endoftext|>


<commit_before>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2013 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with this program.  If not, see http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

describe('set focus', function () {
  var element , scope, compile, timeout, inputVisibleEnable, inputInvisible, inputDisable;

  beforeEach(module('rnr'));
  beforeEach(inject(function ($compile, $rootScope, $timeout) {
    element = angular.element('

');
    inputVisibleEnable = angular.element('<input type="text">');
    inputInvisible = angular.element('<input type="text" style="display: none">');
    inputDisable = angular.element('<input type="text" disabled>');

    scope = $rootScope.$new();
    compile = $compile;
    timeout = $timeout;
    element.append(inputDisable);
    element.append(inputInvisible);
    element.append(inputVisibleEnable);
    compile(element)(scope);
    angular.element(document.body).append(element);
  }));
  afterEach(function () {
    element.remove()
  });

  it('should focus on the first enabled input field', function () {
    timeout.flush();
    expect($(inputVisibleEnable).is(':focus')).toBeTruthy();
  });

  it('should focus on the first enabled input field on click of an element', function () {
    element.trigger('click');
    expect($(inputVisibleEnable).is(':focus')).toBeTruthy();
  });
});<commit_msg>|#000| mocking Jquery Selector.<commit_after>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2013 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with this program.  If not, see http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

describe('set focus', function () {
  var element , scope, compile, timeout, inputVisibleEnable, inputInvisible, inputDisable, jQuerySelector,
    firstVisibleEnabledElement, spyFocus;

  beforeEach(module('rnr'));
  beforeEach(inject(function ($compile, $rootScope, $timeout) {
    element = angular.element('

');
    inputVisibleEnable = angular.element('<input type="text">');
    inputInvisible = angular.element('<input type="text" style="display: none">');
    inputDisable = angular.element('<input type="text" disabled>');

    scope = $rootScope.$new();
    compile = $compile;
    timeout = $timeout;
    element.append(inputDisable);
    element.append(inputInvisible);
    element.append(inputVisibleEnable);
    compile(element)(scope);

    jQuerySelector = spyOn(window, "$").andCallFake(function (selector) {
      switch (selector) {
        case "input[type='text']:visible:enabled":
          return element;
          break;
      }
    });
    firstVisibleEnabledElement = spyOn(element, 'first').andReturn(inputVisibleEnable);
    spyFocus = spyOn(inputVisibleEnable, 'focus').andCallFake(function () {
    });

  }));
  afterEach(function () {
    element.remove()
  });

  it('should focus on the first enabled input field on timeout', function () {
    timeout.flush();

    expect(jQuerySelector).toHaveBeenCalledWith("input[type='text']:visible:enabled");
    expect(firstVisibleEnabledElement).toHaveBeenCalled();
    expect(spyFocus).toHaveBeenCalled()
  });

  it('should focus on the first enabled input field on click of an element', function () {
    element.trigger('click');

    expect(jQuerySelector).toHaveBeenCalledWith("input[type='text']:visible:enabled");
    expect(firstVisibleEnabledElement).toHaveBeenCalled();
    expect(spyFocus).toHaveBeenCalled()
  });
});<|endoftext|>


<commit_before>'use strict';
/*jshint asi: true */

var test = require('tape')

var fs = require('fs');
var path = require('path');
var asyncReduce = require('../');

if (typeof window === 'undefined') {
  test('\nreducing files to a hash with their modes', function (t) {
    t.plan(2)
    asyncReduce(
        [ 'test', 'examples', '.travis.yml', 'index.js' ]
      , {}
      , function size (acc, file, cb) {
          var p = path.join(__dirname, '..', file);

          fs.stat(p, function (err, stat) {
            if (err) return cb(err);

            acc[file] = (stat.mode + '').slice(0, 2)
            cb(null, acc);
          });
        }
      , function done (err, acc) {
          t.notOk(err, 'no error')
          t.deepEqual(
              acc
            , { test: '16',
                examples: '16',
                '.travis.yml': '33',
                'index.js': '33' }
          )
        }
    )
  })
}

test('\nsimulate reducing files to a hash with their modes', function (t) {
  t.plan(2)
  var sizes = {
    test          :  16877,
    examples      :  16877,
    '.travis.yml' :  33188,
    'index.js'    :  33188 }

  asyncReduce(
      [ 'test', 'examples', '.travis.yml', 'index.js' ]
    , {}
    , function size (acc, file, cb) {
        var fileSize = sizes[file]
        acc[file] = fileSize;
        setTimeout(cb.bind(null, null, acc), 5);
      }
    , function done (err, acc) {
        t.notOk(err, 'no error')
        t.deepEqual(
            acc
          , { test: 16877,
              examples: 16877,
              '.travis.yml': 33188,
              'index.js': 33188 }
        )
      }
  )
})

var validIterator = function (acc, item, cb) {}
var validDone = function (err, acc) {}
var seed = ''

test('\nargument validation', function (t) {
  t.throws(
      function () { asyncReduce(1, seed, validIterator, validDone) }
    , /must be an Array/
  )
  t.throws(
      function () { asyncReduce([1, 2], seed, '', validDone) }
    , /iterator must be a function/
  )
  t.throws(
      function () { asyncReduce([1, 2], seed, validIterator, '') }
    , /done must be a function/
  )
  t.end()
})
<commit_msg>checking for process.browser instead of window to ensure we don't run server side tests in browser<commit_after>'use strict';
/*jshint asi: true */

var test = require('tape')

var fs = require('fs');
var path = require('path');
var asyncReduce = require('../');

if (!process.browser) {
  test('\nreducing files to a hash with their modes', function (t) {
    t.plan(2)
    asyncReduce(
        [ 'test', 'examples', '.travis.yml', 'index.js' ]
      , {}
      , function size (acc, file, cb) {
          var p = path.join(__dirname, '..', file);

          fs.stat(p, function (err, stat) {
            if (err) return cb(err);

            acc[file] = (stat.mode + '').slice(0, 2)
            cb(null, acc);
          });
        }
      , function done (err, acc) {
          t.notOk(err, 'no error')
          t.deepEqual(
              acc
            , { test: '16',
                examples: '16',
                '.travis.yml': '33',
                'index.js': '33' }
          )
        }
    )
  })
}

test('\nsimulate reducing files to a hash with their modes', function (t) {
  t.plan(2)
  var sizes = {
    test          :  16877,
    examples      :  16877,
    '.travis.yml' :  33188,
    'index.js'    :  33188 }

  asyncReduce(
      [ 'test', 'examples', '.travis.yml', 'index.js' ]
    , {}
    , function size (acc, file, cb) {
        var fileSize = sizes[file]
        acc[file] = fileSize;
        setTimeout(cb.bind(null, null, acc), 5);
      }
    , function done (err, acc) {
        t.notOk(err, 'no error')
        t.deepEqual(
            acc
          , { test: 16877,
              examples: 16877,
              '.travis.yml': 33188,
              'index.js': 33188 }
        )
      }
  )
})

var validIterator = function (acc, item, cb) {}
var validDone = function (err, acc) {}
var seed = ''

test('\nargument validation', function (t) {
  t.throws(
      function () { asyncReduce(1, seed, validIterator, validDone) }
    , /must be an Array/
  )
  t.throws(
      function () { asyncReduce([1, 2], seed, '', validDone) }
    , /iterator must be a function/
  )
  t.throws(
      function () { asyncReduce([1, 2], seed, validIterator, '') }
    , /done must be a function/
  )
  t.end()
})
<|endoftext|>


<commit_before>import { Tag } from "@markdoc/markdoc";

function generateID(children, attributes) {
  if (attributes.id && typeof attributes.id === "string") {
    return attributes.id;
  }

  const bottomChildren = children
    .map((child) => (child.children ? child.children : child))
    .flat();
  return bottomChildren
    .filter((child) => typeof child === "string")
    .join(" ")
    .replace(/[?]/g, "")
    .replace(/\s+/g, "-")
    .toLowerCase();
}

export const heading = {
  children: ["inline"],
  attributes: {
    id: { type: String },
    level: { type: Number, required: true, default: 1 },
  },
  transform(node, config) {
    const attributes = node.transformAttributes(config);
    const children = node.transformChildren(config);

    const id = generateID(children, attributes);

    return new Tag(
      `h${node.attributes["level"]}`,
      { ...attributes, id },
      children
    );
  },
};
<commit_msg>schema: strip special characters from section ids<commit_after>import { Tag } from "@markdoc/markdoc";

function generateID(children, attributes) {
  if (attributes.id && typeof attributes.id === "string") {
    return attributes.id;
  }

  const bottomChildren = children
    .map((child) => (child.children ? child.children : child))
    .flat();
  return bottomChildren
    .filter((child) => typeof child === "string")
    .join(" ")
    .replace(/[?:+#]/g, "")
    .replace(/\s+/g, "-")
    .toLowerCase();
}

export const heading = {
  children: ["inline"],
  attributes: {
    id: { type: String },
    level: { type: Number, required: true, default: 1 },
  },
  transform(node, config) {
    const attributes = node.transformAttributes(config);
    const children = node.transformChildren(config);

    const id = generateID(children, attributes);

    return new Tag(
      `h${node.attributes["level"]}`,
      { ...attributes, id },
      children
    );
  },
};
<|endoftext|>


<commit_before>var grape = require('grape'),
    EventEmitter = require('events').EventEmitter,
    requestData = require('../');

function createFakeRequest(data, contentType){
    var request = new EventEmitter();

    request.headers = {
            'content-type': contentType || ''
    };

    request.connection = {
        destroy: function(){}
    };

    process.nextTick(function(){
        if(data){
            request.emit('data', data);
        }

        process.nextTick(function(){
            request.emit('end');
        });
    });
    return request;
}

grape('get data', function(t){
    t.plan(1);

    var responseData = {thing:'stuff'};

    var handler = requestData(function(request, response, data){
        t.deepEqual(data, responseData);
    });

    handler(
        createFakeRequest(
            JSON.stringify(responseData)
        ),
        {}
    );
});

grape('get form data', function(t){
    t.plan(1);

    var formData = 'thing=stuff&dingle=berry',
        responseData = {
            thing: 'stuff',
            dingle: 'berry'
        },
        contentType = 'application/x-www-form-urlencoded';

    var handler = requestData(function(request, response, data){
       t.deepEqual(data, responseData);
    });

    handler(
        createFakeRequest(
            formData,
            contentType
        ),
        {}
    );
});

grape('get form data', function(t){
    t.plan(1);

    var responseData = {
            thing: 'stuff',
            dingle: 'berry'
        },
        contentType = 'application/json';

    var handler = requestData(function(request, response, data){
       t.deepEqual(data, responseData);
    });

    handler(
        createFakeRequest(
            JSON.stringify(responseData),
            contentType
        ),
        {}
    );
});

grape('get bad data', function(t){
    t.plan(1);

    var handler = requestData(function(request, response, data){
        t.ok(data instanceof Error);
    });

    handler(
        createFakeRequest(
            'not valid json'
        ),
        {}
    );
});

grape('get no data', function(t){
    t.plan(1);

    var handler = requestData(function(request, response, data){
        t.equal(data, undefined);
    });

    handler(
        createFakeRequest(),
        {}
    );
});<commit_msg>named get json test<commit_after>var grape = require('grape'),
    EventEmitter = require('events').EventEmitter,
    requestData = require('../');

function createFakeRequest(data, contentType){
    var request = new EventEmitter();

    request.headers = {
            'content-type': contentType || ''
    };

    request.connection = {
        destroy: function(){}
    };

    process.nextTick(function(){
        if(data){
            request.emit('data', data);
        }

        process.nextTick(function(){
            request.emit('end');
        });
    });
    return request;
}

grape('get data', function(t){
    t.plan(1);

    var responseData = {thing:'stuff'};

    var handler = requestData(function(request, response, data){
        t.deepEqual(data, responseData);
    });

    handler(
        createFakeRequest(
            JSON.stringify(responseData)
        ),
        {}
    );
});

grape('get form data', function(t){
    t.plan(1);

    var formData = 'thing=stuff&dingle=berry',
        responseData = {
            thing: 'stuff',
            dingle: 'berry'
        },
        contentType = 'application/x-www-form-urlencoded';

    var handler = requestData(function(request, response, data){
       t.deepEqual(data, responseData);
    });

    handler(
        createFakeRequest(
            formData,
            contentType
        ),
        {}
    );
});

grape('get json data', function(t){
    t.plan(1);

    var responseData = {
            thing: 'stuff',
            dingle: 'berry'
        },
        contentType = 'application/json';

    var handler = requestData(function(request, response, data){
       t.deepEqual(data, responseData);
    });

    handler(
        createFakeRequest(
            JSON.stringify(responseData),
            contentType
        ),
        {}
    );
});

grape('get bad data', function(t){
    t.plan(1);

    var handler = requestData(function(request, response, data){
        t.ok(data instanceof Error);
    });

    handler(
        createFakeRequest(
            'not valid json'
        ),
        {}
    );
});

grape('get no data', function(t){
    t.plan(1);

    var handler = requestData(function(request, response, data){
        t.equal(data, undefined);
    });

    handler(
        createFakeRequest(),
        {}
    );
});<|endoftext|>


<commit_before>const test = require('tape')
const r = require('..')

test('createAction', t => {
  // action name
  t.throws(() => { r.createAction() }, 'action name should be present')
  t.throws(() => { r.createAction(1) }, 'action name should be a string')
  t.throws(() => { r.createAction('') }, 'action name cannot be a empty string')
  // action roles
  t.throws(() => { r.createAction('e', {roles: 1}) }, 'action roles should be an array (num)')
  t.throws(() => { r.createAction('e', {roles: {}}) }, 'action roles should be an array (obj)')
  t.throws(() => { r.createAction('e', {roles: ''}) }, 'action roles should be an array (str)')
  t.throws(
    () => { r.createAction('e', {roles: [1]}) },
    'action roles should be an array of strings (arr with wrong types inside, numbers)'
  )
  t.throws(
    () => { r.createAction('e', {roles: [{}]}) },
    'action roles should be an array of strings (arr with wrong types inside, object)'
  )
  t.doesNotThrow(
    () => { r.createAction('rr1', {roles: []}) }, 'action roles should be an array (arr)'
  )
  t.doesNotThrow(
    () => { r.createAction('rr2', {roles: ['role1', 'role2']}) },
    'action roles should be an array of strings'
  )
  // action levels
  t.throws(() => { r.createAction('e', {level: 's'}) }, 'action level should be an number (str)')
  t.throws(() => { r.createAction('e', {level: {}}) }, 'action level should be an number (obj)')
  t.throws(() => { r.createAction('e', {level: []}) }, 'action level should be an number (obj)')
  t.doesNotThrow(() => { r.createAction('rl1', {level: 0}) }, 'action level should be an number')
  t.doesNotThrow(() => { r.createAction('rl2', {level: 99}) }, 'action level should be an number')
  t.end()
})

test('can', t => {
  // with roles
  r.createAction('testRoles', {roles: ['admin', 'other']})
  t.ok(r.can('admin', 'testRoles'), 'can: check roles')
  t.ok(r.can('other', 'testRoles'), 'can: check roles')
  t.notOk(r.can('another', 'testRoles'), 'can: check roles')
  // with levels
  r.createAction('testLevel', {level: 2})
  t.ok(r.can(0, 'testLevel'), 'can: check level true')
  t.notOk(r.can(3, 'testLevel'), 'can: check level false')
  // type checking
  t.throws(() => r.can('asdfasdf', 'asdf'), 'check the action to exists')
  t.throws(() => r.can('asdfasdf', []), 'check the action type')
  t.end()
})

test('revoke', t => {
  r.createAction('forRevoke', {roles: ['uno']})
  t.ok(r.can('uno', 'forRevoke'), 'pretest revoke role permission')
  r.revoke('forRevoke', 'uno')
  t.notOk(r.can('uno', 'forRevoke'), 'revoke role permission')
  t.end()
})
<commit_msg>New: Add ‘can’ test to check level<commit_after>const test = require('tape')
const r = require('..')

test('createAction', t => {
  // action name
  t.throws(() => { r.createAction() }, 'action name should be present')
  t.throws(() => { r.createAction(1) }, 'action name should be a string')
  t.throws(() => { r.createAction('') }, 'action name cannot be a empty string')
  // action roles
  t.throws(() => { r.createAction('e', {roles: 1}) }, 'action roles should be an array (num)')
  t.throws(() => { r.createAction('e', {roles: {}}) }, 'action roles should be an array (obj)')
  t.throws(() => { r.createAction('e', {roles: ''}) }, 'action roles should be an array (str)')
  t.throws(
    () => { r.createAction('e', {roles: [1]}) },
    'action roles should be an array of strings (arr with wrong types inside, numbers)'
  )
  t.throws(
    () => { r.createAction('e', {roles: [{}]}) },
    'action roles should be an array of strings (arr with wrong types inside, object)'
  )
  t.doesNotThrow(
    () => { r.createAction('rr1', {roles: []}) }, 'action roles should be an array (arr)'
  )
  t.doesNotThrow(
    () => { r.createAction('rr2', {roles: ['role1', 'role2']}) },
    'action roles should be an array of strings'
  )
  // action levels
  t.throws(() => { r.createAction('e', {level: 's'}) }, 'action level should be an number (str)')
  t.throws(() => { r.createAction('e', {level: {}}) }, 'action level should be an number (obj)')
  t.throws(() => { r.createAction('e', {level: []}) }, 'action level should be an number (obj)')
  t.doesNotThrow(() => { r.createAction('rl1', {level: 0}) }, 'action level should be an number')
  t.doesNotThrow(() => { r.createAction('rl2', {level: 99}) }, 'action level should be an number')
  t.end()
})

test('can', t => {
  // with roles
  r.createAction('testRoles', {roles: ['admin', 'other']})
  t.ok(r.can('admin', 'testRoles'), 'can: check roles')
  t.ok(r.can('other', 'testRoles'), 'can: check roles')
  t.notOk(r.can('another', 'testRoles'), 'can: check roles')
  // with levels
  r.createAction('testLevel', {level: 2})
  t.ok(r.can(0, 'testLevel'), 'can: check level true')
  t.ok(r.can(2, 'testLevel'), 'can: check level true')
  t.notOk(r.can(3, 'testLevel'), 'can: check level false')
  // type checking
  t.throws(() => r.can('asdfasdf', 'asdf'), 'check the action to exists')
  t.throws(() => r.can('asdfasdf', []), 'check the action type')
  t.end()
})

test('revoke', t => {
  r.createAction('forRevoke', {roles: ['uno']})
  t.ok(r.can('uno', 'forRevoke'), 'pretest revoke role permission')
  r.revoke('forRevoke', 'uno')
  t.notOk(r.can('uno', 'forRevoke'), 'revoke role permission')
  t.end()
})
<|endoftext|>


<commit_before>var lastAnimateTime = +new Date;
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
    //一般集中在25毫秒，左右相差不超过1毫秒
    var currentTime = +new Date;
    var deltaTime = currentTime - lastAnimateTime > 16 ? 0 : currentTime % 16;
    lastAnimateTime = deltaTime + currentTime;
    return setTimeout(callback, deltaTime);
};<commit_msg>解决无法在Nodejs环境下运行的问题<commit_after>var lastAnimateTime = +new Date;
var window = this;
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
    //一般集中在25毫秒，左右相差不超过1毫秒
    var currentTime = +new Date;
    var deltaTime = currentTime - lastAnimateTime > 16 ? 0 : currentTime % 16;
    lastAnimateTime = deltaTime + currentTime;
    return setTimeout(callback, deltaTime);
};<|endoftext|>