blob: 3b39be761b9134b9e5e575d9371575b018271081 [file] [log] [blame] [raw]
// Copyright (c) 2016, Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import path from 'path';
import approvals from 'approvals';
import { AsmParser } from '../lib/parsers/asm-parser';
import { SassAsmParser } from '../lib/parsers/asm-parser-sass';
import { VcAsmParser } from '../lib/parsers/asm-parser-vc';
import { fs, resolvePathFromTestRoot } from './utils';
approvals.mocha();
function processAsm(filename, filters) {
const file = fs.readFileSync(filename, 'utf-8');
let parser;
if (file.includes('Microsoft'))
parser = new VcAsmParser();
else if (filename.includes('sass-'))
parser = new SassAsmParser();
else {
parser = new AsmParser();
parser.binaryHideFuncRe = /^(__.*|_(init|start|fini)|(de)?register_tm_clones|call_gmon_start|frame_dummy|\.plt.*|_dl_relocate_static_pie)$/;
}
return parser.process(file, filters);
}
const casesRoot = resolvePathFromTestRoot('filters-cases');
const files = fs.readdirSync(casesRoot);
const filesInCaseDir = files.map(x => resolvePathFromTestRoot('filters-cases', x));
const cases = filesInCaseDir.filter(x => x.endsWith('.asm'));
const optionsOverride = {
forceApproveAll: false, // set to true to automatically regenerate all the cases.
blockUntilReporterExits: false,
maxLaunches: 1,
normalizeLineEndingsTo: process.platform === 'win32' ? '\r\n' : '\n',
errorOnStaleApprovedFiles: process.platform !== 'win32',
};
function testFilter(filename, suffix, filters) {
const testName = path.basename(filename + suffix);
it(testName, () => {
const result = processAsm(filename, filters);
delete result.parsingTime;
delete result.filteredCount;
approvals.verifyAsJSON(
casesRoot,
testName,
result,
optionsOverride);
}).timeout(5000); // Bump the timeout a bit so that we don't fail for slow cases
}
/*
The before() hooks on mocha are for it()s - They don't execute before the describes!
That's sad because then we can't have cases be loaded in a before() for every describe child to see.
*/
describe('Filter test cases', function () {
describe('No filters', function () {
for (const x of cases) testFilter(x, '.none', {});
});
describe('Directive filters', function () {
for (const x of cases) testFilter(x, '.directives', {directives: true});
});
describe('Directives and labels together', function () {
for (const x of cases) testFilter(x, '.directives.labels', {directives: true, labels: true});
});
describe('Directives, labels and comments', function () {
for (const x of cases) {
testFilter(x, '.directives.labels.comments', {directives: true, labels: true, commentOnly: true});
}
});
describe('Binary, directives, labels and comments', function () {
if (process.platform !== 'win32') {
for (const x of cases) {
testFilter(x, '.binary.directives.labels.comments', {
binary: true,
directives: true,
labels: true,
commentOnly: true,
});
}
}
});
describe('Binary, directives, labels, comments and library code', function () {
if (process.platform !== 'win32') {
for (const x of cases) {
if (!x.endsWith('-bin.asm')) continue;
testFilter(x, '.binary.directives.labels.comments.library', {
binary: true,
directives: true,
labels: true,
commentOnly: true,
libraryCode: true,
});
}
}
});
describe('Binary, directives, labels, comments and library code with dontMaskFilenames', function () {
if (process.platform !== 'win32') {
for (const x of cases) {
if (!x.endsWith('-bin.asm')) continue;
testFilter(x, '.binary.directives.labels.comments.library.dontMaskFilenames', {
binary: true,
directives: true,
labels: true,
commentOnly: true,
libraryCode: true,
dontMaskFilenames: true,
});
}
}
});
describe('Directives and comments', function () {
for (const x of cases) testFilter(x, '.directives.comments', {directives: true, commentOnly: true});
});
describe('Directives and library code', function () {
for (const x of cases) testFilter(x, '.directives.library', {directives: true, libraryCode: true});
});
describe('Directives, labels, comments and library code', function () {
for (const x of cases) {
testFilter(x, '.directives.labels.comments.library',
{directives: true, labels: true, commentOnly: true, libraryCode: true});
}
});
describe('Directives, labels, comments and library code with dontMaskFilenames', function () {
for (const x of cases) {
testFilter(x, '.directives.labels.comments.library.dontMaskFilenames',
{directives: true, labels: true, commentOnly: true, libraryCode: true, dontMaskFilenames: true});
}
});
});
describe('AsmParser tests', () => {
const parser = new AsmParser();
it('should identify generic opcodes', () => {
parser.hasOpcode(' mov r0, #1').should.be.true;
parser.hasOpcode(' ROL A').should.be.true;
});
it('should not identify non-opcodes as opcodes', () => {
parser.hasOpcode(' ;mov r0, #1').should.be.false;
parser.hasOpcode('').should.be.false;
parser.hasOpcode('# moose').should.be.false;
});
it('should identify llvm opcodes', () => {
parser.hasOpcode(' %i1 = phi i32 [ %i2, %.preheader ], [ 0, %bb ]').should.be.true;
});
});
describe('forceApproveAll should be false', () => {
it('should have forceApproveAll false', () => {
optionsOverride.forceApproveAll.should.be.false;
});
});