378 строки
20 KiB
TypeScript
378 строки
20 KiB
TypeScript
/* eslint-disable no-unused-expressions */
|
|
import { parseCompileFlags, getIntelliSenseMode, CppConfigurationProvider } from '@cmt/cpptools';
|
|
import { expect, getTestResourceFilePath } from '@test/util';
|
|
import { CMakeCache } from '@cmt/cache';
|
|
import * as path from 'path';
|
|
import * as codeModel from '@cmt/drivers/codeModel';
|
|
import * as vscode from 'vscode';
|
|
import { Version } from 'vscode-cpptools';
|
|
import * as util from '@cmt/util';
|
|
|
|
const here = __dirname;
|
|
|
|
suite('CppTools tests', () => {
|
|
test('Parse some compiler flags', () => {
|
|
// Parse definition
|
|
const cpptoolsVersion3 = Version.v3;
|
|
const cpptoolsVersion4 = Version.v4;
|
|
const cpptoolsVersion5 = Version.v5;
|
|
const cpptoolsVersion6 = Version.v6;
|
|
|
|
// Verify CppTools API version 6
|
|
let info = parseCompileFlags(cpptoolsVersion6, ['-std=c++23']);
|
|
expect(info.standard).to.eql(undefined);
|
|
info = parseCompileFlags(cpptoolsVersion6, ['-std=c++2b']);
|
|
expect(info.standard).to.eql(undefined);
|
|
info = parseCompileFlags(cpptoolsVersion6, ['-std=gnu++23']);
|
|
expect(info.standard).to.eql(undefined);
|
|
|
|
// Verify CppTools API version 5
|
|
info = parseCompileFlags(cpptoolsVersion5, ['-target', 'arm-arm-none-eabi']);
|
|
expect(info.targetArch).to.eql(undefined);
|
|
info = parseCompileFlags(cpptoolsVersion5, ['-std=c++23']);
|
|
expect(info.standard).to.eql('c++20');
|
|
info = parseCompileFlags(cpptoolsVersion5, ['-std=gnu++14']);
|
|
expect(info.standard).to.eql('gnu++14');
|
|
info = parseCompileFlags(cpptoolsVersion5, []);
|
|
expect(info.standard).to.eql(undefined);
|
|
|
|
// Verify CppTools API version 4
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-DFOO=BAR']);
|
|
expect(info.extraDefinitions).to.eql(['FOO=BAR']);
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-D', 'FOO=BAR']);
|
|
expect(info.extraDefinitions).to.eql(['FOO=BAR']);
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-DFOO=BAR', '/D', 'BAZ=QUX']);
|
|
expect(info.extraDefinitions).to.eql(['FOO=BAR', 'BAZ=QUX']);
|
|
expect(info.standard).to.eql('c++17');
|
|
info = parseCompileFlags(cpptoolsVersion4, [], 'C');
|
|
expect(info.standard).to.eql('c11');
|
|
info = parseCompileFlags(cpptoolsVersion4, [], 'CXX');
|
|
expect(info.standard).to.eql('c++17');
|
|
info = parseCompileFlags(cpptoolsVersion4, [], 'CUDA');
|
|
expect(info.standard).to.eql('c++17');
|
|
// Parse language standard
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-std=c++03']);
|
|
expect(info.standard).to.eql('c++03');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-std=gnu++14']);
|
|
expect(info.standard).to.eql('gnu++14');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-std=c17']);
|
|
expect(info.standard).to.eql('c17');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-std=c++123']);
|
|
expect(info.standard).to.eql('c++17');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-std=c123'], 'C');
|
|
expect(info.standard).to.eql('c11');
|
|
// Parse target architecture
|
|
info = parseCompileFlags(cpptoolsVersion4, ['--target=aarch64-arm-none-eabi']);
|
|
expect(info.targetArch).to.eql('arm64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-target', 'arm64-arm-none-eabi']);
|
|
expect(info.targetArch).to.eql('arm64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-target', 'arm-arm-none-eabi']);
|
|
expect(info.targetArch).to.eql('arm');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-arch=x86_64']);
|
|
expect(info.targetArch).to.eql('x64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-arch', 'aarch64']);
|
|
expect(info.targetArch).to.eql('arm64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-arch', 'arm64']);
|
|
expect(info.targetArch).to.eql('arm64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-arch', 'arm']);
|
|
expect(info.targetArch).to.eql('arm');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-arch', 'i686']);
|
|
expect(info.targetArch).to.eql('x86');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['/arch:x86_64']);
|
|
expect(info.targetArch).to.eql('x64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-march=amd64']);
|
|
expect(info.targetArch).to.eql('x64');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-m32']);
|
|
expect(info.targetArch).to.eql('x86');
|
|
info = parseCompileFlags(cpptoolsVersion4, ['-m00']);
|
|
expect(info.targetArch).to.eql(undefined);
|
|
|
|
// Verify CppTools API version 3
|
|
info = parseCompileFlags(cpptoolsVersion3, ['-std=c++03']);
|
|
expect(info.standard).to.eql('c++03');
|
|
info = parseCompileFlags(cpptoolsVersion3, ['-std=gnu++14']);
|
|
expect(info.standard).to.eql('c++14');
|
|
info = parseCompileFlags(cpptoolsVersion3, ['-std=c17']);
|
|
expect(info.standard).to.eql('c11');
|
|
});
|
|
|
|
test('Get IntelliSenseMode', () => {
|
|
const cpptoolsVersion3 = Version.v3;
|
|
const cpptoolsVersion4 = Version.v4;
|
|
const cpptoolsVersion5 = Version.v5;
|
|
|
|
// Verify CppToolsAPI version 5
|
|
let mode = getIntelliSenseMode(cpptoolsVersion5, 'cl.exe', undefined);
|
|
expect(mode).to.eql(undefined);
|
|
mode = getIntelliSenseMode(cpptoolsVersion5, 'clang', undefined);
|
|
expect(mode).to.eql(undefined);
|
|
mode = getIntelliSenseMode(cpptoolsVersion5, 'clang', 'arm64');
|
|
expect(mode).to.eql('clang-arm64');
|
|
|
|
// Verify CppTools API version 4
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'armclang', 'arm');
|
|
expect(mode).to.eql('clang-arm');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'armclang', 'arm64');
|
|
expect(mode).to.eql('clang-arm64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'armclang', undefined);
|
|
expect(mode).to.eql('clang-arm');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'clang', 'x64');
|
|
expect(mode).to.eql('clang-x64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'clang', 'arm64');
|
|
expect(mode).to.eql('clang-arm64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'clang', 'arm');
|
|
expect(mode).to.eql('clang-arm');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'gcc', undefined);
|
|
expect(mode).to.eql('gcc-x64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'gcc', 'arm64');
|
|
expect(mode).to.eql('gcc-arm64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'gcc', 'arm');
|
|
expect(mode).to.eql('gcc-arm');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'g++', 'x86');
|
|
expect(mode).to.eql('gcc-x86');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'arm-none-eabi-g++', undefined);
|
|
expect(mode).to.eql('gcc-arm');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'aarch64-linux-gnu-gcc', undefined);
|
|
expect(mode).to.eql('gcc-arm64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'bin//Hostx64//x64//cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-x64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'bin//Hostx64//x86//cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-x86');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'bin//Hostx64//ARM//cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-arm');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'bin//Hostx64//ARM64//cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-arm64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion4, 'cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-x64');
|
|
|
|
// Verify CppTools API version 3
|
|
mode = getIntelliSenseMode(cpptoolsVersion3, 'bin//Hostx64//arm//cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-x86');
|
|
mode = getIntelliSenseMode(cpptoolsVersion3, 'bin//Hostx64//arm64//cl.exe', undefined);
|
|
expect(mode).to.eql('msvc-x64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion3, 'arm-none-eabi-g++', undefined);
|
|
expect(mode).to.eql('gcc-x86');
|
|
mode = getIntelliSenseMode(cpptoolsVersion3, 'aarch64-linux-gnu-gcc', undefined);
|
|
expect(mode).to.eql('gcc-x64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion3, 'clang', 'arm64');
|
|
expect(mode).to.eql('clang-x64');
|
|
mode = getIntelliSenseMode(cpptoolsVersion3, 'clang', 'arm');
|
|
expect(mode).to.eql('clang-x86');
|
|
});
|
|
|
|
// Validate codeModel using cppTools API V5
|
|
test('Validate code model V5', async () => {
|
|
const provider = new CppConfigurationProvider();
|
|
provider.cpptoolsVersion = Version.v5;
|
|
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache.txt'));
|
|
const sourceFile1 = path.join(here, 'main.cpp');
|
|
const uri1 = vscode.Uri.file(sourceFile1);
|
|
const codeModel1: codeModel.CodeModelContent = {
|
|
configurations: [{
|
|
name: "Release",
|
|
projects: [{
|
|
name: 'cpptools-test-1',
|
|
sourceDirectory: here,
|
|
targets: [
|
|
{
|
|
name: 'target1',
|
|
type: 'EXECUTABLE',
|
|
fileGroups: [{
|
|
sources: [sourceFile1],
|
|
isGenerated: false,
|
|
compileCommandFragments: ['-DFLAG1'],
|
|
language: 'CXX'
|
|
}]
|
|
},
|
|
{
|
|
name: 'target2',
|
|
type: 'EXECUTABLE',
|
|
fileGroups: [{
|
|
sources: [sourceFile1],
|
|
isGenerated: false,
|
|
compileCommandFragments: ['-DFLAG2'],
|
|
language: 'CXX'
|
|
}]
|
|
}
|
|
]
|
|
}]
|
|
}],
|
|
toolchains: new Map<string, codeModel.CodeModelToolchain>()
|
|
};
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel1, activeTarget: 'target1', activeBuildTypeVariant: 'Release', folder: here });
|
|
|
|
// Update configuration with a 2nd workspace folder.
|
|
const smokeFolder = path.join(here, '../smoke');
|
|
const sourceFile3 = path.join(smokeFolder, 'main.cpp');
|
|
const uri3 = vscode.Uri.file(sourceFile3);
|
|
const codeModel3: codeModel.CodeModelContent = {
|
|
configurations: [{
|
|
name: 'Release',
|
|
projects: [{
|
|
name: 'cpptools-test-3',
|
|
sourceDirectory: smokeFolder,
|
|
targets: [
|
|
{
|
|
name: 'target3',
|
|
type: 'EXECUTABLE',
|
|
fileGroups: [{
|
|
sources: [sourceFile3],
|
|
isGenerated: false,
|
|
compileCommandFragments: ['-DFLAG3'],
|
|
language: 'CXX'
|
|
}]
|
|
}]
|
|
}]
|
|
}],
|
|
toolchains: new Map<string, codeModel.CodeModelToolchain>([['CXX', { path: 'path_from_toolchain_object' }]])
|
|
};
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel3, activeTarget: 'target3', activeBuildTypeVariant: 'Release', folder: smokeFolder });
|
|
let configurations = await provider.provideConfigurations([vscode.Uri.file(sourceFile3)]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.compilerPath).to.eq('path_from_toolchain_object');
|
|
|
|
configurations = await provider.provideConfigurations([uri1]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.defines).to.contain('FLAG1');
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel1, activeTarget: 'target2', activeBuildTypeVariant: 'Release', folder: here });
|
|
configurations = await provider.provideConfigurations([uri1]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.defines).to.contain('FLAG2');
|
|
expect(configurations[0].configuration.compilerPath).to.eq('clang++');
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel1, activeTarget: 'all', activeBuildTypeVariant: 'Release', folder: here });
|
|
configurations = await provider.provideConfigurations([uri1]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.defines.some(def => def === 'FLAG1' || def === 'FLAG2')).to.be.true;
|
|
expect(configurations[0].configuration.defines).to.not.have.all.members(['FLAG1', 'FLAG2']);
|
|
|
|
// Verify the per-folder browsePath.
|
|
const canProvideBrowseConfigPerFolder: boolean = await provider.canProvideBrowseConfigurationsPerFolder();
|
|
expect(canProvideBrowseConfigPerFolder).to.eq(true);
|
|
const browseConfig = await provider.provideFolderBrowseConfiguration(vscode.Uri.file(here));
|
|
expect(browseConfig.browsePath.length).to.eq(1);
|
|
expect(browseConfig.browsePath[0]).to.eq(util.platformNormalizePath(here));
|
|
|
|
// Verify the browsePath with a different folder.
|
|
const configurations2 = await provider.provideConfigurations([uri3]);
|
|
expect(configurations2.length).to.eq(1);
|
|
expect(configurations2[0].configuration.defines).to.contain('FLAG3');
|
|
const browseConfig2 = await provider.provideFolderBrowseConfiguration(vscode.Uri.file(smokeFolder));
|
|
expect(browseConfig2.browsePath.length).to.eq(1);
|
|
expect(browseConfig2.browsePath[0]).to.eq(util.platformNormalizePath(smokeFolder));
|
|
});
|
|
|
|
// Validate codeModel using cppTools API V6
|
|
test('Validate code model latest', async () => {
|
|
const provider = new CppConfigurationProvider();
|
|
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache.txt'));
|
|
const sourceFile1 = path.join(here, 'main.cpp');
|
|
const uri1 = vscode.Uri.file(sourceFile1);
|
|
const codeModel1: codeModel.CodeModelContent = {
|
|
configurations: [{
|
|
name: "Release",
|
|
projects: [{
|
|
name: 'cpptools-test',
|
|
sourceDirectory: here,
|
|
targets: [
|
|
{
|
|
name: 'target1',
|
|
type: 'EXECUTABLE',
|
|
fileGroups: [{
|
|
sources: [sourceFile1],
|
|
isGenerated: false,
|
|
defines: ['DEFINE1'],
|
|
compileCommandFragments: ['-DFRAGMENT1'],
|
|
language: 'CXX'
|
|
}]
|
|
},
|
|
{
|
|
name: 'target2',
|
|
type: 'EXECUTABLE',
|
|
fileGroups: [{
|
|
sources: [sourceFile1],
|
|
isGenerated: false,
|
|
defines: ['DEFINE2'],
|
|
compileCommandFragments: ['-DFRAGMENT2'],
|
|
language: 'CXX'
|
|
}]
|
|
}
|
|
]
|
|
}]
|
|
}],
|
|
toolchains: new Map<string, codeModel.CodeModelToolchain>()
|
|
};
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel1, activeTarget: 'target1', activeBuildTypeVariant: 'Release', folder: here });
|
|
|
|
// Update configuration with a 2nd workspace folder.
|
|
const smokeFolder = path.join(here, '../smoke');
|
|
const sourceFile3 = path.join(smokeFolder, 'main.cpp');
|
|
const uri3 = vscode.Uri.file(sourceFile3);
|
|
const codeModel3: codeModel.CodeModelContent = {
|
|
configurations: [{
|
|
name: 'Release',
|
|
projects: [{
|
|
name: 'cpptools-test2',
|
|
sourceDirectory: smokeFolder,
|
|
targets: [
|
|
{
|
|
name: 'target3',
|
|
type: 'EXECUTABLE',
|
|
fileGroups: [{
|
|
sources: [sourceFile3],
|
|
isGenerated: false,
|
|
compileCommandFragments: ['-DFRAGMENT3'],
|
|
language: 'CXX'
|
|
}]
|
|
}]
|
|
}]
|
|
}],
|
|
toolchains: new Map<string, codeModel.CodeModelToolchain>([['CXX', { path: 'path_from_toolchain_object' }]])
|
|
};
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel3, activeTarget: 'target3', activeBuildTypeVariant: 'Release', folder: smokeFolder });
|
|
let configurations = await provider.provideConfigurations([vscode.Uri.file(sourceFile3)]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.compilerPath).to.eq('path_from_toolchain_object');
|
|
|
|
configurations = await provider.provideConfigurations([uri1]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.defines).to.contain('DEFINE1');
|
|
expect(configurations[0].configuration.compilerFragments).to.contain('-DFRAGMENT1');
|
|
expect(configurations[0].configuration.compilerArgs).to.be.empty;
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel1, activeTarget: 'target2', activeBuildTypeVariant: 'Release', folder: here });
|
|
configurations = await provider.provideConfigurations([uri1]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.defines).to.contain('DEFINE2');
|
|
expect(configurations[0].configuration.compilerFragments).to.contain('-DFRAGMENT2');
|
|
expect(configurations[0].configuration.compilerPath).to.eq('clang++');
|
|
|
|
provider.updateConfigurationData({ cache, codeModelContent: codeModel1, activeTarget: 'all', activeBuildTypeVariant: 'Release', folder: here });
|
|
configurations = await provider.provideConfigurations([uri1]);
|
|
expect(configurations.length).to.eq(1);
|
|
expect(configurations[0].configuration.defines.some(def => def === 'DEFINE1' || def === 'DEFINE2')).to.be.true;
|
|
expect(configurations[0].configuration.defines).to.not.have.all.members(['DEFINE1', 'DEFINE2']);
|
|
|
|
// Verify the per-folder browsePath.
|
|
const canProvideBrowseConfigPerFolder: boolean = await provider.canProvideBrowseConfigurationsPerFolder();
|
|
expect(canProvideBrowseConfigPerFolder).to.eq(true);
|
|
const browseConfig = await provider.provideFolderBrowseConfiguration(vscode.Uri.file(here));
|
|
expect(browseConfig.browsePath.length).to.eq(1);
|
|
expect(browseConfig.browsePath[0]).to.eq(util.platformNormalizePath(here));
|
|
|
|
// Verify the browsePath with a different folder.
|
|
const configurations2 = await provider.provideConfigurations([uri3]);
|
|
expect(configurations2.length).to.eq(1);
|
|
expect(configurations2[0].configuration.defines).to.be.empty;
|
|
expect(configurations2[0].configuration.compilerFragments).to.contain('-DFRAGMENT3');
|
|
const browseConfig2 = await provider.provideFolderBrowseConfiguration(vscode.Uri.file(smokeFolder));
|
|
expect(browseConfig2.browsePath.length).to.eq(1);
|
|
expect(browseConfig2.browsePath[0]).to.eq(util.platformNormalizePath(smokeFolder));
|
|
});
|
|
});
|