Skip to content

Commit f4ba4c6

Browse files
dbrattliclaude
andcommitted
test(operators): add regression tests for scheduler propagation
Cover pairwise, to_marbles, and delay_with_mapper (subscription-delay path): each test installs a source whose subscribe captures the scheduler it received, pipes through the operator, subscribes with a known scheduler, and asserts the captured scheduler matches. Verified to fail on the pre-fix code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 33c4f58 commit f4ba4c6

3 files changed

Lines changed: 80 additions & 1 deletion

File tree

tests/test_observable/test_delaywithmapper.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import unittest
22

3+
from reactivex import Observable, abc
34
from reactivex import operators as ops
5+
from reactivex.disposable import Disposable
6+
from reactivex.scheduler import ImmediateScheduler
47
from reactivex.testing import ReactiveTest, TestScheduler
58

69
on_next = ReactiveTest.on_next
@@ -199,3 +202,37 @@ def create():
199202
assert results.messages == [on_next(210 + 50, 2)]
200203
assert xs.subscriptions == [subscribe(200, 300)]
201204
assert ys.subscriptions == [subscribe(210, 260)]
205+
206+
def test_delay_with_mapper_forwards_scheduler_to_subscription_delay(
207+
self,
208+
) -> None:
209+
captured: dict[str, abc.SchedulerBase | None] = {}
210+
expected: abc.SchedulerBase = ImmediateScheduler()
211+
212+
def sub_delay_subscribe(
213+
observer: abc.ObserverBase[int],
214+
scheduler: abc.SchedulerBase | None = None,
215+
) -> abc.DisposableBase:
216+
captured["scheduler"] = scheduler
217+
observer.on_completed()
218+
return Disposable()
219+
220+
sub_delay: Observable[int] = Observable(sub_delay_subscribe)
221+
222+
def source_subscribe(
223+
observer: abc.ObserverBase[int],
224+
scheduler: abc.SchedulerBase | None = None,
225+
) -> abc.DisposableBase:
226+
observer.on_completed()
227+
return Disposable()
228+
229+
source: Observable[int] = Observable(source_subscribe)
230+
231+
def mapper(_: int) -> Observable[int]:
232+
return source
233+
234+
source.pipe(ops.delay_with_mapper(sub_delay, mapper)).subscribe(
235+
scheduler=expected
236+
)
237+
238+
assert captured["scheduler"] is expected

tests/test_observable/test_marbles.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
import unittest
33

44
import reactivex
5-
from reactivex import notification
5+
from reactivex import Observable, abc, notification
6+
from reactivex import operators as ops
7+
from reactivex.disposable import Disposable
68
from reactivex.observable.marbles import parse
9+
from reactivex.scheduler import ImmediateScheduler
710
from reactivex.testing import TestScheduler
811
from reactivex.testing.reactivetest import ReactiveTest
912

@@ -578,3 +581,22 @@ def test_hot_marble_with_timedelta(self):
578581
ReactiveTest.on_completed(300.7),
579582
]
580583
assert results == expected
584+
585+
586+
class TestToMarbles(unittest.TestCase):
587+
def test_to_marbles_forwards_scheduler_to_source(self) -> None:
588+
captured: dict[str, abc.SchedulerBase | None] = {}
589+
expected: abc.SchedulerBase = ImmediateScheduler()
590+
591+
def source_subscribe(
592+
observer: abc.ObserverBase[int],
593+
scheduler: abc.SchedulerBase | None = None,
594+
) -> abc.DisposableBase:
595+
captured["scheduler"] = scheduler
596+
observer.on_completed()
597+
return Disposable()
598+
599+
source: Observable[int] = Observable(source_subscribe)
600+
source.pipe(ops.to_marbles()).subscribe(scheduler=expected)
601+
602+
assert captured["scheduler"] is expected

tests/test_observable/test_pairwise.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import unittest
22

3+
from reactivex import Observable, abc
34
from reactivex import operators as ops
5+
from reactivex.disposable import Disposable
6+
from reactivex.scheduler import ImmediateScheduler
47
from reactivex.testing import ReactiveTest, TestScheduler
58

69
on_next = ReactiveTest.on_next
@@ -134,3 +137,20 @@ def create():
134137
assert results.messages == [on_next(240, (4, 3))]
135138

136139
assert xs.subscriptions == [subscribe(200, 280)]
140+
141+
def test_pairwise_forwards_scheduler_to_source(self) -> None:
142+
captured: dict[str, abc.SchedulerBase | None] = {}
143+
expected: abc.SchedulerBase = ImmediateScheduler()
144+
145+
def source_subscribe(
146+
observer: abc.ObserverBase[int],
147+
scheduler: abc.SchedulerBase | None = None,
148+
) -> abc.DisposableBase:
149+
captured["scheduler"] = scheduler
150+
observer.on_completed()
151+
return Disposable()
152+
153+
source: Observable[int] = Observable(source_subscribe)
154+
source.pipe(ops.pairwise()).subscribe(scheduler=expected)
155+
156+
assert captured["scheduler"] is expected

0 commit comments

Comments
 (0)