From f06433fb58df390fbed17abc274e666afb3d207e Mon Sep 17 00:00:00 2001 From: vsavkin Date: Tue, 25 Nov 2014 15:16:53 -0800 Subject: [PATCH] feat(test_lib): implement SpyObject --- .../test/compiler/element_injector_spec.js | 14 +++---- modules/facade/src/lang.es6 | 1 + modules/rtts_assert/src/rtts_assert.es6 | 13 +++++- modules/test_lib/src/test_lib.dart | 1 + modules/test_lib/src/test_lib.es6 | 41 +++++++++++++++++++ modules/test_lib/test/test_lib_spec.js | 31 +++++++++++++- tools/transpiler/spec/interfaces_spec.js | 28 +++++++------ 7 files changed, 107 insertions(+), 22 deletions(-) diff --git a/modules/core/test/compiler/element_injector_spec.js b/modules/core/test/compiler/element_injector_spec.js index 96023b5cbb..09ec73e0aa 100644 --- a/modules/core/test/compiler/element_injector_spec.js +++ b/modules/core/test/compiler/element_injector_spec.js @@ -1,5 +1,5 @@ -import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, FakeObject} from 'test_lib/test_lib'; -import {isBlank, isPresent, FIELD, IMPLEMENTS} from 'facade/lang'; +import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, SpyObject} from 'test_lib/test_lib'; +import {isBlank, isPresent, FIELD, IMPLEMENTS, proxy} from 'facade/lang'; import {ListWrapper, MapWrapper, List} from 'facade/collection'; import {ProtoElementInjector, PreBuiltObjects} from 'core/compiler/element_injector'; import {Parent, Ancestor} from 'core/annotations/visibility'; @@ -9,12 +9,10 @@ import {ProtoRecordRange} from 'change_detection/record_range'; import {ViewPort} from 'core/compiler/viewport'; import {NgElement} from 'core/dom/element'; -//TODO: vsavkin: use a spy object -class DummyView extends View { - constructor() { - super(null, null, new ProtoRecordRange(), MapWrapper.create()); - } -} +@proxy +@IMPLEMENTS(View) +class DummyView extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}} + class Directive { } diff --git a/modules/facade/src/lang.es6 b/modules/facade/src/lang.es6 index 30fb0d4e57..20048d89a1 100644 --- a/modules/facade/src/lang.es6 +++ b/modules/facade/src/lang.es6 @@ -1,4 +1,5 @@ import {assert} from 'rtts_assert/rtts_assert'; +export {proxy} from 'rtts_assert/rtts_assert'; export var Type = Function; export var Math = window.Math; diff --git a/modules/rtts_assert/src/rtts_assert.es6 b/modules/rtts_assert/src/rtts_assert.es6 index 5ba6712fb1..fb6f258239 100644 --- a/modules/rtts_assert/src/rtts_assert.es6 +++ b/modules/rtts_assert/src/rtts_assert.es6 @@ -13,6 +13,9 @@ function argPositionName(i) { var primitives = $traceurRuntime.type; +export function proxy(){ +} + function assertArgumentTypes(...params) { var actual, type; var currentArgErrors; @@ -78,11 +81,14 @@ function prettyPrint(value) { } function isType(value, T, errors) { - if (T === primitives.void) { return typeof value === 'undefined'; } + if (_isProxy(value)) { + return true; + } + if (T === primitives.any || value === null) { return true; } @@ -143,6 +149,11 @@ function isType(value, T, errors) { // return res; } +function _isProxy(obj) { + if (!obj || !obj.constructor || !obj.constructor.annotations) return false; + return obj.constructor.annotations.filter((a) => a instanceof proxy).length > 0; +} + function formatErrors(errors, indent = ' ') { return errors.map((e) => { if (typeof e === 'string') return indent + '- ' + e; diff --git a/modules/test_lib/src/test_lib.dart b/modules/test_lib/src/test_lib.dart index c6692d1c69..2f85243ec5 100644 --- a/modules/test_lib/src/test_lib.dart +++ b/modules/test_lib/src/test_lib.dart @@ -24,6 +24,7 @@ class Expect extends gns.Expect { void toEqual(expected) => toHaveSameProps(expected); void toThrowError([message=""]) => this.toThrowWith(message: message); void toBePromise() => _expect(actual is Future, equals(true)); + void toImplement(expected) => toBeA(expected); Function get _expect => gns.guinness.matchers.expect; } diff --git a/modules/test_lib/src/test_lib.es6 b/modules/test_lib/src/test_lib.es6 index 48e35aae7c..2a1b76c841 100644 --- a/modules/test_lib/src/test_lib.es6 +++ b/modules/test_lib/src/test_lib.es6 @@ -73,10 +73,51 @@ window.beforeEach(function() { }; } }; + }, + + toImplement: function() { + return { + compare: function(actualObject, expectedInterface) { + var objProps = Object.keys(actualObject.constructor.prototype); + var intProps = Object.keys(expectedInterface.prototype); + + var missedMethods = []; + intProps.forEach((k) => { + if (!actualObject.constructor.prototype[k]) missedMethods.push(k); + }); + + return { + pass: missedMethods.length == 0, + get message() { + return 'Expected ' + actualObject + ' to have the following methods: ' + missedMethods.join(", "); + } + }; + } + }; } }); }); +export class SpyObject { + spy(name){ + if (! this[name]) { + this[name] = this._createGuinnessCompatibleSpy(); + } + return this[name]; + } + + rttsAssert(value) { + return true; + } + + _createGuinnessCompatibleSpy(){ + var newSpy = jasmine.createSpy(); + newSpy.andCallFake = newSpy.and.callFake; + return newSpy; + } +} + + function mapToString(m) { if (!m) { return ''+m; diff --git a/modules/test_lib/test/test_lib_spec.js b/modules/test_lib/test/test_lib_spec.js index e5bc44d3d0..d1d04db2b9 100644 --- a/modules/test_lib/test/test_lib_spec.js +++ b/modules/test_lib/test/test_lib_spec.js @@ -1,6 +1,7 @@ -import {describe, it, iit, ddescribe, expect, tick, async} from 'test_lib/test_lib'; +import {describe, it, iit, ddescribe, expect, tick, async, SpyObject, beforeEach} from 'test_lib/test_lib'; import {MapWrapper, ListWrapper} from 'facade/collection'; import {PromiseWrapper} from 'facade/async'; +import {IMPLEMENTS, proxy} from 'facade/lang'; class TestObj { prop; @@ -9,6 +10,10 @@ class TestObj { } } +@proxy +@IMPLEMENTS(TestObj) +class SpyTestObj extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} + export function main() { describe('test_lib', () => { describe('equality', () => { @@ -48,5 +53,29 @@ export function main() { expect(MapWrapper.createFromStringMap({'a': 1})).not.toEqual(MapWrapper.createFromStringMap({'a': 1, 'b': 1})); }); }); + + describe("spy objects", () => { + var spyObj; + + beforeEach(() => { + spyObj = new SpyTestObj(); + }); + + it("should pass the runtime check", () => { + var t:TestObj = spyObj; + expect(t).toBeDefined(); + }); + + it("should return a new spy func with no calls", () => { + expect(spyObj.spy("someFunc")).not.toHaveBeenCalled(); + }); + + it("should record function calls", () => { + spyObj.spy("someFunc").andCallFake((a,b) => a + b); + + expect(spyObj.someFunc(1,2)).toEqual(3); + expect(spyObj.spy("someFunc")).toHaveBeenCalledWith(1,2); + }); + }); }); } \ No newline at end of file diff --git a/tools/transpiler/spec/interfaces_spec.js b/tools/transpiler/spec/interfaces_spec.js index 40a62ec968..c88ceff562 100644 --- a/tools/transpiler/spec/interfaces_spec.js +++ b/tools/transpiler/spec/interfaces_spec.js @@ -1,22 +1,26 @@ -import {ddescribe, describe, it, expect, IS_DARTIUM} from 'test_lib/test_lib'; +import {ddescribe, describe, it, iit, expect, IS_DARTIUM} from 'test_lib/test_lib'; import {IMPLEMENTS} from './fixtures/annotations'; -class Interface1 {} -class Interface2 {} +class Interface1 { + one(){} +} +class Interface2 { + two(){} +} @IMPLEMENTS(Interface1, Interface2) -class SomeClass {} +class SomeClass { + one(){} + two(){} +} export function main() { describe('interfaces', function() { - //TODO: remvoe when interfaces are supported in AtScript - if (IS_DARTIUM) { - it('should work', function () { - var s = new SomeClass(); - expect(s instanceof Interface1).toBeTrue(); - expect(s instanceof Interface2).toBeTrue(); - }); - } + it('should work', function () { + var s = new SomeClass(); + expect(s).toImplement(Interface1); + expect(s).toImplement(Interface2); + }); }); }