feat: tests

This commit is contained in:
2023-04-21 12:08:35 +02:00
parent 8cb9285462
commit d8c79256c9
140 changed files with 2100 additions and 2693 deletions

View File

@@ -17,7 +17,6 @@ import {Command} from 'commander';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {copy} from 'fs-extra';
import path from 'path';
import {mkdirPromisified, readFilePromisified} from './common.js';
import {lightweightDefinitionsFromPath, lightweightProjectFromPath} from '@openstapps/easy-ast';
import {openapi3Template} from './resources/openapi-303-template.js';
import {gatherRouteInformation, generateOpenAPIForRoute} from './routes.js';
@@ -27,6 +26,7 @@ import {UMLConfig} from './uml/uml-config.js';
import {capitalize} from './util/string.js';
import {validateFiles, writeReport} from './validate.js';
import {fileURLToPath} from 'url';
import {mkdir, readFile} from 'fs/promises';
// handle unhandled promise rejections
process.on('unhandledRejection', async (reason: unknown) => {
@@ -42,7 +42,7 @@ const commander = new Command('openstapps-core-tools');
// eslint-disable-next-line unicorn/prefer-module
commander.version(
JSON.parse(
readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json')).toString(),
readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json')).toString(),
).version,
);
@@ -100,7 +100,7 @@ commander
// copy schema json schema files
try {
if (!existsSync(outDirectorySchemasPath)) {
await mkdirPromisified(outDirectorySchemasPath, {
await mkdir(outDirectorySchemasPath, {
recursive: true,
});
}
@@ -134,7 +134,7 @@ commander.command('schema <srcPath> <schemaPath>').action(async (relativeSourceP
Logger.info(`Found ${validatableTypes.length} type(s) to generate schemas for.`);
await mkdirPromisified(schemaPath, {
await mkdir(schemaPath, {
recursive: true,
});
@@ -150,7 +150,7 @@ commander.command('schema <srcPath> <schemaPath>').action(async (relativeSourceP
Logger.info(`Using ${corePackageJsonPath} to determine version for schemas.`);
const buffer = await readFilePromisified(corePackageJsonPath);
const buffer = await readFile(corePackageJsonPath);
const corePackageJson = JSON.parse(buffer.toString());
const coreVersion = corePackageJson.version;

View File

@@ -13,17 +13,8 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Logger} from '@openstapps/logger';
import {existsSync, mkdir, readFile, unlink, writeFile} from 'fs';
import glob from 'glob';
import {platform} from 'os';
import {promisify} from 'util';
import path from 'path';
export const globPromisified = promisify(glob.Glob);
export const mkdirPromisified = promisify(mkdir);
export const readFilePromisified = promisify(readFile);
export const writeFilePromisified = promisify(writeFile);
export const unlinkPromisified = promisify(unlink);
import {existsSync} from 'fs';
/**
* Get path that contains a tsconfig.json
@@ -33,21 +24,15 @@ export const unlinkPromisified = promisify(unlink);
export function getTsconfigPath(startPath: string): string {
let tsconfigPath = startPath;
// see https://stackoverflow.com/questions/9652043/identifying-the-file-system-root-with-node-js
const root = platform() === 'win32' ? process.cwd().split(path.sep)[0] : '/';
// repeat until a tsconfig.json is found
while (!existsSync(path.join(tsconfigPath, 'tsconfig.json'))) {
if (tsconfigPath === root) {
const parent = path.resolve(tsconfigPath, '..');
if (tsconfigPath === parent) {
throw new Error(
`Reached file system root ${root} while searching for 'tsconfig.json' in ${startPath}!`,
`Reached file system root ${parent} while searching for 'tsconfig.json' in ${startPath}!`,
);
}
// pop last directory
const tsconfigPathParts = tsconfigPath.split(path.sep);
tsconfigPathParts.pop();
tsconfigPath = tsconfigPathParts.join(path.sep);
tsconfigPath = parent;
}
Logger.info(`Using 'tsconfig.json' from ${tsconfigPath}.`);

View File

@@ -1,11 +1,11 @@
export * from './validate.js'
export * from './types/validator.js'
export * from './validate.js';
export * from './types/validator.js';
export * from './uml/uml-config.js'
export * from './uml/create-diagram.js'
export * from './uml/uml-config.js';
export * from './uml/create-diagram.js';
export * from './routes.js'
export * from './types/routes.js'
export * from './routes.js';
export * from './types/routes.js';
export * from './schema.js'
export * from './types/schema.js'
export * from './schema.js';
export * from './types/schema.js';

View File

@@ -13,7 +13,11 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {OpenAPIV3} from 'openapi-types';
import {isLightweightClass, lightweightProjectFromPath, LightweightProjectWithIndex} from '@openstapps/easy-ast';
import {
isLightweightClass,
lightweightProjectFromPath,
LightweightProjectWithIndex,
} from '@openstapps/easy-ast';
import {RouteInstanceWithMeta, RouteWithMetaInformation} from './types/routes.js';
import {rejectNil} from './util/collections.js';
import {capitalize} from './util/string.js';

View File

@@ -22,7 +22,7 @@ import {getTsconfigPath} from './common.js';
import {definitionsOf, lightweightProjectFromPath} from '@openstapps/easy-ast';
import {isSchemaWithDefinitions} from './util/guards.js';
import path from 'path';
import re2 from './types/re2.js';
import re2 from 're2';
/**
* StAppsCore converter
@@ -64,7 +64,7 @@ export class Converter {
this.generator = new SchemaGenerator(program, createParser(program, config), createFormatter(config));
// create Ajv instance
this.schemaValidator = new Ajv.default({code: {regExp: re2}});
this.schemaValidator = new Ajv.default({code: {regExp: re2 as never}});
}
/**

View File

@@ -1,6 +0,0 @@
import re2 from 're2';
type Re2 = typeof re2 & {code: string};
(re2 as Re2).code = 'require("lib/types/re2").default';
export default re2 as Re2;

View File

@@ -13,7 +13,6 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Logger} from '@openstapps/logger';
import {createWriteStream} from 'fs';
import * as request from 'got';
import {
expandTypeValue,
@@ -22,9 +21,10 @@ import {
LightweightClassDefinition,
LightweightDefinition,
LightweightProperty,
LightweightType
LightweightType,
} from '@openstapps/easy-ast';
import {UMLConfig} from './uml-config.js';
import {writeFile} from 'fs/promises';
/**
* Converts the lightweight class/enum definitions according to the configuration,
@@ -81,8 +81,8 @@ export async function createDiagramFromString(
plantUmlBaseURL: string,
outputFile = `Diagram-${new Date().toISOString()}`,
) {
// eslint-disable-next-line @typescript-eslint/no-var-requires,unicorn/prefer-module
const plantumlEncoder = require('plantuml-encoder');
// @ts-expect-error no declarations
const plantumlEncoder = await import('plantuml-encoder');
const plantUMLCode = plantumlEncoder.encode(`@startuml\n${modelPlantUMLCode}\n@enduml`);
const url = `${plantUmlBaseURL}/svg/${plantUMLCode}`;
let response;
@@ -100,13 +100,10 @@ export async function createDiagramFromString(
throw error;
}
// attach file extension
const fileName = `${outputFile}.svg`;
try {
createWriteStream(fileName).write(response.body);
Logger.log(`Writen data to file: ${fileName}`);
} catch {
throw new Error('Could not write file. Are you missing permissions?');
}
const fileName = `${outputFile.replace(/[^\w-]/g, '_')}.svg`;
await writeFile(fileName, response.body);
Logger.log(`Writen data to file: ${fileName}`);
return fileName;
}

View File

@@ -17,7 +17,7 @@
*/
export function rejectNil<T>(array: Array<T | undefined | null>): T[] {
// eslint-disable-next-line unicorn/no-null
return array.filter(it => it == null) as T[];
return array.filter(it => it != null) as T[];
}
/**

View File

@@ -15,16 +15,17 @@
import {Logger} from '@openstapps/logger';
import Ajv from 'ajv';
import betterAjvErrors, {IOutputError} from 'better-ajv-errors';
import {PathLike} from 'fs';
import type {PathLike} from 'fs';
import {readFile, writeFile} from 'fs/promises';
import {JSONSchema7} from 'json-schema';
import mustache from 'mustache';
import {Schema} from 'ts-json-schema-generator';
import {globPromisified, readFilePromisified, writeFilePromisified} from './common.js';
import {ExpectedValidationErrors, ValidationError, ValidationResult} from './types/validator.js';
import {isThingWithType} from './util/guards.js';
import path from 'path';
import re2 from './types/re2.js';
import {toPosixPath} from './util/posix-path.js';
import re2 from 're2';
import {glob} from 'glob';
import {fileURLToPath} from 'url';
/**
* StAppsCore validator
@@ -35,13 +36,13 @@ export class Validator {
*/
private readonly ajv = new Ajv.default({
verbose: true,
code: {regExp: re2},
code: {regExp: re2 as never},
});
/**
* Map of schema names to schemas
*/
private readonly schemas: {[type: string]: Schema} = {};
private readonly schemas: { [type: string]: Schema } = {};
/**
* A wrapper function for Ajv that transforms the error into the compatible old error
@@ -58,8 +59,9 @@ export class Validator {
*
* @param schemaDirectory Path to directory that contains schema files
*/
public async addSchemas(schemaDirectory: PathLike): Promise<string[]> {
const schemaFiles = await globPromisified(path.posix.join(toPosixPath(schemaDirectory), '*.json'));
public async addSchemas(schemaDirectory: string): Promise<string[]> {
const searchGlob = path.posix.join(schemaDirectory.replaceAll(path.sep, path.posix.sep), '*.json');
const schemaFiles = await glob(searchGlob);
if (schemaFiles.length === 0) {
throw new Error(`No schema files in ${schemaDirectory.toString()}!`);
@@ -70,7 +72,7 @@ export class Validator {
await Promise.all(
schemaFiles.map(async (file: string) => {
// read schema file
const buffer = await readFilePromisified(file);
const buffer = await readFile(file);
// add schema to map
this.schemas[path.basename(file, '.json')] = JSON.parse(buffer.toString());
@@ -92,7 +94,7 @@ export class Validator {
if (schema === undefined) {
if (isThingWithType(instance)) {
// schema name can be inferred from type string
const schemaSuffix = (instance as {type: string}).type
const schemaSuffix = (instance as { type: string }).type
.split(' ')
.map((part: string) => {
return part.slice(0, 1).toUpperCase() + part.slice(1);
@@ -175,8 +177,8 @@ export async function validateFiles(
const v = new Validator();
await v.addSchemas(schemaDirectory);
// get list of files to test
const testFiles = await globPromisified(path.join(resourcesDirectory, '*.json'));
// get a list of files to test
const testFiles = await glob(path.posix.join(resourcesDirectory.replaceAll(path.sep, path.posix.sep), '*.json'), {absolute: true});
if (testFiles.length === 0) {
throw new Error(`No test files in ${resourcesDirectory}!`);
@@ -191,7 +193,7 @@ export async function validateFiles(
testFiles.map(async (testFile: string) => {
const testFileName = path.basename(testFile);
const buffer = await readFilePromisified(path.join(resourcesDirectory, testFileName));
const buffer = await readFile(testFile);
// read test description from file
const testDescription = JSON.parse(buffer.toString());
@@ -260,12 +262,14 @@ export async function validateFiles(
* @param errors Errors that occurred in validation
*/
export async function writeReport(reportPath: PathLike, errors: ExpectedValidationErrors): Promise<void> {
// eslint-disable-next-line unicorn/prefer-module
let buffer = await readFilePromisified(path.resolve(__dirname, '..', 'resources', 'file.html.mustache'));
let buffer = await readFile(
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'file.html.mustache'),
);
const fileTemplate = buffer.toString();
// eslint-disable-next-line unicorn/prefer-module
buffer = await readFilePromisified(path.resolve(__dirname, '..', 'resources', 'error.html.mustache'));
buffer = await readFile(
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'error.html.mustache'),
);
const errorTemplate = buffer.toString();
let output = '';
@@ -295,11 +299,12 @@ export async function writeReport(reportPath: PathLike, errors: ExpectedValidati
});
}
// eslint-disable-next-line unicorn/prefer-module
buffer = await readFilePromisified(path.resolve(__dirname, '..', 'resources', 'report.html.mustache'));
buffer = await readFile(
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'report.html.mustache'),
);
const reportTemplate = buffer.toString();
await writeFilePromisified(
await writeFile(
reportPath,
mustache.render(reportTemplate, {
report: output,