-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1883 from blesh/sequenceEqual
feat(sequenceEqual): adds sequenceEqual operator
- Loading branch information
Showing
6 changed files
with
538 additions
and
0 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
perf/micro/immediate-scheduler/operators/sequenceEqual-comparor.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
var RxOld = require('rx'); | ||
var RxNew = require('../../../../index'); | ||
|
||
module.exports = function (suite) { | ||
function comparor(a, b) { | ||
return a.value === b.value; | ||
} | ||
|
||
var values = [1, 2, 3, 4, 5, 6, 7, 8].map(function (x) { return { value: x }; }); | ||
|
||
var _old = RxOld.Observable.of.apply(null, values.concat(RxOld.Scheduler.immediate)) | ||
.sequenceEqual(RxOld.Observable.of.apply(null, values.concat(RxOld.Scheduler.immediate)), comparor); | ||
var _new = RxNew.Observable.of.apply(null, values).sequenceEqual(RxNew.Observable.of.apply(null, values), comparor); | ||
|
||
function _next(x) { } | ||
function _error(e) { } | ||
function _complete() { } | ||
return suite | ||
.add('old sequenceEqual with comparor with immediate scheduler', function () { | ||
_old.subscribe(_next, _error, _complete); | ||
}) | ||
.add('new sequenceEqual with comparor with immediate scheduler', function () { | ||
_new.subscribe(_next, _error, _complete); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
var RxOld = require('rx'); | ||
var RxNew = require('../../../../index'); | ||
|
||
module.exports = function (suite) { | ||
var _old = RxOld.Observable.range(0, 25, RxOld.Scheduler.immediate) | ||
.sequenceEqual(RxOld.Observable.range(0, 25, RxOld.Scheduler.immediate)); | ||
var _new = RxNew.Observable.range(0, 25).sequenceEqual(RxNew.Observable.range(0, 25)); | ||
|
||
function _next(x) { } | ||
function _error(e) { } | ||
function _complete() { } | ||
return suite | ||
.add('old sequenceEqual with immediate scheduler', function () { | ||
_old.subscribe(_next, _error, _complete); | ||
}) | ||
.add('new sequenceEqual with immediate scheduler', function () { | ||
_new.subscribe(_next, _error, _complete); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,317 @@ | ||
declare const {rxTestScheduler, time, type}; | ||
|
||
const booleans = { T: true, F: false }; | ||
|
||
/** @test {sequenceEqual} */ | ||
describe('Observable.prototype.sequenceEqual', () => { | ||
asDiagram('sequenceEqual(observable)')('should return true for two equal sequences', () => { | ||
const s1 = hot('--a--^--b--c--d--e--f--g--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^-----b--c--d-e-f------g-|'); | ||
const s2subs = '^ !'; | ||
const expected = '-------------------------(T|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return false for two sync observables that are unequal in length', () => { | ||
const s1 = cold('(abcdefg|)'); | ||
const s2 = cold('(abc|)'); | ||
const expected = '(F|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
}); | ||
|
||
it('should return true for two sync observables that match', () => { | ||
const s1 = cold('(abcdefg|)'); | ||
const s2 = cold('(abcdefg|)'); | ||
const expected = '(T|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
}); | ||
|
||
it('should return true for two observables that match when the last one emits and completes in the same frame', () => { | ||
const s1 = hot('--a--^--b--c--d--e--f--g--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--b--c--d--e--f--g------|'); | ||
const s2subs = '^ !'; | ||
const expected = '-------------------------(T|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return true for two observables that match when the last one emits and completes in the same frame', () => { | ||
const s1 = hot('--a--^--b--c--d--e--f--g--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--b--c--d--e--f---------(g|)'); | ||
const s2subs = '^ !'; | ||
const expected = '-------------------------(T|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should error with an errored source', () => { | ||
const s1 = hot('--a--^--b---c---#'); | ||
const s2 = hot('--a--^--b---c-----|'); | ||
const expected = '-----------#'; | ||
const sub = '^ !'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(sub); | ||
expectSubscriptions(s2.subscriptions).toBe(sub); | ||
}); | ||
|
||
it('should error with an errored compareTo', () => { | ||
const s1 = hot('--a--^--b---c-----|'); | ||
const s2 = hot('--a--^--b---c---#'); | ||
const expected = '-----------#'; | ||
const sub = '^ !'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(sub); | ||
expectSubscriptions(s2.subscriptions).toBe(sub); | ||
}); | ||
|
||
it('should error if the source is a throw', () => { | ||
const s1 = cold('#'); // throw | ||
const s2 = cold('---a--b--c--|'); | ||
const expected = '#'; // throw | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected); | ||
}); | ||
|
||
it('should never return if source is a never', () => { | ||
const s1 = cold('------------'); // never | ||
const s2 = cold('--a--b--c--|'); | ||
const expected = '------------'; // never | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected); | ||
}); | ||
|
||
it('should never return if compareTo is a never', () => { | ||
const s1 = cold('--a--b--c--|'); | ||
const s2 = cold('------------'); // never | ||
const expected = '------------'; // never | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected); | ||
}); | ||
|
||
it('should return false if source is empty and compareTo is not', () => { | ||
const s1 = cold('|'); // empty | ||
const s2 = cold('------a------'); | ||
const expected = '------(F|)'; | ||
const subs = '^ !'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(subs); | ||
expectSubscriptions(s2.subscriptions).toBe(subs); | ||
}); | ||
|
||
it('should return false if compareTo is empty and source is not', () => { | ||
const s1 = cold('------a------'); | ||
const s2 = cold('|'); // empty | ||
const expected = '------(F|)'; | ||
const subs = '^ !'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(subs); | ||
expectSubscriptions(s2.subscriptions).toBe(subs); | ||
}); | ||
|
||
it('should return never if compareTo is empty and source is never', () => { | ||
const s1 = cold('-'); | ||
const s2 = cold('|'); | ||
const expected = '-'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected); | ||
}); | ||
|
||
it('should return never if source is empty and compareTo is never', () => { | ||
const s1 = cold('|'); | ||
const s2 = cold('-'); | ||
const expected = '-'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected); | ||
}); | ||
|
||
it('should error if the comparor errors', () => { | ||
const s1 = hot('--a--^--b-----c------d--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--------x---y---z-------|'); | ||
const s2subs = '^ !'; | ||
const expected = '-------------#'; | ||
|
||
let i = 0; | ||
const source = s1.sequenceEqual(s2, (a: any, b: any) => { | ||
if (++i === 2) { | ||
throw new Error('shazbot'); | ||
} | ||
return a.value === b.value; | ||
}); | ||
|
||
const values = { | ||
a: null, | ||
b: { value: 'bees knees' }, | ||
c: { value: 'carpy dumb' }, | ||
d: { value: 'derp' }, | ||
x: { value: 'bees knees', foo: 'lol' }, | ||
y: { value: 'carpy dumb', scooby: 'doo' }, | ||
z: { value: 'derp', weCouldBe: 'dancin, yeah' } | ||
}; | ||
|
||
expectObservable(source).toBe(expected, Object.assign({}, booleans, values), new Error('shazbot')); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should use the provided comparor', () => { | ||
const s1 = hot('--a--^--b-----c------d--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--------x---y---z-------|'); | ||
const s2subs = '^ !'; | ||
const expected = '-------------------------(T|)'; | ||
|
||
const source = s1.sequenceEqual(s2, (a: any, b: any) => a.value === b.value); | ||
|
||
const values = { | ||
a: null, | ||
b: { value: 'bees knees' }, | ||
c: { value: 'carpy dumb' }, | ||
d: { value: 'derp' }, | ||
x: { value: 'bees knees', foo: 'lol' }, | ||
y: { value: 'carpy dumb', scooby: 'doo' }, | ||
z: { value: 'derp', weCouldBe: 'dancin, yeah' } | ||
}; | ||
|
||
expectObservable(source).toBe(expected, Object.assign({}, booleans, values)); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return false for two unequal sequences, compareTo finishing last', () => { | ||
const s1 = hot('--a--^--b--c--d--e--f--g--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^-----b--c--d-e-f------z-|'); | ||
const s2subs = '^ !'; | ||
const expected = '-----------------------(F|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return false for two unequal sequences, early wrong value from source', () => { | ||
const s1 = hot('--a--^--b--c---x-----------|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--b--c--d--e--f--|'); | ||
const s2subs = '^ !'; | ||
const expected = '----------(F|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return false when the source emits an extra value after the compareTo completes', () => { | ||
const s1 = hot('--a--^--b--c--d--e--f--g--h--|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--b--c--d-|'); | ||
const s2subs = '^ !'; | ||
const expected = '------------(F|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return false when the compareTo emits an extra value after the source completes', () => { | ||
const s1 = hot('--a--^--b--c--d-|'); | ||
const s1subs = '^ !'; | ||
const s2 = hot('-----^--b--c--d--e--f--g--h--|'); | ||
const s2subs = '^ !'; | ||
const expected = '------------(F|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
|
||
expectObservable(source).toBe(expected, booleans); | ||
expectSubscriptions(s1.subscriptions).toBe(s1subs); | ||
expectSubscriptions(s2.subscriptions).toBe(s2subs); | ||
}); | ||
|
||
it('should return true for two empty observables', () => { | ||
const s1 = cold('|'); | ||
const s2 = cold('|'); | ||
const expected = '(T|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
expectObservable(source).toBe(expected, booleans); | ||
}); | ||
|
||
it('should return false for an empty observable and an observable that emits', () => { | ||
const s1 = cold('|'); | ||
const s2 = cold('---a--|'); | ||
const expected = '---(F|)'; | ||
|
||
const source = s1.sequenceEqual(s2); | ||
expectObservable(source).toBe(expected, booleans); | ||
}); | ||
|
||
it('should return compare hot and cold observables', () => { | ||
const s1 = hot('---a--^---b---c---d---e---f---g---h---i---j---|'); | ||
const s2 = cold( '----b---c-|'); | ||
const expected1 = '------------(F|)'; | ||
const subs1 = '^ !'; | ||
const delay = '-------------------|'; | ||
const s3 = cold( '-f---g---h---i---j---|'); | ||
const expected2 = ' ---------------------(T|)'; | ||
const subs2 = ' ^ !'; | ||
|
||
const test1 = s1.sequenceEqual(s2); | ||
const test2 = s1.sequenceEqual(s3); | ||
|
||
expectObservable(test1).toBe(expected1, booleans); | ||
rxTestScheduler.schedule(() => expectObservable(test2).toBe(expected2, booleans), time(delay)); | ||
expectSubscriptions(s2.subscriptions).toBe(subs1); | ||
expectSubscriptions(s3.subscriptions).toBe(subs2); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
import {Observable} from '../../Observable'; | ||
import {sequenceEqual, SequenceEqualSignature} from '../../operator/sequenceEqual'; | ||
|
||
Observable.prototype.sequenceEqual = sequenceEqual; | ||
|
||
declare module '../../Observable' { | ||
interface Observable<T> { | ||
sequenceEqual: SequenceEqualSignature<T>; | ||
} | ||
} |
Oops, something went wrong.