<commit_before>var log = require('npmlog');
var BrowserTapConsumer = require('../browser_tap_consumer');
var util = require('util');

function BrowserTestRunner(launcher, reporter, index, singleRun) {
  this.launcher = launcher;
  this.reporter = reporter;
  this.finished = false;
  this.pending = true;
  this.running = false;
  this.index = index;
  this.id = this.launcher.id;
  this.singleRun = singleRun;
}

BrowserTestRunner.prototype = {
  start: function(onFinish) {
    this.onFinish = onFinish;

    if (this.socket) {
      this.socket.emit('start-tests');
    } else {
      this.launcher.on('processExit', this.onProcessExit.bind(this));
      this.launcher.start();
    }
  },

  tryAttach: function(browser, id, socket) {
    if (id !== this.id) {
      return;
    }

    log.info('tryAttach', browser, id);

    var self = this;
    if (this.pending) {
      clearTimeout(this.pending);
    }
    this.pending = false;
    this.socket = socket;

    var runner = {
      browserName: browser,
      reporter: this.reporter,
      logs: [],
      launcherId: this.launcher.id
    };

    this.onStart.call(runner);

    var config = this.launcher.config;

    socket.on('test-result', this.onTestResult.bind(runner));

    socket.on('top-level-error', function(msg, url, line) {
      var message = msg + ' at ' + url + ', line ' + line + '\n';
      runner.logs.push({
        type: 'error',
        text: message
      });

      if (config.get('bail_on_uncaught_error')) {
        self.reporter.report(browser, {
          passed: false,
          name: 'Global error: ' + msg + ' at ' + url + ', line ' + line + '\n',
          logs: [],
          error: {}
        });
      }
    });

    var handleMessage = function(type) {
      return function(/* ...args */) {
        var args = Array.prototype.slice.call(arguments);
        var message = args.map(function(arg) {
          return util.inspect(arg);
        }).join(' ');

        runner.logs.push({
          type: type,
          text: message + '\n'
        });
      };
    };

    socket.on('error', handleMessage('error'));
    socket.on('info', handleMessage('info'));
    socket.on('warn', handleMessage('warn'));
    socket.on('log', handleMessage('log'));

    socket.on('disconnect', function() {
      browser.pending = setTimeout(function() {
        if (self.finished) {
          return;
        }

        var result = {
          passed: false,
          name: 'Browser ' + self.launcher.commandLine() + ' disconnected unexpectedly.'
        };
        self.reporter.report(self.name(), result);
        self.finish();
      }, 1000);
    });

    socket.on('all-test-results', this.onAllTestResults.bind(this));
    socket.on('all-test-results', this.onEnd.bind(runner));

    var tap = new BrowserTapConsumer(socket);
    tap.on('test-result', this.onTestResult.bind(runner));
    tap.on('all-test-results', this.onAllTestResults.bind(this));
  },<commit_msg>Prevent multiple calls to callback error<commit_after>var log = require('npmlog');
var BrowserTapConsumer = require('../browser_tap_consumer');
var util = require('util');

function BrowserTestRunner(launcher, reporter, index, singleRun) {
  this.launcher = launcher;
  this.reporter = reporter;
  this.finished = false;
  this.pending = true;
  this.running = false;
  this.index = index;
  this.id = this.launcher.id;
  this.singleRun = singleRun;
}

BrowserTestRunner.prototype = {
  start: function(onFinish) {
    this.onFinish = onFinish;

    if (this.socket) {
      this.socket.emit('start-tests');
    } else {
      this.launcher.on('processExit', this.onProcessExit.bind(this));
      this.launcher.start();
    }
  },

  tryAttach: function(browser, id, socket) {
    if (id !== this.id) {
      return;
    }

    log.info('tryAttach', browser, id);

    var self = this;
    if (this.pending) {
      clearTimeout(this.pending);
    }
    this.pending = false;
    this.socket = socket;

    var runner = {
      browserName: browser,
      reporter: this.reporter,
      logs: [],
      launcherId: this.launcher.id
    };

    this.onStart.call(runner);

    var config = this.launcher.config;

    socket.on('test-result', this.onTestResult.bind(runner));

    socket.on('top-level-error', function(msg, url, line) {
      var message = msg + ' at ' + url + ', line ' + line + '\n';
      runner.logs.push({
        type: 'error',
        text: message
      });

      if (config.get('bail_on_uncaught_error')) {
        self.reporter.report(browser, {
          passed: false,
          name: 'Global error: ' + msg + ' at ' + url + ', line ' + line + '\n',
          logs: [],
          error: {}
        });
      }
    });

    var handleMessage = function(type) {
      return function(/* ...args */) {
        var args = Array.prototype.slice.call(arguments);
        var message = args.map(function(arg) {
          return util.inspect(arg);
        }).join(' ');

        runner.logs.push({
          type: type,
          text: message + '\n'
        });
      };
    };

    socket.on('error', handleMessage('error'));
    socket.on('info', handleMessage('info'));
    socket.on('warn', handleMessage('warn'));
    socket.on('log', handleMessage('log'));

    socket.on('disconnect', function() {
      browser.pending = setTimeout(function() {
        if (self.finished) {
          return;
        }

        var result = {
          passed: false,
          name: 'Browser ' + self.launcher.commandLine() + ' disconnected unexpectedly.'
        };
        self.reporter.report(self.name(), result);
        self.finish();
      }, 1000);
    });

    socket.once('all-test-results', this.onAllTestResults.bind(this));
    socket.on('all-test-results', this.onEnd.bind(runner));

    var tap = new BrowserTapConsumer(socket);
    tap.on('test-result', this.onTestResult.bind(runner));
    tap.on('all-test-results', this.onAllTestResults.bind(this));
  },
{'fraction_non_alphanumeric': 0.1618711088675753, 'fraction_numerical': 0.0013461214874642437, 'mean_word_length': 2.4318706697459582, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '6520604', 'n_tokens_mistral': 1907, 'n_tokens_neox': 1832, 'n_words': 349}