blob: a753c1c60ae781868b2ad5a76021a4027e21bbf6 [file] [log] [blame]
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Regression tests.
*/
'use strict';
const assert = require('assert');
const { execSync } = require("child_process");
const fs = require('fs');
const sinon = require('sinon');
const tempfile = require('tempfile');
const tempy = require('tempy');
const exceptions = require('../exceptions.js');
const helpers = require('./helpers.js');
const scriptMutator = require('../script_mutator.js');
const sandbox = sinon.createSandbox();
const SYNTAX_ERROR_RE = /.*SyntaxError.*/
function createFuzzTest(fake_db, settings, inputFiles) {
const sources = inputFiles.map(input => helpers.loadTestData(input));
const mutator = new scriptMutator.ScriptMutator(settings, fake_db);
const result = mutator.mutateMultiple(sources);
const output_file = tempfile('.js');
fs.writeFileSync(output_file, result.code);
return output_file;
}
function execFile(jsFile) {
execSync("node " + jsFile, {stdio: ['pipe']});
}
function buildDb(inputDir, corpusName, outputDir) {
execSync(
`node build_db.js -i ${inputDir} -o ${outputDir} ${corpusName}`,
{stdio: ['pipe']});
}
function assertFuzzWithDbThrows(dbInputDir, corpusName, settings, regexp) {
const outPath = tempy.directory();
buildDb(dbInputDir, corpusName, outPath);
settings['MUTATE_CROSSOVER_INSERT'] = 1.0;
assert.throws(
() => {
createFuzzTest(
outPath, settings,
['regress/build_db/cross_over_mutator_input.js']);
},
err => {
assert(regexp.test(err));
return true;
},
'unexpected error',
);
}
describe('Regression tests', () => {
beforeEach(() => {
helpers.deterministicRandom(sandbox);
this.settings = {
ADD_VAR_OR_OBJ_MUTATIONS: 0.0,
MUTATE_CROSSOVER_INSERT: 0.0,
MUTATE_EXPRESSIONS: 0.0,
MUTATE_FUNCTION_CALLS: 0.0,
MUTATE_NUMBERS: 0.0,
MUTATE_VARIABLES: 0.0,
engine: 'V8',
testing: true,
}
});
afterEach(() => {
sandbox.restore();
});
it('combine strict and with', () => {
// Test that when a file with "use strict" is used in the inputs,
// the result is only strict if no other file contains anything
// prohibited in strict mode (here a with statement).
// It is assumed that such input files are marked as sloppy in the
// auto generated exceptions.
sandbox.stub(exceptions, 'getGeneratedSloppy').callsFake(
() => { return new Set(['regress/strict/input_with.js']); });
const file = createFuzzTest(
'test_data/regress/strict/db',
this.settings,
['regress/strict/input_strict.js', 'regress/strict/input_with.js']);
execFile(file);
});
it('combine strict and delete', () => {
// As above with unqualified delete.
sandbox.stub(exceptions, 'getGeneratedSloppy').callsFake(
() => { return new Set(['regress/strict/input_delete.js']); });
const file = createFuzzTest(
'test_data/regress/strict/db',
this.settings,
['regress/strict/input_strict.js', 'regress/strict/input_delete.js']);
execFile(file);
});
it('mutates negative value', () => {
// This tests that the combination of number, function call and expression
// mutator does't produce an update expression.
// Previously the 1 in -1 was replaced with another negative number leading
// to e.g. -/*comment/*-2. Then cloning the expression removed the
// comment and produced --2 in the end.
this.settings['MUTATE_NUMBERS'] = 1.0;
this.settings['MUTATE_FUNCTION_CALLS'] = 1.0;
this.settings['MUTATE_EXPRESSIONS'] = 1.0;
const file = createFuzzTest(
'test_data/regress/numbers/db',
this.settings,
['regress/numbers/input_negative.js']);
execFile(file);
});
it('mutates indices', () => {
// Test that indices are not replaced with a negative number causing a
// syntax error (e.g. {-1: ""}).
this.settings['MUTATE_NUMBERS'] = 1.0;
const file = createFuzzTest(
'test_data/regress/numbers/db',
this.settings,
['regress/numbers/input_indices.js']);
execFile(file);
});
it('create call expression', () => {
// TODO(machenbach): Build_db extracts a function expression without
// parentheses, re-parsing this later fails in cross-over mutator.
assertFuzzWithDbThrows(
'test_data/regress/build_db',
'destructuring',
this.settings,
SYNTAX_ERROR_RE);
});
it('create assignment expression', () => {
// TODO(machenbach): Build_db extracts some assignment expressions with a
// spurious dependency. This leads to an "unknown substitution" error
// when applying the template.
assertFuzzWithDbThrows(
'test_data/regress/build_db',
'this',
this.settings,
/.*Unknown substitution.*/);
});
});