| import { Observable } from '../Observable'; | 
| import { Notification } from '../Notification'; | 
| import { ColdObservable } from './ColdObservable'; | 
| import { HotObservable } from './HotObservable'; | 
| import { SubscriptionLog } from './SubscriptionLog'; | 
| import { VirtualTimeScheduler, VirtualAction } from '../scheduler/VirtualTimeScheduler'; | 
| import { AsyncScheduler } from '../scheduler/AsyncScheduler'; | 
| const defaultMaxFrame = 750; | 
| export class TestScheduler extends VirtualTimeScheduler { | 
|     constructor(assertDeepEqual) { | 
|         super(VirtualAction, defaultMaxFrame); | 
|         this.assertDeepEqual = assertDeepEqual; | 
|         this.hotObservables = []; | 
|         this.coldObservables = []; | 
|         this.flushTests = []; | 
|         this.runMode = false; | 
|     } | 
|     createTime(marbles) { | 
|         const indexOf = marbles.indexOf('|'); | 
|         if (indexOf === -1) { | 
|             throw new Error('marble diagram for time should have a completion marker "|"'); | 
|         } | 
|         return indexOf * TestScheduler.frameTimeFactor; | 
|     } | 
|     createColdObservable(marbles, values, error) { | 
|         if (marbles.indexOf('^') !== -1) { | 
|             throw new Error('cold observable cannot have subscription offset "^"'); | 
|         } | 
|         if (marbles.indexOf('!') !== -1) { | 
|             throw new Error('cold observable cannot have unsubscription marker "!"'); | 
|         } | 
|         const messages = TestScheduler.parseMarbles(marbles, values, error, undefined, this.runMode); | 
|         const cold = new ColdObservable(messages, this); | 
|         this.coldObservables.push(cold); | 
|         return cold; | 
|     } | 
|     createHotObservable(marbles, values, error) { | 
|         if (marbles.indexOf('!') !== -1) { | 
|             throw new Error('hot observable cannot have unsubscription marker "!"'); | 
|         } | 
|         const messages = TestScheduler.parseMarbles(marbles, values, error, undefined, this.runMode); | 
|         const subject = new HotObservable(messages, this); | 
|         this.hotObservables.push(subject); | 
|         return subject; | 
|     } | 
|     materializeInnerObservable(observable, outerFrame) { | 
|         const messages = []; | 
|         observable.subscribe((value) => { | 
|             messages.push({ frame: this.frame - outerFrame, notification: Notification.createNext(value) }); | 
|         }, (err) => { | 
|             messages.push({ frame: this.frame - outerFrame, notification: Notification.createError(err) }); | 
|         }, () => { | 
|             messages.push({ frame: this.frame - outerFrame, notification: Notification.createComplete() }); | 
|         }); | 
|         return messages; | 
|     } | 
|     expectObservable(observable, subscriptionMarbles = null) { | 
|         const actual = []; | 
|         const flushTest = { actual, ready: false }; | 
|         const subscriptionParsed = TestScheduler.parseMarblesAsSubscriptions(subscriptionMarbles, this.runMode); | 
|         const subscriptionFrame = subscriptionParsed.subscribedFrame === Number.POSITIVE_INFINITY ? | 
|             0 : subscriptionParsed.subscribedFrame; | 
|         const unsubscriptionFrame = subscriptionParsed.unsubscribedFrame; | 
|         let subscription; | 
|         this.schedule(() => { | 
|             subscription = observable.subscribe(x => { | 
|                 let value = x; | 
|                 if (x instanceof Observable) { | 
|                     value = this.materializeInnerObservable(value, this.frame); | 
|                 } | 
|                 actual.push({ frame: this.frame, notification: Notification.createNext(value) }); | 
|             }, (err) => { | 
|                 actual.push({ frame: this.frame, notification: Notification.createError(err) }); | 
|             }, () => { | 
|                 actual.push({ frame: this.frame, notification: Notification.createComplete() }); | 
|             }); | 
|         }, subscriptionFrame); | 
|         if (unsubscriptionFrame !== Number.POSITIVE_INFINITY) { | 
|             this.schedule(() => subscription.unsubscribe(), unsubscriptionFrame); | 
|         } | 
|         this.flushTests.push(flushTest); | 
|         const { runMode } = this; | 
|         return { | 
|             toBe(marbles, values, errorValue) { | 
|                 flushTest.ready = true; | 
|                 flushTest.expected = TestScheduler.parseMarbles(marbles, values, errorValue, true, runMode); | 
|             } | 
|         }; | 
|     } | 
|     expectSubscriptions(actualSubscriptionLogs) { | 
|         const flushTest = { actual: actualSubscriptionLogs, ready: false }; | 
|         this.flushTests.push(flushTest); | 
|         const { runMode } = this; | 
|         return { | 
|             toBe(marbles) { | 
|                 const marblesArray = (typeof marbles === 'string') ? [marbles] : marbles; | 
|                 flushTest.ready = true; | 
|                 flushTest.expected = marblesArray.map(marbles => TestScheduler.parseMarblesAsSubscriptions(marbles, runMode)); | 
|             } | 
|         }; | 
|     } | 
|     flush() { | 
|         const hotObservables = this.hotObservables; | 
|         while (hotObservables.length > 0) { | 
|             hotObservables.shift().setup(); | 
|         } | 
|         super.flush(); | 
|         this.flushTests = this.flushTests.filter(test => { | 
|             if (test.ready) { | 
|                 this.assertDeepEqual(test.actual, test.expected); | 
|                 return false; | 
|             } | 
|             return true; | 
|         }); | 
|     } | 
|     static parseMarblesAsSubscriptions(marbles, runMode = false) { | 
|         if (typeof marbles !== 'string') { | 
|             return new SubscriptionLog(Number.POSITIVE_INFINITY); | 
|         } | 
|         const len = marbles.length; | 
|         let groupStart = -1; | 
|         let subscriptionFrame = Number.POSITIVE_INFINITY; | 
|         let unsubscriptionFrame = Number.POSITIVE_INFINITY; | 
|         let frame = 0; | 
|         for (let i = 0; i < len; i++) { | 
|             let nextFrame = frame; | 
|             const advanceFrameBy = (count) => { | 
|                 nextFrame += count * this.frameTimeFactor; | 
|             }; | 
|             const c = marbles[i]; | 
|             switch (c) { | 
|                 case ' ': | 
|                     if (!runMode) { | 
|                         advanceFrameBy(1); | 
|                     } | 
|                     break; | 
|                 case '-': | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '(': | 
|                     groupStart = frame; | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case ')': | 
|                     groupStart = -1; | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '^': | 
|                     if (subscriptionFrame !== Number.POSITIVE_INFINITY) { | 
|                         throw new Error('found a second subscription point \'^\' in a ' + | 
|                             'subscription marble diagram. There can only be one.'); | 
|                     } | 
|                     subscriptionFrame = groupStart > -1 ? groupStart : frame; | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '!': | 
|                     if (unsubscriptionFrame !== Number.POSITIVE_INFINITY) { | 
|                         throw new Error('found a second subscription point \'^\' in a ' + | 
|                             'subscription marble diagram. There can only be one.'); | 
|                     } | 
|                     unsubscriptionFrame = groupStart > -1 ? groupStart : frame; | 
|                     break; | 
|                 default: | 
|                     if (runMode && c.match(/^[0-9]$/)) { | 
|                         if (i === 0 || marbles[i - 1] === ' ') { | 
|                             const buffer = marbles.slice(i); | 
|                             const match = buffer.match(/^([0-9]+(?:\.[0-9]+)?)(ms|s|m) /); | 
|                             if (match) { | 
|                                 i += match[0].length - 1; | 
|                                 const duration = parseFloat(match[1]); | 
|                                 const unit = match[2]; | 
|                                 let durationInMs; | 
|                                 switch (unit) { | 
|                                     case 'ms': | 
|                                         durationInMs = duration; | 
|                                         break; | 
|                                     case 's': | 
|                                         durationInMs = duration * 1000; | 
|                                         break; | 
|                                     case 'm': | 
|                                         durationInMs = duration * 1000 * 60; | 
|                                         break; | 
|                                     default: | 
|                                         break; | 
|                                 } | 
|                                 advanceFrameBy(durationInMs / this.frameTimeFactor); | 
|                                 break; | 
|                             } | 
|                         } | 
|                     } | 
|                     throw new Error('there can only be \'^\' and \'!\' markers in a ' + | 
|                         'subscription marble diagram. Found instead \'' + c + '\'.'); | 
|             } | 
|             frame = nextFrame; | 
|         } | 
|         if (unsubscriptionFrame < 0) { | 
|             return new SubscriptionLog(subscriptionFrame); | 
|         } | 
|         else { | 
|             return new SubscriptionLog(subscriptionFrame, unsubscriptionFrame); | 
|         } | 
|     } | 
|     static parseMarbles(marbles, values, errorValue, materializeInnerObservables = false, runMode = false) { | 
|         if (marbles.indexOf('!') !== -1) { | 
|             throw new Error('conventional marble diagrams cannot have the ' + | 
|                 'unsubscription marker "!"'); | 
|         } | 
|         const len = marbles.length; | 
|         const testMessages = []; | 
|         const subIndex = runMode ? marbles.replace(/^[ ]+/, '').indexOf('^') : marbles.indexOf('^'); | 
|         let frame = subIndex === -1 ? 0 : (subIndex * -this.frameTimeFactor); | 
|         const getValue = typeof values !== 'object' ? | 
|             (x) => x : | 
|             (x) => { | 
|                 if (materializeInnerObservables && values[x] instanceof ColdObservable) { | 
|                     return values[x].messages; | 
|                 } | 
|                 return values[x]; | 
|             }; | 
|         let groupStart = -1; | 
|         for (let i = 0; i < len; i++) { | 
|             let nextFrame = frame; | 
|             const advanceFrameBy = (count) => { | 
|                 nextFrame += count * this.frameTimeFactor; | 
|             }; | 
|             let notification; | 
|             const c = marbles[i]; | 
|             switch (c) { | 
|                 case ' ': | 
|                     if (!runMode) { | 
|                         advanceFrameBy(1); | 
|                     } | 
|                     break; | 
|                 case '-': | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '(': | 
|                     groupStart = frame; | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case ')': | 
|                     groupStart = -1; | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '|': | 
|                     notification = Notification.createComplete(); | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '^': | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 case '#': | 
|                     notification = Notification.createError(errorValue || 'error'); | 
|                     advanceFrameBy(1); | 
|                     break; | 
|                 default: | 
|                     if (runMode && c.match(/^[0-9]$/)) { | 
|                         if (i === 0 || marbles[i - 1] === ' ') { | 
|                             const buffer = marbles.slice(i); | 
|                             const match = buffer.match(/^([0-9]+(?:\.[0-9]+)?)(ms|s|m) /); | 
|                             if (match) { | 
|                                 i += match[0].length - 1; | 
|                                 const duration = parseFloat(match[1]); | 
|                                 const unit = match[2]; | 
|                                 let durationInMs; | 
|                                 switch (unit) { | 
|                                     case 'ms': | 
|                                         durationInMs = duration; | 
|                                         break; | 
|                                     case 's': | 
|                                         durationInMs = duration * 1000; | 
|                                         break; | 
|                                     case 'm': | 
|                                         durationInMs = duration * 1000 * 60; | 
|                                         break; | 
|                                     default: | 
|                                         break; | 
|                                 } | 
|                                 advanceFrameBy(durationInMs / this.frameTimeFactor); | 
|                                 break; | 
|                             } | 
|                         } | 
|                     } | 
|                     notification = Notification.createNext(getValue(c)); | 
|                     advanceFrameBy(1); | 
|                     break; | 
|             } | 
|             if (notification) { | 
|                 testMessages.push({ frame: groupStart > -1 ? groupStart : frame, notification }); | 
|             } | 
|             frame = nextFrame; | 
|         } | 
|         return testMessages; | 
|     } | 
|     run(callback) { | 
|         const prevFrameTimeFactor = TestScheduler.frameTimeFactor; | 
|         const prevMaxFrames = this.maxFrames; | 
|         TestScheduler.frameTimeFactor = 1; | 
|         this.maxFrames = Number.POSITIVE_INFINITY; | 
|         this.runMode = true; | 
|         AsyncScheduler.delegate = this; | 
|         const helpers = { | 
|             cold: this.createColdObservable.bind(this), | 
|             hot: this.createHotObservable.bind(this), | 
|             flush: this.flush.bind(this), | 
|             expectObservable: this.expectObservable.bind(this), | 
|             expectSubscriptions: this.expectSubscriptions.bind(this), | 
|         }; | 
|         try { | 
|             const ret = callback(helpers); | 
|             this.flush(); | 
|             return ret; | 
|         } | 
|         finally { | 
|             TestScheduler.frameTimeFactor = prevFrameTimeFactor; | 
|             this.maxFrames = prevMaxFrames; | 
|             this.runMode = false; | 
|             AsyncScheduler.delegate = undefined; | 
|         } | 
|     } | 
| } | 
| //# sourceMappingURL=TestScheduler.js.map |