diff options
-rw-r--r-- | .devcontainer/Dockerfile | 11 | ||||
-rw-r--r-- | .devcontainer/devcontainer.json | 16 | ||||
-rwxr-xr-x | .devcontainer/post-create.sh | 14 | ||||
-rw-r--r-- | CONTRIBUTING.md | 4 | ||||
-rw-r--r-- | CONTRIBUTORS.md | 1 | ||||
-rw-r--r-- | etc/config/assembly.amazon.properties | 59 | ||||
-rw-r--r-- | lib/compilers/hlsl.ts | 20 | ||||
-rw-r--r-- | static/modes/cppfront-mode.ts | 84 | ||||
-rw-r--r-- | test/demangler-tests.ts (renamed from test/demangler-tests.js) | 82 | ||||
-rw-r--r-- | test/map-file-tests.ts (renamed from test/map-file-tests.js) | 70 | ||||
-rw-r--r-- | test/options-handler.ts (renamed from test/options-handler.js) | 222 | ||||
-rw-r--r-- | test/packager-tests.ts (renamed from test/packager-tests.js) | 2 |
12 files changed, 385 insertions, 200 deletions
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..688e743f9 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,11 @@ +ARG NODE_MAJOR_VERSION + +FROM mcr.microsoft.com/devcontainers/javascript-node:${NODE_MAJOR_VERSION} + +ENV EDITOR="code -w" VISUAL="code -w" + +# install system dependencies for cypress (https://docs.cypress.io/guides/continuous-integration/introduction) +RUN apt update && apt install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb + +# uncomment to install additional npm packages +# RUN su node -c 'npm i -g cowsay@1.5.0' diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..1428e6ac2 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +{ + "name": "compiler-explorer", + "dockerFile": "Dockerfile", + "build": { + "args": {"NODE_MAJOR_VERSION": "20"} + }, + "postCreateCommand": [".devcontainer/post-create.sh"], + "portsAttributes": { + "10240": {"label": "Compiler Explorer"} + }, + "customizations": { + "vscode": { + "extensions": ["dbaeumer.vscode-eslint", "EditorConfig.EditorConfig", "esbenp.prettier-vscode"] + } + } +} diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100755 index 000000000..c7b706cc2 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -eo pipefail + +# when in a VS Code or GitHub Codespaces devcontainer +if [ -n "${REMOTE_CONTAINERS}" ]; then + this_dir=$(cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P) + workspace_root=$(realpath ${this_dir}/..) + + # perform additional one-time setup just after + # the devcontainer is created + npm install --prefix "${workspace_root}" # install node dependencies + +fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1baecb0a..1c3a21241 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,6 +23,10 @@ in the right direction. **Compiler Explorer** currently targets [Node.js](https://nodejs.org/) version 20, so it's better if you do so as well when testing your changes locally. +> Note that this repository is compatible with `GitHub Codespaces` as well as `VS Code Dev Containers`. Opening your +> cloned project with either of these options will ensure that your development environment is already set up and +> configured correctly! + ## In brief - Make your changes, trying to stick to the style and format where possible. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4fcd91f0f..5c6fc4893 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -139,3 +139,4 @@ From oldest to newest contributor, we would like to thank: - [Seyed Ali Ghasemi](https://github.com/gha3mi) - [Guo Ci](https://github.com/guoci) - [Rupert Tombs](https://github.com/Rupt) +- [Andrew Brey](https://github.com/andrewbrey) diff --git a/etc/config/assembly.amazon.properties b/etc/config/assembly.amazon.properties index 055ba2373..2dc7ca81d 100644 --- a/etc/config/assembly.amazon.properties +++ b/etc/config/assembly.amazon.properties @@ -1,4 +1,4 @@ -compilers=&nasm:&gnuas:&llvmas:&ptxas:&gnuasarm:&gnuasarm64:&beebasm +compilers=&nasm:&gnuas:&llvmas:&ptxas:&gnuasarm:&gnuasarm64:&gnuasriscv:&beebasm compilerType=assembly objdumper=/opt/compiler-explorer/gcc-12.1.0/bin/objdump supportsBinary=true @@ -99,6 +99,63 @@ compiler.gnuasarm64g1020.exe=/opt/compiler-explorer/arm64/gcc-10.2.0/aarch64-unk compiler.gnuasarm64g1020.name=AArch64 binutils 2.35.1 compiler.gnuasarm64g1020.semver=2.35.1 +# GNU as for RISC-V +group.gnuasriscv.compilers=&gnuasriscv64:&gnuasriscv32 +group.gnuasriscv.groupName=RISC-V binutils +group.gnuasriscv.isSemVer=true +group.gnuasriscv.options=-g +group.gnuasriscv.supportsExecute=false +group.gnuasriscv.versionFlag=--version + +## GNU as for RISC-V 64-bits +group.gnuasriscv64.compilers=gnuasriscv64g820:gnuasriscv64g1020:gnuasriscv64g1140:gnuasriscv64g1320 +group.gnuasriscv64.groupName=RISC-V (64-bits) binutils +group.gnuasriscv64.baseName=RISC-V (64-bits) binutils + +compiler.gnuasriscv64g820.exe=/opt/compiler-explorer/riscv64/gcc-8.2.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-as +compiler.gnuasriscv64g820.name=RISC-V binutils 2.31.1 +compiler.gnuasriscv64g820.semver=2.31.1 +compiler.gnuasriscv64g820.objdumper=/opt/compiler-explorer/riscv64/gcc-8.2.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-objdump + +compiler.gnuasriscv64g1020.exe=/opt/compiler-explorer/riscv64/gcc-10.2.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-as +compiler.gnuasriscv64g1020.name=RISC-V binutils 2.35.1 +compiler.gnuasriscv64g1020.semver=2.35.1 +compiler.gnuasriscv64g1020.objdumper=/opt/compiler-explorer/riscv64/gcc-10.2.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-objdump + +compiler.gnuasriscv64g1140.exe=/opt/compiler-explorer/riscv64/gcc-11.4.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-as +compiler.gnuasriscv64g1140.name=RISC-V binutils 2.37.0 +compiler.gnuasriscv64g1140.semver=2.37.0 +compiler.gnuasriscv64g1140.objdumper=/opt/compiler-explorer/riscv64/gcc-11.4.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-objdump + +compiler.gnuasriscv64g1320.exe=/opt/compiler-explorer/riscv64/gcc-13.2.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-as +compiler.gnuasriscv64g1320.name=RISC-V binutils 2.38.0 +compiler.gnuasriscv64g1320.semver=2.38.0 +compiler.gnuasriscv64g1320.objdumper=/opt/compiler-explorer/riscv64/gcc-13.2.0/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-objdump + +## GNU as for RISC-V 32-bits +group.gnuasriscv32.compilers=gnuasriscv32g820:gnuasriscv32g1020:gnuasriscv32g1140:gnuasriscv32g1320 +group.gnuasriscv32.groupName=RISC-V (32-bits) binutils +group.gnuasriscv32.baseName=RISC-V (32-bits) binutils + +compiler.gnuasriscv32g820.exe=/opt/compiler-explorer/riscv32/gcc-8.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as +compiler.gnuasriscv32g820.name=RISC-V binutils 2.31.1 +compiler.gnuasriscv32g820.semver=2.31.1 +compiler.gnuasriscv32g820.objdumper=/opt/compiler-explorer/riscv32/gcc-8.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump + +compiler.gnuasriscv32g1020.exe=/opt/compiler-explorer/riscv32/gcc-10.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as +compiler.gnuasriscv32g1020.name=RISC-V binutils 2.35.1 +compiler.gnuasriscv32g1020.semver=2.35.1 +compiler.gnuasriscv32g1020.objdumper=/opt/compiler-explorer/riscv32/gcc-10.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump + +compiler.gnuasriscv32g1140.exe=/opt/compiler-explorer/riscv32/gcc-11.4.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as +compiler.gnuasriscv32g1140.name=RISC-V binutils 2.37.0 +compiler.gnuasriscv32g1140.semver=2.37.0 +compiler.gnuasriscv32g1140.objdumper=/opt/compiler-explorer/riscv32/gcc-11.4.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump + +compiler.gnuasriscv32g1320.exe=/opt/compiler-explorer/riscv32/gcc-13.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as +compiler.gnuasriscv32g1320.name=RISC-V binutils 2.38.0 +compiler.gnuasriscv32g1320.semver=2.38.0 +compiler.gnuasriscv32g1320.objdumper=/opt/compiler-explorer/riscv32/gcc-13.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump group.llvmas.compilers=llvmas30:llvmas31:llvmas32:llvmas33:llvmas341:llvmas350:llvmas351:llvmas352:llvmas37x:llvmas36x:llvmas371:llvmas380:llvmas381:llvmas390:llvmas391:llvmas400:llvmas401:llvmas500:llvmas600:llvmas700:llvmas800:llvmas900:llvmas1000:llvmas1001:llvmas1100:llvmas1101:llvmas1200:llvmas1201:llvmas1300:llvmas1400:llvmas1500:llvmas1600:llvmas1701:llvmas_trunk:llvmas_assertions_trunk group.llvmas.versionFlag=--version diff --git a/lib/compilers/hlsl.ts b/lib/compilers/hlsl.ts index 7050355c1..26d5423b1 100644 --- a/lib/compilers/hlsl.ts +++ b/lib/compilers/hlsl.ts @@ -23,6 +23,7 @@ // POSSIBILITY OF SUCH DAMAGE. import path from 'path'; +import _ from 'underscore'; import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; import {BaseCompiler} from '../base-compiler.js'; @@ -41,6 +42,25 @@ export class HLSLCompiler extends BaseCompiler { this.spirvAsm = new SPIRVAsmParser(this.compilerProps); } + override async generateAST(inputFilename, options) { + // These options make DXC produce an AST dump + const newOptions = _.filter(options, option => option !== '-Zi' && option !== '-Qembed_debug').concat([ + '-ast-dump', + ]); + + const execOptions = this.getDefaultExecOptions(); + // A higher max output is needed for when the user includes headers + execOptions.maxOutput = 1024 * 1024 * 1024; + + return this.llvmAst.processAst( + await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions), + ); + } + + override couldSupportASTDump(version: string) { + return version.includes('libdxcompiler'); + } + /* eslint-disable no-unused-vars */ override optionsForFilter( filters: ParseFiltersAndOutputOptions, diff --git a/static/modes/cppfront-mode.ts b/static/modes/cppfront-mode.ts index 92372b9a9..d7d01cba7 100644 --- a/static/modes/cppfront-mode.ts +++ b/static/modes/cppfront-mode.ts @@ -96,7 +96,12 @@ function definition(): monaco.languages.IMonarchLanguage { cppfront.at_cpp2_balanced_parentheses = balancedParenthesesRegex(5); cppfront.at_cpp2_interpolation = /@at_cpp2_balanced_parentheses\$/; - cppfront.tokenizer.parse_cpp2_interpolation = [[/./, {token: '@rematch', switchTo: 'parse_cpp2_expression'}]]; + cppfront.tokenizer.parse_cpp2_interpolation = [ + [/(\()(.)/, ['delimiter.parenthesis', {token: '@rematch', next: 'parse_cpp2_expression'}]], + [/:[^)]*/, 'string'], + [/\)/, 'delimiter.parenthesis'], + [/\$/, 'delimiter.interpolation', '@pop'], + ]; cppfront.at_cpp2_string_literal = /@encoding?(?:\$?R)?"/; cppfront.tokenizer.parse_cpp2_string_literal = [ @@ -195,13 +200,28 @@ function definition(): monaco.languages.IMonarchLanguage { /@at_cpp2_non_operator_identifier/, { cases: { - '$S2~definition|parameter': {token: 'identifier.definition', next: '@pop'}, + '$S2~definition|parameter': { + token: 'identifier.definition', + switchTo: 'parse_cpp2_parameter_ellipsis.$S2', + }, '$S2==type': {token: 'type.contextual', next: '@pop'}, '@': {token: 'identifier.use', next: '@pop'}, }, }, ], ]; + cppfront.tokenizer.parse_cpp2_parameter_ellipsis = [ + [ + /\.\.\./, + { + cases: { + '$S2==parameter': {token: 'delimiter.ellipsis', next: '@pop'}, + '@': {token: '@rematch', next: '@pop'}, + }, + }, + ], + [/./, '@rematch', '@pop'], + ]; cppfront.at_cpp2_type_qualifier = /const\b|\*/; cppfront.tokenizer.parse_cpp2_type_qualifier_seq = [ @@ -225,9 +245,10 @@ function definition(): monaco.languages.IMonarchLanguage { [/\(/, {token: '@rematch', switchTo: 'parse_cpp2_function_type'}], ]; - cppfront.at_cpp2_template_argument = /@at_cpp2_expression|@at_cpp2_type_id/; + cppfront.at_cpp2_template_argument = /@at_cpp2_string_literal|@at_cpp2_expression|@at_cpp2_type_id/; cppfront.tokenizer.parse_cpp2_template_argument = [ [/@at_cpp2_keyword_type/, 'keyword.type', '@pop'], + [/@at_cpp2_type_qualifier/, {token: '@rematch', switchTo: 'parse_cpp2_type_id'}], [/@at_cpp2_expression/, {token: '@rematch', switchTo: 'parse_cpp2_expression.template_argument'}], [/@at_cpp2_type_id/, {token: '@rematch', switchTo: 'parse_cpp2_type_id'}], ]; @@ -251,6 +272,7 @@ function definition(): monaco.languages.IMonarchLanguage { cppfront.tokenizer.parse_cpp2_id_expression = [ {include: '@whitespace'}, [/::/, ''], + [/\.\.\./, '@rematch', '@pop'], [/\./, 'delimiter'], [/@at_cpp2_identifier</, {token: '@rematch', switchTo: 'parse_cpp2_template_id.$S2'}], [/@at_cpp2_non_operator_identifier(?=\s*(?:\.|::))/, '@rematch', 'parse_cpp2_identifier.use'], @@ -277,17 +299,30 @@ function definition(): monaco.languages.IMonarchLanguage { ]; cppfront.at_cpp2_primary_expression = - /@at_cpp2_literal|@at_cpp2_id_expression|\(|@at_cpp2_unnamed_declaration_head/; + /@at_cpp2_literal|@at_cpp2_id_expression|\.\.\.|\(|@at_cpp2_unnamed_declaration_head/; // Can't ensure sequential parsing. cppfront.tokenizer.parse_cpp2_primary_expression = [ [/inspect\b/, '@rematch', 'parse_cpp2_inspect_expression'], // These two happen to parse UDLs: - [/@at_cpp2_literal/, '@rematch', 'parse_cpp2_literal'], - [/@at_cpp2_id_expression/, '@rematch', 'parse_cpp2_primary_expression_id_expression'], + [/@at_cpp2_literal/, {token: '@rematch', switchTo: 'parse_cpp2_primary_expression_literal_.$S2.$S3'}], + [ + /@at_cpp2_id_expression/, + {token: '@rematch', switchTo: 'parse_cpp2_primary_expression_id_expression_.$S2.$S3'}, + ], + [/\.\.\./, 'delimiter.ellipsis'], // Handle `(` later to workaround `(0)is` being parsed as two adjacent primary expressions. [/@at_cpp2_unnamed_declaration_head/, '@rematch', 'parse_cpp2_declaration.expression'], [/./, {token: '@rematch', switchTo: 'parse_cpp2_postfix_expression.$S2.$S3'}], ]; + cppfront.tokenizer.parse_cpp2_primary_expression_id_expression_ = [ + [/@at_cpp2_id_expression/, '@rematch', 'parse_cpp2_primary_expression_id_expression'], + [/\.\.\./, 'delimiter.ellipsis'], + [/./, {token: '@rematch', switchTo: 'parse_cpp2_postfix_expression.$S2.$S3'}], + ]; + cppfront.tokenizer.parse_cpp2_primary_expression_literal_ = [ + [/@at_cpp2_literal/, '@rematch', 'parse_cpp2_literal'], + [/./, {token: '@rematch', switchTo: 'parse_cpp2_postfix_expression.$S2.$S3'}], + ]; cppfront.at_cpp2_postfix_operator = /\+\+|--|~|\$|\*|&/; cppfront.tokenizer.parse_cpp2_postfix_expression = [ @@ -301,7 +336,9 @@ function definition(): monaco.languages.IMonarchLanguage { /./, { token: '@rematch', - switchTo: 'parse_cpp2_is_as_expression_target.parse_cpp2_binary_expression_tail.$S2.$S3', + switchTo: + 'parse_cpp2_is_as_expression_target.parse_cpp2_expression.' + + 'parse_cpp2_binary_expression_tail.$S2.$S3', }, ], ]; @@ -321,17 +358,15 @@ function definition(): monaco.languages.IMonarchLanguage { ]; cppfront.tokenizer.parse_cpp2_is_as_expression_target = [ - // `@$S2` is the continuation parser. + // `@$S2` is the expression parser. + // `@$S3.$S4.$S5` is the continuation parser. {include: '@whitespace'}, [ /(@at_cpp2_is_as_operator)(\s+)(@at_cpp2_type_id)/, ['keyword', '', {token: '@rematch', switchTo: 'parse_cpp2_type_id'}], ], - [ - /(is\b)(\s*)(@at_cpp2_expression)/, - ['keyword', '', {token: '@rematch', switchTo: 'parse_cpp2_expression'}], - ], - [/./, {token: '@rematch', switchTo: '@$S2.$S3.$S4'}], + [/(is\b)(\s*)(@at_cpp2_expression)/, ['keyword', '', {token: '@rematch', switchTo: '@$S2'}]], + [/./, {token: '@rematch', switchTo: '@$S3.$S4.$S5'}], ]; cppfront.at_cpp2_logical_or_operator = /\*|\/|%|\+|-|<<|>>|<=>|<|>|<=|>=|==|!=|&|\^|\||&&|\|\|/; @@ -399,7 +434,11 @@ function definition(): monaco.languages.IMonarchLanguage { cppfront.tokenizer.parse_cpp2_alternative = [ {include: '@whitespace'}, - [/@at_cpp2_is_as_operator/, '@rematch', 'parse_cpp2_is_as_expression_target.pop'], + [ + /@at_cpp2_is_as_operator/, + '@rematch', + 'parse_cpp2_is_as_expression_target.parse_cpp2_logical_or_expression.pop', + ], [/@at_cpp2_non_operator_identifier/, '@rematch', 'parse_cpp2_identifier.definition'], [/@at_cpp2_unnamed_declaration_head/, 'identifier.definition'], [/=/, {token: 'delimiter', switchTo: 'parse_cpp2_statement'}], @@ -645,14 +684,23 @@ function definition(): monaco.languages.IMonarchLanguage { [/./, '@rematch', '@pop'], ]; - cppfront.tokenizer.parse_cpp2_function_type = [ + cppfront.tokenizer.parse_cpp2_full_function_type = [ {include: '@whitespace'}, - [/\(/, '@rematch', 'parse_cpp2_parameter_declaration_list'], [/throws\b/, 'keyword'], [/->/, '@rematch', 'parse_cpp2_return_list'], [/\[/, '@rematch', 'parse_cpp2_contract_seq'], [/./, '@rematch', '@pop'], ]; + cppfront.tokenizer.parse_cpp2_terse_function = [ + {include: '@whitespace'}, + [/\(/, '@rematch', 'parse_cpp2_parameter_declaration_list'], + [/throws\b|->|\[/, {token: '@rematch', switchTo: 'parse_cpp2_full_function_type'}], + [/requires\b|==?|;/, '@rematch', '@pop'], + [/@at_cpp2_expression/, {token: '@rematch', switchTo: 'parse_cpp2_expression'}], + ]; + cppfront.tokenizer.parse_cpp2_function_type = [ + [/./, {token: '@rematch', switchTo: 'parse_cpp2_terse_function'}], + ]; cppfront.tokenizer.parse_cpp2_declaration_initializer = [ [/./, {token: '@rematch', switchTo: 'parse_cpp2_statement.$S2'}], @@ -684,7 +732,8 @@ function definition(): monaco.languages.IMonarchLanguage { ]; cppfront.at_cpp2_unnamed_declaration_head = /:(?!:)/; - cppfront.at_cpp2_identifier_definition = /@at_cpp2_identifier\s*@at_cpp2_unnamed_declaration_head/; + cppfront.at_cpp2_identifier_definition = + /@at_cpp2_identifier\s*(?:\.\.\.)?\s*@at_cpp2_unnamed_declaration_head/; cppfront.at_cpp2_top_level_declaration_head = /(?:@at_cpp2_access_specifier\s+)?(?!@at_cpp2_access_specifier)@at_cpp2_identifier_definition/; cppfront.at_cpp2_declaration_head = /(?:@at_cpp2_access_specifier\s+)?@at_cpp2_identifier_definition/; @@ -693,6 +742,7 @@ function definition(): monaco.languages.IMonarchLanguage { {include: '@whitespace'}, [/@at_cpp2_access_specifier/, 'keyword'], [/@at_cpp2_identifier/, '@rematch', 'parse_cpp2_identifier.$S2'], + [/\.\.\./, 'delimiter.ellipsis'], [ /@at_cpp2_unnamed_declaration_head/, {token: 'identifier.definition', switchTo: 'parse_cpp2_declaration_signature.$S2'}, diff --git a/test/demangler-tests.js b/test/demangler-tests.ts index be227e6bb..b7cf981ff 100644 --- a/test/demangler-tests.js +++ b/test/demangler-tests.ts @@ -22,22 +22,45 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +import {unwrap} from '../lib/assert.js'; +import {BaseCompiler} from '../lib/base-compiler.js'; +import {CompilationEnvironment} from '../lib/compilation-env.js'; import {CppDemangler, Win32Demangler} from '../lib/demangler/index.js'; import {PrefixTree} from '../lib/demangler/prefix-tree.js'; import * as exec from '../lib/exec.js'; +import * as properties from '../lib/properties.js'; import {SymbolStore} from '../lib/symbol-store.js'; import * as utils from '../lib/utils.js'; -import {chai, fs, path, resolvePathFromTestRoot} from './utils.js'; +import {chai, fs, makeFakeCompilerInfo, path, resolvePathFromTestRoot} from './utils.js'; const cppfiltpath = 'c++filt'; -class DummyCompiler { - exec(command, args, options) { +class DummyCompiler extends BaseCompiler { + constructor() { + const env = { + ceProps: properties.fakeProps({}), + compilerProps: () => {}, + } as unknown as CompilationEnvironment; + + // using c++ as the compiler needs at least one language + const compiler = makeFakeCompilerInfo({lang: 'c++'}); + + super(compiler, env); + } + override exec(command, args, options) { return exec.execute(command, args, options); } } +class DummyCppDemangler extends CppDemangler { + public override collectLabels = super.collectLabels; +} + +class DummyWin32Demangler extends Win32Demangler { + public override collectLabels = super.collectLabels; +} + const catchCppfiltNonexistence = err => { if (!err.message.startsWith('spawn c++filt')) { throw err; @@ -50,8 +73,7 @@ describe('Basic demangling', function () { asm: [{text: 'Hello, World!'}], }; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); return Promise.all([ demangler.process(result).then(output => { @@ -63,8 +85,7 @@ describe('Basic demangling', function () { it('One label and some asm', function () { const result = {asm: [{text: '_Z6squarei:'}, {text: ' ret'}]}; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); return Promise.all([ demangler @@ -80,8 +101,7 @@ describe('Basic demangling', function () { it('One label and use of a label', function () { const result = {asm: [{text: '_Z6squarei:'}, {text: ' mov eax, $_Z6squarei'}]}; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); return Promise.all([ demangler @@ -109,8 +129,7 @@ describe('Basic demangling', function () { ], }; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); return demangler .process(result) @@ -125,20 +144,20 @@ describe('Basic demangling', function () { it('Should ignore comments (CL)', function () { const result = {asm: [{text: ' call ??3@YAXPEAX_K@Z ; operator delete'}]}; - const demangler = new Win32Demangler(cppfiltpath, new DummyCompiler()); + const demangler = new DummyWin32Demangler(cppfiltpath, new DummyCompiler()); demangler.result = result; demangler.symbolstore = new SymbolStore(); demangler.collectLabels(); const output = demangler.win32RawSymbols; - output.should.deep.equal(['??3@YAXPEAX_K@Z']); + unwrap(output).should.deep.equal(['??3@YAXPEAX_K@Z']); }); it('Should ignore comments (CPP)', function () { const result = {asm: [{text: ' call hello ; operator delete'}]}; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); + demangler.result = result; demangler.symbolstore = new SymbolStore(); demangler.collectLabels(); @@ -150,8 +169,8 @@ describe('Basic demangling', function () { it('Should also support ARM branch instructions', () => { const result = {asm: [{text: ' bl _ZN3FooC1Ev'}]}; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); + demangler.result = result; demangler.symbolstore = new SymbolStore(); demangler.collectLabels(); @@ -163,20 +182,20 @@ describe('Basic demangling', function () { it('Should NOT handle undecorated labels', () => { const result = {asm: [{text: '$LN3@caller2:'}]}; - const demangler = new Win32Demangler(cppfiltpath, new DummyCompiler()); + const demangler = new DummyWin32Demangler(cppfiltpath, new DummyCompiler()); demangler.result = result; demangler.symbolstore = new SymbolStore(); demangler.collectLabels(); const output = demangler.win32RawSymbols; - output.should.deep.equal([]); + output?.should.deep.equal([]); }); it('Should ignore comments after jmps', function () { const result = {asm: [{text: ' jmp _Z1fP6mytype # TAILCALL'}]}; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); + demangler.result = result; demangler.symbolstore = new SymbolStore(); demangler.collectLabels(); @@ -188,8 +207,8 @@ describe('Basic demangling', function () { it('Should still work with normal jmps', function () { const result = {asm: [{text: ' jmp _Z1fP6mytype'}]}; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); + demangler.result = result; demangler.symbolstore = new SymbolStore(); demangler.collectLabels(); @@ -211,8 +230,7 @@ describe('Basic demangling', function () { ], }; - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); return Promise.all([ demangler @@ -244,8 +262,8 @@ async function DoDemangleTest(filename) { const resultIn = await readResultFile(filename); const resultOut = await readResultFile(filename + '.demangle'); - const demangler = new CppDemangler(cppfiltpath, new DummyCompiler()); - demangler.demanglerArguments = ['-n']; + const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']); + return demangler.process(resultIn).should.eventually.deep.equal(resultOut); } @@ -282,7 +300,7 @@ describe('File demangling', () => { }); describe('Demangler prefix tree', () => { - const replacements = new PrefixTree(); + const replacements = new PrefixTree([]); replacements.add('a', 'short_a'); replacements.add('aa', 'long_a'); replacements.add('aa_shouldnotmatch', 'ERROR'); @@ -299,7 +317,7 @@ describe('Demangler prefix tree', () => { replacements.replaceAll('a aa a aa').should.eq('short_a long_a short_a long_a'); }); it('should work with empty replacements', () => { - new PrefixTree().replaceAll('Testing 123').should.eq('Testing 123'); + new PrefixTree([]).replaceAll('Testing 123').should.eq('Testing 123'); }); it('should leave unmatching text alone', () => { replacements @@ -310,9 +328,9 @@ describe('Demangler prefix tree', () => { replacements.replaceAll('Everyone loves an aardvark').should.eq('Everyone loves short_an long_ardvshort_ark'); }); it('should find exact matches', () => { - replacements.findExact('a').should.eq('short_a'); - replacements.findExact('aa').should.eq('long_a'); - replacements.findExact('aa_shouldnotmatch').should.eq('ERROR'); + unwrap(replacements.findExact('a')).should.eq('short_a'); + unwrap(replacements.findExact('aa')).should.eq('long_a'); + unwrap(replacements.findExact('aa_shouldnotmatch')).should.eq('ERROR'); }); it('should find not find mismatches', () => { chai.expect(replacements.findExact('aaa')).to.be.null; diff --git a/test/map-file-tests.js b/test/map-file-tests.ts index 4305ae123..9be73d19a 100644 --- a/test/map-file-tests.js +++ b/test/map-file-tests.ts @@ -22,6 +22,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +import {unwrap} from '../lib/assert.js'; import {MapFileReaderDelphi} from '../lib/mapfiles/map-file-delphi.js'; import {MapFileReaderVS} from '../lib/mapfiles/map-file-vs.js'; @@ -49,26 +50,26 @@ describe('Code Segments', function () { reader.segments.length.should.equal(1); let info = reader.getSegmentInfoByStartingAddress('0001', 0x2838); - info.unitName.should.equal('output.pas'); + expect(unwrap(info).unitName).to.equal('output.pas'); info = reader.getSegmentInfoByStartingAddress(undefined, reader.getSegmentOffset('0001') + 0x2838); - info.unitName.should.equal('output.pas'); + expect(unwrap(info).unitName).to.equal('output.pas'); info = reader.getSegmentInfoByStartingAddress('0001', 0x1234); expect(info, 'Address should not be a Start for any segment').to.be.undefined; info = reader.getSegmentInfoAddressIsIn('0001', 0x2838 + 0x10); - info.unitName.should.equal('output.pas'); + expect(unwrap(info).unitName).to.equal('output.pas'); info = reader.getSegmentInfoAddressIsIn(undefined, reader.getSegmentOffset('0001') + 0x2838 + 0x10); - info.unitName.should.equal('output.pas'); + expect(unwrap(info).unitName).to.equal('output.pas'); info = reader.getSegmentInfoAddressIsIn('0001', reader.getSegmentOffset('0001') + 0x2838 + 0x80 + 1); expect(info, 'Address should not be in any segment').to.be.undefined; info = reader.getSegmentInfoByUnitName('output.pas'); - info.unitName.should.equal('output.pas'); - info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); + expect(unwrap(info).unitName).to.equal('output.pas'); + unwrap(info).addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); }); it('Not include this segment', function () { @@ -89,13 +90,13 @@ describe('Code Segments', function () { reader.segments.length.should.equal(1); let info = reader.getSegmentInfoByStartingAddress('0001', 0x2838); - info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); + unwrap(info).addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); info = reader.getSegmentInfoByStartingAddress(undefined, 0x403838); - info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); + unwrap(info).addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); info = reader.getSegmentInfoAddressIsIn(undefined, reader.getSegmentOffset('0001') + 0x2838 + 0x10); - info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); + unwrap(info).addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838); info = reader.getSegmentInfoAddressIsIn('0001', reader.getSegmentOffset('0001') + 0x2837); expect(info).to.be.undefined; @@ -109,12 +110,12 @@ describe('Code Segments', function () { ); let info = reader.getSegmentInfoByStartingAddress('0002', 0); - info.unitName.should.equal('ConsoleApplication1.obj'); + expect(unwrap(info).unitName).to.equal('ConsoleApplication1.obj'); reader.getSegmentOffset('0002').should.equal(0x411000); info = reader.getSegmentInfoByStartingAddress(undefined, 0x411000); - info.unitName.should.equal('ConsoleApplication1.obj'); + expect(unwrap(info).unitName).to.equal('ConsoleApplication1.obj'); }); }); @@ -125,12 +126,12 @@ describe('Symbol info', function () { reader.namedAddresses.length.should.equal(1); let info = reader.getSymbolAt('0001', 0x2838); - info.should.not.equal(undefined, 'Symbol Square should have been returned 1'); - info.displayName.should.equal('Square'); + expect(info).to.not.equal(undefined, 'Symbol Square should have been returned 1'); + expect(unwrap(info).displayName).to.equal('Square'); info = reader.getSymbolAt(undefined, reader.getSegmentOffset('0001') + 0x2838); - info.should.not.equal(undefined, 'Symbol Square should have been returned 2'); - info.displayName.should.equal('Square'); + expect(info).to.not.equal(undefined, 'Symbol Square should have been returned 2'); + expect(unwrap(info).displayName).to.equal('Square'); }); it('Delphi-Map D2009 symbol test', function () { @@ -139,12 +140,13 @@ describe('Symbol info', function () { reader.namedAddresses.length.should.equal(1); let info = reader.getSymbolAt('0001', 0x2c4c); - info.should.not.equal(undefined, 'Symbol MaxArray should have been returned'); - info.displayName.should.equal('output.MaxArray'); + expect(info).to.not.equal(undefined, 'Symbol MaxArray should have been returned'); + expect(unwrap(info).displayName).to.equal('output.MaxArray'); + //todo should not be undefined info = reader.getSymbolAt(undefined, reader.getSegmentOffset('0001') + 0x2c4c); - info.should.not.equal(undefined, 'Symbol MaxArray should have been returned'); - info.displayName.should.equal('output.MaxArray'); + expect(info).to.not.equal(undefined, 'Symbol MaxArray should have been returned'); + expect(unwrap(info).displayName).to.equal('output.MaxArray'); }); it('VS-Map symbol test', function () { @@ -155,12 +157,12 @@ describe('Symbol info', function () { reader.namedAddresses.length.should.equal(1); let info = reader.getSymbolAt('0002', 0x6b0); - info.should.not.equal(undefined, 'Symbol start_verify_argument should have been returned 1'); - info.displayName.should.equal('??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ'); + expect(info).to.not.equal(undefined, 'Symbol start_verify_argument should have been returned 1'); + expect(unwrap(info).displayName).to.equal('??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ'); info = reader.getSymbolAt(undefined, 0x4116b0); - info.should.not.equal(undefined, 'Symbol start_verify_argument should have been returned 2'); - info.displayName.should.equal('??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ'); + expect(info).to.not.equal(undefined, 'Symbol start_verify_argument should have been returned 2'); + expect(unwrap(info).displayName).to.equal('??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ'); }); it('Delphi-Map Duplication prevention', function () { @@ -184,10 +186,10 @@ describe('Delphi-Map Line number info', function () { reader.tryReadingLineNumbers(' 17 0001:000028A4').should.equal(true); let lineInfo = reader.getLineInfoByAddress('0001', 0x28a4); - lineInfo.lineNumber.should.equal(17); + expect(unwrap(lineInfo).lineNumber).to.equal(17); lineInfo = reader.getLineInfoByAddress(undefined, reader.getSegmentOffset('0001') + 0x28a4); - lineInfo.lineNumber.should.equal(17); + expect(unwrap(lineInfo).lineNumber).to.equal(17); }); it('Multiple lines', function () { @@ -197,16 +199,16 @@ describe('Delphi-Map Line number info', function () { .should.equal(true); let lineInfo = reader.getLineInfoByAddress('0001', 0x2838); - lineInfo.lineNumber.should.equal(12); + expect(unwrap(lineInfo).lineNumber).to.equal(12); lineInfo = reader.getLineInfoByAddress('0001', 0x2858); - lineInfo.lineNumber.should.equal(15); + expect(unwrap(lineInfo).lineNumber).to.equal(15); lineInfo = reader.getLineInfoByAddress('0001', 0x2854); - lineInfo.lineNumber.should.equal(14); + expect(unwrap(lineInfo).lineNumber).to.equal(14); lineInfo = reader.getLineInfoByAddress('0001', 0x283b); - lineInfo.lineNumber.should.equal(13); + expect(unwrap(lineInfo).lineNumber).to.equal(13); }); }); @@ -220,12 +222,12 @@ describe('Delphi-Map load test', function () { reader.namedAddresses.length.should.equal(11); let info = reader.getSegmentInfoByUnitName('output.pas'); - info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2c4c); + unwrap(info).addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2c4c); info = reader.getICodeSegmentInfoByUnitName('output.pas'); - info.segment.should.equal('0002'); - info.addressWithoutOffset.should.equal(0xb0); - info.addressInt.should.equal(0x4040b0); + unwrap(info).segment.should.equal('0002'); + unwrap(info).addressWithoutOffset.should.equal(0xb0); + unwrap(info).addressInt.should.equal(0x4040b0); }); }); @@ -235,7 +237,7 @@ describe('VS-Map load test', function () { reader.run(); reader.segments.length.should.equal(1); - reader.getSegmentInfoByUnitName('ConsoleApplication1.obj').addressInt.should.equal(0x411000); + unwrap(reader.getSegmentInfoByUnitName('ConsoleApplication1.obj')).addressInt.should.equal(0x411000); reader.getSegmentOffset('0001').should.equal(0x401000, 'offset 1'); reader.getSegmentOffset('0002').should.equal(0x411000, 'offset 2'); diff --git a/test/options-handler.js b/test/options-handler.ts index e77a50639..96e21dfa0 100644 --- a/test/options-handler.js +++ b/test/options-handler.ts @@ -26,11 +26,16 @@ import {fileURLToPath} from 'url'; import _ from 'underscore'; +import {AppDefaultArguments} from '../app.js'; import {BaseCompiler} from '../lib/base-compiler.js'; -import {ClientOptionsHandler} from '../lib/options-handler.js'; +import {CompilationEnvironment} from '../lib/compilation-env.js'; +import {ClientOptionsHandler, ClientOptionsType} from '../lib/options-handler.js'; import * as properties from '../lib/properties.js'; +import {BaseTool} from '../lib/tooling/base-tool.js'; +import {CompilerInfo} from '../types/compiler.interfaces.js'; +import {LanguageKey} from '../types/languages.interfaces.js'; -import {should} from './utils.js'; +import {makeFakeCompilerInfo, should} from './utils.js'; const languages = { fake: { @@ -122,35 +127,57 @@ const moreLibProps = { 'libs.autolib.versions.autodetect.staticliblink': 'hello', }; -const makeFakeCompilerInfo = (id, lang, group, semver, isSemver) => { - return { +const fakeCompilerInfo = (id: string, lang: string, group: string, semver: string, isSemver: boolean) => { + return makeFakeCompilerInfo({ id: id, exe: '/dev/null', name: id, - lang: lang, + lang: lang as LanguageKey, group: group, isSemVer: isSemver, semver: semver, libsArr: [], - }; + }); }; +class TestBaseCompiler extends BaseCompiler { + public override supportedLibraries = super.supportedLibraries; +} + describe('Options handler', () => { - let fakeOptionProps; - let compilerProps; - let optionsHandler; - let fakeMoreCompilerProps; - let moreCompilerProps; - let moreOptionsHandler; + let fakeOptionProps: ReturnType<typeof properties.fakeProps>; + let compilerProps: properties.CompilerProps; + let optionsHandler: ClientOptionsHandler; + + let fakeMoreCompilerProps: ReturnType<typeof properties.fakeProps>; + let moreCompilerProps: properties.CompilerProps; + let moreOptionsHandler: ClientOptionsHandler; + + let env: CompilationEnvironment; + + function createClientOptions(libs: ReturnType<ClientOptionsHandler['parseLibraries']>) { + return { + libs: { + 'c++': libs.fake, + }, + } as unknown as ClientOptionsType; + } before(() => { fakeOptionProps = properties.fakeProps(optionsProps); compilerProps = new properties.CompilerProps(languages, fakeOptionProps); - optionsHandler = new ClientOptionsHandler([], compilerProps, {env: ['dev']}); + optionsHandler = new ClientOptionsHandler([], compilerProps, {env: ['dev']} as unknown as AppDefaultArguments); fakeMoreCompilerProps = properties.fakeProps(moreLibProps); moreCompilerProps = new properties.CompilerProps(languages, fakeMoreCompilerProps); - moreOptionsHandler = new ClientOptionsHandler([], moreCompilerProps, {env: ['dev']}); + moreOptionsHandler = new ClientOptionsHandler([], moreCompilerProps, { + env: ['dev'], + } as unknown as AppDefaultArguments); + + env = { + ceProps: properties.fakeProps({}), + compilerProps: () => {}, + } as unknown as CompilationEnvironment; }); it('should always return an array of paths', () => { @@ -270,32 +297,32 @@ describe('Options handler', () => { }); it('should order compilers as expected', () => { const compilers = [ - makeFakeCompilerInfo('a1', languages.fake.id, 'a', '0.0.1', true), - makeFakeCompilerInfo('a2', languages.fake.id, 'a', '0.2.0', true), - makeFakeCompilerInfo('a3', languages.fake.id, 'a', '0.2.1', true), + fakeCompilerInfo('a1', languages.fake.id, 'a', '0.0.1', true), + fakeCompilerInfo('a2', languages.fake.id, 'a', '0.2.0', true), + fakeCompilerInfo('a3', languages.fake.id, 'a', '0.2.1', true), - makeFakeCompilerInfo('b1', languages.fake.id, 'b', 'trunk', true), - makeFakeCompilerInfo('b2', languages.fake.id, 'b', '1.0.0', true), - makeFakeCompilerInfo('b3', languages.fake.id, 'b', '0.5.0', true), + fakeCompilerInfo('b1', languages.fake.id, 'b', 'trunk', true), + fakeCompilerInfo('b2', languages.fake.id, 'b', '1.0.0', true), + fakeCompilerInfo('b3', languages.fake.id, 'b', '0.5.0', true), - makeFakeCompilerInfo('c1', languages.fake.id, 'c', '3.0.0', true), - makeFakeCompilerInfo('c2', languages.fake.id, 'c', '3.0.0', true), - makeFakeCompilerInfo('c3', languages.fake.id, 'c', '3.0.0', true), + fakeCompilerInfo('c1', languages.fake.id, 'c', '3.0.0', true), + fakeCompilerInfo('c2', languages.fake.id, 'c', '3.0.0', true), + fakeCompilerInfo('c3', languages.fake.id, 'c', '3.0.0', true), - makeFakeCompilerInfo('d1', languages.fake.id, 'd', 1, true), - makeFakeCompilerInfo('d2', languages.fake.id, 'd', '2.0.0', true), - makeFakeCompilerInfo('d3', languages.fake.id, 'd', '0.0.5', true), + fakeCompilerInfo('d1', languages.fake.id, 'd', '1', true), + fakeCompilerInfo('d2', languages.fake.id, 'd', '2.0.0', true), + fakeCompilerInfo('d3', languages.fake.id, 'd', '0.0.5', true), - makeFakeCompilerInfo('e1', languages.fake.id, 'e', '0..0', false), - makeFakeCompilerInfo('e2', languages.fake.id, 'e', undefined, false), + fakeCompilerInfo('e1', languages.fake.id, 'e', '0..0', false), + fakeCompilerInfo('e2', languages.fake.id, 'e', '', false), - makeFakeCompilerInfo('f1', languages.fake.id, 'f', '5', true), - makeFakeCompilerInfo('f2', languages.fake.id, 'f', '5.1', true), - makeFakeCompilerInfo('f3', languages.fake.id, 'f', '5.2', true), + fakeCompilerInfo('f1', languages.fake.id, 'f', '5', true), + fakeCompilerInfo('f2', languages.fake.id, 'f', '5.1', true), + fakeCompilerInfo('f3', languages.fake.id, 'f', '5.2', true), - makeFakeCompilerInfo('g1', languages.fake.id, 'g', '5 a', true), - makeFakeCompilerInfo('g2', languages.fake.id, 'g', '5.1 b d', true), - makeFakeCompilerInfo('g3', languages.fake.id, 'g', '5.2 ce fg', true), + fakeCompilerInfo('g1', languages.fake.id, 'g', '5 a', true), + fakeCompilerInfo('g2', languages.fake.id, 'g', '5.1 b d', true), + fakeCompilerInfo('g3', languages.fake.id, 'g', '5.2 ce fg', true), ]; const expectedOrder = { a: { @@ -337,26 +364,20 @@ describe('Options handler', () => { _.each(optionsHandler.get().compilers, compiler => { should.equal( compiler['$order'], - expectedOrder[compiler.group][compiler.id], - `group: ${compiler.group} id: ${compiler.id}`, + expectedOrder[(compiler as CompilerInfo).group][(compiler as CompilerInfo).id], + `group: ${(compiler as CompilerInfo).group} id: ${(compiler as CompilerInfo).id}`, ); }); optionsHandler.setCompilers([]); }); it('should get static libraries', () => { const libs = optionsHandler.parseLibraries({fake: optionsProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); + + const clientOptions = createClientOptions(libs); const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + compiler.initialiseLibraries(clientOptions); const staticlinks = compiler.getStaticLibraryLinks([{id: 'fs', version: 'std'}]); staticlinks.should.deep.equal(['-lc++fs', '-lrt', '-lpthread']); @@ -366,18 +387,12 @@ describe('Options handler', () => { }); it('should sort static libraries', () => { const libs = optionsHandler.parseLibraries({fake: optionsProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); + + const clientOptions = createClientOptions(libs); const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + compiler.initialiseLibraries(clientOptions); let staticlinks = compiler.getSortedStaticLibraries([{id: 'someotherlib', version: 'trunk'}]); staticlinks.should.deep.equal(['someotherlib', 'c++fs']); @@ -390,36 +405,24 @@ describe('Options handler', () => { }); it('library sort special case 1', () => { const libs = moreOptionsHandler.parseLibraries({fake: moreLibProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + + const clientOptions = createClientOptions(libs); + compiler.initialiseLibraries(clientOptions); const staticlinks = compiler.getSortedStaticLibraries([{id: 'fs', version: 'std'}]); staticlinks.should.deep.equal(['fsextra', 'c++fs', 'rt', 'pthread']); }); it('library sort special case 2', () => { const libs = moreOptionsHandler.parseLibraries({fake: moreLibProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + + const clientOptions = createClientOptions(libs); + compiler.initialiseLibraries(clientOptions); const staticlinks = compiler.getSortedStaticLibraries([ {id: 'yalib', version: 'trunk'}, @@ -430,17 +433,12 @@ describe('Options handler', () => { }); it('library sort special case 3', () => { const libs = moreOptionsHandler.parseLibraries({fake: moreLibProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); + const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + + const clientOptions = createClientOptions(libs); + compiler.initialiseLibraries(clientOptions); const staticlinks = compiler.getSortedStaticLibraries([ {id: 'fourthlib', version: 'trunk'}, @@ -451,38 +449,26 @@ describe('Options handler', () => { }); it('filtered library list', () => { const libs = moreOptionsHandler.parseLibraries({fake: moreLibProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); compilerInfo.libsArr = ['fs.std', 'someotherlib']; - const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + const compiler = new TestBaseCompiler(compilerInfo, env); + + const clientOptions = createClientOptions(libs); + compiler.initialiseLibraries(clientOptions); const libNames = _.keys(compiler.supportedLibraries); libNames.should.deep.equal(['fs', 'someotherlib']); }); it('can detect libraries from options', () => { const libs = moreOptionsHandler.parseLibraries({fake: moreLibProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); - const env = { - ceProps: properties.fakeProps({}), - compilerProps: () => {}, - }; + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + + const clientOptions = createClientOptions(libs); + compiler.initialiseLibraries(clientOptions); const obj = { libraries: [{id: 'ctre', version: 'trunk'}], @@ -498,27 +484,33 @@ describe('Options handler', () => { }); it("server-side library alias support (just in case client doesn't support it)", () => { const libs = moreOptionsHandler.parseLibraries({fake: moreLibProps.libs}); - const compilerInfo = makeFakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); + const compilerInfo = fakeCompilerInfo('g82', 'c++', 'cpp', '8.2', true); const env = { ceProps: properties.fakeProps({}), compilerProps: () => {}, - }; + } as unknown as CompilationEnvironment; const compiler = new BaseCompiler(compilerInfo, env); - compiler.initialiseLibraries({ - libs: { - 'c++': libs.fake, - }, - }); + + const clientOptions = createClientOptions(libs); + compiler.initialiseLibraries(clientOptions); const staticlinks = compiler.getSortedStaticLibraries([{id: 'someotherlib', version: 'master'}]); staticlinks.should.deep.equal(['someotherlib', 'c++fs']); }); it('should be able to parse basic tools', () => { - const tools = optionsHandler.parseTools({fake: optionsProps.tools}); + class TestBaseTool extends BaseTool { + public override env = super.env; + } + const tools = optionsHandler.parseTools({fake: optionsProps.tools}) as unknown as Record< + string, + Record<string, Partial<TestBaseTool>> + >; + _.each(tools.fake, tool => { delete tool.env; }); + tools.should.deep.equal({ fake: { faketool: { diff --git a/test/packager-tests.js b/test/packager-tests.ts index 8544492b6..73fee2fe9 100644 --- a/test/packager-tests.js +++ b/test/packager-tests.ts @@ -28,7 +28,7 @@ import {Packager} from '../lib/packager.js'; import {fs, path} from './utils.js'; -function newTempDir() { +function newTempDir(): Promise<string> { return new Promise((resolve, reject) => { temp.mkdir({prefix: 'compiler-explorer-compiler', dir: process.env.tmpDir}, (err, dirPath) => { if (err) reject(`Unable to open temp file: ${err}`); |