<commit_before>var createStandardErrorMessage = require('./createStandardErrorMessage');
var throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');
var makePromise = require('./makePromise');
var isPendingPromise = require('./isPendingPromise');
var oathbreaker = require('./oathbreaker');
var UnexpectedError = require('./UnexpectedError');
var testFrameworkPatch = require('./testFrameworkPatch');
var makeAndMethod = require('./makeAndMethod');
var utils = require('./utils');

module.exports = function createWrappedExpectProto(unexpected) {
    var wrappedExpectProto = {
        promise: makePromise,
        errorMode: 'default',

        equal: unexpected.equal,
        inspect: unexpected.inspect,
        createOutput: unexpected.createOutput.bind(unexpected),
        findTypeOf: unexpected.findTypeOf.bind(unexpected),
        findCommonType: unexpected.findCommonType.bind(unexpected),
        it: unexpected.it.bind(unexpected),
        diff: unexpected.diff,
        getType: unexpected.getType,
        output: unexpected.output,
        outputFormat: unexpected.outputFormat,
        format: unexpected.format,

        fail: function () {
            var args = arguments;
            var expect = this._context.expect;
            this.callInNestedContext(function () {
                expect.fail.apply(expect, args);
            });
        },
        withError: function (body, handler) {
            return oathbreaker(makePromise(body).caught(function (e) {
                throwIfNonUnexpectedError(e);
                return handler(e);
            }));
        },
        standardErrorMessage: function (output, options) {
            var that = this;
            options = typeof options === 'object' ? options : {};

            if ('omitSubject' in output) {
                options.subject = this.subject;
            }

            if (options && options.compact) {
                options.compactSubject = function (output) {
                    output.jsFunctionName(that.subjectType.name);
                };
            }
            return createStandardErrorMessage(output, that.subjectOutput, that.testDescription, that.argsOutput, options);
        },
        callInNestedContext: function (callback) {
            var that = this;
            var expect = that._context.expect;
            try {
                var result = oathbreaker(callback());
                if (isPendingPromise(result)) {
                    testFrameworkPatch.promiseCreated();
                    result = result.then(undefined, function (e) {
                        if (e && e._isUnexpected) {
                            throw new UnexpectedError(that, e);
                        }
                        throw e;
                    });
                } else if (!result || typeof result.then !== 'function') {
                    result = makePromise.resolve(result);
                }
                result.and = makeAndMethod(that.execute, that.subject);
                return result;
            } catch (e) {
                if (e && e._isUnexpected) {
                    var wrappedError = new UnexpectedError(that, e);
                    if (that._context.serializeErrorsFromWrappedExpect) {
                        expect.setErrorMessage(wrappedError);
                    }
                    throw wrappedError;
                }
                throw e;
            }
        },
        shift: function (subject, assertionIndex) {
            if (arguments.length <= 1) {
                if (arguments.length === 0) {
                    subject = this.subject;
                }
                assertionIndex = -1;
                for (var i = 0 ; i < this.assertionRule.args.length ; i += 1) {
                    if (this.assertionRule.args[i].isAssertion) {
                        assertionIndex = i;
                        break;
                    }
                }
            } else if (arguments.length === 3) {
                // The 3-argument syntax for wrappedExpect.shift is deprecated, please omit the first (expect) arg
                subject = arguments[1];
                assertionIndex = arguments[2];
            }

            if (assertionIndex !== -1) {
                var args = this.args.slice(0, assertionIndex);
                var rest = this.args.slice(assertionIndex);
                var nextArgumentType = this.findTypeOf(rest[0]);
                if (arguments.length > 1) {
                    // Legacy
                    this.argsOutput = function (output) {
                        args.forEach(function (arg, index) {
                            if (0 < index) {
                                output.text(', ');
                            }
                            output.appendInspected(arg);
                        });

                        if (args.length > 0) {
                            output.sp();
                        }
                        if (nextArgumentType.is('string')) {
                            output.error(rest[0]);
                        } else {
                            output.appendInspected(rest[0]);
                        }
                        if (rest.length > 1) {
                            output.sp();
                        }
                        rest.slice(1).forEach(function (arg, index) {
                            if (0 < index)  {
                                output.text(', ');
                            }
                            output.appendInspected(arg);
                        });
                    };
                }
                if (nextArgumentType.is('expect.it')) {
                    return rest[0](subject);
                } else if (nextArgumentType.is('string')) {
                    return this.execute.apply(this.execute, [subject].concat(rest));
                } else {
                    return subject;
                }
            } else {
                // No assertion to delegate to. Provide the new subject as the fulfillment value:
                return subject;
            }
        },
        _getSubjectType: function () {
            var subject = this.subject;
            var assertionSubjectType = this.assertionRule.subject.type;
            return utils.findFirst(unexpected.types, function (type) {
                return type.identify && type.is(assertionSubjectType) && type.identify(subject);
            });
        },
        _getArgTypes: function (index) {
            var lastIndex = this.assertionRule.args.length - 1;
            return this.args.map(function (arg, index) {
                var assertionArgType = this.assertionRule.args[Math.min(index, lastIndex)].type;
                return utils.findFirst(unexpected.types, function (type) {
                    return type.identify && type.is(assertionArgType) && type.identify(arg);
                });
            }, this);
        },
        _getAssertionIndices: function () {
            var assertionIndices = [];
            var args = this.args;
            function markAssertionIndices(assertionRule, offset) {
                if (assertionRule.args.length > 1 && assertionRule.args[assertionRule.args.length - 2].isAssertion) {
                    assertionIndices.push(offset + assertionRule.args.length - 2);
                    var assertionName = args[offset + assertionRule.args.length - 2];
                    var assertions = unexpected.assertions[assertionName];
                    if (assertions) {
                        for (var j = 0 ; j < assertions.length ; j += 1) {
                            if (assertions[j].args.some(function (a) { return a.isAssertion; })) {
                                markAssertionIndices(assertions[j], offset + assertionRule.args.length - 1);
                                break;
                            }
                        }
                    }
                }
            }
            markAssertionIndices(this.assertionRule, 0);
            return assertionIndices;
        }
    };
<commit_msg>_getAssertionIndices: Compute the indices interatively, and only compute the value once.<commit_after>var createStandardErrorMessage = require('./createStandardErrorMessage');
var throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');
var makePromise = require('./makePromise');
var isPendingPromise = require('./isPendingPromise');
var oathbreaker = require('./oathbreaker');
var UnexpectedError = require('./UnexpectedError');
var testFrameworkPatch = require('./testFrameworkPatch');
var makeAndMethod = require('./makeAndMethod');
var utils = require('./utils');

module.exports = function createWrappedExpectProto(unexpected) {
    var wrappedExpectProto = {
        promise: makePromise,
        errorMode: 'default',

        equal: unexpected.equal,
        inspect: unexpected.inspect,
        createOutput: unexpected.createOutput.bind(unexpected),
        findTypeOf: unexpected.findTypeOf.bind(unexpected),
        findCommonType: unexpected.findCommonType.bind(unexpected),
        it: unexpected.it.bind(unexpected),
        diff: unexpected.diff,
        getType: unexpected.getType,
        output: unexpected.output,
        outputFormat: unexpected.outputFormat,
        format: unexpected.format,

        fail: function () {
            var args = arguments;
            var expect = this._context.expect;
            this.callInNestedContext(function () {
                expect.fail.apply(expect, args);
            });
        },
        withError: function (body, handler) {
            return oathbreaker(makePromise(body).caught(function (e) {
                throwIfNonUnexpectedError(e);
                return handler(e);
            }));
        },
        standardErrorMessage: function (output, options) {
            var that = this;
            options = typeof options === 'object' ? options : {};

            if ('omitSubject' in output) {
                options.subject = this.subject;
            }

            if (options && options.compact) {
                options.compactSubject = function (output) {
                    output.jsFunctionName(that.subjectType.name);
                };
            }
            return createStandardErrorMessage(output, that.subjectOutput, that.testDescription, that.argsOutput, options);
        },
        callInNestedContext: function (callback) {
            var that = this;
            var expect = that._context.expect;
            try {
                var result = oathbreaker(callback());
                if (isPendingPromise(result)) {
                    testFrameworkPatch.promiseCreated();
                    result = result.then(undefined, function (e) {
                        if (e && e._isUnexpected) {
                            throw new UnexpectedError(that, e);
                        }
                        throw e;
                    });
                } else if (!result || typeof result.then !== 'function') {
                    result = makePromise.resolve(result);
                }
                result.and = makeAndMethod(that.execute, that.subject);
                return result;
            } catch (e) {
                if (e && e._isUnexpected) {
                    var wrappedError = new UnexpectedError(that, e);
                    if (that._context.serializeErrorsFromWrappedExpect) {
                        expect.setErrorMessage(wrappedError);
                    }
                    throw wrappedError;
                }
                throw e;
            }
        },
        shift: function (subject, assertionIndex) {
            if (arguments.length <= 1) {
                if (arguments.length === 0) {
                    subject = this.subject;
                }
                assertionIndex = -1;
                for (var i = 0 ; i < this.assertionRule.args.length ; i += 1) {
                    if (this.assertionRule.args[i].isAssertion) {
                        assertionIndex = i;
                        break;
                    }
                }
            } else if (arguments.length === 3) {
                // The 3-argument syntax for wrappedExpect.shift is deprecated, please omit the first (expect) arg
                subject = arguments[1];
                assertionIndex = arguments[2];
            }

            if (assertionIndex !== -1) {
                var args = this.args.slice(0, assertionIndex);
                var rest = this.args.slice(assertionIndex);
                var nextArgumentType = this.findTypeOf(rest[0]);
                if (arguments.length > 1) {
                    // Legacy
                    this.argsOutput = function (output) {
                        args.forEach(function (arg, index) {
                            if (0 < index) {
                                output.text(', ');
                            }
                            output.appendInspected(arg);
                        });

                        if (args.length > 0) {
                            output.sp();
                        }
                        if (nextArgumentType.is('string')) {
                            output.error(rest[0]);
                        } else {
                            output.appendInspected(rest[0]);
                        }
                        if (rest.length > 1) {
                            output.sp();
                        }
                        rest.slice(1).forEach(function (arg, index) {
                            if (0 < index)  {
                                output.text(', ');
                            }
                            output.appendInspected(arg);
                        });
                    };
                }
                if (nextArgumentType.is('expect.it')) {
                    return rest[0](subject);
                } else if (nextArgumentType.is('string')) {
                    return this.execute.apply(this.execute, [subject].concat(rest));
                } else {
                    return subject;
                }
            } else {
                // No assertion to delegate to. Provide the new subject as the fulfillment value:
                return subject;
            }
        },
        _getSubjectType: function () {
            var subject = this.subject;
            var assertionSubjectType = this.assertionRule.subject.type;
            return utils.findFirst(unexpected.types, function (type) {
                return type.identify && type.is(assertionSubjectType) && type.identify(subject);
            });
        },
        _getArgTypes: function (index) {
            var lastIndex = this.assertionRule.args.length - 1;
            return this.args.map(function (arg, index) {
                var assertionArgType = this.assertionRule.args[Math.min(index, lastIndex)].type;
                return utils.findFirst(unexpected.types, function (type) {
                    return type.identify && type.is(assertionArgType) && type.identify(arg);
                });
            }, this);
        },
        _getAssertionIndices: function () {
            if (!this._assertionIndices) {
                var assertionIndices = [];
                var args = this.args;
                var currentAssertionRule = this.assertionRule;
                var offset = 0;
                OUTER: while (true) {
                    if (currentAssertionRule.args.length > 1 && currentAssertionRule.args[currentAssertionRule.args.length - 2].isAssertion) {
                        assertionIndices.push(offset + currentAssertionRule.args.length - 2);
                        var assertions = unexpected.assertions[args[offset + currentAssertionRule.args.length - 2]];
                        if (assertions) {
                            for (var i = 0 ; i < assertions.length ; i += 1) {
                                if (assertions[i].args.some(function (a) { return a.isAssertion; })) {
                                    offset += currentAssertionRule.args.length - 1;
                                    currentAssertionRule = assertions[i];
                                    continue OUTER;
                                }
                            }
                        }
                    }
                    // No further assertions found,
                    break;
                }
                this._assertionIndices = assertionIndices;
            }
            return this._assertionIndices;
        }
    };

{'fraction_non_alphanumeric': 0.09857963130855243, 'fraction_numerical': 0.003626473254759746, 'mean_word_length': 1.2920072032137415, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7197535', 'n_tokens_mistral': 3977, 'n_tokens_neox': 3723, 'n_words': 792}