<commit_before>'use strict';

/*
 * "Passing arrow functions to Mocha is discouraged" ([source][1]).
 *
 * [1]: http://mochajs.org/#arrow-functions
 */

import chai from 'chai';
import dirtyChai from 'dirty-chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';

import { Exedore } from './index';

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

describe( 'Exedore', function() {
    let container
        , deepSpy
        , wrapperFactory
        ;

    beforeEach( function() {
        container = {
            target: function() { }
        };
        deepSpy = sinon.spy( container, 'target' );
        wrapperFactory = {
            create: function () {
                return ( ( target, args = [ ] ) => {
                    // Test that the arguments are the correct types
                    expect( typeof target ).to.equal( 'function' );
                    expect( Array.isArray( args ) ).to.be.true();
                    target.apply( this, args );
                } );
            }
        };
    } );

    describe( 'has a function `around( functionName, advice, targetObject )` that', function() {

        it( 'causes a call to the target function to execute the advice', function() {
            let wrapper = sinon.spy();
            Exedore.around( 'target', wrapper, container );

            container.target();
            expect( wrapper ).to.have.been.calledOnce();
        } );

        it( 'allows the advice to wrap a call the target', function() {
            let wrapper = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper, container );

            // Test assumptions before going into the real test
            expect( wrapper === deepSpy ).to.be.false();
            expect( typeof wrapper ).to.equal( 'function' );
            expect( typeof container.target ).to.equal( 'function' );

            // This is the real test
            container.target( 'what' );
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

        it( 'can chain, with the last one set up being executed around the others', function() {
            let wrapper1 = sinon.spy( wrapperFactory.create() );
            let wrapper2 = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper1, container );
            Exedore.around( 'target', wrapper2, container );
            expect( wrapper1 === wrapper2 ).to.be.false();

            container.target();
            expect( wrapper2 ).to.have.been.calledOnce();
            expect( wrapper1 ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
            expect( wrapper2 ).to.have.been.calledBefore( wrapper1 );
        } );

        it( 'allows the advice to pass the normal arguments to the target', function() {
            let wrapper = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper, container );

            let arg0 = 'happy';
            let arg1 = 42;
            container.target( arg0, arg1 );
            expect( deepSpy ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledWithExactly( arg0, arg1 );
        } );

        it( 'can chain and pass arguments down the chain', function() {
            let wrapper1 = sinon.spy( wrapperFactory.create() );
            let wrapper2 = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper1, container );
            Exedore.around( 'target', wrapper2, container );
            expect( wrapper1 === wrapper2 ).to.be.false();

            let arg0 = 'happy';
            let arg1 = 42;
            container.target( arg0, arg1 );
            expect( wrapper2 ).to.have.been.calledOnce();
            expect( wrapper1 ).to.have.been.calledOnce();
            expect( wrapper2 ).to.have.been.calledBefore( wrapper1 );
            expect( deepSpy ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledWithExactly( arg0, arg1 );
        } );

        it( 'makes the target\'s return value available to the advice', function() {
            // Secret is an integer between 0 and 999,999
            let secret = Math.floor( Math.random() * 1000000 );
            let returnValue = {
                type: 'secret',
                data: {
                    name: '<NAME>',
                    number: secret
                }
            };
            container.target = function() {
                return returnValue
            };
            deepSpy = sinon.spy( container, 'target' );

            let wrapper = sinon.spy( ( target, args = [ ] ) => {
                // Test that the arguments are the correct types
                expect( typeof target ).to.equal( 'function' );
                expect( Array.isArray( args ) ).to.be.true();
                let result = target.apply( this, args );
                expect( result ).to.deep.equal( returnValue );
            } );
            Exedore.around( 'target', wrapper, container );

            container.target();
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

        it( 'executes the target function in the context of its object', function() {
            let _self = null;
            class TargetClass {
                constructor() {
                    _self = this;
                }

                targetFunction() {
                    expect( _self instanceof TargetClass ).to.be.true();
                    expect( this instanceof TargetClass ).to.be.true();
                    expect( this ).to.equal( _self );
                }
            }

            // Use old school function declaration, so that `this` is not
            // lexically bound to the context of this testing function
            let wrapper = sinon.spy( function ( target, args = [ ] ) {
                // Test that the arguments are the correct types
                expect( typeof target ).to.equal( 'function' );
                expect( Array.isArray( args ) ).to.be.true();
                // expect( this instanceof TargetClass ).to.be.true();
                target.apply( this, args );
            } );

            let instance = new TargetClass();
            deepSpy = sinon.spy( instance, 'targetFunction' );
            Exedore.around( 'targetFunction', wrapper, instance );

            instance.targetFunction();
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

        it( 'executes the advice in the context of the target\'s object', function() {
            let _self = null;
            class TargetClass {
                constructor() {
                    _self = this;
                }

                targetFunction() { }
            }

            let wrapper = sinon.spy( function( target, args = [ ] ) {
                expect( this instanceof TargetClass ).to.be.true();
                expect( this ).to.equal( _self );

                target.apply( this, args );
            } );

            let instance = new TargetClass();
            deepSpy = sinon.spy( instance, 'targetFunction' );
            Exedore.around( 'targetFunction', wrapper, instance );

            instance.targetFunction();
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

    } );

    describe( 'has a function `next( context, function, args )` that', function() {

        it( 'calls the passed-in function', function() {
            let target = sinon.spy( function() { return 1; } );
            Exedore.next( this, target );
            expect( target ).to.be.calledOnce();
        } );

        it( 'passes the arguments in `args` to the passed-in function' );
        it( 'returns the value from the passed-in function' );<commit_msg>Test that "next" correctly passes arguments to the function<commit_after>'use strict';

/*
 * "Passing arrow functions to Mocha is discouraged" ([source][1]).
 *
 * [1]: http://mochajs.org/#arrow-functions
 */

import chai from 'chai';
import dirtyChai from 'dirty-chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';

import { Exedore } from './index';

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

describe( 'Exedore', function() {
    let container
        , deepSpy
        , wrapperFactory
        ;

    beforeEach( function() {
        container = {
            target: function() { }
        };
        deepSpy = sinon.spy( container, 'target' );
        wrapperFactory = {
            create: function () {
                return ( ( target, args = [ ] ) => {
                    // Test that the arguments are the correct types
                    expect( typeof target ).to.equal( 'function' );
                    expect( Array.isArray( args ) ).to.be.true();
                    target.apply( this, args );
                } );
            }
        };
    } );

    describe( 'has a function `around( functionName, advice, targetObject )` that', function() {

        it( 'causes a call to the target function to execute the advice', function() {
            let wrapper = sinon.spy();
            Exedore.around( 'target', wrapper, container );

            container.target();
            expect( wrapper ).to.have.been.calledOnce();
        } );

        it( 'allows the advice to wrap a call the target', function() {
            let wrapper = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper, container );

            // Test assumptions before going into the real test
            expect( wrapper === deepSpy ).to.be.false();
            expect( typeof wrapper ).to.equal( 'function' );
            expect( typeof container.target ).to.equal( 'function' );

            // This is the real test
            container.target( 'what' );
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

        it( 'can chain, with the last one set up being executed around the others', function() {
            let wrapper1 = sinon.spy( wrapperFactory.create() );
            let wrapper2 = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper1, container );
            Exedore.around( 'target', wrapper2, container );
            expect( wrapper1 === wrapper2 ).to.be.false();

            container.target();
            expect( wrapper2 ).to.have.been.calledOnce();
            expect( wrapper1 ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
            expect( wrapper2 ).to.have.been.calledBefore( wrapper1 );
        } );

        it( 'allows the advice to pass the normal arguments to the target', function() {
            let wrapper = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper, container );

            let arg0 = 'happy';
            let arg1 = 42;
            container.target( arg0, arg1 );
            expect( deepSpy ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledWithExactly( arg0, arg1 );
        } );

        it( 'can chain and pass arguments down the chain', function() {
            let wrapper1 = sinon.spy( wrapperFactory.create() );
            let wrapper2 = sinon.spy( wrapperFactory.create() );
            Exedore.around( 'target', wrapper1, container );
            Exedore.around( 'target', wrapper2, container );
            expect( wrapper1 === wrapper2 ).to.be.false();

            let arg0 = 'happy';
            let arg1 = 42;
            container.target( arg0, arg1 );
            expect( wrapper2 ).to.have.been.calledOnce();
            expect( wrapper1 ).to.have.been.calledOnce();
            expect( wrapper2 ).to.have.been.calledBefore( wrapper1 );
            expect( deepSpy ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledWithExactly( arg0, arg1 );
        } );

        it( 'makes the target\'s return value available to the advice', function() {
            // Secret is an integer between 0 and 999,999
            let secret = Math.floor( Math.random() * 1000000 );
            let returnValue = {
                type: 'secret',
                data: {
                    name: '<NAME>',
                    number: secret
                }
            };
            container.target = function() {
                return returnValue
            };
            deepSpy = sinon.spy( container, 'target' );

            let wrapper = sinon.spy( ( target, args = [ ] ) => {
                // Test that the arguments are the correct types
                expect( typeof target ).to.equal( 'function' );
                expect( Array.isArray( args ) ).to.be.true();
                let result = target.apply( this, args );
                expect( result ).to.deep.equal( returnValue );
            } );
            Exedore.around( 'target', wrapper, container );

            container.target();
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

        it( 'executes the target function in the context of its object', function() {
            let _self = null;
            class TargetClass {
                constructor() {
                    _self = this;
                }

                targetFunction() {
                    expect( _self instanceof TargetClass ).to.be.true();
                    expect( this instanceof TargetClass ).to.be.true();
                    expect( this ).to.equal( _self );
                }
            }

            // Use old school function declaration, so that `this` is not
            // lexically bound to the context of this testing function
            let wrapper = sinon.spy( function ( target, args = [ ] ) {
                // Test that the arguments are the correct types
                expect( typeof target ).to.equal( 'function' );
                expect( Array.isArray( args ) ).to.be.true();
                // expect( this instanceof TargetClass ).to.be.true();
                target.apply( this, args );
            } );

            let instance = new TargetClass();
            deepSpy = sinon.spy( instance, 'targetFunction' );
            Exedore.around( 'targetFunction', wrapper, instance );

            instance.targetFunction();
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

        it( 'executes the advice in the context of the target\'s object', function() {
            let _self = null;
            class TargetClass {
                constructor() {
                    _self = this;
                }

                targetFunction() { }
            }

            let wrapper = sinon.spy( function( target, args = [ ] ) {
                expect( this instanceof TargetClass ).to.be.true();
                expect( this ).to.equal( _self );

                target.apply( this, args );
            } );

            let instance = new TargetClass();
            deepSpy = sinon.spy( instance, 'targetFunction' );
            Exedore.around( 'targetFunction', wrapper, instance );

            instance.targetFunction();
            expect( wrapper ).to.have.been.calledOnce();
            expect( deepSpy ).to.have.been.calledOnce();
        } );

    } );

    describe( 'has a function `next( context, function, args )` that', function() {
        let targetFunction
            , secret
            ;

        beforeEach( function() {
            targetFunction = sinon.spy( function( num ) { return num * 2 } );
            secret = Math.floor( Math.random() * 1000000 );
        } );

        it( 'calls the passed-in function', function() {
            Exedore.next( this, targetFunction );
            expect( targetFunction ).to.be.calledOnce();
        } );

        it( 'passes the arguments in `args` to the passed-in function', function () {
            Exedore.next( this, targetFunction, [ secret ] );
            expect( targetFunction ).to.be.calledOnce();
            expect( targetFunction ).to.be.calledWithExactly( secret );
        } );

        it( 'returns the value from the passed-in function' );
{'fraction_non_alphanumeric': 0.12334185225751491, 'fraction_numerical': 0.006875988803699647, 'mean_word_length': 1.6719232645098359, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1602122', 'n_tokens_mistral': 4417, 'n_tokens_neox': 4180, 'n_words': 1238}