Path: blob/main/src/vs/workbench/services/configuration/test/browser/configurationEditing.test.ts
4780 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as sinon from 'sinon';6import assert from 'assert';7import * as json from '../../../../../base/common/json.js';8import { Event } from '../../../../../base/common/event.js';9import { Registry } from '../../../../../platform/registry/common/platform.js';10import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';11import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js';12import { TestEnvironmentService, TestTextFileService, workbenchInstantiationService } from '../../../../test/browser/workbenchTestServices.js';13import * as uuid from '../../../../../base/common/uuid.js';14import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from '../../../../../platform/configuration/common/configurationRegistry.js';15import { WorkspaceService } from '../../browser/configurationService.js';16import { ConfigurationEditing, ConfigurationEditingErrorCode, EditableConfigurationTarget } from '../../common/configurationEditing.js';17import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH, USER_STANDALONE_CONFIGURATIONS, IConfigurationCache } from '../../common/configuration.js';18import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';19import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';20import { ITextFileService } from '../../../textfile/common/textfiles.js';21import { ITextModelService } from '../../../../../editor/common/services/resolverService.js';22import { TextModelResolverService } from '../../../textmodelResolver/common/textModelResolverService.js';23import { INotificationService } from '../../../../../platform/notification/common/notification.js';24import { ICommandService } from '../../../../../platform/commands/common/commands.js';25import { CommandService } from '../../../commands/common/commandService.js';26import { URI } from '../../../../../base/common/uri.js';27import { IRemoteAgentService } from '../../../remote/common/remoteAgentService.js';28import { FileService } from '../../../../../platform/files/common/fileService.js';29import { NullLogService } from '../../../../../platform/log/common/log.js';30import { Schemas } from '../../../../../base/common/network.js';31import { IFileService } from '../../../../../platform/files/common/files.js';32import { KeybindingsEditingService, IKeybindingEditingService } from '../../../keybinding/common/keybindingEditing.js';33import { FileUserDataProvider } from '../../../../../platform/userData/common/fileUserDataProvider.js';34import { UriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentityService.js';35import { toDisposable } from '../../../../../base/common/lifecycle.js';36import { InMemoryFileSystemProvider } from '../../../../../platform/files/common/inMemoryFilesystemProvider.js';37import { joinPath } from '../../../../../base/common/resources.js';38import { VSBuffer } from '../../../../../base/common/buffer.js';39import { RemoteAgentService } from '../../../remote/browser/remoteAgentService.js';40import { getSingleFolderWorkspaceIdentifier } from '../../../workspaces/browser/workspaces.js';41import { IUserDataProfilesService, UserDataProfilesService } from '../../../../../platform/userDataProfile/common/userDataProfile.js';42import { hash } from '../../../../../base/common/hash.js';43import { FilePolicyService } from '../../../../../platform/policy/common/filePolicyService.js';44import { runWithFakedTimers } from '../../../../../base/test/common/timeTravelScheduler.js';45import { UserDataProfileService } from '../../../userDataProfile/common/userDataProfileService.js';46import { IUserDataProfileService } from '../../../userDataProfile/common/userDataProfile.js';47import { IBrowserWorkbenchEnvironmentService } from '../../../environment/browser/environmentService.js';48import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';49import { PolicyCategory } from '../../../../../base/common/policy.js';5051const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });5253class ConfigurationCache implements IConfigurationCache {54needsCaching(resource: URI): boolean { return false; }55async read(): Promise<string> { return ''; }56async write(): Promise<void> { }57async remove(): Promise<void> { }58}5960suite('ConfigurationEditing', () => {6162let instantiationService: TestInstantiationService;63let userDataProfileService: IUserDataProfileService;64let environmentService: IBrowserWorkbenchEnvironmentService;65let fileService: IFileService;66let workspaceService: WorkspaceService;67let testObject: ConfigurationEditing;6869suiteSetup(() => {70const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);71configurationRegistry.registerConfiguration({72'id': '_test',73'type': 'object',74'properties': {75'configurationEditing.service.testSetting': {76'type': 'string',77'default': 'isSet'78},79'configurationEditing.service.testSettingTwo': {80'type': 'string',81'default': 'isSet'82},83'configurationEditing.service.testSettingThree': {84'type': 'string',85'default': 'isSet'86},87'configurationEditing.service.policySetting': {88'type': 'string',89'default': 'isSet',90policy: {91name: 'configurationEditing.service.policySetting',92category: PolicyCategory.Extensions,93minimumVersion: '1.0.0',94localization: { description: { key: '', value: '' } }95}96}97}98});99});100101const disposables = ensureNoDisposablesAreLeakedInTestSuite();102103setup(async () => {104disposables.add(toDisposable(() => sinon.restore()));105const logService = new NullLogService();106fileService = disposables.add(new FileService(logService));107const fileSystemProvider = disposables.add(new InMemoryFileSystemProvider());108disposables.add(fileService.registerProvider(ROOT.scheme, fileSystemProvider));109110const workspaceFolder = joinPath(ROOT, uuid.generateUuid());111await fileService.createFolder(workspaceFolder);112113instantiationService = workbenchInstantiationService(undefined, disposables);114environmentService = TestEnvironmentService;115environmentService.policyFile = joinPath(workspaceFolder, 'policies.json');116instantiationService.stub(IEnvironmentService, environmentService);117const uriIdentityService = disposables.add(new UriIdentityService(fileService));118const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, disposables.add(new UserDataProfilesService(environmentService, fileService, uriIdentityService, logService)));119userDataProfileService = disposables.add(new UserDataProfileService(userDataProfilesService.defaultProfile));120const remoteAgentService = disposables.add(instantiationService.createInstance(RemoteAgentService));121disposables.add(fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, userDataProfilesService, uriIdentityService, logService))));122instantiationService.stub(IFileService, fileService);123instantiationService.stub(IRemoteAgentService, remoteAgentService);124workspaceService = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, uriIdentityService, new NullLogService(), disposables.add(new FilePolicyService(environmentService.policyFile, fileService, logService))));125await workspaceService.initialize({126id: hash(workspaceFolder.toString()).toString(16),127uri: workspaceFolder128});129instantiationService.stub(IWorkspaceContextService, workspaceService);130131await workspaceService.initialize(getSingleFolderWorkspaceIdentifier(workspaceFolder));132instantiationService.stub(IConfigurationService, workspaceService);133instantiationService.stub(IKeybindingEditingService, disposables.add(instantiationService.createInstance(KeybindingsEditingService)));134instantiationService.stub(ITextFileService, disposables.add(instantiationService.createInstance(TestTextFileService)));135instantiationService.stub(ITextModelService, <ITextModelService>disposables.add(instantiationService.createInstance(TextModelResolverService)));136instantiationService.stub(ICommandService, CommandService);137testObject = instantiationService.createInstance(ConfigurationEditing, null);138});139140test('errors cases - invalid key', async () => {141try {142await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'unknown.key', value: 'value' }, { donotNotifyError: true });143} catch (error) {144assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY);145return;146}147assert.fail('Should fail with ERROR_UNKNOWN_KEY');148});149150test('errors cases - no workspace', async () => {151await workspaceService.initialize({ id: uuid.generateUuid() });152try {153await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true });154} catch (error) {155assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED);156return;157}158assert.fail('Should fail with ERROR_NO_WORKSPACE_OPENED');159});160161test('errors cases - invalid configuration', async () => {162await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString(',,,,,,,,,,,,,,'));163try {164await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true });165} catch (error) {166assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION);167return;168}169assert.fail('Should fail with ERROR_INVALID_CONFIGURATION');170});171172test('errors cases - invalid global tasks configuration', async () => {173const resource = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);174await fileService.writeFile(resource, VSBuffer.fromString(',,,,,,,,,,,,,,'));175try {176await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks.configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true });177} catch (error) {178assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION);179return;180}181assert.fail('Should fail with ERROR_INVALID_CONFIGURATION');182});183184test('errors cases - dirty', async () => {185instantiationService.stub(ITextFileService, 'isDirty', true);186try {187await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true });188} catch (error) {189assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY);190return;191}192assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.');193});194195test('do not notify error', async () => {196instantiationService.stub(ITextFileService, 'isDirty', true);197const target = sinon.stub();198instantiationService.stub(INotificationService, <INotificationService>{ prompt: target, _serviceBrand: undefined, filter: false, onDidChangeFilter: undefined!, notify: null!, error: null!, info: null!, warn: null!, status: null!, setFilter: null!, getFilter: null!, getFilters: null!, removeFilter: null! });199try {200await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true });201} catch (error) {202assert.strictEqual(false, target.calledOnce);203assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY);204return;205}206assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.');207});208209test('errors cases - ERROR_POLICY_CONFIGURATION', async () => {210await runWithFakedTimers({ useFakeTimers: true }, async () => {211const promise = Event.toPromise(instantiationService.get(IConfigurationService).onDidChangeConfiguration);212await fileService.writeFile(environmentService.policyFile!, VSBuffer.fromString('{ "configurationEditing.service.policySetting": "policyValue" }'));213await promise;214});215try {216await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.policySetting', value: 'value' }, { donotNotifyError: true });217} catch (error) {218assert.strictEqual(error.code, ConfigurationEditingErrorCode.ERROR_POLICY_CONFIGURATION);219return;220}221assert.fail('Should fail with ERROR_POLICY_CONFIGURATION');222});223224test('write policy setting - when not set', async () => {225await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.policySetting', value: 'value' }, { donotNotifyError: true });226const contents = await fileService.readFile(userDataProfileService.currentProfile.settingsResource);227const parsed = json.parse(contents.value.toString());228assert.strictEqual(parsed['configurationEditing.service.policySetting'], 'value');229});230231test('write one setting - empty file', async () => {232await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' });233const contents = await fileService.readFile(userDataProfileService.currentProfile.settingsResource);234const parsed = json.parse(contents.value.toString());235assert.strictEqual(parsed['configurationEditing.service.testSetting'], 'value');236});237238test('write one setting - existing file', async () => {239await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));240await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' });241242const contents = await fileService.readFile(userDataProfileService.currentProfile.settingsResource);243const parsed = json.parse(contents.value.toString());244assert.strictEqual(parsed['configurationEditing.service.testSetting'], 'value');245assert.strictEqual(parsed['my.super.setting'], 'my.super.value');246});247248test('remove an existing setting - existing file', async () => {249await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "my.super.setting": "my.super.value", "configurationEditing.service.testSetting": "value" }'));250await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: undefined });251252const contents = await fileService.readFile(userDataProfileService.currentProfile.settingsResource);253const parsed = json.parse(contents.value.toString());254assert.deepStrictEqual(Object.keys(parsed), ['my.super.setting']);255assert.strictEqual(parsed['my.super.setting'], 'my.super.value');256});257258test('remove non existing setting - existing file', async () => {259await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));260await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: undefined });261262const contents = await fileService.readFile(userDataProfileService.currentProfile.settingsResource);263const parsed = json.parse(contents.value.toString());264assert.deepStrictEqual(Object.keys(parsed), ['my.super.setting']);265assert.strictEqual(parsed['my.super.setting'], 'my.super.value');266});267268test('write overridable settings to user settings', async () => {269const key = '[language]';270const value = { 'configurationEditing.service.testSetting': 'overridden value' };271await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key, value });272273const contents = await fileService.readFile(userDataProfileService.currentProfile.settingsResource);274const parsed = json.parse(contents.value.toString());275assert.deepStrictEqual(parsed[key], value);276});277278test('write overridable settings to workspace settings', async () => {279const key = '[language]';280const value = { 'configurationEditing.service.testSetting': 'overridden value' };281await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key, value });282283const contents = await fileService.readFile(joinPath(workspaceService.getWorkspace().folders[0].uri, FOLDER_SETTINGS_PATH));284const parsed = json.parse(contents.value.toString());285assert.deepStrictEqual(parsed[key], value);286});287288test('write overridable settings to workspace folder settings', async () => {289const key = '[language]';290const value = { 'configurationEditing.service.testSetting': 'overridden value' };291const folderSettingsFile = joinPath(workspaceService.getWorkspace().folders[0].uri, FOLDER_SETTINGS_PATH);292await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE_FOLDER, { key, value }, { scopes: { resource: folderSettingsFile } });293294const contents = await fileService.readFile(folderSettingsFile);295const parsed = json.parse(contents.value.toString());296assert.deepStrictEqual(parsed[key], value);297});298299test('write workspace standalone setting - empty file', async () => {300const target = joinPath(workspaceService.getWorkspace().folders[0].uri, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);301await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' });302303const contents = await fileService.readFile(target);304const parsed = json.parse(contents.value.toString());305assert.strictEqual(parsed['service.testSetting'], 'value');306});307308test('write user standalone setting - empty file', async () => {309const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);310await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks.service.testSetting', value: 'value' });311312const contents = await fileService.readFile(target);313const parsed = json.parse(contents.value.toString());314assert.strictEqual(parsed['service.testSetting'], 'value');315});316317test('write workspace standalone setting - existing file', async () => {318const target = joinPath(workspaceService.getWorkspace().folders[0].uri, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);319await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));320321await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' });322323const contents = await fileService.readFile(target);324const parsed = json.parse(contents.value.toString());325assert.strictEqual(parsed['service.testSetting'], 'value');326assert.strictEqual(parsed['my.super.setting'], 'my.super.value');327});328329test('write user standalone setting - existing file', async () => {330const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);331await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));332333await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks.service.testSetting', value: 'value' });334335const contents = await fileService.readFile(target);336const parsed = json.parse(contents.value.toString());337assert.strictEqual(parsed['service.testSetting'], 'value');338assert.strictEqual(parsed['my.super.setting'], 'my.super.value');339});340341test('write user standalone mcp setting - existing file', async () => {342const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['mcp']);343await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));344345await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'mcp.service.testSetting', value: 'value' });346347const contents = await fileService.readFile(target);348const parsed = json.parse(contents.value.toString());349assert.strictEqual(parsed['service.testSetting'], 'value');350assert.strictEqual(parsed['my.super.setting'], 'my.super.value');351});352353test('write workspace standalone setting - empty file - full JSON', async () => {354await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } });355356const target = joinPath(workspaceService.getWorkspace().folders[0].uri, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);357const contents = await fileService.readFile(target);358const parsed = json.parse(contents.value.toString());359assert.strictEqual(parsed['version'], '1.0.0');360assert.strictEqual(parsed['tasks'][0]['taskName'], 'myTask');361});362363test('write user standalone setting - empty file - full JSON', async () => {364await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } });365366const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);367const contents = await fileService.readFile(target);368const parsed = json.parse(contents.value.toString());369assert.strictEqual(parsed['version'], '1.0.0');370assert.strictEqual(parsed['tasks'][0]['taskName'], 'myTask');371});372373test('write workspace standalone setting - existing file - full JSON', async () => {374const target = joinPath(workspaceService.getWorkspace().folders[0].uri, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);375await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));376377await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } });378379const contents = await fileService.readFile(target);380const parsed = json.parse(contents.value.toString());381assert.strictEqual(parsed['version'], '1.0.0');382assert.strictEqual(parsed['tasks'][0]['taskName'], 'myTask');383});384385test('write user standalone setting - existing file - full JSON', async () => {386const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);387await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": "my.super.value" }'));388389await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } });390391const contents = await fileService.readFile(target);392const parsed = json.parse(contents.value.toString());393assert.strictEqual(parsed['version'], '1.0.0');394assert.strictEqual(parsed['tasks'][0]['taskName'], 'myTask');395});396397test('write workspace standalone setting - existing file with JSON errors - full JSON', async () => {398const target = joinPath(workspaceService.getWorkspace().folders[0].uri, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);399await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": ')); // invalid JSON400401await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } });402403const contents = await fileService.readFile(target);404const parsed = json.parse(contents.value.toString());405assert.strictEqual(parsed['version'], '1.0.0');406assert.strictEqual(parsed['tasks'][0]['taskName'], 'myTask');407});408409test('write user standalone setting - existing file with JSON errors - full JSON', async () => {410const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);411await fileService.writeFile(target, VSBuffer.fromString('{ "my.super.setting": ')); // invalid JSON412413await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } });414415const contents = await fileService.readFile(target);416const parsed = json.parse(contents.value.toString());417assert.strictEqual(parsed['version'], '1.0.0');418assert.strictEqual(parsed['tasks'][0]['taskName'], 'myTask');419});420421test('write workspace standalone setting should replace complete file', async () => {422const target = joinPath(workspaceService.getWorkspace().folders[0].uri, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);423await fileService.writeFile(target, VSBuffer.fromString(`{424"version": "1.0.0",425"tasks": [426{427"taskName": "myTask1"428},429{430"taskName": "myTask2"431}432]433}`));434435await testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } });436437const actual = await fileService.readFile(target);438const expected = JSON.stringify({ 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] }, null, '\t');439assert.strictEqual(actual.value.toString(), expected);440});441442test('write user standalone setting should replace complete file', async () => {443const target = joinPath(environmentService.userRoamingDataHome, USER_STANDALONE_CONFIGURATIONS['tasks']);444await fileService.writeFile(target, VSBuffer.fromString(`{445"version": "1.0.0",446"tasks": [447{448"taskName": "myTask1"449},450{451"taskName": "myTask2"452}453]454}`));455456await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } });457458const actual = await fileService.readFile(target);459const expected = JSON.stringify({ 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] }, null, '\t');460assert.strictEqual(actual.value.toString(), expected);461});462});463464465