mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -42,8 +42,6 @@ function select(builder: Builder, selector: string, offdom?: boolean): MultiBuil
|
||||
}
|
||||
|
||||
suite('Builder', () => {
|
||||
|
||||
test('Binding', function () {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -11,4 +11,32 @@ const $ = dom.$;
|
||||
suite('dom', () => {
|
||||
test('hasClass', () => {
|
||||
});
|
||||
|
||||
suite('$', () => {
|
||||
test('should build simple nodes', () => {
|
||||
const div = $('div');
|
||||
assert(div);
|
||||
assert(div instanceof HTMLElement);
|
||||
assert.equal(div.tagName, 'DIV');
|
||||
assert(!div.firstChild);
|
||||
});
|
||||
|
||||
test('should build nodes with attributes', () => {
|
||||
let div = $('div', { class: 'test' });
|
||||
assert.equal(div.className, 'test');
|
||||
|
||||
div = $('div', null);
|
||||
assert.equal(div.className, '');
|
||||
});
|
||||
|
||||
test('should build nodes with children', () => {
|
||||
let div = $('div', null, $('span', { id: 'demospan' }));
|
||||
let firstChild = div.firstChild as HTMLElement;
|
||||
assert.equal(firstChild.tagName, 'SPAN');
|
||||
assert.equal(firstChild.id, 'demospan');
|
||||
|
||||
div = $('div', null, 'hello');
|
||||
assert.equal(div.firstChild.textContent, 'hello');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,9 +52,12 @@ suite('HtmlContent', () => {
|
||||
test('action', () => {
|
||||
var callbackCalled = false;
|
||||
var result: HTMLElement = renderFormattedText('[[action]]', {
|
||||
actionCallback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
actionHandler: {
|
||||
callback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
},
|
||||
disposeables: []
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.innerHTML, '<a href="#">action</a>');
|
||||
@@ -68,9 +71,12 @@ suite('HtmlContent', () => {
|
||||
test('fancy action', () => {
|
||||
var callbackCalled = false;
|
||||
var result: HTMLElement = renderFormattedText('__**[[action]]**__', {
|
||||
actionCallback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
actionHandler: {
|
||||
callback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
},
|
||||
disposeables: []
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.innerHTML, '<i><b><a href="#">action</a></b></i>');
|
||||
|
||||
@@ -63,232 +63,6 @@ function getSashes(splitview: SplitView): Sash[] {
|
||||
}
|
||||
|
||||
suite('Splitview', () => {
|
||||
let container: HTMLElement;
|
||||
|
||||
setup(() => {
|
||||
container = document.createElement('div');
|
||||
container.style.position = 'absolute';
|
||||
container.style.width = `${200}px`;
|
||||
container.style.height = `${200}px`;
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
container = null;
|
||||
});
|
||||
|
||||
test('empty splitview has empty DOM', () => {
|
||||
});
|
||||
|
||||
test('calls view methods on addView and removeView', () => {
|
||||
const view = new TestView(20, 20);
|
||||
const splitview = new SplitView(container);
|
||||
|
||||
let didLayout = false;
|
||||
const layoutDisposable = view.onDidLayout(() => didLayout = true);
|
||||
|
||||
let didRender = false;
|
||||
const renderDisposable = view.onDidRender(() => didRender = true);
|
||||
|
||||
splitview.addView(view, 20);
|
||||
|
||||
assert.equal(view.size, 20, 'view has right size');
|
||||
assert(didLayout, 'layout is called');
|
||||
assert(didLayout, 'render is called');
|
||||
|
||||
splitview.dispose();
|
||||
layoutDisposable.dispose();
|
||||
renderDisposable.dispose();
|
||||
view.dispose();
|
||||
});
|
||||
|
||||
test('stretches view to viewport', () => {
|
||||
const view = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view, 20);
|
||||
assert.equal(view.size, 200, 'view is stretched');
|
||||
|
||||
splitview.layout(200);
|
||||
assert.equal(view.size, 200, 'view stayed the same');
|
||||
|
||||
splitview.layout(100);
|
||||
assert.equal(view.size, 100, 'view is collapsed');
|
||||
|
||||
splitview.layout(20);
|
||||
assert.equal(view.size, 20, 'view is collapsed');
|
||||
|
||||
splitview.layout(10);
|
||||
assert.equal(view.size, 20, 'view is clamped');
|
||||
|
||||
splitview.layout(200);
|
||||
assert.equal(view.size, 200, 'view is stretched');
|
||||
|
||||
splitview.dispose();
|
||||
view.dispose();
|
||||
});
|
||||
|
||||
test('can resize views', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, 20);
|
||||
splitview.addView(view2, 20);
|
||||
splitview.addView(view3, 20);
|
||||
|
||||
assert.equal(view1.size, 160, 'view1 is stretched');
|
||||
assert.equal(view2.size, 20, 'view2 size is 20');
|
||||
assert.equal(view3.size, 20, 'view3 size is 20');
|
||||
|
||||
splitview.resizeView(1, 40);
|
||||
|
||||
assert.equal(view1.size, 140, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 40, 'view2 is stretched');
|
||||
assert.equal(view3.size, 20, 'view3 stays the same');
|
||||
|
||||
splitview.resizeView(0, 70);
|
||||
|
||||
assert.equal(view1.size, 70, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 110, 'view2 is expanded');
|
||||
assert.equal(view3.size, 20, 'view3 stays the same');
|
||||
|
||||
splitview.resizeView(2, 40);
|
||||
|
||||
assert.equal(view1.size, 70, 'view1 stays the same');
|
||||
assert.equal(view2.size, 90, 'view2 is collapsed');
|
||||
assert.equal(view3.size, 40, 'view3 is stretched');
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('reacts to view changes', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, 20);
|
||||
splitview.addView(view2, 20);
|
||||
splitview.addView(view3, 20);
|
||||
|
||||
assert.equal(view1.size, 160, 'view1 is stretched');
|
||||
assert.equal(view2.size, 20, 'view2 size is 20');
|
||||
assert.equal(view3.size, 20, 'view3 size is 20');
|
||||
|
||||
view1.maximumSize = 20;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 20, 'view2 stays the same');
|
||||
assert.equal(view3.size, 160, 'view3 is stretched');
|
||||
|
||||
view3.maximumSize = 40;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 stays the same');
|
||||
assert.equal(view2.size, 140, 'view2 is stretched');
|
||||
assert.equal(view3.size, 40, 'view3 is collapsed');
|
||||
|
||||
view2.maximumSize = 200;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 stays the same');
|
||||
assert.equal(view2.size, 140, 'view2 stays the same');
|
||||
assert.equal(view3.size, 40, 'view3 stays the same');
|
||||
|
||||
view3.maximumSize = Number.POSITIVE_INFINITY;
|
||||
view3.minimumSize = 100;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 80, 'view2 is collapsed');
|
||||
assert.equal(view3.size, 100, 'view3 is stretched');
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('sashes are properly enabled/disabled', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, 20);
|
||||
splitview.addView(view2, 20);
|
||||
splitview.addView(view3, 20);
|
||||
|
||||
let sashes = getSashes(splitview);
|
||||
assert.equal(sashes.length, 2, 'there are two sashes');
|
||||
assert.equal(sashes[0].enabled, true, 'first sash is enabled');
|
||||
assert.equal(sashes[1].enabled, true, 'second sash is enabled');
|
||||
|
||||
splitview.layout(60);
|
||||
assert.equal(sashes[0].enabled, false, 'first sash is disabled');
|
||||
assert.equal(sashes[1].enabled, false, 'second sash is disabled');
|
||||
|
||||
splitview.layout(20);
|
||||
assert.equal(sashes[0].enabled, false, 'first sash is disabled');
|
||||
assert.equal(sashes[1].enabled, false, 'second sash is disabled');
|
||||
|
||||
splitview.layout(200);
|
||||
assert.equal(sashes[0].enabled, true, 'first sash is enabled');
|
||||
assert.equal(sashes[1].enabled, true, 'second sash is enabled');
|
||||
|
||||
view1.maximumSize = 20;
|
||||
assert.equal(sashes[0].enabled, false, 'first sash is disabled');
|
||||
assert.equal(sashes[1].enabled, true, 'second sash is enabled');
|
||||
|
||||
view2.maximumSize = 20;
|
||||
assert.equal(sashes[0].enabled, false, 'first sash is disabled');
|
||||
assert.equal(sashes[1].enabled, false, 'second sash is disabled');
|
||||
|
||||
view1.maximumSize = 300;
|
||||
assert.equal(sashes[0].enabled, true, 'first sash is enabled');
|
||||
assert.equal(sashes[1].enabled, true, 'second sash is enabled');
|
||||
|
||||
view2.maximumSize = 200;
|
||||
assert.equal(sashes[0].enabled, true, 'first sash is enabled');
|
||||
assert.equal(sashes[1].enabled, true, 'second sash is enabled');
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('issue #35497', () => {
|
||||
const view1 = new TestView(160, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(66, 66);
|
||||
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(986);
|
||||
|
||||
splitview.addView(view1, 142, 0);
|
||||
assert.equal(view1.size, 986, 'first view is stretched');
|
||||
|
||||
view2.onDidRender(() => {
|
||||
assert.throws(() => splitview.resizeView(1, 922));
|
||||
assert.throws(() => splitview.resizeView(1, 922));
|
||||
});
|
||||
|
||||
splitview.addView(view2, 66, 0);
|
||||
assert.equal(view2.size, 66, 'second view is fixed');
|
||||
assert.equal(view1.size, 986 - 66, 'first view is collapsed');
|
||||
|
||||
const viewContainers = container.querySelectorAll('.split-view-view');
|
||||
assert.equal(viewContainers.length, 2, 'there are two view containers');
|
||||
assert.equal((viewContainers.item(0) as HTMLElement).style.height, '66px', 'second view container is 66px');
|
||||
assert.equal((viewContainers.item(1) as HTMLElement).style.height, `${986 - 66}px`, 'first view container is 66px');
|
||||
|
||||
splitview.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@
|
||||
import * as assert from 'assert';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import arrays = require('vs/base/common/arrays');
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
|
||||
suite('Arrays', () => {
|
||||
test('findFirst', function () {
|
||||
@@ -269,5 +270,41 @@ suite('Arrays', () => {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test('coalesce', function () {
|
||||
let a = coalesce([null, 1, null, 2, 3]);
|
||||
assert.equal(a.length, 3);
|
||||
assert.equal(a[0], 1);
|
||||
assert.equal(a[1], 2);
|
||||
assert.equal(a[2], 3);
|
||||
|
||||
coalesce([null, 1, null, void 0, undefined, 2, 3]);
|
||||
assert.equal(a.length, 3);
|
||||
assert.equal(a[0], 1);
|
||||
assert.equal(a[1], 2);
|
||||
assert.equal(a[2], 3);
|
||||
|
||||
let b = [];
|
||||
b[10] = 1;
|
||||
b[20] = 2;
|
||||
b[30] = 3;
|
||||
b = coalesce(b);
|
||||
assert.equal(b.length, 3);
|
||||
assert.equal(b[0], 1);
|
||||
assert.equal(b[1], 2);
|
||||
assert.equal(b[2], 3);
|
||||
|
||||
let sparse = [];
|
||||
sparse[0] = 1;
|
||||
sparse[1] = 1;
|
||||
sparse[17] = 1;
|
||||
sparse[1000] = 1;
|
||||
sparse[1001] = 1;
|
||||
|
||||
assert.equal(sparse.length, 1002);
|
||||
|
||||
sparse = coalesce(sparse);
|
||||
assert.equal(sparse.length, 5);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { LcsDiff, IDiffChange } from 'vs/base/common/diff/diff';
|
||||
import { LcsDiff2 } from 'vs/base/common/diff/diff2';
|
||||
|
||||
class StringDiffSequence {
|
||||
|
||||
@@ -116,11 +115,6 @@ suite('Diff', () => {
|
||||
this.timeout(10000);
|
||||
lcsTests(LcsDiff);
|
||||
});
|
||||
|
||||
test('LcsDiff2 - different strings tests', function () {
|
||||
this.timeout(10000);
|
||||
lcsTests(LcsDiff2);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Diff - Ported from VS', () => {
|
||||
|
||||
@@ -393,11 +393,11 @@ suite('Filters', () => {
|
||||
|
||||
// issue #17836
|
||||
// assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor');
|
||||
assertTopScore(fuzzyScore, 'p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p');
|
||||
assertTopScore(fuzzyScore, 'p', 4, 'parse', 'posix', 'pafdsa', 'path', 'p');
|
||||
assertTopScore(fuzzyScore, 'pa', 0, 'parse', 'pafdsa', 'path');
|
||||
|
||||
// issue #14583
|
||||
assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log');
|
||||
assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log', 'logger');
|
||||
assertTopScore(fuzzyScore, 'e', 2, 'AbstractWorker', 'ActiveXObject', 'else');
|
||||
|
||||
// issue #14446
|
||||
@@ -415,6 +415,8 @@ suite('Filters', () => {
|
||||
assertTopScore(fuzzyScore, 'is', 0, 'isValidViewletId', 'import statement');
|
||||
|
||||
assertTopScore(fuzzyScore, 'title', 1, 'files.trimTrailingWhitespace', 'window.title');
|
||||
|
||||
assertTopScore(fuzzyScore, 'const', 1, 'constructor', 'const', 'cuOnstrul');
|
||||
});
|
||||
|
||||
test('Unexpected suggestion scoring, #28791', function () {
|
||||
|
||||
@@ -83,11 +83,11 @@ suite('History Navigator', () => {
|
||||
});
|
||||
|
||||
test('adding existing element changes the position', function () {
|
||||
let testObject = new HistoryNavigator(['1', '2', '3', '4'], 2);
|
||||
let testObject = new HistoryNavigator(['1', '2', '3', '4'], 5);
|
||||
|
||||
testObject.add('2');
|
||||
|
||||
assert.deepEqual(['4', '2'], toArray(testObject));
|
||||
assert.deepEqual(['1', '3', '4', '2'], toArray(testObject));
|
||||
});
|
||||
|
||||
test('add resets the navigator to last', function () {
|
||||
|
||||
63
src/vs/base/test/common/octicon.test.ts
Normal file
63
src/vs/base/test/common/octicon.test.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon';
|
||||
|
||||
export interface IOcticonFilter {
|
||||
// Returns null if word doesn't match.
|
||||
(query: string, target: { text: string, octiconOffsets?: number[] }): IMatch[];
|
||||
}
|
||||
|
||||
function filterOk(filter: IOcticonFilter, word: string, target: { text: string, octiconOffsets?: number[] }, highlights?: { start: number; end: number; }[]) {
|
||||
let r = filter(word, target);
|
||||
assert(r);
|
||||
if (highlights) {
|
||||
assert.deepEqual(r, highlights);
|
||||
}
|
||||
}
|
||||
|
||||
suite('Octicon', () => {
|
||||
test('matchesFuzzzyOcticonAware', function () {
|
||||
|
||||
// Camel Case
|
||||
|
||||
filterOk(matchesFuzzyOcticonAware, 'ccr', parseOcticons('$(octicon)CamelCaseRocks$(octicon)'), [
|
||||
{ start: 10, end: 11 },
|
||||
{ start: 15, end: 16 },
|
||||
{ start: 19, end: 20 }
|
||||
]);
|
||||
|
||||
filterOk(matchesFuzzyOcticonAware, 'ccr', parseOcticons('$(octicon) CamelCaseRocks $(octicon)'), [
|
||||
{ start: 11, end: 12 },
|
||||
{ start: 16, end: 17 },
|
||||
{ start: 20, end: 21 }
|
||||
]);
|
||||
|
||||
filterOk(matchesFuzzyOcticonAware, 'iut', parseOcticons('$(octicon) Indent $(octico) Using $(octic) Tpaces'), [
|
||||
{ start: 11, end: 12 },
|
||||
{ start: 28, end: 29 },
|
||||
{ start: 43, end: 44 },
|
||||
]);
|
||||
|
||||
// Prefix
|
||||
|
||||
filterOk(matchesFuzzyOcticonAware, 'using', parseOcticons('$(octicon) Indent Using Spaces'), [
|
||||
{ start: 18, end: 23 },
|
||||
]);
|
||||
|
||||
// Broken Octicon
|
||||
|
||||
filterOk(matchesFuzzyOcticonAware, 'octicon', parseOcticons('This $(octicon Indent Using Spaces'), [
|
||||
{ start: 7, end: 14 },
|
||||
]);
|
||||
|
||||
filterOk(matchesFuzzyOcticonAware, 'indent', parseOcticons('This $octicon Indent Using Spaces'), [
|
||||
{ start: 14, end: 20 },
|
||||
]);
|
||||
});
|
||||
});
|
||||
54
src/vs/base/test/common/resources.test.ts
Normal file
54
src/vs/base/test/common/resources.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { distinctParents, dirname } from 'vs/base/common/resources';
|
||||
import { normalize } from 'vs/base/common/paths';
|
||||
|
||||
suite('Resources', () => {
|
||||
|
||||
test('distinctParents', () => {
|
||||
|
||||
// Basic
|
||||
let resources = [
|
||||
URI.file('/some/folderA/file.txt'),
|
||||
URI.file('/some/folderB/file.txt'),
|
||||
URI.file('/some/folderC/file.txt')
|
||||
];
|
||||
|
||||
let distinct = distinctParents(resources, r => r);
|
||||
assert.equal(distinct.length, 3);
|
||||
assert.equal(distinct[0].toString(), resources[0].toString());
|
||||
assert.equal(distinct[1].toString(), resources[1].toString());
|
||||
assert.equal(distinct[2].toString(), resources[2].toString());
|
||||
|
||||
// Parent / Child
|
||||
resources = [
|
||||
URI.file('/some/folderA'),
|
||||
URI.file('/some/folderA/file.txt'),
|
||||
URI.file('/some/folderA/child/file.txt'),
|
||||
URI.file('/some/folderA2/file.txt'),
|
||||
URI.file('/some/file.txt')
|
||||
];
|
||||
|
||||
distinct = distinctParents(resources, r => r);
|
||||
assert.equal(distinct.length, 3);
|
||||
assert.equal(distinct[0].toString(), resources[0].toString());
|
||||
assert.equal(distinct[1].toString(), resources[3].toString());
|
||||
assert.equal(distinct[2].toString(), resources[4].toString());
|
||||
});
|
||||
|
||||
test('dirname', (done) => {
|
||||
const f = URI.file('/some/file/test.txt');
|
||||
const d = dirname(f);
|
||||
assert.equal(d.fsPath, normalize('/some/file', true));
|
||||
|
||||
// does not explode (https://github.com/Microsoft/vscode/issues/41987)
|
||||
dirname(URI.from({ scheme: 'file', authority: '/users/someone/portal.h' }));
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -348,4 +348,37 @@ suite('Strings', () => {
|
||||
assert.equal(strings.stripUTF8BOM('abc'), 'abc');
|
||||
assert.equal(strings.stripUTF8BOM(''), '');
|
||||
});
|
||||
|
||||
test('containsUppercaseCharacter', () => {
|
||||
[
|
||||
[null, false],
|
||||
['', false],
|
||||
['foo', false],
|
||||
['föö', false],
|
||||
['ناك', false],
|
||||
['מבוססת', false],
|
||||
['😀', false],
|
||||
['(#@()*&%()@*#&09827340982374}{:">?></\'\\~`', false],
|
||||
|
||||
['Foo', true],
|
||||
['FOO', true],
|
||||
['FöÖ', true],
|
||||
['FöÖ', true],
|
||||
['\\Foo', true],
|
||||
].forEach(([str, result]) => {
|
||||
assert.equal(strings.containsUppercaseCharacter(<string>str), result, `Wrong result for ${str}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('containsUppercaseCharacter (ignoreEscapedChars)', () => {
|
||||
[
|
||||
['\\Woo', false],
|
||||
['f\\S\\S', false],
|
||||
['foo', false],
|
||||
|
||||
['Foo', true],
|
||||
].forEach(([str, result]) => {
|
||||
assert.equal(strings.containsUppercaseCharacter(<string>str, true), result, `Wrong result for ${str}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,5 +86,5 @@ export function onError(error: Error, done: () => void): void {
|
||||
}
|
||||
|
||||
export function toResource(this: any, path: string) {
|
||||
return URI.file(paths.join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path));
|
||||
return URI.file(paths.join('C:\\', Buffer.from(this.test.fullTitle()).toString('base64'), path));
|
||||
}
|
||||
|
||||
@@ -11,6 +11,169 @@ import { Promise as WinJSPromise } from 'vs/base/common/winjs.base';
|
||||
suite('Polyfill Promise', function () {
|
||||
|
||||
test('sync-resolve, NativePromise', function () {
|
||||
// native promise behaviour
|
||||
const actual: string[] = [];
|
||||
const promise = new Promise(resolve => {
|
||||
actual.push('inCtor');
|
||||
resolve(null);
|
||||
}).then(() => actual.push('inThen'));
|
||||
actual.push('afterCtor');
|
||||
return promise.then(() => {
|
||||
assert.deepEqual(actual, ['inCtor', 'afterCtor', 'inThen']);
|
||||
});
|
||||
});
|
||||
|
||||
test('sync-resolve, WinJSPromise', function () {
|
||||
|
||||
// winjs promise behaviour
|
||||
const actual: string[] = [];
|
||||
const promise = new WinJSPromise(resolve => {
|
||||
actual.push('inCtor');
|
||||
resolve(null);
|
||||
}).then(() => actual.push('inThen'));
|
||||
actual.push('afterCtor');
|
||||
return promise.then(() => {
|
||||
assert.deepEqual(actual, ['inCtor', 'inThen', 'afterCtor']);
|
||||
});
|
||||
});
|
||||
|
||||
test('sync-resolve, PolyfillPromise', function () {
|
||||
|
||||
// winjs promise behaviour
|
||||
const actual: string[] = [];
|
||||
const promise = new PolyfillPromise(resolve => {
|
||||
actual.push('inCtor');
|
||||
resolve(null);
|
||||
}).then(() => actual.push('inThen'));
|
||||
actual.push('afterCtor');
|
||||
return promise.then(() => {
|
||||
assert.deepEqual(actual, ['inCtor', 'afterCtor', 'inThen']);
|
||||
});
|
||||
});
|
||||
|
||||
test('sync-then, NativePromise', function () {
|
||||
const actual: string[] = [];
|
||||
const promise = Promise.resolve(123).then(() => actual.push('inThen'));
|
||||
actual.push('afterThen');
|
||||
return promise.then(() => {
|
||||
assert.deepEqual(actual, ['afterThen', 'inThen']);
|
||||
});
|
||||
});
|
||||
|
||||
test('sync-then, WinJSPromise', function () {
|
||||
const actual: string[] = [];
|
||||
const promise = WinJSPromise.as(123).then(() => actual.push('inThen'));
|
||||
actual.push('afterThen');
|
||||
return promise.then(() => {
|
||||
assert.deepEqual(actual, ['inThen', 'afterThen']);
|
||||
});
|
||||
});
|
||||
|
||||
test('sync-then, PolyfillPromise', function () {
|
||||
const actual: string[] = [];
|
||||
const promise = PolyfillPromise.resolve(123).then(() => actual.push('inThen'));
|
||||
actual.push('afterThen');
|
||||
return promise.then(() => {
|
||||
assert.deepEqual(actual, ['afterThen', 'inThen']);
|
||||
});
|
||||
});
|
||||
|
||||
test('PolyfillPromise, executor has two params', function () {
|
||||
return new PolyfillPromise(function () {
|
||||
assert.equal(arguments.length, 2);
|
||||
assert.equal(typeof arguments[0], 'function');
|
||||
assert.equal(typeof arguments[1], 'function');
|
||||
|
||||
arguments[0]();
|
||||
});
|
||||
});
|
||||
|
||||
// run the same tests for the native and polyfill promise
|
||||
(<any[]>[Promise, PolyfillPromise]).forEach(PromiseCtor => {
|
||||
|
||||
test(PromiseCtor.name + ', resolved value', function () {
|
||||
return new PromiseCtor((resolve: Function) => resolve(1)).then((value: number) => assert.equal(value, 1));
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', rejected value', function () {
|
||||
return new PromiseCtor((_: Function, reject: Function) => reject(1)).then(null, (value: number) => assert.equal(value, 1));
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', catch', function () {
|
||||
return new PromiseCtor((_: Function, reject: Function) => reject(1)).catch((value: number) => assert.equal(value, 1));
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-resolve', function () {
|
||||
return PromiseCtor.resolve(42).then((value: number) => assert.equal(value, 42));
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-reject', function () {
|
||||
return PromiseCtor.reject(42).then(null, (value: number) => assert.equal(value, 42));
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-all, 1', function () {
|
||||
return PromiseCtor.all([
|
||||
PromiseCtor.resolve(1),
|
||||
PromiseCtor.resolve(2)
|
||||
]).then((values: number[]) => {
|
||||
assert.deepEqual(values, [1, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-all, 2', function () {
|
||||
return PromiseCtor.all([
|
||||
PromiseCtor.resolve(1),
|
||||
3,
|
||||
PromiseCtor.resolve(2)
|
||||
]).then((values: number[]) => {
|
||||
assert.deepEqual(values, [1, 3, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-all, 3', function () {
|
||||
return PromiseCtor.all([
|
||||
PromiseCtor.resolve(1),
|
||||
PromiseCtor.reject(13),
|
||||
PromiseCtor.reject(12),
|
||||
]).catch((values: number) => {
|
||||
assert.deepEqual(values, 13);
|
||||
});
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-race, 1', function () {
|
||||
return PromiseCtor.race([
|
||||
PromiseCtor.resolve(1),
|
||||
PromiseCtor.resolve(2),
|
||||
]).then((value: number) => {
|
||||
assert.deepEqual(value, 1);
|
||||
});
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-race, 2', function () {
|
||||
return PromiseCtor.race([
|
||||
PromiseCtor.reject(-1),
|
||||
PromiseCtor.resolve(2),
|
||||
]).catch((value: number) => {
|
||||
assert.deepEqual(value, -1);
|
||||
});
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', static-race, 3', function () {
|
||||
return PromiseCtor.race([
|
||||
PromiseCtor.resolve(1),
|
||||
PromiseCtor.reject(2),
|
||||
]).then((value: number) => {
|
||||
assert.deepEqual(value, 1);
|
||||
});
|
||||
});
|
||||
|
||||
test(PromiseCtor.name + ', throw in ctor', function () {
|
||||
return new PromiseCtor(() => {
|
||||
throw new Error('sooo bad');
|
||||
}).catch((err: Error) => {
|
||||
assert.equal(err.message, 'sooo bad');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,10 +12,10 @@ suite('Decoder', () => {
|
||||
|
||||
test('decoding', function () {
|
||||
const lineDecoder = new decoder.LineDecoder();
|
||||
let res = lineDecoder.write(new Buffer('hello'));
|
||||
let res = lineDecoder.write(Buffer.from('hello'));
|
||||
assert.equal(res.length, 0);
|
||||
|
||||
res = lineDecoder.write(new Buffer('\nworld'));
|
||||
res = lineDecoder.write(Buffer.from('\nworld'));
|
||||
assert.equal(res[0], 'hello');
|
||||
assert.equal(res.length, 1);
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ h1, h2, h3, h4, h5, h6
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
textarea
|
||||
textarea
|
||||
{
|
||||
font-family: Consolas
|
||||
}
|
||||
|
||||
#results
|
||||
#results
|
||||
{
|
||||
margin-top: 2em;
|
||||
margin-left: 2em;
|
||||
|
||||
@@ -25,12 +25,12 @@ h1, h2, h3, h4, h5, h6
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
textarea
|
||||
textarea
|
||||
{
|
||||
font-family: Consolas
|
||||
}
|
||||
|
||||
#results
|
||||
#results
|
||||
{
|
||||
margin-top: 2em;
|
||||
margin-left: 2em;
|
||||
|
||||
@@ -15,6 +15,8 @@ import uuid = require('vs/base/common/uuid');
|
||||
import strings = require('vs/base/common/strings');
|
||||
import extfs = require('vs/base/node/extfs');
|
||||
import { onError } from 'vs/base/test/common/utils';
|
||||
import { Readable } from 'stream';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
|
||||
const ignore = () => { };
|
||||
|
||||
@@ -22,6 +24,38 @@ const mkdirp = (path: string, mode: number, callback: (error) => void) => {
|
||||
extfs.mkdirp(path, mode).done(() => callback(null), error => callback(error));
|
||||
};
|
||||
|
||||
const chunkSize = 64 * 1024;
|
||||
const readError = 'Error while reading';
|
||||
function toReadable(value: string, throwError?: boolean): Readable {
|
||||
const totalChunks = Math.ceil(value.length / chunkSize);
|
||||
const stringChunks: string[] = [];
|
||||
|
||||
for (let i = 0, j = 0; i < totalChunks; ++i, j += chunkSize) {
|
||||
stringChunks[i] = value.substr(j, chunkSize);
|
||||
}
|
||||
|
||||
let counter = 0;
|
||||
return new Readable({
|
||||
read: function () {
|
||||
if (throwError) {
|
||||
this.emit('error', new Error(readError));
|
||||
}
|
||||
|
||||
let res: string;
|
||||
let canPush = true;
|
||||
while (canPush && (res = stringChunks[counter++])) {
|
||||
canPush = this.push(res);
|
||||
}
|
||||
|
||||
// EOS
|
||||
if (!res) {
|
||||
this.push(null);
|
||||
}
|
||||
},
|
||||
encoding: 'utf8'
|
||||
});
|
||||
}
|
||||
|
||||
suite('Extfs', () => {
|
||||
|
||||
test('mkdirp', function (done: () => void) {
|
||||
@@ -40,6 +74,46 @@ suite('Extfs', () => {
|
||||
}); // 493 = 0755
|
||||
});
|
||||
|
||||
test('stat link', function (done: () => void) {
|
||||
if (isWindows) {
|
||||
// Symlinks are not the same on win, and we can not create them programitically without admin privileges
|
||||
return done();
|
||||
}
|
||||
|
||||
const id1 = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id1);
|
||||
const directory = path.join(parentDir, 'extfs', id1);
|
||||
|
||||
const id2 = uuid.generateUuid();
|
||||
const symbolicLink = path.join(parentDir, 'extfs', id2);
|
||||
|
||||
mkdirp(directory, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
fs.symlinkSync(directory, symbolicLink);
|
||||
|
||||
extfs.statLink(directory, (error, statAndIsLink) => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(!statAndIsLink.isSymbolicLink);
|
||||
|
||||
extfs.statLink(symbolicLink, (error, statAndIsLink) => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(statAndIsLink.isSymbolicLink);
|
||||
extfs.delSync(directory);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('delSync - swallows file not found error', function () {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
@@ -174,7 +248,7 @@ suite('Extfs', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('writeFileAndFlush', function (done: () => void) {
|
||||
test('writeFileAndFlush (string)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
@@ -209,6 +283,200 @@ suite('Extfs', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (stream)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
extfs.writeFileAndFlush(testFile, toReadable('Hello World'), null, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.equal(fs.readFileSync(testFile), 'Hello World');
|
||||
|
||||
const largeString = (new Array(100 * 1024)).join('Large String\n');
|
||||
|
||||
extfs.writeFileAndFlush(testFile, toReadable(largeString), null, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.equal(fs.readFileSync(testFile), largeString);
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (file stream)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const sourceFile = require.toUrl('./fixtures/index.html');
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
extfs.writeFileAndFlush(testFile, fs.createReadStream(sourceFile), null, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.equal(fs.readFileSync(testFile).toString(), fs.readFileSync(sourceFile).toString());
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (string, error handling)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
fs.mkdirSync(testFile); // this will trigger an error because testFile is now a directory!
|
||||
|
||||
extfs.writeFileAndFlush(testFile, 'Hello World', null, error => {
|
||||
if (!error) {
|
||||
return onError(new Error('Expected error for writing to readonly file'), done);
|
||||
}
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (stream, error handling EISDIR)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
fs.mkdirSync(testFile); // this will trigger an error because testFile is now a directory!
|
||||
|
||||
const readable = toReadable('Hello World');
|
||||
extfs.writeFileAndFlush(testFile, readable, null, error => {
|
||||
if (!error || (<any>error).code !== 'EISDIR') {
|
||||
return onError(new Error('Expected EISDIR error for writing to folder but got: ' + (error ? (<any>error).code : 'no error')), done);
|
||||
}
|
||||
|
||||
// verify that the stream is still consumable (for https://github.com/Microsoft/vscode/issues/42542)
|
||||
assert.equal(readable.read(), 'Hello World');
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (stream, error handling READERROR)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
extfs.writeFileAndFlush(testFile, toReadable('Hello World', true /* throw error */), null, error => {
|
||||
if (!error || error.message !== readError) {
|
||||
return onError(new Error('Expected error for writing to folder'), done);
|
||||
}
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (stream, error handling EACCES)', function (done: () => void) {
|
||||
if (isLinux) {
|
||||
return done(); // somehow this test fails on Linux in our TFS builds
|
||||
}
|
||||
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
fs.writeFileSync(testFile, '');
|
||||
fs.chmodSync(testFile, 33060); // make readonly
|
||||
|
||||
extfs.writeFileAndFlush(testFile, toReadable('Hello World'), null, error => {
|
||||
if (!error || !((<any>error).code !== 'EACCES' || (<any>error).code !== 'EPERM')) {
|
||||
return onError(new Error('Expected EACCES/EPERM error for writing to folder but got: ' + (error ? (<any>error).code : 'no error')), done);
|
||||
}
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlush (file stream, error handling)', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const sourceFile = require.toUrl('./fixtures/index.html');
|
||||
const newDir = path.join(parentDir, 'extfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
mkdirp(newDir, 493, error => {
|
||||
if (error) {
|
||||
return onError(error, done);
|
||||
}
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
fs.mkdirSync(testFile); // this will trigger an error because testFile is now a directory!
|
||||
|
||||
extfs.writeFileAndFlush(testFile, fs.createReadStream(sourceFile), null, error => {
|
||||
if (!error) {
|
||||
return onError(new Error('Expected error for writing to folder'), done);
|
||||
}
|
||||
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('writeFileAndFlushSync', function (done: () => void) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
@@ -296,4 +564,4 @@ suite('Extfs', () => {
|
||||
extfs.del(parentDir, os.tmpdir(), done, ignore);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,12 +25,12 @@ h1, h2, h3, h4, h5, h6
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
textarea
|
||||
textarea
|
||||
{
|
||||
font-family: Consolas
|
||||
}
|
||||
|
||||
#results
|
||||
#results
|
||||
{
|
||||
margin-top: 2em;
|
||||
margin-left: 2em;
|
||||
|
||||
@@ -301,6 +301,22 @@ suite('Glob', () => {
|
||||
assert(!glob.match(p, '/xpackage.json'));
|
||||
});
|
||||
|
||||
test('issue 41724', function () {
|
||||
let p = 'some/**/*.js';
|
||||
|
||||
assert(glob.match(p, 'some/foo.js'));
|
||||
assert(glob.match(p, 'some/folder/foo.js'));
|
||||
assert(!glob.match(p, 'something/foo.js'));
|
||||
assert(!glob.match(p, 'something/folder/foo.js'));
|
||||
|
||||
p = 'some/**/*';
|
||||
|
||||
assert(glob.match(p, 'some/foo.js'));
|
||||
assert(glob.match(p, 'some/folder/foo.js'));
|
||||
assert(!glob.match(p, 'something/foo.js'));
|
||||
assert(!glob.match(p, 'something/folder/foo.js'));
|
||||
});
|
||||
|
||||
test('brace expansion', function () {
|
||||
let p = '*.{html,js}';
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ h1, h2, h3, h4, h5, h6
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
textarea
|
||||
textarea
|
||||
{
|
||||
font-family: Consolas
|
||||
}
|
||||
|
||||
#results
|
||||
#results
|
||||
{
|
||||
margin-top: 2em;
|
||||
margin-left: 2em;
|
||||
|
||||
Reference in New Issue
Block a user