Add a tester script
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -2,4 +2,4 @@ | |||||||
| .cache/ | .cache/ | ||||||
| CMakeFiles/ | CMakeFiles/ | ||||||
| CMakeCache.txt | CMakeCache.txt | ||||||
| dub.selections.json | node_modules/ | ||||||
|   | |||||||
							
								
								
									
										462
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										462
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,462 @@ | |||||||
|  | { | ||||||
|  |   "name": "elna", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "lockfileVersion": 3, | ||||||
|  |   "requires": true, | ||||||
|  |   "packages": { | ||||||
|  |     "": { | ||||||
|  |       "name": "elna", | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "license": "MPL-2.0", | ||||||
|  |       "dependencies": { | ||||||
|  |         "chalk": "^5.3.0", | ||||||
|  |         "glob": "^10.4.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@isaacs/cliui": { | ||||||
|  |       "version": "8.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", | ||||||
|  |       "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "string-width": "^5.1.2", | ||||||
|  |         "string-width-cjs": "npm:string-width@^4.2.0", | ||||||
|  |         "strip-ansi": "^7.0.1", | ||||||
|  |         "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", | ||||||
|  |         "wrap-ansi": "^8.1.0", | ||||||
|  |         "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@pkgjs/parseargs": { | ||||||
|  |       "version": "0.11.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", | ||||||
|  |       "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", | ||||||
|  |       "optional": true, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=14" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/ansi-regex": { | ||||||
|  |       "version": "6.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", | ||||||
|  |       "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/ansi-regex?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/ansi-styles": { | ||||||
|  |       "version": "6.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", | ||||||
|  |       "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/ansi-styles?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/balanced-match": { | ||||||
|  |       "version": "1.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | ||||||
|  |       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/brace-expansion": { | ||||||
|  |       "version": "2.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", | ||||||
|  |       "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "balanced-match": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/chalk": { | ||||||
|  |       "version": "5.3.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", | ||||||
|  |       "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": "^12.17.0 || ^14.13 || >=16.0.0" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/chalk?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/color-convert": { | ||||||
|  |       "version": "2.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", | ||||||
|  |       "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "color-name": "~1.1.4" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=7.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/color-name": { | ||||||
|  |       "version": "1.1.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | ||||||
|  |       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/cross-spawn": { | ||||||
|  |       "version": "7.0.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", | ||||||
|  |       "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "path-key": "^3.1.0", | ||||||
|  |         "shebang-command": "^2.0.0", | ||||||
|  |         "which": "^2.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/eastasianwidth": { | ||||||
|  |       "version": "0.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", | ||||||
|  |       "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/emoji-regex": { | ||||||
|  |       "version": "9.2.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", | ||||||
|  |       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/foreground-child": { | ||||||
|  |       "version": "3.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", | ||||||
|  |       "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "cross-spawn": "^7.0.0", | ||||||
|  |         "signal-exit": "^4.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=14" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/isaacs" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/glob": { | ||||||
|  |       "version": "10.4.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", | ||||||
|  |       "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "foreground-child": "^3.1.0", | ||||||
|  |         "jackspeak": "^3.1.2", | ||||||
|  |         "minimatch": "^9.0.4", | ||||||
|  |         "minipass": "^7.1.2", | ||||||
|  |         "path-scurry": "^1.11.1" | ||||||
|  |       }, | ||||||
|  |       "bin": { | ||||||
|  |         "glob": "dist/esm/bin.mjs" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=16 || 14 >=14.18" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/isaacs" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/is-fullwidth-code-point": { | ||||||
|  |       "version": "3.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", | ||||||
|  |       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/isexe": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/jackspeak": { | ||||||
|  |       "version": "3.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", | ||||||
|  |       "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@isaacs/cliui": "^8.0.2" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=14" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/isaacs" | ||||||
|  |       }, | ||||||
|  |       "optionalDependencies": { | ||||||
|  |         "@pkgjs/parseargs": "^0.11.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/lru-cache": { | ||||||
|  |       "version": "10.2.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", | ||||||
|  |       "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": "14 || >=16.14" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/minimatch": { | ||||||
|  |       "version": "9.0.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", | ||||||
|  |       "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "brace-expansion": "^2.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=16 || 14 >=14.17" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/isaacs" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/minipass": { | ||||||
|  |       "version": "7.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", | ||||||
|  |       "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=16 || 14 >=14.17" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/path-key": { | ||||||
|  |       "version": "3.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", | ||||||
|  |       "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/path-scurry": { | ||||||
|  |       "version": "1.11.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", | ||||||
|  |       "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "lru-cache": "^10.2.0", | ||||||
|  |         "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=16 || 14 >=14.18" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/isaacs" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/shebang-command": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "shebang-regex": "^3.0.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/shebang-regex": { | ||||||
|  |       "version": "3.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", | ||||||
|  |       "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/signal-exit": { | ||||||
|  |       "version": "4.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", | ||||||
|  |       "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=14" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/isaacs" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/string-width": { | ||||||
|  |       "version": "5.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", | ||||||
|  |       "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "eastasianwidth": "^0.2.0", | ||||||
|  |         "emoji-regex": "^9.2.2", | ||||||
|  |         "strip-ansi": "^7.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/sindresorhus" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/string-width-cjs": { | ||||||
|  |       "name": "string-width", | ||||||
|  |       "version": "4.2.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | ||||||
|  |       "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "emoji-regex": "^8.0.0", | ||||||
|  |         "is-fullwidth-code-point": "^3.0.0", | ||||||
|  |         "strip-ansi": "^6.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/string-width-cjs/node_modules/ansi-regex": { | ||||||
|  |       "version": "5.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | ||||||
|  |       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/string-width-cjs/node_modules/emoji-regex": { | ||||||
|  |       "version": "8.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", | ||||||
|  |       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/string-width-cjs/node_modules/strip-ansi": { | ||||||
|  |       "version": "6.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | ||||||
|  |       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-regex": "^5.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/strip-ansi": { | ||||||
|  |       "version": "7.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", | ||||||
|  |       "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-regex": "^6.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/strip-ansi?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/strip-ansi-cjs": { | ||||||
|  |       "name": "strip-ansi", | ||||||
|  |       "version": "6.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | ||||||
|  |       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-regex": "^5.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { | ||||||
|  |       "version": "5.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | ||||||
|  |       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/which": { | ||||||
|  |       "version": "2.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", | ||||||
|  |       "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "isexe": "^2.0.0" | ||||||
|  |       }, | ||||||
|  |       "bin": { | ||||||
|  |         "node-which": "bin/node-which" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi": { | ||||||
|  |       "version": "8.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", | ||||||
|  |       "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-styles": "^6.1.0", | ||||||
|  |         "string-width": "^5.0.1", | ||||||
|  |         "strip-ansi": "^7.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/wrap-ansi?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi-cjs": { | ||||||
|  |       "name": "wrap-ansi", | ||||||
|  |       "version": "7.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", | ||||||
|  |       "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-styles": "^4.0.0", | ||||||
|  |         "string-width": "^4.1.0", | ||||||
|  |         "strip-ansi": "^6.0.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/wrap-ansi?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { | ||||||
|  |       "version": "5.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | ||||||
|  |       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { | ||||||
|  |       "version": "4.3.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", | ||||||
|  |       "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "color-convert": "^2.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/chalk/ansi-styles?sponsor=1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { | ||||||
|  |       "version": "8.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", | ||||||
|  |       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi-cjs/node_modules/string-width": { | ||||||
|  |       "version": "4.2.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | ||||||
|  |       "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "emoji-regex": "^8.0.0", | ||||||
|  |         "is-fullwidth-code-point": "^3.0.0", | ||||||
|  |         "strip-ansi": "^6.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { | ||||||
|  |       "version": "6.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | ||||||
|  |       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-regex": "^5.0.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -8,5 +8,9 @@ | |||||||
|     "cross": "node tools/cross.js" |     "cross": "node tools/cross.js" | ||||||
|   }, |   }, | ||||||
|   "author": "Eugen Wissner <belka@caraus.de>", |   "author": "Eugen Wissner <belka@caraus.de>", | ||||||
|   "license": "MPL-2.0" |   "license": "MPL-2.0", | ||||||
|  |   "dependencies": { | ||||||
|  |     "chalk": "^5.3.0", | ||||||
|  |     "glob": "^10.4.1" | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										144
									
								
								tools/tester.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								tools/tester.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | |||||||
|  | import { glob } from 'glob' | ||||||
|  | import path from 'path' | ||||||
|  | import childProcess from 'node:child_process' | ||||||
|  | import fs from 'node:fs/promises' | ||||||
|  | import chalk from 'chalk' | ||||||
|  |  | ||||||
|  | // Define constants. | ||||||
|  | const tmp = path.resolve('./build/riscv') | ||||||
|  | const toolDirectory = path.resolve('./build/tools') | ||||||
|  |  | ||||||
|  | async function compileTest (parsedPath) { | ||||||
|  |   const testObject = path.join(tmp, `tests/${parsedPath.name}.o`) | ||||||
|  |   const compilerArguments = [ | ||||||
|  |     '-o', testObject, | ||||||
|  |     path.join(parsedPath.dir, parsedPath.base) | ||||||
|  |   ] | ||||||
|  |  | ||||||
|  |   return new Promise(function (resolve, reject) { | ||||||
|  |     const compilerChild = childProcess.spawn('./build/bin/elna', compilerArguments) | ||||||
|  |     const buffers = [] | ||||||
|  |  | ||||||
|  |     compilerChild.stdout.on('data', data => buffers.push(data)) | ||||||
|  |     compilerChild.stderr.on('data', data => buffers.push(data)) | ||||||
|  |  | ||||||
|  |     compilerChild.on('exit', function (code, signal) { | ||||||
|  |       resolve({ | ||||||
|  |         code: code === null ? signal : code, | ||||||
|  |         output: Buffer.concat(buffers).toString(), | ||||||
|  |         object: testObject | ||||||
|  |       }) | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function checkFailure (parsedPath, buildResult) { | ||||||
|  |   const diffArguments = [ | ||||||
|  |     '-u', '--color=always', | ||||||
|  |     path.resolve('./tests/failures', `${parsedPath.name}.txt`), | ||||||
|  |     '-' | ||||||
|  |   ] | ||||||
|  |  | ||||||
|  |   try { | ||||||
|  |     childProcess.execFileSync('diff', diffArguments, { | ||||||
|  |       input: buildResult.output, | ||||||
|  |       stdio: ['pipe', 'inherit', 'inherit'] | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     return true | ||||||
|  |   } catch (e) { | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function buildTest (parsedPath) { | ||||||
|  |   const linker = path.join(toolDirectory, 'rootfs/riscv32-unknown-linux-gnu/bin/ld') | ||||||
|  |   const testBinary = path.join(tmp, 'root/tests', parsedPath.name) | ||||||
|  |   const testObject = path.join(tmp, `tests/${parsedPath.name}.o`) | ||||||
|  |  | ||||||
|  |   childProcess.execFileSync(linker, ['-o', testBinary, testObject]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function cpioArchive () { | ||||||
|  |   const cwd = path.join(tmp, 'root') | ||||||
|  |   const cpioImage = path.join(tmp, 'root.cpio') | ||||||
|  |   const rootFiles = (await glob(path.join(cwd, '**'))) | ||||||
|  |     .map(file => path.relative(cwd, file)) | ||||||
|  |     .filter(file => file !== '') | ||||||
|  |   const cpioFile = await fs.open(cpioImage, 'w') | ||||||
|  |   const cpioStream = cpioFile.createWriteStream() | ||||||
|  |   try { | ||||||
|  |     const cpioChild = childProcess.execSync('cpio -o --format=newc', { | ||||||
|  |       stdio: ['pipe', cpioStream, 'ignore'], | ||||||
|  |       input: rootFiles.join("\n"), | ||||||
|  |       cwd, | ||||||
|  |       shell: false | ||||||
|  |     }) | ||||||
|  |     return cpioImage | ||||||
|  |   } finally { | ||||||
|  |     await cpioFile.close() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function runVM(cpioImage) { | ||||||
|  |   const kernels = await glob(path.join(toolDirectory, 'linux-*/arch/riscv/boot/Image')) | ||||||
|  |   const vmArguments = [ | ||||||
|  |       '-nographic', | ||||||
|  |       '-M', 'virt', | ||||||
|  |       '-bios', 'default', | ||||||
|  |       '-kernel', kernels[0], | ||||||
|  |       '-append', 'quiet', | ||||||
|  |       '-initrd', cpioImage | ||||||
|  |   ] | ||||||
|  |   childProcess.execFileSync('qemu-system-riscv32', vmArguments, { | ||||||
|  |     stdio: ['ignore', 'inherit', 'inherit'] | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function runInDirectory (directoryPath) { | ||||||
|  |   const testSources = await glob(path.join(directoryPath, '*.eln')) | ||||||
|  |   let failed = 0 | ||||||
|  |  | ||||||
|  |   for (const testEntry of testSources) { | ||||||
|  |     console.log(`Compiling ${path.basename(testEntry)}.`) | ||||||
|  |  | ||||||
|  |     const parsedPath = path.parse(testEntry) | ||||||
|  |     const buildResult = await compileTest(parsedPath) | ||||||
|  |  | ||||||
|  |     if (buildResult.output !== '') { | ||||||
|  |       if (!(await checkFailure(parsedPath, buildResult))) { | ||||||
|  |         ++failed | ||||||
|  |       } | ||||||
|  |       continue | ||||||
|  |     } | ||||||
|  |     buildTest(parsedPath) | ||||||
|  |   } | ||||||
|  |   const rootDirectory = path.join(tmp, 'root') | ||||||
|  |   await fs.cp('./tests/expectations', path.join(rootDirectory, 'expectations'), { recursive: true }) | ||||||
|  |   await fs.cp(path.join(toolDirectory, 'init'), path.join(rootDirectory, 'init')); | ||||||
|  |   const cpioImage = await cpioArchive() | ||||||
|  |   await runVM(cpioImage) | ||||||
|  |  | ||||||
|  |   return { | ||||||
|  |     total: testSources.length, | ||||||
|  |     failed, | ||||||
|  |  | ||||||
|  |     passed () { | ||||||
|  |       return this.total - this.failed | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function createDirectories () { | ||||||
|  |   await fs.rm(tmp, { recursive: true, force: true }) | ||||||
|  |   await fs.mkdir(path.join(tmp, 'tests'), { recursive: true }) | ||||||
|  |   await fs.mkdir(path.join(tmp, 'root/tests'), { recursive: true }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | console.log('Run all tests and check the results.') | ||||||
|  |  | ||||||
|  | await createDirectories() | ||||||
|  | const results = await runInDirectory('./tests') | ||||||
|  |  | ||||||
|  | const summaryMessage = `${results.total} tests run, ${results.passed()} passed, ${results.failed} failed.` | ||||||
|  | console.log(results.failed === 0 ? chalk.green(summaryMessage) : chalk.yellow(summaryMessage)) | ||||||
		Reference in New Issue
	
	Block a user