New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

awesome-test-runner

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

awesome-test-runner - npm Package Compare versions

Comparing version 1.2.2 to 1.3.0

.github/workflows/lint-and-test.yml

3

dist/bin/handlers/run.d.ts

@@ -9,3 +9,6 @@ import yargs from 'yargs';

pattern: string;
overwrite: boolean;
clear: boolean;
}
export declare type OutputOverwriteMode = 'clear' | 'overwrite' | 'exit';
export declare function runHandler(argv: yargs.Arguments<RunArgs>): Promise<void>;

273

dist/bin/handlers/run.js

@@ -17,3 +17,3 @@ "use strict";

const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const ora_1 = __importDefault(require("ora"));

@@ -24,4 +24,60 @@ const chalk_1 = __importDefault(require("chalk"));

const promise_sequential_1 = __importDefault(require("promise-sequential"));
const enquirer_1 = __importDefault(require("enquirer"));
const index_1 = require("../../index");
const utils_1 = require("../../utils");
function exitWithError(text) {
console.error(chalk_1.default `{red {bold Error:} ${text}}`);
process.exit(1);
}
function printWarning(text) {
console.warn(chalk_1.default `{yellowBright {bold Warning:} ${text}}`);
}
function getDirOverwriteMode(argv) {
return __awaiter(this, void 0, void 0, function* () {
if (argv.clear)
return 'clear';
if (argv.overwrite)
return 'overwrite';
const answers = yield enquirer_1.default.prompt([
{
name: 'mode',
type: 'select',
message: 'The output directory is not empty. What do you want to do?',
required: true,
choices: [
{
name: 'exit',
message: 'Exit the program ',
},
{
name: 'overwrite',
message: 'Overwrite only changed files',
},
{
name: 'clear',
message: 'Remove all files and directories in output directory',
},
],
},
]);
console.log();
return answers.mode;
});
}
function confirmFileOverwrite(argv) {
return __awaiter(this, void 0, void 0, function* () {
if (argv.overwrite)
return true;
const answers = yield enquirer_1.default.prompt([
{
name: 'overwrite',
type: 'confirm',
message: 'The output file already exists, and will be overwritten. Continue?',
required: true,
},
]);
console.log();
return answers.overwrite;
});
}
function runHandler(argv) {

@@ -32,125 +88,138 @@ return __awaiter(this, void 0, void 0, function* () {

const output = path_1.default.resolve(process.cwd(), argv.output);
// Start pulling before asking to overwrite
const imagePulled = yield index_1.isImagePulled();
const pullContainerImagePromise = imagePulled ? null : index_1.pullContainerImage();
try {
yield fs_1.default.promises.lstat(code);
yield fs_extra_1.default.lstat(code);
}
catch (error) {
if (error.code === 'ENOENT')
console.error('Code file doesn\'t exist');
exitWithError('Code file doesn\'t exist');
else
console.error(error);
process.exit(1);
exitWithError(error.message);
}
let inputStats;
try {
inputStats = yield fs_1.default.promises.lstat(input);
}
catch (error) {
if (error.code === 'ENOENT')
console.error('Input file or directory doesn\'t exist');
else
console.error(error);
process.exit(1);
}
try {
const outputStats = yield fs_1.default.promises.lstat(output);
if (outputStats.isDirectory()) {
if (!inputStats.isDirectory()) {
console.error('Output is a directory, but input is a file');
process.exit(1);
inputStats = yield fs_extra_1.default.lstat(input);
try {
const outputStats = yield fs_extra_1.default.lstat(output);
if (outputStats.isDirectory()) {
if (!inputStats.isDirectory())
exitWithError('Output is a directory, but input is a file');
const files = yield fs_extra_1.default.readdir(output);
if (files.length !== 0) {
const mode = yield getDirOverwriteMode(argv);
if (mode === 'exit')
process.exit(0);
else if (mode === 'clear')
yield fs_extra_1.default.emptyDir(output);
}
}
else {
if (inputStats.isDirectory())
exitWithError('Output is a file, but input is a directory');
if (argv.clear)
printWarning(chalk_1.default.yellow('Argument --clear can only be used with a directory output'));
if (!(yield confirmFileOverwrite(argv)))
process.exit(0);
}
}
else if (inputStats.isDirectory()) {
console.error('Output is a file, but input is a directory');
process.exit(1);
catch (error) {
if (error.code === 'ENOENT') {
if (inputStats.isDirectory())
yield fs_extra_1.default.mkdir(output);
}
else
exitWithError(error.message);
}
}
catch (error) {
if (error.code === 'ENOENT') {
if (inputStats.isDirectory())
yield fs_1.default.promises.mkdir(output);
if (!imagePulled) {
try {
const pullingSpinner = ora_1.default('Pulling container').start();
yield pullContainerImagePromise;
pullingSpinner.succeed();
}
catch (error) {
exitWithError(error.message);
}
}
else {
console.error(error);
process.exit(1);
}
}
const pullingSpinner = ora_1.default('Pulling container').start();
const { upToDate } = yield index_1.pullContainerImage();
if (upToDate)
pullingSpinner.info(`Pulling container: ${chalk_1.default.blue('Already up to date')}`);
else
pullingSpinner.succeed();
const startingSpinner = ora_1.default('Starting docker container').start();
const runner = new index_1.Runner();
yield runner.start();
try {
yield runner.sendCodeFile(code);
startingSpinner.succeed();
let results;
const runSpinner = ora_1.default('Testing').start();
if (inputStats.isDirectory()) {
const files = yield utils_1.globPromise(argv.pattern, { cwd: input });
results = yield promise_sequential_1.default(files.map((file) => () => __awaiter(this, void 0, void 0, function* () {
runSpinner.text = `Testing ${chalk_1.default.cyan(file)}`;
const result = yield runner.testInputFile(path_1.default.resolve(input, file), argv.time);
const startingSpinner = ora_1.default('Starting docker container').start();
const runner = new index_1.Runner();
try {
yield runner.start();
yield runner.sendCodeFile(code);
startingSpinner.succeed();
let results;
const runSpinner = ora_1.default('Testing').start();
if (inputStats.isDirectory()) {
const files = yield utils_1.globPromise(argv.pattern, { cwd: input });
results = yield promise_sequential_1.default(files.map((file) => () => __awaiter(this, void 0, void 0, function* () {
runSpinner.text = `Testing ${chalk_1.default.cyan(file)}`;
const result = yield runner.testInputFile(path_1.default.resolve(input, file), argv.time);
if (result.type === 'success') {
yield fs_extra_1.default.writeFile(path_1.default.resolve(output, replace_ext_1.default(file, '.out')), result.output, 'utf8');
}
return Object.assign(Object.assign({}, result), { file });
})));
}
else {
const result = yield runner.testInputFile(input, argv.time);
if (result.type === 'success') {
yield fs_1.default.promises.writeFile(path_1.default.resolve(output, replace_ext_1.default(file, '.out')), result.output, 'utf8');
yield fs_extra_1.default.writeFile(output, result.output, 'utf8');
}
return Object.assign(Object.assign({}, result), { file });
})));
}
else {
const result = yield runner.testInputFile(input, argv.time);
if (result.type === 'success') {
yield fs_1.default.promises.writeFile(output, result.output, 'utf8');
results = [Object.assign(Object.assign({}, result), { file: path_1.default.basename(argv.input) })];
}
results = [Object.assign(Object.assign({}, result), { file: path_1.default.basename(argv.input) })];
}
runSpinner.succeed('Testing');
const stopSpinner = ora_1.default('Killing docker container').start();
yield runner.kill();
stopSpinner.succeed();
const resultsTable = new cli_table3_1.default({
head: [
'File',
'Status',
'Execution time',
'Error message',
],
style: {
head: ['cyan'],
},
});
resultsTable.push(...results.map((result) => {
if (result.type === 'success') {
const timeRatio = Math.min(result.time / argv.time, 0.999);
const colors = [chalk_1.default.gray, chalk_1.default.white, chalk_1.default.yellow, chalk_1.default.red];
const color = colors[Math.floor(timeRatio * colors.length)];
runSpinner.succeed('Testing');
const stopSpinner = ora_1.default('Killing docker container').start();
yield runner.kill();
stopSpinner.succeed();
const resultsTable = new cli_table3_1.default({
head: [
'File',
'Status',
'Execution time',
'Error message',
],
style: {
head: ['cyan'],
},
});
resultsTable.push(...results.map((result) => {
if (result.type === 'success') {
const timeRatio = Math.min(result.time / argv.time, 0.999);
const colors = [chalk_1.default.gray, chalk_1.default.white, chalk_1.default.yellow, chalk_1.default.red];
const color = colors[Math.floor(timeRatio * colors.length)];
return [
result.file,
chalk_1.default.green('✔ Success'),
color(`${result.time.toFixed(3)} s`),
'',
];
}
if (result.type === 'runtime-error') {
return [
result.file,
chalk_1.default.red('✖ Runtime error'),
'',
result.message,
];
}
return [
result.file,
chalk_1.default.green('✔ Success'),
color(`${result.time.toFixed(3)} s`),
chalk_1.default.yellow('⚠ Time limit exceeded'),
'',
];
}
if (result.type === 'runtime-error') {
return [
result.file,
chalk_1.default.red('✖ Runtime error'),
'',
result.message,
];
}
return [
result.file,
chalk_1.default.yellow('⚠ Time limit exceeded'),
'',
'',
];
}));
console.log(resultsTable.toString());
}));
console.log(resultsTable.toString());
}
catch (error) {
yield runner.kill();
exitWithError(error.message);
}
}
catch (error) {
yield runner.kill();
throw error;
if (error.code === 'ENOENT')
exitWithError('Input file or directory doesn\'t exist');
else
exitWithError(error.message);
}

@@ -157,0 +226,0 @@ });

@@ -39,2 +39,11 @@ #!/usr/bin/env node

});
commandYargs.option('overwrite', {
type: 'boolean',
describe: 'Overwrite files in output folder',
});
commandYargs.option('clear', {
type: 'boolean',
describe: 'Remove all files in output directory',
});
commandYargs.conflicts('clear', 'overwrite');
}, run_1.runHandler)

@@ -41,0 +50,0 @@ .demandCommand()

@@ -28,5 +28,4 @@ export interface ResultSuccess {

}
export declare function pullContainerImage(): Promise<{
upToDate: boolean;
}>;
export declare function isImagePulled(): Promise<boolean>;
export declare function pullContainerImage(): Promise<void>;
export declare function isDockerAvailable(): Promise<boolean>;

@@ -15,4 +15,5 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.isDockerAvailable = exports.pullContainerImage = exports.Runner = exports.Language = void 0;
exports.isDockerAvailable = exports.pullContainerImage = exports.isImagePulled = exports.Runner = exports.Language = void 0;
const path_1 = __importDefault(require("path"));
const eol_1 = __importDefault(require("eol"));
const utils_1 = require("./utils");

@@ -105,8 +106,15 @@ var Language;

exports.Runner = Runner;
function isImagePulled() {
return __awaiter(this, void 0, void 0, function* () {
const { stdout } = yield utils_1.execPromise(`docker images -q ${containerImageName}`);
return eol_1.default
.split(stdout)
.filter((line) => line.trim().length > 0)
.length > 0;
});
}
exports.isImagePulled = isImagePulled;
function pullContainerImage() {
return __awaiter(this, void 0, void 0, function* () {
const { stdout } = yield utils_1.execPromise(`docker pull ${containerImageName}`);
return {
upToDate: stdout.includes('Status: Image is up to date'),
};
yield utils_1.execPromise(`docker pull ${containerImageName}`);
});

@@ -113,0 +121,0 @@ }

{
"name": "awesome-test-runner",
"version": "1.2.2",
"version": "1.3.0",
"description": "Safely test console programs in Docker containers",

@@ -23,2 +23,3 @@ "main": "dist/index.js",

"dependencies": {
"@types/fs-extra": "^9.0.3",
"@types/glob": "^7.1.3",

@@ -31,2 +32,5 @@ "@types/node": "^14.14.6",

"cli-table3": "^0.6.0",
"enquirer": "^2.3.6",
"eol": "^0.9.1",
"fs-extra": "^9.0.1",
"glob": "^7.1.6",

@@ -33,0 +37,0 @@ "ora": "^5.1.0",

import yargs from 'yargs';
import path from 'path';
import fs from 'fs';
import fse from 'fs-extra';
import ora from 'ora';

@@ -9,3 +9,6 @@ import chalk from 'chalk';

import sequential from 'promise-sequential';
import { Runner, Result, pullContainerImage } from '../../index';
import Enquirer from 'enquirer';
import {
Runner, Result, pullContainerImage, isImagePulled,
} from '../../index';
import { globPromise } from '../../utils';

@@ -20,4 +23,64 @@

pattern: string;
overwrite: boolean;
clear: boolean;
}
export type OutputOverwriteMode = 'clear' | 'overwrite' | 'exit';
function exitWithError(text: string) {
console.error(chalk`{red {bold Error:} ${text}}`);
process.exit(1);
}
function printWarning(text: string) {
console.warn(chalk`{yellowBright {bold Warning:} ${text}}`);
}
async function getDirOverwriteMode(argv: yargs.Arguments<RunArgs>): Promise<OutputOverwriteMode> {
if (argv.clear) return 'clear';
if (argv.overwrite) return 'overwrite';
const answers = await Enquirer.prompt<{
mode: OutputOverwriteMode;
}>([
{
name: 'mode',
type: 'select',
message: 'The output directory is not empty. What do you want to do?',
required: true,
choices: [
{
name: 'exit',
message: 'Exit the program ',
},
{
name: 'overwrite',
message: 'Overwrite only changed files',
},
{
name: 'clear',
message: 'Remove all files and directories in output directory',
},
],
},
]);
console.log();
return answers.mode;
}
async function confirmFileOverwrite(argv: yargs.Arguments<RunArgs>): Promise<boolean> {
if (argv.overwrite) return true;
const answers = await Enquirer.prompt<{
overwrite: boolean;
}>([
{
name: 'overwrite',
type: 'confirm',
message: 'The output file already exists, and will be overwritten. Continue?',
required: true,
},
]);
console.log();
return answers.overwrite;
}
export async function runHandler(argv: yargs.Arguments<RunArgs>): Promise<void> {

@@ -28,63 +91,82 @@ const code = path.resolve(process.cwd(), argv.code);

// Start pulling before asking to overwrite
const imagePulled = await isImagePulled();
const pullContainerImagePromise: null | Promise<void> = imagePulled ? null : pullContainerImage();
try {
await fs.promises.lstat(code);
await fse.lstat(code);
} catch (error) {
if (error.code === 'ENOENT') console.error('Code file doesn\'t exist');
else console.error(error);
process.exit(1);
if (error.code === 'ENOENT') exitWithError('Code file doesn\'t exist');
else exitWithError(error.message);
}
let inputStats: fs.Stats;
let inputStats: fse.Stats;
try {
inputStats = await fs.promises.lstat(input);
} catch (error) {
if (error.code === 'ENOENT') console.error('Input file or directory doesn\'t exist');
else console.error(error);
process.exit(1);
}
inputStats = await fse.lstat(input);
try {
const outputStats = await fs.promises.lstat(output);
if (outputStats.isDirectory()) {
if (!inputStats.isDirectory()) {
console.error('Output is a directory, but input is a file');
process.exit(1);
try {
const outputStats = await fse.lstat(output);
if (outputStats.isDirectory()) {
if (!inputStats.isDirectory()) exitWithError('Output is a directory, but input is a file');
const files = await fse.readdir(output);
if (files.length !== 0) {
const mode = await getDirOverwriteMode(argv);
if (mode === 'exit') process.exit(0);
else if (mode === 'clear') await fse.emptyDir(output);
}
} else {
if (inputStats.isDirectory()) exitWithError('Output is a file, but input is a directory');
if (argv.clear) printWarning(chalk.yellow('Argument --clear can only be used with a directory output'));
if (!await confirmFileOverwrite(argv)) process.exit(0);
}
} else if (inputStats.isDirectory()) {
console.error('Output is a file, but input is a directory');
process.exit(1);
} catch (error) {
if (error.code === 'ENOENT') {
if (inputStats.isDirectory()) await fse.mkdir(output);
} else exitWithError(error.message);
}
} catch (error) {
if (error.code === 'ENOENT') {
if (inputStats.isDirectory()) await fs.promises.mkdir(output);
} else {
console.error(error);
process.exit(1);
if (!imagePulled) {
try {
const pullingSpinner = ora('Pulling container').start();
await pullContainerImagePromise;
pullingSpinner.succeed();
} catch (error) {
exitWithError(error.message);
}
}
}
const pullingSpinner = ora('Pulling container').start();
const { upToDate } = await pullContainerImage();
if (upToDate) pullingSpinner.info(`Pulling container: ${chalk.blue('Already up to date')}`);
else pullingSpinner.succeed();
const startingSpinner = ora('Starting docker container').start();
const runner = new Runner();
try {
await runner.start();
await runner.sendCodeFile(code);
startingSpinner.succeed();
const startingSpinner = ora('Starting docker container').start();
const runner = new Runner();
await runner.start();
try {
await runner.sendCodeFile(code);
startingSpinner.succeed();
let results: (Result & {
file: string;
})[];
const runSpinner = ora('Testing').start();
if (inputStats.isDirectory()) {
const files = await globPromise(argv.pattern, { cwd: input });
results = await sequential(files.map((file) => async () => {
runSpinner.text = `Testing ${chalk.cyan(file)}`;
const result = await runner.testInputFile(path.resolve(input, file), argv.time);
let results: (Result & {
file: string;
})[];
const runSpinner = ora('Testing').start();
if (inputStats.isDirectory()) {
const files = await globPromise(argv.pattern, { cwd: input });
results = await sequential(files.map((file) => async () => {
runSpinner.text = `Testing ${chalk.cyan(file)}`;
const result = await runner.testInputFile(path.resolve(input, file), argv.time);
if (result.type === 'success') {
await fse.writeFile(
path.resolve(output, replaceExt(file, '.out')),
result.output,
'utf8',
);
}
return {
...result,
file,
};
}));
} else {
const result = await runner.testInputFile(input, argv.time);
if (result.type === 'success') {
await fs.promises.writeFile(
path.resolve(output, replaceExt(file, '.out')),
await fse.writeFile(
output,
result.output,

@@ -94,69 +176,60 @@ 'utf8',

}
return {
results = [{
...result,
file,
};
}));
} else {
const result = await runner.testInputFile(input, argv.time);
if (result.type === 'success') {
await fs.promises.writeFile(
output,
result.output,
'utf8',
);
file: path.basename(argv.input),
}];
}
results = [{
...result,
file: path.basename(argv.input),
}];
}
runSpinner.succeed('Testing');
const stopSpinner = ora('Killing docker container').start();
await runner.kill();
stopSpinner.succeed();
const resultsTable = new Table({
head: [
'File',
'Status',
'Execution time',
'Error message',
],
style: {
head: ['cyan'],
},
});
resultsTable.push(
...results.map((result) => {
if (result.type === 'success') {
const timeRatio = Math.min(result.time / argv.time, 0.999);
const colors = [chalk.gray, chalk.white, chalk.yellow, chalk.red];
const color = colors[Math.floor(timeRatio * colors.length)];
runSpinner.succeed('Testing');
const stopSpinner = ora('Killing docker container').start();
await runner.kill();
stopSpinner.succeed();
const resultsTable = new Table({
head: [
'File',
'Status',
'Execution time',
'Error message',
],
style: {
head: ['cyan'],
},
});
resultsTable.push(
...results.map((result) => {
if (result.type === 'success') {
const timeRatio = Math.min(result.time / argv.time, 0.999);
const colors = [chalk.gray, chalk.white, chalk.yellow, chalk.red];
const color = colors[Math.floor(timeRatio * colors.length)];
return [
result.file,
chalk.green('✔ Success'),
color(`${result.time.toFixed(3)} s`),
'',
];
}
if (result.type === 'runtime-error') {
return [
result.file,
chalk.red('✖ Runtime error'),
'',
result.message,
];
}
return [
result.file,
chalk.green('✔ Success'),
color(`${result.time.toFixed(3)} s`),
chalk.yellow('⚠ Time limit exceeded'),
'',
];
} if (result.type === 'runtime-error') {
return [
result.file,
chalk.red('✖ Runtime error'),
'',
result.message,
];
}
return [
result.file,
chalk.yellow('⚠ Time limit exceeded'),
'',
'',
];
}),
);
console.log(resultsTable.toString());
}),
);
console.log(resultsTable.toString());
} catch (error) {
await runner.kill();
exitWithError(error.message);
}
} catch (error) {
await runner.kill();
throw error;
if (error.code === 'ENOENT') exitWithError('Input file or directory doesn\'t exist');
else exitWithError(error.message);
}
}

@@ -38,2 +38,11 @@ #!/usr/bin/env node

});
commandYargs.option('overwrite', {
type: 'boolean',
describe: 'Overwrite files in output folder',
});
commandYargs.option('clear', {
type: 'boolean',
describe: 'Remove all files in output directory',
});
commandYargs.conflicts('clear', 'overwrite');
},

@@ -40,0 +49,0 @@ runHandler,

import path from 'path';
import eol from 'eol';
import { execPromise, execWithInput } from './utils';

@@ -95,11 +96,14 @@

export async function pullContainerImage(): Promise<{
upToDate: boolean,
}> {
const { stdout } = await execPromise(`docker pull ${containerImageName}`);
return {
upToDate: stdout.includes('Status: Image is up to date'),
};
export async function isImagePulled(): Promise<boolean> {
const { stdout } = await execPromise(`docker images -q ${containerImageName}`);
return eol
.split(stdout)
.filter((line) => line.trim().length > 0)
.length > 0;
}
export async function pullContainerImage(): Promise<void> {
await execPromise(`docker pull ${containerImageName}`);
}
export async function isDockerAvailable(): Promise<boolean> {

@@ -106,0 +110,0 @@ try {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc