Merge lp:~michihenning/storage-framework/more-operations into lp:storage-framework/devel

Proposed by Michi Henning
Status: Merged
Approved by: Michi Henning
Approved revision: 97
Merged at revision: 77
Proposed branch: lp:~michihenning/storage-framework/more-operations
Merge into: lp:storage-framework/devel
Diff against target: 3348 lines (+1103/-1154)
20 files modified
include/unity/storage/qt/ItemListJob.h (+2/-0)
include/unity/storage/qt/internal/Handler.h (+4/-4)
include/unity/storage/qt/internal/ItemImpl.h (+1/-1)
include/unity/storage/qt/internal/ItemListJobImpl.h (+11/-0)
include/unity/storage/qt/internal/ListJobImplBase.h (+3/-0)
include/unity/storage/qt/internal/MultiItemJobImpl.h (+7/-4)
include/unity/storage/qt/internal/MultiItemListJobImpl.h (+80/-0)
src/qt/CMakeLists.txt (+2/-0)
src/qt/internal/AccountsJobImpl.cpp (+9/-9)
src/qt/internal/ItemImpl.cpp (+79/-7)
src/qt/internal/ItemJobImpl.cpp (+6/-7)
src/qt/internal/ItemListJobImpl.cpp (+27/-4)
src/qt/internal/ListJobImplBase.cpp (+3/-3)
src/qt/internal/MultiItemJobImpl.cpp (+16/-18)
src/qt/internal/MultiItemListJobImpl.cpp (+136/-0)
src/qt/internal/StorageErrorImpl.cpp (+1/-1)
src/qt/internal/VoidJobImpl.cpp (+5/-5)
src/qt/internal/unmarshal_error.cpp (+14/-14)
tests/remote-client/MockProvider.cpp (+63/-0)
tests/remote-client/remote-client_test.cpp (+634/-1077)
To merge this branch: bzr merge lp:~michihenning/storage-framework/more-operations
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Approve
Michi Henning (community) Approve
Review via email: mp+308015@code.launchpad.net

Commit message

Added more operation implementations and tests.
Replaced enum class with enum.

Description of the change

Added more operation implementations and tests.
Replaced enum class with enum.

To post a comment you must log in.
95. By Michi Henning

Merged James's QML branch.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:94
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/144/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/852
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/859
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/666/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/666
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/666/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/144/rebuild

review: Approve (continuous-integration)
96. By Michi Henning

Merged devel.

97. By Michi Henning

Re-enabled two Q_DECLARE_METATYPE.

Revision history for this message
Michi Henning (michihenning) wrote :

Top-approving because James is on holidays.

review: Approve
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:95
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/145/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/854
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/861
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/668/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/668
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/668/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/145/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/unity/storage/qt/ItemListJob.h'
2--- include/unity/storage/qt/ItemListJob.h 2016-09-28 04:37:14 +0000
3+++ include/unity/storage/qt/ItemListJob.h 2016-10-10 05:27:34 +0000
4@@ -37,6 +37,7 @@
5 class ListJobImplBase;
6 class ItemListJobImpl;
7 class MultiItemJobImpl;
8+class MultiItemListJobImpl;
9
10 } // namespace internal
11
12@@ -72,6 +73,7 @@
13 friend class internal::ListJobImplBase;
14 friend class internal::ItemListJobImpl;
15 friend class internal::MultiItemJobImpl;
16+ friend class internal::MultiItemListJobImpl;
17 };
18
19 } // namespace qt
20
21=== modified file 'include/unity/storage/qt/internal/Handler.h'
22--- include/unity/storage/qt/internal/Handler.h 2016-09-28 04:37:14 +0000
23+++ include/unity/storage/qt/internal/Handler.h 2016-10-10 05:27:34 +0000
24@@ -54,7 +54,7 @@
25 auto e = unmarshal_error(call);
26 switch (e.type())
27 {
28- case StorageError::NoError:
29+ case StorageError::Type::NoError:
30 {
31 // LCOV_EXCL_START
32 QString msg = "impossible provider exception: " + e.errorString();
33@@ -63,9 +63,9 @@
34 break;
35 // LCOV_EXCL_STOP
36 }
37- case StorageError::LocalCommsError:
38- case StorageError::RemoteCommsError:
39- case StorageError::ResourceError:
40+ case StorageError::Type::LocalCommsError:
41+ case StorageError::Type::RemoteCommsError:
42+ case StorageError::Type::ResourceError:
43 {
44 // Log these errors because they are unexpected.
45 QString msg = "provider exception: " + e.errorString();
46
47=== modified file 'include/unity/storage/qt/internal/ItemImpl.h'
48--- include/unity/storage/qt/internal/ItemImpl.h 2016-10-10 02:07:13 +0000
49+++ include/unity/storage/qt/internal/ItemImpl.h 2016-10-10 05:27:34 +0000
50@@ -145,7 +145,7 @@
51 auto e = StorageErrorImpl::logic_error(method + ": source and target must belong to the same account");
52 return T::make_job(e);
53 }
54- if (newParent.type() == Item::File)
55+ if (newParent.type() == Item::Type::File)
56 {
57 auto e = StorageErrorImpl::logic_error(method + ": newParent cannot be a file");
58 return T::make_job(e);
59
60=== modified file 'include/unity/storage/qt/internal/ItemListJobImpl.h'
61--- include/unity/storage/qt/internal/ItemListJobImpl.h 2016-09-28 04:37:14 +0000
62+++ include/unity/storage/qt/internal/ItemListJobImpl.h 2016-10-10 05:27:34 +0000
63@@ -40,6 +40,7 @@
64 {
65
66 class AccountImpl;
67+class ItemImpl;
68
69 class ItemListJobImpl : public ListJobImplBase
70 {
71@@ -51,6 +52,10 @@
72 QString const& method,
73 QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
74 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
75+ static ItemListJob* make_job(std::shared_ptr<ItemImpl> const& item,
76+ QString const& method,
77+ QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
78+ std::function<void(storage::internal::ItemMetadata const&)> const& validate);
79 static ItemListJob* make_job(StorageError const& error);
80
81 private:
82@@ -59,6 +64,12 @@
83 QString const& method,
84 QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
85 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
86+ ItemListJobImpl(std::shared_ptr<ItemImpl> const& account,
87+ QString const& method,
88+ QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
89+ std::function<void(storage::internal::ItemMetadata const&)> const& validate);
90+
91+ std::shared_ptr<ItemImpl> item_impl_;
92 };
93
94 } // namespace internal
95
96=== modified file 'include/unity/storage/qt/internal/ListJobImplBase.h'
97--- include/unity/storage/qt/internal/ListJobImplBase.h 2016-09-28 04:37:14 +0000
98+++ include/unity/storage/qt/internal/ListJobImplBase.h 2016-10-10 05:27:34 +0000
99@@ -21,7 +21,10 @@
100 #include <unity/storage/qt/ItemListJob.h>
101 #include <unity/storage/qt/StorageError.h>
102
103+#pragma GCC diagnostic push
104+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
105 #include <QDBusPendingReply>
106+#pragma GCC diagnostic pop
107
108 namespace unity
109 {
110
111=== modified file 'include/unity/storage/qt/internal/MultiItemJobImpl.h'
112--- include/unity/storage/qt/internal/MultiItemJobImpl.h 2016-09-28 04:37:14 +0000
113+++ include/unity/storage/qt/internal/MultiItemJobImpl.h 2016-10-10 05:27:34 +0000
114@@ -45,19 +45,22 @@
115 {
116 Q_OBJECT
117 public:
118+ using ReplyType = QList<QDBusPendingReply<storage::internal::ItemMetadata>>;
119+ using ValidateFunc = std::function<void(storage::internal::ItemMetadata const&)>;
120+
121 virtual ~MultiItemJobImpl() = default;
122
123 static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account,
124 QString const& method,
125- QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies,
126- std::function<void(storage::internal::ItemMetadata const&)> const& validate);
127+ ReplyType const& replies,
128+ ValidateFunc const& validate);
129
130 private:
131 MultiItemJobImpl() = default;
132 MultiItemJobImpl(std::shared_ptr<AccountImpl> const& account,
133 QString const& method,
134- QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies,
135- std::function<void(storage::internal::ItemMetadata const&)> const& validate);
136+ ReplyType const& replies,
137+ ValidateFunc const& validate);
138
139 int replies_remaining_;
140 };
141
142=== added file 'include/unity/storage/qt/internal/MultiItemListJobImpl.h'
143--- include/unity/storage/qt/internal/MultiItemListJobImpl.h 1970-01-01 00:00:00 +0000
144+++ include/unity/storage/qt/internal/MultiItemListJobImpl.h 2016-10-10 05:27:34 +0000
145@@ -0,0 +1,80 @@
146+/*
147+ * Copyright (C) 2016 Canonical Ltd
148+ *
149+ * This program is free software: you can redistribute it and/or modify
150+ * it under the terms of the GNU Lesser General Public License version 3 as
151+ * published by the Free Software Foundation.
152+ *
153+ * This program is distributed in the hope that it will be useful,
154+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
155+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
156+ * GNU Lesser General Public License for more details.
157+ *
158+ * You should have received a copy of the GNU Lesser General Public License
159+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
160+ *
161+ * Authors: Michi Henning <michi.henning@canonical.com>
162+ */
163+
164+#pragma once
165+
166+#include <unity/storage/qt/internal/ListJobImplBase.h>
167+#include <unity/storage/qt/ItemListJob.h>
168+
169+#include <QDBusPendingReply>
170+
171+namespace unity
172+{
173+namespace storage
174+{
175+namespace internal
176+{
177+
178+class ItemMetadata;
179+
180+}
181+
182+namespace qt
183+{
184+namespace internal
185+{
186+
187+class ItemImpl;
188+
189+class MultiItemListJobImpl : public ListJobImplBase
190+{
191+ Q_OBJECT
192+public:
193+ using ReplyType = QDBusPendingReply<QList<storage::internal::ItemMetadata>, QString>;
194+ using ValidateFunc = std::function<void(storage::internal::ItemMetadata const&)>;
195+ using FetchFunc = std::function<QDBusPendingReply<QList<unity::storage::internal::ItemMetadata>,
196+ QString>(QString const& page_token)>;
197+
198+ virtual ~MultiItemListJobImpl() = default;
199+
200+ static ItemListJob* make_job(std::shared_ptr<ItemImpl> const& item,
201+ QString const& method,
202+ ReplyType const& reply,
203+ ValidateFunc const& validate,
204+ FetchFunc const& fetch_next);
205+ static ItemListJob* make_job(StorageError const& error);
206+
207+private:
208+ MultiItemListJobImpl() = default;
209+ MultiItemListJobImpl(std::shared_ptr<ItemImpl> const& item,
210+ QString const& method,
211+ ReplyType const& reply,
212+ ValidateFunc const& validate,
213+ FetchFunc const& fetch_next);
214+
215+ std::function<void(ReplyType const&)> process_reply_;
216+ std::function<void(StorageError const&)> process_error_;
217+
218+ std::shared_ptr<ItemImpl> item_impl_;
219+ FetchFunc fetch_next_;
220+};
221+
222+} // namespace internal
223+} // namespace qt
224+} // namespace storage
225+} // namespace unity
226
227=== modified file 'src/qt/CMakeLists.txt'
228--- src/qt/CMakeLists.txt 2016-10-10 05:18:24 +0000
229+++ src/qt/CMakeLists.txt 2016-10-10 05:27:34 +0000
230@@ -32,6 +32,7 @@
231 internal/ItemListJobImpl.cpp
232 internal/ListJobImplBase.cpp
233 internal/MultiItemJobImpl.cpp
234+ internal/MultiItemListJobImpl.cpp
235 internal/RuntimeImpl.cpp
236 internal/StorageErrorImpl.cpp
237 internal/unmarshal_error.cpp
238@@ -51,6 +52,7 @@
239 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ItemListJobImpl.h
240 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ListJobImplBase.h
241 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/MultiItemJobImpl.h
242+ ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/MultiItemListJobImpl.h
243 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/VoidJobImpl.h
244 )
245
246
247=== modified file 'src/qt/internal/AccountsJobImpl.cpp'
248--- src/qt/internal/AccountsJobImpl.cpp 2016-09-20 04:53:49 +0000
249+++ src/qt/internal/AccountsJobImpl.cpp 2016-10-10 05:27:34 +0000
250@@ -52,7 +52,7 @@
251
252 AccountsJobImpl::AccountsJobImpl(AccountsJob* public_instance, shared_ptr<RuntimeImpl> const& runtime)
253 : public_instance_(public_instance)
254- , status_(AccountsJob::Loading)
255+ , status_(AccountsJob::Status::Loading)
256 , runtime_(runtime)
257 {
258 assert(public_instance);
259@@ -63,13 +63,13 @@
260
261 AccountsJobImpl::AccountsJobImpl(AccountsJob* public_instance, StorageError const& error)
262 : public_instance_(public_instance)
263- , status_(AccountsJob::Loading)
264+ , status_(AccountsJob::Status::Loading)
265 , error_(error)
266 {
267 assert(public_instance);
268- assert(error.type() != StorageError::NoError);
269+ assert(error.type() != StorageError::Type::NoError);
270
271- status_ = emit_status_changed(AccountsJob::Error);
272+ status_ = emit_status_changed(AccountsJob::Status::Error);
273 }
274
275 bool AccountsJobImpl::isValid() const
276@@ -94,7 +94,7 @@
277 {
278 return QList<Account>();
279 }
280- if (status_ != AccountsJob::Finished)
281+ if (status_ != AccountsJob::Status::Finished)
282 {
283 return QList<Account>();
284 }
285@@ -113,13 +113,13 @@
286 {
287 disconnect(this);
288 error_ = StorageErrorImpl::local_comms_error("AccountsJob(): timeout retrieving Online accounts");
289- status_ = emit_status_changed(AccountsJob::Error);
290+ status_ = emit_status_changed(AccountsJob::Status::Error);
291 }
292 // LCOV_EXCL_STOP
293
294 AccountsJob::Status AccountsJobImpl::emit_status_changed(AccountsJob::Status new_status) const
295 {
296- if (status_ == AccountsJob::Loading) // Once in a final state, we don't emit the signal again.
297+ if (status_ == AccountsJob::Status::Loading) // Once in a final state, we don't emit the signal again.
298 {
299 // We defer emission of the signal so the client gets a chance to connect to the signal
300 // in case we emit the signal from the constructor.
301@@ -139,7 +139,7 @@
302 QString msg = method + ": Runtime was destroyed previously";
303 auto This = const_cast<AccountsJobImpl*>(this);
304 This->error_ = StorageErrorImpl::runtime_destroyed_error(msg);
305- This->status_ = emit_status_changed(AccountsJob::Error);
306+ This->status_ = emit_status_changed(AccountsJob::Status::Error);
307 }
308 return runtime;
309 }
310@@ -174,7 +174,7 @@
311 a->displayName()));
312 }
313 }
314- status_ = emit_status_changed(AccountsJob::Finished);
315+ status_ = emit_status_changed(AccountsJob::Status::Finished);
316 }
317
318 } // namespace internal
319
320=== modified file 'src/qt/internal/ItemImpl.cpp'
321--- src/qt/internal/ItemImpl.cpp 2016-10-10 02:07:13 +0000
322+++ src/qt/internal/ItemImpl.cpp 2016-10-10 05:27:34 +0000
323@@ -23,6 +23,7 @@
324 #include <unity/storage/qt/internal/ItemJobImpl.h>
325 #include <unity/storage/qt/internal/ItemListJobImpl.h>
326 #include <unity/storage/qt/internal/MultiItemJobImpl.h>
327+#include <unity/storage/qt/internal/MultiItemListJobImpl.h>
328 #include <unity/storage/qt/internal/VoidJobImpl.h>
329 #include <unity/storage/qt/internal/validate.h>
330
331@@ -81,11 +82,11 @@
332 switch (md_.type)
333 {
334 case storage::ItemType::file:
335- return Item::File;
336+ return Item::Type::File;
337 case storage::ItemType::folder:
338- return Item::Folder;
339+ return Item::Type::Folder;
340 case storage::ItemType::root:
341- return Item::Root;
342+ return Item::Type::Root;
343 default:
344 abort(); // LCOV_EXCL_LINE // Impossible
345 }
346@@ -190,7 +191,7 @@
347 {
348 if (md.type == ItemType::root)
349 {
350- QString msg = method + ": impossible root item returned by server";
351+ QString msg = method + ": impossible root item returned by provider";
352 qCritical().noquote() << msg;
353 throw StorageErrorImpl::local_comms_error(msg);
354 }
355@@ -241,17 +242,88 @@
356
357 ItemListJob* ItemImpl::list() const
358 {
359- return nullptr; // TODO
360+ QString const method = "Item::list()";
361+
362+ auto invalid_job = check_invalid_or_destroyed<MultiItemListJobImpl>(method);
363+ if (invalid_job)
364+ {
365+ return invalid_job;
366+ }
367+ if (md_.type == storage::ItemType::file)
368+ {
369+ auto e = StorageErrorImpl::logic_error(method + ": cannot perform list on a file");
370+ return ItemListJobImpl::make_job(e);
371+ }
372+
373+ auto validate = [method](storage::internal::ItemMetadata const& md)
374+ {
375+ if (md.type == storage::ItemType::root)
376+ {
377+ throw StorageErrorImpl::local_comms_error(method + ": impossible root item returned by provider");
378+ }
379+ };
380+
381+ auto fetch_next = [this](QString const& page_token)
382+ {
383+ return account_->provider()->List(md_.item_id, page_token);
384+ };
385+
386+ auto reply = account_->provider()->List(md_.item_id, "");
387+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
388+ return MultiItemListJobImpl::make_job(This, method, reply, validate, fetch_next);
389 }
390
391 ItemListJob* ItemImpl::lookup(QString const& name) const
392 {
393- return nullptr; // TODO
394+ QString const method = "Item::lookup()";
395+
396+ auto invalid_job = check_invalid_or_destroyed<ItemListJobImpl>(method);
397+ if (invalid_job)
398+ {
399+ return invalid_job;
400+ }
401+ if (md_.type == storage::ItemType::file)
402+ {
403+ auto e = StorageErrorImpl::logic_error(method + ": cannot perform lookup on a file");
404+ return ItemListJobImpl::make_job(e);
405+ }
406+
407+ auto validate = [](storage::internal::ItemMetadata const&)
408+ {
409+ };
410+
411+ auto reply = account_->provider()->Lookup(md_.item_id, name);
412+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
413+ return ItemListJobImpl::make_job(This, method, reply, validate);
414 }
415
416 ItemJob* ItemImpl::createFolder(QString const& name) const
417 {
418- return nullptr; // TODO
419+ QString const method = "Item::createFolder()";
420+
421+ auto invalid_job = check_invalid_or_destroyed<ItemJobImpl>(method);
422+ if (invalid_job)
423+ {
424+ return invalid_job;
425+ }
426+ if (md_.type == storage::ItemType::file)
427+ {
428+ auto e = StorageErrorImpl::logic_error(method + ": cannot create a folder with a file as the parent");
429+ return ItemJobImpl::make_job(e);
430+ }
431+
432+ auto validate = [method](storage::internal::ItemMetadata const& md)
433+ {
434+ if (md.type != storage::ItemType::file)
435+ {
436+ return;
437+ }
438+ throw StorageErrorImpl::local_comms_error(method + ": impossible file item returned by provider");
439+ };
440+
441+ auto reply = account_->provider()->CreateFolder(md_.item_id, name);
442+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
443+ return ItemJobImpl::make_job(This, method, reply, validate);
444 }
445
446 Uploader* ItemImpl::createFile(QString const& name) const
447
448=== modified file 'src/qt/internal/ItemJobImpl.cpp'
449--- src/qt/internal/ItemJobImpl.cpp 2016-09-29 02:40:05 +0000
450+++ src/qt/internal/ItemJobImpl.cpp 2016-10-10 05:27:34 +0000
451@@ -40,7 +40,7 @@
452 QString const& method,
453 QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
454 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
455- : status_(ItemJob::Loading)
456+ : status_(ItemJob::Status::Loading)
457 , method_(method)
458 , account_(account)
459 , validate_(validate)
460@@ -55,7 +55,7 @@
461 if (!runtime || !runtime->isValid())
462 {
463 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
464- status_ = ItemJob::Error;
465+ status_ = ItemJob::Status::Error;
466 Q_EMIT public_instance_->statusChanged(status_);
467 return;
468 }
469@@ -65,13 +65,13 @@
470 {
471 validate_(metadata);
472 item_ = ItemImpl::make_item(method_, metadata, account_);
473- status_ = ItemJob::Finished;
474+ status_ = ItemJob::Status::Finished;
475 }
476 catch (StorageError const& e)
477 {
478 // Bad metadata received from provider, validate_() or make_item() have logged it.
479 error_ = e;
480- status_ = ItemJob::Error;
481+ status_ = ItemJob::Status::Error;
482 }
483 Q_EMIT public_instance_->statusChanged(status_);
484 };
485@@ -79,7 +79,7 @@
486 auto process_error = [this](StorageError const& error)
487 {
488 error_ = error;
489- status_ = ItemJob::Error;
490+ status_ = ItemJob::Status::Error;
491 Q_EMIT public_instance_->statusChanged(status_);
492 };
493
494@@ -92,12 +92,11 @@
495 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
496 : ItemJobImpl(item->account_impl(), method, reply, validate)
497 {
498- assert(item);
499 item_impl_= item;
500 }
501
502 ItemJobImpl::ItemJobImpl(StorageError const& error)
503- : status_(ItemJob::Error)
504+ : status_(ItemJob::Status::Error)
505 , error_(error)
506 {
507 }
508
509=== modified file 'src/qt/internal/ItemListJobImpl.cpp'
510--- src/qt/internal/ItemListJobImpl.cpp 2016-09-28 04:37:14 +0000
511+++ src/qt/internal/ItemListJobImpl.cpp 2016-10-10 05:27:34 +0000
512@@ -47,7 +47,7 @@
513 if (!runtime || !runtime->isValid())
514 {
515 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
516- status_ = ItemListJob::Error;
517+ status_ = ItemListJob::Status::Error;
518 Q_EMIT public_instance_->statusChanged(status_);
519 return;
520 }
521@@ -67,8 +67,11 @@
522 // Bad metadata received from provider, validate_() or make_item() have logged it.
523 }
524 }
525- status_ = ItemListJob::Finished;
526- Q_EMIT public_instance_->itemsReady(items);
527+ status_ = ItemListJob::Status::Finished;
528+ if (!items.isEmpty())
529+ {
530+ Q_EMIT public_instance_->itemsReady(items);
531+ }
532 Q_EMIT public_instance_->statusChanged(status_);
533 };
534
535@@ -76,13 +79,22 @@
536 {
537 // TODO: method name is not being set this way.
538 error_ = error;
539- status_ = ItemListJob::Error;
540+ status_ = ItemListJob::Status::Error;
541 Q_EMIT public_instance_->statusChanged(status_);
542 };
543
544 new Handler<QList<storage::internal::ItemMetadata>>(this, reply, process_reply, process_error);
545 }
546
547+ItemListJobImpl::ItemListJobImpl(shared_ptr<ItemImpl> const& item,
548+ QString const& method,
549+ QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
550+ std::function<void(storage::internal::ItemMetadata const&)> const& validate)
551+ : ItemListJobImpl(item->account_impl(), method, reply, validate)
552+{
553+ item_impl_ = item;
554+}
555+
556 ItemListJob* ItemListJobImpl::make_job(shared_ptr<AccountImpl> const& account,
557 QString const& method,
558 QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
559@@ -94,6 +106,17 @@
560 return job;
561 }
562
563+ItemListJob* ItemListJobImpl::make_job(shared_ptr<ItemImpl> const& item,
564+ QString const& method,
565+ QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
566+ std::function<void(storage::internal::ItemMetadata const&)> const& validate)
567+{
568+ unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(item, method, reply, validate));
569+ auto job = new ItemListJob(move(impl));
570+ job->p_->set_public_instance(job);
571+ return job;
572+}
573+
574 ItemListJob* ItemListJobImpl::make_job(StorageError const& error)
575 {
576 return ListJobImplBase::make_job(error);
577
578=== modified file 'src/qt/internal/ListJobImplBase.cpp'
579--- src/qt/internal/ListJobImplBase.cpp 2016-09-28 04:37:14 +0000
580+++ src/qt/internal/ListJobImplBase.cpp 2016-10-10 05:27:34 +0000
581@@ -37,14 +37,14 @@
582 {
583
584 ListJobImplBase::ListJobImplBase()
585- : status_(ItemListJob::Finished)
586+ : status_(ItemListJob::Status::Finished)
587 {
588 }
589
590 ListJobImplBase::ListJobImplBase(shared_ptr<AccountImpl> const& account,
591 QString const& method,
592 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
593- : status_(ItemListJob::Loading)
594+ : status_(ItemListJob::Status::Loading)
595 , method_(method)
596 , account_(account)
597 , validate_(validate)
598@@ -55,7 +55,7 @@
599 }
600
601 ListJobImplBase::ListJobImplBase(StorageError const& error)
602- : status_(ItemListJob::Error)
603+ : status_(ItemListJob::Status::Error)
604 , error_(error)
605 {
606 }
607
608=== modified file 'src/qt/internal/MultiItemJobImpl.cpp'
609--- src/qt/internal/MultiItemJobImpl.cpp 2016-09-28 04:37:14 +0000
610+++ src/qt/internal/MultiItemJobImpl.cpp 2016-10-10 05:27:34 +0000
611@@ -37,8 +37,8 @@
612
613 MultiItemJobImpl::MultiItemJobImpl(shared_ptr<AccountImpl> const& account,
614 QString const& method,
615- QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies,
616- std::function<void(storage::internal::ItemMetadata const&)> const& validate)
617+ ReplyType const& replies,
618+ ValidateFunc const& validate)
619 : ListJobImplBase(account, method, validate)
620 , replies_remaining_(replies.size())
621 {
622@@ -54,20 +54,18 @@
623
624 auto process_reply = [this](QDBusPendingReply<storage::internal::ItemMetadata> const& r)
625 {
626- assert(status_ != ItemListJob::Finished);
627+ if (status_ != ItemListJob::Status::Loading)
628+ {
629+ return;
630+ }
631
632 --replies_remaining_;
633
634- if (status_ == ItemListJob::Error)
635- {
636- return;
637- }
638-
639 auto runtime = account_->runtime();
640 if (!runtime || !runtime->isValid())
641 {
642 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
643- status_ = ItemListJob::Error;
644+ status_ = ItemListJob::Status::Error;
645 Q_EMIT public_instance_->statusChanged(status_);
646 return;
647 }
648@@ -82,33 +80,33 @@
649 catch (StorageError const& e)
650 {
651 // Bad metadata received from provider, validate_() or make_item() have logged it.
652- status_ = ItemListJob::Error;
653+ status_ = ItemListJob::Status::Error;
654 error_ = e;
655 Q_EMIT public_instance_->statusChanged(status_);
656 return;
657 }
658 QList<Item> items;
659 items.append(item);
660+ if (replies_remaining_ == 0)
661+ {
662+ status_ = ItemListJob::Status::Finished;
663+ }
664 Q_EMIT public_instance_->itemsReady(items);
665-
666 if (replies_remaining_ == 0)
667 {
668- status_ = ItemListJob::Finished;
669 Q_EMIT public_instance_->statusChanged(status_);
670 }
671 };
672
673 auto process_error = [this](StorageError const& error)
674 {
675- assert(status_ != ItemListJob::Finished);
676-
677- if (status_ == ItemListJob::Error)
678+ if (status_ != ItemListJob::Status::Loading)
679 {
680 return;
681 }
682 // TODO: method name is not being set this way.
683 error_ = error;
684- status_ = ItemListJob::Error;
685+ status_ = ItemListJob::Status::Error;
686 Q_EMIT public_instance_->statusChanged(status_);
687 };
688
689@@ -120,8 +118,8 @@
690
691 ItemListJob* MultiItemJobImpl::make_job(shared_ptr<AccountImpl> const& account,
692 QString const& method,
693- QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies,
694- std::function<void(storage::internal::ItemMetadata const&)> const& validate)
695+ ReplyType const& replies,
696+ ValidateFunc const& validate)
697 {
698 unique_ptr<MultiItemJobImpl> impl(new MultiItemJobImpl(account, method, replies, validate));
699 auto job = new ItemListJob(move(impl));
700
701=== added file 'src/qt/internal/MultiItemListJobImpl.cpp'
702--- src/qt/internal/MultiItemListJobImpl.cpp 1970-01-01 00:00:00 +0000
703+++ src/qt/internal/MultiItemListJobImpl.cpp 2016-10-10 05:27:34 +0000
704@@ -0,0 +1,136 @@
705+/*
706+ * Copyright (C) 2016 Canonical Ltd
707+ *
708+ * This program is free software: you can redistribute it and/or modify
709+ * it under the terms of the GNU Lesser General Public License version 3 as
710+ * published by the Free Software Foundation.
711+ *
712+ * This program is distributed in the hope that it will be useful,
713+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
714+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
715+ * GNU Lesser General Public License for more details.
716+ *
717+ * You should have received a copy of the GNU Lesser General Public License
718+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
719+ *
720+ * Authors: Michi Henning <michi.henning@canonical.com>
721+ */
722+
723+#include <unity/storage/qt/internal/MultiItemListJobImpl.h>
724+
725+#include <unity/storage/internal/dbusmarshal.h>
726+#include <unity/storage/qt/internal/AccountImpl.h>
727+#include <unity/storage/qt/internal/Handler.h>
728+#include <unity/storage/qt/internal/ItemImpl.h>
729+#include <unity/storage/qt/internal/RuntimeImpl.h>
730+
731+using namespace std;
732+
733+namespace unity
734+{
735+namespace storage
736+{
737+namespace qt
738+{
739+namespace internal
740+{
741+
742+MultiItemListJobImpl::MultiItemListJobImpl(shared_ptr<ItemImpl> const& item,
743+ QString const& method,
744+ ReplyType const& reply,
745+ ValidateFunc const& validate,
746+ FetchFunc const& fetch_next)
747+ : ListJobImplBase(item->account_impl(), method, validate)
748+ , fetch_next_(fetch_next)
749+{
750+ assert(fetch_next);
751+
752+ item_impl_ = item;
753+
754+ process_reply_ = [this](ReplyType const& r)
755+ {
756+ if (status_ != ItemListJob::Status::Loading)
757+ {
758+ return;
759+ }
760+ auto runtime = item_impl_->account_impl()->runtime();
761+ if (!runtime || !runtime->isValid())
762+ {
763+ error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
764+ status_ = ItemListJob::Status::Error;
765+ Q_EMIT public_instance_->statusChanged(status_);
766+ return;
767+ }
768+
769+ QList<Item> items;
770+ auto metadata = r.argumentAt<0>();
771+ for (auto const& md : metadata)
772+ {
773+ try
774+ {
775+ validate_(md);
776+ auto item = ItemImpl::make_item(method_, md, account_);
777+ items.append(item);
778+ }
779+ catch (StorageError const& e)
780+ {
781+ // Bad metadata received from provider, validate_() or make_item() have logged it.
782+ error_ = e;
783+ status_ = ItemListJob::Status::Error;
784+ Q_EMIT public_instance_->statusChanged(status_);
785+ return;
786+ }
787+ }
788+ QString token = r.argumentAt<1>();
789+ if (token.isEmpty())
790+ {
791+ status_ = ItemListJob::Status::Finished;
792+ }
793+ if (!items.isEmpty())
794+ {
795+ Q_EMIT public_instance_->itemsReady(items);
796+ }
797+ if (token.isEmpty())
798+ {
799+ Q_EMIT public_instance_->statusChanged(status_);
800+ }
801+ else
802+ {
803+ new Handler<ReplyType>(this, fetch_next_(token), process_reply_, process_error_);
804+ }
805+ };
806+
807+ process_error_ = [this](StorageError const& error)
808+ {
809+ assert(status_ == ItemListJob::Status::Loading);
810+
811+ // TODO: method name is not being set this way.
812+ error_ = error;
813+ status_ = ItemListJob::Status::Error;
814+ Q_EMIT public_instance_->statusChanged(status_);
815+ };
816+
817+ new Handler<ReplyType>(this, reply, process_reply_, process_error_);
818+}
819+
820+ItemListJob* MultiItemListJobImpl::make_job(shared_ptr<ItemImpl> const& item,
821+ QString const& method,
822+ ReplyType const& reply,
823+ ValidateFunc const& validate,
824+ FetchFunc const& fetch_next)
825+{
826+ unique_ptr<MultiItemListJobImpl> impl(new MultiItemListJobImpl(item, method, reply, validate, fetch_next));
827+ auto job = new ItemListJob(move(impl));
828+ job->p_->set_public_instance(job);
829+ return job;
830+}
831+
832+ItemListJob* MultiItemListJobImpl::make_job(StorageError const& error)
833+{
834+ return ListJobImplBase::make_job(error);
835+}
836+
837+} // namespace internal
838+} // namespace qt
839+} // namespace storage
840+} // namespace unity
841
842=== modified file 'src/qt/internal/StorageErrorImpl.cpp'
843--- src/qt/internal/StorageErrorImpl.cpp 2016-10-10 01:18:01 +0000
844+++ src/qt/internal/StorageErrorImpl.cpp 2016-10-10 05:27:34 +0000
845@@ -35,7 +35,7 @@
846 namespace
847 {
848
849-static const QString ERROR_NAMES[StorageError::__LAST_STORAGE_ERROR] =
850+static const QString ERROR_NAMES[StorageError::Type::__LAST_STORAGE_ERROR] =
851 {
852 QStringLiteral("NoError"),
853 QStringLiteral("LocalCommsError"),
854
855=== modified file 'src/qt/internal/VoidJobImpl.cpp'
856--- src/qt/internal/VoidJobImpl.cpp 2016-09-28 04:37:14 +0000
857+++ src/qt/internal/VoidJobImpl.cpp 2016-10-10 05:27:34 +0000
858@@ -36,7 +36,7 @@
859 VoidJobImpl::VoidJobImpl(shared_ptr<ItemImpl> const& item,
860 QString const& method,
861 QDBusPendingReply<void> const& reply)
862- : status_(VoidJob::Loading)
863+ : status_(VoidJob::Status::Loading)
864 , method_(method)
865 , item_(item)
866 {
867@@ -49,19 +49,19 @@
868 if (!runtime || !runtime->isValid())
869 {
870 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
871- status_ = VoidJob::Error;
872+ status_ = VoidJob::Status::Error;
873 Q_EMIT public_instance_->statusChanged(status_);
874 return;
875 }
876
877- status_ = VoidJob::Finished;
878+ status_ = VoidJob::Status::Finished;
879 Q_EMIT public_instance_->statusChanged(status_);
880 };
881
882 auto process_error = [this](StorageError const& error)
883 {
884 error_ = error;
885- status_ = VoidJob::Error;
886+ status_ = VoidJob::Status::Error;
887 Q_EMIT public_instance_->statusChanged(status_);
888 };
889
890@@ -69,7 +69,7 @@
891 }
892
893 VoidJobImpl::VoidJobImpl(StorageError const& error)
894- : status_(VoidJob::Error)
895+ : status_(VoidJob::Status::Error)
896 , error_(error)
897 {
898 }
899
900=== modified file 'src/qt/internal/unmarshal_error.cpp'
901--- src/qt/internal/unmarshal_error.cpp 2016-09-16 06:25:08 +0000
902+++ src/qt/internal/unmarshal_error.cpp 2016-10-10 05:27:34 +0000
903@@ -49,7 +49,7 @@
904 }
905
906 template<>
907-StorageError make_error<StorageError::NotExists>(QDBusPendingCallWatcher const& call)
908+StorageError make_error<StorageError::Type::NotExists>(QDBusPendingCallWatcher const& call)
909 {
910 QDBusPendingReply<QString, QString> reply = call;
911 auto msg = reply.argumentAt<0>();
912@@ -58,7 +58,7 @@
913 }
914
915 template<>
916-StorageError make_error<StorageError::Exists>(QDBusPendingCallWatcher const& call)
917+StorageError make_error<StorageError::Type::Exists>(QDBusPendingCallWatcher const& call)
918 {
919 QDBusPendingReply<QString, QString, QString> reply = call;
920 auto msg = reply.argumentAt<0>();
921@@ -68,7 +68,7 @@
922 }
923
924 template<>
925-StorageError make_error<StorageError::ResourceError>(QDBusPendingCallWatcher const& call)
926+StorageError make_error<StorageError::Type::ResourceError>(QDBusPendingCallWatcher const& call)
927 {
928 QDBusPendingReply<QString, int> reply = call;
929 auto msg = reply.argumentAt<0>();
930@@ -78,17 +78,17 @@
931
932 static const map<QString, function<StorageError(QDBusPendingCallWatcher const& call)>> exception_factories =
933 {
934- { "RemoteCommsException", make_error<StorageError::RemoteCommsError> },
935- { "NotExistsException", make_error<StorageError::NotExists> },
936- { "ExistsException", make_error<StorageError::Exists> },
937- { "ConflictException", make_error<StorageError::Conflict> },
938- { "PermissionException", make_error<StorageError::PermissionDenied> },
939- { "CancelledException", make_error<StorageError::Cancelled> },
940- { "LogicException", make_error<StorageError::LogicError> },
941- { "InvalidArgumentException", make_error<StorageError::InvalidArgument> },
942- { "ResourceException", make_error<StorageError::ResourceError> },
943- { "QuotaException", make_error<StorageError::QuotaExceeded> },
944- { "UnknownException", make_error<StorageError::LocalCommsError> } // Yes, LocalCommsError is intentional
945+ { "RemoteCommsException", make_error<StorageError::Type::RemoteCommsError> },
946+ { "NotExistsException", make_error<StorageError::Type::NotExists> },
947+ { "ExistsException", make_error<StorageError::Type::Exists> },
948+ { "ConflictException", make_error<StorageError::Type::Conflict> },
949+ { "PermissionException", make_error<StorageError::Type::PermissionDenied> },
950+ { "CancelledException", make_error<StorageError::Type::Cancelled> },
951+ { "LogicException", make_error<StorageError::Type::LogicError> },
952+ { "InvalidArgumentException", make_error<StorageError::Type::InvalidArgument> },
953+ { "ResourceException", make_error<StorageError::Type::ResourceError> },
954+ { "QuotaException", make_error<StorageError::Type::QuotaExceeded> },
955+ { "UnknownException", make_error<StorageError::Type::LocalCommsError> } // Yes, LocalCommsError is intentional
956 };
957
958 } // namespace
959
960=== modified file 'tests/remote-client/MockProvider.cpp'
961--- tests/remote-client/MockProvider.cpp 2016-09-29 02:40:05 +0000
962+++ tests/remote-client/MockProvider.cpp 2016-10-10 05:27:34 +0000
963@@ -75,6 +75,64 @@
964 string const& item_id, string const& page_token,
965 Context const&)
966 {
967+ if (cmd_ == "list_slow")
968+ {
969+ this_thread::sleep_for(chrono::seconds(1));
970+ }
971+ if (cmd_ == "list_empty")
972+ {
973+ boost::promise<tuple<ItemList,string>> p;
974+ p.set_value(make_tuple(ItemList(), string()));
975+ return p.get_future();
976+ }
977+ if (cmd_ == "list_no_permission")
978+ {
979+ string msg = string("permission denied");
980+ return make_exceptional_future<tuple<ItemList,string>>(PermissionException(msg));
981+ }
982+ if (cmd_ == "list_return_root")
983+ {
984+ ItemList children =
985+ {
986+ {
987+ "child_id", { "root_id" }, "Child", "etag", ItemType::root,
988+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
989+ }
990+ };
991+ boost::promise<tuple<ItemList,string>> p;
992+ p.set_value(make_tuple(children, string()));
993+ return p.get_future();
994+ }
995+ if (cmd_ == "list_two_children")
996+ {
997+ ItemList children;
998+ string next_token;
999+ if (page_token == "")
1000+ {
1001+ next_token = "next";
1002+ children =
1003+ {
1004+ {
1005+ "child_id", { "root_id" }, "Child", "etag", ItemType::file,
1006+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
1007+ }
1008+ };
1009+ }
1010+ else
1011+ {
1012+ next_token = "";
1013+ children =
1014+ {
1015+ {
1016+ "child2_id", { "root_id" }, "Child2", "etag", ItemType::file,
1017+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
1018+ }
1019+ };
1020+ }
1021+ boost::promise<tuple<ItemList,string>> p;
1022+ p.set_value(make_tuple(children, next_token));
1023+ return p.get_future();
1024+ }
1025 if (item_id != "root_id")
1026 {
1027 string msg = string("Item::list(): no such item: \"") + item_id + "\"";
1028@@ -191,6 +249,11 @@
1029 string const& parent_id, string const& name,
1030 Context const&)
1031 {
1032+ if (cmd_ == "create_folder_returns_file")
1033+ {
1034+ Item metadata{"new_folder_id", { parent_id }, name, "etag", ItemType::file, {}};
1035+ return make_ready_future<Item>(metadata);
1036+ }
1037 Item metadata{"new_folder_id", { parent_id }, name, "etag", ItemType::folder, {}};
1038 return make_ready_future<Item>(metadata);
1039 }
1040
1041=== modified file 'tests/remote-client/remote-client_test.cpp'
1042--- tests/remote-client/remote-client_test.cpp 2016-10-10 02:13:59 +0000
1043+++ tests/remote-client/remote-client_test.cpp 2016-10-10 05:27:34 +0000
1044@@ -56,9 +56,12 @@
1045
1046 class AccountTest : public RemoteClientTest {};
1047 class CopyTest : public RemoteClientTest {};
1048+class CreateFolderTest : public RemoteClientTest {};
1049 class DeleteTest : public RemoteClientTest {};
1050 class GetTest : public RemoteClientTest {};
1051 class ItemTest : public RemoteClientTest {};
1052+class ListTest : public RemoteClientTest {};
1053+class LookupTest : public RemoteClientTest {};
1054 class MoveTest : public RemoteClientTest {};
1055 class ParentsTest : public RemoteClientTest {};
1056 class RootsTest : public RemoteClientTest {};
1057@@ -68,16 +71,16 @@
1058 {
1059 Runtime runtime;
1060 EXPECT_TRUE(runtime.isValid());
1061- EXPECT_EQ(StorageError::NoError, runtime.error().type());
1062+ EXPECT_EQ(StorageError::Type::NoError, runtime.error().type());
1063
1064- EXPECT_EQ(StorageError::NoError, runtime.shutdown().type());
1065+ EXPECT_EQ(StorageError::Type::NoError, runtime.shutdown().type());
1066 EXPECT_FALSE(runtime.isValid());
1067- EXPECT_EQ(StorageError::NoError, runtime.error().type());
1068+ EXPECT_EQ(StorageError::Type::NoError, runtime.error().type());
1069
1070 // Check that a second shutdown sets the error.
1071- EXPECT_EQ(StorageError::RuntimeDestroyed, runtime.shutdown().type());
1072+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, runtime.shutdown().type());
1073 EXPECT_FALSE(runtime.isValid());
1074- EXPECT_EQ(StorageError::RuntimeDestroyed, runtime.error().type());
1075+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, runtime.error().type());
1076 EXPECT_EQ("Runtime::shutdown(): Runtime was destroyed previously", runtime.error().message());
1077 }
1078
1079@@ -94,7 +97,7 @@
1080 EXPECT_FALSE(rt.isValid());
1081 EXPECT_FALSE(rt.connection().isConnected());
1082 auto e = rt.error();
1083- EXPECT_EQ(StorageError::LocalCommsError, e.type());
1084+ EXPECT_EQ(StorageError::Type::LocalCommsError, e.type());
1085 EXPECT_EQ("Runtime(): DBus connection is not connected", e.message());
1086 }
1087 #endif
1088@@ -324,19 +327,19 @@
1089 {
1090 unique_ptr<AccountsJob> j(runtime_->accounts());
1091 EXPECT_TRUE(j->isValid());
1092- EXPECT_EQ(AccountsJob::Loading, j->status());
1093- EXPECT_EQ(StorageError::NoError, j->error().type());
1094+ EXPECT_EQ(AccountsJob::Status::Loading, j->status());
1095+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1096 EXPECT_EQ(QList<Account>(), j->accounts()); // We haven't waited for the result yet.
1097
1098 QSignalSpy spy(j.get(), &AccountsJob::statusChanged);
1099 spy.wait(SIGNAL_WAIT_TIME);
1100 ASSERT_EQ(1, spy.count());
1101 auto arg = spy.takeFirst();
1102- EXPECT_EQ(AccountsJob::Finished, qvariant_cast<AccountsJob::Status>(arg.at(0)));
1103+ EXPECT_EQ(AccountsJob::Status::Finished, qvariant_cast<AccountsJob::Status>(arg.at(0)));
1104
1105 EXPECT_TRUE(j->isValid());
1106- EXPECT_EQ(AccountsJob::Finished, j->status());
1107- EXPECT_EQ(StorageError::NoError, j->error().type());
1108+ EXPECT_EQ(AccountsJob::Status::Finished, j->status());
1109+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1110
1111 auto accounts = j->accounts();
1112
1113@@ -347,12 +350,12 @@
1114
1115 TEST_F(AccountTest, runtime_destroyed)
1116 {
1117- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime.
1118+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime.
1119
1120 AccountsJob* j = runtime_->accounts();
1121 EXPECT_FALSE(j->isValid());
1122- EXPECT_EQ(AccountsJob::Error, j->status());
1123- EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type());
1124+ EXPECT_EQ(AccountsJob::Status::Error, j->status());
1125+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, j->error().type());
1126 EXPECT_EQ("Runtime::accounts(): Runtime was destroyed previously", j->error().message());
1127 EXPECT_EQ(QList<Account>(), j->accounts());
1128
1129@@ -361,7 +364,7 @@
1130 spy.wait(SIGNAL_WAIT_TIME);
1131 ASSERT_EQ(1, spy.count());
1132 auto arg = spy.takeFirst();
1133- EXPECT_EQ(AccountsJob::Error, qvariant_cast<AccountsJob::Status>(arg.at(0)));
1134+ EXPECT_EQ(AccountsJob::Status::Error, qvariant_cast<AccountsJob::Status>(arg.at(0)));
1135 }
1136
1137 TEST_F(RootsTest, roots)
1138@@ -370,8 +373,8 @@
1139
1140 unique_ptr<ItemListJob> j(acc_.roots());
1141 EXPECT_TRUE(j->isValid());
1142- EXPECT_EQ(ItemListJob::Loading, j->status());
1143- EXPECT_EQ(StorageError::NoError, j->error().type());
1144+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
1145+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1146
1147 // Check that we get the statusChanged and itemsReady signals.
1148 QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
1149@@ -386,17 +389,17 @@
1150
1151 ASSERT_EQ(1, status_spy.count());
1152 arg = status_spy.takeFirst();
1153- EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1154- EXPECT_EQ(StorageError::NoError, j->error().type());
1155+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1156+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1157
1158 EXPECT_TRUE(j->isValid());
1159- EXPECT_EQ(ItemListJob::Finished, j->status());
1160- EXPECT_EQ(StorageError::NoError, j->error().type());
1161+ EXPECT_EQ(ItemListJob::Status::Finished, j->status());
1162+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1163
1164 // Check contents of returned item.
1165 auto root = items[0];
1166 EXPECT_TRUE(root.isValid());
1167- EXPECT_EQ(Item::Root, root.type());
1168+ EXPECT_EQ(Item::Type::Root, root.type());
1169 EXPECT_EQ("root_id", root.itemId());
1170 EXPECT_EQ("Root", root.name());
1171 EXPECT_EQ("etag", root.etag());
1172@@ -407,12 +410,12 @@
1173
1174 TEST_F(RootsTest, runtime_destroyed)
1175 {
1176- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime.
1177+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime.
1178
1179 unique_ptr<ItemListJob> j(acc_.roots());
1180 EXPECT_FALSE(j->isValid());
1181- EXPECT_EQ(ItemListJob::Error, j->status());
1182- EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type());
1183+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
1184+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, j->error().type());
1185 EXPECT_EQ("Account::roots(): Runtime was destroyed previously", j->error().message());
1186
1187 // Signal must be received.
1188@@ -420,7 +423,7 @@
1189 spy.wait(SIGNAL_WAIT_TIME);
1190 ASSERT_EQ(1, spy.count());
1191 auto arg = spy.takeFirst();
1192- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1193+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1194 }
1195
1196 TEST_F(RootsTest, runtime_destroyed_while_item_list_job_running)
1197@@ -429,17 +432,17 @@
1198
1199 unique_ptr<ItemListJob> j(acc_.roots());
1200 EXPECT_TRUE(j->isValid());
1201- EXPECT_EQ(ItemListJob::Loading, j->status());
1202- EXPECT_EQ(StorageError::NoError, j->error().type());
1203+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
1204+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1205
1206- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
1207+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
1208
1209 // Signal must be received.
1210 QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
1211 spy.wait(SIGNAL_WAIT_TIME);
1212 ASSERT_EQ(1, spy.count());
1213 auto arg = spy.takeFirst();
1214- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1215+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1216
1217 EXPECT_EQ("Account::roots(): Runtime was destroyed previously", j->error().message());
1218 }
1219@@ -449,8 +452,8 @@
1220 Account a;
1221 unique_ptr<ItemListJob> j(a.roots());
1222 EXPECT_FALSE(j->isValid());
1223- EXPECT_EQ(ItemListJob::Error, j->status());
1224- EXPECT_EQ(StorageError::LogicError, j->error().type());
1225+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
1226+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1227 EXPECT_EQ("Account::roots(): cannot create job from invalid account", j->error().message());
1228
1229 // Signal must be received.
1230@@ -458,7 +461,7 @@
1231 spy.wait(SIGNAL_WAIT_TIME);
1232 ASSERT_EQ(1, spy.count());
1233 auto arg = spy.takeFirst();
1234- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1235+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1236
1237 EXPECT_EQ("Account::roots(): cannot create job from invalid account", j->error().message());
1238 }
1239@@ -469,18 +472,18 @@
1240
1241 unique_ptr<ItemListJob> j(acc_.roots());
1242 EXPECT_TRUE(j->isValid());
1243- EXPECT_EQ(ItemListJob::Loading, j->status());
1244- EXPECT_EQ(StorageError::NoError, j->error().type());
1245+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
1246+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1247 EXPECT_EQ("No error", j->error().message());
1248
1249 QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
1250 spy.wait(SIGNAL_WAIT_TIME);
1251 ASSERT_EQ(1, spy.count());
1252 auto arg = spy.takeFirst();
1253- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1254+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1255
1256- EXPECT_EQ(ItemListJob::Error, j->status());
1257- EXPECT_EQ(StorageError::PermissionDenied, j->error().type());
1258+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
1259+ EXPECT_EQ(StorageError::Type::PermissionDenied, j->error().type());
1260 EXPECT_EQ("PermissionDenied: roots(): I'm sorry Dave, I'm afraid I can't do that.", j->error().errorString());
1261 }
1262
1263@@ -496,7 +499,7 @@
1264 auto arg = status_spy.takeFirst();
1265
1266 // Bad metadata is ignored, so status is finished, and itemsReady was never called.
1267- EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1268+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1269 EXPECT_EQ(0, status_spy.count());
1270 }
1271
1272@@ -513,7 +516,7 @@
1273
1274 EXPECT_EQ("root_id", j->item().itemId());
1275 EXPECT_EQ("Root", j->item().name());
1276- EXPECT_EQ(Item::Root, j->item().type());
1277+ EXPECT_EQ(Item::Type::Root, j->item().type());
1278 }
1279
1280 // Get a file.
1281@@ -525,7 +528,7 @@
1282
1283 EXPECT_EQ("child_id", j->item().itemId());
1284 EXPECT_EQ("Child", j->item().name());
1285- EXPECT_EQ(Item::File, j->item().type());
1286+ EXPECT_EQ(Item::Type::File, j->item().type());
1287 }
1288
1289 // Get a folder.
1290@@ -537,25 +540,25 @@
1291
1292 EXPECT_EQ("child_folder_id", j->item().itemId());
1293 EXPECT_EQ("Child_Folder", j->item().name());
1294- EXPECT_EQ(Item::Folder, j->item().type());
1295+ EXPECT_EQ(Item::Type::Folder, j->item().type());
1296 }
1297 }
1298
1299 TEST_F(GetTest, runtime_destroyed)
1300 {
1301- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime.
1302+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime.
1303
1304 unique_ptr<ItemJob> j(acc_.get("root_id"));
1305 EXPECT_FALSE(j->isValid());
1306- EXPECT_EQ(ItemJob::Error, j->status());
1307- EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type());
1308+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1309+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, j->error().type());
1310 EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message());
1311
1312 // Signal must be received.
1313 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1314 spy.wait(SIGNAL_WAIT_TIME);
1315 auto arg = spy.takeFirst();
1316- EXPECT_EQ(ItemJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1317+ EXPECT_EQ(ItemJob::Status::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1318
1319 EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message());
1320 }
1321@@ -567,12 +570,12 @@
1322 unique_ptr<ItemJob> j(acc_.get("child_folder_id"));
1323 EXPECT_TRUE(j->isValid());
1324
1325- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
1326+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
1327
1328 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1329 spy.wait(SIGNAL_WAIT_TIME);
1330 auto arg = spy.takeFirst();
1331- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1332+ EXPECT_EQ(ItemJob::Status::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1333
1334 EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message());
1335 }
1336@@ -582,8 +585,8 @@
1337 Account a;
1338 unique_ptr<ItemJob> j(a.get("child_Id"));
1339 EXPECT_FALSE(j->isValid());
1340- EXPECT_EQ(ItemJob::Error, j->status());
1341- EXPECT_EQ(StorageError::LogicError, j->error().type());
1342+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1343+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1344 EXPECT_EQ("Account::get(): cannot create job from invalid account", j->error().message());
1345
1346 // Signal must be received.
1347@@ -591,7 +594,7 @@
1348 spy.wait(SIGNAL_WAIT_TIME);
1349 ASSERT_EQ(1, spy.count());
1350 auto arg = spy.takeFirst();
1351- EXPECT_EQ(ItemJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1352+ EXPECT_EQ(ItemJob::Status::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1353
1354 EXPECT_EQ("Account::get(): cannot create job from invalid account", j->error().message());
1355 }
1356@@ -606,7 +609,7 @@
1357 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1358 spy.wait(SIGNAL_WAIT_TIME);
1359 auto arg = spy.takeFirst();
1360- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1361+ EXPECT_EQ(ItemJob::Status::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1362
1363 EXPECT_EQ("Account::get(): received invalid metadata from provider: item_id cannot be empty", j->error().message());
1364 }
1365@@ -621,9 +624,10 @@
1366 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1367 spy.wait(SIGNAL_WAIT_TIME);
1368 auto arg = spy.takeFirst();
1369- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1370+ EXPECT_EQ(ItemJob::Status::Error, qvariant_cast<ItemJob::Status>(arg.at(0)));
1371
1372- EXPECT_EQ("metadata(): no such item: no_such_id", j->error().message()) << j->error().message().toStdString();
1373+ // TODO: This is missing the method name
1374+ EXPECT_EQ("NotExists: metadata(): no such item: no_such_id", j->error().errorString());
1375 EXPECT_EQ("no_such_id", j->error().itemId());
1376 }
1377
1378@@ -641,18 +645,18 @@
1379
1380 unique_ptr<VoidJob> j(item.deleteItem());
1381 EXPECT_TRUE(j->isValid());
1382- EXPECT_EQ(VoidJob::Loading, j->status());
1383- EXPECT_EQ(StorageError::NoError, j->error().type());
1384+ EXPECT_EQ(VoidJob::Status::Loading, j->status());
1385+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1386
1387 EXPECT_EQ("child_id", item.itemId());
1388
1389 QSignalSpy spy(j.get(), &VoidJob::statusChanged);
1390 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
1391
1392- EXPECT_EQ(VoidJob::Finished, j->status());
1393+ EXPECT_EQ(VoidJob::Status::Finished, j->status());
1394 EXPECT_TRUE(j->isValid());
1395- EXPECT_EQ(StorageError::NoError, j->error().type());
1396- EXPECT_EQ(VoidJob::Finished, j->status());
1397+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1398+ EXPECT_EQ(VoidJob::Status::Finished, j->status());
1399 }
1400
1401 TEST_F(DeleteTest, no_such_item)
1402@@ -669,17 +673,17 @@
1403
1404 unique_ptr<VoidJob> j(item.deleteItem());
1405 EXPECT_TRUE(j->isValid());
1406- EXPECT_EQ(VoidJob::Loading, j->status());
1407- EXPECT_EQ(StorageError::NoError, j->error().type());
1408+ EXPECT_EQ(VoidJob::Status::Loading, j->status());
1409+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1410
1411 EXPECT_EQ("child_id", item.itemId());
1412
1413 QSignalSpy spy(j.get(), &VoidJob::statusChanged);
1414 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
1415
1416- EXPECT_EQ(VoidJob::Error, j->status());
1417+ EXPECT_EQ(VoidJob::Status::Error, j->status());
1418 EXPECT_FALSE(j->isValid());
1419- EXPECT_EQ(StorageError::NotExists, j->error().type());
1420+ EXPECT_EQ(StorageError::Type::NotExists, j->error().type());
1421 EXPECT_EQ("delete_item(): no such item: child_id", j->error().message());
1422 }
1423
1424@@ -697,14 +701,14 @@
1425
1426 unique_ptr<VoidJob> j(item.deleteItem());
1427 EXPECT_FALSE(j->isValid());
1428- EXPECT_EQ(VoidJob::Error, j->status());
1429- EXPECT_EQ(StorageError::LogicError, j->error().type());
1430+ EXPECT_EQ(VoidJob::Status::Error, j->status());
1431+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1432
1433 // Signal must be received.
1434 QSignalSpy spy(j.get(), &VoidJob::statusChanged);
1435 spy.wait(SIGNAL_WAIT_TIME);
1436 auto arg = spy.takeFirst();
1437- EXPECT_EQ(ItemJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1438+ EXPECT_EQ(VoidJob::Status::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1439
1440 EXPECT_EQ("Item::deleteItem(): cannot delete root", j->error().message());
1441 }
1442@@ -721,19 +725,19 @@
1443 item = j->item();
1444 }
1445
1446- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime.
1447+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime.
1448
1449 unique_ptr<VoidJob> j(item.deleteItem());
1450 EXPECT_FALSE(j->isValid());
1451- EXPECT_EQ(ItemJob::Error, j->status());
1452- EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type());
1453+ EXPECT_EQ(VoidJob::Status::Error, j->status());
1454+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, j->error().type());
1455 EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message());
1456
1457 // Signal must be received.
1458 QSignalSpy spy(j.get(), &VoidJob::statusChanged);
1459 spy.wait(SIGNAL_WAIT_TIME);
1460 auto arg = spy.takeFirst();
1461- EXPECT_EQ(ItemJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1462+ EXPECT_EQ(VoidJob::Status::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1463
1464 EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message());
1465 }
1466@@ -752,16 +756,16 @@
1467
1468 unique_ptr<VoidJob> j(item.deleteItem());
1469 EXPECT_TRUE(j->isValid());
1470- EXPECT_EQ(VoidJob::Loading, j->status());
1471- EXPECT_EQ(StorageError::NoError, j->error().type());
1472+ EXPECT_EQ(VoidJob::Status::Loading, j->status());
1473+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1474
1475- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime.
1476+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime.
1477
1478 // Signal must be received.
1479 QSignalSpy spy(j.get(), &VoidJob::statusChanged);
1480 spy.wait(SIGNAL_WAIT_TIME);
1481 auto arg = spy.takeFirst();
1482- EXPECT_EQ(VoidJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1483+ EXPECT_EQ(VoidJob::Status::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1484
1485 EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message()) << j->error().message().toStdString();
1486 }
1487@@ -771,8 +775,8 @@
1488 Item i;
1489 unique_ptr<VoidJob> j(i.deleteItem());
1490 EXPECT_FALSE(j->isValid());
1491- EXPECT_EQ(VoidJob::Error, j->status());
1492- EXPECT_EQ(StorageError::LogicError, j->error().type());
1493+ EXPECT_EQ(VoidJob::Status::Error, j->status());
1494+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1495 EXPECT_EQ("Item::deleteItem(): cannot create job from invalid item", j->error().message());
1496
1497 // Signal must be received.
1498@@ -780,7 +784,7 @@
1499 spy.wait(SIGNAL_WAIT_TIME);
1500 ASSERT_EQ(1, spy.count());
1501 auto arg = spy.takeFirst();
1502- EXPECT_EQ(VoidJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1503+ EXPECT_EQ(VoidJob::Status::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
1504
1505 EXPECT_EQ("Item::deleteItem(): cannot create job from invalid item", j->error().message());
1506 }
1507@@ -808,7 +812,7 @@
1508 EXPECT_EQ("", i.itemId());
1509 EXPECT_EQ("", i.name());
1510 EXPECT_EQ("", i.etag());
1511- EXPECT_EQ(Item::File, i.type());
1512+ EXPECT_EQ(Item::Type::File, i.type());
1513 auto mtime = i.lastModifiedTime();
1514 EXPECT_FALSE(mtime.isValid());
1515 auto pids = i.parentIds();
1516@@ -828,7 +832,7 @@
1517 EXPECT_EQ("Child", i.name());
1518 EXPECT_TRUE(i.account().isValid());
1519 EXPECT_EQ("etag", i.etag());
1520- EXPECT_EQ(Item::File, i.type());
1521+ EXPECT_EQ(Item::Type::File, i.type());
1522
1523 // Copy constructor
1524 Item i2(i);
1525@@ -877,7 +881,7 @@
1526 EXPECT_EQ("Root", i2.name());
1527 EXPECT_TRUE(i2.account().isValid());
1528 EXPECT_EQ("etag", i2.etag());
1529- EXPECT_EQ(Item::Root, i2.type());
1530+ EXPECT_EQ(Item::Type::Root, i2.type());
1531
1532 // Move assignment
1533 unique_ptr<ItemJob> j3(acc_.get("child_folder_id"));
1534@@ -893,7 +897,7 @@
1535 EXPECT_EQ("Child_Folder", i1.name());
1536 EXPECT_EQ(i1.account(), i1.account());
1537 EXPECT_EQ("etag", i1.etag());
1538- EXPECT_EQ(Item::Folder, i1.type());
1539+ EXPECT_EQ(Item::Type::Folder, i1.type());
1540
1541 // Moved-from object must be invalid
1542 EXPECT_FALSE(i3.isValid());
1543@@ -1055,15 +1059,15 @@
1544 // no parents immediately.
1545 unique_ptr<ItemListJob> j(root.parents());
1546 EXPECT_TRUE(j->isValid());
1547- EXPECT_EQ(ItemListJob::Finished, j->status());
1548- EXPECT_EQ(StorageError::NoError, j->error().type());
1549+ EXPECT_EQ(ItemListJob::Status::Finished, j->status());
1550+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1551
1552 // Signal must be received.
1553 QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
1554 spy.wait(SIGNAL_WAIT_TIME);
1555 ASSERT_EQ(1, spy.count());
1556 auto arg = spy.takeFirst();
1557- EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1558+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1559 }
1560
1561 Item child;
1562@@ -1078,8 +1082,8 @@
1563 {
1564 unique_ptr<ItemListJob> j(child.parents());
1565 EXPECT_TRUE(j->isValid());
1566- EXPECT_EQ(ItemListJob::Loading, j->status());
1567- EXPECT_EQ(StorageError::NoError, j->error().type());
1568+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
1569+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1570
1571 QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
1572 QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
1573@@ -1089,7 +1093,7 @@
1574 parents = qvariant_cast<QList<Item>>(list_arg.at(0));
1575
1576 // When the signal for the final item arrives, status must be Finished.
1577- EXPECT_EQ(ItemListJob::Finished, j->status());
1578+ EXPECT_EQ(ItemListJob::Status::Finished, j->status());
1579
1580 // Finished signal must be received.
1581 if (status_spy.count() == 0)
1582@@ -1098,7 +1102,7 @@
1583 }
1584 ASSERT_EQ(1, status_spy.count());
1585 auto status_arg = status_spy.takeFirst();
1586- EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
1587+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
1588
1589 // Child must have one parent, namely the root.
1590 ASSERT_EQ(1, parents.size());
1591@@ -1152,7 +1156,7 @@
1592 }
1593 ASSERT_EQ(1, status_spy.count());
1594 auto status_arg = status_spy.takeFirst();
1595- EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
1596+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
1597
1598 // Child must have two parents.
1599 ASSERT_EQ(2, parents.size());
1600@@ -1191,8 +1195,8 @@
1601 status_spy.wait(SIGNAL_WAIT_TIME);
1602 ASSERT_EQ(1, status_spy.count());
1603 auto status_arg = status_spy.takeFirst();
1604- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
1605- EXPECT_EQ(StorageError::ResourceError, j->error().type());
1606+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
1607+ EXPECT_EQ(StorageError::Type::ResourceError, j->error().type());
1608 EXPECT_EQ("ResourceError: metadata(): weird error", j->error().errorString());
1609 EXPECT_EQ(42, j->error().errorCode());
1610
1611@@ -1210,8 +1214,8 @@
1612 Item invalid;
1613 unique_ptr<ItemListJob> j(invalid.parents());
1614 EXPECT_FALSE(j->isValid());
1615- EXPECT_EQ(ItemListJob::Error, j->status());
1616- EXPECT_EQ(StorageError::LogicError, j->error().type());
1617+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
1618+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1619 EXPECT_EQ("Item::parents(): cannot create job from invalid item", j->error().message());
1620
1621 // Signal must be received.
1622@@ -1219,7 +1223,7 @@
1623 spy.wait(SIGNAL_WAIT_TIME);
1624 ASSERT_EQ(1, spy.count());
1625 auto arg = spy.takeFirst();
1626- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1627+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1628 }
1629
1630 TEST_F(ParentsTest, runtime_destroyed)
1631@@ -1234,19 +1238,19 @@
1632 root = j->item();
1633 }
1634
1635- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime.
1636+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime.
1637
1638 unique_ptr<ItemListJob> j(root.parents());
1639 EXPECT_FALSE(j->isValid());
1640- EXPECT_EQ(ItemJob::Error, j->status());
1641- EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type());
1642+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
1643+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, j->error().type());
1644 EXPECT_EQ("Item::parents(): Runtime was destroyed previously", j->error().message());
1645
1646 // Signal must be received.
1647 QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
1648 spy.wait(SIGNAL_WAIT_TIME);
1649 auto arg = spy.takeFirst();
1650- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1651+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1652
1653 EXPECT_EQ("Item::parents(): Runtime was destroyed previously", j->error().message());
1654 }
1655@@ -1273,14 +1277,14 @@
1656
1657 unique_ptr<ItemListJob> j(child.parents());
1658
1659- EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
1660+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
1661
1662 // Signal must be received.
1663 QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
1664 spy.wait(SIGNAL_WAIT_TIME);
1665 ASSERT_EQ(1, spy.count());
1666 auto arg = spy.takeFirst();
1667- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1668+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1669
1670 EXPECT_EQ("Item::parents(): Runtime was destroyed previously", j->error().message());
1671 }
1672@@ -1308,14 +1312,14 @@
1673 {
1674 unique_ptr<ItemListJob> j(child.parents());
1675 EXPECT_TRUE(j->isValid());
1676- EXPECT_EQ(ItemListJob::Loading, j->status());
1677- EXPECT_EQ(StorageError::NoError, j->error().type());
1678+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
1679+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1680
1681 QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
1682 spy.wait(SIGNAL_WAIT_TIME);
1683 ASSERT_EQ(1, spy.count());
1684 auto arg = spy.takeFirst();
1685- EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1686+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
1687
1688 EXPECT_EQ("Item::parents(): provider returned a file as a parent", j->error().message());
1689 }
1690@@ -1343,19 +1347,19 @@
1691
1692 unique_ptr<ItemJob> j(child.copy(root, "copied_item"));
1693 EXPECT_TRUE(j->isValid());
1694- EXPECT_EQ(ItemJob::Loading, j->status());
1695- EXPECT_EQ(StorageError::NoError, j->error().type());
1696+ EXPECT_EQ(ItemJob::Status::Loading, j->status());
1697+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1698
1699 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1700 spy.wait(SIGNAL_WAIT_TIME);
1701 ASSERT_EQ(1, spy.count());
1702 auto arg = spy.takeFirst();
1703 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1704- EXPECT_EQ(ItemJob::Finished, status);
1705+ EXPECT_EQ(ItemJob::Status::Finished, status);
1706
1707 EXPECT_TRUE(j->isValid());
1708- EXPECT_EQ(ItemJob::Finished, j->status());
1709- EXPECT_EQ(StorageError::NoError, j->error().type());
1710+ EXPECT_EQ(ItemJob::Status::Finished, j->status());
1711+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1712 auto copied_file = j->item();
1713 EXPECT_EQ("new_item_id", copied_file.itemId());
1714 EXPECT_EQ(root.itemId(), copied_file.parentIds()[0]);
1715@@ -1377,8 +1381,8 @@
1716 Item child;
1717 unique_ptr<ItemJob> j(child.copy(root, "copied_item"));
1718 EXPECT_FALSE(j->isValid());
1719- EXPECT_EQ(ItemJob::Error, j->status());
1720- EXPECT_EQ(StorageError::LogicError, j->error().type());
1721+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1722+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1723 EXPECT_EQ("LogicError", j->error().name());
1724 EXPECT_EQ("LogicError: Item::copy(): cannot create job from invalid item", j->error().errorString());
1725
1726@@ -1387,11 +1391,11 @@
1727 ASSERT_EQ(1, spy.count());
1728 auto arg = spy.takeFirst();
1729 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1730- EXPECT_EQ(ItemJob::Error, status);
1731+ EXPECT_EQ(ItemJob::Status::Error, status);
1732
1733 EXPECT_FALSE(j->isValid());
1734- EXPECT_EQ(ItemJob::Error, j->status());
1735- EXPECT_EQ(StorageError::LogicError, j->error().type());
1736+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1737+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1738 EXPECT_EQ("LogicError", j->error().name());
1739 EXPECT_EQ("LogicError: Item::copy(): cannot create job from invalid item", j->error().errorString());
1740 }
1741@@ -1419,8 +1423,8 @@
1742 Item invalid_parent;
1743 unique_ptr<ItemJob> j(child.copy(invalid_parent, "copied_item"));
1744 EXPECT_FALSE(j->isValid());
1745- EXPECT_EQ(ItemJob::Error, j->status());
1746- EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
1747+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1748+ EXPECT_EQ(StorageError::Type::InvalidArgument, j->error().type());
1749 EXPECT_EQ("InvalidArgument: Item::copy(): newParent is invalid", j->error().errorString());
1750
1751 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1752@@ -1428,11 +1432,11 @@
1753 ASSERT_EQ(1, spy.count());
1754 auto arg = spy.takeFirst();
1755 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1756- EXPECT_EQ(ItemJob::Error, status);
1757+ EXPECT_EQ(ItemJob::Status::Error, status);
1758
1759 EXPECT_FALSE(j->isValid());
1760- EXPECT_EQ(ItemJob::Error, j->status());
1761- EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
1762+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1763+ EXPECT_EQ(StorageError::Type::InvalidArgument, j->error().type());
1764 EXPECT_EQ("InvalidArgument: Item::copy(): newParent is invalid", j->error().errorString());
1765 }
1766
1767@@ -1458,8 +1462,8 @@
1768
1769 unique_ptr<ItemJob> j(child.copy(root, ""));
1770 EXPECT_FALSE(j->isValid());
1771- EXPECT_EQ(ItemJob::Error, j->status());
1772- EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
1773+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1774+ EXPECT_EQ(StorageError::Type::InvalidArgument, j->error().type());
1775 EXPECT_EQ("InvalidArgument: Item::copy(): newName cannot be empty", j->error().errorString());
1776
1777 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1778@@ -1467,11 +1471,11 @@
1779 ASSERT_EQ(1, spy.count());
1780 auto arg = spy.takeFirst();
1781 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1782- EXPECT_EQ(ItemJob::Error, status);
1783+ EXPECT_EQ(ItemJob::Status::Error, status);
1784
1785 EXPECT_FALSE(j->isValid());
1786- EXPECT_EQ(ItemJob::Error, j->status());
1787- EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
1788+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1789+ EXPECT_EQ(StorageError::Type::InvalidArgument, j->error().type());
1790 EXPECT_EQ("InvalidArgument: Item::copy(): newName cannot be empty", j->error().errorString());
1791 }
1792
1793@@ -1510,8 +1514,8 @@
1794
1795 unique_ptr<ItemJob> j(child.copy(root1, "copied_Item"));
1796 EXPECT_FALSE(j->isValid());
1797- EXPECT_EQ(ItemJob::Error, j->status());
1798- EXPECT_EQ(StorageError::LogicError, j->error().type());
1799+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1800+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1801 EXPECT_EQ("LogicError: Item::copy(): source and target must belong to the same account", j->error().errorString());
1802
1803 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1804@@ -1519,11 +1523,11 @@
1805 ASSERT_EQ(1, spy.count());
1806 auto arg = spy.takeFirst();
1807 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1808- EXPECT_EQ(ItemJob::Error, status);
1809+ EXPECT_EQ(ItemJob::Status::Error, status);
1810
1811 EXPECT_FALSE(j->isValid());
1812- EXPECT_EQ(ItemJob::Error, j->status());
1813- EXPECT_EQ(StorageError::LogicError, j->error().type());
1814+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1815+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1816 EXPECT_EQ("LogicError: Item::copy(): source and target must belong to the same account", j->error().errorString());
1817 }
1818
1819@@ -1549,8 +1553,8 @@
1820
1821 unique_ptr<ItemJob> j(child.copy(child, "copied_Item"));
1822 EXPECT_FALSE(j->isValid());
1823- EXPECT_EQ(ItemJob::Error, j->status());
1824- EXPECT_EQ(StorageError::LogicError, j->error().type());
1825+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1826+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1827 EXPECT_EQ("LogicError: Item::copy(): newParent cannot be a file", j->error().errorString()) << j->error().errorString().toStdString();
1828
1829 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1830@@ -1558,11 +1562,11 @@
1831 ASSERT_EQ(1, spy.count());
1832 auto arg = spy.takeFirst();
1833 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1834- EXPECT_EQ(ItemJob::Error, status);
1835+ EXPECT_EQ(ItemJob::Status::Error, status);
1836
1837 EXPECT_FALSE(j->isValid());
1838- EXPECT_EQ(ItemJob::Error, j->status());
1839- EXPECT_EQ(StorageError::LogicError, j->error().type());
1840+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1841+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1842 EXPECT_EQ("LogicError: Item::copy(): newParent cannot be a file", j->error().errorString());
1843 }
1844
1845@@ -1594,11 +1598,11 @@
1846 ASSERT_EQ(1, spy.count());
1847 auto arg = spy.takeFirst();
1848 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1849- EXPECT_EQ(ItemJob::Error, status);
1850+ EXPECT_EQ(ItemJob::Status::Error, status);
1851
1852 EXPECT_FALSE(j->isValid());
1853- EXPECT_EQ(ItemJob::Error, j->status());
1854- EXPECT_EQ(StorageError::LocalCommsError, j->error().type());
1855+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1856+ EXPECT_EQ(StorageError::Type::LocalCommsError, j->error().type());
1857 EXPECT_EQ("LocalCommsError: Item::copy(): source and target item type differ", j->error().errorString());
1858 }
1859
1860@@ -1624,19 +1628,19 @@
1861
1862 unique_ptr<ItemJob> j(child.move(root, "moved_item"));
1863 EXPECT_TRUE(j->isValid());
1864- EXPECT_EQ(ItemJob::Loading, j->status());
1865- EXPECT_EQ(StorageError::NoError, j->error().type());
1866+ EXPECT_EQ(ItemJob::Status::Loading, j->status());
1867+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1868
1869 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1870 spy.wait(SIGNAL_WAIT_TIME);
1871 ASSERT_EQ(1, spy.count());
1872 auto arg = spy.takeFirst();
1873 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1874- EXPECT_EQ(ItemJob::Finished, status);
1875+ EXPECT_EQ(ItemJob::Status::Finished, status);
1876
1877 EXPECT_TRUE(j->isValid());
1878- EXPECT_EQ(ItemJob::Finished, j->status());
1879- EXPECT_EQ(StorageError::NoError, j->error().type());
1880+ EXPECT_EQ(ItemJob::Status::Finished, j->status());
1881+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
1882 auto moved_file = j->item();
1883 EXPECT_EQ("child_id", moved_file.itemId());
1884 EXPECT_EQ(root.itemId(), moved_file.parentIds()[0]);
1885@@ -1658,8 +1662,8 @@
1886 Item child;
1887 unique_ptr<ItemJob> j(child.move(root, "moved_item"));
1888 EXPECT_FALSE(j->isValid());
1889- EXPECT_EQ(ItemJob::Error, j->status());
1890- EXPECT_EQ(StorageError::LogicError, j->error().type());
1891+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1892+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1893 EXPECT_EQ("LogicError", j->error().name());
1894 EXPECT_EQ("LogicError: Item::move(): cannot create job from invalid item", j->error().errorString());
1895
1896@@ -1668,11 +1672,11 @@
1897 ASSERT_EQ(1, spy.count());
1898 auto arg = spy.takeFirst();
1899 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1900- EXPECT_EQ(ItemJob::Error, status);
1901+ EXPECT_EQ(ItemJob::Status::Error, status);
1902
1903 EXPECT_FALSE(j->isValid());
1904- EXPECT_EQ(ItemJob::Error, j->status());
1905- EXPECT_EQ(StorageError::LogicError, j->error().type());
1906+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1907+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
1908 EXPECT_EQ("LogicError", j->error().name());
1909 EXPECT_EQ("LogicError: Item::move(): cannot create job from invalid item", j->error().errorString());
1910 }
1911@@ -1705,13 +1709,13 @@
1912 ASSERT_EQ(1, spy.count());
1913 auto arg = spy.takeFirst();
1914 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1915- EXPECT_EQ(ItemJob::Error, status);
1916+ EXPECT_EQ(ItemJob::Status::Error, status);
1917
1918 EXPECT_FALSE(j->isValid());
1919- EXPECT_EQ(ItemJob::Error, j->status());
1920- EXPECT_EQ(StorageError::LocalCommsError, j->error().type());
1921+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1922+ EXPECT_EQ(StorageError::Type::LocalCommsError, j->error().type());
1923 EXPECT_EQ("LocalCommsError", j->error().name());
1924- EXPECT_EQ("LocalCommsError: Item::move(): impossible root item returned by server", j->error().errorString());
1925+ EXPECT_EQ("LocalCommsError: Item::move(): impossible root item returned by provider", j->error().errorString());
1926 }
1927
1928 TEST_F(MoveTest, type_mismatch)
1929@@ -1742,939 +1746,492 @@
1930 ASSERT_EQ(1, spy.count());
1931 auto arg = spy.takeFirst();
1932 auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
1933- EXPECT_EQ(ItemJob::Error, status);
1934+ EXPECT_EQ(ItemJob::Status::Error, status);
1935
1936 EXPECT_FALSE(j->isValid());
1937- EXPECT_EQ(ItemJob::Error, j->status());
1938- EXPECT_EQ(StorageError::LocalCommsError, j->error().type());
1939+ EXPECT_EQ(ItemJob::Status::Error, j->status());
1940+ EXPECT_EQ(StorageError::Type::LocalCommsError, j->error().type());
1941 EXPECT_EQ("LocalCommsError: Item::move(): source and target item type differ", j->error().errorString());
1942 }
1943
1944-#if 0
1945-TEST_F(RootTest, basic)
1946-{
1947- auto runtime = Runtime::create(connection());
1948-
1949- auto acc = get_account(runtime);
1950- auto root = get_root(runtime);
1951- EXPECT_EQ("root_id", root->native_identity());
1952- EXPECT_EQ(acc, root->account());
1953- EXPECT_EQ(ItemType::root, root->type());
1954- EXPECT_EQ("Root", root->name());
1955- EXPECT_NE("", root->etag());
1956-
1957- auto parents = call(root->parents());
1958- EXPECT_TRUE(parents.isEmpty());
1959- EXPECT_TRUE(root->parent_ids().isEmpty());
1960-
1961- // get(<root-ID>) must return the root.
1962- auto item = call(root->get(root->native_identity()));
1963- EXPECT_NE(nullptr, dynamic_pointer_cast<Root>(item));
1964- EXPECT_TRUE(root->equal_to(item));
1965-
1966- // Free and used space can be anything, but must be > 0.
1967- auto free_space = call(root->free_space_bytes());
1968- cerr << "bytes free: " << free_space << endl;
1969- EXPECT_GT(free_space, 0);
1970-
1971- auto used_space = call(root->used_space_bytes());
1972- cerr << "bytes used: " << used_space << endl;
1973- EXPECT_GT(used_space, 0);
1974-}
1975-
1976-TEST_F(FolderTest, basic)
1977-{
1978- auto runtime = Runtime::create(connection());
1979-
1980- auto root = get_root(runtime);
1981- clear_folder(root);
1982-
1983- auto items = call(root->list());
1984+TEST_F(LookupTest, basic)
1985+{
1986+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
1987+
1988+ Item root;
1989+ {
1990+ unique_ptr<ItemJob> j(acc_.get("root_id"));
1991+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
1992+ spy.wait(SIGNAL_WAIT_TIME);
1993+ root = j->item();
1994+ }
1995+
1996+ unique_ptr<ItemListJob> j(root.lookup("Child"));
1997+ EXPECT_TRUE(j->isValid());
1998+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
1999+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
2000+
2001+ QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
2002+ QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
2003+
2004+ status_spy.wait(SIGNAL_WAIT_TIME);
2005+
2006+ auto list_arg = ready_spy.takeFirst();
2007+ auto list = qvariant_cast<QList<Item>>(list_arg.at(0));
2008+ ASSERT_EQ(1, list.size());
2009+ auto child = list[0];
2010+ ASSERT_EQ("child_id", child.itemId());
2011+ ASSERT_EQ("Child", child.name());
2012+
2013+ auto arg = status_spy.takeFirst();
2014+ auto status = qvariant_cast<ItemListJob::Status>(arg.at(0));
2015+ EXPECT_EQ(ItemListJob::Status::Finished, status);
2016+
2017+ EXPECT_TRUE(j->isValid());
2018+ EXPECT_EQ(ItemListJob::Status::Finished, j->status());
2019+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
2020+}
2021+
2022+TEST_F(LookupTest, invalid)
2023+{
2024+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2025+
2026+ Item root;
2027+ unique_ptr<ItemListJob> j(root.lookup("Child"));
2028+ EXPECT_FALSE(j->isValid());
2029+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
2030+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
2031+ EXPECT_EQ("LogicError: Item::lookup(): cannot create job from invalid item", j->error().errorString());
2032+
2033+ // Signal must be received.
2034+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
2035+ spy.wait(SIGNAL_WAIT_TIME);
2036+ ASSERT_EQ(1, spy.count());
2037+ auto arg = spy.takeFirst();
2038+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
2039+
2040+ EXPECT_EQ("LogicError: Item::lookup(): cannot create job from invalid item", j->error().errorString());
2041+}
2042+
2043+TEST_F(LookupTest, wrong_type)
2044+{
2045+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2046+
2047+ Item root;
2048+ {
2049+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2050+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2051+ spy.wait(SIGNAL_WAIT_TIME);
2052+ root = j->item();
2053+ }
2054+
2055+ Item child;
2056+ {
2057+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2058+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2059+ spy.wait(SIGNAL_WAIT_TIME);
2060+ child = j->item();
2061+ }
2062+
2063+ unique_ptr<ItemListJob> j(child.lookup("Child"));
2064+ EXPECT_FALSE(j->isValid());
2065+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
2066+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
2067+ EXPECT_EQ("LogicError: Item::lookup(): cannot perform lookup on a file", j->error().errorString());
2068+
2069+ // Signal must be received.
2070+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
2071+ spy.wait(SIGNAL_WAIT_TIME);
2072+ ASSERT_EQ(1, spy.count());
2073+ auto arg = spy.takeFirst();
2074+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
2075+
2076+ EXPECT_EQ("LogicError: Item::lookup(): cannot perform lookup on a file", j->error().errorString());
2077+}
2078+
2079+TEST_F(CreateFolderTest, basic)
2080+{
2081+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2082+
2083+ Item root;
2084+ {
2085+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2086+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2087+ spy.wait(SIGNAL_WAIT_TIME);
2088+ root = j->item();
2089+ }
2090+
2091+ unique_ptr<ItemJob> j(root.createFolder("new_folder"));
2092+ EXPECT_TRUE(j->isValid());
2093+
2094+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2095+ spy.wait(SIGNAL_WAIT_TIME);
2096+ ASSERT_EQ(1, spy.count());
2097+ auto arg = spy.takeFirst();
2098+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
2099+ EXPECT_EQ(ItemJob::Status::Finished, status);
2100+
2101+ EXPECT_TRUE(j->isValid());
2102+ EXPECT_EQ(ItemJob::Status::Finished, j->status());
2103+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
2104+
2105+ auto new_folder = j->item();
2106+ EXPECT_EQ("new_folder", new_folder.name());
2107+ EXPECT_EQ(Item::Type::Folder, new_folder.type());
2108+}
2109+
2110+TEST_F(CreateFolderTest, invalid)
2111+{
2112+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2113+
2114+ Item root;
2115+ unique_ptr<ItemJob> j(root.createFolder("new_folder"));
2116+ EXPECT_FALSE(j->isValid());
2117+ EXPECT_EQ(ItemJob::Status::Error, j->status());
2118+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
2119+ EXPECT_EQ("LogicError: Item::createFolder(): cannot create job from invalid item", j->error().errorString());
2120+
2121+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2122+ spy.wait(SIGNAL_WAIT_TIME);
2123+ ASSERT_EQ(1, spy.count());
2124+ auto arg = spy.takeFirst();
2125+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
2126+ EXPECT_EQ(ItemJob::Status::Error, status);
2127+
2128+ EXPECT_EQ("LogicError: Item::createFolder(): cannot create job from invalid item", j->error().errorString());
2129+}
2130+
2131+TEST_F(CreateFolderTest, wrong_type)
2132+{
2133+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2134+
2135+ Item root;
2136+ {
2137+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2138+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2139+ spy.wait(SIGNAL_WAIT_TIME);
2140+ root = j->item();
2141+ }
2142+
2143+ Item child;
2144+ {
2145+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2146+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2147+ spy.wait(SIGNAL_WAIT_TIME);
2148+ child = j->item();
2149+ }
2150+
2151+ unique_ptr<ItemJob> j(child.createFolder("new_folder"));
2152+ EXPECT_FALSE(j->isValid());
2153+ EXPECT_EQ(ItemJob::Status::Error, j->status());
2154+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
2155+ EXPECT_EQ("LogicError: Item::createFolder(): cannot create a folder with a file as the parent",
2156+ j->error().errorString());
2157+
2158+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2159+ spy.wait(SIGNAL_WAIT_TIME);
2160+ ASSERT_EQ(1, spy.count());
2161+ auto arg = spy.takeFirst();
2162+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
2163+ EXPECT_EQ(ItemJob::Status::Error, status);
2164+
2165+ EXPECT_EQ("LogicError: Item::createFolder(): cannot create a folder with a file as the parent",
2166+ j->error().errorString());
2167+}
2168+
2169+TEST_F(CreateFolderTest, wrong_return_type)
2170+{
2171+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("create_folder_returns_file")));
2172+
2173+ Item root;
2174+ {
2175+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2176+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2177+ spy.wait(SIGNAL_WAIT_TIME);
2178+ root = j->item();
2179+ }
2180+
2181+ unique_ptr<ItemJob> j(root.createFolder("new_folder"));
2182+ EXPECT_TRUE(j->isValid());
2183+
2184+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2185+ spy.wait(SIGNAL_WAIT_TIME);
2186+ ASSERT_EQ(1, spy.count());
2187+ auto arg = spy.takeFirst();
2188+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
2189+ EXPECT_EQ(ItemJob::Status::Error, status);
2190+
2191+ EXPECT_EQ("LocalCommsError: Item::createFolder(): impossible file item returned by provider",
2192+ j->error().errorString());
2193+}
2194+
2195+TEST_F(ListTest, basic)
2196+{
2197+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2198+
2199+ Item root;
2200+ {
2201+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2202+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2203+ spy.wait(SIGNAL_WAIT_TIME);
2204+ root = j->item();
2205+ }
2206+
2207+ unique_ptr<ItemListJob> j(root.list());
2208+ EXPECT_TRUE(j->isValid());
2209+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
2210+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
2211+
2212+ QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
2213+ QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
2214+ ready_spy.wait(SIGNAL_WAIT_TIME);
2215+ ASSERT_EQ(1, ready_spy.count());
2216+ auto list_arg = ready_spy.takeFirst();
2217+ auto items = qvariant_cast<QList<Item>>(list_arg.at(0));
2218 ASSERT_EQ(1, items.size());
2219-
2220- // Create a file and check that it was created with correct type, name, and size 0.
2221- auto uploader = call(root->create_file("file1", 10));
2222- EXPECT_EQ(10, uploader->size());
2223- auto file = call(uploader->finish_upload());
2224- EXPECT_EQ(ItemType::file, file->type());
2225- EXPECT_EQ("some_upload", file->name());
2226- EXPECT_EQ(10, file->size());
2227- EXPECT_EQ("some_id", file->native_identity());
2228-
2229- // For coverage: getting a file must return the correct one.
2230- file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2231- EXPECT_EQ("child_id", file->native_identity());
2232- EXPECT_EQ("Child", file->name());
2233-}
2234-
2235-TEST_F(FileTest, upload)
2236-{
2237- auto runtime = Runtime::create(connection());
2238-
2239- auto root = get_root(runtime);
2240- clear_folder(root);
2241-
2242- // Get a file.
2243- auto children = call(root->lookup("Child"));
2244- ASSERT_EQ(1, children.size());
2245- auto file = dynamic_pointer_cast<File>(children[0]);
2246- EXPECT_EQ("child_id", file->native_identity());
2247- EXPECT_EQ("Child", file->name());
2248-
2249- auto uploader = call(file->create_uploader(ConflictPolicy::error_if_conflict, 0));
2250- EXPECT_EQ(0, uploader->size());
2251-
2252- auto uploaded_file = call(uploader->finish_upload());
2253- EXPECT_EQ("some_id", uploaded_file->native_identity());
2254- EXPECT_EQ("some_upload", uploaded_file->name());
2255-}
2256-
2257-TEST_F(RootTest, root_exceptions)
2258-{
2259- auto runtime = Runtime::create(connection());
2260-
2261- auto root = get_root(runtime);
2262- clear_folder(root);
2263-
2264- try
2265- {
2266- call(root->delete_item());
2267- FAIL();
2268- }
2269- catch (LogicException const& e)
2270- {
2271- EXPECT_EQ("Item::delete_item(): cannot delete root folder", e.error_message()) << e.what();
2272- }
2273-
2274- {
2275- try
2276- {
2277- call(root->get("no_such_file_id"));
2278- FAIL();
2279- }
2280- catch (NotExistsException const& e)
2281- {
2282- EXPECT_EQ("no_such_file_id", e.key());
2283- }
2284- }
2285-}
2286-
2287-TEST_F(RuntimeTest, runtime_destroyed_exceptions)
2288-{
2289- // Getting the runtime from an account after shutting down the runtime must fail.
2290- {
2291- auto runtime = Runtime::create(connection());
2292- auto acc = get_account(runtime);
2293- runtime->shutdown();
2294- try
2295- {
2296- acc->runtime();
2297- FAIL();
2298- }
2299- catch (RuntimeDestroyedException const& e)
2300- {
2301- EXPECT_EQ("Account::runtime(): runtime was destroyed previously", e.error_message());
2302- }
2303- }
2304-
2305- // Getting the runtime from an account after destroying the runtime must fail.
2306- {
2307- auto runtime = Runtime::create(connection());
2308- auto acc = get_account(runtime);
2309- runtime.reset();
2310- try
2311- {
2312- acc->runtime();
2313- FAIL();
2314- }
2315- catch (RuntimeDestroyedException const& e)
2316- {
2317- EXPECT_EQ("Account::runtime(): runtime was destroyed previously", e.error_message());
2318- }
2319- }
2320-
2321- // Getting accounts after shutting down the runtime must fail.
2322- {
2323- auto runtime = Runtime::create(connection());
2324- runtime->shutdown();
2325- try
2326- {
2327- call(runtime->accounts());
2328- FAIL();
2329- }
2330- catch (RuntimeDestroyedException const& e)
2331- {
2332- EXPECT_EQ("Runtime::accounts(): runtime was destroyed previously", e.error_message());
2333- }
2334- }
2335-
2336- // Getting roots from an account after shutting down the runtime must fail.
2337- {
2338- auto runtime = Runtime::create(connection());
2339- auto acc = get_account(runtime);
2340- runtime->shutdown();
2341- try
2342- {
2343- call(acc->roots());
2344- FAIL();
2345- }
2346- catch (RuntimeDestroyedException const& e)
2347- {
2348- EXPECT_EQ("Account::roots(): runtime was destroyed previously", e.error_message());
2349- }
2350- }
2351-
2352- // Getting the account from a root with a destroyed runtime must fail.
2353- {
2354- auto runtime = Runtime::create(connection());
2355- auto root = get_root(runtime);
2356- runtime.reset();
2357- try
2358- {
2359- root->account();
2360- FAIL();
2361- }
2362- catch (RuntimeDestroyedException const& e)
2363- {
2364- EXPECT_EQ("Root::account(): runtime was destroyed previously", e.error_message());
2365- }
2366- }
2367-
2368- // Getting the account from a root with a destroyed account must fail.
2369- {
2370- auto runtime = Runtime::create(connection());
2371- auto acc = get_account(runtime);
2372- auto root = get_root(runtime);
2373- runtime.reset();
2374- acc.reset();
2375- try
2376- {
2377- root->account();
2378- FAIL();
2379- }
2380- catch (RuntimeDestroyedException const& e)
2381- {
2382- EXPECT_EQ("Root::account(): runtime was destroyed previously", e.error_message());
2383- }
2384- }
2385-
2386- // Getting the root from an item with a destroyed runtime must fail.
2387- {
2388- auto runtime = Runtime::create(connection());
2389- auto root = get_root(runtime);
2390- clear_folder(root);
2391-
2392- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2393- runtime.reset();
2394- try
2395- {
2396- file->root();
2397- FAIL();
2398- }
2399- catch (RuntimeDestroyedException const& e)
2400- {
2401- EXPECT_EQ("Item::root(): runtime was destroyed previously", e.error_message());
2402- }
2403- }
2404-
2405- // Getting the root from an item with a destroyed root must fail.
2406- {
2407- auto runtime = Runtime::create(connection());
2408- auto acc = get_account(runtime);
2409- auto root = get_root(runtime);
2410- clear_folder(root);
2411-
2412- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2413- runtime.reset();
2414- acc.reset();
2415- root.reset();
2416- try
2417- {
2418- file->root();
2419- FAIL();
2420- }
2421- catch (RuntimeDestroyedException const& e)
2422- {
2423- EXPECT_EQ("Item::root(): runtime was destroyed previously", e.error_message());
2424- }
2425- }
2426-
2427- // etag() with destroyed runtime must fail.
2428- {
2429- auto runtime = Runtime::create(connection());
2430- auto root = get_root(runtime);
2431- clear_folder(root);
2432-
2433- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2434- runtime->shutdown();
2435- try
2436- {
2437- file->etag();
2438- FAIL();
2439- }
2440- catch (RuntimeDestroyedException const& e)
2441- {
2442- EXPECT_EQ("Item::etag(): runtime was destroyed previously", e.error_message());
2443- }
2444- }
2445-
2446- // metadata() with destroyed runtime must fail.
2447- {
2448- auto runtime = Runtime::create(connection());
2449- auto root = get_root(runtime);
2450- clear_folder(root);
2451-
2452- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2453- runtime->shutdown();
2454- try
2455- {
2456- file->metadata();
2457- FAIL();
2458- }
2459- catch (RuntimeDestroyedException const& e)
2460- {
2461- EXPECT_EQ("Item::metadata(): runtime was destroyed previously", e.error_message());
2462- }
2463- }
2464-
2465- // last_modified_time() with destroyed runtime must fail.
2466- {
2467- auto runtime = Runtime::create(connection());
2468- auto root = get_root(runtime);
2469- clear_folder(root);
2470-
2471- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2472- runtime->shutdown();
2473- try
2474- {
2475- file->last_modified_time();
2476- FAIL();
2477- }
2478- catch (RuntimeDestroyedException const& e)
2479- {
2480- EXPECT_EQ("Item::last_modified_time(): runtime was destroyed previously", e.error_message());
2481- }
2482- }
2483-
2484- // copy() with destroyed runtime must fail.
2485- {
2486- auto runtime = Runtime::create(connection());
2487- auto root = get_root(runtime);
2488- clear_folder(root);
2489-
2490- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2491- runtime->shutdown();
2492- try
2493- {
2494- call(file->copy(root, "file2"));
2495- FAIL();
2496- }
2497- catch (RuntimeDestroyedException const& e)
2498- {
2499- EXPECT_EQ("Item::copy(): runtime was destroyed previously", e.error_message());
2500- }
2501- }
2502-
2503- // move() with destroyed runtime must fail.
2504- {
2505- auto runtime = Runtime::create(connection());
2506- auto root = get_root(runtime);
2507- clear_folder(root);
2508-
2509- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2510- runtime->shutdown();
2511- try
2512- {
2513- call(file->move(root, "file2"));
2514- FAIL();
2515- }
2516- catch (RuntimeDestroyedException const& e)
2517- {
2518- EXPECT_EQ("Item::move(): runtime was destroyed previously", e.error_message());
2519- }
2520- }
2521-
2522- // parents() on root with destroyed runtime must fail.
2523- {
2524- auto runtime = Runtime::create(connection());
2525- auto root = get_root(runtime);
2526- clear_folder(root);
2527-
2528- runtime->shutdown();
2529- try
2530- {
2531- call(root->parents());
2532- FAIL();
2533- }
2534- catch (RuntimeDestroyedException const& e)
2535- {
2536- EXPECT_EQ("Root::parents(): runtime was destroyed previously", e.error_message());
2537- }
2538- }
2539-
2540- // parents() on file with destroyed runtime must fail.
2541- {
2542- auto runtime = Runtime::create(connection());
2543- auto root = get_root(runtime);
2544- clear_folder(root);
2545-
2546- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2547- runtime->shutdown();
2548- try
2549- {
2550- call(file->parents());
2551- FAIL();
2552- }
2553- catch (RuntimeDestroyedException const& e)
2554- {
2555- EXPECT_EQ("Item::parents(): runtime was destroyed previously", e.error_message());
2556- }
2557- }
2558-
2559- // parent_ids() with destroyed runtime must fail.
2560- {
2561- auto runtime = Runtime::create(connection());
2562- auto root = get_root(runtime);
2563- clear_folder(root);
2564-
2565- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2566- runtime->shutdown();
2567- try
2568- {
2569- file->parent_ids();
2570- FAIL();
2571- }
2572- catch (RuntimeDestroyedException const& e)
2573- {
2574- EXPECT_EQ("Item::parent_ids(): runtime was destroyed previously", e.error_message());
2575- }
2576- }
2577-
2578- // parent_ids() on root with destroyed runtime must fail.
2579- {
2580- auto runtime = Runtime::create(connection());
2581- auto root = get_root(runtime);
2582- clear_folder(root);
2583-
2584- runtime->shutdown();
2585- try
2586- {
2587- root->parent_ids();
2588- FAIL();
2589- }
2590- catch (RuntimeDestroyedException const& e)
2591- {
2592- EXPECT_EQ("Root::parent_ids(): runtime was destroyed previously", e.error_message());
2593- }
2594- }
2595-
2596- // delete_item() with destroyed runtime must fail.
2597- {
2598- auto runtime = Runtime::create(connection());
2599- auto root = get_root(runtime);
2600- clear_folder(root);
2601-
2602- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2603- runtime->shutdown();
2604- try
2605- {
2606- call(file->delete_item());
2607- FAIL();
2608- }
2609- catch (RuntimeDestroyedException const& e)
2610- {
2611- EXPECT_EQ("Item::delete_item(): runtime was destroyed previously", e.error_message());
2612- }
2613- }
2614-
2615- // delete_item() on root with destroyed runtime must fail.
2616- {
2617- auto runtime = Runtime::create(connection());
2618- auto root = get_root(runtime);
2619- clear_folder(root);
2620-
2621- runtime->shutdown();
2622- try
2623- {
2624- call(root->delete_item());
2625- FAIL();
2626- }
2627- catch (RuntimeDestroyedException const& e)
2628- {
2629- EXPECT_EQ("Item::delete_item(): runtime was destroyed previously", e.error_message());
2630- }
2631- }
2632-
2633- // creation_time() with destroyed runtime must fail.
2634- {
2635- auto runtime = Runtime::create(connection());
2636- auto root = get_root(runtime);
2637- clear_folder(root);
2638-
2639- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2640- runtime->shutdown();
2641- try
2642- {
2643- file->creation_time();
2644- FAIL();
2645- }
2646- catch (RuntimeDestroyedException const& e)
2647- {
2648- EXPECT_EQ("Item::creation_time(): runtime was destroyed previously", e.error_message());
2649- }
2650- }
2651-
2652- // native_metadata() with destroyed runtime must fail.
2653- {
2654- auto runtime = Runtime::create(connection());
2655- auto root = get_root(runtime);
2656- clear_folder(root);
2657-
2658- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2659- runtime->shutdown();
2660- try
2661- {
2662- file->native_metadata();
2663- FAIL();
2664- }
2665- catch (RuntimeDestroyedException const& e)
2666- {
2667- EXPECT_EQ("Item::native_metadata(): runtime was destroyed previously", e.error_message());
2668- }
2669- }
2670-
2671- // name() on root with destroyed runtime must fail.
2672- {
2673- auto runtime = Runtime::create(connection());
2674- auto root = get_root(runtime);
2675- clear_folder(root);
2676-
2677- runtime->shutdown();
2678- try
2679- {
2680- root->name();
2681- FAIL();
2682- }
2683- catch (RuntimeDestroyedException const& e)
2684- {
2685- EXPECT_EQ("Item::name(): runtime was destroyed previously", e.error_message());
2686- }
2687- }
2688-
2689- // name() on folder with destroyed runtime must fail.
2690- {
2691- auto runtime = Runtime::create(connection());
2692- auto root = get_root(runtime);
2693- clear_folder(root);
2694-
2695- auto folder = dynamic_pointer_cast<Folder>(call(root->get("child_folder_id")));
2696- runtime->shutdown();
2697- try
2698- {
2699- folder->name();
2700- FAIL();
2701- }
2702- catch (RuntimeDestroyedException const& e)
2703- {
2704- EXPECT_EQ("Item::name(): runtime was destroyed previously", e.error_message());
2705- }
2706- }
2707-
2708- // name() on file with destroyed runtime must fail.
2709- {
2710- auto runtime = Runtime::create(connection());
2711- auto root = get_root(runtime);
2712- clear_folder(root);
2713-
2714- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2715- runtime->shutdown();
2716- try
2717- {
2718- file->name();
2719- FAIL();
2720- }
2721- catch (RuntimeDestroyedException const& e)
2722- {
2723- EXPECT_EQ("Item::name(): runtime was destroyed previously", e.error_message());
2724- }
2725- }
2726-
2727- // list() with destroyed runtime must fail.
2728- {
2729- auto runtime = Runtime::create(connection());
2730- auto root = get_root(runtime);
2731- clear_folder(root);
2732-
2733- runtime->shutdown();
2734- try
2735- {
2736- call(root->list());
2737- FAIL();
2738- }
2739- catch (RuntimeDestroyedException const& e)
2740- {
2741- EXPECT_EQ("Folder::list(): runtime was destroyed previously", e.error_message());
2742- }
2743- }
2744-
2745- // lookup() with destroyed runtime must fail.
2746- {
2747- auto runtime = Runtime::create(connection());
2748- auto root = get_root(runtime);
2749- clear_folder(root);
2750-
2751- runtime->shutdown();
2752- try
2753- {
2754- call(root->lookup("file"));
2755- FAIL();
2756- }
2757- catch (RuntimeDestroyedException const& e)
2758- {
2759- EXPECT_EQ("Folder::lookup(): runtime was destroyed previously", e.error_message());
2760- }
2761- }
2762-
2763- // create_folder() with destroyed runtime must fail.
2764- {
2765- auto runtime = Runtime::create(connection());
2766- auto root = get_root(runtime);
2767- clear_folder(root);
2768-
2769- runtime->shutdown();
2770- try
2771- {
2772- call(root->create_folder("folder"));
2773- FAIL();
2774- }
2775- catch (RuntimeDestroyedException const& e)
2776- {
2777- EXPECT_EQ("Folder::create_folder(): runtime was destroyed previously", e.error_message());
2778- }
2779- }
2780-
2781- // create_file() with destroyed runtime must fail.
2782- {
2783- auto runtime = Runtime::create(connection());
2784- auto root = get_root(runtime);
2785- clear_folder(root);
2786-
2787- runtime->shutdown();
2788- try
2789- {
2790- call(root->create_file("file", 0));
2791- FAIL();
2792- }
2793- catch (RuntimeDestroyedException const& e)
2794- {
2795- EXPECT_EQ("Folder::create_file(): runtime was destroyed previously", e.error_message());
2796- }
2797- }
2798-
2799- // size() with destroyed runtime must fail.
2800- {
2801- auto runtime = Runtime::create(connection());
2802- auto root = get_root(runtime);
2803- clear_folder(root);
2804-
2805- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2806- runtime->shutdown();
2807- try
2808- {
2809- file->size();
2810- FAIL();
2811- }
2812- catch (RuntimeDestroyedException const& e)
2813- {
2814- EXPECT_EQ("File::size(): runtime was destroyed previously", e.error_message());
2815- }
2816- }
2817-
2818- // create_uploader() with destroyed runtime must fail.
2819- {
2820- auto runtime = Runtime::create(connection());
2821- auto root = get_root(runtime);
2822- clear_folder(root);
2823-
2824- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2825- runtime->shutdown();
2826- try
2827- {
2828- call(file->create_uploader(ConflictPolicy::overwrite, 0));
2829- FAIL();
2830- }
2831- catch (RuntimeDestroyedException const& e)
2832- {
2833- EXPECT_EQ("File::create_uploader(): runtime was destroyed previously", e.error_message()) << e.what();
2834- }
2835- }
2836-
2837- // create_downloader() with destroyed runtime must fail.
2838- {
2839- auto runtime = Runtime::create(connection());
2840- auto root = get_root(runtime);
2841- clear_folder(root);
2842-
2843- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2844- runtime->shutdown();
2845- try
2846- {
2847- call(file->create_downloader());
2848- FAIL();
2849- }
2850- catch (RuntimeDestroyedException const& e)
2851- {
2852- EXPECT_EQ("File::create_downloader(): runtime was destroyed previously", e.error_message());
2853- }
2854- }
2855-
2856- // free_space_bytes() with destroyed runtime must fail.
2857- {
2858- auto runtime = Runtime::create(connection());
2859- auto root = get_root(runtime);
2860- clear_folder(root);
2861-
2862- runtime->shutdown();
2863- try
2864- {
2865- call(root->free_space_bytes());
2866- FAIL();
2867- }
2868- catch (RuntimeDestroyedException const& e)
2869- {
2870- EXPECT_EQ("Root::free_space_bytes(): runtime was destroyed previously", e.error_message());
2871- }
2872- }
2873-
2874- // used_space_bytes() with destroyed runtime must fail.
2875- {
2876- auto runtime = Runtime::create(connection());
2877- auto root = get_root(runtime);
2878- clear_folder(root);
2879-
2880- runtime->shutdown();
2881- try
2882- {
2883- call(root->used_space_bytes());
2884- FAIL();
2885- }
2886- catch (RuntimeDestroyedException const& e)
2887- {
2888- EXPECT_EQ("Root::used_space_bytes(): runtime was destroyed previously", e.error_message());
2889- }
2890- }
2891-
2892- // get() with destroyed runtime must fail.
2893- {
2894- auto runtime = Runtime::create(connection());
2895- auto root = get_root(runtime);
2896- clear_folder(root);
2897-
2898- runtime->shutdown();
2899- try
2900- {
2901- call(root->get("some_id"));
2902- FAIL();
2903- }
2904- catch (RuntimeDestroyedException const& e)
2905- {
2906- EXPECT_EQ("Root::get(): runtime was destroyed previously", e.error_message());
2907- }
2908- }
2909-}
2910-
2911-TEST_F(DestroyedTest, roots_destroyed_while_reply_outstanding)
2912-{
2913- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider));
2914-
2915- auto fut = acc_->roots();
2916- runtime_->shutdown();
2917- try
2918- {
2919- ASSERT_TRUE(wait(fut));
2920- fut.result();
2921- FAIL();
2922- }
2923- catch (RuntimeDestroyedException const& e)
2924- {
2925- EXPECT_EQ("Account::roots(): runtime was destroyed previously", e.error_message());
2926- }
2927-}
2928-
2929-TEST_F(DestroyedTest, get_destroyed_while_reply_outstanding)
2930-{
2931- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_metadata")));
2932-
2933- auto root = call(acc_->roots())[0];
2934- auto fut = root->get("root_id");
2935- runtime_->shutdown();
2936- try
2937- {
2938- ASSERT_TRUE(wait(fut));
2939- fut.result();
2940- FAIL();
2941- }
2942- catch (RuntimeDestroyedException const& e)
2943- {
2944- EXPECT_EQ("Root::get(): runtime was destroyed previously", e.error_message());
2945- }
2946-}
2947-
2948-TEST_F(DestroyedTest, copy_destroyed_while_reply_outstanding)
2949-{
2950- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2951-
2952- auto root = call(acc_->roots())[0];
2953- auto fut = root->copy(root, "new name");
2954- runtime_->shutdown();
2955- try
2956- {
2957- ASSERT_TRUE(wait(fut));
2958- fut.result();
2959- FAIL();
2960- }
2961- catch (RuntimeDestroyedException const& e)
2962- {
2963- EXPECT_EQ("Item::copy(): runtime was destroyed previously", e.error_message());
2964- }
2965-}
2966-
2967-TEST_F(DestroyedTest, move_destroyed_while_reply_outstanding)
2968-{
2969- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_move")));
2970-
2971- auto root = call(acc_->roots())[0];
2972- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
2973- auto fut = file->move(root, "new name");
2974- runtime_->shutdown();
2975- try
2976- {
2977- ASSERT_TRUE(wait(fut));
2978- fut.result();
2979- FAIL();
2980- }
2981- catch (RuntimeDestroyedException const& e)
2982- {
2983- EXPECT_EQ("Item::move(): runtime was destroyed previously", e.error_message());
2984- }
2985-}
2986-
2987-TEST_F(DestroyedTest, list_destroyed_while_reply_outstanding)
2988-{
2989- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list slow")));
2990-
2991- auto root = call(acc_->roots())[0];
2992- auto fut = root->list();
2993- runtime_->shutdown();
2994- try
2995- {
2996- ASSERT_TRUE(wait(fut));
2997- fut.result();
2998- FAIL();
2999- }
3000- catch (RuntimeDestroyedException const& e)
3001- {
3002- EXPECT_EQ("Folder::list(): runtime was destroyed previously", e.error_message());
3003- }
3004-}
3005-
3006-TEST_F(DestroyedTest, lookup_destroyed_while_reply_outstanding)
3007-{
3008- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("lookup slow")));
3009-
3010- auto root = call(acc_->roots())[0];
3011- auto fut = root->lookup("Child");
3012- runtime_->shutdown();
3013- try
3014- {
3015- ASSERT_TRUE(wait(fut));
3016- fut.result();
3017- FAIL();
3018- }
3019- catch (RuntimeDestroyedException const& e)
3020- {
3021- EXPECT_EQ("Folder::lookup(): runtime was destroyed previously", e.error_message());
3022- }
3023-}
3024-
3025-TEST_F(DestroyedTest, create_folder_destroyed_while_reply_outstanding)
3026-{
3027- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("create_folder slow")));
3028-
3029- auto root = call(acc_->roots())[0];
3030- auto fut = root->create_folder("Child");
3031- runtime_->shutdown();
3032- try
3033- {
3034- ASSERT_TRUE(wait(fut));
3035- fut.result();
3036- FAIL();
3037- }
3038- catch (RuntimeDestroyedException const& e)
3039- {
3040- EXPECT_EQ("Folder::create_folder(): runtime was destroyed previously", e.error_message());
3041- }
3042-}
3043-
3044-TEST_F(DestroyedTest, create_file_destroyed_while_reply_outstanding)
3045-{
3046- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("create_file slow")));
3047-
3048- auto root = call(acc_->roots())[0];
3049- auto fut = root->create_file("Child", 0);
3050- runtime_->shutdown();
3051- try
3052- {
3053- ASSERT_TRUE(wait(fut));
3054- fut.result();
3055- FAIL();
3056- }
3057- catch (RuntimeDestroyedException const& e)
3058- {
3059- EXPECT_EQ("Folder::create_file(): runtime was destroyed previously", e.error_message());
3060- }
3061-}
3062-
3063-TEST_F(DestroyedTest, create_uploader_destroyed_while_reply_outstanding)
3064-{
3065- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("create_file slow")));
3066-
3067- auto root = call(acc_->roots())[0];
3068- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
3069- auto fut = file->create_uploader(ConflictPolicy::overwrite, 0);
3070- runtime_->shutdown();
3071- try
3072- {
3073- ASSERT_TRUE(wait(fut));
3074- fut.result();
3075- FAIL();
3076- }
3077- catch (RuntimeDestroyedException const& e)
3078- {
3079- EXPECT_EQ("File::create_uploader(): runtime was destroyed previously", e.error_message());
3080- }
3081-}
3082-
3083-TEST_F(DestroyedTest, create_downloader_destroyed_while_reply_outstanding)
3084-{
3085- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("create_file slow")));
3086-
3087- auto root = call(acc_->roots())[0];
3088- auto file = dynamic_pointer_cast<File>(call(root->get("child_id")));
3089- auto fut = file->create_downloader();
3090- runtime_->shutdown();
3091- try
3092- {
3093- ASSERT_TRUE(wait(fut));
3094- fut.result();
3095- FAIL();
3096- }
3097- catch (RuntimeDestroyedException const& e)
3098- {
3099- EXPECT_EQ("File::create_downloader(): runtime was destroyed previously", e.error_message());
3100- }
3101-}
3102-#endif
3103+ EXPECT_EQ("child_id", items[0].itemId());
3104+
3105+ // When the signal for the final item arrives, status must be Finished.
3106+ EXPECT_EQ(ItemListJob::Status::Finished, j->status());
3107+
3108+ // Finished signal must be received.
3109+ if (status_spy.count() == 0)
3110+ {
3111+ status_spy.wait(SIGNAL_WAIT_TIME);
3112+ }
3113+ ASSERT_EQ(1, status_spy.count());
3114+ auto status_arg = status_spy.takeFirst();
3115+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
3116+}
3117+
3118+TEST_F(ListTest, empty_list)
3119+{
3120+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list_empty")));
3121+
3122+ Item root;
3123+ {
3124+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3125+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3126+ spy.wait(SIGNAL_WAIT_TIME);
3127+ root = j->item();
3128+ }
3129+
3130+ unique_ptr<ItemListJob> j(root.list());
3131+ EXPECT_TRUE(j->isValid());
3132+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
3133+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
3134+
3135+ QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
3136+ QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
3137+ status_spy.wait(SIGNAL_WAIT_TIME);
3138+ ASSERT_EQ(0, ready_spy.count());
3139+
3140+ EXPECT_EQ(ItemListJob::Status::Finished, j->status());
3141+
3142+ ASSERT_EQ(1, status_spy.count());
3143+ auto status_arg = status_spy.takeFirst();
3144+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
3145+}
3146+
3147+TEST_F(ListTest, two_children)
3148+{
3149+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list_two_children")));
3150+
3151+ Item root;
3152+ {
3153+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3154+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3155+ spy.wait(SIGNAL_WAIT_TIME);
3156+ root = j->item();
3157+ }
3158+
3159+ unique_ptr<ItemListJob> j(root.list());
3160+ EXPECT_TRUE(j->isValid());
3161+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
3162+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
3163+
3164+ QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
3165+ QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
3166+
3167+ QList<Item> items;
3168+ ready_spy.wait(SIGNAL_WAIT_TIME);
3169+ auto list_arg = ready_spy.takeFirst();
3170+ auto this_item = qvariant_cast<QList<Item>>(list_arg.at(0));
3171+ items.append(this_item);
3172+ if (ready_spy.count() < 1)
3173+ {
3174+ ASSERT_TRUE(ready_spy.wait(SIGNAL_WAIT_TIME));
3175+ }
3176+ list_arg = ready_spy.takeFirst();
3177+ this_item = qvariant_cast<QList<Item>>(list_arg.at(0));
3178+ items.append(this_item);
3179+
3180+ // Finished signal must be received.
3181+ if (status_spy.count() == 0)
3182+ {
3183+ status_spy.wait(SIGNAL_WAIT_TIME);
3184+ }
3185+ ASSERT_EQ(1, status_spy.count());
3186+ auto status_arg = status_spy.takeFirst();
3187+ EXPECT_EQ(ItemListJob::Status::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
3188+
3189+ // Must have two children.
3190+ ASSERT_EQ(2, items.size());
3191+ EXPECT_EQ("child_id", items[0].itemId());
3192+ EXPECT_EQ("child2_id", items[1].itemId());
3193+}
3194+
3195+TEST_F(ListTest, job_out_of_scope)
3196+{
3197+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list_slow")));
3198+
3199+ Item root;
3200+ {
3201+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3202+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3203+ spy.wait(SIGNAL_WAIT_TIME);
3204+ root = j->item();
3205+ }
3206+
3207+ unique_ptr<ItemListJob> j(root.list());
3208+ // Just to show that it's safe to drop the job on the floor while
3209+ // operation is in progress.
3210+}
3211+
3212+TEST_F(ListTest, invalid)
3213+{
3214+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
3215+
3216+ Item root;
3217+ unique_ptr<ItemListJob> j(root.list());
3218+ EXPECT_FALSE(j->isValid());
3219+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
3220+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
3221+ EXPECT_EQ("LogicError: Item::list(): cannot create job from invalid item", j->error().errorString());
3222+
3223+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
3224+ spy.wait(SIGNAL_WAIT_TIME);
3225+ ASSERT_EQ(1, spy.count());
3226+ auto arg = spy.takeFirst();
3227+ auto status = qvariant_cast<ItemListJob::Status>(arg.at(0));
3228+ EXPECT_EQ(ItemListJob::Status::Error, status);
3229+
3230+ EXPECT_EQ("LogicError: Item::list(): cannot create job from invalid item", j->error().errorString());
3231+}
3232+
3233+TEST_F(ListTest, wrong_type)
3234+{
3235+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
3236+
3237+ Item root;
3238+ {
3239+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3240+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3241+ spy.wait(SIGNAL_WAIT_TIME);
3242+ root = j->item();
3243+ }
3244+
3245+ Item child;
3246+ {
3247+ unique_ptr<ItemJob> j(acc_.get("child_id"));
3248+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3249+ spy.wait(SIGNAL_WAIT_TIME);
3250+ child = j->item();
3251+ }
3252+
3253+ unique_ptr<ItemListJob> j(child.list());
3254+ EXPECT_FALSE(j->isValid());
3255+ EXPECT_EQ(ItemListJob::Status::Error, j->status());
3256+ EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
3257+ EXPECT_EQ("LogicError: Item::list(): cannot perform list on a file", j->error().errorString());
3258+
3259+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
3260+ spy.wait(SIGNAL_WAIT_TIME);
3261+ ASSERT_EQ(1, spy.count());
3262+ auto arg = spy.takeFirst();
3263+ auto status = qvariant_cast<ItemListJob::Status>(arg.at(0));
3264+ EXPECT_EQ(ItemListJob::Status::Error, status);
3265+
3266+ EXPECT_EQ("LogicError: Item::list(): cannot perform list on a file", j->error().errorString());
3267+}
3268+
3269+TEST_F(ListTest, wrong_return_type)
3270+{
3271+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list_return_root")));
3272+
3273+ Item root;
3274+ {
3275+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3276+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3277+ spy.wait(SIGNAL_WAIT_TIME);
3278+ root = j->item();
3279+ }
3280+
3281+ unique_ptr<ItemListJob> j(root.list());
3282+ EXPECT_TRUE(j->isValid());
3283+ EXPECT_EQ(ItemListJob::Status::Loading, j->status());
3284+ EXPECT_EQ(StorageError::Type::NoError, j->error().type());
3285+
3286+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
3287+ spy.wait(SIGNAL_WAIT_TIME);
3288+ ASSERT_EQ(1, spy.count());
3289+ auto arg = spy.takeFirst();
3290+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
3291+
3292+ EXPECT_EQ("LocalCommsError: Item::list(): impossible root item returned by provider", j->error().errorString());
3293+}
3294+
3295+TEST_F(ListTest, runtime_destroyed_while_item_list_job_running)
3296+{
3297+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list_slow")));
3298+
3299+ Item root;
3300+ {
3301+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3302+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3303+ spy.wait(SIGNAL_WAIT_TIME);
3304+ root = j->item();
3305+ }
3306+
3307+ unique_ptr<ItemListJob> j(root.list());
3308+
3309+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
3310+
3311+ // Signal must be received.
3312+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
3313+ spy.wait(SIGNAL_WAIT_TIME);
3314+ ASSERT_EQ(1, spy.count());
3315+ auto arg = spy.takeFirst();
3316+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
3317+
3318+ EXPECT_EQ("Item::list(): Runtime was destroyed previously", j->error().message());
3319+}
3320+
3321+TEST_F(ListTest, no_permission)
3322+{
3323+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("list_no_permission")));
3324+
3325+ Item root;
3326+ {
3327+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3328+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3329+ spy.wait(SIGNAL_WAIT_TIME);
3330+ root = j->item();
3331+ }
3332+
3333+ unique_ptr<ItemListJob> j(root.list());
3334+ EXPECT_TRUE(j->isValid());
3335+
3336+ // Signal must be received.
3337+ QSignalSpy spy(j.get(), &ItemListJob::statusChanged);
3338+ spy.wait(SIGNAL_WAIT_TIME);
3339+ ASSERT_EQ(1, spy.count());
3340+ auto arg = spy.takeFirst();
3341+ EXPECT_EQ(ItemListJob::Status::Error, qvariant_cast<ItemListJob::Status>(arg.at(0)));
3342+
3343+ EXPECT_EQ("permission denied", j->error().message());
3344+ EXPECT_EQ(StorageError::Type::PermissionDenied, j->error().type());
3345+}
3346
3347 int main(int argc, char** argv)
3348 {

Subscribers

People subscribed via source and target branches

to all changes: