diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 37897df..55775de 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,13 +4,17 @@ "isShellCommand": true, "tasks": [ { - "taskName": "ts-watch", + "taskName": "watch", "args": [], "isBuildCommand": true, "isWatching": true, "problemMatcher": [ "$tsc" ] + }, + { + "taskName": "build-test-watch", + "isWatching": true } ] } \ No newline at end of file diff --git a/adapter/adapterProxy.ts b/adapter/adapterProxy.ts index 528f5d0..8ad3465 100644 --- a/adapter/adapterProxy.ts +++ b/adapter/adapterProxy.ts @@ -37,7 +37,7 @@ export class AdapterProxy { return request.command in transformer ? p.then(() => transformer[request.command](request.arguments)) : p; - }, Promise.resolve()) + }, Promise.resolve()); } /** diff --git a/gulpfile.js b/gulpfile.js index 2c609f3..e70f0a6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -8,13 +8,14 @@ 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'); var sources = [ 'adapter', 'common', - 'node', - 'webkit', + 'test', 'typings', + 'webkit', ].map(function(tsFolder) { return tsFolder + '/**/*.ts'; }); var projectConfig = { @@ -26,16 +27,30 @@ var projectConfig = { }; gulp.task('build', function () { - gulp.src(sources, { base: '.' }) + return gulp.src(sources, { base: '.' }) .pipe(sourcemaps.init()) .pipe(ts(projectConfig)) .pipe(sourcemaps.write('.', { includeContent: false, sourceRoot: '/opendebug-webkit' })) .pipe(gulp.dest('out')); }); -gulp.task('ts-watch', ['build'], function(cb) { +gulp.task('watch', ['build'], function(cb) { log('Watching build sources...'); - gulp.watch(sources, ['build']); + return gulp.watch(sources, ['build']); }); gulp.task('default', ['build']); + + +function test() { + return gulp.src('out/test/**/*.test.js', { read: false }) + .pipe(mocha()) + .on('error', function() { }); +} + +gulp.task('build-test', ['build'], test); +gulp.task('test', test); + +gulp.task('watch-build-test', ['build', 'build-test'], function(cb) { + return gulp.watch(sources, ['build', 'build-test']); +}); diff --git a/package.json b/package.json index a893b5f..23c597e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "name": "Microsoft Corporation, Visual Studio Code Team" }, "publisher": "Microsoft", - "engines": { "vscode": "*" }, + "engines": { + "vscode": "*" + }, "license": "", "dependencies": { "ws": "^0.7.2", @@ -14,20 +16,28 @@ }, "devDependencies": { "gulp": "^3.9.0", + "gulp-mocha": "^2.1.3", "gulp-sourcemaps": "^1.5.2", "gulp-typescript": "^2.8.0", "gulp-util": "^3.0.5", + "mocha": "^2.3.3", "tsd": "^0.6.3", "typescript": "^1.6.2" }, "contributes": { - "debugAdapter": [ - { - "type": "webkit", - "enableBreakpointsFor": { "languageIds": ["javascript", "typescript", "coffeescript"] }, - "program": "./out/webkit/openDebugWebkit.js", - "runtime": "node" - } - ] - } + "debugAdapter": [ + { + "type": "webkit", + "enableBreakpointsFor": { + "languageIds": [ + "javascript", + "typescript", + "coffeescript" + ] + }, + "program": "./out/webkit/openDebugWebkit.js", + "runtime": "node" + } + ] + } } diff --git a/test/adapter/lineNumberTransformer.test.ts b/test/adapter/lineNumberTransformer.test.ts new file mode 100644 index 0000000..771b1e5 --- /dev/null +++ b/test/adapter/lineNumberTransformer.test.ts @@ -0,0 +1,86 @@ +/// + +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + +import assert = require('assert'); +import { LineNumberTransformer } from '../../adapter/lineNumberTransformer'; + +function createTransformer(clientLinesStartAt1: boolean, targetLinesStartAt1: boolean): LineNumberTransformer { + const transformer = new LineNumberTransformer(targetLinesStartAt1); + transformer.initialize({ linesStartAt1: clientLinesStartAt1 }); + + return transformer; +} + +describe('LineNumberTransformer', () => { + const c0t0Transformer = createTransformer(false, false); + const c0t1Transformer = createTransformer(false, true); + const c1t0Transformer = createTransformer(true, false); + const c1t1Transformer = createTransformer(true, true); + + describe('setBreakpoints()', () => { + function getArgs(lines: number[]): DebugProtocol.SetBreakpointsArguments { + return { + source: { path: "test/path" }, + lines + }; + } + + function testSetBreakpoints(transformer: LineNumberTransformer, cLines: number[], tLines: number[] = cLines): void { + const args = getArgs(cLines); + transformer.setBreakpoints(args); + assert.deepEqual(args, getArgs(tLines)); + } + + it('fixes args.lines', () => { + testSetBreakpoints(c0t0Transformer, [0, 1, 2]); + testSetBreakpoints(c0t1Transformer, [0, 1, 2], [1, 2, 3]); + testSetBreakpoints(c1t0Transformer, [1, 2, 3], [0, 1, 2]); + testSetBreakpoints(c1t1Transformer, [1, 2, 3]); + }); + }); + + describe('setBreakpointsResponse()', () => { + function getResponse(lines: number[]): SetBreakpointsResponseBody { + return { + breakpoints: lines.map(line => ({ verified: true, line: line })) + }; + } + + function testSetBreakpointsResponse(transformer: LineNumberTransformer, tLines: number[], cLines: number[] = tLines): void { + const response = getResponse(tLines); + transformer.setBreakpointsResponse(response); + assert.deepEqual(response, getResponse(cLines)); + } + + it('fixes the breakpoints\' lines', () => { + testSetBreakpointsResponse(c0t0Transformer, [0, 1, 2]); + testSetBreakpointsResponse(c0t1Transformer, [1, 2, 3], [0, 1, 2]); + testSetBreakpointsResponse(c1t0Transformer, [0, 1, 2], [1, 2, 3]); + testSetBreakpointsResponse(c1t1Transformer, [1, 2, 3]); + }); + }); + + describe('stackTraceResponse', () => { + function getResponse(lines: number[]): StackTraceResponseBody { + return { + stackFrames: lines.map(line => ({ id: 0, name: '', line, column: 0 })) + }; + } + + function testStackTraceResponse(transformer: LineNumberTransformer, tLines: number[], cLines: number[] = tLines): void { + const response = getResponse(tLines); + transformer.stackTraceResponse(response); + assert.deepEqual(response, getResponse(cLines)); + } + + it('fixes the stackFrames\' lines', () => { + testStackTraceResponse(c0t0Transformer, [0, 1, 2]); + testStackTraceResponse(c0t1Transformer, [1, 2, 3], [0, 1, 2]); + testStackTraceResponse(c1t0Transformer, [0, 1, 2], [1, 2, 3]); + testStackTraceResponse(c1t1Transformer, [1, 2, 3]); + }) + }); +}); \ No newline at end of file diff --git a/typings/mocha/mocha.d.ts b/typings/mocha/mocha.d.ts new file mode 100644 index 0000000..b4f182a --- /dev/null +++ b/typings/mocha/mocha.d.ts @@ -0,0 +1,220 @@ +// Type definitions for mocha 2.2.5 +// Project: http://mochajs.org/ +// Definitions by: Kazi Manzur Rashid , otiai10 , jt000 , Vadim Macagon +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +interface MochaSetupOptions { + //milliseconds to wait before considering a test slow + slow?: number; + + // timeout in milliseconds + timeout?: number; + + // ui name "bdd", "tdd", "exports" etc + ui?: string; + + //array of accepted globals + globals?: any[]; + + // reporter instance (function or string), defaults to `mocha.reporters.Spec` + reporter?: any; + + // bail on the first test failure + bail?: boolean; + + // ignore global leaks + ignoreLeaks?: boolean; + + // grep string or regexp to filter tests with + grep?: any; +} + +interface MochaDone { + (error?: Error): void; +} + +declare var mocha: Mocha; +declare var describe: Mocha.IContextDefinition; +declare var xdescribe: Mocha.IContextDefinition; +// alias for `describe` +declare var context: Mocha.IContextDefinition; +// alias for `describe` +declare var suite: Mocha.IContextDefinition; +declare var it: Mocha.ITestDefinition; +declare var xit: Mocha.ITestDefinition; +// alias for `it` +declare var test: Mocha.ITestDefinition; + +declare function before(action: () => void): void; + +declare function before(action: (done: MochaDone) => void): void; + +declare function setup(action: () => void): void; + +declare function setup(action: (done: MochaDone) => void): void; + +declare function after(action: () => void): void; + +declare function after(action: (done: MochaDone) => void): void; + +declare function teardown(action: () => void): void; + +declare function teardown(action: (done: MochaDone) => void): void; + +declare function beforeEach(action: () => void): void; + +declare function beforeEach(action: (done: MochaDone) => void): void; + +declare function suiteSetup(action: () => void): void; + +declare function suiteSetup(action: (done: MochaDone) => void): void; + +declare function afterEach(action: () => void): void; + +declare function afterEach(action: (done: MochaDone) => void): void; + +declare function suiteTeardown(action: () => void): void; + +declare function suiteTeardown(action: (done: MochaDone) => void): void; + +declare class Mocha { + constructor(options?: { + grep?: RegExp; + ui?: string; + reporter?: string; + timeout?: number; + bail?: boolean; + }); + + /** Setup mocha with the given options. */ + setup(options: MochaSetupOptions): Mocha; + bail(value?: boolean): Mocha; + addFile(file: string): Mocha; + /** Sets reporter by name, defaults to "spec". */ + reporter(name: string): Mocha; + /** Sets reporter constructor, defaults to mocha.reporters.Spec. */ + reporter(reporter: (runner: Mocha.IRunner, options: any) => any): Mocha; + ui(value: string): Mocha; + grep(value: string): Mocha; + grep(value: RegExp): Mocha; + invert(): Mocha; + ignoreLeaks(value: boolean): Mocha; + checkLeaks(): Mocha; + /** + * Function to allow assertion libraries to throw errors directly into mocha. + * This is useful when running tests in a browser because window.onerror will + * only receive the 'message' attribute of the Error. + */ + throwError(error: Error): void; + /** Enables growl support. */ + growl(): Mocha; + globals(value: string): Mocha; + globals(values: string[]): Mocha; + useColors(value: boolean): Mocha; + useInlineDiffs(value: boolean): Mocha; + timeout(value: number): Mocha; + slow(value: number): Mocha; + enableTimeouts(value: boolean): Mocha; + asyncOnly(value: boolean): Mocha; + noHighlighting(value: boolean): Mocha; + /** Runs tests and invokes `onComplete()` when finished. */ + run(onComplete?: (failures: number) => void): Mocha.IRunner; +} + +// merge the Mocha class declaration with a module +declare module Mocha { + /** Partial interface for Mocha's `Runnable` class. */ + interface IRunnable { + title: string; + fn: Function; + async: boolean; + sync: boolean; + timedOut: boolean; + } + + /** Partial interface for Mocha's `Suite` class. */ + interface ISuite { + parent: ISuite; + title: string; + + fullTitle(): string; + } + + /** Partial interface for Mocha's `Test` class. */ + interface ITest extends IRunnable { + parent: ISuite; + pending: boolean; + + fullTitle(): string; + } + + /** Partial interface for Mocha's `Runner` class. */ + interface IRunner {} + + interface IContextDefinition { + (description: string, spec: () => void): ISuite; + only(description: string, spec: () => void): ISuite; + skip(description: string, spec: () => void): void; + timeout(ms: number): void; + } + + interface ITestDefinition { + (expectation: string, assertion?: () => void): ITest; + (expectation: string, assertion?: (done: MochaDone) => void): ITest; + only(expectation: string, assertion?: () => void): ITest; + only(expectation: string, assertion?: (done: MochaDone) => void): ITest; + skip(expectation: string, assertion?: () => void): void; + skip(expectation: string, assertion?: (done: MochaDone) => void): void; + timeout(ms: number): void; + } + + export module reporters { + export class Base { + stats: { + suites: number; + tests: number; + passes: number; + pending: number; + failures: number; + }; + + constructor(runner: IRunner); + } + + export class Doc extends Base {} + export class Dot extends Base {} + export class HTML extends Base {} + export class HTMLCov extends Base {} + export class JSON extends Base {} + export class JSONCov extends Base {} + export class JSONStream extends Base {} + export class Landing extends Base {} + export class List extends Base {} + export class Markdown extends Base {} + export class Min extends Base {} + export class Nyan extends Base {} + export class Progress extends Base { + /** + * @param options.open String used to indicate the start of the progress bar. + * @param options.complete String used to indicate a complete test on the progress bar. + * @param options.incomplete String used to indicate an incomplete test on the progress bar. + * @param options.close String used to indicate the end of the progress bar. + */ + constructor(runner: IRunner, options?: { + open?: string; + complete?: string; + incomplete?: string; + close?: string; + }); + } + export class Spec extends Base {} + export class TAP extends Base {} + export class XUnit extends Base { + constructor(runner: IRunner, options?: any); + } + } +} + +declare module "mocha" { + export = Mocha; +} diff --git a/typings/tsd.d.ts b/typings/tsd.d.ts index 00a755f..65062b0 100644 --- a/typings/tsd.d.ts +++ b/typings/tsd.d.ts @@ -1,5 +1,6 @@ /// /// +/// /// /// ///