From dad026abfa35d8ff4b64ee69a738df26a7a559fe Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Fri, 13 Oct 2023 11:18:34 -0700 Subject: [PATCH 1/3] partial work --- package/scripts/common/quarto | 9 ++- src/command/render/flags.ts | 23 +++++-- src/command/render/pandoc.ts | 6 +- src/command/render/render-files.ts | 3 +- src/command/render/render.ts | 2 +- src/command/render/types.ts | 3 +- src/execute/types.ts | 3 +- tests/docs/luacov/covtools.ts | 98 +++++++++++++++++++++++++++++ tests/docs/luacov/fixup_coverage.ts | 98 +++++++++++++++++++++++++++++ tests/docs/luacov/query.ts | 19 ++++++ tests/test.ts | 24 ++++--- 11 files changed, 268 insertions(+), 20 deletions(-) create mode 100644 tests/docs/luacov/covtools.ts create mode 100644 tests/docs/luacov/fixup_coverage.ts create mode 100644 tests/docs/luacov/query.ts diff --git a/package/scripts/common/quarto b/package/scripts/common/quarto index 1f867701733..6a6116506ab 100755 --- a/package/scripts/common/quarto +++ b/package/scripts/common/quarto @@ -158,7 +158,6 @@ else export DENO_DOM_PLUGIN=$QUARTO_BIN_PATH/tools/${ARCH_DIR}/deno_dom/libplugin.so fi - if [ "$QUARTO_DENO" == "" ]; then DENO_DIR=$ARCH_DIR export QUARTO_DENO="${SCRIPT_PATH}/tools/${DENO_DIR}/deno" @@ -172,6 +171,14 @@ QUARTO_DENO_OPTIONS="--unstable --no-config ${QUARTO_CACHE_OPTIONS} --allow-read if [ "$QUARTO_TS_PROFILE" != "" ]; then QUARTO_DENO_EXTRA_OPTIONS="--inspect-brk ${QUARTO_DENO_EXTRA_OPTIONS}" QUARTO_TS_PROFILE=true "${QUARTO_DENO}" ${QUARTO_ACTION} ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} "${QUARTO_IMPORT_ARGMAP}" "${QUARTO_TARGET}" "$@" +elif [ -f "$DEV_PATH" -a "$1" == "deno" ]; then + shift; + QUARTO_ACTION="$1" + shift + "${QUARTO_DENO}" ${QUARTO_ACTION} ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} ${QUARTO_IMPORT_ARGMAP} "$@" +elif [ -f "$DEV_PATH" -a "$1" == "repl" ]; then + shift; + "${QUARTO_DENO}" repl ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} ${QUARTO_IMPORT_ARGMAP} "$@" else "${QUARTO_DENO}" ${QUARTO_ACTION} ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} ${QUARTO_IMPORT_ARGMAP} "${QUARTO_TARGET}" "$@" fi \ No newline at end of file diff --git a/src/command/render/flags.ts b/src/command/render/flags.ts index 449fe021381..9446239a0fe 100644 --- a/src/command/render/flags.ts +++ b/src/command/render/flags.ts @@ -1,9 +1,8 @@ /* -* flags.ts -* -* Copyright (C) 2020-2022 Posit Software, PBC -* -*/ + * flags.ts + * + * Copyright (C) 2020-2023 Posit Software, PBC + */ import { existsSync } from "fs/mod.ts"; import { readYaml, readYamlFromString } from "../../core/yaml.ts"; @@ -339,6 +338,19 @@ export async function parseRenderFlags(args: string[]) { } break; + case "--env": + arg = argsStack.shift(); + if (arg) { + const metadata = parseMetadataFlagValue(arg); + if (metadata) { + if (flags["env"] === undefined) { + flags["env"] = {}; + } + flags["env"][metadata.name] = String(metadata.value); + } + } + break; + default: arg = argsStack.shift(); break; @@ -443,6 +455,7 @@ export function fixupPandocArgs(pandocArgs: string[], flags: RenderFlags) { removeArgs.set("--quiet", false); removeArgs.set("--q", false); removeArgs.set("--profile", true); + removeArgs.set("--env", true); // Remove un-needed pandoc args (including -M/--metadata as appropriate) pandocArgs = removePandocArgs(pandocArgs, removeArgs); diff --git a/src/command/render/pandoc.ts b/src/command/render/pandoc.ts index 0dba6068776..c3f2aa1e07d 100644 --- a/src/command/render/pandoc.ts +++ b/src/command/render/pandoc.ts @@ -1,7 +1,7 @@ /* * pandoc.ts * - * Copyright (C) 2020-2022 Posit Software, PBC + * Copyright (C) 2020-2023 Posit Software, PBC */ import { basename, dirname, isAbsolute, join } from "path/mod.ts"; @@ -207,7 +207,9 @@ export async function runPandoc( ): Promise { const beforePandocHooks: (() => unknown)[] = []; const afterPandocHooks: (() => unknown)[] = []; - const pandocEnv: { [key: string]: string } = {}; + const pandocEnv: { [key: string]: string } = { + ...(options.flags?.env || {}), + }; // compute cwd for render const cwd = dirname(options.source); diff --git a/src/command/render/render-files.ts b/src/command/render/render-files.ts index e2a835b5ed7..e5caf720bd4 100644 --- a/src/command/render/render-files.ts +++ b/src/command/render/render-files.ts @@ -1,7 +1,7 @@ /* * render-files.ts * - * Copyright (C) 2020-2022 Posit Software, PBC + * Copyright (C) 2020-2023 Posit Software, PBC */ // ensures cell handlers are installed @@ -215,6 +215,7 @@ export async function renderExecute( previewServer: context.options.previewServer, handledLanguages: languages(), projectType: context.project?.config?.project?.[kProjectType], + env: context.options.flags?.env, }); popTiming(); diff --git a/src/command/render/render.ts b/src/command/render/render.ts index 9e2213ecde0..6f8b34cfb82 100644 --- a/src/command/render/render.ts +++ b/src/command/render/render.ts @@ -1,7 +1,7 @@ /* * render.ts * - * Copyright (C) 2020-2022 Posit Software, PBC + * Copyright (C) 2020-2023 Posit Software, PBC */ import { ensureDirSync, existsSync } from "fs/mod.ts"; diff --git a/src/command/render/types.ts b/src/command/render/types.ts index 02a46678430..bb56412605a 100644 --- a/src/command/render/types.ts +++ b/src/command/render/types.ts @@ -1,7 +1,7 @@ /* * types.ts * - * Copyright (C) 2020-2022 Posit Software, PBC + * Copyright (C) 2020-2023 Posit Software, PBC */ import { Document } from "../../core/deno-dom.ts"; @@ -247,6 +247,7 @@ export interface RenderFlags extends PandocFlags { debug?: boolean; quiet?: boolean; version?: string; + env?: Record; } export interface OutputRecipe { diff --git a/src/execute/types.ts b/src/execute/types.ts index f1625bbc296..641075fb56d 100644 --- a/src/execute/types.ts +++ b/src/execute/types.ts @@ -1,7 +1,7 @@ /* * types.ts * - * Copyright (C) 2020-2022 Posit Software, PBC + * Copyright (C) 2020-2023 Posit Software, PBC */ import { kIncludeAfterBody, @@ -86,6 +86,7 @@ export interface ExecuteOptions { previewServer?: boolean; handledLanguages: string[]; // list of languages handled by cell language handlers, after the execution engine projectType?: string; + env?: Record; } // result of execution diff --git a/tests/docs/luacov/covtools.ts b/tests/docs/luacov/covtools.ts new file mode 100644 index 00000000000..1982a715205 --- /dev/null +++ b/tests/docs/luacov/covtools.ts @@ -0,0 +1,98 @@ +import { join } from "path/mod.ts"; +import { shortUuid } from "../../../src/core/uuid.ts"; +import { fixupCoverageNames } from "./fixup_coverage.ts"; +import { resourcePath } from "../../../src/core/resources.ts"; + +import type { CoverageEntry } from "./fixup_coverage.ts"; + +export function getDb() { + const testsPath = resourcePath("../../tests"); + return Deno.openKv(join(testsPath, "lua_testcov_tool", "data", "main.db")); +} + +type IncomingCov = { + luacovFilename: string; + testName: string; +}; + +export async function requestIncomingCovFilename(testName: string) { + const db = await getDb(); + + const uuid = shortUuid(); + const testsPath = resourcePath("../../tests"); + + const incomingCovFilename = join( + testsPath, + "lua_testcov_tool", + "data", + "inbound", + `incoming-${uuid}.stats.out`, + ); + + db.set(["incoming", uuid], { + luacovFilename: incomingCovFilename, + testName, + }); + + return incomingCovFilename; +} + +export async function processIncomingQueue() { + const db = await getDb(); + const quartoPath = resourcePath("../.."); + + const entries = db.list({ prefix: ["incoming"] }); + for await (const entry of entries) { + const { luacovFilename, testName } = entry.value as IncomingCov; + try { + const text = await Deno.readTextFile(luacovFilename); + const coverage = fixupCoverageNames(text); + const normalizedCoverage: Record = {}; + for (const [key, value] of Object.entries(coverage)) { + if (!value.name.startsWith(quartoPath)) { + console.log( + `coverage name ${value.name} not in main path, won't normalize`, + ); + } + normalizedCoverage[key.replace(quartoPath, "")] = value; + } + + // break up the coverage object into tiny objects that fit + // the 64k limit of the kv store + for (const [key, value] of Object.entries(normalizedCoverage)) { + await db.set(["coverage", testName, key], { + coverage: value, + }); + } + + await db.delete(entry.key); + await Deno.remove(luacovFilename); + } catch (e) { + console.log(e); + // do nothing + } + } +} + +export async function getTestsCovering( + file: string, + lineNumber?: number, +) { + const tests: string[] = []; + const db = await getDb(); + + // this is pretty inefficient, + // shrug for now + const entries = db.list({ prefix: ["coverage"] }); + for await (const entry of entries) { + const key = entry.key; + const value = entry.value as { coverage: CoverageEntry }; + if (key[key.length - 1] !== file) { + continue; + } + if (lineNumber === undefined || value.coverage.entries[lineNumber - 1]) { + tests.push(key[1] as string); + } + } + return tests; +} diff --git a/tests/docs/luacov/fixup_coverage.ts b/tests/docs/luacov/fixup_coverage.ts new file mode 100644 index 00000000000..499f465c699 --- /dev/null +++ b/tests/docs/luacov/fixup_coverage.ts @@ -0,0 +1,98 @@ +export type CoverageEntry = { + count: number; + name: string; + entries: number[]; +}; + +export function fixupCoverageNames( + text: string, +): Record { + let count = 0; + let name = ""; + const allEntries: Record = {}; + + for (const line of text.split("\n")) { + if (line === "") { + continue; + } + const entries = line.split(":"); + if (entries.length < 2) { + const numEntries = line.trim().split(" ").map((x) => parseInt(x)); + if (allEntries[name] === undefined) { + allEntries[name] = { + count, + name, + entries: numEntries, + }; + } else { + allEntries[name] = { + count: allEntries[name].count + count, + name, + entries: allEntries[name].entries.map((x: number, i: number) => + x + numEntries[i] + ), + }; + } + continue; + } + let countStr: string; + [countStr, name] = entries; + count = parseInt(countStr); + // exceedingly dumb path normalizer + let oldLength; + if (name.startsWith("/")) { + do { + oldLength = name.length; + name = name.replaceAll(/[/]([^/]+)[/]\.\.[/]/g, "/").replaceAll( + "/./", + "/", + ); + } while (name.length < oldLength); + } + } + return allEntries; +} + +export function fixupCoverageNamesAsText(text: string) { + const result = []; + for (const entry of Object.values(fixupCoverageNames(text))) { + result.push(`${entry.count}:${entry.name}`); + result.push(entry.entries.join(" ")); + } + return result.join("\n"); +} + +if (import.meta.main) { + const text = Deno.readTextFileSync(Deno.args[0]); + for (const entry of Object.values(fixupCoverageNames(text))) { + console.log(`${entry.count}:${entry.name}`); + console.log(entry.entries.join(" ")); + } +} + +/* +22:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/extensions/quarto/docusaurus/docusaurus_renderers.lua +55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 +33:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/extensions/quarto/docusaurus/docusaurus_utils.lua +55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 55 55 55 +86:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/extensions/quarto/kbd/kbd.lua +0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 55 +334:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/extensions/quarto/video/video.lua +0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 55 0 0 0 55 0 0 0 55 0 55 0 55 55 55 55 55 0 0 55 55 55 55 55 0 0 55 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 55 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 55 55 55 55 55 55 55 55 55 55 0 0 0 0 55 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 55 55 +479:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/customnodes.lua +0 0 0 0 0 55 0 55 55 55 0 55 67 67 15 52 4 0 48 0 55 0 55 30434 264 0 30170 55 0 55 3190 0 0 0 3190 3190 3190 9198 6008 6008 5917 5917 5917 0 5454 4701 1582 0 3190 0 0 1417 0 0 0 0 0 0 0 0 1417 3190 0 0 3190 618 2572 1553 0 1553 0 495 1058 0 660 660 660 660 660 0 0 0 0 0 0 1155 0 0 1155 0 0 0 0 0 0 0 1417 0 0 0 0 1417 1417 495 0 0 0 0 0 0 0 0 495 495 0 0 495 0 0 0 922 922 0 0 4757 3835 922 0 0 261 0 0 261 261 261 0 261 261 103 103 37 0 0 66 36 0 30 0 1080 0 922 18974 253 0 0 253 0 18721 468 0 18253 15640 0 2613 922 0 922 10011 8 0 8 8 0 0 0 0 0 0 10003 8 0 9995 3054 0 6941 922 0 922 0 0 0 0 0 0 0 0 0 0 0 0 922 55 0 55 33 33 29 4 4 0 0 0 0 0 33 33 33 33 33 33 0 33 55 0 55 33 33 33 0 33 33 55 0 55 55 55 0 0 36 36 86 50 50 50 0 91 0 0 33 185 33 33 0 160 160 33 0 127 127 127 7 0 120 120 0 0 120 0 0 0 0 120 120 0 0 120 120 2 118 0 0 118 0 33 0 203 203 145 145 0 58 58 0 58 0 0 0 0 0 58 36 0 58 58 30 0 28 0 91 33 55 0 0 33 0 0 0 33 33 0 66 363 33 0 220 187 33 33 55 0 0 264 264 264 0 0 0 264 264 264 264 0 264 0 0 0 264 264 0 264 55 0 0 605 605 0 0 0 0 605 0 0 0 0 605 0 605 1155 550 605 0 0 0 0 0 0 0 605 605 1320 880 440 0 165 0 0 605 33 0 33 33 0 0 0 0 0 605 0 0 605 660 0 0 1650 1650 0 0 0 0 1650 440 0 0 0 1650 1705 0 0 3866 3866 3866 0 0 0 0 0 0 55 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 55 0 55 0 55 55 55 0 0 55 55 0 0 0 0 0 55 0 55 0 110 0 55 +37:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/emulatedfilter.lua +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 110 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 110 110 55 +22:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/parse.lua +0 0 0 0 0 0 3599 1920 1920 1920 7 0 1679 1679 55 0 55 55 55 55 55 110 +64:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/render.lua +0 0 0 0 0 55 0 29 58 0 13 42 0 29 55 0 55 0 0 0 0 32 0 3 29 0 7 0 22 0 32 32 3 0 0 32 32 0 0 0 0 32 105 105 32 0 0 0 0 0 0 0 0 0 0 0 0 55 0 55 55 55 55 110 +153:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/runemulation.lua +0 0 0 0 0 55 0 0 55 3466 0 3411 550 0 0 0 0 550 1100 550 54 0 550 550 496 0 0 0 0 0 2915 0 0 0 0 2915 0 2915 0 0 2915 0 0 0 6326 3411 0 0 3411 0 3411 3411 3411 55 55 55 55 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 55 55 0 55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 55 55 0 55 0 0 55 0 3575 3520 0 3355 165 221 56 112 56 56 0 165 0 0 0 0 0 55 0 55 55 0 55 0 55 55 110 55 55 0 0 110 55 0 55 0 55 0 0 0 0 0 55 110 +73:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/traceexecution.lua +0 0 0 0 0 55 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 110 55 2970 55 110 55 +195:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./ast/wrappedwriter.lua +0 0 0 0 0 55 110 55 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 110 +156:/Users/cscheid/repos/github/quarto-dev/quarto-cli/src/resources/filters/./common/base64.lua +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 55 55 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 110 0 110 0 0 0 0 55 110 7370 110 110 110 220 7150 110 110 55 0 55 55 3630 3575 55 55 55 0 55 55 0 55 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 55 40 40 40 40 2640 2600 2560 0 40 40 0 40 40 40 40 40 924 884 884 884 0 0 0 0 0 0 0 0 884 884 0 884 884 0 40 12 12 12 28 20 20 20 0 40 110 +*/ diff --git a/tests/docs/luacov/query.ts b/tests/docs/luacov/query.ts new file mode 100644 index 00000000000..c1d8362ad15 --- /dev/null +++ b/tests/docs/luacov/query.ts @@ -0,0 +1,19 @@ +import { getTestsCovering, processIncomingQueue } from "./covtools.ts"; +import { resourcePath } from "../../../src/core/resources.ts"; +import { join } from "path/mod.ts"; + +if (import.meta.main) { + const quartoPath = resourcePath("../.."); + + await processIncomingQueue(); + let path = Deno.args[0]; + if (!path.startsWith("/")) { + path = join(Deno.cwd(), path); + } + path = path.replace(quartoPath, ""); + const line = Number(Deno.args[1]); + const tests = await getTestsCovering(path, isNaN(line) ? undefined : line); + for (const test of tests) { + console.log(test); + } +} diff --git a/tests/test.ts b/tests/test.ts index 0d54b0bd5d0..ef7d17d9796 100644 --- a/tests/test.ts +++ b/tests/test.ts @@ -1,9 +1,8 @@ /* -* test.ts -* -* Copyright (C) 2020-2022 Posit Software, PBC -* -*/ + * test.ts + * + * Copyright (C) 2020-2023 Posit Software, PBC + */ import { existsSync } from "fs/mod.ts"; import { fail } from "testing/asserts.ts"; import { warning } from "log/mod.ts"; @@ -17,6 +16,7 @@ import { runningInCI } from "../src/core/ci-info.ts"; import { relative } from "path/mod.ts"; import { quartoConfig } from "../src/core/quarto.ts"; import { fromFileUrl } from "path/win32.ts"; +import { requestIncomingCovFilename } from "./docs/luacov/covtools.ts"; export interface TestDescriptor { // The name of the test @@ -57,12 +57,21 @@ export interface TestContext { ignore?: boolean; } -export function testQuartoCmd( +export async function testQuartoCmd( cmd: string, args: string[], verify: Verify[], context?: TestContext, ) { + if (Deno.env.get("QUARTO_FINE_GRAINED_LUACOV")) { + const testCovFilename = await requestIncomingCovFilename( + [cmd, ...args].join(" "), + ); + args.push( + "--env", + `QUARTO_LUACOV=${testCovFilename}`, + ); + } const name = `quarto ${cmd} ${args.join(" ")}`; test({ name, @@ -161,11 +170,10 @@ export function test(test: TestDescriptor) { }; let lastVerify; try { - try { await test.execute(); } catch (e) { - logError(e) + logError(e); } // Cleanup the output logging From c27628ce1fd2bb5ac4169bffe2676bf5e10d3520 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Sat, 14 Oct 2023 09:26:52 -0700 Subject: [PATCH 2/3] basic finegrained coverage tool --- src/resources/filters/ast/runemulation.lua | 9 ++ src/resources/pandoc/datadir/init.lua | 2 +- .../pandoc/datadir/luacov/reporter.lua | 110 +++++++++--------- .../pandoc/datadir/luacov/runner.lua | 38 +++--- tests/test.ts | 2 +- 5 files changed, 86 insertions(+), 75 deletions(-) diff --git a/src/resources/filters/ast/runemulation.lua b/src/resources/filters/ast/runemulation.lua index e5101952557..b0e304cc305 100644 --- a/src/resources/filters/ast/runemulation.lua +++ b/src/resources/filters/ast/runemulation.lua @@ -155,5 +155,14 @@ function run_as_extended_ast(specTable) end end + if luacov_runner ~= nil then + table.insert(pandocFilterList, { + Pandoc = function(doc) + luacov_runner.shutdown() + return nil + end + }) + end + return pandocFilterList end \ No newline at end of file diff --git a/src/resources/pandoc/datadir/init.lua b/src/resources/pandoc/datadir/init.lua index e7b83c4d103..28dda8de3e8 100644 --- a/src/resources/pandoc/datadir/init.lua +++ b/src/resources/pandoc/datadir/init.lua @@ -1445,7 +1445,7 @@ function require(modname) end if os.getenv("QUARTO_LUACOV") ~= nil then - require("luacov") + luacov_runner = require("luacov") end -- resolves a path, providing either the original path diff --git a/src/resources/pandoc/datadir/luacov/reporter.lua b/src/resources/pandoc/datadir/luacov/reporter.lua index 0aadce12b35..657e556646a 100644 --- a/src/resources/pandoc/datadir/luacov/reporter.lua +++ b/src/resources/pandoc/datadir/luacov/reporter.lua @@ -7,7 +7,7 @@ local reporter = {} local LineScanner = require("luacov.linescanner") local luacov = require("luacov.runner") local util = require("luacov.util") -local lfs_ok, lfs = pcall(require, "lfs") +-- local lfs_ok, lfs = pcall(require, "lfs") ---------------------------------------------------------------- local dir_sep = package.config:sub(1, 1) @@ -97,60 +97,60 @@ function ReporterBase:new(conf) -- including files without tests -- only .lua files - if conf.includeuntestedfiles then - if not lfs_ok then - print("The option includeuntestedfiles requires the lfs module (from luafilesystem) to be installed.") - os.exit(1) - end - - local function add_empty_file_coverage_data(file_path) - - -- Leading "./" must be trimmed from the file paths because the paths of tested - -- files do not have a leading "./" either - if (file_path:match("^%.[/\\]")) then - file_path = file_path:sub(3) - end - - if luacov.file_included(file_path) then - local file_stats = { - max = 0, - max_hits = 0 - } - - local filename = luacov.real_name(file_path) - - if not filtered_data[filename] then - table.insert(files, filename) - filtered_data[filename] = file_stats - end - end - - end - - local function add_empty_dir_coverage_data(directory_path) - - for filename, attr in dirtree(directory_path) do - if attr.mode == "file" and fileMatches(filename, '.%.lua$') then - add_empty_file_coverage_data(filename) - end - end - - end - - if (conf.includeuntestedfiles == true) then - add_empty_dir_coverage_data("." .. dir_sep) - - elseif (type(conf.includeuntestedfiles) == "table" and conf.includeuntestedfiles[1]) then - for _, include_path in ipairs(conf.includeuntestedfiles) do - if (fileMatches(include_path, '.%.lua$')) then - add_empty_file_coverage_data(include_path) - else - add_empty_dir_coverage_data(include_path) - end - end - end - - end + -- if conf.includeuntestedfiles then + -- if not lfs_ok then + -- print("The option includeuntestedfiles requires the lfs module (from luafilesystem) to be installed.") + -- os.exit(1) + -- end + + -- local function add_empty_file_coverage_data(file_path) + + -- -- Leading "./" must be trimmed from the file paths because the paths of tested + -- -- files do not have a leading "./" either + -- if (file_path:match("^%.[/\\]")) then + -- file_path = file_path:sub(3) + -- end + + -- if luacov.file_included(file_path) then + -- local file_stats = { + -- max = 0, + -- max_hits = 0 + -- } + + -- local filename = luacov.real_name(file_path) + + -- if not filtered_data[filename] then + -- table.insert(files, filename) + -- filtered_data[filename] = file_stats + -- end + -- end + + -- end + + -- local function add_empty_dir_coverage_data(directory_path) + + -- for filename, attr in dirtree(directory_path) do + -- if attr.mode == "file" and fileMatches(filename, '.%.lua$') then + -- add_empty_file_coverage_data(filename) + -- end + -- end + + -- end + + -- if (conf.includeuntestedfiles == true) then + -- add_empty_dir_coverage_data("." .. dir_sep) + + -- elseif (type(conf.includeuntestedfiles) == "table" and conf.includeuntestedfiles[1]) then + -- for _, include_path in ipairs(conf.includeuntestedfiles) do + -- if (fileMatches(include_path, '.%.lua$')) then + -- add_empty_file_coverage_data(include_path) + -- else + -- add_empty_dir_coverage_data(include_path) + -- end + -- end + -- end + + -- end table.sort(files) diff --git a/src/resources/pandoc/datadir/luacov/runner.lua b/src/resources/pandoc/datadir/luacov/runner.lua index c97a7ce2896..0766fdfac4a 100644 --- a/src/resources/pandoc/datadir/luacov/runner.lua +++ b/src/resources/pandoc/datadir/luacov/runner.lua @@ -139,8 +139,8 @@ local on_exit_run_once = false local function on_exit() -- Lua >= 5.2 could call __gc when user call os.exit -- so this method could be called twice - if on_exit_run_once then return end - on_exit_run_once = true + -- if on_exit_run_once then return end + -- on_exit_run_once = true -- disable hooks before aggregating stats debug.sethook(nil) runner.save_stats() @@ -424,16 +424,18 @@ local hook_per_thread -- Determines whether debug hooks are separate for each thread. local function has_hook_per_thread() - if hook_per_thread == nil then - local old_hook, old_mask, old_count = debug.gethook() - local noop = function() end - debug.sethook(noop, "l") - local thread_hook = coroutine.wrap(function() return debug.gethook() end)() - hook_per_thread = thread_hook ~= noop - debug.sethook(old_hook, old_mask, old_count) - end + return false + + -- if hook_per_thread == nil then + -- local old_hook, old_mask, old_count = debug.gethook() + -- local noop = function() end + -- debug.sethook(noop, "l") + -- local thread_hook = coroutine.wrap(function() return debug.gethook() end)() + -- hook_per_thread = thread_hook ~= noop + -- debug.sethook(old_hook, old_mask, old_count) + -- end - return hook_per_thread + -- return hook_per_thread end -------------------------------------------------- @@ -467,10 +469,10 @@ function runner.init(configuration) -- metatable trick on filehandle won't work if Lua exits through -- os.exit() hence wrap that with exit code as well - os.exit = function(...) -- luacheck: no global - on_exit() - raw_os_exit(...) - end + -- os.exit = function(...) -- luacheck: no global + -- on_exit() + -- raw_os_exit(...) + -- end debug.sethook(runner.debug_hook, "l") @@ -503,9 +505,9 @@ function runner.init(configuration) end end - if not runner.tick then - runner.on_exit_trick = on_exit_wrap(on_exit) - end + -- if not runner.tick then + -- runner.on_exit_trick = on_exit_wrap(on_exit) + -- end runner.initialized = true runner.paused = false diff --git a/tests/test.ts b/tests/test.ts index 8c63eb75f66..649312ba478 100644 --- a/tests/test.ts +++ b/tests/test.ts @@ -63,7 +63,7 @@ export async function testQuartoCmd( verify: Verify[], context?: TestContext, ) { - if (Deno.env.get("QUARTO_FINE_GRAINED_LUACOV")) { + if (cmd === "render" && Deno.env.get("QUARTO_FINE_GRAINED_LUACOV")) { const testCovFilename = await requestIncomingCovFilename( [cmd, ...args].join(" "), ); From 61e082115948ab26c2f4d03f2338f9fcc73005f7 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Mon, 16 Oct 2023 08:48:36 -0700 Subject: [PATCH 3/3] remove stale files --- tests/docs/luacov/covtools.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/docs/luacov/covtools.ts b/tests/docs/luacov/covtools.ts index 1982a715205..b054d6a57d1 100644 --- a/tests/docs/luacov/covtools.ts +++ b/tests/docs/luacov/covtools.ts @@ -68,8 +68,12 @@ export async function processIncomingQueue() { await db.delete(entry.key); await Deno.remove(luacovFilename); } catch (e) { - console.log(e); - // do nothing + if (e.name === "NotFound") { + console.log(`file ${luacovFilename} not found, skipping`); + await db.delete(entry.key); + } else { + console.log(e); + } } } }