<commit_before>'use strict';

module.exports = function(grunt) {
    /**
     * Override task "global" options with target-specific configuration.
     */
    var targetConfigOverride = function(options, targetConfig) {
        var config = [];
        Object.keys(options).forEach(function(attr) {
            config[attr] = targetConfig[attr] ? targetConfig[attr] : options[attr];
        });

        return config;
    }

    /**
     * Validates configuration options.
     */
    var validateConfig = function(config) {
        // Minimally validate all options.
        // Format will be handled by the Redbot utility itself.
        var severity = ['noFail', 'warning', 'bad'];
        if (config.severity == undefined || severity.indexOf(config.severity) < 0 ) {
            grunt.warning('Severity currently set to "' + config.severity + '" and must be set to a valid value: ' + severity.join(', '));
        }
        if (config.bin == undefined) {
            grunt.warning('You have overridden the path to redbot with an invalid substitute.');
        }
        if (config.severity != 'noFail' && config.format != 'har') {
            grunt.verbose.writeln('Severity option is skipped unless format is set to "har".'.yellow);
        }
    }

    grunt.registerMultiTask('redbot', 'Test HTTP implementation using redbot validator.', function() {
        var options = this.options({
            assets: false,
            bin: 'redbot',
            format: 'txt',
            severity: 'noFail'
        });
        var config = targetConfigOverride(options, this.data);
        validateConfig(config);

        if (this.data.uri == undefined) {
            grunt.warning('You must specify at least one URI for redbot to process.');
        }
        // Post-process URIs
        if (!(this.data.uri instanceof Array)) {
            this.data.uri = [this.data.uri];
        }
        var uris = this.data.uri;

        var done = this.async();
        var exec = require('child_process').exec;
        uris.forEach(function(uri) {
            var args = [uri, '-o ' + config.format];
            if (config.assets) {
                args.push('-a');
            }
            var cmd = config.bin + ' ' + args.join(' ');
            grunt.verbose.writeln(('Exec: ' + cmd).cyan);
            var res = exec(cmd, null, function(error, result, code) {
                if (error) {
                    grunt.warn('exec error: ' + error)
                    return done(error);
                }
                if (config.format == 'har') {
                    result = JSON.parse(result);
                    var code = result.log.entries[0].response.status;
                    if (code >= 300) {
                        grunt.log.writeln(('Your redbot test received a response with the code HTTP ' + code).yellow);
                    }
                }
                grunt.log.subhead(('Redbot Response for "' + uri + '"').underline);
                grunt.log.writeln(result);
                // Setting the timeout seems to give the process sufficient time to print the buffer.
                // Not sure which step of the pipeline (request, processing, print) needs this time, so making it
                // a configurable in case it needs to vary by project.
                setTimeout(function() {
                    done();
                }, config.timeout || 50);
            });
        });
    });
}<commit_msg>Further refactoring into more testable code.<commit_after>'use strict';

module.exports = function(grunt) {

    grunt.registerMultiTask('redbot', 'Test HTTP implementation using redbot validator.', function() {
        var options = this.options({
            assets: false,
            bin: 'redbot',
            format: 'txt',
            severity: 'noFail'
        });
        var config = targetConfigOverride(options, this.data);
        validateConfig(config);

        if (this.data.uri == undefined) {
            grunt.warning('You must specify at least one URI for redbot to process.');
        }
        // Post-process URIs
        if (!(this.data.uri instanceof Array)) {
            this.data.uri = [this.data.uri];
        }
        var uris = this.data.uri;
        var done = this.async();

        uris.forEach(function(uri) {
            var args = [uri, '-o ' + config.format];
            if (config.assets) {
                args.push('-a');
            }
            var cmd = config.bin + ' ' + args.join(' ');
            redbot(cmd, uri, config, done);
        });
    });

    /**
     * Runs the redbot commandline with the provided arguments.
     */
    var redbot = function(cmd, uri, config, done) {
        var exec = require('child_process').exec;
        grunt.verbose.writeln(('Exec: ' + cmd).cyan);
        var res = exec(cmd, null, function(error, result, code) {
            if (error) {
                grunt.warn('exec error: ' + error)
                return done(error);
            }
            if (config.format == 'har') {
                result = JSON.parse(result);
                validateHttpResponse(result.log.entries[0].response);
            }
            grunt.log.subhead(('Redbot Response for "' + uri + '"').underline);
            grunt.log.writeln(result);
            // Setting the timeout seems to give the process sufficient time to
            // print the buffer. Not sure which step of the pipeline (request,
            // processing, print) needs this time, so making it a configurable
            // in case it needs to vary by project.
            setTimeout(function() {
                done();
            }, config.timeout || 50);
        });
    }

    /**
     * Validates the HTTP response contained in the Redbot HAR file.
     */
    var validateHttpResponse = function(response) {
        var code = response.status;
        if (code >= 300) {
            // Only a printed warning, as a 'bad' response may be the purpose
            // of a specific URL test. However, if you expect it to be a good
            // response, some indicator of broken test validity seems critical
            // to avoid pending insanity.
            grunt.log.writeln(('Your redbot test received a response with the code HTTP ' + code).yellow);
        }

        return code;
    }

    /**
     * Override task "global" options with target-specific configuration.
     */
    var targetConfigOverride = function(options, targetConfig) {
        var config = [];
        Object.keys(options).forEach(function(attr) {
            config[attr] = targetConfig[attr] ? targetConfig[attr] : options[attr];
        });

        return config;
    }

    /**
     * Validates configuration options.
     *
     * Format will be handled by the Redbot utility itself.
     */
    var validateConfig = function(config) {
        var severity = ['noFail', 'warning', 'bad'];
        if (config.severity == undefined || severity.indexOf(config.severity) < 0 ) {
            grunt.warning('Severity currently set to "' + config.severity + '" and must be set to a valid value: ' + severity.join(', '));
        }
        if (config.bin == undefined) {
            grunt.warning('You have overridden the path to redbot with an invalid substitute.');
        }
        if (config.severity != 'noFail' && config.format != 'har') {
            grunt.verbose.writeln('Severity option is skipped unless format is set to "har".'.yellow);
        }

        return true;
    }
}
{'fraction_non_alphanumeric': 0.12076129205200375, 'fraction_numerical': 0.0018764240718402358, 'mean_word_length': 1.7812150577711516, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '4844412', 'n_tokens_mistral': 2020, 'n_tokens_neox': 1930, 'n_words': 580}