1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-23 15:16:54 -05:00
Original: 17a214bbd5
This commit is contained in:
Nayeem Rahman 2019-09-28 14:33:17 +01:00 committed by Ryan Dahl
parent af18093498
commit a472b6732d
25 changed files with 444 additions and 166 deletions

View file

@ -4,5 +4,5 @@ parameters:
steps: steps:
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-write --allow-read --allow-env ./format.ts --check - bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-write --allow-read --allow-env ./format.ts --check
- bash: export START_TIME=$(date +%s) - bash: export START_TIME=$(date +%s)
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-net --allow-write --allow-read --allow-env --config=tsconfig.test.json ./testing/runner.ts --exclude node_modules - bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-net --allow-write --allow-read --allow-env --config=tsconfig.test.json ./testing/runner.ts --exclude node_modules,**/testdata
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-read .ci/check_source_file_changes.ts $START_TIME - bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-read .ci/check_source_file_changes.ts $START_TIME

View file

@ -1,4 +1,7 @@
import { globrex } from "./globrex.ts"; import { globrex } from "./globrex.ts";
import { isAbsolute, join } from "./path/mod.ts";
import { WalkInfo, walk, walkSync } from "./walk.ts";
const { cwd } = Deno;
export interface GlobOptions { export interface GlobOptions {
// Allow ExtGlob features // Allow ExtGlob features
@ -41,7 +44,11 @@ export interface GlobOptions {
* @returns A RegExp for the glob pattern * @returns A RegExp for the glob pattern
*/ */
export function glob(glob: string, options: GlobOptions = {}): RegExp { export function glob(glob: string, options: GlobOptions = {}): RegExp {
return globrex(glob, options).regex; const result = globrex(glob, options);
if (options.filepath) {
return result.path!.regex;
}
return result.regex;
} }
/** Test whether the given string is a glob */ /** Test whether the given string is a glob */
@ -76,3 +83,61 @@ export function isGlob(str: string): boolean {
return false; return false;
} }
export interface ExpandGlobOptions extends GlobOptions {
root?: string;
includeDirs?: boolean;
}
/**
* Expand the glob string from the specified `root` directory and yield each
* result as a `WalkInfo` object.
*/
// TODO: Use a proper glob expansion algorithm.
// This is a very incomplete solution. The whole directory tree from `root` is
// walked and parent paths are not supported.
export async function* expandGlob(
globString: string,
{
root = cwd(),
includeDirs = true,
extended = false,
globstar = false,
strict = false,
filepath = true,
flags = ""
}: ExpandGlobOptions = {}
): AsyncIterableIterator<WalkInfo> {
const absoluteGlob = isAbsolute(globString)
? globString
: join(root, globString);
const globOptions = { extended, globstar, strict, filepath, flags };
yield* walk(root, {
match: [glob(absoluteGlob, globOptions)],
includeDirs
});
}
/** Synchronous version of `expandGlob()`. */
// TODO: As `expandGlob()`.
export function* expandGlobSync(
globString: string,
{
root = cwd(),
includeDirs = true,
extended = false,
globstar = false,
strict = false,
filepath = true,
flags = ""
}: ExpandGlobOptions = {}
): IterableIterator<WalkInfo> {
const absoluteGlob = isAbsolute(globString)
? globString
: join(root, globString);
const globOptions = { extended, globstar, strict, filepath, flags };
yield* walkSync(root, {
match: [glob(absoluteGlob, globOptions)],
includeDirs
});
}

View file

@ -1,9 +1,16 @@
const { mkdir } = Deno; const { cwd, mkdir } = Deno;
type FileInfo = Deno.FileInfo;
import { test, runIfMain } from "../testing/mod.ts"; import { test, runIfMain } from "../testing/mod.ts";
import { assert, assertEquals } from "../testing/asserts.ts"; import { assert, assertEquals } from "../testing/asserts.ts";
import { glob, isGlob } from "./glob.ts"; import { isWindows } from "./path/constants.ts";
import { join } from "./path.ts"; import {
ExpandGlobOptions,
expandGlob,
glob,
isGlob,
expandGlobSync
} from "./glob.ts";
import { join, normalize, relative } from "./path.ts";
import { WalkInfo } from "./walk.ts";
import { testWalk } from "./walk_test.ts"; import { testWalk } from "./walk_test.ts";
import { touch, walkArray } from "./walk_test.ts"; import { touch, walkArray } from "./walk_test.ts";
@ -131,7 +138,6 @@ testWalk(
const arr = await walkArray(".", { const arr = await walkArray(".", {
match: [glob("x.*", { flags: "g", globstar: true })] match: [glob("x.*", { flags: "g", globstar: true })]
}); });
console.log(arr);
assertEquals(arr.length, 2); assertEquals(arr.length, 2);
assertEquals(arr[0], "x.js"); assertEquals(arr[0], "x.js");
assertEquals(arr[1], "x.ts"); assertEquals(arr[1], "x.ts");
@ -253,4 +259,76 @@ test({
} }
}); });
async function expandGlobArray(
globString: string,
options: ExpandGlobOptions
): Promise<string[]> {
const infos: WalkInfo[] = [];
for await (const info of expandGlob(globString, options)) {
infos.push(info);
}
infos.sort();
const infosSync = [...expandGlobSync(globString, options)];
infosSync.sort();
assertEquals(infos, infosSync);
const root = normalize(options.root || cwd());
const paths = infos.map(({ filename }): string => filename);
for (const path of paths) {
assert(path.startsWith(root));
}
const relativePaths = paths.map((path: string): string =>
relative(root, path)
);
relativePaths.sort();
return relativePaths;
}
function urlToFilePath(url: URL): string {
// Since `new URL('file:///C:/a').pathname` is `/C:/a`, remove leading slash.
return url.pathname.slice(url.protocol == "file:" && isWindows ? 1 : 0);
}
const EG_OPTIONS = {
root: urlToFilePath(new URL(join("testdata", "glob"), import.meta.url)),
includeDirs: true,
extended: false,
globstar: false,
strict: false,
filepath: false,
flags: ""
};
test(async function expandGlobExt(): Promise<void> {
const options = { ...EG_OPTIONS, extended: true };
assertEquals(await expandGlobArray("abc?(def|ghi)", options), [
"abc",
"abcdef"
]);
assertEquals(await expandGlobArray("abc*(def|ghi)", options), [
"abc",
"abcdef",
"abcdefghi"
]);
assertEquals(await expandGlobArray("abc+(def|ghi)", options), [
"abcdef",
"abcdefghi"
]);
assertEquals(await expandGlobArray("abc@(def|ghi)", options), ["abcdef"]);
assertEquals(await expandGlobArray("abc{def,ghi}", options), ["abcdef"]);
assertEquals(await expandGlobArray("abc!(def|ghi)", options), ["abc"]);
});
test(async function expandGlobGlobstar(): Promise<void> {
const options = { ...EG_OPTIONS, globstar: true };
assertEquals(await expandGlobArray(join("**", "abc"), options), [
"abc",
join("subdir", "abc")
]);
});
test(async function expandGlobIncludeDirs(): Promise<void> {
const options = { ...EG_OPTIONS, includeDirs: false };
assertEquals(await expandGlobArray("subdir", options), []);
});
runIfMain(import.meta); runIfMain(import.meta);

View file

@ -5,17 +5,18 @@
import { GlobOptions } from "./glob.ts"; import { GlobOptions } from "./glob.ts";
const isWin = Deno.build.os === "win"; const isWin = Deno.build.os === "win";
const SEP = isWin ? `\\\\+` : `\\/`; const SEP = isWin ? `(\\\\+|\\/)` : `\\/`;
const SEP_ESC = isWin ? `\\\\` : `/`; const SEP_ESC = isWin ? `\\\\` : `/`;
const GLOBSTAR = `((?:[^/]*(?:/|$))*)`; const SEP_RAW = isWin ? `\\` : `/`;
const WILDCARD = `([^/]*)`; const GLOBSTAR = `((?:[^${SEP_ESC}/]*(?:${SEP_ESC}|\/|$))*)`;
const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}]*(?:${SEP_ESC}|$))*)`; const WILDCARD = `([^${SEP_ESC}/]*)`;
const WILDCARD_SEGMENT = `([^${SEP_ESC}]*)`; const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}/]*(?:${SEP_ESC}|\/|$))*)`;
const WILDCARD_SEGMENT = `([^${SEP_ESC}/]*)`;
export interface GlobrexResult { export interface GlobrexResult {
regex: RegExp; regex: RegExp;
path?: { path?: {
regex: string | RegExp; regex: RegExp;
segments: RegExp[]; segments: RegExp[];
globstar?: RegExp; globstar?: RegExp;
}; };
@ -44,11 +45,8 @@ export function globrex(
): GlobrexResult { ): GlobrexResult {
let regex = ""; let regex = "";
let segment = ""; let segment = "";
let path: { let pathRegexStr = "";
regex: string | RegExp; const pathSegments = [];
segments: RegExp[];
globstar?: RegExp;
} = { regex: "", segments: [] };
// If we are doing extended matching, this boolean is true when we are inside // If we are doing extended matching, this boolean is true when we are inside
// a group (eg {*.html,*.js}), and false otherwise. // a group (eg {*.html,*.js}), and false otherwise.
@ -72,13 +70,13 @@ export function globrex(
const { split, last, only } = options; const { split, last, only } = options;
if (only !== "path") regex += str; if (only !== "path") regex += str;
if (filepath && only !== "regex") { if (filepath && only !== "regex") {
path.regex += str === "\\/" ? SEP : str; pathRegexStr += str.match(new RegExp(`^${SEP}$`)) ? SEP : str;
if (split) { if (split) {
if (last) segment += str; if (last) segment += str;
if (segment !== "") { if (segment !== "") {
// change it 'includes' // change it 'includes'
if (!flags.includes("g")) segment = `^${segment}$`; if (!flags.includes("g")) segment = `^${segment}$`;
path.segments.push(new RegExp(segment, flags)); pathSegments.push(new RegExp(segment, flags));
} }
segment = ""; segment = "";
} else { } else {
@ -267,9 +265,9 @@ export function globrex(
let isGlobstar = let isGlobstar =
starCount > 1 && // multiple "*"'s starCount > 1 && // multiple "*"'s
// from the start of the segment // from the start of the segment
(prevChar === "/" || prevChar === undefined) && [SEP_RAW, "/", undefined].includes(prevChar) &&
// to the end of the segment // to the end of the segment
(nextChar === "/" || nextChar === undefined); [SEP_RAW, "/", undefined].includes(nextChar);
if (isGlobstar) { if (isGlobstar) {
// it's a globstar, so match zero or more path segments // it's a globstar, so match zero or more path segments
add(GLOBSTAR, { only: "regex" }); add(GLOBSTAR, { only: "regex" });
@ -292,20 +290,22 @@ export function globrex(
if (!flags.includes("g")) { if (!flags.includes("g")) {
regex = `^${regex}$`; regex = `^${regex}$`;
segment = `^${segment}$`; segment = `^${segment}$`;
if (filepath) path.regex = `^${path.regex}$`; if (filepath) pathRegexStr = `^${pathRegexStr}$`;
} }
const result: GlobrexResult = { regex: new RegExp(regex, flags) }; const result: GlobrexResult = { regex: new RegExp(regex, flags) };
// Push the last segment // Push the last segment
if (filepath) { if (filepath) {
path.segments.push(new RegExp(segment, flags)); pathSegments.push(new RegExp(segment, flags));
path.regex = new RegExp(path.regex.toString(), flags); result.path = {
path.globstar = new RegExp( regex: new RegExp(pathRegexStr, flags),
segments: pathSegments,
globstar: new RegExp(
!flags.includes("g") ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, !flags.includes("g") ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT,
flags flags
); )
result.path = path; };
} }
return result; return result;

View file

@ -50,3 +50,4 @@ export const CHAR_9 = 57; /* 9 */
export const isWindows = build.os === "win"; export const isWindows = build.os === "win";
export const EOL = isWindows ? "\r\n" : "\n"; export const EOL = isWindows ? "\r\n" : "\n";
export const SEP = isWindows ? "\\" : "/";

0
fs/testdata/glob/abc vendored Normal file
View file

0
fs/testdata/glob/abcdef vendored Normal file
View file

0
fs/testdata/glob/abcdefghi vendored Normal file
View file

0
fs/testdata/glob/subdir/abc vendored Normal file
View file

View file

@ -348,7 +348,7 @@ async function runTestsSerial(
} }
/** Defines options for controlling execution details of a test suite. */ /** Defines options for controlling execution details of a test suite. */
export interface RunOptions { export interface RunTestsOptions {
parallel?: boolean; parallel?: boolean;
exitOnFail?: boolean; exitOnFail?: boolean;
only?: RegExp; only?: RegExp;
@ -368,7 +368,7 @@ export async function runTests({
only = /[^\s]/, only = /[^\s]/,
skip = /^\s*$/, skip = /^\s*$/,
disableLog = false disableLog = false
}: RunOptions = {}): Promise<void> { }: RunTestsOptions = {}): Promise<void> {
const tests: TestDefinition[] = candidates.filter( const tests: TestDefinition[] = candidates.filter(
({ name }): boolean => only.test(name) && !skip.test(name) ({ name }): boolean => only.test(name) && !skip.test(name)
); );
@ -415,7 +415,7 @@ export async function runTests({
*/ */
export async function runIfMain( export async function runIfMain(
meta: ImportMeta, meta: ImportMeta,
opts?: RunOptions opts?: RunTestsOptions
): Promise<void> { ): Promise<void> {
if (meta.main) { if (meta.main) {
return runTests(opts); return runTests(opts);

View file

@ -1,44 +1,46 @@
#!/usr/bin/env -S deno -A #!/usr/bin/env -S deno -A
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { parse } from "../flags/mod.ts"; import { parse } from "../flags/mod.ts";
import { glob, isGlob, walk } from "../fs/mod.ts"; import {
import { runTests } from "./mod.ts"; WalkInfo,
const { args, cwd } = Deno; expandGlobSync,
glob,
ExpandGlobOptions
} from "../fs/mod.ts";
import { isWindows } from "../fs/path/constants.ts";
import { isAbsolute, join } from "../fs/path/mod.ts";
import { RunTestsOptions, runTests } from "./mod.ts";
const { DenoError, ErrorKind, args, cwd, exit } = Deno;
const DEFAULT_GLOBS = [ const DIR_GLOBS = [join("**", "?(*_)test.{js,ts}")];
"**/*_test.ts",
"**/*_test.js",
"**/test.ts",
"**/test.js"
];
/* eslint-disable max-len */
function showHelp(): void { function showHelp(): void {
console.log(`Deno test runner console.log(`Deno test runner
USAGE: USAGE:
deno -A https://deno.land/std/testing/runner.ts [OPTIONS] [FILES...] deno -A https://deno.land/std/testing/runner.ts [OPTIONS] [MODULES...]
OPTIONS: OPTIONS:
-q, --quiet Don't show output from test cases -q, --quiet Don't show output from test cases
-f, --failfast Stop test suite on first error -f, --failfast Stop running tests on first error
-e, --exclude <FILES...> List of file names to exclude from run. If this options is -e, --exclude <MODULES...> List of comma-separated modules to exclude
used files to match must be specified after "--". --allow-none Exit with status 0 even when no test modules are
found
ARGS: ARGS:
[FILES...] List of file names to run. Defaults to: ${DEFAULT_GLOBS.join( [MODULES...] List of test modules to run.
"," A directory <dir> will expand to:
)} ${DIR_GLOBS.map((s: string): string => `${join("<dir>", s)}`)
`); .join(`
} `)}
/* eslint-enable max-len */ Defaults to "." when none are provided.
function filePathToRegExp(str: string): RegExp { Note that modules can refer to file paths or URLs. File paths support glob
if (isGlob(str)) { expansion.
return glob(str, { flags: "g" });
}
return RegExp(str, "g"); Examples:
deno test src/**/*_test.ts
deno test tests`);
} }
function isRemoteUrl(url: string): boolean { function isRemoteUrl(url: string): boolean {
@ -58,114 +60,186 @@ function partition(
); );
} }
/** function filePathToUrl(path: string): string {
* Given list of globs or URLs to include and exclude and root directory return return `file://${isWindows ? "/" : ""}${path.replace(/\\/g, "/")}`;
* list of file URLs that should be imported for test runner.
*/
export async function getMatchingUrls(
matchPaths: string[],
excludePaths: string[],
root: string
): Promise<string[]> {
const [includeLocal, includeRemote] = partition(matchPaths, isRemoteUrl);
const [excludeLocal, excludeRemote] = partition(excludePaths, isRemoteUrl);
const localFileIterator = walk(root, {
match: includeLocal.map((f: string): RegExp => filePathToRegExp(f)),
skip: excludeLocal.map((f: string): RegExp => filePathToRegExp(f))
});
let matchingLocalUrls: string[] = [];
for await (const { filename } of localFileIterator) {
matchingLocalUrls.push(`file://${filename}`);
} }
const excludeRemotePatterns = excludeRemote.map( function expandDirectory(dir: string, options: ExpandGlobOptions): WalkInfo[] {
return DIR_GLOBS.flatMap((s: string): WalkInfo[] => [
...expandGlobSync(s, { ...options, root: dir })
]);
}
/**
* Given a list of globs or URLs to include and exclude and a root directory
* from which to expand relative globs, return a list of URLs
* (file: or remote) that should be imported for the test runner.
*/
export async function findTestModules(
includeModules: string[],
excludeModules: string[],
root: string = cwd()
): Promise<string[]> {
const [includePaths, includeUrls] = partition(includeModules, isRemoteUrl);
const [excludePaths, excludeUrls] = partition(excludeModules, isRemoteUrl);
const expandGlobOpts = {
root,
extended: true,
globstar: true,
filepath: true
};
// TODO: We use the `g` flag here to support path prefixes when specifying
// excludes. Replace with a solution that does this more correctly.
const excludePathPatterns = excludePaths.map(
(s: string): RegExp =>
glob(isAbsolute(s) ? s : join(root, s), { ...expandGlobOpts, flags: "g" })
);
const excludeUrlPatterns = excludeUrls.map(
(url: string): RegExp => RegExp(url) (url: string): RegExp => RegExp(url)
); );
const matchingRemoteUrls = includeRemote.filter( const notExcludedPath = ({ filename }: WalkInfo): boolean =>
(candidateUrl: string): boolean => { !excludePathPatterns.some((p: RegExp): boolean => !!filename.match(p));
return !excludeRemotePatterns.some((pattern: RegExp): boolean => { const notExcludedUrl = (url: string): boolean =>
const r = pattern.test(candidateUrl); !excludeUrlPatterns.some((p: RegExp): boolean => !!url.match(p));
pattern.lastIndex = 0;
return r; const matchedPaths = includePaths
}); .flatMap((s: string): WalkInfo[] => [...expandGlobSync(s, expandGlobOpts)])
} .filter(notExcludedPath)
.flatMap(({ filename, info }): string[] =>
info.isDirectory()
? expandDirectory(filename, { ...expandGlobOpts, includeDirs: false })
.filter(notExcludedPath)
.map(({ filename }): string => filename)
: [filename]
); );
return matchingLocalUrls.concat(matchingRemoteUrls); const matchedUrls = includeUrls.filter(notExcludedUrl);
return [...matchedPaths.map(filePathToUrl), ...matchedUrls];
} }
export interface RunTestModulesOptions extends RunTestsOptions {
include?: string[];
exclude?: string[];
allowNone?: boolean;
}
/** /**
* This function runs matching test files in `root` directory. * Import the specified test modules and run their tests as a suite.
* *
* File matching and excluding supports glob syntax, ie. if encountered arg is * Test modules are specified as an array of strings and can include local files
* a glob it will be expanded using `glob` method from `fs` module. * or URLs.
* *
* Note that your shell may expand globs for you: * File matching and excluding support glob syntax - arguments recognized as
* $ deno -A ./runner.ts **\/*_test.ts **\/test.ts * globs will be expanded using `glob()` from the `fs` module.
* *
* Expanding using `fs.glob`: * Example:
* $ deno -A ./runner.ts \*\*\/\*_test.ts \*\*\/test.ts
* *
* `**\/*_test.ts` and `**\/test.ts"` are arguments that will be parsed and * runTestModules({ include: ["**\/*_test.ts", "**\/test.ts"] });
* expanded as: [glob("**\/*_test.ts"), glob("**\/test.ts")] *
* Any matched directory `<dir>` will expand to:
* <dir>/**\/?(*_)test.{js,ts}
*
* So the above example is captured naturally by:
*
* runTestModules({ include: ["."] });
*
* Which is the default used for:
*
* runTestModules();
*/ */
// TODO: change return type to `Promise<void>` once, `runTests` is updated // TODO: Change return type to `Promise<void>` once, `runTests` is updated
// to return boolean instead of exiting // to return boolean instead of exiting.
export async function main(root: string = cwd()): Promise<void> { export async function runTestModules({
const parsedArgs = parse(args.slice(1), { include = ["."],
boolean: ["quiet", "failfast", "help"], exclude = [],
string: ["exclude"], allowNone = false,
alias: { parallel = false,
help: ["h"], exitOnFail = false,
quiet: ["q"], only = /[^\s]/,
failfast: ["f"], skip = /^\s*$/,
exclude: ["e"] disableLog = false
}: RunTestModulesOptions = {}): Promise<void> {
const testModuleUrls = await findTestModules(include, exclude);
if (testModuleUrls.length == 0) {
const noneFoundMessage = "No matching test modules found.";
if (!allowNone) {
throw new DenoError(ErrorKind.NotFound, noneFoundMessage);
} else if (!disableLog) {
console.log(noneFoundMessage);
} }
});
if (parsedArgs.help) {
return showHelp();
}
let includeFiles: string[];
let excludeFiles: string[];
if (parsedArgs._.length) {
includeFiles = (parsedArgs._ as string[])
.map((fileGlob: string): string[] => {
return fileGlob.split(",");
})
.flat();
} else {
includeFiles = DEFAULT_GLOBS;
}
if (parsedArgs.exclude) {
excludeFiles = (parsedArgs.exclude as string).split(",");
} else {
excludeFiles = [];
}
const foundTestUrls = await getMatchingUrls(includeFiles, excludeFiles, root);
if (foundTestUrls.length === 0) {
console.error("No matching test files found.");
return; return;
} }
console.log(`Found ${foundTestUrls.length} matching test files.`); if (!disableLog) {
console.log(`Found ${testModuleUrls.length} matching test modules.`);
}
for (const url of foundTestUrls) { for (const url of testModuleUrls) {
await import(url); await import(url);
} }
await runTests({ await runTests({
exitOnFail: !!parsedArgs.failfast, parallel,
disableLog: !!parsedArgs.quiet exitOnFail,
only,
skip,
disableLog
}); });
} }
async function main(): Promise<void> {
const parsedArgs = parse(args.slice(1), {
boolean: ["allow-none", "failfast", "help", "quiet"],
string: ["exclude"],
alias: {
exclude: ["e"],
failfast: ["f"],
help: ["h"],
quiet: ["q"]
},
default: {
"allow-none": false,
failfast: false,
help: false,
quiet: false
}
});
if (parsedArgs.help) {
return showHelp();
}
const include =
parsedArgs._.length > 0
? (parsedArgs._ as string[]).flatMap((fileGlob: string): string[] =>
fileGlob.split(",")
)
: ["."];
const exclude =
parsedArgs.exclude != null ? (parsedArgs.exclude as string).split(",") : [];
const allowNone = parsedArgs["allow-none"];
const exitOnFail = parsedArgs.failfast;
const disableLog = parsedArgs.quiet;
try {
await runTestModules({
include,
exclude,
allowNone,
exitOnFail,
disableLog
});
} catch (error) {
if (!disableLog) {
console.error(error.message);
}
exit(1);
}
}
if (import.meta.main) { if (import.meta.main) {
main(); main();
} }

View file

@ -1,30 +1,78 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { test } from "./mod.ts"; import { test } from "./mod.ts";
import { findTestModules } from "./runner.ts";
import { isWindows } from "../fs/path/constants.ts";
import { assertEquals } from "../testing/asserts.ts"; import { assertEquals } from "../testing/asserts.ts";
import { getMatchingUrls } from "./runner.ts";
import { join } from "../fs/path/mod.ts";
/** function urlToFilePath(url: URL): string {
* IMPORTANT: This file assumes it is run from root of repository. // Since `new URL('file:///C:/a').pathname` is `/C:/a`, remove leading slash.
*/ return url.pathname.slice(url.protocol == "file:" && isWindows ? 1 : 0);
const cwd = Deno.cwd(); }
const TEST_ROOT_PATH = join(cwd, "fmt");
test(async function getMatchingUrlsRemote(): Promise<void> { const TEST_DATA_URL = new URL("testdata", import.meta.url);
const matches = [ const TEST_DATA_PATH = urlToFilePath(TEST_DATA_URL);
"https://deno.land/std/fmt/colors_test.ts",
"http://deno.land/std/fmt/printf_test.ts" test(async function findTestModulesDir1(): Promise<void> {
const urls = await findTestModules(["."], [], TEST_DATA_PATH);
assertEquals(urls.sort(), [
`${TEST_DATA_URL}/bar_test.js`,
`${TEST_DATA_URL}/foo_test.ts`,
`${TEST_DATA_URL}/subdir/bar_test.js`,
`${TEST_DATA_URL}/subdir/foo_test.ts`,
`${TEST_DATA_URL}/subdir/test.js`,
`${TEST_DATA_URL}/subdir/test.ts`,
`${TEST_DATA_URL}/test.js`,
`${TEST_DATA_URL}/test.ts`
]);
});
test(async function findTestModulesDir2(): Promise<void> {
const urls = await findTestModules(["subdir"], [], TEST_DATA_PATH);
assertEquals(urls.sort(), [
`${TEST_DATA_URL}/subdir/bar_test.js`,
`${TEST_DATA_URL}/subdir/foo_test.ts`,
`${TEST_DATA_URL}/subdir/test.js`,
`${TEST_DATA_URL}/subdir/test.ts`
]);
});
test(async function findTestModulesGlob(): Promise<void> {
const urls = await findTestModules(["**/*_test.{js,ts}"], [], TEST_DATA_PATH);
assertEquals(urls.sort(), [
`${TEST_DATA_URL}/bar_test.js`,
`${TEST_DATA_URL}/foo_test.ts`,
`${TEST_DATA_URL}/subdir/bar_test.js`,
`${TEST_DATA_URL}/subdir/foo_test.ts`
]);
});
test(async function findTestModulesExcludeDir(): Promise<void> {
const urls = await findTestModules(["."], ["subdir"], TEST_DATA_PATH);
assertEquals(urls.sort(), [
`${TEST_DATA_URL}/bar_test.js`,
`${TEST_DATA_URL}/foo_test.ts`,
`${TEST_DATA_URL}/test.js`,
`${TEST_DATA_URL}/test.ts`
]);
});
test(async function findTestModulesExcludeGlob(): Promise<void> {
const urls = await findTestModules(["."], ["**/foo*"], TEST_DATA_PATH);
assertEquals(urls.sort(), [
`${TEST_DATA_URL}/bar_test.js`,
`${TEST_DATA_URL}/subdir/bar_test.js`,
`${TEST_DATA_URL}/subdir/test.js`,
`${TEST_DATA_URL}/subdir/test.ts`,
`${TEST_DATA_URL}/test.js`,
`${TEST_DATA_URL}/test.ts`
]);
});
test(async function findTestModulesRemote(): Promise<void> {
const urls = [
"https://example.com/colors_test.ts",
"http://example.com/printf_test.ts"
]; ];
const matches = await findTestModules(urls, []);
const urls = await getMatchingUrls(matches, [], TEST_ROOT_PATH); assertEquals(matches, urls);
assertEquals(urls, matches);
});
test(async function getMatchingUrlsLocal(): Promise<void> {
const urls = await getMatchingUrls(
["fmt/*_test.ts"],
["colors*"],
TEST_ROOT_PATH
);
assertEquals(urls.length, 1);
}); });

1
testing/testdata/bar.js vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/bar_test.js vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/foo.ts vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/foo_test.ts vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/subdir/bar.js vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/subdir/bar_test.js vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/subdir/foo.ts vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/subdir/foo_test.ts vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/subdir/test.js vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/subdir/test.ts vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/test.js vendored Normal file
View file

@ -0,0 +1 @@
export {};

1
testing/testdata/test.ts vendored Normal file
View file

@ -0,0 +1 @@
export {};

View file

@ -33,7 +33,7 @@ test(async function xevalCliReplvar(): Promise<void> {
await p.stdin!.write(encode("hello")); await p.stdin!.write(encode("hello"));
await p.stdin!.close(); await p.stdin!.close();
assertEquals(await p.status(), { code: 0, success: true }); assertEquals(await p.status(), { code: 0, success: true });
assertEquals(decode(await p.output()), "hello\n"); assertEquals(decode(await p.output()).trimEnd(), "hello");
}); });
test(async function xevalCliSyntaxError(): Promise<void> { test(async function xevalCliSyntaxError(): Promise<void> {