Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Vitest as Testing Framework #1132

Merged
merged 9 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,991 changes: 1,874 additions & 2,117 deletions package-lock.json

Large diffs are not rendered by default.

47 changes: 8 additions & 39 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@
"wiki:query-api": "ts-node src/documentation/print-query-wiki.ts",
"wiki:interface": "ts-node src/documentation/print-interface-wiki.ts",
"build": "tsc --project .",
"build:bundle-flowr": "npm run build && esbuild --bundle dist/src/cli/flowr.js --platform=node --bundle --minify --target=node18 --outfile=dist/src/cli/flowr.min.js",
"build:bundle-flowr": "npm run build && esbuild --bundle dist/src/cli/flowr.js --platform=node --bundle --minify --target=node22 --outfile=dist/src/cli/flowr.min.js",
"lint-local": "npx eslint --version && npx eslint src/ test/ --rule \"no-warning-comments: off\"",
"lint": "npm run license-compat -- --summary && npx eslint --version && npx eslint src/ test/",
"license-compat": "license-checker --onlyAllow 'MIT;MIT OR X11;GPLv2;LGPL;GNUGPL;ISC;Apache-2.0;FreeBSD;BSD-2-Clause;clearbsd;ModifiedBSD;BSD-3-Clause;Python-2.0;Unlicense;WTFPL;BlueOak-1.0.0;CC-BY-4.0;CC-BY-3.0;CC0-1.0;0BSD'",
"doc": "typedoc",
"test": "nyc --no-clean mocha",
"test": "vitest --config test/vitest.config.mts",
"test:coverage": "npm run test -- --coverage",
"performance-test": "func() { cd test/performance/ && bash run-all-suites.sh $1 $2 $3; cd ../../; }; func",
"test-full": "npm run test -- --test-installation",
"test-full": "npm run test:coverage -- --no-watch -- --make-summary --test-installation",
"detect-circular-deps": "npx madge --extensions ts,tsx --circular src/",
"checkup": "npm run flowr -- --execute \":version\" && npm run lint && npm run test-full -- --forbid-only && docker build -t test-flowr -f scripts/Dockerfile . && npm run doc && npm-run-all wiki:*"
},
Expand All @@ -51,33 +52,6 @@
],
"author": "Florian Sihler",
"license": "ISC",
"mocha": {
"require": "ts-node/register",
"timeout": 60000,
"spec": "test/**/*.spec.ts",
"source-map": true,
"recursive": true,
"exit": true,
"produce-source-map": true
},
"nyc": {
"all": true,
"per-file": true,
"check-coverage": false,
"skip-full": true,
"lines": 70,
"extension": [
".ts"
],
"include": [
"src/**/*.ts"
],
"reporter": [
"text",
"lcov",
"cobertura"
]
},
"eslintConfig": {
"settings": {
"import/resolver": {
Expand Down Expand Up @@ -192,33 +166,28 @@
"@commitlint/config-angular": "^19.3.0",
"@eagleoutice/eslint-config-flowr": "^1.0.14",
"@j-ulrich/release-it-regex-bumper": "^5.1.0",
"@types/chai": "^4.3.16",
"@types/chai-as-promised": "^7.1.8",
"@types/command-line-args": "^5.2.3",
"@types/command-line-usage": "^5.0.4",
"@types/mocha": "^10.0.6",
"@types/n-readlines": "^1.0.6",
"@types/n3": "^1.16.4",
"@types/object-hash": "^3.0.6",
"@types/semver": "^7.5.6",
"@types/tmp": "^0.2.6",
"@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"chai": "^4.3.16",
"chai-as-promised": "^7.1.1",
"@vitest/coverage-v8": "^2.1.4",
"esbuild": "^0.23.1",
"eslint": "^8.57.1",
"license-checker": "^25.0.1",
"mocha": "^10.7.3",
"mocha-multi-reporters": "^1.5.1",
"nyc": "^17.0.0",
"npm-run-all": "^4.1.5",
"release-it": "^17.6.0",
"ts-node": "^10.9.2",
"typedoc": "^0.26.7",
"typedoc-plugin-missing-exports": "^3.0.0",
"typedoc-theme-hierarchy": "^5.0.3",
"typedoc-umlclass": "^0.10.0",
"typescript": "^5.6.2"
"typescript": "^5.6.2",
"vitest": "^2.1.4"
},
"dependencies": {
"@xmldom/xmldom": "^0.9.2",
Expand Down
18 changes: 0 additions & 18 deletions test/functionality/_helper/collect-tests.ts

This file was deleted.

85 changes: 16 additions & 69 deletions test/functionality/_helper/label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ import { DefaultMap } from '../../../src/util/defaultmap';
import type { MergeableRecord } from '../../../src/util/objects';
import type { FlowrCapabilityWithPath, SupportedFlowrCapabilityId } from '../../../src/r-bridge/data/get';
import { getAllCapabilities } from '../../../src/r-bridge/data/get';
import { randomString } from '../../../src/util/random';

// map flowr ids to the capabilities
const TheGlobalLabelMap: DefaultMap<string, TestLabel[]> = new DefaultMap(() => []);
export const TheGlobalLabelMap: DefaultMap<string, TestLabel[]> = new DefaultMap(() => []);

const uniqueTestId = (() => {
let id = 0;
return () => id++;
})();
function uniqueTestId(): string {
return randomString(20);
}


const TestLabelContexts = ['parse', 'desugar', 'dataflow', 'other', 'slice', 'output', 'lineage', 'query'] as const;
export type TestLabelContext = typeof TestLabelContexts[number]

export interface TestLabel extends MergeableRecord {
readonly id: number
readonly id: string
readonly name: string
/** even if ids appear multiple times we only want to count each one once */
/** even if ids appear multiple times, we only want to count each one once */
readonly capabilities: ReadonlySet<SupportedFlowrCapabilityId>
/** this is automatically set (hihi) by functions like `assertAst` to correctly derive what part of capability we check */
readonly context: Set<TestLabelContext>
Expand Down Expand Up @@ -67,9 +67,9 @@ export function label(testname: string, ids?: readonly SupportedFlowrCapabilityI

function getFullNameOfLabel(label: TestLabel): string {
if(label.capabilities.size === 0) {
return `#${label.id} ${label.name}`;
return `${label.name}`;
} else {
return `#${label.id} ${label.name} [${[...label.capabilities].join(', ')}]`;
return `${label.name} [${[...label.capabilities].join(', ')}]`;
}
}

Expand Down Expand Up @@ -103,81 +103,31 @@ export function decorateLabelContext(label: TestLabel | string, context: readonl
return getFullNameOfLabel(label);
}

function printIdRange(start: number, last: number): string {
if(start === last) {
return `#${start}`;
} else {
return `#${start}-#${last}`;
}
}

function mergeConsecutiveIds(ids: readonly number[]): string {
if(ids.length === 0) {
return '';
}

const sorted = [...ids].sort((a, b) => a - b);
const result: string[] = [];
let start: number = sorted[0];
let last: number = start;

for(const id of sorted.slice(1)) {
if(id === last + 1) {
last = id;
} else {
result.push(printIdRange(start, last));
start = id;
last = id;
}
}
result.push(printIdRange(start, last));
return `\x1b[36m${result.join('\x1b[m, \x1b[36m')}\x1b[m`;
}

function printCapability(label: FlowrCapabilityWithPath, testNames: TestLabel[]) {
function printMissingCapability(label: FlowrCapabilityWithPath, testNames: readonly TestLabel[]) {
const supportClaim = label.supported ? ` (claim: ${label.supported} supported)` : '';
const paddedLabel = `${' '.repeat(label.path.length * 2 - 2)}[${label.path.join('/')}] ${label.name}${supportClaim}`;
const tests = testNames.length > 1 ? 'tests:' : 'test: ';
// we only have to warn if we claim to support but do not offer
if(testNames.length === 0) {
if(label.supported !== 'not' && label.supported !== undefined) {
console.log(`\x1b[1;31m${paddedLabel} is not covered by any tests\x1b[0m`);
} else {
console.log(`${paddedLabel}`);
}
return;
}

// group by contexts
const contextMap = new DefaultMap<TestLabelContext, TestLabel[]>(() => []);
for(const t of testNames) {
for(const c of t.context) {
contextMap.get(c).push(t);
}
}
let formattedTestNames = '';
for(const [context, tests] of contextMap.entries()) {
const formatted = mergeConsecutiveIds(tests.map(t => t.id));
formattedTestNames += `\n${' '.repeat(label.path.length * 2 - 2)} - ${context} [${tests.length}]: ${formatted}`;
}

console.log(`\x1b[1m${paddedLabel}\x1b[0m is covered by ${testNames.length} ${tests}${formattedTestNames}`);
}

function printLabelSummary(): void {
console.log('== Test Capability Coverage ' + '='.repeat(80));
export function printMissingLabelSummary(map: Map<string, readonly TestLabel[]> | DefaultMap<string, readonly TestLabel[]> = TheGlobalLabelMap): void {
console.log('== Test Capability Coverage (missing only)' + '='.repeat(80));
// only list those for which we have a support claim
const allCapabilities = [...getAllCapabilities()];
const entries = allCapabilities.map(c => [c, TheGlobalLabelMap.get(c.id)] as const);
const entries = allCapabilities.map(c => [c, map.get(c.id)] as const);

for(const [capability, testNames] of entries) {
printCapability(capability, testNames);
printMissingCapability(capability, testNames ?? []);
}

console.log('-- Tests-By-Context (Systematic Only)' + '-'.repeat(80));
const contextMap = new DefaultMap<TestLabelContext, number>(() => 0);
const blockedIds = new Set<number>();
for(const testNames of TheGlobalLabelMap.values()) {
const blockedIds = new Set<string>();
for(const testNames of map.values()) {
for(const t of testNames) {
if(blockedIds.has(t.id)) {
continue;
Expand All @@ -192,6 +142,3 @@ function printLabelSummary(): void {
console.log(`- ${context}: ${count}`);
}
}

after(printLabelSummary);
process.on('exit', printLabelSummary);
9 changes: 0 additions & 9 deletions test/functionality/_helper/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,3 @@ export function setMinLevelOfAllLogs(minLevel: LogLevel, log2File = false) {
});
serverLog.settings.minLevel = LogLevel.Fatal;
}

/**
* Just a convenience function to enable all logs.
*/
export function enableLog(minLevel: LogLevel = LogLevel.Trace) {
// we use a test hook as well to be more flexible
before(() => setMinLevelOfAllLogs(minLevel, false));
setMinLevelOfAllLogs(minLevel, false);
}
11 changes: 1 addition & 10 deletions test/functionality/_helper/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@
import * as dns from 'dns/promises';

/** check if this process has a network connection (yet, the network connection might be slow/blocked in other ways)*/
export const hasNetworkConnection = async(): Promise<boolean> => {
export const checkNetworkConnection = async(): Promise<boolean> => {
const value = (await dns.resolve('google.com').catch(() => {
/* do nothing */
}));
return typeof value === 'object' ? value.length > 0 : false;
};


/** Automatically skip a test if no internet connection is available */
export const testRequiresNetworkConnection = async(test: Mocha.Context): Promise<void> => {
if(!await hasNetworkConnection()) {
console.warn('Skipping test because no internet connection is available');
test.skip();
}
};
4 changes: 2 additions & 2 deletions test/functionality/_helper/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { requestFromInput } from '../../../src/r-bridge/retriever';
import { deterministicCountingIdGenerator } from '../../../src/r-bridge/lang-4.x/ast/model/processing/decorate';
import type { QueryResults, Query, QueryResultsWithoutMeta } from '../../../src/queries/query';
import { SupportedQueries , executeQueries } from '../../../src/queries/query';
import { assert } from 'chai';
import type { VirtualQueryArgumentsWithType } from '../../../src/queries/virtual-query/virtual-queries';
import type { TestLabel } from './label';
import { decorateLabelContext } from './label';
import type { VirtualCompoundConstraint } from '../../../src/queries/virtual-query/compound-query';
import { log } from '../../../src/util/log';
import { dataflowGraphToMermaidUrl } from '../../../src/core/print/dataflow-printer';
import type { PipelineOutput } from '../../../src/core/steps/pipeline/pipeline';
import { assert, test } from 'vitest';


function normalizeResults<Queries extends Query>(result: QueryResults<Queries['type']>): QueryResultsWithoutMeta<Queries> {
Expand Down Expand Up @@ -47,7 +47,7 @@ export function assertQuery<
) {
const effectiveName = decorateLabelContext(name, ['query']);

it(effectiveName, async() => {
test(effectiveName, async() => {
for(const query of queries) {
if(query.type === 'compound') {
continue;
Expand Down
Loading
Loading