Merge branch 'feat/nullsafety-stream-chat' of git://github.com/felangel/stream-chat-flutter into felangel-feat/nullsafety-stream-chat

This commit is contained in:
Sahil Kumar
2021-04-02 18:59:52 +05:30
40 changed files with 1662 additions and 1190 deletions
@@ -2,6 +2,6 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "self:">
</FileRef> </FileRef>
</Workspace> </Workspace>
+15 -16
View File
@@ -2,12 +2,9 @@ import 'package:flutter/material.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
Future<void> main() async { Future<void> main() async {
/// Create a new instance of [StreamChatClient] passing the apikey obtained from your /// Create a new instance of [StreamChatClient]
/// project dashboard. /// by passing the apikey obtained from your project dashboard.
final client = StreamChatClient( final client = StreamChatClient('b67pax5b2wdq', logLevel: Level.INFO);
'b67pax5b2wdq',
logLevel: Level.INFO,
);
/// Set the current user. In a production scenario, this should be done using /// Set the current user. In a production scenario, this should be done using
/// a backend to generate a user token using our server SDK. /// a backend to generate a user token using our server SDK.
@@ -21,7 +18,7 @@ Future<void> main() async {
'https://getstream.io/random_png/?id=cool-shadow-7&amp;name=Cool+shadow', 'https://getstream.io/random_png/?id=cool-shadow-7&amp;name=Cool+shadow',
}, },
), ),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo''',
); );
/// Creates a channel using the type `messaging` and `godevs`. /// Creates a channel using the type `messaging` and `godevs`.
@@ -44,15 +41,16 @@ Future<void> main() async {
/// Example using Stream's Low Level Dart client. /// Example using Stream's Low Level Dart client.
class StreamExample extends StatelessWidget { class StreamExample extends StatelessWidget {
/// To initialize this example, an instance of [client] and [channel] is required. /// To initialize this example, an instance of
/// [client] and [channel] is required.
const StreamExample({ const StreamExample({
Key key, Key key,
@required this.client, @required this.client,
@required this.channel, @required this.channel,
}) : super(key: key); }) : super(key: key);
/// Instance of [StreamChatClient] we created earlier. This contains information about /// Instance of [StreamChatClient] we created earlier.
/// our application and connection state. /// This contains information about our application and connection state.
final StreamChatClient client; final StreamChatClient client;
/// The channel we'd like to observe and participate. /// The channel we'd like to observe and participate.
@@ -104,8 +102,8 @@ class HomeScreen extends StatelessWidget {
} }
return const Center( return const Center(
child: SizedBox( child: SizedBox(
width: 100.0, width: 100,
height: 100.0, height: 100,
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
); );
@@ -180,7 +178,7 @@ class _MessageViewState extends State<MessageView> {
return Align( return Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text(item.text), child: Text(item.text),
), ),
); );
@@ -188,7 +186,7 @@ class _MessageViewState extends State<MessageView> {
return Align( return Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text(item.text), child: Text(item.text),
), ),
); );
@@ -197,7 +195,7 @@ class _MessageViewState extends State<MessageView> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@@ -245,7 +243,8 @@ class _MessageViewState extends State<MessageView> {
} }
} }
/// Helper extension for quickly retrieving the current user id from a [StreamChatClient]. /// Helper extension for quickly retrieving
/// the current user id from a [StreamChatClient].
extension on StreamChatClient { extension on StreamChatClient {
String get uid => state.user.id; String get uid => state.user.id;
} }
+5 -4
View File
@@ -1,21 +1,22 @@
name: example name: example
description: A new Flutter project. description: A new Flutter project.
publish_to: 'none' publish_to: "none"
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
dependencies: dependencies:
cupertino_icons: ^1.0.0
flutter: flutter:
sdk: flutter sdk: flutter
cupertino_icons: ^1.0.0 stream_chat:
stream_chat:
path: ../ path: ../
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter: flutter:
uses-material-design: true uses-material-design: true
@@ -352,7 +352,7 @@ class Channel {
state?.addMessage(response.message); state?.addMessage(response.message);
return response; return response;
} catch (error) { } catch (error) {
if (error is DioError && error.type != DioErrorType.RESPONSE) { if (error is DioError && error.type != DioErrorType.response) {
state?.retryQueue?.add([message]); state?.retryQueue?.add([message]);
} }
rethrow; rethrow;
@@ -405,7 +405,7 @@ class Channel {
)); ));
return response; return response;
} catch (error) { } catch (error) {
if (error is DioError && error.type != DioErrorType.RESPONSE) { if (error is DioError && error.type != DioErrorType.response) {
state?.retryQueue?.add([message]); state?.retryQueue?.add([message]);
} }
rethrow; rethrow;
@@ -446,7 +446,7 @@ class Channel {
return response; return response;
} catch (error) { } catch (error) {
if (error is DioError && error.type != DioErrorType.RESPONSE) { if (error is DioError && error.type != DioErrorType.response) {
state?.retryQueue?.add([message]); state?.retryQueue?.add([message]);
} }
rethrow; rethrow;
@@ -74,7 +74,7 @@ class RetryQueue {
} catch (error) { } catch (error) {
ApiError apiError; ApiError apiError;
if (error is DioError) { if (error is DioError) {
if (error.type == DioErrorType.RESPONSE) { if (error.type == DioErrorType.response) {
_messageQueue.remove(message); _messageQueue.remove(message);
return; return;
} }
+35 -15
View File
@@ -252,7 +252,7 @@ class StreamChatClient {
this.httpClient.options.connectTimeout = connectTimeout.inMilliseconds; this.httpClient.options.connectTimeout = connectTimeout.inMilliseconds;
this.httpClient.interceptors.add( this.httpClient.interceptors.add(
InterceptorsWrapper( InterceptorsWrapper(
onRequest: (options) async { onRequest: (options, handler) async {
options.queryParameters.addAll(_commonQueryParams); options.queryParameters.addAll(_commonQueryParams);
options.headers.addAll(_httpHeaders); options.headers.addAll(_httpHeaders);
@@ -280,15 +280,17 @@ class StreamChatClient {
data: $stringData data: $stringData
'''); ''');
handler.next(options);
return options;
}, },
onError: _tokenExpiredInterceptor, onError: _tokenExpiredInterceptor,
), ),
); );
} }
Future<void> _tokenExpiredInterceptor(DioError err) async { Future<void> _tokenExpiredInterceptor(
DioError err,
ErrorInterceptorHandler handler,
) async {
final apiError = ApiError( final apiError = ApiError(
err.response?.data, err.response?.data,
err.response?.statusCode, err.response?.statusCode,
@@ -312,17 +314,35 @@ class StreamChatClient {
await connectUser(User(id: userId), newToken); await connectUser(User(id: userId), newToken);
try { try {
return await httpClient.request( handler.resolve(
err.request.path, await httpClient.request(
cancelToken: err.request.cancelToken, err.requestOptions.path,
data: err.request.data, cancelToken: err.requestOptions.cancelToken,
onReceiveProgress: err.request.onReceiveProgress, data: err.requestOptions.data,
onSendProgress: err.request.onSendProgress, onReceiveProgress: err.requestOptions.onReceiveProgress,
queryParameters: err.request.queryParameters, onSendProgress: err.requestOptions.onSendProgress,
options: err.request, queryParameters: err.requestOptions.queryParameters,
options: Options(
method: err.requestOptions.method,
sendTimeout: err.requestOptions.sendTimeout,
receiveTimeout: err.requestOptions.receiveTimeout,
extra: err.requestOptions.extra,
headers: err.requestOptions.headers,
responseType: err.requestOptions.responseType,
contentType: err.requestOptions.contentType,
validateStatus: err.requestOptions.validateStatus,
receiveDataWhenStatusError:
err.requestOptions.receiveDataWhenStatusError,
followRedirects: err.requestOptions.followRedirects,
maxRedirects: err.requestOptions.maxRedirects,
requestEncoder: err.requestOptions.requestEncoder,
responseDecoder: err.requestOptions.responseDecoder,
listFormat: err.requestOptions.listFormat,
),
),
); );
} catch (err) { } catch (err) {
return err; handler.reject(err);
} }
} }
} }
@@ -784,7 +804,7 @@ class StreamChatClient {
} }
Object _parseError(DioError error) { Object _parseError(DioError error) {
if (error.type == DioErrorType.RESPONSE) { if (error.type == DioErrorType.response) {
final apiError = final apiError =
ApiError(error.response?.data, error.response?.statusCode); ApiError(error.response?.data, error.response?.statusCode);
logger.severe('apiError: ${apiError.toString()}'); logger.severe('apiError: ${apiError.toString()}');
@@ -931,7 +951,7 @@ class StreamChatClient {
_connectCompleter = Completer(); _connectCompleter = Completer();
_anonymous = true; _anonymous = true;
final uuid = Uuid(); const uuid = Uuid();
state.user = OwnUser(id: uuid.v4()); state.user = OwnUser(id: uuid.v4());
return connect().then((event) { return connect().then((event) {
@@ -35,7 +35,7 @@ class Attachment {
this.extraData, this.extraData,
this.file, this.file,
UploadState uploadState, UploadState uploadState,
}) : id = id ?? Uuid().v4(), }) : id = id ?? const Uuid().v4(),
title = title ?? file?.name, title = title ?? file?.name,
localUri = file?.path != null ? Uri.parse(file.path) : null { localUri = file?.path != null ? Uri.parse(file.path) : null {
this.uploadState = uploadState ?? this.uploadState = uploadState ??
@@ -73,7 +73,7 @@ class Message {
this.deletedAt, this.deletedAt,
this.status = MessageSendingStatus.sent, this.status = MessageSendingStatus.sent,
this.skipPush, this.skipPush,
}) : id = id ?? Uuid().v4(), }) : id = id ?? const Uuid().v4(),
pinExpires = pinExpires?.toUtc(); pinExpires = pinExpires?.toUtc();
/// Create a new instance from a json /// Create a new instance from a json
+16 -16
View File
@@ -9,22 +9,22 @@ environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
dependencies: dependencies:
async: ^2.4.2 async: ^2.5.0
collection: ^1.14.13 collection: ^1.15.0
dio: ^3.0.10 dio: ">=4.0.0-prev3 <4.0.0"
freezed_annotation: ^0.12.0 freezed_annotation: ^0.14.0
http_parser: ^3.1.4 http_parser: ^4.0.0
json_annotation: ^3.0.1 json_annotation: ^4.0.0
logging: ^0.11.4 logging: ^1.0.0
meta: ^1.2.4 meta: ^1.3.0
mime: ^0.9.7 mime: ^1.0.0
rxdart: ^0.25.0 rxdart: ^0.26.0
uuid: ^2.2.2 uuid: ^3.0.0
web_socket_channel: ^1.2.0 web_socket_channel: ^2.0.0
dev_dependencies: dev_dependencies:
build_runner: ^1.10.0 build_runner: ^1.10.0
freezed: ^0.12.7 freezed: ^0.14.0
json_serializable: ^3.3.0 json_serializable: ^4.0.0
mockito: ^4.1.1 mocktail: ^0.1.0
test: ^1.15.7 test: ^1.16.0
File diff suppressed because it is too large Load Diff
@@ -4,13 +4,13 @@ import 'package:stream_chat/stream_chat.dart';
void main() { void main() {
group('src/api/requests', () { group('src/api/requests', () {
test('SortOption', () { test('SortOption', () {
final option = SortOption('name'); const option = SortOption('name');
final j = option.toJson(); final j = option.toJson();
expect(j, {'field': 'name', 'direction': -1}); expect(j, {'field': 'name', 'direction': -1});
}); });
test('PaginationParams', () { test('PaginationParams', () {
final option = PaginationParams(); const option = PaginationParams();
final j = option.toJson(); final j = option.toJson();
expect(j, {'limit': 10, 'offset': 0}); expect(j, {'limit': 10, 'offset': 0});
}); });
@@ -3284,7 +3284,7 @@ void main() {
}); });
test('QueryReactionsResponse', () { test('QueryReactionsResponse', () {
const jsonExample = r''' const jsonExample = '''
{"reactions": [{"message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f","user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680","user": {"id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680","role": "user","created_at": "2020-01-28T22:17:30.83015Z","updated_at": "2020-01-28T22:17:31.19435Z","banned": false,"online": false,"image": "https://randomuser.me/api/portraits/women/2.jpg","name": "Mia Denys"},"type": "love","score": 1,"created_at": "2020-01-28T22:17:31.128376Z","updated_at": "2020-01-28T22:17:31.128376Z"}]} {"reactions": [{"message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f","user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680","user": {"id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680","role": "user","created_at": "2020-01-28T22:17:30.83015Z","updated_at": "2020-01-28T22:17:31.19435Z","banned": false,"online": false,"image": "https://randomuser.me/api/portraits/women/2.jpg","name": "Mia Denys"},"type": "love","score": 1,"created_at": "2020-01-28T22:17:31.128376Z","updated_at": "2020-01-28T22:17:31.128376Z"}]}
'''; ''';
final response = final response =
@@ -3402,31 +3402,31 @@ void main() {
test('ListDevicesResponse', () { test('ListDevicesResponse', () {
const jsonExample = const jsonExample =
r'''{"devices":[{"push_provider":"firebase","id":"test"}],"duration":"0.35ms"}'''; '''{"devices":[{"push_provider":"firebase","id":"test"}],"duration":"0.35ms"}''';
final response = ListDevicesResponse.fromJson(json.decode(jsonExample)); final response = ListDevicesResponse.fromJson(json.decode(jsonExample));
expect(response.devices, isA<List<Device>>()); expect(response.devices, isA<List<Device>>());
}); });
test('SendFileResponse', () { test('SendFileResponse', () {
const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; const jsonExample = '''{"file": "file-url","duration":"0.35ms"}''';
final response = SendFileResponse.fromJson(json.decode(jsonExample)); final response = SendFileResponse.fromJson(json.decode(jsonExample));
expect(response.file, isA<String>()); expect(response.file, isA<String>());
}); });
test('SendImageResponse', () { test('SendImageResponse', () {
const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; const jsonExample = '''{"file": "file-url","duration":"0.35ms"}''';
final response = SendImageResponse.fromJson(json.decode(jsonExample)); final response = SendImageResponse.fromJson(json.decode(jsonExample));
expect(response.file, isA<String>()); expect(response.file, isA<String>());
}); });
test('SendImageResponse', () { test('SendImageResponse', () {
const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; const jsonExample = '''{"file": "file-url","duration":"0.35ms"}''';
final response = SendImageResponse.fromJson(json.decode(jsonExample)); final response = SendImageResponse.fromJson(json.decode(jsonExample));
expect(response.file, isA<String>()); expect(response.file, isA<String>());
}); });
test('EmptyResponse', () { test('EmptyResponse', () {
const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; const jsonExample = '''{"file": "file-url","duration":"0.35ms"}''';
final response = EmptyResponse.fromJson(json.decode(jsonExample)); final response = EmptyResponse.fromJson(json.decode(jsonExample));
expect(response.duration, isA<String>()); expect(response.duration, isA<String>());
}); });
@@ -3481,8 +3481,7 @@ void main() {
}); });
test('UpdateUsersResponse', () { test('UpdateUsersResponse', () {
const jsonExample = const jsonExample = '''{"users": {"bbb19d9a-ee50-45bc-84e5-0584e79d0c9e":{
r'''{"users": {"bbb19d9a-ee50-45bc-84e5-0584e79d0c9e":{
"id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e",
"role": "user", "role": "user",
"created_at": "2020-01-28T22:17:30.826259Z", "created_at": "2020-01-28T22:17:30.826259Z",
@@ -3498,7 +3497,7 @@ void main() {
test('ConnectGuestUserResponse', () { test('ConnectGuestUserResponse', () {
const jsonExample = const jsonExample =
r'{"user":{"id":"guest-ac612aee-25fe-49fb-b1af-969e41f452a0-wild-breeze-7","role":"guest","created_at":"2020-02-03T10:19:01.538434Z","updated_at":"2020-02-03T10:19:01.539543Z","banned":false,"online":false},"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZ3Vlc3QtYWM2MTJhZWUtMjVmZS00OWZiLWIxYWYtOTY5ZTQxZjQ1MmEwLXdpbGQtYnJlZXplLTcifQ.mmoFGu7oJjpFsp7nFN78UbIpO7gowbuIbyoppsuvbXA","duration":"4.66ms"}'; '''{"user":{"id":"guest-ac612aee-25fe-49fb-b1af-969e41f452a0-wild-breeze-7","role":"guest","created_at":"2020-02-03T10:19:01.538434Z","updated_at":"2020-02-03T10:19:01.539543Z","banned":false,"online":false},"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZ3Vlc3QtYWM2MTJhZWUtMjVmZS00OWZiLWIxYWYtOTY5ZTQxZjQ1MmEwLXdpbGQtYnJlZXplLTcifQ.mmoFGu7oJjpFsp7nFN78UbIpO7gowbuIbyoppsuvbXA","duration":"4.66ms"}''';
final response = final response =
ConnectGuestUserResponse.fromJson(json.decode(jsonExample)); ConnectGuestUserResponse.fromJson(json.decode(jsonExample));
expect(response.user, isA<User>()); expect(response.user, isA<User>());
@@ -0,0 +1,11 @@
import 'package:test/test.dart';
import 'package:stream_chat/src/api/web_socket_channel_stub.dart';
void main() {
test('src/api/web_socket_stub_test', () {
expect(
() => connectWebSocket('fakeurl'),
throwsA(isA<UnimplementedError>()),
);
});
}
@@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:mockito/mockito.dart'; import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/api/connection_status.dart'; import 'package:stream_chat/src/api/connection_status.dart';
import 'package:stream_chat/src/api/websocket.dart'; import 'package:stream_chat/src/api/websocket.dart';
import 'package:stream_chat/src/models/event.dart'; import 'package:stream_chat/src/models/event.dart';
@@ -19,7 +19,7 @@ class Functions {
}) => }) =>
null; null;
void handleFunc(Event event) => null; void handleFunc(Event event) {}
} }
class MockFunctions extends Mock implements Functions {} class MockFunctions extends Mock implements Functions {}
@@ -28,35 +28,35 @@ class MockWSChannel extends Mock implements WebSocketChannel {}
class MockWSSink extends Mock implements WebSocketSink {} class MockWSSink extends Mock implements WebSocketSink {}
class FakeEvent extends Fake implements Event {}
void main() { void main() {
group('src/api/websocket', () { group('src/api/websocket', () {
setUpAll(() {
registerFallbackValue<Event>(FakeEvent());
});
test('should connect with correct parameters', () async { test('should connect with correct parameters', () async {
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
user: User(id: 'testid'), user: User(id: 'testid'),
logger: Logger('ws'), logger: Logger('ws'),
connectParams: {'test': 'true'}, connectParams: {'test': 'true'},
connectPayload: {'payload': 'test'}, connectPayload: {'payload': 'test'},
handler: (e) { handler: print,
print(e);
},
connectFunc: connectFunc, connectFunc: connectFunc,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final streamController = StreamController<String>.broadcast(); final streamController = StreamController<String>.broadcast();
const computedUrl = const computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); when(() => mockWSChannel.sink).thenAnswer((_) => MockWSSink());
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer(
return streamController.stream; (_) => streamController.stream,
}); );
final timer = Timer.periodic( final timer = Timer.periodic(
const Duration(milliseconds: 100), const Duration(milliseconds: 100),
@@ -65,7 +65,7 @@ void main() {
await ws.connect(); await ws.connect();
verify(connectFunc(computedUrl)).called(1); verify(() => connectFunc(computedUrl)).called(1);
expect(ws.connectionStatus, ConnectionStatus.connected); expect(ws.connectionStatus, ConnectionStatus.connected);
await streamController.close(); await streamController.close();
@@ -76,7 +76,6 @@ void main() {
test('should connect with correct parameters and handle events', () async { test('should connect with correct parameters and handle events', () async {
final handleFunc = MockFunctions().handleFunc; final handleFunc = MockFunctions().handleFunc;
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
user: User(id: 'testid'), user: User(id: 'testid'),
@@ -86,27 +85,21 @@ void main() {
handler: handleFunc, handler: handleFunc,
connectFunc: connectFunc, connectFunc: connectFunc,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final streamController = StreamController<String>.broadcast();
final StreamController<String> streamController = const computedUrl =
StreamController<String>.broadcast();
final computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); when(() => mockWSChannel.sink).thenAnswer((_) => MockWSSink());
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer((_) => streamController.stream);
return streamController.stream;
});
final connect = ws.connect().then((_) { final connect = ws.connect().then((_) {
streamController.sink.add('{}'); streamController.sink.add('{}');
return Future.delayed(Duration(milliseconds: 200)); return Future.delayed(const Duration(milliseconds: 200));
}).then((value) { }).then((value) {
verify(connectFunc(computedUrl)).called(1); verify(() => connectFunc(computedUrl)).called(1);
verify(handleFunc(any)).called(greaterThan(0)); verify(() => handleFunc(any())).called(greaterThan(0));
return streamController.close(); return streamController.close();
}); });
@@ -118,9 +111,7 @@ void main() {
test('should close correctly the controller', () async { test('should close correctly the controller', () async {
final handleFunc = MockFunctions().handleFunc; final handleFunc = MockFunctions().handleFunc;
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
user: User(id: 'testid'), user: User(id: 'testid'),
@@ -130,27 +121,21 @@ void main() {
handler: handleFunc, handler: handleFunc,
connectFunc: connectFunc, connectFunc: connectFunc,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final streamController = StreamController<String>.broadcast();
final StreamController<String> streamController = const computedUrl =
StreamController<String>.broadcast();
final computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); when(() => mockWSChannel.sink).thenAnswer((_) => MockWSSink());
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer((_) => streamController.stream);
return streamController.stream;
});
final connect = ws.connect().then((_) { final connect = ws.connect().then((_) {
streamController.sink.add('{}'); streamController.sink.add('{}');
return Future.delayed(Duration(milliseconds: 200)); return Future.delayed(const Duration(milliseconds: 200));
}).then((value) { }).then((value) {
verify(connectFunc(computedUrl)).called(1); verify(() => connectFunc(computedUrl)).called(1);
verify(handleFunc(any)).called(greaterThan(0)); verify(() => handleFunc(any())).called(greaterThan(0));
return streamController.close(); return streamController.close();
}); });
@@ -159,6 +144,7 @@ void main() {
return connect; return connect;
}); });
test('should close correctly the controller while connecting', () async { test('should close correctly the controller while connecting', () async {
final handleFunc = MockFunctions().handleFunc; final handleFunc = MockFunctions().handleFunc;
@@ -198,9 +184,7 @@ void main() {
test('should run correctly health check', () async { test('should run correctly health check', () async {
final handleFunc = MockFunctions().handleFunc; final handleFunc = MockFunctions().handleFunc;
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
user: User(id: 'testid'), user: User(id: 'testid'),
@@ -210,32 +194,27 @@ void main() {
handler: handleFunc, handler: handleFunc,
connectFunc: connectFunc, connectFunc: connectFunc,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final mockWSSink = MockWSSink(); final mockWSSink = MockWSSink();
final streamController = StreamController<String>.broadcast();
final StreamController<String> streamController = const computedUrl =
StreamController<String>.broadcast();
final computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer((_) => streamController.stream);
return streamController.stream; when(() => mockWSChannel.sink).thenReturn(mockWSSink);
});
when(mockWSChannel.sink).thenReturn(mockWSSink);
final timer = Timer.periodic( final timer = Timer.periodic(
Duration(milliseconds: 1000), const Duration(milliseconds: 1000),
(_) => streamController.sink.add('{}'), (_) => streamController.sink.add('{}'),
); );
final connect = ws.connect().then((_) { final connect = ws.connect().then((_) {
streamController.sink.add('{}'); streamController.sink.add('{}');
return Future.delayed(Duration(milliseconds: 200)); return Future.delayed(const Duration(milliseconds: 200));
}).then((value) async { }).then((value) async {
verify(mockWSSink.add("{'type': 'health.check'}")).called(greaterThan(0)); verify(() => mockWSSink.add("{'type': 'health.check'}"))
.called(greaterThan(0));
timer.cancel(); timer.cancel();
await streamController.close(); await streamController.close();
@@ -249,9 +228,7 @@ void main() {
test('should run correctly reconnection check', () async { test('should run correctly reconnection check', () async {
final handleFunc = MockFunctions().handleFunc; final handleFunc = MockFunctions().handleFunc;
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
Logger.root.level = Level.ALL; Logger.root.level = Level.ALL;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
@@ -262,34 +239,28 @@ void main() {
handler: handleFunc, handler: handleFunc,
connectFunc: connectFunc, connectFunc: connectFunc,
reconnectionMonitorTimeout: 1, reconnectionMonitorTimeout: 1,
reconnectionMonitorInterval: 1,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final mockWSSink = MockWSSink(); final mockWSSink = MockWSSink();
var streamController = StreamController<String>.broadcast();
StreamController<String> streamController = const computedUrl =
StreamController<String>.broadcast();
final computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer((_) => streamController.stream);
return streamController.stream; when(() => mockWSChannel.sink).thenReturn(mockWSSink);
});
when(mockWSChannel.sink).thenReturn(mockWSSink);
final connect = ws.connect().then((_) { final connect = ws.connect().then((_) {
streamController.sink.add('{}'); streamController.sink.add('{}');
streamController.close(); streamController.close();
streamController = StreamController<String>.broadcast(); streamController = StreamController<String>.broadcast();
streamController.sink.add('{}'); streamController.sink.add('{}');
return Future.delayed(Duration(milliseconds: 200)); return Future.delayed(const Duration(milliseconds: 200));
}).then((value) async { }).then((value) async {
verify(mockWSSink.add("{'type': 'health.check'}")).called(greaterThan(0)); verify(() => mockWSSink.add("{'type': 'health.check'}"))
.called(greaterThan(0));
verify(connectFunc(computedUrl)).called(2); verify(() => connectFunc(computedUrl)).called(2);
await streamController.close(); await streamController.close();
return mockWSSink.close(); return mockWSSink.close();
@@ -302,9 +273,7 @@ void main() {
test('should close correctly the controller', () async { test('should close correctly the controller', () async {
final handleFunc = MockFunctions().handleFunc; final handleFunc = MockFunctions().handleFunc;
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
user: User(id: 'testid'), user: User(id: 'testid'),
@@ -314,28 +283,22 @@ void main() {
handler: handleFunc, handler: handleFunc,
connectFunc: connectFunc, connectFunc: connectFunc,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final mockWSSink = MockWSSink(); final mockWSSink = MockWSSink();
final streamController = StreamController<String>.broadcast();
final StreamController<String> streamController = const computedUrl =
StreamController<String>.broadcast();
final computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer((_) => streamController.stream);
return streamController.stream; when(() => mockWSChannel.sink).thenReturn(mockWSSink);
});
when(mockWSChannel.sink).thenReturn(mockWSSink);
final connect = ws.connect().then((_) { final connect = ws.connect().then((_) {
streamController.sink.add('{}'); streamController.sink.add('{}');
return Future.delayed(Duration(milliseconds: 200)); return Future.delayed(const Duration(milliseconds: 200));
}).then((value) async { }).then((value) async {
await ws.disconnect(); await ws.disconnect();
verify(mockWSSink.close()).called(greaterThan(0)); verify(mockWSSink.close).called(greaterThan(0));
await streamController.close(); await streamController.close();
await mockWSSink.close(); await mockWSSink.close();
@@ -348,41 +311,34 @@ void main() {
test('should throw an error', () async { test('should throw an error', () async {
final ConnectWebSocket connectFunc = MockFunctions().connectFunc; final ConnectWebSocket connectFunc = MockFunctions().connectFunc;
final ws = WebSocket( final ws = WebSocket(
baseUrl: 'baseurl', baseUrl: 'baseurl',
user: User(id: 'testid'), user: User(id: 'testid'),
logger: Logger('ws'), logger: Logger('ws'),
connectParams: {'test': 'true'}, connectParams: {'test': 'true'},
connectPayload: {'payload': 'test'}, connectPayload: {'payload': 'test'},
handler: (e) { handler: print,
print(e);
},
connectFunc: connectFunc, connectFunc: connectFunc,
); );
final mockWSChannel = MockWSChannel(); final mockWSChannel = MockWSChannel();
final streamController = StreamController<String>.broadcast(); final streamController = StreamController<String>.broadcast();
const computedUrl =
final computedUrl =
'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D';
when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); when(() => connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel);
when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); when(() => mockWSChannel.sink).thenAnswer((_) => MockWSSink());
when(mockWSChannel.stream).thenAnswer((_) { when(() => mockWSChannel.stream).thenAnswer((_) => streamController.stream);
return streamController.stream;
});
Future.delayed( Future.delayed(
Duration(milliseconds: 1000), const Duration(milliseconds: 1000),
() => streamController.sink.addError('test error'), () => streamController.sink.addError('test error'),
); );
try { try {
expect(await ws.connect(), throwsA(isA<String>())); expect(await ws.connect(), throwsA(isA<String>()));
} catch (e) { } catch (e) {
verify(connectFunc(computedUrl)).called(greaterThanOrEqualTo(1)); verify(() => connectFunc(computedUrl)).called(greaterThanOrEqualTo(1));
streamController.close();
} }
}); });
} }
File diff suppressed because it is too large Load Diff
@@ -5,7 +5,7 @@ import 'package:stream_chat/src/models/action.dart';
void main() { void main() {
group('src/models/action', () { group('src/models/action', () {
const jsonExample = r'''{ const jsonExample = '''{
"name": "name", "name": "name",
"style": "style", "style": "style",
"text": "text", "text": "text",
@@ -1,12 +1,12 @@
import 'dart:convert';
import 'package:stream_chat/src/models/attachment.dart'; import 'package:stream_chat/src/models/attachment.dart';
import 'package:stream_chat/src/models/action.dart'; import 'package:stream_chat/src/models/action.dart';
import 'dart:convert';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
group('src/models/attachment', () { group('src/models/attachment', () {
const jsonExample = r'''{ const jsonExample = '''{
"type": "giphy", "type": "giphy",
"title": "awesome", "title": "awesome",
"title_link": "https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti", "title_link": "https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti",
@@ -38,22 +38,27 @@ void main() {
test('should parse json correctly', () { test('should parse json correctly', () {
final attachment = Attachment.fromJson(json.decode(jsonExample)); final attachment = Attachment.fromJson(json.decode(jsonExample));
expect(attachment.type, "giphy"); expect(attachment.type, 'giphy');
expect(attachment.title, "awesome"); expect(attachment.title, 'awesome');
expect(attachment.titleLink, expect(
"https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti"); attachment.titleLink,
expect(attachment.thumbUrl, 'https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti',
"https://media0.giphy.com/media/3o7TKnCdBx5cMg0qti/giphy.gif"); );
expect(
attachment.thumbUrl,
'https://media0.giphy.com/media/3o7TKnCdBx5cMg0qti/giphy.gif',
);
expect(attachment.actions, hasLength(3)); expect(attachment.actions, hasLength(3));
expect(attachment.actions[0], isA<Action>()); expect(attachment.actions[0], isA<Action>());
}); });
test('should serialize to json correctly', () { test('should serialize to json correctly', () {
final channel = Attachment( final channel = Attachment(
type: "image", type: 'image',
title: "soo", title: 'soo',
titleLink: titleLink:
"https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti"); 'https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti',
);
expect( expect(
channel.toJson(), channel.toJson(),
@@ -10,7 +10,7 @@ import 'package:stream_chat/stream_chat.dart';
void main() { void main() {
group('src/models/channel_state', () { group('src/models/channel_state', () {
const jsonExample = r'''{ const jsonExample = '''{
"channel": { "channel": {
"id": "dev", "id": "dev",
"type": "team", "type": "team",
@@ -853,28 +853,32 @@ void main() {
expect(channelState.channel.config.commands, hasLength(1)); expect(channelState.channel.config.commands, hasLength(1));
expect(channelState.channel.config.commands[0], isA<Command>()); expect(channelState.channel.config.commands[0], isA<Command>());
expect(channelState.channel.lastMessageAt, expect(channelState.channel.lastMessageAt,
DateTime.parse("2020-01-30T13:43:41.062362Z")); DateTime.parse('2020-01-30T13:43:41.062362Z'));
expect(channelState.channel.createdAt, expect(channelState.channel.createdAt,
DateTime.parse("2019-04-03T18:43:33.213373Z")); DateTime.parse('2019-04-03T18:43:33.213373Z'));
expect(channelState.channel.updatedAt, expect(channelState.channel.updatedAt,
DateTime.parse("2019-04-03T18:43:33.213374Z")); DateTime.parse('2019-04-03T18:43:33.213374Z'));
expect(channelState.channel.createdBy, isA<User>()); expect(channelState.channel.createdBy, isA<User>());
expect(channelState.channel.frozen, true); expect(channelState.channel.frozen, true);
expect(channelState.channel.extraData['example'], 1); expect(channelState.channel.extraData['example'], 1);
expect(channelState.channel.extraData['name'], "#dev"); expect(channelState.channel.extraData['name'], '#dev');
expect(channelState.channel.extraData['image'], expect(
"https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png"); channelState.channel.extraData['image'],
'https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png',
);
expect(channelState.messages, hasLength(25)); expect(channelState.messages, hasLength(25));
expect(channelState.messages[0], isA<Message>()); expect(channelState.messages[0], isA<Message>());
expect(channelState.messages[0], isNotNull); expect(channelState.messages[0], isNotNull);
expect(channelState.messages[0].createdAt, expect(
DateTime.parse("2020-01-29T03:23:02.843948Z")); channelState.messages[0].createdAt,
DateTime.parse('2020-01-29T03:23:02.843948Z'),
);
expect(channelState.messages[0].user, isA<User>()); expect(channelState.messages[0].user, isA<User>());
expect(channelState.watcherCount, 5); expect(channelState.watcherCount, 5);
}); });
test('should serialize to json correctly', () { test('should serialize to json correctly', () {
const toJsonExample = r''' const toJsonExample = '''
{ {
"channel": { "channel": {
"id": "dev", "id": "dev",
@@ -17,19 +17,19 @@ void main() {
test('should parse json correctly', () { test('should parse json correctly', () {
final channel = ChannelModel.fromJson(json.decode(jsonExample)); final channel = ChannelModel.fromJson(json.decode(jsonExample));
expect(channel.id, equals("test")); expect(channel.id, equals('test'));
expect(channel.type, equals("livestream")); expect(channel.type, equals('livestream'));
expect(channel.cid, equals("test:livestream")); expect(channel.cid, equals('test:livestream'));
expect(channel.extraData["cats"], equals(true)); expect(channel.extraData['cats'], equals(true));
expect(channel.extraData["fruit"], equals(["bananas", "apples"])); expect(channel.extraData['fruit'], equals(['bananas', 'apples']));
}); });
test('should serialize to json correctly', () { test('should serialize to json correctly', () {
final channel = ChannelModel( final channel = ChannelModel(
type: "type", type: 'type',
id: "id", id: 'id',
cid: "a:a", cid: 'a:a',
extraData: {"name": "cool"}, extraData: {'name': 'cool'},
); );
expect( expect(
@@ -40,10 +40,10 @@ void main() {
test('should serialize to json correctly when frozen is provided', () { test('should serialize to json correctly when frozen is provided', () {
final channel = ChannelModel( final channel = ChannelModel(
type: "type", type: 'type',
id: "id", id: 'id',
cid: "a:a", cid: 'a:a',
extraData: {"name": "cool"}, extraData: {'name': 'cool'},
frozen: false, frozen: false,
); );
@@ -1,6 +1,6 @@
import 'package:stream_chat/src/models/command.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:stream_chat/src/models/command.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
@@ -30,9 +30,9 @@ void main() {
expect( expect(
command.toJson(), command.toJson(),
{ {
"name": "giphy", 'name': 'giphy',
"description": "Post a random gif to the channel", 'description': 'Post a random gif to the channel',
"args": "[text]", 'args': '[text]',
}, },
); );
}); });
@@ -5,7 +5,7 @@ import 'package:stream_chat/src/models/device.dart';
void main() { void main() {
group('src/models/device', () { group('src/models/device', () {
const jsonExample = r'''{ const jsonExample = '''{
"id": "device-id", "id": "device-id",
"push_provider": "push-provider" "push_provider": "push-provider"
}'''; }''';
@@ -55,7 +55,7 @@ void main() {
type: 'type', type: 'type',
cid: 'cid', cid: 'cid',
connectionId: 'connectionId', connectionId: 'connectionId',
createdAt: DateTime.parse("2020-01-29T03:22:47.63613Z"), createdAt: DateTime.parse('2020-01-29T03:22:47.63613Z'),
me: OwnUser(id: 'id2'), me: OwnUser(id: 'id2'),
totalUnreadCount: 1, totalUnreadCount: 1,
unreadChannels: 1, unreadChannels: 1,
@@ -28,8 +28,8 @@ void main() {
final member = Member.fromJson(json.decode(jsonExample)); final member = Member.fromJson(json.decode(jsonExample));
expect(member.user, isA<User>()); expect(member.user, isA<User>());
expect(member.role, 'member'); expect(member.role, 'member');
expect(member.createdAt, DateTime.parse("2020-01-28T22:17:30.95443Z")); expect(member.createdAt, DateTime.parse('2020-01-28T22:17:30.95443Z'));
expect(member.updatedAt, DateTime.parse("2020-01-28T22:17:30.95443Z")); expect(member.updatedAt, DateTime.parse('2020-01-28T22:17:30.95443Z'));
}); });
}); });
} }
@@ -76,10 +76,10 @@ void main() {
test('should parse json correctly', () { test('should parse json correctly', () {
final message = Message.fromJson(json.decode(jsonExample)); final message = Message.fromJson(json.decode(jsonExample));
expect(message.id, "4637f7e4-a06b-42db-ba5a-8d8270dd926f"); expect(message.id, '4637f7e4-a06b-42db-ba5a-8d8270dd926f');
expect(message.text, expect(message.text,
"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA"); 'https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA');
expect(message.type, "regular"); expect(message.type, 'regular');
expect(message.user, isA<User>()); expect(message.user, isA<User>());
expect(message.silent, isA<bool>()); expect(message.silent, isA<bool>());
expect(message.attachments, isA<List<Attachment>>()); expect(message.attachments, isA<List<Attachment>>());
@@ -87,8 +87,8 @@ void main() {
expect(message.ownReactions, isA<List<Reaction>>()); expect(message.ownReactions, isA<List<Reaction>>());
expect(message.reactionCounts, {'love': 1}); expect(message.reactionCounts, {'love': 1});
expect(message.reactionScores, {'love': 1}); expect(message.reactionScores, {'love': 1});
expect(message.createdAt, DateTime.parse("2020-01-28T22:17:31.107978Z")); expect(message.createdAt, DateTime.parse('2020-01-28T22:17:31.107978Z'));
expect(message.updatedAt, DateTime.parse("2020-01-28T22:17:31.130506Z")); expect(message.updatedAt, DateTime.parse('2020-01-28T22:17:31.130506Z'));
expect(message.mentionedUsers, isA<List<User>>()); expect(message.mentionedUsers, isA<List<User>>());
expect(message.pinned, false); expect(message.pinned, false);
expect(message.pinnedAt, null); expect(message.pinnedAt, null);
@@ -98,38 +98,37 @@ void main() {
test('should serialize to json correctly', () { test('should serialize to json correctly', () {
final message = Message( final message = Message(
id: "4637f7e4-a06b-42db-ba5a-8d8270dd926f", id: '4637f7e4-a06b-42db-ba5a-8d8270dd926f',
text: text:
"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", 'https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA',
silent: false, silent: false,
attachments: [ attachments: [
Attachment.fromJson({ Attachment.fromJson({
"type": "video", 'type': 'video',
"author_name": "GIPHY", 'author_name': 'GIPHY',
"title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", 'title': 'The Lion King Disney GIF - Find \u0026 Share on GIPHY',
"title_link": 'title_link':
"https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", 'https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif',
"text": 'text':
"Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", '''Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.''',
"image_url": 'image_url':
"https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", 'https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif',
"thumb_url": 'thumb_url':
"https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", 'https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif',
"asset_url": 'asset_url':
"https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", 'https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4',
"og_scrape_url": 'og_scrape_url':
"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" 'https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA'
}) })
], ],
showInChannel: true, showInChannel: true,
parentId: 'parentId', parentId: 'parentId',
extraData: {'hey': 'test'}, extraData: {'hey': 'test'},
status: MessageSendingStatus.sent,
); );
expect( expect(
message.toJson(), message.toJson(),
json.decode(r''' json.decode('''
{ {
"id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f",
"text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA",
@@ -1,7 +1,7 @@
import 'package:test/test.dart';
import 'package:stream_chat/src/models/reaction.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:test/test.dart';
import 'package:stream_chat/src/models/reaction.dart';
import 'package:stream_chat/src/models/user.dart'; import 'package:stream_chat/src/models/user.dart';
void main() { void main() {
@@ -30,13 +30,13 @@ void main() {
test('should parse json correctly', () { test('should parse json correctly', () {
final reaction = Reaction.fromJson(json.decode(jsonExample)); final reaction = Reaction.fromJson(json.decode(jsonExample));
expect(reaction.messageId, '76cd8c82-b557-4e48-9d12-87995d3a0e04'); expect(reaction.messageId, '76cd8c82-b557-4e48-9d12-87995d3a0e04');
expect(reaction.createdAt, DateTime.parse("2020-01-28T22:17:31.108742Z")); expect(reaction.createdAt, DateTime.parse('2020-01-28T22:17:31.108742Z'));
expect(reaction.type, 'wow'); expect(reaction.type, 'wow');
expect( expect(
reaction.user.toJson(), reaction.user.toJson(),
User.init("2de0297c-f3f2-489d-b930-ef77342edccf", extraData: { User.init('2de0297c-f3f2-489d-b930-ef77342edccf', extraData: {
"image": "https://randomuser.me/api/portraits/women/45.jpg", 'image': 'https://randomuser.me/api/portraits/women/45.jpg',
"name": "Daisy Morgan" 'name': 'Daisy Morgan'
}).toJson(), }).toJson(),
); );
expect(reaction.score, 1); expect(reaction.score, 1);
@@ -47,13 +47,13 @@ void main() {
test('should serialize to json correctly', () { test('should serialize to json correctly', () {
final reaction = Reaction( final reaction = Reaction(
messageId: '76cd8c82-b557-4e48-9d12-87995d3a0e04', messageId: '76cd8c82-b557-4e48-9d12-87995d3a0e04',
createdAt: DateTime.parse("2020-01-28T22:17:31.108742Z"), createdAt: DateTime.parse('2020-01-28T22:17:31.108742Z'),
type: 'wow', type: 'wow',
user: User.init("2de0297c-f3f2-489d-b930-ef77342edccf", extraData: { user: User.init('2de0297c-f3f2-489d-b930-ef77342edccf', extraData: {
"image": "https://randomuser.me/api/portraits/women/45.jpg", 'image': 'https://randomuser.me/api/portraits/women/45.jpg',
"name": "Daisy Morgan" 'name': 'Daisy Morgan'
}), }),
userId: "2de0297c-f3f2-489d-b930-ef77342edccf", userId: '2de0297c-f3f2-489d-b930-ef77342edccf',
extraData: {'bananas': 'yes'}, extraData: {'bananas': 'yes'},
score: 1, score: 1,
); );
@@ -61,10 +61,10 @@ void main() {
expect( expect(
reaction.toJson(), reaction.toJson(),
{ {
"message_id": "76cd8c82-b557-4e48-9d12-87995d3a0e04", 'message_id': '76cd8c82-b557-4e48-9d12-87995d3a0e04',
"type": "wow", 'type': 'wow',
"score": 1, 'score': 1,
"bananas": 'yes', 'bananas': 'yes',
}, },
); );
}); });
@@ -31,8 +31,8 @@ void main() {
); );
expect(read.toJson(), { expect(read.toJson(), {
"user": {"id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e"}, 'user': {'id': 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e'},
"last_read": "2020-01-28T22:17:30.966485Z", 'last_read': '2020-01-28T22:17:30.966485Z',
'unread_messages': 10, 'unread_messages': 10,
}); });
}); });
@@ -17,11 +17,13 @@ void main() {
}); });
test('should serialize to json correctly', () { test('should serialize to json correctly', () {
final user = final user = User(
User(id: 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e', role: "abc"); id: 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e',
role: 'abc',
);
expect(user.toJson(), { expect(user.toJson(), {
'id': "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", 'id': 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e',
}); });
}); });
}); });
@@ -208,7 +208,7 @@ class _UserListViewState extends State<UserListView>
var message = error.toString(); var message = error.toString();
if (error is DioError) { if (error is DioError) {
final dioError = error as DioError; final dioError = error as DioError;
if (dioError.type == DioErrorType.RESPONSE) { if (dioError.type == DioErrorType.response) {
message = dioError.message; message = dioError.message;
} else { } else {
message = 'Check your connection and retry'; message = 'Check your connection and retry';
+19 -15
View File
@@ -5,43 +5,47 @@ version: 1.5.1
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
publish_to: none
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
stream_chat_flutter_core: ^1.5.0 stream_chat_flutter_core:
path: ../stream_chat_flutter_core
photo_view: ^0.11.0 photo_view: ^0.11.0
rxdart: ^0.25.0 rxdart: ^0.26.0
scrollable_positioned_list: ^0.1.8 scrollable_positioned_list: ^0.1.8
jiffy: ^3.0.1 jiffy: ^3.0.1
flutter_svg: ^0.19.3 flutter_svg: ">=0.21.0-nullsafety.0 <0.21.0"
flutter_portal: ^0.3.0 flutter_portal: ^0.3.0
cached_network_image: ^2.5.0 cached_network_image: ">=3.0.0-nullsafety <3.0.0"
shimmer: ^1.1.2 shimmer: ^1.1.2
flutter_markdown: ^0.5.2 flutter_markdown: ^0.5.2
url_launcher: ^5.7.10 url_launcher: ^6.0.0
emojis: ^0.9.3 emojis: ^0.9.3
video_player: ^2.0.0 video_player: ^2.0.0
chewie: ^1.0.0 chewie: ^1.0.0
file_picker: ^2.1.5 file_picker: ^3.0.0
image_picker: ^0.6.7+17 image_picker: ^0.7.0
flutter_keyboard_visibility: ^4.0.2 flutter_keyboard_visibility: ^5.0.0
video_compress: ^2.1.1 video_compress: ^2.1.1
visibility_detector: ^0.1.5 visibility_detector: ^0.1.5
meta: ^1.2.4 http_parser: ^4.0.0
lottie: ^0.7.0+1 meta: ^1.3.0
lottie: ^1.0.0
substring_highlight: ^0.1.2 substring_highlight: ^0.1.2
flutter_slidable: ^0.5.7 flutter_slidable: ^0.5.7
image_gallery_saver: ^1.6.7 image_gallery_saver: ^1.6.7
share_plus: ^1.2.0 share_plus: ^2.0.0
photo_manager: ^1.0.0 photo_manager: ^1.0.0
ezanimation: ^0.4.1 ezanimation: ^0.4.1
synchronized: ^2.1.0 synchronized: ^3.0.0
characters: ^1.0.0 characters: ^1.0.0
dio: ^3.0.10 dio: ">=4.0.0-prev3 <4.0.0"
path_provider: ^1.6.27 path_provider: ^2.0.0
video_thumbnail: ^0.2.5+1 video_thumbnail: ^0.2.5+1
@@ -60,4 +64,4 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mockito: ^4.1.3 mockito: ^4.1.3
pedantic: ^1.9.2 pedantic: ^1.9.2
@@ -350,7 +350,7 @@ class StreamChannelState extends State<StreamChannel> {
var message = snapshot.error.toString(); var message = snapshot.error.toString();
if (snapshot.error is DioError) { if (snapshot.error is DioError) {
final dioError = snapshot.error as DioError; final dioError = snapshot.error as DioError;
if (dioError.type == DioErrorType.RESPONSE) { if (dioError.type == DioErrorType.response) {
message = dioError.message; message = dioError.message;
} else { } else {
message = 'Check your connection and retry'; message = 'Check your connection and retry';
@@ -5,6 +5,8 @@ version: 1.5.0
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
publish_to: none
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.17.0"
@@ -12,7 +14,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
rxdart: ^0.25.0 rxdart: ^0.26.0
stream_chat: ^1.5.0 stream_chat: ^1.5.0
dependency_overrides: dependency_overrides:
@@ -22,4 +24,6 @@ dependency_overrides:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mockito: ^4.1.3 fake_async: ^1.1.0
mockito: ^4.1.3
@@ -11,7 +11,8 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
cupertino_icons: ^1.0.0 cupertino_icons: ^1.0.0
stream_chat: ^1.4.0 stream_chat:
path: ../../stream_chat
stream_chat_persistence: stream_chat_persistence:
path: ../ path: ../
@@ -19,10 +19,10 @@ class ChannelDao extends DatabaseAccessor<MoorChatDatabase>
(select(channels)..where((c) => c.cid.equals(cid))).join([ (select(channels)..where((c) => c.cid.equals(cid))).join([
leftOuterJoin(users, channels.createdById.equalsExp(users.id)), leftOuterJoin(users, channels.createdById.equalsExp(users.id)),
]).map((rows) { ]).map((rows) {
final channel = rows.readTable(channels); final channel = rows.readTableOrNull(channels);
final createdBy = rows.readTable(users); final createdBy = rows.readTableOrNull(users);
return channel.toChannelModel(createdBy: createdBy?.toUser()); return channel.toChannelModel(createdBy: createdBy?.toUser());
}).getSingle(); }).getSingleOrNull();
/// Delete all channels by matching cid in [cids] /// Delete all channels by matching cid in [cids]
/// ///
@@ -17,16 +17,16 @@ class ConnectionEventDao extends DatabaseAccessor<MoorChatDatabase>
/// Get the latest stored connection event /// Get the latest stored connection event
Future<Event> get connectionEvent => select(connectionEvents) Future<Event> get connectionEvent => select(connectionEvents)
.map((eventEntity) => eventEntity.toEvent()) .map((eventEntity) => eventEntity.toEvent())
.getSingle(); .getSingleOrNull();
/// Get the latest stored lastSyncAt /// Get the latest stored lastSyncAt
Future<DateTime> get lastSyncAt => Future<DateTime> get lastSyncAt =>
select(connectionEvents).getSingle().then((r) => r?.lastSyncAt); select(connectionEvents).getSingleOrNull().then((r) => r?.lastSyncAt);
/// Update stored connection event with latest data /// Update stored connection event with latest data
Future<void> updateConnectionEvent(Event event) async => Future<void> updateConnectionEvent(Event event) async =>
transaction(() async { transaction(() async {
final connectionInfo = await select(connectionEvents).getSingle(); final connectionInfo = await select(connectionEvents).getSingleOrNull();
await into(connectionEvents).insert( await into(connectionEvents).insert(
ConnectionEventEntity( ConnectionEventEntity(
id: 1, id: 1,
@@ -36,9 +36,9 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
(delete(messages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); (delete(messages)..where((tbl) => tbl.channelCid.isIn(cids))).go();
Future<Message> _messageFromJoinRow(TypedResult rows) async { Future<Message> _messageFromJoinRow(TypedResult rows) async {
final userEntity = rows.readTable(_users); final userEntity = rows.readTableOrNull(_users);
final pinnedByEntity = rows.readTable(_pinnedByUsers); final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers);
final msgEntity = rows.readTable(messages); final msgEntity = rows.readTableOrNull(messages);
final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); final latestReactions = await _db.reactionDao.getReactions(msgEntity.id);
final ownReactions = await _db.reactionDao.getReactionsByUserId( final ownReactions = await _db.reactionDao.getReactionsByUserId(
msgEntity.id, msgEntity.id,
@@ -66,7 +66,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
]) ])
..where(messages.id.equals(id))) ..where(messages.id.equals(id)))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
.getSingle(); .getSingleOrNull();
/// Returns all the messages of a particular thread by matching /// Returns all the messages of a particular thread by matching
/// [Messages.channelCid] with [cid] /// [Messages.channelCid] with [cid]
@@ -77,7 +77,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)),
]) ])
..where(messages.channelCid.equals(cid)) ..where(messages.channelCid.equals(cid))
..where(isNotNull(messages.parentId)) ..where(messages.parentId.isNotNull())
..orderBy([OrderingTerm.asc(messages.createdAt)])) ..orderBy([OrderingTerm.asc(messages.createdAt)]))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
.get()); .get());
@@ -93,7 +93,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
leftOuterJoin( leftOuterJoin(
_pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)),
]) ])
..where(isNotNull(messages.parentId)) ..where(messages.parentId.isNotNull())
..where(messages.parentId.equals(parentId)) ..where(messages.parentId.equals(parentId))
..orderBy([OrderingTerm.asc(messages.createdAt)])) ..orderBy([OrderingTerm.asc(messages.createdAt)]))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
@@ -136,7 +136,8 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
]) ])
..where(messages.channelCid.equals(cid)) ..where(messages.channelCid.equals(cid))
..where( ..where(
isNull(messages.parentId) | messages.showInChannel.equals(true)) messages.parentId.isNull() | messages.showInChannel.equals(true),
)
..orderBy([OrderingTerm.asc(messages.createdAt)])) ..orderBy([OrderingTerm.asc(messages.createdAt)]))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
.get()); .get());
@@ -36,9 +36,9 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
(delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); (delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go();
Future<Message> _messageFromJoinRow(TypedResult rows) async { Future<Message> _messageFromJoinRow(TypedResult rows) async {
final userEntity = rows.readTable(users); final userEntity = rows.readTableOrNull(users);
final pinnedByEntity = rows.readTable(_pinnedByUsers); final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers);
final msgEntity = rows.readTable(pinnedMessages); final msgEntity = rows.readTableOrNull(pinnedMessages);
final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); final latestReactions = await _db.reactionDao.getReactions(msgEntity.id);
final ownReactions = await _db.reactionDao.getReactionsByUserId( final ownReactions = await _db.reactionDao.getReactionsByUserId(
msgEntity.id, msgEntity.id,
@@ -66,7 +66,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
]) ])
..where(pinnedMessages.id.equals(id))) ..where(pinnedMessages.id.equals(id)))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
.getSingle(); .getSingleOrNull();
/// Returns all the messages of a particular thread by matching /// Returns all the messages of a particular thread by matching
/// [PinnedMessages.channelCid] with [cid] /// [PinnedMessages.channelCid] with [cid]
@@ -77,7 +77,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)),
]) ])
..where(pinnedMessages.channelCid.equals(cid)) ..where(pinnedMessages.channelCid.equals(cid))
..where(isNotNull(pinnedMessages.parentId)) ..where(pinnedMessages.parentId.isNotNull())
..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)]))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
.get()); .get());
@@ -93,7 +93,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
leftOuterJoin(_pinnedByUsers, leftOuterJoin(_pinnedByUsers,
pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)),
]) ])
..where(isNotNull(pinnedMessages.parentId)) ..where(pinnedMessages.parentId.isNotNull())
..where(pinnedMessages.parentId.equals(parentId)) ..where(pinnedMessages.parentId.equals(parentId))
..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)]))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
@@ -135,7 +135,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)),
]) ])
..where(pinnedMessages.channelCid.equals(cid)) ..where(pinnedMessages.channelCid.equals(cid))
..where(isNull(pinnedMessages.parentId) | ..where(pinnedMessages.parentId.isNull() |
pinnedMessages.showInChannel.equals(true)) pinnedMessages.showInChannel.equals(true))
..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)]))
.map(_messageFromJoinRow) .map(_messageFromJoinRow)
@@ -23,8 +23,8 @@ class ReactionDao extends DatabaseAccessor<MoorChatDatabase>
..where(reactions.messageId.equals(messageId)) ..where(reactions.messageId.equals(messageId))
..orderBy([OrderingTerm.asc(reactions.createdAt)])) ..orderBy([OrderingTerm.asc(reactions.createdAt)]))
.map((rows) { .map((rows) {
final userEntity = rows.readTable(users); final userEntity = rows.readTableOrNull(users);
final reactionEntity = rows.readTable(reactions); final reactionEntity = rows.readTableOrNull(reactions);
return reactionEntity.toReaction(user: userEntity?.toUser()); return reactionEntity.toReaction(user: userEntity?.toUser());
}).get(); }).get();
+14 -10
View File
@@ -5,20 +5,23 @@ version: 1.5.0
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
publish_to: none
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
logging: ^0.11.4 logging: ^1.0.0
meta: ^1.2.4 meta: ^1.3.0
moor: ^3.4.0 moor: ^4.2.0
mutex: ^2.0.0 mutex: ^3.0.0
path: ^1.7.0 path: ^1.8.0
path_provider: ^1.6.27 path_provider: ^2.0.0
sqlite3_flutter_libs: ^0.4.0+1 sqlite3_flutter_libs: ^0.4.0+1
stream_chat: ^1.5.0 stream_chat:
path: ../stream_chat
dependency_overrides: dependency_overrides:
stream_chat: stream_chat:
@@ -26,6 +29,7 @@ dependency_overrides:
dev_dependencies: dev_dependencies:
build_runner: ^1.11.0 build_runner: ^1.11.0
mockito: ^4.1.3 mocktail: ^0.1.0
moor_generator: ^3.4.1 moor_generator: ^4.2.0
test: ^1.15.7 pedantic: ^1.11.0
test: ^1.16.0
@@ -1,4 +1,4 @@
import 'package:mockito/mockito.dart'; import 'package:mocktail/mocktail.dart';
import 'package:stream_chat_persistence/src/dao/dao.dart'; import 'package:stream_chat_persistence/src/dao/dao.dart';
import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
@@ -1,4 +1,4 @@
import 'package:mockito/mockito.dart'; import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart';
@@ -84,121 +84,124 @@ void main() {
const parentId = 'testParentId'; const parentId = 'testParentId';
final replies = List.generate(3, (index) => Message(id: 'testId$index')); final replies = List.generate(3, (index) => Message(id: 'testId$index'));
when(mockDatabase.messageDao.getThreadMessagesByParentId(parentId)) when(() => mockDatabase.messageDao.getThreadMessagesByParentId(parentId))
.thenAnswer((_) async => replies); .thenAnswer((_) async => replies);
final fetchedReplies = await client.getReplies(parentId); final fetchedReplies = await client.getReplies(parentId);
expect(fetchedReplies.length, replies.length); expect(fetchedReplies.length, replies.length);
verify(mockDatabase.messageDao.getThreadMessagesByParentId(parentId)) verify(() =>
mockDatabase.messageDao.getThreadMessagesByParentId(parentId))
.called(1); .called(1);
}); });
test('getConnectionInfo', () async { test('getConnectionInfo', () async {
final event = Event(type: 'testEvent'); final event = Event(type: 'testEvent');
when(mockDatabase.connectionEventDao.connectionEvent) when(() => mockDatabase.connectionEventDao.connectionEvent)
.thenAnswer((_) async => event); .thenAnswer((_) async => event);
final fetchedEvent = await client.getConnectionInfo(); final fetchedEvent = await client.getConnectionInfo();
expect(fetchedEvent.type, event.type); expect(fetchedEvent.type, event.type);
verify(mockDatabase.connectionEventDao.connectionEvent).called(1); verify(() => mockDatabase.connectionEventDao.connectionEvent).called(1);
}); });
test('getLastSyncAt', () async { test('getLastSyncAt', () async {
final lastSync = DateTime.now(); final lastSync = DateTime.now();
when(mockDatabase.connectionEventDao.lastSyncAt) when(() => mockDatabase.connectionEventDao.lastSyncAt)
.thenAnswer((_) async => lastSync); .thenAnswer((_) async => lastSync);
final fetchedLastSync = await client.getLastSyncAt(); final fetchedLastSync = await client.getLastSyncAt();
expect(fetchedLastSync, isSameDateAs(lastSync)); expect(fetchedLastSync, isSameDateAs(lastSync));
verify(mockDatabase.connectionEventDao.lastSyncAt).called(1); verify(() => mockDatabase.connectionEventDao.lastSyncAt).called(1);
}); });
test('updateConnectionInfo', () async { test('updateConnectionInfo', () async {
final event = Event(type: 'testEvent'); final event = Event(type: 'testEvent');
when(mockDatabase.connectionEventDao.updateConnectionEvent(event)) when(() => mockDatabase.connectionEventDao.updateConnectionEvent(event))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.updateConnectionInfo(event); await client.updateConnectionInfo(event);
verify(mockDatabase.connectionEventDao.updateConnectionEvent(event)) verify(() => mockDatabase.connectionEventDao.updateConnectionEvent(event))
.called(1); .called(1);
}); });
test('updateLastSyncAt', () async { test('updateLastSyncAt', () async {
final lastSync = DateTime.now(); final lastSync = DateTime.now();
when(mockDatabase.connectionEventDao.updateLastSyncAt(lastSync)) when(() => mockDatabase.connectionEventDao.updateLastSyncAt(lastSync))
.thenAnswer((_) { .thenAnswer((_) {
return; return;
}); });
await client.updateLastSyncAt(lastSync); await client.updateLastSyncAt(lastSync);
verify(mockDatabase.connectionEventDao.updateLastSyncAt(lastSync)) verify(() => mockDatabase.connectionEventDao.updateLastSyncAt(lastSync))
.called(1); .called(1);
}); });
test('getChannelCids', () async { test('getChannelCids', () async {
final channelCids = List.generate(3, (index) => 'testCid$index'); final channelCids = List.generate(3, (index) => 'testCid$index');
when(mockDatabase.channelDao.cids).thenAnswer((_) async => channelCids); when(() => mockDatabase.channelDao.cids)
.thenAnswer((_) async => channelCids);
final fetchedChannelCids = await client.getChannelCids(); final fetchedChannelCids = await client.getChannelCids();
expect(fetchedChannelCids.length, channelCids.length); expect(fetchedChannelCids.length, channelCids.length);
verify(mockDatabase.channelDao.cids).called(1); verify(() => mockDatabase.channelDao.cids).called(1);
}); });
test('getChannelByCid', () async { test('getChannelByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
final channelModel = ChannelModel(cid: cid); final channelModel = ChannelModel(cid: cid);
when(mockDatabase.channelDao.getChannelByCid(cid)) when(() => mockDatabase.channelDao.getChannelByCid(cid))
.thenAnswer((_) async => channelModel); .thenAnswer((_) async => channelModel);
final fetchedChannelModel = await client.getChannelByCid(cid); final fetchedChannelModel = await client.getChannelByCid(cid);
expect(fetchedChannelModel.cid, channelModel.cid); expect(fetchedChannelModel.cid, channelModel.cid);
verify(mockDatabase.channelDao.getChannelByCid(cid)).called(1); verify(() => mockDatabase.channelDao.getChannelByCid(cid)).called(1);
}); });
test('getMembersByCid', () async { test('getMembersByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
final members = List.generate(3, (index) => Member()); final members = List.generate(3, (index) => Member());
when(mockDatabase.memberDao.getMembersByCid(cid)) when(() => mockDatabase.memberDao.getMembersByCid(cid))
.thenAnswer((_) async => members); .thenAnswer((_) async => members);
final fetchedMembers = await client.getMembersByCid(cid); final fetchedMembers = await client.getMembersByCid(cid);
expect(fetchedMembers.length, members.length); expect(fetchedMembers.length, members.length);
verify(mockDatabase.memberDao.getMembersByCid(cid)).called(1); verify(() => mockDatabase.memberDao.getMembersByCid(cid)).called(1);
}); });
test('getReadsByCid', () async { test('getReadsByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
final reads = List.generate(3, (index) => Read()); final reads = List.generate(3, (index) => Read());
when(mockDatabase.readDao.getReadsByCid(cid)) when(() => mockDatabase.readDao.getReadsByCid(cid))
.thenAnswer((_) async => reads); .thenAnswer((_) async => reads);
final fetchedReads = await client.getReadsByCid(cid); final fetchedReads = await client.getReadsByCid(cid);
expect(fetchedReads.length, reads.length); expect(fetchedReads.length, reads.length);
verify(mockDatabase.readDao.getReadsByCid(cid)).called(1); verify(() => mockDatabase.readDao.getReadsByCid(cid)).called(1);
}); });
test('getMessagesByCid', () async { test('getMessagesByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
when(mockDatabase.messageDao.getMessagesByCid(cid)) when(() => mockDatabase.messageDao.getMessagesByCid(cid))
.thenAnswer((_) async => messages); .thenAnswer((_) async => messages);
final fetchedMessages = await client.getMessagesByCid(cid); final fetchedMessages = await client.getMessagesByCid(cid);
expect(fetchedMessages.length, messages.length); expect(fetchedMessages.length, messages.length);
verify(mockDatabase.messageDao.getMessagesByCid(cid)).called(1); verify(() => mockDatabase.messageDao.getMessagesByCid(cid)).called(1);
}); });
test('getPinnedMessagesByCid', () async { test('getPinnedMessagesByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
when(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)) when(() => mockDatabase.pinnedMessageDao.getMessagesByCid(cid))
.thenAnswer((_) async => messages); .thenAnswer((_) async => messages);
final fetchedMessages = await client.getPinnedMessagesByCid(cid); final fetchedMessages = await client.getPinnedMessagesByCid(cid);
expect(fetchedMessages.length, messages.length); expect(fetchedMessages.length, messages.length);
verify(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)).called(1); verify(() => mockDatabase.pinnedMessageDao.getMessagesByCid(cid))
.called(1);
}); });
test('getChannelStateByCid', () async { test('getChannelStateByCid', () async {
@@ -208,15 +211,15 @@ void main() {
final reads = List.generate(3, (index) => Read()); final reads = List.generate(3, (index) => Read());
final channel = ChannelModel(cid: cid); final channel = ChannelModel(cid: cid);
when(mockDatabase.memberDao.getMembersByCid(cid)) when(() => mockDatabase.memberDao.getMembersByCid(cid))
.thenAnswer((_) async => members); .thenAnswer((_) async => members);
when(mockDatabase.readDao.getReadsByCid(cid)) when(() => mockDatabase.readDao.getReadsByCid(cid))
.thenAnswer((_) async => reads); .thenAnswer((_) async => reads);
when(mockDatabase.channelDao.getChannelByCid(cid)) when(() => mockDatabase.channelDao.getChannelByCid(cid))
.thenAnswer((_) async => channel); .thenAnswer((_) async => channel);
when(mockDatabase.messageDao.getMessagesByCid(cid)) when(() => mockDatabase.messageDao.getMessagesByCid(cid))
.thenAnswer((_) async => messages); .thenAnswer((_) async => messages);
when(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)) when(() => mockDatabase.pinnedMessageDao.getMessagesByCid(cid))
.thenAnswer((_) async => messages); .thenAnswer((_) async => messages);
final fetchedChannelState = await client.getChannelStateByCid(cid); final fetchedChannelState = await client.getChannelStateByCid(cid);
@@ -226,11 +229,12 @@ void main() {
expect(fetchedChannelState.read.length, reads.length); expect(fetchedChannelState.read.length, reads.length);
expect(fetchedChannelState.channel.cid, channel.cid); expect(fetchedChannelState.channel.cid, channel.cid);
verify(mockDatabase.memberDao.getMembersByCid(cid)).called(1); verify(() => mockDatabase.memberDao.getMembersByCid(cid)).called(1);
verify(mockDatabase.readDao.getReadsByCid(cid)).called(1); verify(() => mockDatabase.readDao.getReadsByCid(cid)).called(1);
verify(mockDatabase.channelDao.getChannelByCid(cid)).called(1); verify(() => mockDatabase.channelDao.getChannelByCid(cid)).called(1);
verify(mockDatabase.messageDao.getMessagesByCid(cid)).called(1); verify(() => mockDatabase.messageDao.getMessagesByCid(cid)).called(1);
verify(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)).called(1); verify(() => mockDatabase.pinnedMessageDao.getMessagesByCid(cid))
.called(1);
}); });
test('getChannelStates', () async { test('getChannelStates', () async {
@@ -252,17 +256,17 @@ void main() {
) )
.toList(growable: false); .toList(growable: false);
when(mockDatabase.channelQueryDao.getChannels()) when(() => mockDatabase.channelQueryDao.getChannels())
.thenAnswer((_) async => channels); .thenAnswer((_) async => channels);
when(mockDatabase.memberDao.getMembersByCid(cid)) when(() => mockDatabase.memberDao.getMembersByCid(cid))
.thenAnswer((_) async => members); .thenAnswer((_) async => members);
when(mockDatabase.readDao.getReadsByCid(cid)) when(() => mockDatabase.readDao.getReadsByCid(cid))
.thenAnswer((_) async => reads); .thenAnswer((_) async => reads);
when(mockDatabase.channelDao.getChannelByCid(cid)) when(() => mockDatabase.channelDao.getChannelByCid(cid))
.thenAnswer((_) async => channel); .thenAnswer((_) async => channel);
when(mockDatabase.messageDao.getMessagesByCid(cid)) when(() => mockDatabase.messageDao.getMessagesByCid(cid))
.thenAnswer((_) async => messages); .thenAnswer((_) async => messages);
when(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)) when(() => mockDatabase.pinnedMessageDao.getMessagesByCid(cid))
.thenAnswer((_) async => messages); .thenAnswer((_) async => messages);
final fetchedChannelStates = await client.getChannelStates(); final fetchedChannelStates = await client.getChannelStates();
@@ -278,151 +282,160 @@ void main() {
expect(fetched.channel.cid, original.channel.cid); expect(fetched.channel.cid, original.channel.cid);
} }
verify(mockDatabase.channelQueryDao.getChannels()).called(1); verify(() => mockDatabase.channelQueryDao.getChannels()).called(1);
verify(mockDatabase.memberDao.getMembersByCid(cid)).called(3); verify(() => mockDatabase.memberDao.getMembersByCid(cid)).called(3);
verify(mockDatabase.readDao.getReadsByCid(cid)).called(3); verify(() => mockDatabase.readDao.getReadsByCid(cid)).called(3);
verify(mockDatabase.channelDao.getChannelByCid(cid)).called(3); verify(() => mockDatabase.channelDao.getChannelByCid(cid)).called(3);
verify(mockDatabase.messageDao.getMessagesByCid(cid)).called(3); verify(() => mockDatabase.messageDao.getMessagesByCid(cid)).called(3);
verify(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)).called(3); verify(() => mockDatabase.pinnedMessageDao.getMessagesByCid(cid))
.called(3);
}); });
test('updateChannelQueries', () async { test('updateChannelQueries', () async {
const filter = <String, dynamic>{}; const filter = <String, dynamic>{};
const cids = <String>[]; const cids = <String>[];
when(mockDatabase.channelQueryDao.updateChannelQueries(filter, cids)) when(() =>
mockDatabase.channelQueryDao.updateChannelQueries(filter, cids))
.thenAnswer((realInvocation) async { .thenAnswer((realInvocation) async {
return; return;
}); });
await client.updateChannelQueries(filter, cids); await client.updateChannelQueries(filter, cids);
verify(mockDatabase.channelQueryDao.updateChannelQueries(filter, cids)) verify(() =>
mockDatabase.channelQueryDao.updateChannelQueries(filter, cids))
.called(1); .called(1);
}); });
test('deleteMessageById', () async { test('deleteMessageById', () async {
const messageId = 'testMessageId'; const messageId = 'testMessageId';
when(mockDatabase.messageDao.deleteMessageByIds([messageId])) when(() => mockDatabase.messageDao.deleteMessageByIds([messageId]))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteMessageById(messageId); await client.deleteMessageById(messageId);
verify(mockDatabase.messageDao.deleteMessageByIds([messageId])).called(1); verify(() => mockDatabase.messageDao.deleteMessageByIds([messageId]))
.called(1);
}); });
test('deletePinnedMessageById', () async { test('deletePinnedMessageById', () async {
const messageId = 'testMessageId'; const messageId = 'testMessageId';
when(mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId])) when(() => mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId]))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deletePinnedMessageById(messageId); await client.deletePinnedMessageById(messageId);
verify(mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId])) verify(() =>
mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId]))
.called(1); .called(1);
}); });
test('deleteMessageByIds', () async { test('deleteMessageByIds', () async {
const messageIds = <String>[]; const messageIds = <String>[];
when(mockDatabase.messageDao.deleteMessageByIds(messageIds)) when(() => mockDatabase.messageDao.deleteMessageByIds(messageIds))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteMessageByIds(messageIds); await client.deleteMessageByIds(messageIds);
verify(mockDatabase.messageDao.deleteMessageByIds(messageIds)).called(1); verify(() => mockDatabase.messageDao.deleteMessageByIds(messageIds))
.called(1);
}); });
test('deletePinnedMessageByIds', () async { test('deletePinnedMessageByIds', () async {
const messageIds = <String>[]; const messageIds = <String>[];
when(mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds)) when(() => mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deletePinnedMessageByIds(messageIds); await client.deletePinnedMessageByIds(messageIds);
verify(mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds)) verify(() => mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds))
.called(1); .called(1);
}); });
test('deleteMessageByCid', () async { test('deleteMessageByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
when(mockDatabase.messageDao.deleteMessageByCids([cid])) when(() => mockDatabase.messageDao.deleteMessageByCids([cid]))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteMessageByCid(cid); await client.deleteMessageByCid(cid);
verify(mockDatabase.messageDao.deleteMessageByCids([cid])).called(1); verify(() => mockDatabase.messageDao.deleteMessageByCids([cid]))
.called(1);
}); });
test('deletePinnedMessageByCid', () async { test('deletePinnedMessageByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
when(mockDatabase.pinnedMessageDao.deleteMessageByCids([cid])) when(() => mockDatabase.pinnedMessageDao.deleteMessageByCids([cid]))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deletePinnedMessageByCid(cid); await client.deletePinnedMessageByCid(cid);
verify(mockDatabase.pinnedMessageDao.deleteMessageByCids([cid])) verify(() => mockDatabase.pinnedMessageDao.deleteMessageByCids([cid]))
.called(1); .called(1);
}); });
test('deleteMessageByCids', () async { test('deleteMessageByCids', () async {
const cids = <String>[]; const cids = <String>[];
when(mockDatabase.messageDao.deleteMessageByCids(cids)) when(() => mockDatabase.messageDao.deleteMessageByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteMessageByCids(cids); await client.deleteMessageByCids(cids);
verify(mockDatabase.messageDao.deleteMessageByCids(cids)).called(1); verify(() => mockDatabase.messageDao.deleteMessageByCids(cids)).called(1);
}); });
test('deletePinnedMessageByCids', () async { test('deletePinnedMessageByCids', () async {
const cids = <String>[]; const cids = <String>[];
when(mockDatabase.pinnedMessageDao.deleteMessageByCids(cids)) when(() => mockDatabase.pinnedMessageDao.deleteMessageByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deletePinnedMessageByCids(cids); await client.deletePinnedMessageByCids(cids);
verify(mockDatabase.pinnedMessageDao.deleteMessageByCids(cids)).called(1); verify(() => mockDatabase.pinnedMessageDao.deleteMessageByCids(cids))
.called(1);
}); });
test('deleteChannels', () async { test('deleteChannels', () async {
const cids = <String>[]; const cids = <String>[];
when(mockDatabase.channelDao.deleteChannelByCids(cids)) when(() => mockDatabase.channelDao.deleteChannelByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteChannels(cids); await client.deleteChannels(cids);
verify(mockDatabase.channelDao.deleteChannelByCids(cids)).called(1); verify(() => mockDatabase.channelDao.deleteChannelByCids(cids)).called(1);
}); });
test('updateMessages', () async { test('updateMessages', () async {
const cid = 'testCid'; const cid = 'testCid';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
when(mockDatabase.messageDao.updateMessages(cid, messages)) when(() => mockDatabase.messageDao.updateMessages(cid, messages))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.updateMessages(cid, messages); await client.updateMessages(cid, messages);
verify(mockDatabase.messageDao.updateMessages(cid, messages)).called(1); verify(() => mockDatabase.messageDao.updateMessages(cid, messages))
.called(1);
}); });
test('updatePinnedMessages', () async { test('updatePinnedMessages', () async {
const cid = 'testCid'; const cid = 'testCid';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
when(mockDatabase.pinnedMessageDao.updateMessages(cid, messages)) when(() => mockDatabase.pinnedMessageDao.updateMessages(cid, messages))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.updatePinnedMessages(cid, messages); await client.updatePinnedMessages(cid, messages);
verify(mockDatabase.pinnedMessageDao.updateMessages(cid, messages)) verify(() => mockDatabase.pinnedMessageDao.updateMessages(cid, messages))
.called(1); .called(1);
}); });
@@ -441,7 +454,7 @@ void main() {
); );
}, },
); );
when(mockDatabase.messageDao.getThreadMessages(cid)) when(() => mockDatabase.messageDao.getThreadMessages(cid))
.thenAnswer((realInvocation) async => messages); .thenAnswer((realInvocation) async => messages);
final fetchedThreads = await client.getChannelThreads(cid); final fetchedThreads = await client.getChannelThreads(cid);
@@ -452,85 +465,90 @@ void main() {
expect(fetched.key, original.key); expect(fetched.key, original.key);
} }
verify(mockDatabase.messageDao.getThreadMessages(cid)).called(1); verify(() => mockDatabase.messageDao.getThreadMessages(cid)).called(1);
}); });
test('updateChannels', () async { test('updateChannels', () async {
final channels = List.generate(3, (index) => ChannelModel()); final channels = List.generate(3, (index) => ChannelModel());
when(mockDatabase.channelDao.updateChannels(channels)) when(() => mockDatabase.channelDao.updateChannels(channels))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.updateChannels(channels); await client.updateChannels(channels);
verify(mockDatabase.channelDao.updateChannels(channels)).called(1); verify(() => mockDatabase.channelDao.updateChannels(channels)).called(1);
}); });
test('updateMembers', () async { test('updateMembers', () async {
const cid = 'testCid'; const cid = 'testCid';
final members = List.generate(3, (index) => Member()); final members = List.generate(3, (index) => Member());
when(mockDatabase.memberDao.updateMembers(cid, members)) when(() => mockDatabase.memberDao.updateMembers(cid, members))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.updateMembers(cid, members); await client.updateMembers(cid, members);
verify(mockDatabase.memberDao.updateMembers(cid, members)).called(1); verify(() => mockDatabase.memberDao.updateMembers(cid, members))
.called(1);
}); });
test('updateReads', () async { test('updateReads', () async {
const cid = 'testCid'; const cid = 'testCid';
final reads = List.generate(3, (index) => Read()); final reads = List.generate(3, (index) => Read());
when(mockDatabase.readDao.updateReads(cid, reads)).thenAnswer((_) async { when(() => mockDatabase.readDao.updateReads(cid, reads))
.thenAnswer((_) async {
return; return;
}); });
await client.updateReads(cid, reads); await client.updateReads(cid, reads);
verify(mockDatabase.readDao.updateReads(cid, reads)).called(1); verify(() => mockDatabase.readDao.updateReads(cid, reads)).called(1);
}); });
test('updateUsers', () async { test('updateUsers', () async {
final users = List.generate(3, (index) => User()); final users = List.generate(3, (index) => User());
when(mockDatabase.userDao.updateUsers(users)).thenAnswer((_) async { when(() => mockDatabase.userDao.updateUsers(users)).thenAnswer((_) async {
return; return;
}); });
await client.updateUsers(users); await client.updateUsers(users);
verify(mockDatabase.userDao.updateUsers(users)).called(1); verify(() => mockDatabase.userDao.updateUsers(users)).called(1);
}); });
test('updateReactions', () async { test('updateReactions', () async {
final reactions = List.generate(3, (index) => Reaction()); final reactions = List.generate(3, (index) => Reaction());
when(mockDatabase.reactionDao.updateReactions(reactions)) when(() => mockDatabase.reactionDao.updateReactions(reactions))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.updateReactions(reactions); await client.updateReactions(reactions);
verify(mockDatabase.reactionDao.updateReactions(reactions)).called(1); verify(() => mockDatabase.reactionDao.updateReactions(reactions))
.called(1);
}); });
test('deleteReactionsByMessageId', () async { test('deleteReactionsByMessageId', () async {
final messageIds = <String>[]; final messageIds = <String>[];
when(mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds)) when(() =>
mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteReactionsByMessageId(messageIds); await client.deleteReactionsByMessageId(messageIds);
verify(mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds)) verify(() =>
mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds))
.called(1); .called(1);
}); });
test('deleteMembersByCids', () async { test('deleteMembersByCids', () async {
final cids = <String>[]; final cids = <String>[];
when(mockDatabase.memberDao.deleteMemberByCids(cids)) when(() => mockDatabase.memberDao.deleteMemberByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async {
return; return;
}); });
await client.deleteMembersByCids(cids); await client.deleteMembersByCids(cids);
verify(mockDatabase.memberDao.deleteMemberByCids(cids)).called(1); verify(() => mockDatabase.memberDao.deleteMemberByCids(cids)).called(1);
}); });
tearDown(() async { tearDown(() async {