Skip to content

Commit

Permalink
Make Event and TestEvent sealed classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
renggli committed May 13, 2023
1 parent d87e5ba commit 36dec77
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 206 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# Changelog

## 0.3.0 (Unpublished)

- Dart 3.0 requirement.
- Make `Event` and `TestEvent` sealed classes.

## 0.2.0

- Dart 2.17 requirement
- Dart 2.17 requirement.
- Add a redux like store, and example.
- Add `race` constructor.
- Add `takeUntil` and `skipUntil` operators.
Expand Down
23 changes: 0 additions & 23 deletions lib/src/events/complete.dart

This file was deleted.

29 changes: 0 additions & 29 deletions lib/src/events/error.dart

This file was deleted.

77 changes: 73 additions & 4 deletions lib/src/events/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import 'package:meta/meta.dart';
import 'package:more/functional.dart';

import '../core/observer.dart';
import 'complete.dart';
import 'error.dart';
import 'next.dart';

/// Abstract immutable event object of type `T.
@immutable
abstract class Event<T> {
sealed class Event<T> {
/// Default constructor for events.
const Event();

Expand Down Expand Up @@ -76,3 +73,75 @@ abstract class Event<T> {
/// Performs this event on the [observer].
void observe(Observer<T> observer);
}

/// Event with value of type `T`.
class NextEvent<T> extends Event<T> {
const NextEvent(this.value);

@override
bool get isNext => true;

@override
final T value;

@override
void observe(Observer<T> observer) => observer.next(value);

@override
bool operator ==(Object other) =>
identical(this, other) || (other is NextEvent && value == other.value);

@override
int get hashCode => value.hashCode;

@override
String toString() => 'NextEvent<$T>(value: $value)';
}

/// Event of an error with optional stack trace of a sequence of type `T`.
class ErrorEvent<T> extends Event<T> {
const ErrorEvent(this.error, this.stackTrace);

@override
bool get isError => true;

@override
final Object error;

@override
final StackTrace stackTrace;

@override
void observe(Observer<T> observer) => observer.error(error, stackTrace);

@override
bool operator ==(Object other) =>
identical(this, other) || (other is ErrorEvent && error == other.error);

@override
int get hashCode => error.hashCode;

@override
String toString() => 'ErrorEvent<$T>(error: $error, stackTrace: $stackTrace)';
}

/// Event of the completion of a sequence of type `T`.
class CompleteEvent<T> extends Event<T> {
const CompleteEvent();

@override
bool get isComplete => true;

@override
void observe(Observer<T> observer) => observer.complete();

@override
bool operator ==(Object other) =>
identical(this, other) || other is CompleteEvent;

@override
int get hashCode => 34822;

@override
String toString() => 'CompleteEvent<$T>()';
}
26 changes: 0 additions & 26 deletions lib/src/events/next.dart

This file was deleted.

6 changes: 4 additions & 2 deletions lib/src/testing/cold_observable.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import '../core/observer.dart';
import '../disposables/disposable.dart';
import 'test_events.dart';
import 'test_observable.dart';

class ColdObservable<T> extends TestObservable<T> {
Expand All @@ -8,9 +9,10 @@ class ColdObservable<T> extends TestObservable<T> {
@override
Disposable subscribe(Observer<T> observer) {
final subscriber = createSubscriber(observer);
for (final event in sequence.events) {
for (final event in sequence.events.whereType<WrappedEvent<T>>()) {
final timestamp = scheduler.now.add(scheduler.stepDuration * event.index);
scheduler.scheduleAbsolute(timestamp, () => event.observe(subscriber));
scheduler.scheduleAbsolute(
timestamp, () => event.event.observe(subscriber));
}
return subscriber;
}
Expand Down
8 changes: 4 additions & 4 deletions lib/src/testing/hot_observable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ class HotObservable<T> extends TestObservable<T> {
HotObservable(TestScheduler scheduler, TestEventSequence<T> sequence)
: super(scheduler, sequence) {
final subscriptionIndex = sequence.events
.where((element) => element.event is SubscribeEvent)
.map((element) => element.index)
.whereType<SubscribeEvent<T>>()
.map((event) => event.index)
.firstWhere((index) => true, orElse: () => 0);
for (final event in sequence.events) {
for (final event in sequence.events.whereType<WrappedEvent<T>>()) {
final timestamp = scheduler.now
.add(scheduler.stepDuration * (event.index - subscriptionIndex));
scheduler.scheduleAbsolute(timestamp, () => event.observe(subject));
scheduler.scheduleAbsolute(timestamp, () => event.event.observe(subject));
}
}

Expand Down
70 changes: 32 additions & 38 deletions lib/src/testing/test_event_sequence.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,34 +48,30 @@ class TestEventSequence<T> {
withinGroup = false;
break;
case subscribeMarker:
if (sequence
.where((element) => element.event is SubscribeEvent)
.isNotEmpty) {
if (sequence.whereType<SubscribeEvent<T>>().isNotEmpty) {
throw ArgumentError.value(
marbles, 'marbles', 'Repeated subscription.');
}
sequence.add(TestEvent(index, const SubscribeEvent()));
sequence.add(SubscribeEvent(index));
break;
case unsubscribeMarker:
if (sequence
.where((element) => element.event is UnsubscribeEvent)
.isNotEmpty) {
if (sequence.whereType<UnsubscribeEvent<T>>().isNotEmpty) {
throw ArgumentError.value(
marbles, 'marbles', 'Repeated unsubscription.');
}
sequence.add(TestEvent(index, const UnsubscribeEvent()));
sequence.add(UnsubscribeEvent(index));
break;
case completeMarker:
sequence.add(TestEvent(index, Event<T>.complete()));
sequence.add(WrappedEvent<T>(index, Event<T>.complete()));
break;
case errorMarker:
sequence
.add(TestEvent(index, Event<T>.error(error, StackTrace.current)));
sequence.add(WrappedEvent<T>(
index, Event<T>.error(error, StackTrace.current)));
break;
default:
final marble = marbles[i];
final value = values.containsKey(marble) ? values[marble] : marble;
sequence.add(TestEvent(index, Event<T>.next(value as T)));
sequence.add(WrappedEvent<T>(index, Event<T>.next(value as T)));
break;
}
if (!withinGroup) {
Expand All @@ -91,8 +87,9 @@ class TestEventSequence<T> {
/// Sequence of [TestEvent] instances.
final List<TestEvent<T>> events;

/// Sequence of [Event] instances (unwrapping the test events).
Iterable<Event<T>> get baseEvents => events.map((value) => value.event);
/// Sequence of [Event] instances.
Iterable<Event<T>> get baseEvents =>
events.whereType<WrappedEvent<T>>().map((value) => value.event);

/// Optional mapping from marble tokens to objects.
final BiMap<String, T> values;
Expand All @@ -115,30 +112,27 @@ class TestEventSequence<T> {
buffer.write(groupStartMarker);
}
for (final eventAtIndex in eventsAtIndex) {
final event = eventAtIndex.event;
if (event is SubscribeEvent) {
buffer.write(subscribeMarker);
} else if (event is UnsubscribeEvent) {
buffer.write(unsubscribeMarker);
} else if (event.isComplete) {
buffer.write(completeMarker);
} else if (event.isError) {
buffer.write(errorMarker);
} else if (event.isNext) {
final value = event.value;
if (values.containsValue(value)) {
buffer.write(values.inverse[value]);
} else {
final unusedCharacter = value is String && value.length == 1
? value
: nextMarkers
.toList()
.firstWhere((char) => !values.containsKey(char));
values[unusedCharacter] = value;
buffer.write(unusedCharacter);
}
} else {
throw ArgumentError.value(event, 'event');
switch (eventAtIndex) {
case WrappedEvent<T>(event: NextEvent<T>(value: final value)):
if (values.containsValue(value)) {
buffer.write(values.inverse[value]);
} else {
final unusedCharacter = value is String && value.length == 1
? value
: nextMarkers
.toList()
.firstWhere((char) => !values.containsKey(char));
values[unusedCharacter] = value;
buffer.write(unusedCharacter);
}
case WrappedEvent<T>(event: ErrorEvent<T>()):
buffer.write(errorMarker);
case WrappedEvent<T>(event: CompleteEvent<T>()):
buffer.write(completeMarker);
case SubscribeEvent<T>():
buffer.write(subscribeMarker);
case UnsubscribeEvent<T>():
buffer.write(unsubscribeMarker);
}
}
if (eventsAtIndex.length > 1) {
Expand Down
Loading

0 comments on commit 36dec77

Please sign in to comment.