From b2b129a7f468b69c6e1133adb1588d295ade7c2e Mon Sep 17 00:00:00 2001 From: Gorkem Ercan Date: Thu, 22 Jun 2023 12:37:57 -0400 Subject: [PATCH] CustomSchemaProvider for tests (#898) Introduces a new CustomSchemaProvider. Removes the earlier hack from SchemaService that mapped schemas to itself. Updates the tests for the new API. --- .../services/yamlSchemaService.ts | 17 +- test/autoCompletion.test.ts | 224 +++++++++--------- test/autoCompletionFix.test.ts | 104 ++++---- test/code-action-schema.test.ts | 21 +- test/hover.test.ts | 59 ++--- test/schemaValidation.test.ts | 169 ++++++------- test/utils/testHelper.ts | 110 +++++++++ 7 files changed, 419 insertions(+), 285 deletions(-) diff --git a/src/languageservice/services/yamlSchemaService.ts b/src/languageservice/services/yamlSchemaService.ts index 06882bc14..08c03229f 100644 --- a/src/languageservice/services/yamlSchemaService.ts +++ b/src/languageservice/services/yamlSchemaService.ts @@ -405,17 +405,6 @@ export class YAMLSchemaService extends JSONSchemaService { } } - /** - * If this resource matches a schemaID directly then use that schema. - * This will be used in the case where the yaml language server is being used as a library - * and clients want to save a schema with a particular ID and also use that schema - * in language features - */ - const normalizedResourceID = this.normalizeId(resource); - if (this.schemasById[normalizedResourceID]) { - schemas.push(normalizedResourceID); - } - if (schemas.length > 0) { // Join all schemas with the highest priority. const highestPrioSchemas = this.highestPrioritySchemas(schemas); @@ -444,7 +433,7 @@ export class YAMLSchemaService extends JSONSchemaService { return { errors: [], schema: { - anyOf: schemas.map((schemaObj) => { + allOf: schemas.map((schemaObj) => { return schemaObj.schema; }), }, @@ -516,11 +505,11 @@ export class YAMLSchemaService extends JSONSchemaService { private async resolveCustomSchema(schemaUri, doc): ResolvedSchema { const unresolvedSchema = await this.loadSchema(schemaUri); const schema = await this.resolveSchemaContent(unresolvedSchema, schemaUri, []); - if (schema.schema) { + if (schema.schema && typeof schema.schema === 'object') { schema.schema.url = schemaUri; } if (schema.schema && schema.schema.schemaSequence && schema.schema.schemaSequence[doc.currentDocIndex]) { - return new ResolvedSchema(schema.schema.schemaSequence[doc.currentDocIndex]); + return new ResolvedSchema(schema.schema.schemaSequence[doc.currentDocIndex], schema.errors); } return schema; } diff --git a/test/autoCompletion.test.ts b/test/autoCompletion.test.ts index 9741b7be0..78b14996d 100644 --- a/test/autoCompletion.test.ts +++ b/test/autoCompletion.test.ts @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ /* eslint-disable @typescript-eslint/no-var-requires */ -import { caretPosition, SCHEMA_ID, setupLanguageService, setupSchemaIDTextDocument, toFsPath } from './utils/testHelper'; +import { + caretPosition, + SCHEMA_ID, + setupLanguageService, + setupSchemaIDTextDocument, + TestCustomSchemaProvider, + toFsPath, +} from './utils/testHelper'; import assert = require('assert'); import path = require('path'); import { createExpectedCompletion } from './utils/verifyError'; @@ -20,6 +27,7 @@ describe('Auto Completion Tests', () => { let languageService: LanguageService; let languageHandler: LanguageHandlers; let yamlSettings: SettingsState; + let schemaProvider: TestCustomSchemaProvider; before(() => { languageSettingsSetup = new ServiceSetup().withCompletion().withSchemaFileMatch({ @@ -30,10 +38,12 @@ describe('Auto Completion Tests', () => { languageService: langService, languageHandler: langHandler, yamlSettings: settings, + schemaProvider: testSchemaProvider, } = setupLanguageService(languageSettingsSetup.languageSettings); languageService = langService; languageHandler = langHandler; yamlSettings = settings; + schemaProvider = testSchemaProvider; }); /** @@ -59,14 +69,14 @@ describe('Auto Completion Tests', () => { } afterEach(() => { - languageService.deleteSchema(SCHEMA_ID); + schemaProvider.deleteSchema(SCHEMA_ID); languageService.configure(languageSettingsSetup.languageSettings); }); describe('YAML Completion Tests', function () { describe('JSON Schema Tests', function () { it('Autocomplete on root without word', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -90,7 +100,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on root with partial word', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -114,7 +124,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on default value (without :)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -139,7 +149,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on default value (without value content)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -164,7 +174,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on default value with \\"', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -185,7 +195,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete name and value with \\"', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -206,7 +216,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on default value (with value content)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -231,7 +241,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on default value (with value content contains dash)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { name: { @@ -256,7 +266,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on boolean value (without value content)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { yaml: { @@ -286,7 +296,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on boolean value with key of `null`', () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { validation: { @@ -310,7 +320,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on boolean value (with value content)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { yaml: { @@ -340,7 +350,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on number value (without value content)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { timeout: { @@ -365,7 +375,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on number value (with value content)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { timeout: { @@ -390,7 +400,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete key in middle of file', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -420,7 +430,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete key with default value in middle of file', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -453,7 +463,7 @@ describe('Auto Completion Tests', () => { const languageSettingsSetup = new ServiceSetup().withCompletion(); languageSettingsSetup.languageSettings.disableDefaultProperties = true; languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -483,7 +493,7 @@ describe('Auto Completion Tests', () => { const languageSettingsSetup = new ServiceSetup().withCompletion(); languageSettingsSetup.languageSettings.disableDefaultProperties = true; languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -512,7 +522,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete second key in middle of file', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -546,7 +556,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete does not happen right after key object', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { timeout: { @@ -565,7 +575,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete does not happen right after : under an object', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -593,7 +603,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete with defaultSnippet markdown', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -621,7 +631,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on multi yaml documents in a single file on root', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { timeout: { @@ -646,7 +656,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete on multi yaml documents in a single file on scalar', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { timeout: { @@ -671,7 +681,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion has no results on value when they are not available', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { time: { @@ -689,7 +699,7 @@ describe('Auto Completion Tests', () => { }); it('Test that properties that have multiple types get auto completed properly', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -741,7 +751,7 @@ describe('Auto Completion Tests', () => { }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'kind: '; // len: 6 const validator = parseSetup(content, 6); validator @@ -777,7 +787,7 @@ describe('Auto Completion Tests', () => { it('Insert required attributes at correct level', (done) => { const schema = require(path.join(__dirname, './fixtures/testRequiredProperties.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- top:\n prop1: demo\n- '; const completion = parseSetup(content, content.length); completion @@ -795,7 +805,7 @@ describe('Auto Completion Tests', () => { it('Insert required attributes at correct level even on first element', (done) => { const schema = require(path.join(__dirname, './fixtures/testRequiredProperties.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- '; const completion = parseSetup(content, content.length); completion @@ -813,7 +823,7 @@ describe('Auto Completion Tests', () => { it('Provide the 3 types when none provided', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayMaxProperties.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- '; const completion = parseSetup(content, content.length); completion @@ -843,7 +853,7 @@ describe('Auto Completion Tests', () => { it('Provide the 2 types when one is provided', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayMaxProperties.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- prop1:\n '; const completion = parseSetup(content, content.length); completion @@ -867,7 +877,7 @@ describe('Auto Completion Tests', () => { it('Provide the 2 types when one is provided and the second is typed', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayMaxProperties.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- prop1:\n p'; const completion = parseSetup(content, content.length); completion @@ -891,7 +901,7 @@ describe('Auto Completion Tests', () => { it('Provide no completion when maxProperties reached', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayMaxProperties.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- prop1:\n prop2:\n '; const completion = parseSetup(content, content.length); completion @@ -902,7 +912,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion should escape @', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { '@type': { @@ -922,7 +932,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion should escape colon when indicating map', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { 'test: colon': { @@ -947,7 +957,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion should not escape colon when no white-space following', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { 'test:colon': { @@ -972,7 +982,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion should not escape colon when no key part present', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { ':colon': { @@ -1021,7 +1031,7 @@ describe('Auto Completion Tests', () => { }; it('should suggest "then" block if "if" match filePatternAssociation', async () => { schema.if.filePatternAssociation = SCHEMA_ID; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: aName\n '; const completion = await parseSetup(content, content.length); expect(completion.items.map((i) => i.label)).to.deep.equal(['pineapple', 'basket']); @@ -1032,7 +1042,7 @@ describe('Auto Completion Tests', () => { describe('Array Specific Tests', function () { it('Should insert empty array item', (done) => { const schema = require(path.join(__dirname, './fixtures/testStringArray.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'fooBa'; // len: 5 const completion = parseSetup(content, content.lastIndexOf('Ba') + 2); // pos: 3+2 completion @@ -1043,7 +1053,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete without word and extra space', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1075,7 +1085,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete without word and autocompletion beside -', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1107,7 +1117,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete without word on space before array symbol', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1142,7 +1152,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete on empty node with array from schema', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1177,7 +1187,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete with letter', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1209,7 +1219,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete without word (second item)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1244,7 +1254,7 @@ describe('Auto Completion Tests', () => { }); it('Array autocomplete with letter (second item)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1279,7 +1289,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion after array', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -1317,7 +1327,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion after array with depth - no indent', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { archive: { @@ -1357,7 +1367,7 @@ describe('Auto Completion Tests', () => { }); it('Autocompletion after array with depth - indent', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { archive: { @@ -1398,7 +1408,7 @@ describe('Auto Completion Tests', () => { }); it('Array of enum autocomplete without word on array symbol', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { references: { @@ -1425,7 +1435,7 @@ describe('Auto Completion Tests', () => { }); it('Array of enum autocomplete without word', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { references: { @@ -1452,7 +1462,7 @@ describe('Auto Completion Tests', () => { }); it('Array of enum autocomplete with letter', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { references: { @@ -1481,7 +1491,7 @@ describe('Auto Completion Tests', () => { it('Array of objects autocomplete with 4 space indentation check', async () => { const languageSettingsSetup = new ServiceSetup().withCompletion().withIndentation(' '); languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { metadata: { @@ -1534,7 +1544,7 @@ describe('Auto Completion Tests', () => { it('Array of objects autocomplete with 2 space indentation check', async () => { const languageSettingsSetup = new ServiceSetup().withCompletion().withIndentation(' '); languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { metadata: { @@ -1586,7 +1596,7 @@ describe('Auto Completion Tests', () => { it('Array of objects autocomplete with 3 space indentation check', async () => { const languageSettingsSetup = new ServiceSetup().withCompletion().withIndentation(' '); languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { metadata: { @@ -1661,7 +1671,7 @@ describe('Auto Completion Tests', () => { it('Object in array with 4 space indentation check', async () => { const languageSettingsSetup = new ServiceSetup().withCompletion().withIndentation(' '); languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { rules: { @@ -1735,7 +1745,7 @@ describe('Auto Completion Tests', () => { describe('JSON Schema 7 Specific Tests', function () { it('Autocomplete works with examples', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { foodItems: { @@ -1763,7 +1773,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete works with const', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { fruit: { @@ -1786,7 +1796,7 @@ describe('Auto Completion Tests', () => { .then(done, done); }); it('Autocomplete should suggest prop with const value', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { fruit: { @@ -1809,7 +1819,7 @@ describe('Auto Completion Tests', () => { .then(done, done); }); it('Should insert quotation value if there is special char', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { from: { @@ -1833,7 +1843,7 @@ describe('Auto Completion Tests', () => { describe('Indentation Specific Tests', function () { it('Indent should be considered with position relative to slash', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayIndent.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'install:\n - he'; // len: 15 const completion = parseSetup(content, content.lastIndexOf('he') + 2); // pos: 13+2 completion @@ -1851,7 +1861,7 @@ describe('Auto Completion Tests', () => { it('Large indent should be considered with position relative to slash', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayIndent.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'install:\n - he'; // len: 25 const completion = parseSetup(content, content.lastIndexOf('he') + 2); // pos: 23+2 completion @@ -1869,7 +1879,7 @@ describe('Auto Completion Tests', () => { it('Tab indent should be considered with position relative to slash', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayIndent.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'install:\n -\t he'; // len: 27 const completion = parseSetup(content, content.lastIndexOf('he') + 2); // pos: 25+2 completion @@ -1959,7 +1969,7 @@ describe('Auto Completion Tests', () => { it('should not provide modeline completion on first character when schema is associated', async () => { const specificSchemaId = path.join(__dirname, 'test.yaml'); const testTextDocument = setupSchemaIDTextDocument('', specificSchemaId); - languageService.addSchema(specificSchemaId, { + schemaProvider.addSchema(specificSchemaId, { type: 'object', properties: { name: { @@ -2019,7 +2029,7 @@ describe('Auto Completion Tests', () => { it('4 space indentation', async () => { const languageSettingsSetup = new ServiceSetup().withCompletion().withIndentation(' '); languageService.configure(languageSettingsSetup.languageSettings); - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -2051,7 +2061,7 @@ describe('Auto Completion Tests', () => { describe('Bug fixes', () => { it('Object in array completion indetetion', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { components: { @@ -2105,7 +2115,7 @@ describe('Auto Completion Tests', () => { }); it('Object completion', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { env: { @@ -2133,7 +2143,7 @@ describe('Auto Completion Tests', () => { }); it('Complex default object completion', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { env: { @@ -2175,7 +2185,7 @@ describe('Auto Completion Tests', () => { }); it('should handle array schema without items', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'array', items: { anyOf: [ @@ -2208,7 +2218,7 @@ describe('Auto Completion Tests', () => { }); it('auto completion based on the list indentation', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'array', items: { type: 'object', @@ -2242,7 +2252,7 @@ describe('Auto Completion Tests', () => { }); it('should complete string which contains number in default value', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { env: { @@ -2269,7 +2279,7 @@ describe('Auto Completion Tests', () => { }); it('should complete string which contains number in examples values', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { fooBar: { @@ -2296,7 +2306,7 @@ describe('Auto Completion Tests', () => { }); it('should provide label as string for examples completion item', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { fooBar: { @@ -2316,7 +2326,7 @@ describe('Auto Completion Tests', () => { }); it('should provide completion for flow map', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { A: { type: 'string', enum: ['a1', 'a2'] }, B: { type: 'string', enum: ['b1', 'b2'] } }, }); @@ -2333,7 +2343,7 @@ describe('Auto Completion Tests', () => { }); it('should provide completion for "null" enum value', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { kind: { @@ -2354,7 +2364,7 @@ describe('Auto Completion Tests', () => { }); it('should provide completion for empty file', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { oneOf: [ { type: 'object', @@ -2393,7 +2403,7 @@ describe('Auto Completion Tests', () => { }); it('should not provide additional ":" on existing property completion', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { kind: { @@ -2412,7 +2422,7 @@ describe('Auto Completion Tests', () => { }); it('should not provide additional ":" on existing property completion when try to complete partial property', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { kind: { @@ -2431,7 +2441,7 @@ describe('Auto Completion Tests', () => { }); it('should use markdownDescription for property completion', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { kind: { @@ -2458,7 +2468,7 @@ describe('Auto Completion Tests', () => { }); it('should follow $ref in additionalItems', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { test: { @@ -2491,7 +2501,7 @@ describe('Auto Completion Tests', () => { }); it('should follow $ref in additionalItems: extra space after cursor', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { test: { @@ -2523,7 +2533,7 @@ describe('Auto Completion Tests', () => { }); it('should follow $ref in additionalItems for flow style array', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { test: { @@ -2567,7 +2577,7 @@ describe('Auto Completion Tests', () => { }); it('should convert to string non string completion label', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { version: { @@ -2592,7 +2602,7 @@ describe('Auto Completion Tests', () => { describe('Array completion', () => { it('Simple array object completion with "-" without any item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_simpleArrayObject:\n -'; const completion = parseSetup(content, content.length); completion @@ -2606,7 +2616,7 @@ describe('Auto Completion Tests', () => { it('Simple array object completion without "-" after array item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_simpleArrayObject:\n - obj1:\n name: 1\n '; const completion = parseSetup(content, content.length); completion @@ -2619,7 +2629,7 @@ describe('Auto Completion Tests', () => { it('Simple array object completion with "-" after array item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_simpleArrayObject:\n - obj1:\n name: 1\n -'; const completion = parseSetup(content, content.length); completion @@ -2633,7 +2643,7 @@ describe('Auto Completion Tests', () => { it('Array anyOf two objects completion with "- " without any item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_array_anyOf_2objects:\n - '; const completion = parseSetup(content, content.length); completion @@ -2649,7 +2659,7 @@ describe('Auto Completion Tests', () => { it('Array anyOf two objects completion with "-" without any item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_array_anyOf_2objects:\n -'; const completion = parseSetup(content, content.length); completion @@ -2663,7 +2673,7 @@ describe('Auto Completion Tests', () => { it('Simple array object completion without "-" befor array empty item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_simpleArrayObject:\n |\n| -'; // len: 30, pos: 26 const completion = parseSetup(content); completion @@ -2676,7 +2686,7 @@ describe('Auto Completion Tests', () => { it('Array anyOf two objects completion without "-" after array item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_array_anyOf_2objects:\n - obj1:\n name: 1\n '; const completion = parseSetup(content, content.length); completion @@ -2688,7 +2698,7 @@ describe('Auto Completion Tests', () => { it('Array nested anyOf without "-" should return all array items', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_array_nested_anyOf:\n - obj1:\n name:1\n '; const completion = parseSetup(content, content.length); completion @@ -2700,7 +2710,7 @@ describe('Auto Completion Tests', () => { it('Array anyOf two objects completion with "-" after array item', (done) => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_array_anyOf_2objects:\n - obj1:\n name: 1\n -'; const completion = parseSetup(content, content.length); completion @@ -2714,7 +2724,7 @@ describe('Auto Completion Tests', () => { it('Array anyOf two objects completion indentation', async () => { const schema = require(path.join(__dirname, './fixtures/testArrayCompletionSchema.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test_array_anyOf_2objects:\n - obj'; const completion = await parseSetup(content, content.length); expect(completion.items.length).is.equal(4); @@ -2724,7 +2734,7 @@ describe('Auto Completion Tests', () => { }); it('Autocomplete key in nested object while typing', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { parent: { @@ -2822,7 +2832,7 @@ describe('Auto Completion Tests', () => { }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const result = await parseSetup(content, content.length); @@ -2850,7 +2860,7 @@ describe('Auto Completion Tests', () => { }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const result = await parseSetup(content, content.length); @@ -2899,7 +2909,7 @@ describe('Auto Completion Tests', () => { }, type: 'array', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- '; const result = await parseSetup(content, content.length); @@ -2944,7 +2954,7 @@ describe('Auto Completion Tests', () => { }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const result = await parseSetup(content, content.length); @@ -2964,7 +2974,7 @@ describe('Auto Completion Tests', () => { definitions: { obj1 }, $ref: '#/definitions/obj1', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'type: typeObj1\n'; const result = await parseSetup(content, content.length); @@ -2998,7 +3008,7 @@ describe('Auto Completion Tests', () => { required: ['type', 'options', 'prop1'], type: 'object', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const result = await parseSetup(content, content.length); @@ -3031,7 +3041,7 @@ describe('Auto Completion Tests', () => { }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const result = await parseSetup(content, content.length); @@ -3053,7 +3063,7 @@ describe('Auto Completion Tests', () => { }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name:\n '; const result = await parseSetup(content, content.length); @@ -3074,7 +3084,7 @@ describe('Auto Completion Tests', () => { }, type: 'array', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = '- '; const result = await parseSetup(content, content.length); @@ -3085,7 +3095,7 @@ describe('Auto Completion Tests', () => { definitions: { obj1 }, $ref: '#/definitions/obj1', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'type: typeObj1\n'; const result = await parseSetup(content, content.length); @@ -3096,7 +3106,7 @@ describe('Auto Completion Tests', () => { definitions: { obj1 }, $ref: '#/definitions/obj1', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'ty'; const result = await parseSetup(content, content.length); @@ -3109,7 +3119,7 @@ describe('Auto Completion Tests', () => { vegetable: {}, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const result = await parseSetup(content, content.length); diff --git a/test/autoCompletionFix.test.ts b/test/autoCompletionFix.test.ts index e13630504..81053315b 100644 --- a/test/autoCompletionFix.test.ts +++ b/test/autoCompletionFix.test.ts @@ -8,7 +8,13 @@ import { LanguageHandlers } from '../src/languageserver/handlers/languageHandler import { LanguageService } from '../src/languageservice/yamlLanguageService'; import { SettingsState, TextDocumentTestManager } from '../src/yamlSettings'; import { ServiceSetup } from './utils/serviceSetup'; -import { caretPosition, SCHEMA_ID, setupLanguageService, setupSchemaIDTextDocument } from './utils/testHelper'; +import { + caretPosition, + SCHEMA_ID, + setupLanguageService, + setupSchemaIDTextDocument, + TestCustomSchemaProvider, +} from './utils/testHelper'; import { expect } from 'chai'; import { createExpectedCompletion } from './utils/verifyError'; import * as path from 'path'; @@ -19,7 +25,7 @@ describe('Auto Completion Fix Tests', () => { let languageService: LanguageService; let languageHandler: LanguageHandlers; let yamlSettings: SettingsState; - + let schemaProvider: TestCustomSchemaProvider; before(() => { languageSettingsSetup = new ServiceSetup().withCompletion().withSchemaFileMatch({ uri: 'https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.22.4-standalone-strict/all.json', @@ -29,10 +35,12 @@ describe('Auto Completion Fix Tests', () => { languageService: langService, languageHandler: langHandler, yamlSettings: settings, + schemaProvider: testSchemaProvider, } = setupLanguageService(languageSettingsSetup.languageSettings); languageService = langService; languageHandler = langHandler; yamlSettings = settings; + schemaProvider = testSchemaProvider; }); /** @@ -72,12 +80,12 @@ describe('Auto Completion Fix Tests', () => { } afterEach(() => { - languageService.deleteSchema(SCHEMA_ID); + schemaProvider.deleteSchema(SCHEMA_ID); languageService.configure(languageSettingsSetup.languageSettings); }); it('should show completion on map under array', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'array', items: { type: 'object', @@ -104,7 +112,7 @@ describe('Auto Completion Fix Tests', () => { }); it('completion with array objects', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'array', items: { type: 'object', @@ -137,7 +145,7 @@ describe('Auto Completion Fix Tests', () => { }); it('should show completion on array empty array item', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'array', items: { type: 'object', @@ -193,7 +201,7 @@ spec: it('should complete array', async () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const schema = require(path.join(__dirname, './fixtures/test-nested-object-array.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `objA: - name: nameA1 @@ -208,7 +216,7 @@ objB: it('should complete array item for "oneOf" schema', async () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const schema = require(path.join(__dirname, './fixtures/test-completion-oneOf.json')); - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `metadata: Selector: query: @@ -220,7 +228,7 @@ objB: }); it('Autocomplete with short nextLine - nested object', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { example: { @@ -253,7 +261,7 @@ objB: }); it('Should suggest valid matches from oneOf', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { oneOf: [ { type: 'object', @@ -289,7 +297,7 @@ objB: }); it('Should suggest all the matches from allOf', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { allOf: [ { type: 'object', @@ -330,7 +338,7 @@ objB: }); it('Autocomplete with a new line inside the object', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { example: { @@ -362,7 +370,7 @@ objB: }); it('Autocomplete on the first array item', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { examples: { @@ -397,7 +405,7 @@ objB: }); it('Array of enum autocomplete of irregular order', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { apiVersion: { @@ -425,7 +433,7 @@ objB: }); it('Test that properties have enum of string type with number', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { version: { @@ -450,7 +458,7 @@ objB: }); it('Autocomplete indent on array when parent is array', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { examples: { @@ -480,7 +488,7 @@ objB: ); }); it('Autocomplete indent on array object when parent is array', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { examples: { @@ -515,7 +523,7 @@ objB: ); }); it('Autocomplete indent on array object when parent is array of an array', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { array1: { @@ -587,7 +595,7 @@ objB: }, }; it('array indent on the first item', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'objectWithArray:\n - '; // len: 21 const completion = await parseSetup(content, 1, 4); @@ -604,7 +612,7 @@ objB: ); }); it('array indent on the second item', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'objectWithArray:\n - item: first line\n '; // len: 42 const completion = await parseSetup(content, 2, 4); @@ -643,7 +651,7 @@ objB: }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const completion = await parseSetup(content, 0, 1); @@ -668,7 +676,7 @@ objB: }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const completion = await parseSetup(content, 0, 1); @@ -692,7 +700,7 @@ objB: }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const completion = await parseSetup(content, 0, 1); @@ -704,7 +712,7 @@ objB: }); it('Autocomplete should not suggest items for parent object', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -744,7 +752,7 @@ objB: }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const completion = await parseSetup(content, 0, 6); expect(completion.items.length).equal(1); @@ -762,7 +770,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'prop: | | '; // len: 8, pos: 6 const completion = await parseCaret(content); @@ -779,7 +787,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'na '; const completion = await parseSetup(content, 0, 2); @@ -798,7 +806,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'na \n'; const completion = await parseSetup(content, 0, 2); @@ -817,7 +825,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ' na '; const completion = await parseSetup(content, 0, 2); @@ -846,7 +854,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'array:\n - name / '; const completion = await parseSetup(content, 1, 9); @@ -867,7 +875,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: my| | '; const completion = await parseCaret(content); @@ -886,7 +894,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: my| | \n'; const completion = await parseCaret(content); @@ -905,7 +913,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: my na| | '; const completion = await parseCaret(content); @@ -934,7 +942,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'array:\n - name: my name /| | '; const completion = await parseCaret(content); @@ -962,7 +970,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'parent:\n prop1: const1\n prop2: '; const completion = await parseSetup(content, 2, 9); @@ -994,7 +1002,7 @@ objB: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'arrayObj:\n - item1: test\n - item2: '; const completion = await parseSetup(content, 2, 11); @@ -1026,7 +1034,7 @@ objB: }, }; it('1st item', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'arrayObj:\n - '; const completion = await parseSetup(content, 1, 4); @@ -1037,7 +1045,7 @@ objB: }); }); it('next item', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'arrayObj:\n - item1: a\n - item2: b\n - '; const completion = await parseSetup(content, 3, 4); @@ -1049,7 +1057,7 @@ objB: }); }); it('array completion - should suggest correct indent when extra spaces after cursor', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { test: { @@ -1078,7 +1086,7 @@ objB: expect(result.items[0].insertText).to.be.equal('objA:\n itemA: '); }); it('array of arrays completion - should suggest correct indent when extra spaces after cursor', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { array1: { @@ -1117,7 +1125,7 @@ objB: expect(result.items[0].insertText).to.be.equal('array2:\n - objA:\n itemA: '); }); it('object of array of arrays completion - should suggest correct indent when extra spaces after cursor', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { array1: { @@ -1167,7 +1175,7 @@ objB: ], }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'value: '; const completion = await parseSetup(content, 0, content.length); @@ -1208,14 +1216,14 @@ test1: pr `; it('nested object', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const completion = await parseSetup(content, 5, 6); expect(completion.items.length).equal(2); expect(completion.items[0].label).to.be.equal('prop1'); }); it('root object', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const completion = await parseSetup(content, 2, 4); expect(completion.items.length).equal(2); @@ -1245,7 +1253,7 @@ test1: }; it('completion should handle indented comment on new line', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'example:\n prop1: "test"\n \n #comment'; const completion = await parseSetup(content, 2, 2); expect(completion.items.length).equal(2); @@ -1257,7 +1265,7 @@ test1: }); it('completion should handle comment at same indent level on new line', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'example:\n prop1: "test"\n \n #comment'; const completion = await parseSetup(content, 2, 2); expect(completion.items.length).equal(2); @@ -1269,7 +1277,7 @@ test1: }); it('completion should handle suggestion without comment on next line', async () => { - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'example:\n prop1: "test"\n \n prop3: "test"'; const completion = await parseSetup(content, 2, 2); expect(completion.items.length).equal(1); @@ -1289,7 +1297,7 @@ test1: description: 'Property Description', }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = ''; const completion = await parseSetup(content, 0, content.length); diff --git a/test/code-action-schema.test.ts b/test/code-action-schema.test.ts index d320b0f9e..91e787c00 100644 --- a/test/code-action-schema.test.ts +++ b/test/code-action-schema.test.ts @@ -2,32 +2,37 @@ * Copyright (c) Red Hat. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SCHEMA_ID, setupLanguageService, setupSchemaIDTextDocument, TEST_URI } from './utils/testHelper'; +import { + SCHEMA_ID, + setupLanguageService, + setupSchemaIDTextDocument, + TEST_URI, + TestCustomSchemaProvider, +} from './utils/testHelper'; import { ServiceSetup } from './utils/serviceSetup'; import { TextDocumentIdentifier, CodeActionParams, CodeActionContext, TextEdit, Range } from 'vscode-languageserver'; import { expect } from 'chai'; import { SettingsState, TextDocumentTestManager } from '../src/yamlSettings'; import { ValidationHandler } from '../src/languageserver/handlers/validationHandlers'; -import { LanguageService } from '../src/languageservice/yamlLanguageService'; import { YamlCodeActions } from '../src/languageservice/services/yamlCodeActions'; import { TextDocument } from 'vscode-languageserver-textdocument'; describe('Schema Errors Code Action Tests', () => { let languageSettingsSetup: ServiceSetup; let validationHandler: ValidationHandler; - let languageService: LanguageService; let yamlSettings: SettingsState; + let schemaProvider: TestCustomSchemaProvider; before(() => { languageSettingsSetup = new ServiceSetup().withValidate(); const { - languageService: langService, validationHandler: valHandler, yamlSettings: settings, + schemaProvider: testSchemaProvider, } = setupLanguageService(languageSettingsSetup.languageSettings); - languageService = langService; validationHandler = valHandler; yamlSettings = settings; + schemaProvider = testSchemaProvider; }); function parseSetup(content: string, customSchemaID?: string): TextDocument { @@ -38,12 +43,12 @@ describe('Schema Errors Code Action Tests', () => { } afterEach(() => { - languageService.deleteSchema(SCHEMA_ID); + schemaProvider.deleteSchema(SCHEMA_ID); }); describe('Convert value code action tests', () => { it('Should provide convert to boolean action for false', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -70,7 +75,7 @@ describe('Schema Errors Code Action Tests', () => { }); it('Should provide convert to boolean action for true', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { diff --git a/test/hover.test.ts b/test/hover.test.ts index d45e781d0..afd286904 100644 --- a/test/hover.test.ts +++ b/test/hover.test.ts @@ -3,8 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { ServiceSetup } from './utils/serviceSetup'; -import { caretPosition, SCHEMA_ID, setupLanguageService, setupSchemaIDTextDocument } from './utils/testHelper'; -import { LanguageService } from '../src'; +import { + caretPosition, + SCHEMA_ID, + setupLanguageService, + setupSchemaIDTextDocument, + TestCustomSchemaProvider, +} from './utils/testHelper'; import * as assert from 'assert'; import { Hover, MarkupContent, Position } from 'vscode-languageserver-types'; import { LanguageHandlers } from '../src/languageserver/handlers/languageHandlers'; @@ -15,9 +20,9 @@ import { TestTelemetry } from './utils/testsTypes'; describe('Hover Tests', () => { let languageSettingsSetup: ServiceSetup; let languageHandler: LanguageHandlers; - let languageService: LanguageService; let yamlSettings: SettingsState; let telemetry: TestTelemetry; + let schemaProvider: TestCustomSchemaProvider; before(() => { languageSettingsSetup = new ServiceSetup().withHover().withSchemaFileMatch({ @@ -25,19 +30,19 @@ describe('Hover Tests', () => { fileMatch: ['bad-schema.yaml'], }); const { - languageService: langService, languageHandler: langHandler, yamlSettings: settings, telemetry: testTelemetry, + schemaProvider: testSchemaProvider, } = setupLanguageService(languageSettingsSetup.languageSettings); - languageService = langService; languageHandler = langHandler; yamlSettings = settings; telemetry = testTelemetry; + schemaProvider = testSchemaProvider; }); afterEach(() => { - languageService.deleteSchema(SCHEMA_ID); + schemaProvider.deleteSchema(SCHEMA_ID); }); /** @@ -64,7 +69,7 @@ describe('Hover Tests', () => { describe('Hover', function () { it('Hover on key on root', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -86,7 +91,7 @@ describe('Hover Tests', () => { }); it('Hover on value on root', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -108,7 +113,7 @@ describe('Hover Tests', () => { }); it('Hover on key with depth', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -134,7 +139,7 @@ describe('Hover Tests', () => { }); it('Hover on value with depth', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -160,7 +165,7 @@ describe('Hover Tests', () => { }); it('Hover works on both root node and child nodes works', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -196,7 +201,7 @@ describe('Hover Tests', () => { }); it('Hover does not show results when there isnt description field', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -212,7 +217,7 @@ describe('Hover Tests', () => { }); it('Hover on first document in multi document', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -228,7 +233,7 @@ describe('Hover Tests', () => { }); it('Hover on second document in multi document', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -251,7 +256,7 @@ describe('Hover Tests', () => { }); it('Hover should not return anything on key', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: {}, }); @@ -263,7 +268,7 @@ describe('Hover Tests', () => { }); it('Hover should not return anything on value', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: {}, }); @@ -275,7 +280,7 @@ describe('Hover Tests', () => { }); it('Hover works on array nodes', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -303,7 +308,7 @@ describe('Hover Tests', () => { }); it('Hover works on additional array nodes', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { authors: { @@ -335,7 +340,7 @@ describe('Hover Tests', () => { }); it('Hover works on oneOf reference array nodes', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', definitions: { stringoptions: { @@ -444,7 +449,7 @@ storage: }); it('Hover on refs node', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', additionalProperties: false, properties: { @@ -491,7 +496,7 @@ users: }); it('Hover on null property', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { childObject: { @@ -520,18 +525,18 @@ users: fileMatch: ['bad-schema.yaml'], }); const { - languageService: langService, languageHandler: langHandler, yamlSettings: settings, telemetry: testTelemetry, + schemaProvider: testSchemaProvider, } = setupLanguageService(languageSettingsSetup.languageSettings); - languageService = langService; languageHandler = langHandler; yamlSettings = settings; telemetry = testTelemetry; + schemaProvider = testSchemaProvider; })(); //https://github.com/redhat-developer/vscode-yaml/issues/886 - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', title: 'Person', properties: { @@ -552,7 +557,7 @@ users: }); it('Hover works on examples', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { animal: { @@ -583,7 +588,7 @@ Source: [${SCHEMA_ID}](file:///${SCHEMA_ID})` }); it('Hover on property next value on null', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { childObject: { @@ -622,7 +627,7 @@ Source: [${SCHEMA_ID}](file:///${SCHEMA_ID})` describe('Hover on anyOf', () => { it('should show all matched schemas in anyOf', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { title: 'The Root', description: 'Root Object', type: 'object', diff --git a/test/schemaValidation.test.ts b/test/schemaValidation.test.ts index 3c62261ca..42d6cd5af 100644 --- a/test/schemaValidation.test.ts +++ b/test/schemaValidation.test.ts @@ -2,7 +2,7 @@ * Copyright (c) Red Hat. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SCHEMA_ID, setupLanguageService, setupSchemaIDTextDocument } from './utils/testHelper'; +import { SCHEMA_ID, TestCustomSchemaProvider, setupLanguageService, setupSchemaIDTextDocument } from './utils/testHelper'; import { createDiagnosticWithData, createExpectedError } from './utils/verifyError'; import { ServiceSetup } from './utils/serviceSetup'; import { @@ -33,6 +33,7 @@ describe('Validation Tests', () => { let languageService: LanguageService; let yamlSettings: SettingsState; let telemetry: TestTelemetry; + let schemaProvider: TestCustomSchemaProvider; before(() => { languageSettingsSetup = new ServiceSetup() @@ -51,11 +52,13 @@ describe('Validation Tests', () => { validationHandler: valHandler, yamlSettings: settings, telemetry: testTelemetry, + schemaProvider: testSchemaProvider, } = setupLanguageService(languageSettingsSetup.languageSettings); languageService = langService; validationHandler = valHandler; yamlSettings = settings; telemetry = testTelemetry; + schemaProvider = testSchemaProvider; }); function parseSetup(content: string, customSchemaID?: string): Promise { @@ -66,12 +69,12 @@ describe('Validation Tests', () => { } afterEach(() => { - languageService.deleteSchema(SCHEMA_ID); + schemaProvider.deleteSchema(SCHEMA_ID); }); describe('Boolean tests', () => { it('Boolean true test', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -89,7 +92,7 @@ describe('Validation Tests', () => { }); it('Basic false test', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -107,7 +110,7 @@ describe('Validation Tests', () => { }); it('Test that boolean value without quotations is valid', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -125,7 +128,7 @@ describe('Validation Tests', () => { }); it('Test that boolean value in quotations is interpreted as string not boolean', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -156,7 +159,7 @@ describe('Validation Tests', () => { }); it('Error on incorrect value type (boolean)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -189,7 +192,7 @@ describe('Validation Tests', () => { describe('String tests', () => { it('Test that boolean inside of quotations is of type string', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -207,7 +210,7 @@ describe('Validation Tests', () => { }); it('Type string validates under children', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -230,7 +233,7 @@ describe('Validation Tests', () => { }); it('Type String does not error on valid node', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -248,7 +251,7 @@ describe('Validation Tests', () => { }); it('Error on incorrect value type (string)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -279,7 +282,7 @@ describe('Validation Tests', () => { }); it('Test that boolean is invalid when no strings present and schema wants string', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -312,7 +315,7 @@ describe('Validation Tests', () => { describe('Pattern tests', () => { it('Test a valid Unicode pattern', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { prop: { @@ -328,7 +331,7 @@ describe('Validation Tests', () => { .then(done, done); }); it('Test an invalid Unicode pattern', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { prop: { @@ -359,7 +362,7 @@ describe('Validation Tests', () => { }); it('Test a valid Unicode patternProperty', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', patternProperties: { '^tes\\p{Letter}$': true, @@ -373,7 +376,7 @@ describe('Validation Tests', () => { .then(done, done); }); it('Test an invalid Unicode patternProperty', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', patternProperties: { '^tes\\p{Letter}$': true, @@ -403,7 +406,7 @@ describe('Validation Tests', () => { describe('Number tests', () => { it('Type Number does not error on valid node', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { timeout: { @@ -421,7 +424,7 @@ describe('Validation Tests', () => { }); it('Error on incorrect value type (number)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -454,7 +457,7 @@ describe('Validation Tests', () => { describe('Null tests', () => { it('Basic test on nodes with null', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', additionalProperties: false, properties: { @@ -502,7 +505,7 @@ describe('Validation Tests', () => { describe('Object tests', () => { it('Basic test on nodes with children', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -528,7 +531,7 @@ describe('Validation Tests', () => { }); it('Test with multiple nodes with children', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -560,7 +563,7 @@ describe('Validation Tests', () => { }); it('Type Object does not error on valid node', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { registry: { @@ -583,7 +586,7 @@ describe('Validation Tests', () => { }); it('Error on incorrect value type (object)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', title: 'Object', properties: { @@ -622,7 +625,7 @@ describe('Validation Tests', () => { describe('Array tests', () => { it('Type Array does not error on valid node', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { resolvers: { @@ -643,7 +646,7 @@ describe('Validation Tests', () => { }); it('Error on incorrect value type (array)', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { resolvers: { @@ -676,7 +679,7 @@ describe('Validation Tests', () => { describe('Anchor tests', () => { it('Anchor should not error', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { default: { @@ -699,7 +702,7 @@ describe('Validation Tests', () => { }); it('Anchor with multiple references should not error', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { default: { @@ -722,7 +725,7 @@ describe('Validation Tests', () => { }); it('Multiple Anchor in array of references should not error', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { default: { @@ -746,7 +749,7 @@ describe('Validation Tests', () => { }); it('Multiple Anchors being referenced in same level at same time for yaml 1.1', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { customize: { @@ -767,7 +770,7 @@ describe('Validation Tests', () => { }); it('Multiple Anchors being referenced in same level at same time for yaml generate error for 1.2', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { customize: { @@ -789,7 +792,7 @@ describe('Validation Tests', () => { }); it('Nested object anchors should expand properly', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', additionalProperties: { type: 'object', @@ -821,7 +824,7 @@ describe('Validation Tests', () => { }); it('Anchor reference with a validation error in a sub-object emits the error in the right location', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { src: {}, @@ -871,7 +874,7 @@ describe('Validation Tests', () => { }); it('Array Anchor merge', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { arr: { @@ -908,7 +911,7 @@ obj: describe('Custom tag tests', () => { it('Custom Tags without type', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { analytics: { @@ -935,7 +938,7 @@ obj: }); it('Custom Tags with type', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { resolvers: { @@ -956,7 +959,7 @@ obj: }); it('Include with value should not error', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { customize: { @@ -987,7 +990,7 @@ obj: describe('Multiple type tests', function () { it('Do not error when there are multiple types in schema and theyre valid', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { license: { @@ -1007,7 +1010,7 @@ obj: describe('Invalid YAML errors', function () { it('Error when theres a finished untyped item', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -1029,7 +1032,7 @@ obj: }); it('Error when theres no value for a node', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -1093,7 +1096,7 @@ obj: }, $schema: 'http://json-schema.org/draft-07/schema#', }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'test: &test\n prop1: hello\nsample:\n <<: *test\n prop2: another_test'; const validator = parseSetup(content); validator @@ -1139,7 +1142,7 @@ obj: }, ], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'kind: '; const validator = parseSetup(content); validator @@ -1164,7 +1167,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const validator = parseSetup('nulltest: ' + content); validator .then(function (result) { @@ -1186,7 +1189,7 @@ obj: }, required: ['values'], }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'values: [Null, NULL, null, ~,]'; const validator = parseSetup(content); validator @@ -1199,7 +1202,7 @@ obj: describe('Multi Document schema validation tests', () => { it('Document does not error when --- is present with schema', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -1217,7 +1220,7 @@ obj: }); it('Multi Document does not error when --- is present with schema', (done) => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { cwd: { @@ -1237,7 +1240,7 @@ obj: describe('Schema with title', () => { it('validator uses schema title instead of url', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', title: 'Schema Super title', properties: { @@ -1334,7 +1337,7 @@ obj: describe('Conditional Schema', () => { it('validator use "then" block if "if" valid', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', default: [], properties: { @@ -1388,7 +1391,7 @@ obj: }; it('validator use "then" block if "if" match filePatternAssociation', async () => { schema.if.filePatternAssociation = SCHEMA_ID; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: aName'; const result = await parseSetup(content); @@ -1396,7 +1399,7 @@ obj: }); it('validator use "then" block if "if" match filePatternAssociation - regexp', async () => { schema.if.filePatternAssociation = '*.yaml'; // SCHEMA_ID: "default_schema_id.yaml" - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: aName'; const result = await parseSetup(content); @@ -1404,7 +1407,7 @@ obj: }); it('validator use "else" block if "if" not match filePatternAssociation', async () => { schema.if.filePatternAssociation = 'wrong'; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = 'name: aName'; const result = await parseSetup(content); @@ -1424,7 +1427,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schemaWithURIReference); + schemaProvider.addSchema(SCHEMA_ID, schemaWithURIReference); let content = ` one: '//foo/bar' `; @@ -1460,7 +1463,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schemaWithURIReference); + schemaProvider.addSchema(SCHEMA_ID, schemaWithURIReference); const content = ` one: '' `; @@ -1478,14 +1481,14 @@ obj: yamlSettings.specificValidatorPaths = []; }); afterEach(() => { - languageService.deleteSchema(sharedSchemaId); + schemaProvider.deleteSchema(SCHEMA_ID); + schemaProvider.deleteSchema(sharedSchemaId); }); it('should distinguish types in error "Incorrect type (Expected "type1 | type2 | type3")"', async () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const schema = require(path.join(__dirname, './fixtures/testMultipleSimilarSchema.json')); - - languageService.addSchema(sharedSchemaId, schema.sharedSchema); - languageService.addSchema(SCHEMA_ID, schema.schema); + schemaProvider.addSchemaWithUri(SCHEMA_ID, 'file:///sharedSchema.json', schema.sharedSchema); + schemaProvider.addSchema(SCHEMA_ID, schema.schema); const content = 'test_anyOf_objects:\n '; const result = await parseSetup(content); @@ -1501,8 +1504,8 @@ obj: // eslint-disable-next-line @typescript-eslint/no-var-requires const schema = require(path.join(__dirname, './fixtures/testMultipleSimilarSchema.json')); - languageService.addSchema(sharedSchemaId, schema.sharedSchema); - languageService.addSchema(SCHEMA_ID, schema.schema); + schemaProvider.addSchemaWithUri(SCHEMA_ID, 'file:///sharedSchema.json', schema.sharedSchema); + schemaProvider.addSchema(SCHEMA_ID, schema.schema); const content = 'test_anyOf_objects:\n propA:'; const result = await parseSetup(content); @@ -1514,8 +1517,8 @@ obj: // eslint-disable-next-line @typescript-eslint/no-var-requires const schema = require(path.join(__dirname, './fixtures/testMultipleSimilarSchema.json')); - languageService.addSchema(sharedSchemaId, schema.sharedSchema); - languageService.addSchema(SCHEMA_ID, schema.schema); + schemaProvider.addSchemaWithUri(SCHEMA_ID, 'file:///sharedSchema.json', schema.sharedSchema); + schemaProvider.addSchema(SCHEMA_ID, schema.schema); const content = 'test_anyOf_objects:\n constA:'; const result = await parseSetup(content); @@ -1527,8 +1530,8 @@ obj: // eslint-disable-next-line @typescript-eslint/no-var-requires const schema = require(path.join(__dirname, './fixtures/testMultipleSimilarSchema.json')); - languageService.addSchema(sharedSchemaId, schema.sharedSchema); - languageService.addSchema(SCHEMA_ID, schema.schema); + schemaProvider.addSchemaWithUri(sharedSchemaId, 'file:///sharedSchema.json', schema.sharedSchema); + schemaProvider.addSchema(SCHEMA_ID, schema.schema); const content = 'test_anyOf_objects:\n someProp:'; const result = await parseSetup(content); @@ -1556,7 +1559,7 @@ obj: describe('Empty document validation', () => { it('should provide validation for empty document', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -1584,7 +1587,7 @@ obj: }); it('should provide validation for document which contains only whitespaces', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { scripts: { @@ -1620,7 +1623,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `prop2: you could be there 'prop2'`; const result = await parseSetup(content); expect(result.length).to.eq(0); @@ -1644,7 +1647,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `prop2: you should not be there 'prop2'`; const result = await parseSetup(content); expect(result.length).to.eq(1); @@ -1664,7 +1667,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `prop1: value1\npropX: you should not be there 'propX'`; const result = await parseSetup(content); expect( @@ -1690,7 +1693,7 @@ obj: }, additionalProperties: true, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `prop2: you could be there 'prop2'`; const result = await parseSetup(content); expect(result.length).to.eq(0); @@ -1707,7 +1710,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `env: \${{ matrix.env1 }`; const result = await parseSetup(content); expect(result).to.be.not.empty; @@ -1724,7 +1727,7 @@ obj: format: 'ipv4', }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `- 10.15.12.500`; const result = await parseSetup(content); expect(result).to.be.not.empty; @@ -1741,7 +1744,7 @@ obj: format: 'ipv4', }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `- 255.255.255.255`; const result = await parseSetup(content); expect(result).to.be.empty; @@ -1756,7 +1759,7 @@ obj: format: 'ipv6', }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `- 10.15.12.500`; const result = await parseSetup(content); expect(result).to.be.not.empty; @@ -1773,7 +1776,7 @@ obj: format: 'ipv6', }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `- 2001:0db8:85a3:0000:0000:8a2e:0370:7334\n- 2001:0db8:85a3:0000:0000:8a2e:0370:7334\n- FEDC:BA98:7654:3210:FEDC:BA98:7654:3210\n- 1080::8:800:200C:417A\n- FF01::101\n- ::1`; const result = await parseSetup(content); expect(result).to.be.empty; @@ -1782,7 +1785,7 @@ obj: it('should handle not valid schema object', async () => { const schema = 'Foo'; - languageService.addSchema(SCHEMA_ID, schema as JSONSchema); + schemaProvider.addSchema(SCHEMA_ID, schema as JSONSchema); const content = `foo: bar`; const result = await parseSetup(content); expect(result).to.have.length(1); @@ -1800,7 +1803,7 @@ obj: }, additionalProperties: true, }; - languageService.addSchema(SCHEMA_ID, schema as JSONSchema); + schemaProvider.addSchema(SCHEMA_ID, schema as JSONSchema); const content = `bar: ddd`; const result = await parseSetup(content); expect(result.length).to.eq(1); @@ -1827,7 +1830,7 @@ obj: }, }, }; - languageService.addSchema(SCHEMA_ID, schema); + schemaProvider.addSchema(SCHEMA_ID, schema); const content = `container: image: alpine command: @@ -1845,8 +1848,12 @@ obj: }); describe('Enum tests', () => { + afterEach(() => { + schemaProvider.deleteSchema(SCHEMA_ID); + }); + it('Enum Validation with invalid enum value', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { first: { @@ -1866,7 +1873,7 @@ obj: }); it('Enum Validation with invalid type', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { first: { @@ -1886,7 +1893,7 @@ obj: }); it('Enum Validation with invalid data', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { definitions: { rule: { description: 'A rule', @@ -1921,7 +1928,7 @@ obj: }); it('value matches more than one schema in oneOf - but among one is format matches', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { repository: { @@ -1945,7 +1952,7 @@ obj: }); it('value matches more than one schema in oneOf', async () => { - languageService.addSchema(SCHEMA_ID, { + schemaProvider.addSchema(SCHEMA_ID, { type: 'object', properties: { foo: {}, diff --git a/test/utils/testHelper.ts b/test/utils/testHelper.ts index 3695ab5ac..71a9e4dd4 100644 --- a/test/utils/testHelper.ts +++ b/test/utils/testHelper.ts @@ -15,6 +15,7 @@ import { TextDocument } from 'vscode-languageserver-textdocument'; import { ClientCapabilities } from 'vscode-json-languageservice'; import { yamlDocumentsCache } from '../../src/languageservice/parser/yaml-documents'; import { TestTelemetry } from './testsTypes'; +import { JSONSchema } from '../../src/languageservice/jsonSchema'; export function toFsPath(str: unknown): string { if (typeof str !== 'string') { @@ -56,6 +57,7 @@ export interface TestLanguageServerSetup { languageHandler: LanguageHandlers; yamlSettings: SettingsState; telemetry: TestTelemetry; + schemaProvider: TestCustomSchemaProvider; } export function setupLanguageService(languageSettings: LanguageSettings): TestLanguageServerSetup { @@ -63,6 +65,11 @@ export function setupLanguageService(languageSettings: LanguageSettings): TestLa process.argv.push('--node-ipc'); const connection = createConnection(); const schemaRequestHandlerWrapper = (connection: Connection, uri: string): Promise => { + const testSchemaProvider = TestCustomSchemaProvider.instance(); + const testSchema = testSchemaProvider.getContentForSchema(uri); + if (testSchema) { + return Promise.resolve(testSchema); + } return schemaRequestHandler( connection, uri, @@ -85,12 +92,15 @@ export function setupLanguageService(languageSettings: LanguageSettings): TestLa const validationHandler = serverInit.validationHandler; const languageHandler = serverInit.languageHandler; languageService.configure(languageSettings); + const schemaProvider = TestCustomSchemaProvider.instance(); + languageService.registerCustomSchemaProvider(schemaItSelfCustomSchemaProvider); return { languageService, validationHandler, languageHandler, yamlSettings, telemetry, + schemaProvider, }; } @@ -114,3 +124,103 @@ export function caretPosition(content: string): { position: number; content: str // console.log(`now: len: ${content.length}, content: "${content}", pos: ${position}, str: "${content.substring(position)}"`); return { position, content }; } + +/* + * A class that provides custom schemas for testing purposes. + */ +export class TestCustomSchemaProvider { + private schemas: Array<[string, string, JSONSchema]> = new Array(0); + private static self: TestCustomSchemaProvider; + + private constructor() { + // use instance only + } + + public static instance(): TestCustomSchemaProvider { + if (!TestCustomSchemaProvider.self) { + TestCustomSchemaProvider.self = new TestCustomSchemaProvider(); + } + return TestCustomSchemaProvider.self; + } + + /** + * Adds a schema to the list of custom schemas. + * @param doc The uri of the document + * @param schema The JSON schema object. + */ + public addSchema(doc: string, schema: JSONSchema): void { + this.addSchemaWithUri(doc, `file:///${doc}`, schema); + } + + /** + * Adds a schema to the list of custom schemas. + * @param doc The uri of the document + * @param uri The uri of the schema + * @param schema The JSON schema object. + */ + public addSchemaWithUri(doc: string, uri: string, schema: JSONSchema): void { + const item: [string, string, JSONSchema] = [doc, uri, schema]; + this.schemas.push(item); + } + + /** + * Deletes a schema from the list of custom schemas. + * @param doc The uri of the document + */ + public deleteSchema(doc: string): void { + const items = this.schemas.filter((item) => item[0] === doc); + if (items.length > 0) { + this.schemas = this.schemas.filter((item) => item[0] !== doc); + } + } + + /** + * Checks if a schema exists for a given document. + * @param doc The uri of the document + * @returns True if a schema exists for the document, false otherwise. + */ + public has(doc: string): boolean { + const item = this.schemas.findIndex((item) => item[0] === doc); + return item > -1; + } + + /** + * Returns the schemas for a given document + * @param doc The uri of the document. + * @returns The uris of the schemas + * @throws Error if no schema found + */ + public getSchemas(doc: string): string | string[] { + if (this.has(doc)) { + const items = this.schemas.filter((item) => item[0] === doc); + if (items.length === 1) { + return items[0][1]; + } + return items.map((item) => { + return item[1]; + }); + } + throw new Error(`Test schema not found for ${doc}`); + } + + /** + * Returns the content of a schema for a given uri. + * @param uri The uri of the schema. + * @returns The content of the schema as a string, or null if the schema is not found. + */ + public getContentForSchema(uri: string): string | null { + const item = this.schemas.findIndex((item) => item[1] === uri); + if (item < 0) { + return null; + } + return JSON.stringify(this.schemas[item][2]); + } +} + +export async function schemaItSelfCustomSchemaProvider(uri: string): Promise { + const schemaProvider = TestCustomSchemaProvider.instance(); + if (schemaProvider.has(uri)) { + return schemaProvider.getSchemas(uri); + } + return undefined; +}