"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Red Hat. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
const serviceSetup_1 = require("./utils/serviceSetup");
const testHelper_1 = require("./utils/testHelper");
const assert_1 = __importDefault(require("assert"));
const vscode_languageserver_types_1 = require("vscode-languageserver-types");
const yamlSettings_1 = require("../src/yamlSettings");
const chai_1 = require("chai");
describe('Hover Tests', () => {
    let languageSettingsSetup;
    let languageHandler;
    let yamlSettings;
    let telemetry;
    let schemaProvider;
    before(() => {
        languageSettingsSetup = new serviceSetup_1.ServiceSetup().withHover().withSchemaFileMatch({
            uri: 'http://google.com',
            fileMatch: ['bad-schema.yaml'],
        });
        const { languageHandler: langHandler, yamlSettings: settings, telemetry: testTelemetry, schemaProvider: testSchemaProvider, } = (0, testHelper_1.setupLanguageService)(languageSettingsSetup.languageSettings);
        languageHandler = langHandler;
        yamlSettings = settings;
        telemetry = testTelemetry;
        schemaProvider = testSchemaProvider;
    });
    afterEach(() => {
        schemaProvider.deleteSchema(testHelper_1.SCHEMA_ID);
    });
    /**
     * Generates hover information for the given document and caret (cursor) position.
     * @param content The content of the document.
     * @param position The position of the caret in the document.
     * Alternatively, `position` can be omitted if the caret is located in the content using `|` bookends.
     * For example, `content = 'ab|c|d'` places the caret over the `'c'`, at `position = 2`
     * @returns An instance of `Hover`.
     */
    function parseSetup(content, position) {
        if (typeof position === 'undefined') {
            ({ content, position } = (0, testHelper_1.caretPosition)(content));
        }
        const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(content);
        yamlSettings.documents = new yamlSettings_1.TextDocumentTestManager();
        yamlSettings.documents.set(testTextDocument);
        return languageHandler.hoverHandler({
            position: testTextDocument.positionAt(position),
            textDocument: testTextDocument,
        });
    }
    describe('Hover', function () {
        it('Hover on key on root', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    cwd: {
                        type: 'string',
                        description: 'The directory from which bower should run. All relative paths will be calculated according to this setting.',
                    },
                },
            });
            const content = 'c|w|d: test'; // len: 9, pos: 1
            const hover = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value, `The directory from which bower should run. All relative paths will be calculated according to this setting.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover on value on root', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    cwd: {
                        type: 'string',
                        description: 'The directory from which bower should run. All relative paths will be calculated according to this setting.',
                    },
                },
            });
            const content = 'cwd: t|e|st'; // len: 9, pos: 6
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `The directory from which bower should run. All relative paths will be calculated according to this setting.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover on key with depth', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    scripts: {
                        type: 'object',
                        properties: {
                            postinstall: {
                                type: 'string',
                                description: 'A script to run after install',
                            },
                        },
                    },
                },
            });
            const content = 'scripts:\n  post|i|nstall: test'; // len: 28, pos: 15
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `A script to run after install\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover on value with depth', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    scripts: {
                        type: 'object',
                        properties: {
                            postinstall: {
                                type: 'string',
                                description: 'A script to run after install',
                            },
                        },
                    },
                },
            });
            const content = 'scripts:\n  postinstall: te|s|t'; // len: 28, pos: 26
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `A script to run after install\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover works on both root node and child nodes works', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    scripts: {
                        type: 'object',
                        properties: {
                            postinstall: {
                                type: 'string',
                                description: 'A script to run after install',
                            },
                        },
                        description: 'Contains custom hooks used to trigger other automated tools',
                    },
                },
            });
            const content1 = 'scr|i|pts:\n  postinstall: test'; // len: 28, pos: 3
            const firstHover = await parseSetup(content1);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(firstHover.contents), true);
            assert_1.default.strictEqual(firstHover.contents.kind, 'markdown');
            assert_1.default.strictEqual(firstHover.contents.value, `Contains custom hooks used to trigger other automated tools\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            const content2 = 'scripts:\n  post|i|nstall: test'; // len: 28, pos: 15
            const secondHover = await parseSetup(content2);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(secondHover.contents), true);
            assert_1.default.strictEqual(secondHover.contents.value, `A script to run after install\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover does not show results when there isnt description field', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    analytics: {
                        type: 'boolean',
                    },
                },
            });
            const content = 'ana|l|ytics: true'; // len: 15, pos: 3
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, '');
        });
        it('Hover on first document in multi document', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    analytics: {
                        type: 'boolean',
                    },
                },
            });
            const content = '---\nanalytics: true\n...\n---\njson: test\n...';
            const result = await parseSetup(content, 10);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, '');
        });
        it('Hover on second document in multi document', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    analytics: {
                        type: 'boolean',
                    },
                    json: {
                        type: 'string',
                        description: 'A file path to the configuration file',
                    },
                },
            });
            const content = '---\nanalytics: true\n...\n---\njs|o|n: test\n...'; // len: 42, pos: 30
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `A file path to the configuration file\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover should not return anything on key', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {},
            });
            const content = 'm|y|_unknown_hover: test'; // len: 22, pos: 1
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, '');
        });
        it('Hover should not return anything on value', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {},
            });
            const content = 'my_unknown_hover: tes|t|'; // len: 22, pos: 21
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, '');
        });
        it('Hover works on array nodes', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    authors: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                name: {
                                    type: 'string',
                                    description: 'Full name of the author.',
                                },
                            },
                        },
                    },
                },
            });
            const content = 'authors:\n  - n|a|me: Josh'; // len: 23, pos: 14
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `Full name of the author.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover works on additional array nodes', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    authors: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                name: {
                                    type: 'string',
                                    description: 'Full name of the author.',
                                },
                                email: {
                                    type: 'string',
                                    description: 'Email address of the author.',
                                },
                            },
                        },
                    },
                },
            });
            const content = 'authors:\n  - name: Josh\n  - |e|mail: jp'; // len: 37, pos: 28
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `Email address of the author.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover works on oneOf reference array nodes', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                definitions: {
                    stringoptions: {
                        $id: '#/definitions/stringoptions',
                        type: 'array',
                        additionalItems: false,
                        uniqueItems: true,
                        minItems: 1,
                        items: {
                            oneOf: [
                                {
                                    type: 'string',
                                },
                            ],
                        },
                    },
                },
                properties: {
                    ignition: {
                        type: 'object',
                        properties: {
                            proxy: {
                                type: 'object',
                                properties: {
                                    no_proxy: {
                                        $ref: '#/definitions/stringoptions',
                                        title: 'no_proxy (list of strings):',
                                        description: 'Specifies a list of strings to hosts that should be excluded from proxying. Each value is represented by an IP address prefix (1.2.3.4), an IP address prefix in CIDR notation (1.2.3.4/8), a domain name, or a special DNS label (*). An IP address prefix and domain name can also include a literal port number (1.2.3.4:80). A domain name matches that name and all subdomains. A domain name with a leading . matches subdomains only. For example foo.com matches foo.com and bar.foo.com; .y.com matches x.y.com but not y.com. A single asterisk (*) indicates that no proxying should be done.',
                                    },
                                },
                            },
                        },
                    },
                    storage: {
                        type: 'object',
                        properties: {
                            raid: {
                                type: 'array',
                                items: {
                                    oneOf: [
                                        {
                                            properties: {
                                                name: {
                                                    type: 'string',
                                                    title: 'name (string):',
                                                    description: 'The name to use for the resulting md device.',
                                                },
                                                devices: {
                                                    $ref: '#/definitions/stringoptions',
                                                    title: 'devices (list of strings):',
                                                    description: 'The list of devices (referenced by their absolute path) in the array.',
                                                },
                                                options: {
                                                    $ref: '#/definitions/stringoptions',
                                                    title: 'options (list of strings):',
                                                    description: 'Any additional options to be passed to mdadm.',
                                                },
                                            },
                                        },
                                    ],
                                },
                            },
                        },
                    },
                },
            });
            const content1 = `ignition:
  proxy:
    no_proxy:
      - 10|.|10.10.10
      - service.local
storage:
  raid:
    - name: Raid
      devices:
        - /dev/disk/by-id/ata-WDC_WD10SPZX-80Z10T2_WD-WX41A49H9FT4
        - /dev/disk/by-id/ata-WDC_WD10SPZX-80Z10T2_WD-WXL1A49KPYFD`; // len: 257, pos: 43
            let result = await parseSetup(content1);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### no\\_proxy (list of strings):\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            const content2 = `ignition:
  proxy:
    no_proxy:
      - 10.10.10.10
      - service.local
storage:
  raid:
    - name: Raid
      devices:
        - /dev/disk/by-id/ata-WDC_WD|1|0SPZX-80Z10T2_WD-WX41A49H9FT4
        - /dev/disk/by-id/ata-WDC_WD10SPZX-80Z10T2_WD-WXL1A49KPYFD`; // len: 257, pos: 160
            result = await parseSetup(content2);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### devices (list of strings):\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover on refs node', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                additionalProperties: false,
                properties: {
                    title: {
                        type: 'string',
                        description: 'Title of this file',
                    },
                    refs: {
                        type: 'object',
                    },
                    users: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                name: {
                                    type: 'string',
                                    description: 'Name of the user',
                                },
                                place: {
                                    type: 'string',
                                    description: 'Place of residence',
                                },
                            },
                        },
                    },
                },
            });
            const content = `title: meetup
refs:
  place: &default_place NYC
users:
  - name: foo
    place: SFC
  - name: bar
    |p|lace: *default_place`;
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `Place of residence\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover on null property', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    childObject: {
                        type: 'object',
                        description: 'should return this description',
                    },
                },
            });
            const content = 'c|h|ildObject: \n'; // len: 14, pos: 1
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `should return this description\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover handles inline pattern modifiers', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    description: {
                        type: 'string',
                        description: 'Field with dotall pattern.',
                        pattern: '(?s).*',
                    },
                    multilineAndDotall: {
                        type: 'string',
                        description: 'Field with multiline and dotall pattern.',
                        pattern: '(?ms)^start.*end$',
                    },
                },
            });
            let result = await parseSetup('description: a|n|y text');
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `Field with dotall pattern.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            result = await parseSetup('multilineAndDotall: start middle c|o|ntent end');
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `Field with multiline and dotall pattern.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
        });
        it('Hover handles unsupported pattern', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    unsupportedPattern: {
                        type: 'string',
                        description: 'Field with unsupported pattern.',
                        pattern: '(?x)text .*',
                    },
                },
            });
            const result = await parseSetup('unsupportedPattern: text c|o|ntent');
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `Field with unsupported pattern.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
        });
        it('hover on value and its description has multiline, indentation and special string', async () => {
            (() => {
                languageSettingsSetup = new serviceSetup_1.ServiceSetup()
                    .withHover()
                    .withIndentation('  ')
                    .withSchemaFileMatch({
                    uri: 'http://google.com',
                    fileMatch: ['bad-schema.yaml'],
                });
                const { languageHandler: langHandler, yamlSettings: settings, telemetry: testTelemetry, schemaProvider: testSchemaProvider, } = (0, testHelper_1.setupLanguageService)(languageSettingsSetup.languageSettings);
                languageHandler = langHandler;
                yamlSettings = settings;
                telemetry = testTelemetry;
                schemaProvider = testSchemaProvider;
            })();
            //https://github.com/redhat-developer/vscode-yaml/issues/886
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                title: 'Person',
                properties: {
                    firstName: {
                        type: 'string',
                        description: 'At the top level my_var is shown properly.\n\n    Issue with my_var2\n      here my_var3',
                    },
                },
            });
            const content = 'fi|r|stName: '; // len: 12, pos: 1
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### Person\n\nAt the top level my\\_var is shown properly.\n\n&emsp;&emsp;Issue with my\\_var2\n\n&emsp;&emsp;&emsp;here my\\_var3\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover displays enum descriptions if present', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    animal: {
                        type: 'string',
                        description: 'should return this description',
                        enum: ['cat', 'dog', 'non'],
                        enumDescriptions: ['', 'Canis familiaris'],
                    },
                },
            });
            const content = 'animal:\n  ca|t|'; // len: 13, pos: 12
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `should return this description

Allowed Values:

* \`cat\`
* \`dog\`: Canis familiaris
* \`non\`

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover displays unique enum values', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    animal: {
                        description: 'should return this description',
                        anyOf: [
                            {
                                enum: ['cat', 'dog', 'non'],
                                enumDescriptions: ['', 'Canis familiaris'],
                            },
                            {
                                enum: ['bird', 'fish', 'non'], // the second "non" from this enum should be filtered out
                                enumDescriptions: ['', 'Special fish'],
                            },
                        ],
                    },
                },
            });
            const content = 'animal:\n  no|n|'; // len: 13, pos: 12
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `should return this description

Allowed Values:

* \`non\`
* \`cat\`
* \`dog\`: Canis familiaris
* \`bird\`
* \`fish\`: Special fish

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover displays unique enum values with prroper description (1st case)', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    animal: {
                        description: 'should return this description',
                        anyOf: [
                            {
                                enum: ['cat', 'dog', 'fish'],
                                enumDescriptions: ['1st cat', '1st dog', '1st fish'], // should use this description for "fish"
                            },
                            {
                                enum: ['bird', 'fish', 'ant'],
                            },
                        ],
                    },
                },
            });
            const content = 'animal:\n  fis|n|'; // len: 13, pos: 12
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `should return this description

Allowed Values:

* \`ant\`
* \`cat\`: 1st cat
* \`dog\`: 1st dog
* \`fish\`: 1st fish
* \`bird\`

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover displays unique enum values with prroper description (2nd case)', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    animal: {
                        description: 'should return this description',
                        anyOf: [
                            {
                                enum: ['cat', 'dog', 'fish'],
                            },
                            {
                                enum: ['bird', 'fish', 'ant'],
                                enumDescriptions: ['2nd bird', '2nd fish', '2nd ant'], // should use this description for "fish"
                            },
                        ],
                    },
                },
            });
            const content = 'animal:\n  fis|n|'; // len: 13, pos: 12
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `should return this description

Allowed Values:

* \`ant\`: 2nd ant
* \`cat\`
* \`dog\`
* \`fish\`: 2nd fish
* \`bird\`: 2nd bird

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover displays unique enum values with prroper description (3rd case)', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    animal: {
                        description: 'should return this description',
                        anyOf: [
                            {
                                enum: ['cat', 'dog', 'fish'],
                                enumDescriptions: ['1st cat', '1st dog', '1st fish'], // should use this description for "fish"
                            },
                            {
                                enum: ['bird', 'fish', 'ant'],
                                enumDescriptions: ['2nd bird', '2nd fish', '2nd ant'],
                            },
                        ],
                    },
                },
            });
            const content = 'animal:\n  fis|n|'; // len: 13, pos: 12
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `should return this description

Allowed Values:

* \`ant\`: 2nd ant
* \`cat\`: 1st cat
* \`dog\`: 1st dog
* \`fish\`: 1st fish
* \`bird\`: 2nd bird

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover displays escaped quote strings correctly in enum', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    value: {
                        type: 'string',
                        description: 'Test enum with special quote strings',
                        enum: ['', '""', "''"],
                    },
                },
            });
            const content = 'value: |\n|'; // len: 8, pos: 7
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `Test enum with special quote strings

Allowed Values:

* \`"''"\`
* \`""\`
* \`"\\"\\""\`

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover works on examples', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    animal: {
                        type: 'string',
                        description: 'should return this description',
                        enum: ['cat', 'dog'],
                        examples: [
                            'cat',
                            {
                                animal: {
                                    type: 'dog',
                                },
                            },
                        ],
                    },
                },
            });
            const content = 'animal:\n  ca|t|'; // len: 13, pos: 12
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.kind, 'markdown');
            assert_1.default.strictEqual(result.contents.value, `should return this description

Allowed Values:

* \`cat\`
* \`dog\`

Example:

\`\`\`yaml
cat
\`\`\`

Example:

\`\`\`yaml
animal:
  type: dog
\`\`\`

Source: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover on property next value on null', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    childObject: {
                        type: 'object',
                        description: 'childObject description',
                        properties: {
                            prop: {
                                type: 'string',
                                description: 'should return this description',
                            },
                        },
                    },
                },
            });
            const content = 'childObject:\r\n  |p|rop:\r\n  '; // len: 25, pos: 16
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `should return this description\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('should work with bad schema', async () => {
            const doc = (0, testHelper_1.setupSchemaIDTextDocument)('foo:\n bar', 'bad-schema.yaml');
            yamlSettings.documents = new yamlSettings_1.TextDocumentTestManager();
            yamlSettings.documents.set(doc);
            const result = await languageHandler.hoverHandler({
                position: vscode_languageserver_types_1.Position.create(0, 1),
                textDocument: doc,
            });
            (0, chai_1.expect)(result).to.be.null;
        });
        it('Hover preserves literal parentheses', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    parentheses: {
                        type: 'string',
                        description: 'Parentheses should be literal: (abc)(1).',
                    },
                },
            });
            const content = 'parenth|e|ses: x';
            const hover = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value, `Parentheses should be literal: (abc)(1).\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover preserves literal dots', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    dotInText: {
                        type: 'string',
                        description: 'Dots should be literal in normal text: v1.2.3, 3.14159, example.com.',
                    },
                },
            });
            const content = 'dot|I|nText: x';
            const hover = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value, `Dots should be literal in normal text: v1.2.3, 3.14159, example.com.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover preserves bare URL in description (no escaping)', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    repo: {
                        type: 'string',
                        description: 'The YAML Language Server at https://github.com/redhat-developer/yaml-language-server',
                    },
                },
            });
            const content = 'rep|o|: x';
            const hover = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value, `The YAML Language Server at https://github.com/redhat-developer/yaml-language-server\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover preserves URL wrapped in parentheses in description (no escaping)', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    repo: {
                        type: 'string',
                        description: 'Yaml Language Server (https://github.com/redhat-developer/yaml-language-server)',
                    },
                },
            });
            const content = 'rep|o|: x';
            const hover = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value, `Yaml Language Server (https://github.com/redhat-developer/yaml-language-server)\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
        it('Hover prefers markdownDescription for $ref siblings', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'http://json-schema.org/draft-07/schema#',
                type: 'object',
                properties: {
                    foo: {
                        type: 'string',
                        title: 'foo title',
                        description: 'foo desc',
                        markdownDescription: 'foo md desc **bold** \n * line \n* another \n\n',
                    },
                    bar: {
                        $ref: '#/$defs/veggie',
                        title: 'bar title',
                        description: 'bar desc',
                        markdownDescription: 'bar md desc **bold** \n * line \n* another \n\n',
                    },
                },
                $defs: {
                    veggie: {
                        type: 'string',
                        enum: ['potato', 'carrot'],
                    },
                },
            });
            const hover = await parseSetup('b|a|r: potato');
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.ok(hover.contents.value.includes('bar md desc **bold**'));
            assert_1.default.ok(hover.contents.value.includes('* another'));
            assert_1.default.ok(!hover.contents.value.includes('bar desc'));
        });
    });
    describe('Hover on anyOf', () => {
        it('should show all matched schemas in anyOf', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                title: 'The Root',
                description: 'Root Object',
                type: 'object',
                properties: {
                    child: {
                        title: 'Child',
                        anyOf: [
                            {
                                $ref: '#/definitions/FirstChoice',
                            },
                            {
                                $ref: '#/definitions/SecondChoice',
                            },
                        ],
                    },
                },
                required: ['child'],
                additionalProperties: false,
                definitions: {
                    FirstChoice: {
                        title: 'FirstChoice',
                        description: 'The first choice',
                        type: 'object',
                        properties: {
                            choice: {
                                title: 'Choice',
                                default: 'first',
                                enum: ['first'],
                                type: 'string',
                            },
                            property_a: {
                                title: 'Property A',
                                type: 'string',
                            },
                        },
                        required: ['property_a'],
                    },
                    SecondChoice: {
                        title: 'SecondChoice',
                        description: 'The second choice',
                        type: 'object',
                        properties: {
                            choice: {
                                title: 'Choice',
                                default: 'second',
                                enum: ['second'],
                                type: 'string',
                            },
                            property_b: {
                                title: 'Property B',
                                type: 'string',
                            },
                        },
                        required: ['property_b'],
                    },
                },
            });
            let content = 'ch|i|ld:';
            let result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### FirstChoice || SecondChoice\n\nThe first choice || The second choice\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
            //use case 1:
            content = 'ch|i|ld: \n  property_a: test';
            result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### FirstChoice\n\nThe first choice\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
            //use case 2:
            content = 'ch|i|ld: \n  property_b: test';
            result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### SecondChoice\n\nThe second choice\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
        });
        it('should show the parent description in anyOf (no child descriptions)', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                title: 'The Root',
                description: 'Root Object',
                type: 'object',
                properties: {
                    optionalZipFile: {
                        title: 'ZIP file',
                        anyOf: [{ type: 'string', pattern: '\\.zip$' }, { type: 'null' }],
                        default: null,
                        description: 'Optional ZIP file path.',
                    },
                },
                required: ['optionalZipFile'],
                additionalProperties: false,
            });
            const content = 'optionalZipF|i|le:';
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### ZIP file || ZIP file\n\nOptional ZIP file path.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
        });
        it('should concat parent and child descriptions in anyOf', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                title: 'The Root',
                description: 'Root Object',
                type: 'object',
                properties: {
                    child: {
                        title: 'Child',
                        anyOf: [
                            {
                                $ref: '#/definitions/FirstChoice',
                            },
                            {
                                $ref: '#/definitions/SecondChoice',
                            },
                        ],
                        description: 'The parent description.',
                    },
                },
                required: ['child'],
                additionalProperties: false,
                definitions: {
                    FirstChoice: {
                        title: 'FirstChoice',
                        description: 'The first choice',
                        type: 'object',
                        properties: {
                            choice: {
                                title: 'Choice',
                                default: 'first',
                                enum: ['first'],
                                type: 'string',
                            },
                            property_a: {
                                title: 'Property A',
                                type: 'string',
                            },
                        },
                        required: ['property_a'],
                    },
                    SecondChoice: {
                        title: 'SecondChoice',
                        description: 'The second choice',
                        type: 'object',
                        properties: {
                            choice: {
                                title: 'Choice',
                                default: 'second',
                                enum: ['second'],
                                type: 'string',
                            },
                            property_b: {
                                title: 'Property B',
                                type: 'string',
                            },
                        },
                        required: ['property_b'],
                    },
                },
            });
            const content = 'ch|i|ld:';
            const result = await parseSetup(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.strictEqual(result.contents.value, `#### FirstChoice || SecondChoice\n\nThe parent description.\nThe first choice || The second choice\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
        });
    });
    describe('Bug fixes', () => {
        it('should convert binary data correctly', async () => {
            const content = 'foo: [ !!binary R0lG|O|DlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmleECcgggoBADs= ]\n'; // len: 107, pos: 20
            const result = await parseSetup(content);
            (0, chai_1.expect)(telemetry.messages).to.be.empty;
            (0, chai_1.expect)(result).to.be.null;
        });
    });
    describe('YAML 1.1 boolean hover', () => {
        let yaml11LanguageHandler;
        let yaml11Settings;
        let yaml11SchemaProvider;
        before(() => {
            const yaml11Setup = new serviceSetup_1.ServiceSetup().withHover().withYamlVersion('1.1');
            const { languageHandler: langHandler, yamlSettings: settings, schemaProvider: testSchemaProvider, } = (0, testHelper_1.setupLanguageService)(yaml11Setup.languageSettings);
            yaml11LanguageHandler = langHandler;
            yaml11Settings = settings;
            yaml11SchemaProvider = testSchemaProvider;
        });
        afterEach(() => {
            yaml11SchemaProvider.deleteSchema(testHelper_1.SCHEMA_ID);
        });
        function parseSetupYaml11(content, position) {
            if (typeof position === 'undefined') {
                ({ content, position } = (0, testHelper_1.caretPosition)(content));
            }
            const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(content);
            yaml11Settings.documents = new yamlSettings_1.TextDocumentTestManager();
            yaml11Settings.documents.set(testTextDocument);
            return yaml11LanguageHandler.hoverHandler({
                position: testTextDocument.positionAt(position),
                textDocument: testTextDocument,
            });
        }
        it('Hover on YAML 1.1 boolean value "True" with enum schema', async () => {
            yaml11SchemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    enabled: {
                        type: 'boolean',
                        description: 'Enable or disable the feature',
                        enum: [true, false],
                    },
                },
            });
            const content = 'enabled: |T|rue';
            const result = await parseSetupYaml11(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.notStrictEqual(result.contents.value, '');
            (0, chai_1.expect)(result.contents.value).to.include('Enable or disable the feature');
        });
        it('Hover on YAML 1.1 boolean value "False" with enum schema', async () => {
            yaml11SchemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    enabled: {
                        type: 'boolean',
                        description: 'Enable or disable the feature',
                        enum: [true, false],
                    },
                },
            });
            const content = 'enabled: |F|alse';
            const result = await parseSetupYaml11(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.notStrictEqual(result.contents.value, '');
            (0, chai_1.expect)(result.contents.value).to.include('Enable or disable the feature');
        });
        it('Hover on YAML 1.1 boolean value "yes" with const schema', async () => {
            yaml11SchemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    confirmed: {
                        type: 'boolean',
                        description: 'Confirmation flag',
                        const: true,
                    },
                },
            });
            const content = 'confirmed: |y|es';
            const result = await parseSetupYaml11(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.notStrictEqual(result.contents.value, '');
            (0, chai_1.expect)(result.contents.value).to.include('Confirmation flag');
        });
        it('Hover on YAML 1.1 boolean value "no" with const schema', async () => {
            yaml11SchemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    disabled: {
                        type: 'boolean',
                        description: 'Disabled flag',
                        const: false,
                    },
                },
            });
            const content = 'disabled: |n|o';
            const result = await parseSetupYaml11(content);
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(result.contents), true);
            assert_1.default.notStrictEqual(result.contents.value, '');
            (0, chai_1.expect)(result.contents.value).to.include('Disabled flag');
        });
    });
    describe('hoverSchemaSource configuration', () => {
        it('Hover should not show schema source when hoverSchemaSource is false', async () => {
            const languageSettingsSetupWithoutSource = new serviceSetup_1.ServiceSetup()
                .withHover()
                .withhoverSchemaSource(false)
                .withSchemaFileMatch({
                uri: testHelper_1.SCHEMA_ID,
                fileMatch: ['*.yaml'],
            });
            const { languageHandler: langHandler, yamlSettings: settings, schemaProvider: testSchemaProvider, } = (0, testHelper_1.setupLanguageService)(languageSettingsSetupWithoutSource.languageSettings);
            testSchemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    cwd: {
                        type: 'string',
                        description: 'The directory from which bower should run.',
                    },
                },
            });
            const content = 'c|w|d: test';
            const { content: parsedContent, position } = (0, testHelper_1.caretPosition)(content);
            const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(parsedContent);
            settings.documents = new yamlSettings_1.TextDocumentTestManager();
            settings.documents.set(testTextDocument);
            const hover = await langHandler.hoverHandler({
                position: testTextDocument.positionAt(position),
                textDocument: testTextDocument,
            });
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value, 'The directory from which bower should run.');
            assert_1.default.strictEqual(hover.contents.value.includes('Source:'), false);
            testSchemaProvider.deleteSchema(testHelper_1.SCHEMA_ID);
        });
        it('Hover should show schema source by default', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    cwd: {
                        type: 'string',
                        description: 'The directory from which bower should run.',
                    },
                },
            });
            const content = 'c|w|d: test';
            const { content: parsedContent, position } = (0, testHelper_1.caretPosition)(content);
            const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(parsedContent);
            yamlSettings.documents = new yamlSettings_1.TextDocumentTestManager();
            yamlSettings.documents.set(testTextDocument);
            const hover = await languageHandler.hoverHandler({
                position: testTextDocument.positionAt(position),
                textDocument: testTextDocument,
            });
            assert_1.default.strictEqual(vscode_languageserver_types_1.MarkupContent.is(hover.contents), true);
            assert_1.default.strictEqual(hover.contents.kind, 'markdown');
            assert_1.default.strictEqual(hover.contents.value.includes('Source:'), true);
            assert_1.default.strictEqual(hover.contents.value, `The directory from which bower should run.\n\nSource: [${testHelper_1.SCHEMA_ID}](file:///${testHelper_1.SCHEMA_ID})`);
        });
    });
});
//# sourceMappingURL=hover.test.js.map