While working with Firebase Firestore, I am coming across the following error:
E/flutter ( 4477): [ERROR:flutter/shell/common/shell.cc(93)] Dart Unhandled Exception: type 'Future<Group>' is not a subtype of type 'Group', stack trace: #0 new List.from (dart:core-patch/array_patch.dart:41:5)
E/flutter ( 4477): #1 GroupService.getGroups (package:money_manager/core/services/group_service.dart:56:21)
E/flutter ( 4477): <asynchronous suspension>
E/flutter ( 4477): #2 GroupViewModel._getAllGroups (package:money_manager/core/view_models/group_viewmodel.dart:44:26)
E/flutter ( 4477): <asynchronous suspension>
E/flutter ( 4477):
Though I think I have made proper use of async-await wherever necessary, I am not being able to figure out this error. Relevant code:
in group-service.dart :
Future<List<Group>> getGroups() async {
final userData = await getUserData();
List<Group> groups = [];
if (userData['groups'] != null) {
List<String> groupIds = List.from(userData['groups'].map((e) => e['id']));
groups = List.from(groupIds.map((e) async {
return await getGroupFromId(e);
}));
}
return groups;
}
Future<Group> getGroupFromId(String groupId) async {
final groupData = await getGroupData(groupId);
return Group.fromJson(groupData);
}
Future<Map<String, dynamic>> getGroupData(String groupId) async {
DocumentReference groupDoc =
FirebaseFirestore.instance.collection('groups').doc(groupId);
final snapshot = await groupDoc.get();
Map<String, dynamic> groupData = snapshot.data() as Map<String, dynamic>;
return groupData;
}
in group_viewmodel.dart:
List<Group> _userGroups = [];
void _getAllGroups() async {
List<Group> groups = await _groupService.getGroups();
_userGroups = groups;
}
The problem is in the following line:
groups = List.from(groupIds.map((e) async {
return await getGroupFromId(e);
}));
Even though you're using await before the return of the map() function, it will still return a Future. map() is a synchronous function, and it doesn't run the inner function asynchronously. Thus, it will return an Iterable<Future<Group>>, which fails to be converted into a List<Group> in the List.from() function.
There is a handy function that takes an iterable of futures and waits for each one of them, Future.wait(). Here's how your code will look like with it:
groups = List.from(await Future.wait(groupIds.map((e) async {
return await getGroupFromId(e);
})));
And even better with tear-offs:
groups = List.from(await Future.wait(groupIds.map(getGroupFromId)));
There is an example in asio, which caches the sent messages in a deque. I think when there are too many unsent messages in this deque, such as 1000, I want to process it through constbuffersequence, that is, batch sending, so the following How should the code be changed, thank you!
void deliver(const chat_message& msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
boost::asio::async_write(socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
boost::bind(&chat_session::handle_write, shared_from_this(),
boost::asio::placeholders::error));
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
boost::asio::async_write(socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
boost::bind(&chat_session::handle_write, shared_from_this(),
boost::asio::placeholders::error));
}
}
else
{
room_.leave(shared_from_this());
}
}
You can transform the deque to any container modeling the const buffer sequence concept:
std::vector<asio::const_buffer> buffers;
std::transform(
begin(write_msgs_), end(write_msgs_), back_inserter(buffers),
[](Message const& s) { return asio::buffer(s); });
async_write( //
socket_, buffers,
[this, self = shared_from_this()] //
(error_code ec, std::size_t bytes_written) {
// ...
write_msgs_.clear();
});
The transform is a force of habit here, you might prefer
std::vector<asio::const_buffer> buffers;
for (auto& s: write_msgs_)
buffers.push_back(asio::buffer(s));
Live Demo
Modified from this recent example How to safely write to a socket from multiple threads?:
Live On Coliru
#include <boost/asio.hpp>
#include <deque>
#include <iostream>
namespace asio = boost::asio;
using boost::system::error_code;
using asio::ip::tcp;
using Message = std::string;
class chat_session : public std::enable_shared_from_this<chat_session> {
public:
chat_session(tcp::socket socket) : socket_(std::move(socket)) {}
void start() { do_read(); }
void deliver_many(std::vector<Message> msgs) {
post(socket_.get_executor(),
[this, msgs = std::move(msgs), self = shared_from_this()] //
() mutable {
for (auto& msg : msgs) {
do_write(std::move(msg));
}
});
}
void deliver(Message msg) {
post(socket_.get_executor(),
[this, msg = std::move(msg), self = shared_from_this()] //
() mutable { do_write(std::move(msg)); });
}
private:
void do_read() {
async_read_until(
socket_, asio::dynamic_buffer(incoming_), '\0',
[this, self = shared_from_this()] //
(error_code ec, std::size_t length) {
if (!ec) {
process_message(incoming_.substr(0, length - 1));
incoming_.erase(0, length);
do_read();
} else if (ec != asio::error::eof) {
std::cerr << "Read error: " << ec.message() << std::endl;
}
});
}
void do_write(Message message)
{
write_msgs_.push_back(std::move(message)); // assumed on (implicit) strand
if (write_msgs_.size() == 1) {
write_loop();
}
}
void write_loop() {
std::cerr << "write_loop with write_msgs_.size() = " << write_msgs_.size() << std::endl;
if (write_msgs_.empty())
return;
if (write_msgs_.size() > 100) {
std::vector<asio::const_buffer> buffers;
std::transform(
begin(write_msgs_), end(write_msgs_), back_inserter(buffers),
[](Message const& s) { return asio::buffer(s); });
async_write( //
socket_, buffers,
[this, self = shared_from_this()] //
(error_code ec, std::size_t /*length*/) {
if (!ec) {
write_msgs_.clear();
write_loop();
} else if (ec != asio::error::eof) {
std::cerr << "Write error: " << ec.message() << std::endl;
}
});
} else {
async_write( //
socket_, asio::buffer(write_msgs_.front()),
[this, self = shared_from_this()] //
(error_code ec, std::size_t /*length*/) {
if (!ec) {
write_msgs_.pop_front();
write_loop();
} else if (ec != asio::error::eof) {
std::cerr << "Write error: " << ec.message() << std::endl;
}
});
}
}
void process_message(Message const& message) {
std::vector<Message> responses;
for (int i = 0; i < 200; ++i) {
responses.push_back("Response #" + std::to_string(i) + " for " +
message + "\n");
}
// dispatch/post to executor because we might be on a different thread (not in this example)
// (not in this example)
post(socket_.get_executor(),
std::bind(&chat_session::deliver_many, shared_from_this(),
std::move(responses)));
}
tcp::socket socket_;
Message incoming_;
std::deque<Message> write_msgs_;
};
class server {
public:
server(asio::any_io_executor ex, unsigned short port)
: acceptor_(ex, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
make_strand(acceptor_.get_executor()),
[this](error_code ec, tcp::socket&& s) {
if (!ec) {
std::cout << "Accepted " << s.remote_endpoint() << std::endl;
std::make_shared<chat_session>(std::move(s))->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
};
int main() {
asio::thread_pool ctx;
server s(ctx.get_executor(), 8989);
ctx.join();
}
When sending a single message from a client:
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp
./a.out&
sleep .5; printf 'HelloWorld\0' | nc 127.0.0.1 8989 -w1
shows e.g.:
Accepted 127.0.0.1:39538
write_loop with write_msgs_.size() = 1
Response #0 for HelloWorld
write_loop with write_msgs_.size() = 199
Response #1 for HelloWorld
Response #2 for HelloWorld
Response #3 for HelloWorld
Response #4 for HelloWorld
Response #5 for HelloWorld
Response #6 for HelloWorld
Response #7 for HelloWorld
Response #8 for HelloWorld
Response #9 for HelloWorld
Response #10 for HelloWorld
Response #11 for HelloWorld
Response #12 for HelloWorld
Response #13 for HelloWorld
Response #14 for HelloWorld
Response #15 for HelloWorld
Response #16 for HelloWorld
Response #17 for HelloWorld
Response #18 for HelloWorld
Response #19 for HelloWorld
Response #20 for HelloWorld
Response #21 for HelloWorld
Response #22 for HelloWorld
Response #23 for HelloWorld
Response #24 for HelloWorld
Response #25 for HelloWorld
Response #26 for HelloWorld
Response #27 for HelloWorld
Response #28 for HelloWorld
Response #29 for HelloWorld
Response #30 for HelloWorld
Response #31 for HelloWorld
Response #32 for HelloWorld
Response #33 for HelloWorld
Response #34 for HelloWorld
Response #35 for HelloWorld
Response #36 for HelloWorld
Response #37 for HelloWorld
Response #38 for HelloWorld
Response #39 for HelloWorld
Response #40 for HelloWorld
Response #41 for HelloWorld
Response #42 for HelloWorld
Response #43 for HelloWorld
Response #44 for HelloWorld
Response #45 for HelloWorld
Response #46 for HelloWorld
Response #47 for HelloWorld
Response #48 for HelloWorld
Response #49 for HelloWorld
Response #50 for HelloWorld
Response #51 for HelloWorld
Response #52 for HelloWorld
Response #53 for HelloWorld
Response #54 for HelloWorld
Response #55 for HelloWorld
Response #56 for HelloWorld
Response #57 for HelloWorld
Response #58 for HelloWorld
Response #59 for HelloWorld
Response #60 for HelloWorld
Response #61 for HelloWorld
Response #62 for HelloWorld
Response #63 for HelloWorld
Response #64 for HelloWorld
Response #65 for HelloWorld
Response #66 for HelloWorld
Response #67 for HelloWorld
Response #68 for HelloWorld
Response #69 for HelloWorld
Response #70 for HelloWorld
Response #71 for HelloWorld
Response #72 for HelloWorld
Response #73 for HelloWorld
Response #74 for HelloWorld
Response #75 for HelloWorld
Response #76 for HelloWorld
Response #77 for HelloWorld
Response #78 for HelloWorld
Response #79 for HelloWorld
Response #80 for HelloWorld
Response #81 for HelloWorld
Response #82 for HelloWorld
Response #83 for HelloWorld
Response #84 for HelloWorld
Response #85 for HelloWorld
Response #86 for HelloWorld
Response #87 for HelloWorld
Response #88 for HelloWorld
Response #89 for HelloWorld
Response #90 for HelloWorld
Response #91 for HelloWorld
Response #92 for HelloWorld
Response #93 for HelloWorld
Response #94 for HelloWorld
Response #95 for HelloWorld
Response #96 for HelloWorld
Response #97 for HelloWorld
Response #98 for HelloWorld
Response #99 for HelloWorld
Response #100 for HelloWorld
Response #101 for HelloWorld
Response #102 for HelloWorld
Response #103 for HelloWorld
Response #104 for HelloWorld
Response #105 for HelloWorld
Response #106 for HelloWorld
Response #107 for HelloWorld
Response #108 for HelloWorld
Response #109 for HelloWorld
Response #110 for HelloWorld
Response #111 for HelloWorld
Response #112 for HelloWorld
Response #113 for HelloWorld
Response #114 for HelloWorld
Response #115 for HelloWorld
Response #116 for HelloWorld
Response #117 for HelloWorld
Response #118 for HelloWorld
Response #119 for HelloWorld
Response #120 for HelloWorld
Response #121 for HelloWorld
Response #122 for HelloWorld
Response #123 for HelloWorld
Response #124 for HelloWorld
Response #125 for HelloWorld
Response #126 for HelloWorld
Response #127 for HelloWorld
Response #128 for HelloWorld
Response #129 for HelloWorld
Response #130 for HelloWorld
Response #131 for HelloWorld
Response #132 for HelloWorld
Response #133 for HelloWorld
Response #134 for HelloWorld
Response #135 for HelloWorld
Response #136 for HelloWorld
Response #137 for HelloWorld
Response #138 for HelloWorld
Response #139 for HelloWorld
Response #140 for HelloWorld
Response #141 for HelloWorld
Response #142 for HelloWorld
Response #143 for HelloWorld
Response #144 for HelloWorld
Response #145 for HelloWorld
Response #146 for HelloWorld
Response #147 for HelloWorld
Response #148 for HelloWorld
Response #149 for HelloWorld
Response #150 for HelloWorld
Response #151 for HelloWorld
Response #152 for HelloWorld
Response #153 for HelloWorld
Response #154 for HelloWorld
Response #155 for HelloWorld
Response #156 for HelloWorld
Response #157 for HelloWorld
Response #158 for HelloWorld
Response #159 for HelloWorld
Response #160 for HelloWorld
Response #161 for HelloWorld
Response #162 for HelloWorld
Response #163 for HelloWorld
Response #164 for HelloWorld
Response #165 for HelloWorld
Response #166 for HelloWorld
Response #167 for HelloWorld
Response #168 for HelloWorld
Response #169 for HelloWorld
Response #170 for HelloWorld
Response #171 for HelloWorld
Response #172 for HelloWorld
Response #173 for HelloWorld
Response #174 for HelloWorld
Response #175 for HelloWorld
Response #176 for HelloWorld
Response #177 for HelloWorld
Response #178 for HelloWorld
Response #179 for HelloWorld
Response #180 for HelloWorld
Response #181 for HelloWorld
Response #182 for HelloWorld
Response #183 for HelloWorld
Response #184 for HelloWorld
Response #185 for HelloWorld
Response #186 for HelloWorld
Response #187 for HelloWorld
Response #188 for HelloWorld
Response #189 for HelloWorld
Response #190 for HelloWorld
Response #191 for HelloWorld
Response #192 for HelloWorld
Response #193 for HelloWorld
Response #194 for HelloWorld
Response #195 for HelloWorld
Response #196 for HelloWorld
Response #197 for HelloWorld
Response #198 for HelloWorld
Response #199 for HelloWorld
write_loop with write_msgs_.size() = 0
I have the following output in one of my tests:
Assertion failed:
Expected :[[] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] ["seq07"] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] []]
Actual :[() () () () () () () () () () () () () () () () () () () () () () () () () () ("seq07") () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () ()]
What do () and ("seq07") mean in this output?
As noted in another answer, () is an empty list and [] is an empty vector.
Note however that = compares the contents of lists and vectors, it ignores the type of the container:
(= '("seq07") ["seq07"]) ;; => true
(= '(()) [[]]) ;; => true
The assertion failure in the question is due to the actual vector having fewer elements than the expected vector:
(= ['("seq07")] ['("seq07") '()]) ;; => false
() is a notation for list whereas [] is a notation for vectors
() is an empty list and ("seq07") is a list that contains a single member - the string seq07
you can read more about clojure lists here
EDIT: just found this interesting SO question about lists vs vectors
I am trying to capture a suspend lambda / coroutine and invoke it, but the mocking call just hangs.
#Test
fun test() = coroutinesTestRule.testDispatcher.runBlockingTest {
coEvery { db.withTransaction(captureCoroutine<suspend () -> Unit>()) } answers {
coroutine<suspend () -> Unit>().coInvoke()
}
}
Any hints or tips if I'm doing something wrong or is this just impossible?
I believe you need to use coAnswers:
#Test
fun test() = coroutinesTestRule.testDispatcher.runBlockingTest {
coEvery {
db.withTransaction(captureCoroutine<suspend () -> Unit>())
} coAnswers {
coroutine<suspend () -> Unit>().coInvoke()
}
}
I am trying to write a widget test for my flutter screens which are built with bloc. But I am not able to access any of my widget through the test. Following is my widget test code:
FeedbackListBloc feedbackListBloc;
FeedbackListRepository feedbackListRepository;
PrefStore prefStore;
group('login error handling', () {
feedbackListRepository = MockFeedbackListRepository();
prefStore = MockPrefStore();
feedbackListBloc = FeedbackListBloc(feedbackListRepository,prefStore);
testWidgets('validate Feedback List widget', (WidgetTester tester) async {
Widget testWidget = new MediaQuery(
data: MediaQueryData(),
child: MaterialApp(home: FeedbackList(feedbackListBloc: feedbackListBloc))
);
Widget localizedWidget = Localizations(
delegates: [
AppLocalizations.delegate,
// Built-in localization of basic text for Material widgets
GlobalMaterialLocalizations.delegate,
// Built-in localization for text direction LTR/RTL
GlobalWidgetsLocalizations.delegate,
],
locale: Locale('en'),
child: testWidget,
);
await tester.pumpWidget(localizedWidget);
await tester.pumpAndSettle();
expect(find.byIcon(Icons.add), findsOneWidget);
});
});
I am always getting following error in my expect method:
test/widget_test/dashboard/feedback/feedback_list/ui/feedback_list_test.dart
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _WidgetTypeFinder:<zero widgets with type "CircularProgressIndicator" (ignoring offstage
widgets)>
Which: means none were found but one was expected
When the exception was thrown, this was the stack:
#4 main.<anonymous closure>.<anonymous closure> (file:///Users/pankajsahdevea/Desktop/HD/Work/Haufe/Code/IF2.0/if_ui_Sep13,2019/test/widget_test/dashboard/feedback/feedback_list/ui/feedback_list_test.dart:45:7)
<asynchronous suspension>
#5 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:124:25)
#6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:696:19)
<asynchronous suspension>
#9 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:679:14)
#10 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1050:24)
#16 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1047:15)
#17 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:121:22)
#18 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:171:27)
<asynchronous suspension>
#19 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:242:15)
#24 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:239:5)
#25 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:33)
#30 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:13)
#31 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:392:25)
#45 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:384:19)
#46 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:418:5)
#47 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
(elided 28 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package stack_trace)
This was caught by the test expectation on the following line:
file:///Users/pankajsahdevea/Desktop/HD/Work/Haufe/Code/IF2.0/if_ui_Sep13,2019/test/widget_test/dashboard/feedback/feedback_list/ui/feedback_list_test.dart line 45
The test description was:
validate Feedback List widget
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: validate Feedback List widget