ar
Version:
ar - Read Unix archive files.
157 lines (146 loc) • 4.87 kB
text/typescript
/// <reference path="../bower_components/DefinitelyTyped/node/node.d.ts" />
/**
* ar test runner command line utility
*/
import ar = require('../ar');
import fs = require('fs');
import path = require('path');
import util = require('util');
var glob = require('glob'),
cwd = process.cwd();
// Change to the test runner directory.
process.chdir(__dirname);
/**
* Pads the number with zeroes so it is length long as a string.
*/
function padNumber(num: number, length: number): string {
var numStr = "" + num;
while (numStr.length < length) {
numStr = "0" + numStr;
}
return numStr;
}
/**
* Appends dots to the string until it is length long.
*/
function appendDots(str: string, length: number): string {
while (str.length < length) {
str = str + ".";
}
return str;
}
class Test {
private archive: ar.Archive;
private dirPath: string;
/**
* Constructs a new unit test.
* Filename is the name of an archive file.
*/
constructor(private filename: string) {}
/**
* Compares the ar file against the real file on the hard drive.
*/
private testFile(arFile: ar.ARFile, filePath: string) {
var realFileContents: NodeBuffer = fs.readFileSync(filePath),
arFileContents: NodeBuffer = arFile.fileData(), i: number;
if (realFileContents.length !== arFileContents.length) {
throw new Error("Archive file's length does not match file: " +
arFileContents.length + " bytes vs " + realFileContents.length +
" bytes.");
}
// Compare contents, byte-by-byte. Yeah, this isn't efficient, but our tests
// are small.
for (i = 0; i < arFileContents.length; i++) {
if (arFileContents.readUInt8(i) !== realFileContents.readUInt8(i)) {
throw new Error("Archive file and file differ at byte " + i + ".");
}
}
// All good!
}
/**
* Run after archive initialization. Iterates over all of the files in the
* archive, tests each against the folder's files, and ensures that no files
* are missing.
*/
private testFiles() {
var files: string[] = fs.readdirSync(this.dirPath),
arFiles: ar.ARFile[] = this.archive.getFiles(),
i: number, file: ar.ARFile, name: string, nameIdx: number;
for (i = 0; i < arFiles.length; i++) {
file = arFiles[i];
name = file.name();
nameIdx = files.indexOf(name);
if (nameIdx === -1) {
throw new Error("Archive file contains extraneous file \"" + name + "\".");
}
this.testFile(file, path.resolve(this.dirPath, name));
// Remove this file, since we've tested it.
files.splice(nameIdx, 1);
}
if (files.length > 0) {
throw new Error("Archive file is missing the following files: " + files.toString());
}
}
/**
* Runs the test, prints out status, and returns true if it passed.
*/
public run(testNumber: number, totalTests: number): boolean {
var dirName: string;
// Outputs a 76 character-wide line, without a newline. Leaves 4 characters
// for test status.
util.print(appendDots(["[", padNumber(testNumber, 2), "/",
padNumber(totalTests, 2), "] ",
this.filename, " "].join(''), 76));
try {
this.archive = new ar.Archive(fs.readFileSync(this.filename));
dirName = path.basename(this.filename);
// Strip extension.
dirName = dirName.substr(0, dirName.length - 2);
// Strip characters after first -.
if (dirName.indexOf('-') !== -1) {
dirName = dirName.substr(0, dirName.indexOf('-'));
}
this.dirPath = path.resolve(path.dirname(this.filename), dirName);
if (!fs.existsSync(this.dirPath)) {
throw new Error("Cannot find test data in folder \"" + this.dirPath + "\"");
}
this.testFiles();
util.print("..OK\n");
return true;
} catch (e) {
util.print("FAIL\n");
console.log("\t" + e);
return false;
}
}
}
class TestSuite {
private tests: Test[] = [];
/**
* Creates a test suite for the given set of files.
*/
constructor(filenames: string[]) {
var i;
for (i = 0; i < filenames.length; i++) {
this.tests.push(new Test(filenames[i]));
}
}
/**
* Run all of the tests in the suite.
*/
public run(): void {
var i, length = this.tests.length, passed = 0;
console.log("Running " + length + " tests...");
for (i = 0; i < length; i++) {
if (this.tests[i].run(i+1, length)) passed++;
}
console.log("Tests complete! " + passed + "/" + this.tests.length + " (" + ((passed / this.tests.length)*100) + "%) passed.");
}
}
// Locate all of the archive files.
glob("*.a", function (er, files: string[]) {
if (er != null) throw er;
(new TestSuite(files)).run();
// Change back to the directory the user ran the script from.
process.chdir(cwd);
});