<commit_before>'use strict';

var _ = require('lodash');

/**
 * Serializer is a reporter that takes a stream of tests running potentially
 * in parallel and converts it to a stream of messages that seem like the tests
 * are running sequentially. It does this by delaying messages when necessary.
 *
 * This is useful for use by reporters that don't support parallelism.
 */
function Serializer(reporter) {
  this._reporter = reporter;
  // Serialized test path
  this._currentTest = null;
  // Map from serialized test path to array of suppressed messages
  this._pendingTestMessages = {};
}

Serializer.prototype._storeMessageForLater = function(serializedTestPath, message) {
  if (!this._pendingTestMessages[serializedTestPath]) {
    this._pendingTestMessages[serializedTestPath] = [];
  }

  this._pendingTestMessages[serializedTestPath].push(message);
};

/**
 * Emits pending messages for a given test and clears them from the queue.
 */
Serializer.prototype._emitPendingMessagesForTest = function(serializedTestPath) {
  var testPath = JSON.parse(serializedTestPath);
  var pendingMessages = this._pendingTestMessages[serializedTestPath];
  pendingMessages.forEach(this._reporter.gotMessage.bind(this._reporter, testPath));
  delete this._pendingTestMessages[serializedTestPath];
};

Serializer.prototype._pendingTestHasFinished = function(serializedTestPath) {
  return _.last(this._pendingTestMessages[serializedTestPath]).type === 'finish';
};

Serializer.prototype._pickNewCurrentTest = function() {
  var pendingTests = _.keys(this._pendingTestMessages);
  if (pendingTests.length === 0) {
    return;
  }

  var pendingTest = _.find(pendingTests, this._pendingTestHasFinished.bind(this)) || _.first(pendingTests);
  this._currentTest = pendingTest;
  this._emitPendingMessagesForTest(pendingTest);
};

Serializer.prototype.registerTests = function(testPaths) {
  if (this._reporter.registerTests) {
    this._reporter.registerTests(testPaths);
  }
};

Serializer.prototype.gotMessage = function(testPath, message) {
  var serializedTestPath = JSON.stringify(testPath);

  if (this._currentTest === serializedTestPath) {
    this._reporter.gotMessage(testPath, message);

    if (message.type === 'finish') {
      this._currentTest = null;
    }
  } else {
    this._storeMessageForLater(serializedTestPath, message);
  }

  if (!this._currentTest) {
    this._pickNewCurrentTest();
  }
};

Serializer.prototype.done = function() {
  _.keys(this._pendingTestMessages).forEach(this._emitPendingMessagesForTest.bind(this));

  if (this._reporter.done) {
    this._reporter.done();
  }
};

module.exports = Serializer;
<commit_msg>Serializer: Don't throw away the last test until a new one is picked<commit_after>'use strict';

var _ = require('lodash');

/**
 * Serializer is a reporter that takes a stream of tests running potentially
 * in parallel and converts it to a stream of messages that seem like the tests
 * are running sequentially. It does this by delaying messages when necessary.
 *
 * This is useful for use by reporters that don't support parallelism.
 */
function Serializer(reporter) {
  this._reporter = reporter;
  // Serialized test path
  this._currentTest = null;
  this._canPickNewTest = true;
  // Map from serialized test path to array of suppressed messages
  this._pendingTestMessages = {};
}

Serializer.prototype._storeMessageForLater = function(serializedTestPath, message) {
  if (!this._pendingTestMessages[serializedTestPath]) {
    this._pendingTestMessages[serializedTestPath] = [];
  }

  this._pendingTestMessages[serializedTestPath].push(message);
};

/**
 * Emits pending messages for a given test and clears them from the queue.
 */
Serializer.prototype._emitPendingMessagesForTest = function(serializedTestPath) {
  var testPath = JSON.parse(serializedTestPath);
  var pendingMessages = this._pendingTestMessages[serializedTestPath];
  pendingMessages.forEach(this._reporter.gotMessage.bind(this._reporter, testPath));
  delete this._pendingTestMessages[serializedTestPath];
};

Serializer.prototype._pendingTestHasFinished = function(serializedTestPath) {
  return _.last(this._pendingTestMessages[serializedTestPath]).type === 'finish';
};

Serializer.prototype._pickNewCurrentTest = function() {
  var pendingTests = _.keys(this._pendingTestMessages);
  if (pendingTests.length === 0) {
    return;
  }

  var pendingTest = _.find(pendingTests, this._pendingTestHasFinished.bind(this)) || _.first(pendingTests);
  this._currentTest = pendingTest;
  this._emitPendingMessagesForTest(pendingTest);
  this._canPickNewTest = false;
};

Serializer.prototype.registerTests = function(testPaths) {
  if (this._reporter.registerTests) {
    this._reporter.registerTests(testPaths);
  }
};

Serializer.prototype.gotMessage = function(testPath, message) {
  var serializedTestPath = JSON.stringify(testPath);

  if (this._currentTest === serializedTestPath) {
    this._reporter.gotMessage(testPath, message);

    if (message.type === 'finish') {
      this._canPickNewTest = true;
    }
  } else {
    this._storeMessageForLater(serializedTestPath, message);
  }

  if (this._canPickNewTest) {
    this._pickNewCurrentTest();
  }
};

Serializer.prototype.done = function() {
  _.keys(this._pendingTestMessages).forEach(this._emitPendingMessagesForTest.bind(this));

  if (this._reporter.done) {
    this._reporter.done();
  }
};

module.exports = Serializer;

{'fraction_non_alphanumeric': 0.1095915727222325, 'fraction_numerical': 0.00036961744594344855, 'mean_word_length': 5.033444816053512, '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': '4008456', 'n_tokens_mistral': 1548, 'n_tokens_neox': 1518, 'n_words': 340}