Add test module

This commit is contained in:
MrKBear 2021-11-28 15:03:37 +08:00
parent 84b927a71b
commit 18b167266d
7 changed files with 254 additions and 25 deletions

View File

@ -1,4 +1,5 @@
import { Logger, LevelLogLabel } from "./logger/index"; import { Logger } from "./logger/Logger";
import { LevelLogLabel } from "./logger/LevelLogLabel";
App<IAppOption>({ App<IAppOption>({

View File

@ -11,7 +11,7 @@ class InternalLogLabel {
* *
*/ */
public static readonly normalStyle:LogStyle = new LogStyle() public static readonly normalStyle:LogStyle = new LogStyle()
.setColor("#CCCCCC").setBorder("4px", "1px solid #979797").setBlank("0 5px"); .setColor("#979797").setBorder("4px", "1px solid #979797").setBlank("0 5px");
/** /**
* *
@ -27,7 +27,7 @@ class InternalLogLabel {
// 获得调用堆栈 // 获得调用堆栈
let stack = StackInfo.getFirstStack(); let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.fileName ?? "Unknown file name", return new LogLabel(stack?.calcFileName() ?? "Unknown file name",
InternalLogLabel.normalStyle, false, true, true); InternalLogLabel.normalStyle, false, true, true);
} }
@ -39,7 +39,7 @@ class InternalLogLabel {
// 获得调用堆栈 // 获得调用堆栈
let stack = StackInfo.getFirstStack(); let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.url ?? "Unknown url", return new LogLabel(stack?.calcPathName() ?? "Unknown url",
InternalLogLabel.normalStyle, false, true, true); InternalLogLabel.normalStyle, false, true, true);
} }
@ -51,7 +51,7 @@ class InternalLogLabel {
// 获得调用堆栈 // 获得调用堆栈
let stack = StackInfo.getFirstStack(); let stack = StackInfo.getFirstStack();
return new LogLabel(stack?.url ?? "Unknown url", return new LogLabel(stack?.calcPathName() ?? "Unknown url",
InternalLogLabel.normalStyle, true, false, true); InternalLogLabel.normalStyle, true, false, true);
} }

View File

@ -1,4 +1,4 @@
import {LOGGER_CONSOLE, LOGGER_FILTER} from "../Config"; import { LOGGER_FILTER, LOGGER_CONSOLE } from "../utils/Config";
import { InternalLogLabel } from "./InternalLogLabel"; import { InternalLogLabel } from "./InternalLogLabel";
import { LogLabel } from "./LogLabel"; import { LogLabel } from "./LogLabel";
import { MultipleLogContent } from "./MultipleLogContent"; import { MultipleLogContent } from "./MultipleLogContent";
@ -147,12 +147,12 @@ class Logger {
public static logLine<T>(content:T, ...labels:LogLabel[]):T { public static logLine<T>(content:T, ...labels:LogLabel[]):T {
return Logger.logBase<Array<T>>( return Logger.logBase<Array<T>>(
new MultipleLogContent<Array<T>>(content), labels, new MultipleLogContent<Array<T>>(content), labels,
[InternalLogLabel.urlLabel, InternalLogLabel.blankLabel] [InternalLogLabel.fileNameLabel, InternalLogLabel.blankLabel]
)[0]; )[0];
} }
/** /**
* Logger.logMultiple * Logger.logLine
*/ */
public static ll:typeof Logger.logLine = Logger.logLine; public static ll:typeof Logger.logLine = Logger.logLine;
@ -164,7 +164,7 @@ class Logger {
public static logLineMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T { public static logLineMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T {
return Logger.logBase<T>( return Logger.logBase<T>(
new MultipleLogContent<T>(...content), labels, new MultipleLogContent<T>(...content), labels,
[InternalLogLabel.urlLabel, InternalLogLabel.blankLabel] [InternalLogLabel.fileNameLabel, InternalLogLabel.blankLabel]
); );
} }

View File

@ -19,13 +19,46 @@ class StackInfo {
*/ */
public url:string | undefined; public url:string | undefined;
public setInfo(functionName:string, fileName:string, url:string):StackInfo { /**
*
*/
public fileNameLine: string | undefined;
/**
*
* @param functionName
* @param fileName
* @param url
*/
public setInfo(functionName:string, fileNameLine:string, url:string):StackInfo {
this.functionName = functionName; this.functionName = functionName;
this.fileName = fileName; this.fileNameLine = fileNameLine;
this.url = url; this.url = url;
return this; return this;
} }
/**
*
*/
public calcFileName():string | undefined {
let replaceToTs = this.fileNameLine?.replace(".js", ".ts");
let matched = replaceToTs?.match(/^(.+\.(js|ts)):\d+:\d+$/);
return matched ? matched[1] : undefined;
}
/**
*
*/
public calcPathName():string | undefined {
let replaceToTs = this.url?.replace(".js", ".ts");
let matched = replaceToTs?.match(/^https?:\/\/(\d+\.){3}\d+:\d+\/(.+):\d+:\d+$/);
return matched ? matched[2] : undefined;
}
/** /**
* *
*/ */
@ -65,7 +98,7 @@ class StackInfo {
/** /**
* *
*/ */
public static readonly excludeFile:RegExp = /^Logger\.js:\d+:\d+/; public static readonly excludeFile:RegExp = /^.*(\\|\/)logger(\\|\/).+\.js:\d+:\d+/;
/** /**
* *
@ -76,9 +109,9 @@ class StackInfo {
for(let i = 0; i < callStack.length; i++) { for(let i = 0; i < callStack.length; i++) {
if(!callStack[i].fileName) continue; if(!callStack[i].url) continue;
if(!StackInfo.excludeFile.test(callStack[i].fileName ?? "")) { if(!StackInfo.excludeFile.test(callStack[i].url ?? "")) {
return callStack[i]; return callStack[i];
} }
} }

View File

@ -1,11 +0,0 @@
import Logger from "./Logger";
export default Logger;
export { Logger };
export { InternalLogLabel } from "./InternalLogLabel";
export { MultipleLogContent } from "./MultipleLogContent";
export { LevelLogLabel } from "./LevelLogLabel";
export { LogLabel } from "./LogLabel";
export { LogStyle } from "./LogStyle";
export { StackInfo } from "./StackInfo";

View File

@ -0,0 +1,206 @@
// import { Logger } from "../logger/Logger";
import { LogStyle } from "../logger/LogStyle";
import { LogLabel } from "../logger/LogLabel";
/**
*
*/
class TestResult {
/**
*
*/
public caseName:string;
/**
*
*/
public result:boolean;
/**
*
*/
public message:string;
/**
*
*/
public attach:string;
/**
*
* @param caseName
*/
constructor(caseName:string) {
this.caseName = caseName;
this.result = false;
this.message = "";
this.attach = "";
}
/**
*
*/
public setResult(result:boolean, message?:string, attach?:string) {
this.result = result;
this.message = message ?? (result ? "success!" : "failed!");
this.attach = attach ?? this.attach;
return this;
}
}
/**
*
*/
type TestFunction = () => TestResult | Promise<TestResult>;
/**
*
*/
class CaseCollect {
/**
*
*/
public key:string;
/**
*
*/
public caseFunction:TestFunction;
/**
*
*/
result: Promise<TestResult> | undefined;
/**
* @param key
* @param caseFunction
*/
public constructor(key:string, caseFunction:TestFunction) {
this.key = key;
this.caseFunction = caseFunction;
}
/**
*
*/
public async runTestCase():Promise<CaseCollect> {
let result = this.caseFunction();
if(result instanceof Promise) {
this.result = result;
} else {
this.result = Promise.resolve(result);
}
return this;
}
public static readonly baseStyle = new LogStyle().setBlank();
public static readonly successLabel:LogLabel = new LogLabel("√",
new LogStyle().setBlank("0 4px").setBorder("1000px", "1px solid green")
);
/**
*
* @param current
* @param total
*/
public printResult(current?:number, total?:number) {
// 如果测试没有运行,先运行它
if(this.result === void 0) this.runTestCase();
this.result?.then((res) => {
if(res.result) {
console.log(
`%c√%c %c1/1%c %c${ this.key }%c ` + res.message,
"padding:0 4px; border-radius:1000px; border:1px solid green; color:green",
"", "padding:0 4px; border-radius:4px; border:1px solid green; color:green",
"", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797",
""
)
} else {
console.log(
`%c√%c %c1/1%c %c${ this.key }%c ` + res.message,
"padding:0 4px; border-radius:1000px; border:1px solid red; color:red",
"", "padding:0 4px; border-radius:4px; border:1px solid red; color:red",
"", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797",
""
)
}
console.log(res)
})
}
/**
*
* @param testCaseClass
*/
public static collectCase(testCaseClass:ITestCase):CaseCollect[] {
// 获取静态方法 key
let key = Object.getOwnPropertyNames(testCaseClass);
// 过滤掉通用的方法和属性
key = key.filter((key) => !/(length|name|prototype)/.test(key) );
// 生成 CaseCollect
let caseCollect = [];
for (let i = 0; i < key.length; i++) {
caseCollect.push(new CaseCollect(key[i], testCaseClass[key[i]]))
}
return caseCollect;
}
/**
*
*/
public static async runCollectCase(cases:CaseCollect[]):Promise<CaseCollect[]> {
let running:Promise<CaseCollect>[] = [];
for(let i = 0; i < cases.length; i++) {
running.push(cases[i].runTestCase());
}
return Promise.all(running);
}
/**
*
*/
public static runUnitTest(testCaseClass:ITestCase) {
let caseCollect = this.collectCase(testCaseClass);
CaseCollect.runCollectCase(caseCollect).then((caseCollect:CaseCollect[]) => {
for(let i = 0; i < caseCollect.length; i++) {
caseCollect[i].printResult()
}
})
}
}
/**
*
*/
interface ITestCase {
/**
*
*/
[key:string]:TestFunction;
}
export default ITestCase;
export { ITestCase, TestResult, TestFunction, CaseCollect };