webkit -> Chrome throughout
And, while I'm changing every single relative import path, move product source into src/
This commit is contained in:
Родитель
71db62a826
Коммит
34a973f91b
|
@ -4,7 +4,7 @@
|
|||
{
|
||||
"name": "launch as server",
|
||||
"type": "node",
|
||||
"program": "${workspaceRoot}/out/webkit/webKitDebug.js",
|
||||
"program": "${workspaceRoot}/out/src/chrome/chromeDebug.js",
|
||||
"runtimeArgs": ["--harmony"],
|
||||
"stopOnEntry": false,
|
||||
"args": [ "--server=4712" ],
|
||||
|
|
|
@ -8,7 +8,7 @@ To avoid a conflict, delete the installed extension at `~/.vscode/extensions/msj
|
|||
|
||||
### OS X/Linux
|
||||
* `git clone` this repository
|
||||
* Run `ln -s <path to repo> ~/.vscode/extensions/vsc-webkit`
|
||||
* Run `ln -s <path to repo> ~/.vscode/extensions/vscode-chrome-debug`
|
||||
* You could clone it to the extensions directory if you want, but working with hidden folders in OS X can be a pain.
|
||||
|
||||
### Then...
|
||||
|
@ -26,8 +26,6 @@ There is a set of mocha tests which can be run with `gulp test` or with the `tes
|
|||
|
||||
See the project under testapp/ for a bunch of test scenarios crammed onto one page.
|
||||
|
||||
## Code
|
||||
Some files were copied from [the Node adapter](https://github.com/Microsoft/vscode-node-debug) and I'll periodically check for fixes to port over.
|
||||
* Files under common/
|
||||
* adapter/sourceMaps/sourceMaps.ts
|
||||
* adapter/sourceMaps/pathUtilities.ts
|
||||
## Naming
|
||||
Client: VS Code
|
||||
Target: The debuggee, which implements the Chrome Debug Protocol
|
||||
|
|
|
@ -109,4 +109,4 @@ General things to try if you're having issues:
|
|||
* Check the console for warnings that this extension prints in some cases when it can't attach
|
||||
* Ensure the code in Chrome matches the code in Code. Chrome may cache an old version.
|
||||
* If you set a breakpoint in code that runs immediately when the page loads, you won't hit that breakpoint until you refresh the page.
|
||||
* File a bug in this extension's [GitHub repo](https://github.com/Microsoft/vscode-webkit-debug). Set the "diagnosticLogging" field in your launch config and attach the logs when filing a bug.
|
||||
* File a bug in this extension's [GitHub repo](https://github.com/Microsoft/vscode-chrome-debug). Set the "diagnosticLogging" field in your launch config and attach the logs when filing a bug.
|
||||
|
|
41
gulpfile.js
41
gulpfile.js
|
@ -2,23 +2,27 @@
|
|||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
var gulp = require('gulp');
|
||||
var path = require('path');
|
||||
var ts = require('gulp-typescript');
|
||||
var log = require('gulp-util').log;
|
||||
var typescript = require('typescript');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var mocha = require('gulp-mocha');
|
||||
const gulp = require('gulp');
|
||||
const path = require('path');
|
||||
const ts = require('gulp-typescript');
|
||||
const log = require('gulp-util').log;
|
||||
const typescript = require('typescript');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
const mocha = require('gulp-mocha');
|
||||
const tslint = require('gulp-tslint');
|
||||
|
||||
var sources = [
|
||||
'adapter',
|
||||
'common',
|
||||
const sources = [
|
||||
'src',
|
||||
'test',
|
||||
'typings',
|
||||
'webkit',
|
||||
].map(function(tsFolder) { return tsFolder + '/**/*.ts'; });
|
||||
|
||||
var projectConfig = {
|
||||
const lintSources = [
|
||||
'test',
|
||||
'src'
|
||||
].map(function(tsFolder) { return tsFolder + '/**/*.ts'; });
|
||||
|
||||
const projectConfig = {
|
||||
noImplicitAny: false,
|
||||
target: 'ES5',
|
||||
module: 'commonjs',
|
||||
|
@ -41,19 +45,6 @@ gulp.task('watch', ['build'], function(cb) {
|
|||
|
||||
gulp.task('default', ['build']);
|
||||
|
||||
// Don't lint code from tsd or common, and whitelist my files under adapter
|
||||
var lintSources = [
|
||||
'test',
|
||||
'webkit',
|
||||
].map(function(tsFolder) { return tsFolder + '/**/*.ts'; });
|
||||
lintSources = lintSources.concat([
|
||||
'adapter/sourceMaps/sourceMapTransformer.ts',
|
||||
'adapter/adapterProxy.ts',
|
||||
'adapter/lineNumberTransformer.ts',
|
||||
'adapter/pathTransformer.ts',
|
||||
]);
|
||||
|
||||
var tslint = require('gulp-tslint');
|
||||
gulp.task('tslint', function(){
|
||||
return gulp.src(lintSources, { base: '.' })
|
||||
.pipe(tslint())
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"typescriptreact"
|
||||
]
|
||||
},
|
||||
"program": "./out/webkit/webkitDebug.js",
|
||||
"program": "./out/src/chrome/chromeDebug.js",
|
||||
"runtime": "node",
|
||||
"initialConfigurations": [
|
||||
{
|
||||
|
|
|
@ -4,18 +4,35 @@
|
|||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {IDebugAdapter, IDebugTransformer} from '../webkit/webKitAdapterInterfaces';
|
||||
import * as utils from '../webkit/utilities';
|
||||
import {IDebugAdapter, IDebugTransformer} from './chrome/debugAdapterInterfaces';
|
||||
import * as utils from './utils';
|
||||
|
||||
export type EventHandler = (event: DebugProtocol.Event) => void;
|
||||
|
||||
/**
|
||||
* Keeps a set of IDebugTransformers and an IDebugAdapter. Has one public method - dispatchRequest, which passes a request through each
|
||||
* IDebugTransformer, then to the IDebugAdapter.
|
||||
*/
|
||||
export class AdapterProxy {
|
||||
private static INTERNAL_EVENTS = ['scriptParsed', 'clearClientContext', 'clearTargetContext'];
|
||||
|
||||
public constructor(private _requestTransformers: IDebugTransformer[], private _debugAdapter: IDebugAdapter, private _eventHandler: EventHandler) {
|
||||
private _requestTransformers: IDebugTransformer[];
|
||||
private _debugAdapter: IDebugAdapter;
|
||||
private _eventHandler: EventHandler;
|
||||
|
||||
public constructor(requestTransformers: IDebugTransformer[], debugAdapter: IDebugAdapter, eventHandler: EventHandler) {
|
||||
this._requestTransformers = requestTransformers;
|
||||
this._debugAdapter = debugAdapter;
|
||||
this._eventHandler = eventHandler;
|
||||
|
||||
this._debugAdapter.registerEventHandler(event => this.onAdapterEvent(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes the request through all IDebugTransformers, then the IDebugAdapter. The request from the IDebugAdapter is passed through all the
|
||||
* IDebugTransformers in reverse.
|
||||
* Returns a Promise that resolves to the transformed response body.
|
||||
*/
|
||||
public dispatchRequest(request: DebugProtocol.Request): Promise<any> {
|
||||
if (!(request.command in this._debugAdapter)) {
|
||||
return utils.errP('unknowncommand');
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
import * as WebSocket from 'ws';
|
||||
import {EventEmitter} from 'events';
|
||||
import * as utils from './utilities';
|
||||
import {Logger, LogLevel} from './utilities';
|
||||
import * as utils from '../utils';
|
||||
import {Logger, LogLevel} from '../utils';
|
||||
|
||||
interface IMessageWithId {
|
||||
id: number;
|
||||
|
@ -120,9 +120,9 @@ class ResReqWebSocket extends EventEmitter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Connects to a target supporting the webkit protocol and sends and receives messages
|
||||
* Connects to a target supporting the Chrome Debug Protocol and sends and receives messages
|
||||
*/
|
||||
export class WebKitConnection {
|
||||
export class ChromeConnection {
|
||||
private _nextId = 1;
|
||||
private _socket: ResReqWebSocket;
|
||||
|
||||
|
@ -191,67 +191,67 @@ export class WebKitConnection {
|
|||
this._socket.close();
|
||||
}
|
||||
|
||||
public debugger_setBreakpoint(location: WebKitProtocol.Debugger.Location, condition?: string): Promise<WebKitProtocol.Debugger.SetBreakpointResponse> {
|
||||
return this.sendMessage('Debugger.setBreakpoint', <WebKitProtocol.Debugger.SetBreakpointParams>{ location, condition });
|
||||
public debugger_setBreakpoint(location: Chrome.Debugger.Location, condition?: string): Promise<Chrome.Debugger.SetBreakpointResponse> {
|
||||
return this.sendMessage('Debugger.setBreakpoint', <Chrome.Debugger.SetBreakpointParams>{ location, condition });
|
||||
}
|
||||
|
||||
public debugger_setBreakpointByUrl(url: string, lineNumber: number, columnNumber: number): Promise<WebKitProtocol.Debugger.SetBreakpointByUrlResponse> {
|
||||
return this.sendMessage('Debugger.setBreakpointByUrl', <WebKitProtocol.Debugger.SetBreakpointByUrlParams>{ url, lineNumber, columnNumber });
|
||||
public debugger_setBreakpointByUrl(url: string, lineNumber: number, columnNumber: number): Promise<Chrome.Debugger.SetBreakpointByUrlResponse> {
|
||||
return this.sendMessage('Debugger.setBreakpointByUrl', <Chrome.Debugger.SetBreakpointByUrlParams>{ url, lineNumber, columnNumber });
|
||||
}
|
||||
|
||||
public debugger_removeBreakpoint(breakpointId: string): Promise<WebKitProtocol.Response> {
|
||||
return this.sendMessage('Debugger.removeBreakpoint', <WebKitProtocol.Debugger.RemoveBreakpointParams>{ breakpointId });
|
||||
public debugger_removeBreakpoint(breakpointId: string): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.removeBreakpoint', <Chrome.Debugger.RemoveBreakpointParams>{ breakpointId });
|
||||
}
|
||||
|
||||
public debugger_stepOver(): Promise<WebKitProtocol.Response> {
|
||||
public debugger_stepOver(): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.stepOver');
|
||||
}
|
||||
|
||||
public debugger_stepIn(): Promise<WebKitProtocol.Response> {
|
||||
public debugger_stepIn(): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.stepInto');
|
||||
}
|
||||
|
||||
public debugger_stepOut(): Promise<WebKitProtocol.Response> {
|
||||
public debugger_stepOut(): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.stepOut');
|
||||
}
|
||||
|
||||
public debugger_resume(): Promise<WebKitProtocol.Response> {
|
||||
public debugger_resume(): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.resume');
|
||||
}
|
||||
|
||||
public debugger_pause(): Promise<WebKitProtocol.Response> {
|
||||
public debugger_pause(): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.pause');
|
||||
}
|
||||
|
||||
public debugger_evaluateOnCallFrame(callFrameId: string, expression: string, objectGroup = 'dummyObjectGroup', returnByValue?: boolean): Promise<WebKitProtocol.Debugger.EvaluateOnCallFrameResponse> {
|
||||
return this.sendMessage('Debugger.evaluateOnCallFrame', <WebKitProtocol.Debugger.EvaluateOnCallFrameParams>{ callFrameId, expression, objectGroup, returnByValue });
|
||||
public debugger_evaluateOnCallFrame(callFrameId: string, expression: string, objectGroup = 'dummyObjectGroup', returnByValue?: boolean): Promise<Chrome.Debugger.EvaluateOnCallFrameResponse> {
|
||||
return this.sendMessage('Debugger.evaluateOnCallFrame', <Chrome.Debugger.EvaluateOnCallFrameParams>{ callFrameId, expression, objectGroup, returnByValue });
|
||||
}
|
||||
|
||||
public debugger_setPauseOnExceptions(state: string): Promise<WebKitProtocol.Response> {
|
||||
return this.sendMessage('Debugger.setPauseOnExceptions', <WebKitProtocol.Debugger.SetPauseOnExceptionsParams>{ state });
|
||||
public debugger_setPauseOnExceptions(state: string): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Debugger.setPauseOnExceptions', <Chrome.Debugger.SetPauseOnExceptionsParams>{ state });
|
||||
}
|
||||
|
||||
public debugger_getScriptSource(scriptId: WebKitProtocol.Debugger.ScriptId): Promise<WebKitProtocol.Debugger.GetScriptSourceResponse> {
|
||||
return this.sendMessage('Debugger.getScriptSource', <WebKitProtocol.Debugger.GetScriptSourceParams>{ scriptId });
|
||||
public debugger_getScriptSource(scriptId: Chrome.Debugger.ScriptId): Promise<Chrome.Debugger.GetScriptSourceResponse> {
|
||||
return this.sendMessage('Debugger.getScriptSource', <Chrome.Debugger.GetScriptSourceParams>{ scriptId });
|
||||
}
|
||||
|
||||
public runtime_getProperties(objectId: string, ownProperties: boolean, accessorPropertiesOnly: boolean): Promise<WebKitProtocol.Runtime.GetPropertiesResponse> {
|
||||
return this.sendMessage('Runtime.getProperties', <WebKitProtocol.Runtime.GetPropertiesParams>{ objectId, ownProperties, accessorPropertiesOnly });
|
||||
public runtime_getProperties(objectId: string, ownProperties: boolean, accessorPropertiesOnly: boolean): Promise<Chrome.Runtime.GetPropertiesResponse> {
|
||||
return this.sendMessage('Runtime.getProperties', <Chrome.Runtime.GetPropertiesParams>{ objectId, ownProperties, accessorPropertiesOnly });
|
||||
}
|
||||
|
||||
public runtime_evaluate(expression: string, objectGroup = 'dummyObjectGroup', contextId?: number, returnByValue = false): Promise<WebKitProtocol.Runtime.EvaluateResponse> {
|
||||
return this.sendMessage('Runtime.evaluate', <WebKitProtocol.Runtime.EvaluateParams>{ expression, objectGroup, contextId, returnByValue });
|
||||
public runtime_evaluate(expression: string, objectGroup = 'dummyObjectGroup', contextId?: number, returnByValue = false): Promise<Chrome.Runtime.EvaluateResponse> {
|
||||
return this.sendMessage('Runtime.evaluate', <Chrome.Runtime.EvaluateParams>{ expression, objectGroup, contextId, returnByValue });
|
||||
}
|
||||
|
||||
public page_setOverlayMessage(message: string): Promise<WebKitProtocol.Response> {
|
||||
public page_setOverlayMessage(message: string): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Page.setOverlayMessage', { message });
|
||||
}
|
||||
|
||||
public page_clearOverlayMessage(): Promise<WebKitProtocol.Response> {
|
||||
public page_clearOverlayMessage(): Promise<Chrome.Response> {
|
||||
return this.sendMessage('Page.setOverlayMessage');
|
||||
}
|
||||
|
||||
private sendMessage(method: any, params?: any): Promise<WebKitProtocol.Response> {
|
||||
private sendMessage(method: any, params?: any): Promise<Chrome.Response> {
|
||||
return this._socket.sendMessage({
|
||||
id: this._nextId++,
|
||||
method,
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
import {WebKitDebugSession} from './webKitDebugSession';
|
||||
import {ChromeDebugSession} from './chromeDebugSession';
|
||||
import {DebugSession} from 'vscode-debugadapter';
|
||||
|
||||
DebugSession.run(WebKitDebugSession);
|
||||
DebugSession.run(ChromeDebugSession);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,8 @@
|
|||
declare namespace WebKitProtocol {
|
||||
/**
|
||||
* Chrome Debugging Protocol - documented at
|
||||
* https://developer.chrome.com/devtools/docs/protocol/1.1/index
|
||||
*/
|
||||
declare namespace Chrome {
|
||||
interface Notification {
|
||||
method: string;
|
||||
params: any;
|
|
@ -5,16 +5,16 @@
|
|||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
import {DebugSession, ErrorDestination, OutputEvent} from 'vscode-debugadapter';
|
||||
|
||||
import {WebKitDebugAdapter} from './webKitDebugAdapter';
|
||||
import * as utils from './utilities';
|
||||
import {Logger} from './utilities';
|
||||
import {ChromeDebugAdapter} from './chromeDebugAdapter';
|
||||
import * as utils from '../utils';
|
||||
import {Logger} from '../utils';
|
||||
|
||||
import {AdapterProxy} from '../adapter/adapterProxy';
|
||||
import {LineNumberTransformer} from '../adapter/lineNumberTransformer';
|
||||
import {PathTransformer} from '../adapter/pathTransformer';
|
||||
import {SourceMapTransformer} from '../adapter/sourceMaps/sourceMapTransformer';
|
||||
import {AdapterProxy} from '../adapterProxy';
|
||||
import {LineNumberTransformer} from '../transformers/lineNumberTransformer';
|
||||
import {PathTransformer} from '../transformers/pathTransformer';
|
||||
import {SourceMapTransformer} from '../transformers/sourceMaps/sourceMapTransformer';
|
||||
|
||||
export class WebKitDebugSession extends DebugSession {
|
||||
export class ChromeDebugSession extends DebugSession {
|
||||
private _adapterProxy: AdapterProxy;
|
||||
|
||||
public constructor(targetLinesStartAt1: boolean, isServer: boolean = false) {
|
||||
|
@ -31,7 +31,7 @@ export class WebKitDebugSession extends DebugSession {
|
|||
new SourceMapTransformer(),
|
||||
new PathTransformer()
|
||||
],
|
||||
new WebKitDebugAdapter(),
|
||||
new ChromeDebugAdapter(),
|
||||
event => this.sendEvent(event));
|
||||
}
|
||||
|
||||
|
@ -115,29 +115,29 @@ export class WebKitDebugSession extends DebugSession {
|
|||
*/
|
||||
|
||||
class Message implements DebugProtocol.ProtocolMessage {
|
||||
seq: number;
|
||||
type: string;
|
||||
public seq: number;
|
||||
public type: string;
|
||||
|
||||
public constructor(type: string) {
|
||||
this.seq = 0;
|
||||
this.type = type;
|
||||
}
|
||||
public constructor(type: string) {
|
||||
this.seq = 0;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
class Response extends Message implements DebugProtocol.Response {
|
||||
request_seq: number;
|
||||
success: boolean;
|
||||
command: string;
|
||||
public request_seq: number;
|
||||
public success: boolean;
|
||||
public command: string;
|
||||
|
||||
public constructor(request: DebugProtocol.Request, message?: string) {
|
||||
super('response');
|
||||
this.request_seq = request.seq;
|
||||
this.command = request.command;
|
||||
if (message) {
|
||||
this.success = false;
|
||||
(<any>this).message = message;
|
||||
} else {
|
||||
this.success = true;
|
||||
}
|
||||
}
|
||||
public constructor(request: DebugProtocol.Request, message?: string) {
|
||||
super('response');
|
||||
this.request_seq = request.seq;
|
||||
this.command = request.command;
|
||||
if (message) {
|
||||
this.success = false;
|
||||
(<any>this).message = message;
|
||||
} else {
|
||||
this.success = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*---------------------------------------------------------
|
||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
import * as Utils from '../utils';
|
||||
|
||||
/**
|
||||
* Maps a url from target to an absolute local path.
|
||||
* If not given an absolute path (with file: prefix), searches the current working directory for a matching file.
|
||||
* http://localhost/scripts/code.js => d:/app/scripts/code.js
|
||||
* file:///d:/scripts/code.js => d:/scripts/code.js
|
||||
*/
|
||||
export function targetUrlToClientPath(webRoot: string, aUrl: string): string {
|
||||
if (!aUrl) {
|
||||
return '';
|
||||
}
|
||||
|
||||
aUrl = decodeURI(aUrl);
|
||||
|
||||
// If the url is an absolute path to a file that exists, return it without file:///.
|
||||
// A remote absolute url (cordova) will still need the logic below.
|
||||
if (aUrl.startsWith('file:///') && Utils.existsSync(aUrl.replace(/^file:\/\/\//, ''))) {
|
||||
return Utils.canonicalizeUrl(aUrl);
|
||||
}
|
||||
|
||||
// If we don't have the client workingDirectory for some reason, don't try to map the url to a client path
|
||||
if (!webRoot) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Search the filesystem under the webRoot for the file that best matches the given url
|
||||
let pathName = decodeURIComponent(url.parse(Utils.canonicalizeUrl(aUrl)).pathname);
|
||||
if (!pathName || pathName === '/') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Dealing with the path portion of either a url or an absolute path to remote file.
|
||||
// Need to force path.sep separator
|
||||
pathName = pathName.replace(/\//g, path.sep);
|
||||
const pathParts = pathName.split(path.sep);
|
||||
while (pathParts.length > 0) {
|
||||
const clientPath = path.join(webRoot, pathParts.join(path.sep));
|
||||
if (Utils.existsSync(clientPath)) {
|
||||
return Utils.canonicalizeUrl(clientPath);
|
||||
}
|
||||
|
||||
pathParts.shift();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a RemoteObject to a value+variableHandleRef for the client.
|
||||
*/
|
||||
export function remoteObjectToValue(object: Chrome.Runtime.RemoteObject, stringify = true): { value: string, variableHandleRef?: string } {
|
||||
let value = '';
|
||||
let variableHandleRef: string;
|
||||
|
||||
if (object) {
|
||||
if (object.type === 'object') {
|
||||
if (object.subtype === 'null') {
|
||||
value = 'null';
|
||||
} else {
|
||||
// If it's a non-null object, create a variable reference so the client can ask for its props
|
||||
variableHandleRef = object.objectId;
|
||||
value = object.description;
|
||||
}
|
||||
} else if (object.type === 'undefined') {
|
||||
value = 'undefined';
|
||||
} else if (object.type === 'function') {
|
||||
const firstBraceIdx = object.description.indexOf('{');
|
||||
if (firstBraceIdx >= 0) {
|
||||
value = object.description.substring(0, firstBraceIdx) + '{ … }';
|
||||
} else {
|
||||
const firstArrowIdx = object.description.indexOf('=>');
|
||||
value = firstArrowIdx >= 0 ?
|
||||
object.description.substring(0, firstArrowIdx + 2) + ' …' :
|
||||
object.description;
|
||||
}
|
||||
} else {
|
||||
// The value is a primitive value, or something that has a description (not object, primitive, or undefined). And force to be string
|
||||
if (typeof object.value === 'undefined') {
|
||||
value = object.description;
|
||||
} else {
|
||||
value = stringify ? JSON.stringify(object.value) : object.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { value, variableHandleRef };
|
||||
}
|
|
@ -3,9 +3,9 @@
|
|||
*--------------------------------------------------------*/
|
||||
|
||||
import * as url from 'url';
|
||||
import * as Utilities from './utilities';
|
||||
import * as ChromeUtils from './chromeUtils';
|
||||
|
||||
export function formatConsoleMessage(m: WebKitProtocol.Console.Message): { text: string, isError: boolean } {
|
||||
export function formatConsoleMessage(m: Chrome.Console.Message): { text: string, isError: boolean } {
|
||||
let outputText: string;
|
||||
if (m.type === 'log') {
|
||||
outputText = resolveParams(m);
|
||||
|
@ -37,7 +37,7 @@ export function formatConsoleMessage(m: WebKitProtocol.Console.Message): { text:
|
|||
return { text: outputText, isError: m.level === 'error' };
|
||||
}
|
||||
|
||||
function resolveParams(m: WebKitProtocol.Console.Message): string {
|
||||
function resolveParams(m: Chrome.Console.Message): string {
|
||||
if (!m.parameters || !m.parameters.length) {
|
||||
return m.text;
|
||||
}
|
||||
|
@ -79,8 +79,8 @@ function resolveParams(m: WebKitProtocol.Console.Message): string {
|
|||
return text;
|
||||
}
|
||||
|
||||
function remoteObjectToString(obj: WebKitProtocol.Runtime.RemoteObject): string {
|
||||
const result = Utilities.remoteObjectToValue(obj, /*stringify=*/false);
|
||||
function remoteObjectToString(obj: Chrome.Runtime.RemoteObject): string {
|
||||
const result = ChromeUtils.remoteObjectToValue(obj, /*stringify=*/false);
|
||||
if (result.variableHandleRef) {
|
||||
// The DebugProtocol console API doesn't support returning a variable reference, so do our best to
|
||||
// build a useful string out of this object.
|
||||
|
@ -111,7 +111,7 @@ function remoteObjectToString(obj: WebKitProtocol.Runtime.RemoteObject): string
|
|||
}
|
||||
}
|
||||
|
||||
function arrayRemoteObjToString(obj: WebKitProtocol.Runtime.RemoteObject): string {
|
||||
function arrayRemoteObjToString(obj: Chrome.Runtime.RemoteObject): string {
|
||||
if (obj.preview && obj.preview.properties) {
|
||||
let props: string = obj.preview.properties
|
||||
.map(prop => prop.value)
|
||||
|
@ -127,7 +127,7 @@ function arrayRemoteObjToString(obj: WebKitProtocol.Runtime.RemoteObject): strin
|
|||
}
|
||||
}
|
||||
|
||||
function stackTraceToString(stackTrace: WebKitProtocol.Console.StackTrace): string {
|
||||
function stackTraceToString(stackTrace: Chrome.Console.StackTrace): string {
|
||||
return stackTrace
|
||||
.map(frame => {
|
||||
const fnName = frame.functionName || (frame.url ? '(anonymous)' : '(eval)');
|
|
@ -1,3 +1,11 @@
|
|||
/*---------------------------------------------------------
|
||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* This file contains extended forms of interfaces from vscode-debugprotocol
|
||||
*/
|
||||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
export interface ILaunchRequestArgs extends DebugProtocol.LaunchRequestArguments {
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {IBreakpoint, IDebugTransformer, ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../webkit/webKitAdapterInterfaces';
|
||||
import {IDebugTransformer, ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../chrome/debugAdapterInterfaces';
|
||||
|
||||
/**
|
||||
* Converts from 1 based lines on the client side to 0 based lines on the target side
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {ISetBreakpointsArgs, IDebugTransformer, ILaunchRequestArgs, IAttachRequestArgs, IStackTraceResponseBody} from '../webkit/webKitAdapterInterfaces';
|
||||
import * as utils from '../webkit/utilities';
|
||||
import {ISetBreakpointsArgs, IDebugTransformer, ILaunchRequestArgs, IAttachRequestArgs, IStackTraceResponseBody} from '../chrome/debugAdapterInterfaces';
|
||||
import * as utils from '../utils';
|
||||
import * as ChromeUtils from '../chrome/chromeUtils';
|
||||
|
||||
interface IPendingBreakpoint {
|
||||
resolve: () => void;
|
||||
|
@ -18,8 +19,8 @@ interface IPendingBreakpoint {
|
|||
*/
|
||||
export class PathTransformer implements IDebugTransformer {
|
||||
private _webRoot: string;
|
||||
private _clientPathToWebkitUrl = new Map<string, string>();
|
||||
private _webkitUrlToClientPath = new Map<string, string>();
|
||||
private _clientPathToTargetUrl = new Map<string, string>();
|
||||
private _targetUrlToClientPath = new Map<string, string>();
|
||||
private _pendingBreakpointsByPath = new Map<string, IPendingBreakpoint>();
|
||||
|
||||
public launch(args: ILaunchRequestArgs): void {
|
||||
|
@ -45,8 +46,8 @@ export class PathTransformer implements IDebugTransformer {
|
|||
}
|
||||
|
||||
const url = utils.canonicalizeUrl(args.source.path);
|
||||
if (this._clientPathToWebkitUrl.has(url)) {
|
||||
args.source.path = this._clientPathToWebkitUrl.get(url);
|
||||
if (this._clientPathToTargetUrl.has(url)) {
|
||||
args.source.path = this._clientPathToTargetUrl.get(url);
|
||||
utils.Logger.log(`Paths.setBP: Resolved ${url} to ${args.source.path}`);
|
||||
resolve();
|
||||
} else {
|
||||
|
@ -62,20 +63,20 @@ export class PathTransformer implements IDebugTransformer {
|
|||
}
|
||||
|
||||
public clearTargetContext(): void {
|
||||
this._clientPathToWebkitUrl = new Map<string, string>();
|
||||
this._webkitUrlToClientPath = new Map<string, string>();
|
||||
this._clientPathToTargetUrl = new Map<string, string>();
|
||||
this._targetUrlToClientPath = new Map<string, string>();
|
||||
}
|
||||
|
||||
public scriptParsed(event: DebugProtocol.Event): void {
|
||||
const webkitUrl: string = event.body.scriptUrl;
|
||||
const clientPath = utils.webkitUrlToClientPath(this._webRoot, webkitUrl);
|
||||
const targetUrl: string = event.body.scriptUrl;
|
||||
const clientPath = ChromeUtils.targetUrlToClientPath(this._webRoot, targetUrl);
|
||||
|
||||
if (!clientPath) {
|
||||
utils.Logger.log(`Paths.scriptParsed: could not resolve ${webkitUrl} to a file in the workspace. webRoot: ${this._webRoot}`);
|
||||
utils.Logger.log(`Paths.scriptParsed: could not resolve ${targetUrl} to a file in the workspace. webRoot: ${this._webRoot}`);
|
||||
} else {
|
||||
utils.Logger.log(`Paths.scriptParsed: resolved ${webkitUrl} to ${clientPath}. webRoot: ${this._webRoot}`);
|
||||
this._clientPathToWebkitUrl.set(clientPath, webkitUrl);
|
||||
this._webkitUrlToClientPath.set(webkitUrl, clientPath);
|
||||
utils.Logger.log(`Paths.scriptParsed: resolved ${targetUrl} to ${clientPath}. webRoot: ${this._webRoot}`);
|
||||
this._clientPathToTargetUrl.set(clientPath, targetUrl);
|
||||
this._targetUrlToClientPath.set(targetUrl, clientPath);
|
||||
|
||||
event.body.scriptUrl = clientPath;
|
||||
}
|
||||
|
@ -93,9 +94,9 @@ export class PathTransformer implements IDebugTransformer {
|
|||
if (frame.source.path) {
|
||||
// Try to resolve the url to a path in the workspace. If it's not in the workspace,
|
||||
// just use the script.url as-is. It will be resolved or cleared by the SourceMapTransformer.
|
||||
const clientPath = this._webkitUrlToClientPath.has(frame.source.path) ?
|
||||
this._webkitUrlToClientPath.get(frame.source.path) :
|
||||
utils.webkitUrlToClientPath(this._webRoot, frame.source.path);
|
||||
const clientPath = this._targetUrlToClientPath.has(frame.source.path) ?
|
||||
this._targetUrlToClientPath.get(frame.source.path) :
|
||||
ChromeUtils.targetUrlToClientPath(this._webRoot, frame.source.path);
|
||||
|
||||
// Incoming stackFrames have sourceReference and path set. If the path was resolved to a file in the workspace,
|
||||
// clear the sourceReference since it's not needed.
|
|
@ -2,12 +2,13 @@
|
|||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* tslint:disable */
|
||||
// TODO - This file was originally copied from vscode-node-debug and needs to be cleaned up to meet our guidelines.
|
||||
|
||||
import * as Path from 'path';
|
||||
import * as URL from 'url';
|
||||
|
||||
import * as utils from '../../webkit/utilities';
|
||||
import * as utils from '../../utils';
|
||||
|
||||
export function getPathRoot(p: string) {
|
||||
if (p) {
|
|
@ -7,10 +7,10 @@ import * as path from 'path';
|
|||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {IDebugTransformer, ISetBreakpointsArgs, ILaunchRequestArgs, IAttachRequestArgs,
|
||||
ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../../webkit/webKitAdapterInterfaces';
|
||||
ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../../chrome/debugAdapterInterfaces';
|
||||
import {ISourceMaps, SourceMaps} from './sourceMaps';
|
||||
import * as utils from '../../webkit/utilities';
|
||||
import {Logger} from '../../webkit/utilities';
|
||||
import * as utils from '../../utils';
|
||||
import {Logger} from '../../utils';
|
||||
|
||||
interface IPendingBreakpoint {
|
||||
resolve: () => void;
|
|
@ -9,8 +9,8 @@ import * as URL from 'url';
|
|||
import * as FS from 'fs';
|
||||
import {SourceMapConsumer} from 'source-map';
|
||||
import * as PathUtils from './pathUtilities';
|
||||
import * as utils from '../../webkit/utilities';
|
||||
import {Logger} from '../../webkit/utilities';
|
||||
import * as utils from '../../utils';
|
||||
import {Logger} from '../../utils';
|
||||
|
||||
|
||||
export interface MappingResult {
|
|
@ -202,53 +202,7 @@ export class Logger {
|
|||
}
|
||||
|
||||
/**
|
||||
* Maps a url from webkit to an absolute local path.
|
||||
* If not given an absolute path (with file: prefix), searches the current working directory for a matching file.
|
||||
* http://localhost/scripts/code.js => d:/app/scripts/code.js
|
||||
* file:///d:/scripts/code.js => d:/scripts/code.js
|
||||
*/
|
||||
export function webkitUrlToClientPath(webRoot: string, aUrl: string): string {
|
||||
if (!aUrl) {
|
||||
return '';
|
||||
}
|
||||
|
||||
aUrl = decodeURI(aUrl);
|
||||
|
||||
// If the url is an absolute path to a file that exists, return it without file:///.
|
||||
// A remote absolute url (cordova) will still need the logic below.
|
||||
if (aUrl.startsWith('file:///') && existsSync(aUrl.replace(/^file:\/\/\//, ''))) {
|
||||
return canonicalizeUrl(aUrl);
|
||||
}
|
||||
|
||||
// If we don't have the client workingDirectory for some reason, don't try to map the url to a client path
|
||||
if (!webRoot) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Search the filesystem under the webRoot for the file that best matches the given url
|
||||
let pathName = decodeURIComponent(url.parse(canonicalizeUrl(aUrl)).pathname);
|
||||
if (!pathName || pathName === '/') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Dealing with the path portion of either a url or an absolute path to remote file.
|
||||
// Need to force path.sep separator
|
||||
pathName = pathName.replace(/\//g, path.sep);
|
||||
const pathParts = pathName.split(path.sep);
|
||||
while (pathParts.length > 0) {
|
||||
const clientPath = path.join(webRoot, pathParts.join(path.sep));
|
||||
if (existsSync(clientPath)) {
|
||||
return canonicalizeUrl(clientPath);
|
||||
}
|
||||
|
||||
pathParts.shift();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a url either from the client or the webkit target to a common format for comparing.
|
||||
* Modify a url either from the client or the target to a common format for comparing.
|
||||
* The client can handle urls in this format too.
|
||||
* file:///D:\\scripts\\code.js => d:/scripts/code.js
|
||||
* file:///Users/me/project/code.js => /Users/me/project/code.js
|
||||
|
@ -308,44 +262,6 @@ export function stripTrailingSlash(aPath: string): string {
|
|||
.replace(/\\$/, '');
|
||||
}
|
||||
|
||||
export function remoteObjectToValue(object: WebKitProtocol.Runtime.RemoteObject, stringify = true): { value: string, variableHandleRef: string } {
|
||||
let value = '';
|
||||
let variableHandleRef: string;
|
||||
|
||||
if (object) {
|
||||
if (object.type === 'object') {
|
||||
if (object.subtype === 'null') {
|
||||
value = 'null';
|
||||
} else {
|
||||
// If it's a non-null object, create a variable reference so the client can ask for its props
|
||||
variableHandleRef = object.objectId;
|
||||
value = object.description;
|
||||
}
|
||||
} else if (object.type === 'undefined') {
|
||||
value = 'undefined';
|
||||
} else if (object.type === 'function') {
|
||||
const firstBraceIdx = object.description.indexOf('{');
|
||||
if (firstBraceIdx >= 0) {
|
||||
value = object.description.substring(0, firstBraceIdx) + '{ … }';
|
||||
} else {
|
||||
const firstArrowIdx = object.description.indexOf('=>');
|
||||
value = firstArrowIdx >= 0 ?
|
||||
object.description.substring(0, firstArrowIdx + 2) + ' …' :
|
||||
object.description;
|
||||
}
|
||||
} else {
|
||||
// The value is a primitive value, or something that has a description (not object, primitive, or undefined). And force to be string
|
||||
if (typeof object.value === 'undefined') {
|
||||
value = object.description;
|
||||
} else {
|
||||
value = stringify ? JSON.stringify(object.value) : object.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { value, variableHandleRef };
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for returning a rejected promise with an Error object. Avoids double-wrapping an Error, which could happen
|
||||
* when passing on a failure from a Promise error handler.
|
|
@ -4,45 +4,48 @@
|
|||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {IStackTraceResponseBody, ISetBreakpointsResponseBody} from '../../webkit/webKitAdapterInterfaces';
|
||||
import {ISetBreakpointsResponseBody} from '../../src/chrome/debugAdapterInterfaces';
|
||||
|
||||
import * as mockery from 'mockery';
|
||||
import {EventEmitter} from 'events';
|
||||
import * as assert from 'assert';
|
||||
|
||||
import * as testUtils from '../testUtils';
|
||||
import * as utils from '../../webkit/utilities';
|
||||
import * as utils from '../../src/utils';
|
||||
|
||||
/** Not mocked - use for type only */
|
||||
import {WebKitDebugAdapter as _WebKitDebugAdapter} from '../../webkit/webKitDebugAdapter';
|
||||
import {ChromeDebugAdapter as _ChromeDebugAdapter} from '../../src/chrome/chromeDebugAdapter';
|
||||
|
||||
const MODULE_UNDER_TEST = '../../webkit/webKitDebugAdapter';
|
||||
suite('WebKitDebugAdapter', () => {
|
||||
let mockWebKitConnection: Sinon.SinonMock;
|
||||
const MODULE_UNDER_TEST = '../../src/chrome/chromeDebugAdapter';
|
||||
suite('ChromeDebugAdapter', () => {
|
||||
let mockChromeConnection: Sinon.SinonMock;
|
||||
|
||||
setup(() => {
|
||||
testUtils.setupUnhandledRejectionListener();
|
||||
mockery.enable({ useCleanCache: true, warnOnReplace: false });
|
||||
mockery.registerAllowables([
|
||||
MODULE_UNDER_TEST,
|
||||
'./utilities']);
|
||||
|
||||
// Allow the common/ stuff - almost none of it is actually used but I can't get rid of the requires entirely
|
||||
mockery.registerAllowables([
|
||||
'../common/debugSession',
|
||||
'../common/handles',
|
||||
'../common/v8Protocol',
|
||||
'./v8Protocol',
|
||||
'../utils',
|
||||
'./chromeUtils',
|
||||
'./consoleHelper',
|
||||
'events']);
|
||||
|
||||
// Allow vscode-debugadapter and dependencies - not complicated stuff
|
||||
mockery.registerAllowables([
|
||||
'vscode-debugadapter',
|
||||
'./debugSession',
|
||||
'./protocol',
|
||||
'./messages',
|
||||
'./handles'
|
||||
]);
|
||||
|
||||
mockery.registerMock('os', { platform: () => 'win32' });
|
||||
testUtils.registerEmptyMocks(['child_process', 'url', 'path', 'net', 'fs', 'http']);
|
||||
mockWebKitConnection = testUtils.createRegisteredSinonMock('./webKitConnection', new DefaultMockWebKitConnection(), 'WebKitConnection');
|
||||
mockChromeConnection = testUtils.createRegisteredSinonMock('./chromeConnection', new DefaultMockChromeConnection(), 'ChromeConnection');
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
DefaultMockWebKitConnection.EE.removeAllListeners();
|
||||
DefaultMockChromeConnection.EE.removeAllListeners();
|
||||
testUtils.removeUnhandledRejectionListener();
|
||||
mockery.deregisterAll();
|
||||
mockery.disable();
|
||||
|
@ -68,7 +71,7 @@ suite('WebKitDebugAdapter', () => {
|
|||
});
|
||||
|
||||
test('if unsuccessful, the promise is rejected and an initialized event is not fired', done => {
|
||||
mockWebKitConnection.expects('attach').returns(utils.errP('Testing attach failed'));
|
||||
mockChromeConnection.expects('attach').returns(utils.errP('Testing attach failed'));
|
||||
|
||||
const wkda = instantiateWKDA();
|
||||
wkda.registerEventHandler((event: DebugProtocol.Event) => {
|
||||
|
@ -91,19 +94,19 @@ suite('WebKitDebugAdapter', () => {
|
|||
columnNumber = cols[i];
|
||||
}
|
||||
|
||||
mockWebKitConnection.expects('debugger_setBreakpointByUrl')
|
||||
mockChromeConnection.expects('debugger_setBreakpointByUrl')
|
||||
.once()
|
||||
.withArgs(FILE_NAME, lineNumber, columnNumber)
|
||||
.returns(<WebKitProtocol.Debugger.SetBreakpointByUrlResponse>{ id: 0, result: { breakpointId: BP_ID + i, locations: [{ scriptId, lineNumber, columnNumber }] } });
|
||||
.returns(<Chrome.Debugger.SetBreakpointByUrlResponse>{ id: 0, result: { breakpointId: BP_ID + i, locations: [{ scriptId, lineNumber, columnNumber }] } });
|
||||
});
|
||||
}
|
||||
|
||||
function expectRemoveBreakpoint(indicies: number[]): void {
|
||||
indicies.forEach(i => {
|
||||
mockWebKitConnection.expects('debugger_removeBreakpoint')
|
||||
mockChromeConnection.expects('debugger_removeBreakpoint')
|
||||
.once()
|
||||
.withArgs(BP_ID + i)
|
||||
.returns(<WebKitProtocol.Response>{ id: 0 });
|
||||
.returns(<Chrome.Response>{ id: 0 });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -128,7 +131,7 @@ suite('WebKitDebugAdapter', () => {
|
|||
return attach(wkda).then(() => {
|
||||
return wkda.setBreakpoints({ source: { path: FILE_NAME }, lines, cols });
|
||||
}).then(response => {
|
||||
mockWebKitConnection.verify();
|
||||
mockChromeConnection.verify();
|
||||
assert.deepEqual(response, makeExpectedResponse(lines, cols));
|
||||
});
|
||||
});
|
||||
|
@ -142,7 +145,7 @@ suite('WebKitDebugAdapter', () => {
|
|||
return attach(wkda).then(() => {
|
||||
return wkda.setBreakpoints({ source: { path: FILE_NAME }, lines, cols });
|
||||
}).then(response => {
|
||||
mockWebKitConnection.verify();
|
||||
mockChromeConnection.verify();
|
||||
assert.deepEqual(response, makeExpectedResponse(lines, cols));
|
||||
});
|
||||
});
|
||||
|
@ -163,7 +166,7 @@ suite('WebKitDebugAdapter', () => {
|
|||
expectSetBreakpoint(lines, cols);
|
||||
return wkda.setBreakpoints({ source: { path: FILE_NAME }, lines, cols });
|
||||
}).then(response => {
|
||||
mockWebKitConnection.verify();
|
||||
mockChromeConnection.verify();
|
||||
assert.deepEqual(response, makeExpectedResponse(lines, cols));
|
||||
});
|
||||
});
|
||||
|
@ -184,7 +187,7 @@ suite('WebKitDebugAdapter', () => {
|
|||
expectSetBreakpoint(lines, cols);
|
||||
return wkda.setBreakpoints({ source: { path: FILE_NAME }, lines, cols });
|
||||
}).then(response => {
|
||||
mockWebKitConnection.verify();
|
||||
mockChromeConnection.verify();
|
||||
assert.deepEqual(response, makeExpectedResponse(lines, cols));
|
||||
});
|
||||
});
|
||||
|
@ -199,17 +202,17 @@ suite('WebKitDebugAdapter', () => {
|
|||
return wkda.setBreakpoints({ source: { path: FILE_NAME }, lines, cols });
|
||||
}).then(response => {
|
||||
expectRemoveBreakpoint([2, 3]);
|
||||
DefaultMockWebKitConnection.EE.emit('Debugger.globalObjectCleared');
|
||||
DefaultMockWebKitConnection.EE.emit('Debugger.scriptParsed', <WebKitProtocol.Debugger.Script>{ scriptId: 'afterRefreshScriptId', url: FILE_NAME });
|
||||
DefaultMockWebKitConnection.EE.emit('Debugger.breakpointResolved', <WebKitProtocol.Debugger.BreakpointResolvedParams>{ breakpointId: BP_ID + 2, location: { scriptId: 'afterRefreshScriptId' } });
|
||||
DefaultMockWebKitConnection.EE.emit('Debugger.breakpointResolved', <WebKitProtocol.Debugger.BreakpointResolvedParams>{ breakpointId: BP_ID + 3, location: { scriptId: 'afterRefreshScriptId' } });
|
||||
DefaultMockChromeConnection.EE.emit('Debugger.globalObjectCleared');
|
||||
DefaultMockChromeConnection.EE.emit('Debugger.scriptParsed', <Chrome.Debugger.Script>{ scriptId: 'afterRefreshScriptId', url: FILE_NAME });
|
||||
DefaultMockChromeConnection.EE.emit('Debugger.breakpointResolved', <Chrome.Debugger.BreakpointResolvedParams>{ breakpointId: BP_ID + 2, location: { scriptId: 'afterRefreshScriptId' } });
|
||||
DefaultMockChromeConnection.EE.emit('Debugger.breakpointResolved', <Chrome.Debugger.BreakpointResolvedParams>{ breakpointId: BP_ID + 3, location: { scriptId: 'afterRefreshScriptId' } });
|
||||
|
||||
lines.push(321);
|
||||
cols.push(123);
|
||||
expectSetBreakpoint(lines, cols, 'afterRefreshScriptId');
|
||||
return wkda.setBreakpoints({ source: { path: FILE_NAME }, lines, cols });
|
||||
}).then(response => {
|
||||
mockWebKitConnection.verify();
|
||||
mockChromeConnection.verify();
|
||||
assert.deepEqual(response, makeExpectedResponse(lines, cols));
|
||||
});
|
||||
});
|
||||
|
@ -259,7 +262,7 @@ suite('WebKitDebugAdapter', () => {
|
|||
}
|
||||
});
|
||||
|
||||
DefaultMockWebKitConnection.EE.emit('Console.onMessageAdded', {
|
||||
DefaultMockChromeConnection.EE.emit('Console.onMessageAdded', {
|
||||
message: {
|
||||
source: 'console-api',
|
||||
level: 'log',
|
||||
|
@ -292,15 +295,15 @@ suite('WebKitDebugAdapter', () => {
|
|||
suite('target close/error/detach', () => { });
|
||||
});
|
||||
|
||||
function attach(wkda: _WebKitDebugAdapter): Promise<void> {
|
||||
function attach(wkda: _ChromeDebugAdapter): Promise<void> {
|
||||
return wkda.attach({ port: 9222 });
|
||||
}
|
||||
|
||||
class DefaultMockWebKitConnection {
|
||||
class DefaultMockChromeConnection {
|
||||
public static EE = new EventEmitter();
|
||||
|
||||
public on(eventName: string, handler: (msg: any) => void): void {
|
||||
DefaultMockWebKitConnection.EE.on(eventName, handler);
|
||||
DefaultMockChromeConnection.EE.on(eventName, handler);
|
||||
}
|
||||
|
||||
public attach(port: number): Promise<void> {
|
||||
|
@ -308,7 +311,7 @@ class DefaultMockWebKitConnection {
|
|||
}
|
||||
}
|
||||
|
||||
function instantiateWKDA(): _WebKitDebugAdapter {
|
||||
const WebKitDebugAdapter: typeof _WebKitDebugAdapter = require(MODULE_UNDER_TEST).WebKitDebugAdapter;
|
||||
return new WebKitDebugAdapter();
|
||||
function instantiateWKDA(): _ChromeDebugAdapter {
|
||||
const ChromeDebugAdapter: typeof _ChromeDebugAdapter = require(MODULE_UNDER_TEST).ChromeDebugAdapter;
|
||||
return new ChromeDebugAdapter();
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*---------------------------------------------------------
|
||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
import * as mockery from 'mockery';
|
||||
import * as assert from 'assert';
|
||||
import * as _path from 'path';
|
||||
|
||||
import * as testUtils from '../testUtils';
|
||||
|
||||
/** ChromeUtils without mocks - use for type only */
|
||||
import * as _ChromeUtils from '../../src/chrome/chromeUtils';
|
||||
|
||||
let path: typeof _path;
|
||||
|
||||
const MODULE_UNDER_TEST = '../../src/chrome/chromeUtils';
|
||||
suite('ChromeUtils', () => {
|
||||
function getChromeUtils(): typeof _ChromeUtils {
|
||||
return require(MODULE_UNDER_TEST);
|
||||
}
|
||||
|
||||
setup(() => {
|
||||
testUtils.setupUnhandledRejectionListener();
|
||||
|
||||
mockery.enable({ useCleanCache: true, warnOnReplace: false });
|
||||
testUtils.win32Mocks();
|
||||
mockery.registerMock('fs', { statSync: () => { } });
|
||||
mockery.registerMock('http', {});
|
||||
path = require('path');
|
||||
|
||||
mockery.registerAllowables([
|
||||
MODULE_UNDER_TEST,
|
||||
'url',
|
||||
'../utils']);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
testUtils.removeUnhandledRejectionListener();
|
||||
|
||||
mockery.deregisterAll();
|
||||
mockery.disable();
|
||||
});
|
||||
|
||||
suite('targetUrlToClientPath()', () => {
|
||||
const TEST_CLIENT_PATH = 'c:\\site\\scripts\\a.js';
|
||||
const TEST_TARGET_LOCAL_URL = 'file:///' + TEST_CLIENT_PATH;
|
||||
const TEST_TARGET_HTTP_URL = 'http://site.com/page/scripts/a.js';
|
||||
const TEST_WEB_ROOT = 'c:\\site';
|
||||
|
||||
test('an empty string is returned for a missing url', () => {
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath('', ''), '');
|
||||
});
|
||||
|
||||
test('an empty string is returned when the webRoot is missing', () => {
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath(null, TEST_TARGET_HTTP_URL), '');
|
||||
});
|
||||
|
||||
test('a url without a path returns an empty string', () => {
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath(TEST_WEB_ROOT, 'http://site.com'), '');
|
||||
});
|
||||
|
||||
test('it searches the disk for a path that exists, built from the url', () => {
|
||||
const statSync = (aPath: string) => {
|
||||
if (aPath !== TEST_CLIENT_PATH) throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath(TEST_WEB_ROOT, TEST_TARGET_HTTP_URL), TEST_CLIENT_PATH);
|
||||
});
|
||||
|
||||
test(`returns an empty string when it can't resolve a url`, () => {
|
||||
const statSync = (aPath: string) => {
|
||||
throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath(TEST_WEB_ROOT, TEST_TARGET_HTTP_URL), '');
|
||||
});
|
||||
|
||||
test('file:/// urls are returned canonicalized', () => {
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath('', TEST_TARGET_LOCAL_URL), TEST_CLIENT_PATH);
|
||||
});
|
||||
|
||||
test('uri encodings are fixed for file:/// paths', () => {
|
||||
const clientPath = 'c:\\project\\path with spaces\\script.js';
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath(TEST_WEB_ROOT, 'file:///' + encodeURI(clientPath)), clientPath);
|
||||
});
|
||||
|
||||
test('uri encodings are fixed in URLs', () => {
|
||||
const pathSegment = 'path with spaces\\script.js';
|
||||
const url = 'http:\\' + encodeURIComponent(pathSegment);
|
||||
|
||||
assert.equal(getChromeUtils().targetUrlToClientPath(TEST_WEB_ROOT, url), path.join(TEST_WEB_ROOT, pathSegment));
|
||||
});
|
||||
});
|
||||
|
||||
suite('remoteObjectToValue()', () => {
|
||||
const TEST_OBJ_ID = 'objectId';
|
||||
|
||||
function testRemoteObjectToValue(obj: any, value: string, variableHandleRef?: string, stringify?: boolean): void {
|
||||
const Utilities = getChromeUtils();
|
||||
|
||||
assert.deepEqual(Utilities.remoteObjectToValue(obj, stringify), { value, variableHandleRef });
|
||||
}
|
||||
|
||||
test('bool', () => {
|
||||
testRemoteObjectToValue({ type: 'boolean', value: true }, 'true');
|
||||
});
|
||||
|
||||
test('string', () => {
|
||||
let value = 'test string';
|
||||
testRemoteObjectToValue({ type: 'string', value }, `"${value}"`);
|
||||
testRemoteObjectToValue({ type: 'string', value }, `${value}`, undefined, /*stringify=*/false);
|
||||
|
||||
value = 'test string\r\nwith\nnewlines\n\n';
|
||||
const expValue = 'test string\\r\\nwith\\nnewlines\\n\\n';
|
||||
testRemoteObjectToValue({ type: 'string', value }, `"${expValue}"`);
|
||||
});
|
||||
|
||||
test('number', () => {
|
||||
testRemoteObjectToValue({ type: 'number', value: 1, description: '1' }, '1');
|
||||
});
|
||||
|
||||
test('array', () => {
|
||||
const description = 'Array[2]';
|
||||
testRemoteObjectToValue({ type: 'object', description, objectId: TEST_OBJ_ID }, description, TEST_OBJ_ID);
|
||||
});
|
||||
|
||||
test('regexp', () => {
|
||||
const description = '/^asdf/g';
|
||||
testRemoteObjectToValue({ type: 'object', description, objectId: TEST_OBJ_ID }, description, TEST_OBJ_ID);
|
||||
});
|
||||
|
||||
test('symbol', () => {
|
||||
const description = 'Symbol(s)';
|
||||
testRemoteObjectToValue({ type: 'symbol', description, objectId: TEST_OBJ_ID }, description);
|
||||
});
|
||||
|
||||
test('function', () => {
|
||||
// ES6 arrow fn
|
||||
testRemoteObjectToValue({ type: 'function', description: '() => {\n var x = 1;\n var y = 1;\n}', objectId: TEST_OBJ_ID }, '() => { … }');
|
||||
|
||||
// named fn
|
||||
testRemoteObjectToValue({ type: 'function', description: 'function asdf() {\n var z = 5;\n}' }, 'function asdf() { … }');
|
||||
|
||||
// anonymous fn
|
||||
testRemoteObjectToValue({ type: 'function', description: 'function () {\n var z = 5;\n}' }, 'function () { … }');
|
||||
});
|
||||
|
||||
test('undefined', () => {
|
||||
testRemoteObjectToValue({ type: 'undefined' }, 'undefined');
|
||||
});
|
||||
|
||||
test('null', () => {
|
||||
testRemoteObjectToValue({ type: 'object', subtype: 'null' }, 'null');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
import * as assert from 'assert';
|
||||
|
||||
import * as testUtils from '../testUtils';
|
||||
import * as ConsoleHelper from '../../webkit/consoleHelper';
|
||||
import * as ConsoleHelper from '../../src/chrome/consoleHelper';
|
||||
|
||||
suite('ConsoleHelper', () => {
|
||||
setup(() => {
|
||||
|
@ -16,7 +16,7 @@ suite('ConsoleHelper', () => {
|
|||
testUtils.removeUnhandledRejectionListener();
|
||||
});
|
||||
|
||||
function doAssert(message: WebKitProtocol.Console.Message, expectedText: string, expectedIsError = false): void {
|
||||
function doAssert(message: Chrome.Console.Message, expectedText: string, expectedIsError = false): void {
|
||||
assert.deepEqual(ConsoleHelper.formatConsoleMessage(message), { text: expectedText, isError: expectedIsError });
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ suite('ConsoleHelper', () => {
|
|||
});
|
||||
|
||||
/**
|
||||
* Build the webkit notifications objects for various console APIs.
|
||||
* Build the Chrome notifications objects for various console APIs.
|
||||
*/
|
||||
namespace Console {
|
||||
/**
|
||||
|
@ -70,7 +70,7 @@ namespace Console {
|
|||
* @param params - The list of parameters passed to the log function
|
||||
* @param overrideProps - An object of props that the message should have. The rest are filled in with defaults.
|
||||
*/
|
||||
function makeMockMessage(type: string, params: any[], overrideProps?: any): WebKitProtocol.Console.Message {
|
||||
function makeMockMessage(type: string, params: any[], overrideProps?: any): Chrome.Console.Message {
|
||||
const message = {
|
||||
source: 'console-api',
|
||||
level: 'log',
|
||||
|
@ -102,16 +102,16 @@ namespace Console {
|
|||
return message;
|
||||
}
|
||||
|
||||
export function makeLog(...params: any[]): WebKitProtocol.Console.Message {
|
||||
export function makeLog(...params: any[]): Chrome.Console.Message {
|
||||
return makeMockMessage('log', params);
|
||||
}
|
||||
|
||||
export function makeAssert(...params: any[]): WebKitProtocol.Console.Message {
|
||||
export function makeAssert(...params: any[]): Chrome.Console.Message {
|
||||
const fakeStackTrace = [{ url: '/script/a.js', lineNumber: 4, functionName: 'myFn' }];
|
||||
return makeMockMessage('assert', params, { level: 'error', stackTrace: fakeStackTrace });
|
||||
}
|
||||
|
||||
export function makeNetworkLog(text: string, url: string): WebKitProtocol.Console.Message {
|
||||
export function makeNetworkLog(text: string, url: string): Chrome.Console.Message {
|
||||
return makeMockMessage('log', [text], { source: 'network', url, level: 'error' });
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {IStackTraceResponseBody} from '../webkit/webKitAdapterInterfaces';
|
||||
import {IStackTraceResponseBody} from '../src/chrome/debugAdapterInterfaces';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as sinon from 'sinon';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import * as assert from 'assert';
|
||||
|
||||
import * as testUtils from '../testUtils';
|
||||
import {AdapterProxy} from '../../adapter/adapterProxy';
|
||||
import {AdapterProxy} from '../../src/adapterProxy';
|
||||
|
||||
suite('AdapterProxy', () => {
|
||||
setup(() => {
|
|
@ -6,8 +6,8 @@ import * as assert from 'assert';
|
|||
|
||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
||||
|
||||
import {ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../../webkit/webKitAdapterInterfaces';
|
||||
import { LineNumberTransformer } from '../../adapter/lineNumberTransformer';
|
||||
import {ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../../src/chrome/debugAdapterInterfaces';
|
||||
import { LineNumberTransformer } from '../../src/transformers/lineNumberTransformer';
|
||||
import * as testUtils from '../testUtils';
|
||||
|
||||
function createTransformer(clientLinesStartAt1: boolean, targetLinesStartAt1: boolean): LineNumberTransformer {
|
|
@ -7,9 +7,9 @@ import * as mockery from 'mockery';
|
|||
|
||||
import * as testUtils from '../testUtils';
|
||||
|
||||
import {PathTransformer as _PathTransformer} from '../../adapter/pathTransformer';
|
||||
import {PathTransformer as _PathTransformer} from '../../src/transformers/pathTransformer';
|
||||
|
||||
const MODULE_UNDER_TEST = '../../adapter/pathTransformer';
|
||||
const MODULE_UNDER_TEST = '../../src/transformers/pathTransformer';
|
||||
function createTransformer(): _PathTransformer {
|
||||
return new (require(MODULE_UNDER_TEST).PathTransformer)();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ suite('PathTransformer', () => {
|
|||
|
||||
|
||||
let utilsMock: Sinon.SinonMock;
|
||||
let chromeUtilsMock: Sinon.SinonMock;
|
||||
let transformer: _PathTransformer;
|
||||
|
||||
setup(() => {
|
||||
|
@ -28,7 +29,8 @@ suite('PathTransformer', () => {
|
|||
mockery.registerAllowables([MODULE_UNDER_TEST, 'path']);
|
||||
|
||||
// Mock the utils functions
|
||||
utilsMock = testUtils.createRegisteredSinonMock('../webkit/utilities', testUtils.getDefaultUtilitiesMock());
|
||||
utilsMock = testUtils.createRegisteredSinonMock('../utils', testUtils.getDefaultUtilitiesMock());
|
||||
chromeUtilsMock = testUtils.createRegisteredSinonMock('../chrome/chromeUtils', testUtils.getDefaultUtilitiesMock());
|
||||
transformer = createTransformer();
|
||||
});
|
||||
|
||||
|
@ -48,7 +50,7 @@ suite('PathTransformer', () => {
|
|||
});
|
||||
|
||||
test('resolves correctly when it can map the client script to the target script', () => {
|
||||
utilsMock.expects('webkitUrlToClientPath')
|
||||
chromeUtilsMock.expects('targetUrlToClientPath')
|
||||
.withExactArgs(/*webRoot=*/undefined, TARGET_URL).returns(CLIENT_PATH);
|
||||
utilsMock.expects('canonicalizeUrl')
|
||||
.returns(CLIENT_PATH);
|
||||
|
@ -63,7 +65,7 @@ suite('PathTransformer', () => {
|
|||
});
|
||||
|
||||
test(`doesn't resolve until it can map the client script to the target script`, () => {
|
||||
utilsMock.expects('webkitUrlToClientPath')
|
||||
chromeUtilsMock.expects('targetUrlToClientPath')
|
||||
.withExactArgs(/*webRoot=*/undefined, TARGET_URL).returns(CLIENT_PATH);
|
||||
utilsMock.expects('canonicalizeUrl')
|
||||
.twice()
|
||||
|
@ -98,7 +100,7 @@ suite('PathTransformer', () => {
|
|||
|
||||
suite('scriptParsed', () => {
|
||||
test('modifies args.source.path of the script parsed event when the file can be mapped', () => {
|
||||
utilsMock.expects('webkitUrlToClientPath')
|
||||
chromeUtilsMock.expects('targetUrlToClientPath')
|
||||
.withExactArgs(/*webRoot=*/undefined, TARGET_URL).returns(CLIENT_PATH);
|
||||
|
||||
const scriptParsedArgs = <any>{ body: { scriptUrl: TARGET_URL } };
|
||||
|
@ -108,7 +110,7 @@ suite('PathTransformer', () => {
|
|||
});
|
||||
|
||||
test(`doesn't modify args.source.path when the file can't be mapped`, () => {
|
||||
utilsMock.expects('webkitUrlToClientPath')
|
||||
chromeUtilsMock.expects('targetUrlToClientPath')
|
||||
.withExactArgs(/*webRoot=*/undefined, TARGET_URL).returns('');
|
||||
|
||||
const scriptParsedArgs = <any>{ body: { scriptUrl: TARGET_URL } };
|
||||
|
@ -122,7 +124,7 @@ suite('PathTransformer', () => {
|
|||
const RUNTIME_LINES = [2, 5, 8];
|
||||
|
||||
test('modifies the source path and clears sourceReference when the file can be mapped', () => {
|
||||
utilsMock.expects('webkitUrlToClientPath')
|
||||
chromeUtilsMock.expects('targetUrlToClientPath')
|
||||
.thrice()
|
||||
.withExactArgs(undefined, TARGET_URL).returns(CLIENT_PATH);
|
||||
|
||||
|
@ -134,7 +136,7 @@ suite('PathTransformer', () => {
|
|||
});
|
||||
|
||||
test(`doesn't modify the source path or clear the sourceReference when the file can't be mapped`, () => {
|
||||
utilsMock.expects('webkitUrlToClientPath')
|
||||
chromeUtilsMock.expects('targetUrlToClientPath')
|
||||
.thrice()
|
||||
.withExactArgs(undefined, TARGET_URL).returns('');
|
||||
|
|
@ -7,9 +7,10 @@ import * as mockery from 'mockery';
|
|||
|
||||
import * as testUtils from '../../testUtils';
|
||||
|
||||
import {getAbsSourceRoot as _getAbsSourceRoot} from '../../../adapter/sourceMaps/pathUtilities';
|
||||
// Don't use - imported without mocks for type
|
||||
import {getAbsSourceRoot as _getAbsSourceRoot} from '../../../src/transformers/sourceMaps/pathUtilities';
|
||||
|
||||
const MODULE_UNDER_TEST = '../../../adapter/sourceMaps/pathUtilities';
|
||||
const MODULE_UNDER_TEST = '../../../src/transformers/sourceMaps/pathUtilities';
|
||||
|
||||
suite('PathUtilities', () => {
|
||||
setup(() => {
|
||||
|
@ -17,7 +18,7 @@ suite('PathUtilities', () => {
|
|||
|
||||
// Set up mockery
|
||||
mockery.enable({ warnOnReplace: false, useCleanCache: true });
|
||||
mockery.registerAllowables([MODULE_UNDER_TEST, 'url', 'http', 'fs', '../../webkit/utilities']);
|
||||
mockery.registerAllowables([MODULE_UNDER_TEST, 'url', 'http', 'fs', '../../utils']);
|
||||
testUtils.win32Mocks();
|
||||
});
|
||||
|
|
@ -7,12 +7,12 @@ import {DebugProtocol} from 'vscode-debugprotocol';
|
|||
import * as assert from 'assert';
|
||||
import * as mockery from 'mockery';
|
||||
|
||||
import {ISetBreakpointsResponseBody, IStackTraceResponseBody,
|
||||
ILaunchRequestArgs, ISetBreakpointsArgs, IBreakpoint} from '../../../webkit/webKitAdapterInterfaces';
|
||||
import {ISetBreakpointsResponseBody,
|
||||
ILaunchRequestArgs, ISetBreakpointsArgs, IBreakpoint} from '../../../src/chrome/debugAdapterInterfaces';
|
||||
import * as testUtils from '../../testUtils';
|
||||
import { ISourceMaps, MappingResult } from '../../../adapter/sourceMaps/sourceMaps';
|
||||
import { ISourceMaps, MappingResult } from '../../../src/transformers/sourceMaps/sourceMaps';
|
||||
|
||||
const MODULE_UNDER_TEST = '../../../adapter/sourceMaps/sourceMapTransformer';
|
||||
const MODULE_UNDER_TEST = '../../../src/transformers/sourceMaps/sourceMapTransformer';
|
||||
const AUTHORED_PATH = 'c:/project/authored.ts';
|
||||
const RUNTIME_PATH = 'c:/project/runtime.js';
|
||||
const AUTHORED_LINES = [1, 2, 3];
|
||||
|
@ -25,7 +25,7 @@ const RUNTIME_LINES2 = [78, 81];
|
|||
const RUNTIME_COLS2 = [0, 1];
|
||||
|
||||
// Not mocked, use for type only
|
||||
import {SourceMapTransformer as _SourceMapTransformer} from '../../../adapter/sourceMaps/sourceMapTransformer';
|
||||
import {SourceMapTransformer as _SourceMapTransformer} from '../../../src/transformers/sourceMaps/sourceMapTransformer';
|
||||
|
||||
suite('SourceMapTransformer', () => {
|
||||
let utilsMock: Sinon.SinonMock;
|
||||
|
@ -36,7 +36,7 @@ suite('SourceMapTransformer', () => {
|
|||
// Set up mockery
|
||||
mockery.enable({ warnOnReplace: false, useCleanCache: true });
|
||||
|
||||
utilsMock = testUtils.createRegisteredSinonMock('../../webkit/utilities', testUtils.getDefaultUtilitiesMock());
|
||||
utilsMock = testUtils.createRegisteredSinonMock('../../utils', testUtils.getDefaultUtilitiesMock());
|
||||
mockery.registerAllowables([MODULE_UNDER_TEST, 'path']);
|
||||
});
|
||||
|
||||
|
@ -112,7 +112,7 @@ suite('SourceMapTransformer', () => {
|
|||
const args = createArgs(RUNTIME_PATH, RUNTIME_LINES);
|
||||
const expected = createArgs(RUNTIME_PATH, RUNTIME_LINES);
|
||||
|
||||
return getTransformer(false).setBreakpoints(args, 0).then(() => {
|
||||
return getTransformer(/*sourceMaps=*/false).setBreakpoints(args, 0).then(() => {
|
||||
assert.deepEqual(args, expected);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,322 @@
|
|||
/*---------------------------------------------------------
|
||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
import * as mockery from 'mockery';
|
||||
import * as assert from 'assert';
|
||||
import * as _path from 'path';
|
||||
|
||||
import * as testUtils from './testUtils';
|
||||
|
||||
/** Utils without mocks - use for type only */
|
||||
import * as _Utils from '../src/utils';
|
||||
|
||||
let path: typeof _path;
|
||||
|
||||
const MODULE_UNDER_TEST = '../src/utils';
|
||||
suite('Utils', () => {
|
||||
function getUtils(): typeof _Utils {
|
||||
return require(MODULE_UNDER_TEST);
|
||||
}
|
||||
|
||||
setup(() => {
|
||||
testUtils.setupUnhandledRejectionListener();
|
||||
|
||||
mockery.enable({ useCleanCache: true, warnOnReplace: false });
|
||||
testUtils.win32Mocks();
|
||||
mockery.registerMock('fs', { statSync: () => { } });
|
||||
mockery.registerMock('http', {});
|
||||
path = require('path');
|
||||
|
||||
mockery.registerAllowables([
|
||||
'url', MODULE_UNDER_TEST]);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
testUtils.removeUnhandledRejectionListener();
|
||||
|
||||
mockery.deregisterAll();
|
||||
mockery.disable();
|
||||
});
|
||||
|
||||
suite('getPlatform()/getBrowserPath()', () => {
|
||||
test('osx', () => {
|
||||
mockery.registerMock('os', { platform: () => 'darwin' });
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.getPlatform(), Utils.Platform.OSX);
|
||||
assert.equal(
|
||||
Utils.getBrowserPath(),
|
||||
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome');
|
||||
});
|
||||
|
||||
test('win', () => {
|
||||
// Overwrite the statSync mock to say the x86 path doesn't exist
|
||||
const statSync = (aPath: string) => {
|
||||
if (aPath.indexOf('(x86)') >= 0) throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.getPlatform(), Utils.Platform.Windows);
|
||||
assert.equal(
|
||||
Utils.getBrowserPath(),
|
||||
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe');
|
||||
});
|
||||
|
||||
test('winx86', () => {
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.getPlatform(), Utils.Platform.Windows);
|
||||
assert.equal(
|
||||
Utils.getBrowserPath(),
|
||||
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe');
|
||||
});
|
||||
|
||||
test('linux', () => {
|
||||
mockery.registerMock('os', { platform: () => 'linux' });
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.getPlatform(), Utils.Platform.Linux);
|
||||
assert.equal(
|
||||
Utils.getBrowserPath(),
|
||||
'/usr/bin/google-chrome');
|
||||
});
|
||||
|
||||
test('freebsd (default to Linux for anything unknown)', () => {
|
||||
mockery.registerMock('os', { platform: () => 'freebsd' });
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.getPlatform(), Utils.Platform.Linux);
|
||||
assert.equal(
|
||||
Utils.getBrowserPath(),
|
||||
'/usr/bin/google-chrome');
|
||||
});
|
||||
});
|
||||
|
||||
suite('existsSync()', () => {
|
||||
test('it returns false when statSync throws', () => {
|
||||
const statSync = (aPath: string) => {
|
||||
if (aPath.indexOf('notfound') >= 0) throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.existsSync('exists'), true);
|
||||
assert.equal(Utils.existsSync('thisfilenotfound'), false);
|
||||
});
|
||||
});
|
||||
|
||||
suite('reversedArr()', () => {
|
||||
test('it does not modify the input array', () => {
|
||||
let arr = [2, 4, 6];
|
||||
getUtils().reversedArr(arr);
|
||||
assert.deepEqual(arr, [2, 4, 6]);
|
||||
|
||||
arr = [1];
|
||||
getUtils().reversedArr(arr);
|
||||
assert.deepEqual(arr, [1]);
|
||||
});
|
||||
|
||||
test('it reverses the array', () => {
|
||||
assert.deepEqual(getUtils().reversedArr([1, 3, 5, 7]), [7, 5, 3, 1]);
|
||||
assert.deepEqual(
|
||||
getUtils().reversedArr([-1, 'hello', null, undefined, [1, 2]]),
|
||||
[[1, 2], undefined, null, 'hello', -1]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('promiseTimeout()', () => {
|
||||
test('when given a promise it fails if the promise never resolves', () => {
|
||||
return getUtils().promiseTimeout(new Promise(() => { }), 5).then(
|
||||
() => assert.fail('This promise should fail'),
|
||||
e => { }
|
||||
);
|
||||
});
|
||||
|
||||
test('when given a promise it succeeds if the promise resolves', () => {
|
||||
return getUtils().promiseTimeout(Promise.resolve('test'), 5).then(
|
||||
result => {
|
||||
assert.equal(result, 'test');
|
||||
},
|
||||
e => assert.fail('This promise should pass')
|
||||
);
|
||||
});
|
||||
|
||||
test('when not given a promise it resolves', () => {
|
||||
return getUtils().promiseTimeout(null, 5).then(
|
||||
null,
|
||||
() => assert.fail('This promise should pass')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('retryAsync()', () => {
|
||||
test('when the function passes, it resolves with the value', () => {
|
||||
return getUtils().retryAsync(() => Promise.resolve('pass'), /*timeoutMs=*/5).then(
|
||||
result => {
|
||||
assert.equal(result, 'pass');
|
||||
},
|
||||
e => {
|
||||
assert.fail('This should have passed');
|
||||
});
|
||||
});
|
||||
|
||||
test('when the function fails, it rejects', () => {
|
||||
return getUtils().retryAsync(() => getUtils().errP('fail'), /*timeoutMs=*/5)
|
||||
.then(
|
||||
() => assert.fail('This promise should fail'),
|
||||
e => assert.equal(e.message, 'fail'));
|
||||
});
|
||||
});
|
||||
|
||||
suite('canonicalizeUrl()', () => {
|
||||
function testCanUrl(inUrl: string, expectedUrl: string): void {
|
||||
const Utils = getUtils();
|
||||
assert.equal(Utils.canonicalizeUrl(inUrl), expectedUrl);
|
||||
}
|
||||
|
||||
test('enforces path.sep slash', () => {
|
||||
testCanUrl('c:\\thing\\file.js', 'c:\\thing\\file.js');
|
||||
testCanUrl('c:/thing/file.js', 'c:\\thing\\file.js');
|
||||
});
|
||||
|
||||
test('removes file:///', () => {
|
||||
testCanUrl('file:///c:/file.js', 'c:\\file.js');
|
||||
});
|
||||
|
||||
test('ensures local path starts with / on OSX', () => {
|
||||
mockery.registerMock('os', { platform: () => 'darwin' });
|
||||
testCanUrl('file:///Users/scripts/app.js', '/Users/scripts/app.js');
|
||||
});
|
||||
|
||||
test('force lowercase drive letter on Win to match VS Code', () => {
|
||||
// note default 'os' mock is win32
|
||||
testCanUrl('file:///D:/FILE.js', 'd:\\FILE.js');
|
||||
});
|
||||
|
||||
test('http:// url - no change', () => {
|
||||
const url = 'http://site.com/My/Cool/Site/script.js?stuff';
|
||||
testCanUrl(url, url);
|
||||
});
|
||||
|
||||
test('strips trailing slash', () => {
|
||||
testCanUrl('http://site.com/', 'http://site.com');
|
||||
});
|
||||
});
|
||||
|
||||
suite('fixDriveLetterAndSlashes', () => {
|
||||
test('works for c:/... cases', () => {
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('C:/path/stuff'), 'c:\\path\\stuff');
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('c:/path\\stuff'), 'c:\\path\\stuff');
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('C:\\path'), 'c:\\path');
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('C:\\'), 'c:\\');
|
||||
});
|
||||
|
||||
test('works for file:/// cases', () => {
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('file:///C:/path/stuff'), 'file:///c:\\path\\stuff');
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('file:///c:/path\\stuff'), 'file:///c:\\path\\stuff');
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('file:///C:\\path'), 'file:///c:\\path');
|
||||
assert.equal(getUtils().fixDriveLetterAndSlashes('file:///C:\\'), 'file:///c:\\');
|
||||
});
|
||||
});
|
||||
|
||||
suite('getUrl', () => {
|
||||
const URL = 'http://testsite.com/testfile';
|
||||
const RESPONSE = 'response';
|
||||
|
||||
function registerMockHTTP(dataResponses: string[], error?: string): void {
|
||||
mockery.registerMock('http', { get: (url, callback) => {
|
||||
assert.equal(url, URL);
|
||||
|
||||
if (error) {
|
||||
return { on:
|
||||
(eventName, eventCallback) => {
|
||||
if (eventName === 'error') {
|
||||
eventCallback(error);
|
||||
}
|
||||
}};
|
||||
} else {
|
||||
callback({
|
||||
statusCode: 200,
|
||||
on: (eventName, eventCallback) => {
|
||||
if (eventName === 'data') {
|
||||
dataResponses.forEach(eventCallback);
|
||||
} else if (eventName === 'end') {
|
||||
setTimeout(eventCallback, 0);
|
||||
}
|
||||
}});
|
||||
|
||||
return { on: () => { }};
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
test('combines chunks', () => {
|
||||
// Create a mock http.get that provides data in two chunks
|
||||
registerMockHTTP(['res', 'ponse']);
|
||||
return getUtils().getURL(URL).then(response => {
|
||||
assert.equal(response, RESPONSE);
|
||||
});
|
||||
});
|
||||
|
||||
test('rejects the promise on an error', () => {
|
||||
registerMockHTTP(undefined, 'fail');
|
||||
return getUtils().getURL(URL).then(
|
||||
response => {
|
||||
assert.fail('Should not be resolved');
|
||||
},
|
||||
e => {
|
||||
assert.equal(e, 'fail');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('isURL', () => {
|
||||
function assertIsURL(url: string): void {
|
||||
assert(getUtils().isURL(url));
|
||||
}
|
||||
|
||||
function assertNotURL(url: string): void {
|
||||
assert(!getUtils().isURL(url));
|
||||
}
|
||||
|
||||
test('returns true for URLs', () => {
|
||||
assertIsURL('http://localhost');
|
||||
assertIsURL('http://mysite.com');
|
||||
assertIsURL('file:///c:/project/code.js');
|
||||
assertIsURL('webpack:///webpack/webpackthing');
|
||||
assertIsURL('https://a.b.c:123/asdf?fsda');
|
||||
});
|
||||
|
||||
test('returns false for not-URLs', () => {
|
||||
assertNotURL('a');
|
||||
assertNotURL('/project/code.js');
|
||||
assertNotURL('c:/project/code.js');
|
||||
assertNotURL('abc123!@#');
|
||||
assertNotURL('');
|
||||
assertNotURL(null);
|
||||
});
|
||||
});
|
||||
|
||||
suite('lstrip', () => {
|
||||
test('does what it says', () => {
|
||||
assert.equal(getUtils().lstrip('test', 'te'), 'st');
|
||||
assert.equal(getUtils().lstrip('asdf', ''), 'asdf');
|
||||
assert.equal(getUtils().lstrip('asdf', null), 'asdf');
|
||||
assert.equal(getUtils().lstrip('asdf', 'asdf'), '');
|
||||
assert.equal(getUtils().lstrip('asdf', '123'), 'asdf');
|
||||
assert.equal(getUtils().lstrip('asdf', 'sdf'), 'asdf');
|
||||
});
|
||||
});
|
||||
|
||||
suite('pathToFileURL', () => {
|
||||
test('converts windows-style paths', () => {
|
||||
assert.equal(getUtils().pathToFileURL('c:\\code\\app.js'), 'file:///c:/code/app.js');
|
||||
});
|
||||
|
||||
test('converts unix-style paths', () => {
|
||||
assert.equal(getUtils().pathToFileURL('/code/app.js'), 'file:///code/app.js');
|
||||
});
|
||||
|
||||
test('encodes as URI and forces forwards slash', () => {
|
||||
assert.equal(getUtils().pathToFileURL('c:\\path with spaces\\blah.js'), 'file:///c:/path%20with%20spaces/blah.js');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,435 +0,0 @@
|
|||
/*---------------------------------------------------------
|
||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
import * as mockery from 'mockery';
|
||||
import * as assert from 'assert';
|
||||
import * as _path from 'path';
|
||||
|
||||
import * as testUtils from '../testUtils';
|
||||
|
||||
/** Utilities without mocks - use for type only */
|
||||
import * as _Utilities from '../../webkit/utilities';
|
||||
|
||||
let path: typeof _path;
|
||||
|
||||
const MODULE_UNDER_TEST = '../../webkit/utilities';
|
||||
suite('Utilities', () => {
|
||||
function getUtilities(): typeof _Utilities {
|
||||
return require(MODULE_UNDER_TEST);
|
||||
}
|
||||
|
||||
setup(() => {
|
||||
testUtils.setupUnhandledRejectionListener();
|
||||
|
||||
mockery.enable({ useCleanCache: true, warnOnReplace: false });
|
||||
testUtils.win32Mocks();
|
||||
mockery.registerMock('fs', { statSync: () => { } });
|
||||
mockery.registerMock('http', {});
|
||||
path = require('path');
|
||||
|
||||
mockery.registerAllowables([
|
||||
'url', MODULE_UNDER_TEST]);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
testUtils.removeUnhandledRejectionListener();
|
||||
|
||||
mockery.deregisterAll();
|
||||
mockery.disable();
|
||||
});
|
||||
|
||||
suite('getPlatform()/getBrowserPath()', () => {
|
||||
test('osx', () => {
|
||||
mockery.registerMock('os', { platform: () => 'darwin' });
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.getPlatform(), Utilities.Platform.OSX);
|
||||
assert.equal(
|
||||
Utilities.getBrowserPath(),
|
||||
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome');
|
||||
});
|
||||
|
||||
test('win', () => {
|
||||
// Overwrite the statSync mock to say the x86 path doesn't exist
|
||||
const statSync = (aPath: string) => {
|
||||
if (aPath.indexOf('(x86)') >= 0) throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.getPlatform(), Utilities.Platform.Windows);
|
||||
assert.equal(
|
||||
Utilities.getBrowserPath(),
|
||||
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe');
|
||||
});
|
||||
|
||||
test('winx86', () => {
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.getPlatform(), Utilities.Platform.Windows);
|
||||
assert.equal(
|
||||
Utilities.getBrowserPath(),
|
||||
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe');
|
||||
});
|
||||
|
||||
test('linux', () => {
|
||||
mockery.registerMock('os', { platform: () => 'linux' });
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.getPlatform(), Utilities.Platform.Linux);
|
||||
assert.equal(
|
||||
Utilities.getBrowserPath(),
|
||||
'/usr/bin/google-chrome');
|
||||
});
|
||||
|
||||
test('freebsd (default to Linux for anything unknown)', () => {
|
||||
mockery.registerMock('os', { platform: () => 'freebsd' });
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.getPlatform(), Utilities.Platform.Linux);
|
||||
assert.equal(
|
||||
Utilities.getBrowserPath(),
|
||||
'/usr/bin/google-chrome');
|
||||
});
|
||||
});
|
||||
|
||||
suite('existsSync()', () => {
|
||||
test('it returns false when statSync throws', () => {
|
||||
const statSync = (aPath: string) => {
|
||||
if (aPath.indexOf('notfound') >= 0) throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.existsSync('exists'), true);
|
||||
assert.equal(Utilities.existsSync('thisfilenotfound'), false);
|
||||
});
|
||||
});
|
||||
|
||||
suite('reversedArr()', () => {
|
||||
test('it does not modify the input array', () => {
|
||||
let arr = [2, 4, 6];
|
||||
getUtilities().reversedArr(arr);
|
||||
assert.deepEqual(arr, [2, 4, 6]);
|
||||
|
||||
arr = [1];
|
||||
getUtilities().reversedArr(arr);
|
||||
assert.deepEqual(arr, [1]);
|
||||
});
|
||||
|
||||
test('it reverses the array', () => {
|
||||
assert.deepEqual(getUtilities().reversedArr([1, 3, 5, 7]), [7, 5, 3, 1]);
|
||||
assert.deepEqual(
|
||||
getUtilities().reversedArr([-1, 'hello', null, undefined, [1, 2]]),
|
||||
[[1, 2], undefined, null, 'hello', -1]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('promiseTimeout()', () => {
|
||||
test('when given a promise it fails if the promise never resolves', () => {
|
||||
return getUtilities().promiseTimeout(new Promise(() => { }), 5).then(
|
||||
() => assert.fail('This promise should fail'),
|
||||
e => { }
|
||||
);
|
||||
});
|
||||
|
||||
test('when given a promise it succeeds if the promise resolves', () => {
|
||||
return getUtilities().promiseTimeout(Promise.resolve('test'), 5).then(
|
||||
result => {
|
||||
assert.equal(result, 'test');
|
||||
},
|
||||
e => assert.fail('This promise should pass')
|
||||
);
|
||||
});
|
||||
|
||||
test('when not given a promise it resolves', () => {
|
||||
return getUtilities().promiseTimeout(null, 5).then(
|
||||
null,
|
||||
() => assert.fail('This promise should pass')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('retryAsync()', () => {
|
||||
test('when the function passes, it resolves with the value', () => {
|
||||
return getUtilities().retryAsync(() => Promise.resolve('pass'), /*timeoutMs=*/5).then(
|
||||
result => {
|
||||
assert.equal(result, 'pass');
|
||||
},
|
||||
e => {
|
||||
assert.fail('This should have passed');
|
||||
});
|
||||
});
|
||||
|
||||
test('when the function fails, it rejects', () => {
|
||||
return getUtilities().retryAsync(() => getUtilities().errP('fail'), /*timeoutMs=*/5)
|
||||
.then(
|
||||
() => assert.fail('This promise should fail'),
|
||||
e => assert.equal(e.message, 'fail'));
|
||||
});
|
||||
});
|
||||
|
||||
suite('webkitUrlToClientPath()', () => {
|
||||
const TEST_CLIENT_PATH = 'c:\\site\\scripts\\a.js';
|
||||
const TEST_WEBKIT_LOCAL_URL = 'file:///' + TEST_CLIENT_PATH;
|
||||
const TEST_WEBKIT_HTTP_URL = 'http://site.com/page/scripts/a.js';
|
||||
const TEST_WEB_ROOT = 'c:\\site';
|
||||
|
||||
test('an empty string is returned for a missing url', () => {
|
||||
assert.equal(getUtilities().webkitUrlToClientPath('', ''), '');
|
||||
});
|
||||
|
||||
test('an empty string is returned when the webRoot is missing', () => {
|
||||
assert.equal(getUtilities().webkitUrlToClientPath(null, TEST_WEBKIT_HTTP_URL), '');
|
||||
});
|
||||
|
||||
test('a url without a path returns an empty string', () => {
|
||||
assert.equal(getUtilities().webkitUrlToClientPath(TEST_WEB_ROOT, 'http://site.com'), '');
|
||||
});
|
||||
|
||||
test('it searches the disk for a path that exists, built from the url', () => {
|
||||
const statSync = (aPath: string) => {
|
||||
if (aPath !== TEST_CLIENT_PATH) throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
assert.equal(getUtilities().webkitUrlToClientPath(TEST_WEB_ROOT, TEST_WEBKIT_HTTP_URL), TEST_CLIENT_PATH);
|
||||
});
|
||||
|
||||
test(`returns an empty string when it can't resolve a url`, () => {
|
||||
const statSync = (aPath: string) => {
|
||||
throw new Error('Not found');
|
||||
};
|
||||
mockery.registerMock('fs', { statSync });
|
||||
assert.equal(getUtilities().webkitUrlToClientPath(TEST_WEB_ROOT, TEST_WEBKIT_HTTP_URL), '');
|
||||
});
|
||||
|
||||
test('file:/// urls are returned canonicalized', () => {
|
||||
assert.equal(getUtilities().webkitUrlToClientPath('', TEST_WEBKIT_LOCAL_URL), TEST_CLIENT_PATH);
|
||||
});
|
||||
|
||||
test('uri encodings are fixed for file:/// paths', () => {
|
||||
const clientPath = 'c:\\project\\path with spaces\\script.js';
|
||||
assert.equal(getUtilities().webkitUrlToClientPath(TEST_WEB_ROOT, 'file:///' + encodeURI(clientPath)), clientPath);
|
||||
});
|
||||
|
||||
test('uri encodings are fixed in URLs', () => {
|
||||
const pathSegment = 'path with spaces\\script.js';
|
||||
const url = 'http:\\' + encodeURIComponent(pathSegment);
|
||||
|
||||
assert.equal(getUtilities().webkitUrlToClientPath(TEST_WEB_ROOT, url), path.join(TEST_WEB_ROOT, pathSegment));
|
||||
});
|
||||
});
|
||||
|
||||
suite('canonicalizeUrl()', () => {
|
||||
function testCanUrl(inUrl: string, expectedUrl: string): void {
|
||||
const Utilities = getUtilities();
|
||||
assert.equal(Utilities.canonicalizeUrl(inUrl), expectedUrl);
|
||||
}
|
||||
|
||||
test('enforces path.sep slash', () => {
|
||||
testCanUrl('c:\\thing\\file.js', 'c:\\thing\\file.js');
|
||||
testCanUrl('c:/thing/file.js', 'c:\\thing\\file.js');
|
||||
});
|
||||
|
||||
test('removes file:///', () => {
|
||||
testCanUrl('file:///c:/file.js', 'c:\\file.js');
|
||||
});
|
||||
|
||||
test('ensures local path starts with / on OSX', () => {
|
||||
mockery.registerMock('os', { platform: () => 'darwin' });
|
||||
testCanUrl('file:///Users/scripts/app.js', '/Users/scripts/app.js');
|
||||
});
|
||||
|
||||
test('force lowercase drive letter on Win to match VS Code', () => {
|
||||
// note default 'os' mock is win32
|
||||
testCanUrl('file:///D:/FILE.js', 'd:\\FILE.js');
|
||||
});
|
||||
|
||||
test('http:// url - no change', () => {
|
||||
const url = 'http://site.com/My/Cool/Site/script.js?stuff';
|
||||
testCanUrl(url, url);
|
||||
});
|
||||
|
||||
test('strips trailing slash', () => {
|
||||
testCanUrl('http://site.com/', 'http://site.com');
|
||||
});
|
||||
});
|
||||
|
||||
suite('fixDriveLetterAndSlashes', () => {
|
||||
test('works for c:/... cases', () => {
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('C:/path/stuff'), 'c:\\path\\stuff');
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('c:/path\\stuff'), 'c:\\path\\stuff');
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('C:\\path'), 'c:\\path');
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('C:\\'), 'c:\\');
|
||||
});
|
||||
|
||||
test('works for file:/// cases', () => {
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('file:///C:/path/stuff'), 'file:///c:\\path\\stuff');
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('file:///c:/path\\stuff'), 'file:///c:\\path\\stuff');
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('file:///C:\\path'), 'file:///c:\\path');
|
||||
assert.equal(getUtilities().fixDriveLetterAndSlashes('file:///C:\\'), 'file:///c:\\');
|
||||
});
|
||||
});
|
||||
|
||||
suite('remoteObjectToValue()', () => {
|
||||
const TEST_OBJ_ID = 'objectId';
|
||||
|
||||
function testRemoteObjectToValue(obj: any, value: string, variableHandleRef?: string, stringify?: boolean): void {
|
||||
const Utilities = getUtilities();
|
||||
|
||||
assert.deepEqual(Utilities.remoteObjectToValue(obj, stringify), { value, variableHandleRef });
|
||||
}
|
||||
|
||||
test('bool', () => {
|
||||
testRemoteObjectToValue({ type: 'boolean', value: true }, 'true');
|
||||
});
|
||||
|
||||
test('string', () => {
|
||||
let value = 'test string';
|
||||
testRemoteObjectToValue({ type: 'string', value }, `"${value}"`);
|
||||
testRemoteObjectToValue({ type: 'string', value }, `${value}`, undefined, /*stringify=*/false);
|
||||
|
||||
value = 'test string\r\nwith\nnewlines\n\n';
|
||||
const expValue = 'test string\\r\\nwith\\nnewlines\\n\\n';
|
||||
testRemoteObjectToValue({ type: 'string', value }, `"${expValue}"`);
|
||||
});
|
||||
|
||||
test('number', () => {
|
||||
testRemoteObjectToValue({ type: 'number', value: 1, description: '1' }, '1');
|
||||
});
|
||||
|
||||
test('array', () => {
|
||||
const description = 'Array[2]';
|
||||
testRemoteObjectToValue({ type: 'object', description, objectId: TEST_OBJ_ID }, description, TEST_OBJ_ID);
|
||||
});
|
||||
|
||||
test('regexp', () => {
|
||||
const description = '/^asdf/g';
|
||||
testRemoteObjectToValue({ type: 'object', description, objectId: TEST_OBJ_ID }, description, TEST_OBJ_ID);
|
||||
});
|
||||
|
||||
test('symbol', () => {
|
||||
const description = 'Symbol(s)';
|
||||
testRemoteObjectToValue({ type: 'symbol', description, objectId: TEST_OBJ_ID }, description);
|
||||
});
|
||||
|
||||
test('function', () => {
|
||||
// ES6 arrow fn
|
||||
testRemoteObjectToValue({ type: 'function', description: '() => {\n var x = 1;\n var y = 1;\n}', objectId: TEST_OBJ_ID }, '() => { … }');
|
||||
|
||||
// named fn
|
||||
testRemoteObjectToValue({ type: 'function', description: 'function asdf() {\n var z = 5;\n}' }, 'function asdf() { … }');
|
||||
|
||||
// anonymous fn
|
||||
testRemoteObjectToValue({ type: 'function', description: 'function () {\n var z = 5;\n}' }, 'function () { … }');
|
||||
});
|
||||
|
||||
test('undefined', () => {
|
||||
testRemoteObjectToValue({ type: 'undefined' }, 'undefined');
|
||||
});
|
||||
|
||||
test('null', () => {
|
||||
testRemoteObjectToValue({ type: 'object', subtype: 'null' }, 'null');
|
||||
});
|
||||
});
|
||||
|
||||
suite('getUrl', () => {
|
||||
const URL = 'http://testsite.com/testfile';
|
||||
const RESPONSE = 'response';
|
||||
|
||||
function registerMockHTTP(dataResponses: string[], error?: string): void {
|
||||
mockery.registerMock('http', { get: (url, callback) => {
|
||||
assert.equal(url, URL);
|
||||
|
||||
if (error) {
|
||||
return { on:
|
||||
(eventName, eventCallback) => {
|
||||
if (eventName === 'error') {
|
||||
eventCallback(error);
|
||||
}
|
||||
}};
|
||||
} else {
|
||||
callback({
|
||||
statusCode: 200,
|
||||
on: (eventName, eventCallback) => {
|
||||
if (eventName === 'data') {
|
||||
dataResponses.forEach(eventCallback);
|
||||
} else if (eventName === 'end') {
|
||||
setTimeout(eventCallback, 0);
|
||||
}
|
||||
}});
|
||||
|
||||
return { on: () => { }};
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
test('combines chunks', () => {
|
||||
// Create a mock http.get that provides data in two chunks
|
||||
registerMockHTTP(['res', 'ponse']);
|
||||
return getUtilities().getURL(URL).then(response => {
|
||||
assert.equal(response, RESPONSE);
|
||||
});
|
||||
});
|
||||
|
||||
test('rejects the promise on an error', () => {
|
||||
registerMockHTTP(undefined, 'fail');
|
||||
return getUtilities().getURL(URL).then(
|
||||
response => {
|
||||
assert.fail('Should not be resolved');
|
||||
},
|
||||
e => {
|
||||
assert.equal(e, 'fail');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('isURL', () => {
|
||||
function assertIsURL(url: string): void {
|
||||
assert(getUtilities().isURL(url));
|
||||
}
|
||||
|
||||
function assertNotURL(url: string): void {
|
||||
assert(!getUtilities().isURL(url));
|
||||
}
|
||||
|
||||
test('returns true for URLs', () => {
|
||||
assertIsURL('http://localhost');
|
||||
assertIsURL('http://mysite.com');
|
||||
assertIsURL('file:///c:/project/code.js');
|
||||
assertIsURL('webpack:///webpack/webpackthing');
|
||||
assertIsURL('https://a.b.c:123/asdf?fsda');
|
||||
});
|
||||
|
||||
test('returns false for not-URLs', () => {
|
||||
assertNotURL('a');
|
||||
assertNotURL('/project/code.js');
|
||||
assertNotURL('c:/project/code.js');
|
||||
assertNotURL('abc123!@#');
|
||||
assertNotURL('');
|
||||
assertNotURL(null);
|
||||
});
|
||||
});
|
||||
|
||||
suite('lstrip', () => {
|
||||
test('does what it says', () => {
|
||||
assert.equal(getUtilities().lstrip('test', 'te'), 'st');
|
||||
assert.equal(getUtilities().lstrip('asdf', ''), 'asdf');
|
||||
assert.equal(getUtilities().lstrip('asdf', null), 'asdf');
|
||||
assert.equal(getUtilities().lstrip('asdf', 'asdf'), '');
|
||||
assert.equal(getUtilities().lstrip('asdf', '123'), 'asdf');
|
||||
assert.equal(getUtilities().lstrip('asdf', 'sdf'), 'asdf');
|
||||
});
|
||||
});
|
||||
|
||||
suite('pathToFileURL', () => {
|
||||
test('converts windows-style paths', () => {
|
||||
assert.equal(getUtilities().pathToFileURL('c:\\code\\app.js'), 'file:///c:/code/app.js');
|
||||
});
|
||||
|
||||
test('converts unix-style paths', () => {
|
||||
assert.equal(getUtilities().pathToFileURL('/code/app.js'), 'file:///code/app.js');
|
||||
});
|
||||
|
||||
test('encodes as URI and forces forwards slash', () => {
|
||||
assert.equal(getUtilities().pathToFileURL('c:\\path with spaces\\blah.js'), 'file:///c:/path%20with%20spaces/blah.js');
|
||||
});
|
||||
});
|
||||
});
|
Загрузка…
Ссылка в новой задаче