Merge lp:~michihenning/storage-framework/copy-and-move into lp:storage-framework/devel

Proposed by Michi Henning
Status: Merged
Approved by: Michi Henning
Approved revision: 93
Merged at revision: 75
Proposed branch: lp:~michihenning/storage-framework/copy-and-move
Merge into: lp:storage-framework/devel
Prerequisite: lp:~michihenning/storage-framework/parents
Diff against target: 925 lines (+656/-65)
7 files modified
include/unity/storage/qt/internal/ItemImpl.h (+61/-1)
include/unity/storage/qt/internal/ItemJobImpl.h (+9/-0)
src/qt/internal/AccountImpl.cpp (+1/-3)
src/qt/internal/ItemImpl.cpp (+66/-26)
src/qt/internal/ItemJobImpl.cpp (+21/-0)
tests/remote-client/MockProvider.cpp (+37/-2)
tests/remote-client/remote-client_test.cpp (+461/-33)
To merge this branch: bzr merge lp:~michihenning/storage-framework/copy-and-move
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Approve
James Henstridge Approve
Review via email: mp+307116@code.launchpad.net

Commit message

Added copy and move implementations.

Description of the change

Added copy and move implementations. Re-factored semantic checks for ItemImpl operations into two templates, to avoid endlessly repeating almost identical code.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

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

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

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

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

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

review: Approve (continuous-integration)
Revision history for this message
James Henstridge (jamesh) wrote :

Looks good. Again, one issue that is more of a suggestion for possible improvement than a bug, so I'm marking the branch approved and leaving it up to you to top approve it when you're ready.

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

Simplified ItemImpl template methods, thanks!

91. By Michi Henning

Merged dependent branch.

92. By Michi Henning

Simplified ItemImpl template methods for checking preconditions.

93. By Michi Henning

Merged parent branch and resolved conflicts.

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

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

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/143/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/internal/ItemImpl.h'
2--- include/unity/storage/qt/internal/ItemImpl.h 2016-10-10 02:14:34 +0000
3+++ include/unity/storage/qt/internal/ItemImpl.h 2016-10-10 02:14:34 +0000
4@@ -20,6 +20,9 @@
5
6 #include <unity/storage/internal/ItemMetadata.h>
7 #include <unity/storage/qt/Account.h>
8+#include <unity/storage/qt/internal/AccountImpl.h>
9+#include <unity/storage/qt/internal/RuntimeImpl.h>
10+#include <unity/storage/qt/internal/StorageErrorImpl.h>
11 #include <unity/storage/qt/Item.h>
12
13 namespace unity
14@@ -82,9 +85,16 @@
15 std::shared_ptr<AccountImpl> const& account);
16
17 std::shared_ptr<RuntimeImpl> runtime() const;
18+ std::shared_ptr<AccountImpl> account_impl() const;
19
20 private:
21- //std::shared_ptr<RuntimeImpl> get_runtime(QString const& method) const;
22+ template<typename T>
23+ decltype(T::make_job(StorageError())) check_invalid_or_destroyed(QString const& method) const;
24+
25+ template<typename T>
26+ decltype(T::make_job(StorageError())) check_copy_move_precondition(QString const& method,
27+ Item const& newParent,
28+ QString const& newName) const;
29
30 bool is_valid_;
31 storage::internal::ItemMetadata md_;
32@@ -93,6 +103,56 @@
33 friend class unity::storage::qt::Item;
34 };
35
36+template<typename T>
37+decltype(T::make_job(StorageError())) ItemImpl::check_invalid_or_destroyed(QString const& method) const
38+{
39+ if (!is_valid_)
40+ {
41+ auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid item");
42+ return T::make_job(e);
43+ }
44+ auto runtime = account_->runtime();
45+ if (!runtime || !runtime->isValid())
46+ {
47+ auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously");
48+ return T::make_job(e);
49+ }
50+ return nullptr;
51+}
52+
53+template<typename T>
54+decltype(T::make_job(StorageError())) ItemImpl::check_copy_move_precondition(QString const& method,
55+ Item const& newParent,
56+ QString const& newName) const
57+{
58+ auto invalid_job = check_invalid_or_destroyed<T>(method);
59+ if (invalid_job)
60+ {
61+ return invalid_job;
62+ }
63+ if (!newParent.isValid())
64+ {
65+ auto e = StorageErrorImpl::invalid_argument_error(method + ": newParent is invalid");
66+ return T::make_job(e);
67+ }
68+ if (newName.isEmpty())
69+ {
70+ auto e = StorageErrorImpl::invalid_argument_error(method + ": newName cannot be empty");
71+ return T::make_job(e);
72+ }
73+ if (account() != newParent.account())
74+ {
75+ auto e = StorageErrorImpl::logic_error(method + ": source and target must belong to the same account");
76+ return T::make_job(e);
77+ }
78+ if (newParent.type() == Item::File)
79+ {
80+ auto e = StorageErrorImpl::logic_error(method + ": newParent cannot be a file");
81+ return T::make_job(e);
82+ }
83+ return nullptr;
84+}
85+
86 } // namespace internal
87 } // namespace qt
88 } // namespace storage
89
90=== modified file 'include/unity/storage/qt/internal/ItemJobImpl.h'
91--- include/unity/storage/qt/internal/ItemJobImpl.h 2016-10-10 02:14:34 +0000
92+++ include/unity/storage/qt/internal/ItemJobImpl.h 2016-10-10 02:14:34 +0000
93@@ -57,6 +57,10 @@
94 QString const& method,
95 QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
96 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
97+ static ItemJob* make_job(std::shared_ptr<ItemImpl> const&,
98+ QString const& method,
99+ QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
100+ std::function<void(storage::internal::ItemMetadata const&)> const& validate);
101 static ItemJob* make_job(StorageError const& e);
102
103 private:
104@@ -64,6 +68,10 @@
105 QString const& method,
106 QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
107 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
108+ ItemJobImpl(std::shared_ptr<ItemImpl> const& item,
109+ QString const& method,
110+ QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
111+ std::function<void(storage::internal::ItemMetadata const&)> const& validate);
112 ItemJobImpl(StorageError const& e);
113
114 ItemJob* public_instance_;
115@@ -71,6 +79,7 @@
116 StorageError error_;
117 QString method_;
118 std::shared_ptr<AccountImpl> account_;
119+ std::shared_ptr<ItemImpl> item_impl_;
120 std::function<void(storage::internal::ItemMetadata const&)> validate_;
121 Item item_;
122 };
123
124=== modified file 'src/qt/internal/AccountImpl.cpp'
125--- src/qt/internal/AccountImpl.cpp 2016-10-10 02:14:34 +0000
126+++ src/qt/internal/AccountImpl.cpp 2016-10-10 02:14:34 +0000
127@@ -102,7 +102,7 @@
128 if (md.type != ItemType::root)
129 {
130 QString msg = method + ": provider returned non-root item type: " + QString::number(int(md.type));
131- qCritical() << msg;
132+ qCritical().noquote() << msg;
133 throw StorageErrorImpl::local_comms_error(msg);
134 }
135 };
136@@ -128,11 +128,9 @@
137 return ItemJobImpl::make_job(e);
138 }
139
140- // LCOV_EXCL_START
141 auto validate = [](storage::internal::ItemMetadata const&)
142 {
143 };
144- // LCOV_EXCL_STOP
145
146 auto reply = provider_->Metadata(itemId);
147 auto This = const_pointer_cast<AccountImpl>(shared_from_this());
148
149=== modified file 'src/qt/internal/ItemImpl.cpp'
150--- src/qt/internal/ItemImpl.cpp 2016-10-10 02:14:34 +0000
151+++ src/qt/internal/ItemImpl.cpp 2016-10-10 02:14:34 +0000
152@@ -20,12 +20,9 @@
153
154 #include "ProviderInterface.h"
155 #include <unity/storage/provider/metadata_keys.h>
156-#include <unity/storage/qt/internal/AccountImpl.h>
157 #include <unity/storage/qt/internal/ItemJobImpl.h>
158 #include <unity/storage/qt/internal/ItemListJobImpl.h>
159 #include <unity/storage/qt/internal/MultiItemJobImpl.h>
160-#include <unity/storage/qt/internal/RuntimeImpl.h>
161-#include <unity/storage/qt/internal/StorageErrorImpl.h>
162 #include <unity/storage/qt/internal/VoidJobImpl.h>
163 #include <unity/storage/qt/internal/validate.h>
164
165@@ -119,16 +116,10 @@
166 {
167 QString const method = "Item::parents()";
168
169- if (!is_valid_)
170- {
171- auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid item");
172- return ListJobImplBase::make_job(e);
173- }
174- auto runtime = account_->runtime();
175- if (!runtime || !runtime->isValid())
176- {
177- auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously");
178- return ListJobImplBase::make_job(e);
179+ auto invalid_job = check_invalid_or_destroyed<ItemListJobImpl>(method);
180+ if (invalid_job)
181+ {
182+ return invalid_job;
183 }
184
185 if (md_.type == storage::ItemType::root)
186@@ -150,7 +141,7 @@
187 if (md.type == ItemType::file)
188 {
189 QString msg = method + ": provider returned a file as a parent";
190- qCritical() << msg;
191+ qCritical().noquote() << msg;
192 throw StorageErrorImpl::local_comms_error(msg);
193 }
194 };
195@@ -160,28 +151,72 @@
196
197 ItemJob* ItemImpl::copy(Item const& newParent, QString const& newName) const
198 {
199- return nullptr; // TODO
200+ QString const method = "Item::copy()";
201+
202+ auto invalid_job = check_copy_move_precondition<ItemJobImpl>(method, newParent, newName);
203+ if (invalid_job)
204+ {
205+ return invalid_job;
206+ }
207+
208+ auto validate = [this, method](storage::internal::ItemMetadata const& md)
209+ {
210+ if ((md_.type == ItemType::file && md.type != ItemType::file)
211+ ||
212+ (md_.type != ItemType::file && md.type == ItemType::file))
213+ {
214+ QString msg = method + ": source and target item type differ";
215+ qCritical().noquote() << msg;
216+ throw StorageErrorImpl::local_comms_error(msg);
217+ }
218+ };
219+
220+ auto reply = account_->provider()->Copy(md_.item_id, newParent.itemId(), newName);
221+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
222+ return ItemJobImpl::make_job(This, method, reply, validate);
223 }
224
225 ItemJob* ItemImpl::move(Item const& newParent, QString const& newName) const
226 {
227- return nullptr; // TODO
228+ QString const method = "Item::move()";
229+
230+ auto invalid_job = check_copy_move_precondition<ItemJobImpl>(method, newParent, newName);
231+ if (invalid_job)
232+ {
233+ return invalid_job;
234+ }
235+
236+ auto validate = [this, method](storage::internal::ItemMetadata const& md)
237+ {
238+ if (md.type == ItemType::root)
239+ {
240+ QString msg = method + ": impossible root item returned by server";
241+ qCritical().noquote() << msg;
242+ throw StorageErrorImpl::local_comms_error(msg);
243+ }
244+ if ((md_.type == ItemType::file && md.type != ItemType::file)
245+ ||
246+ (md_.type != ItemType::file && md.type == ItemType::file))
247+ {
248+ QString msg = method + ": source and target item type differ";
249+ qCritical().noquote() << msg;
250+ throw StorageErrorImpl::local_comms_error(msg);
251+ }
252+ };
253+
254+ auto reply = account_->provider()->Move(md_.item_id, newParent.itemId(), newName);
255+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
256+ return ItemJobImpl::make_job(This, method, reply, validate);
257 }
258
259 VoidJob* ItemImpl::deleteItem() const
260 {
261 QString const method = "Item::deleteItem()";
262
263- if (!is_valid_)
264- {
265- auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid item");
266- return VoidJobImpl::make_job(e);
267- }
268- auto runtime = account_->runtime();
269- if (!runtime || !runtime->isValid())
270- {
271- auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously");
272- return VoidJobImpl::make_job(e);
273+ auto invalid_job = check_invalid_or_destroyed<VoidJobImpl>(method);
274+ if (invalid_job)
275+ {
276+ return invalid_job;
277 }
278 if (md_.type == storage::ItemType::root)
279 {
280@@ -313,6 +348,11 @@
281 return account_->runtime();
282 }
283
284+shared_ptr<AccountImpl> ItemImpl::account_impl() const
285+{
286+ return account_;
287+}
288+
289 } // namespace internal
290 } // namespace qt
291 } // namespace storage
292
293=== modified file 'src/qt/internal/ItemJobImpl.cpp'
294--- src/qt/internal/ItemJobImpl.cpp 2016-10-10 02:14:34 +0000
295+++ src/qt/internal/ItemJobImpl.cpp 2016-10-10 02:14:34 +0000
296@@ -86,6 +86,16 @@
297 new Handler<storage::internal::ItemMetadata>(this, reply, process_reply, process_error);
298 }
299
300+ItemJobImpl::ItemJobImpl(shared_ptr<ItemImpl> const& item,
301+ QString const& method,
302+ QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
303+ std::function<void(storage::internal::ItemMetadata const&)> const& validate)
304+ : ItemJobImpl(item->account_impl(), method, reply, validate)
305+{
306+ assert(item);
307+ item_impl_= item;
308+}
309+
310 ItemJobImpl::ItemJobImpl(StorageError const& error)
311 : status_(ItemJob::Error)
312 , error_(error)
313@@ -123,6 +133,17 @@
314 return job;
315 }
316
317+ItemJob* ItemJobImpl::make_job(shared_ptr<ItemImpl> const& item,
318+ QString const& method,
319+ QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
320+ std::function<void(storage::internal::ItemMetadata const&)> const& validate)
321+{
322+ unique_ptr<ItemJobImpl> impl(new ItemJobImpl(item, method, reply, validate));
323+ auto job = new ItemJob(move(impl));
324+ job->p_->public_instance_ = job;
325+ return job;
326+}
327+
328 ItemJob* ItemJobImpl::make_job(StorageError const& error)
329 {
330 unique_ptr<ItemJobImpl> impl(new ItemJobImpl(error));
331
332=== modified file 'tests/remote-client/MockProvider.cpp'
333--- tests/remote-client/MockProvider.cpp 2016-10-10 02:14:34 +0000
334+++ tests/remote-client/MockProvider.cpp 2016-10-10 02:14:34 +0000
335@@ -248,7 +248,29 @@
336 string const& item_id, string const& new_parent_id,
337 string const& new_name, Context const&)
338 {
339- Item metadata{item_id, { new_parent_id }, new_name, "etag", ItemType::file, {}};
340+ if (cmd_ == "move_returns_root")
341+ {
342+ Item metadata
343+ {
344+ "root_id", { new_parent_id }, new_name, "etag", ItemType::root,
345+ { { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
346+ };
347+ return make_ready_future(metadata);
348+ }
349+ if (cmd_ == "move_type_mismatch")
350+ {
351+ Item metadata
352+ {
353+ item_id, { new_parent_id }, new_name, "etag", ItemType::folder,
354+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
355+ };
356+ return make_ready_future(metadata);
357+ }
358+ Item metadata
359+ {
360+ item_id, { new_parent_id }, new_name, "etag", ItemType::file,
361+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
362+ };
363 return make_ready_future(metadata);
364 }
365
366@@ -256,7 +278,20 @@
367 string const&, string const& new_parent_id,
368 string const& new_name, Context const&)
369 {
370- Item metadata{"new_item_id", { new_parent_id }, new_name, "etag", ItemType::file, {}};
371+ if (cmd_ == "copy_type_mismatch")
372+ {
373+ Item metadata
374+ {
375+ "new_item_id", { new_parent_id }, new_name, "etag", ItemType::folder,
376+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
377+ };
378+ return make_ready_future(metadata);
379+ }
380+ Item metadata
381+ {
382+ "new_item_id", { new_parent_id }, new_name, "etag", ItemType::file,
383+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
384+ };
385 return make_ready_future(metadata);
386 }
387
388
389=== modified file 'tests/remote-client/remote-client_test.cpp'
390--- tests/remote-client/remote-client_test.cpp 2016-10-10 02:14:34 +0000
391+++ tests/remote-client/remote-client_test.cpp 2016-10-10 02:14:34 +0000
392@@ -55,9 +55,11 @@
393 };
394
395 class AccountTest : public RemoteClientTest {};
396+class CopyTest : public RemoteClientTest {};
397 class DeleteTest : public RemoteClientTest {};
398 class GetTest : public RemoteClientTest {};
399 class ItemTest : public RemoteClientTest {};
400+class MoveTest : public RemoteClientTest {};
401 class ParentsTest : public RemoteClientTest {};
402 class RootsTest : public RemoteClientTest {};
403 class RuntimeTest : public ProviderFixture {};
404@@ -774,7 +776,7 @@
405 EXPECT_EQ("Item::deleteItem(): cannot create job from invalid item", j->error().message());
406
407 // Signal must be received.
408- QSignalSpy spy(j.get(), &unity::storage::qt::VoidJob::statusChanged);
409+ QSignalSpy spy(j.get(), &VoidJob::statusChanged);
410 spy.wait(SIGNAL_WAIT_TIME);
411 ASSERT_EQ(1, spy.count());
412 auto arg = spy.takeFirst();
413@@ -1125,39 +1127,37 @@
414 }
415
416 QList<Item> parents;
417+ unique_ptr<ItemListJob> j(child.parents());
418+ EXPECT_TRUE(j->isValid());
419+
420+ QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
421+ QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
422+
423+ ready_spy.wait(SIGNAL_WAIT_TIME);
424+ auto list_arg = ready_spy.takeFirst();
425+ auto this_parent = qvariant_cast<QList<Item>>(list_arg.at(0));
426+ parents.append(this_parent);
427+ while (ready_spy.count() < 1)
428 {
429- unique_ptr<ItemListJob> j(child.parents());
430- EXPECT_TRUE(j->isValid());
431-
432- QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady);
433- QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged);
434-
435 ready_spy.wait(SIGNAL_WAIT_TIME);
436- auto list_arg = ready_spy.takeFirst();
437- auto this_parent = qvariant_cast<QList<Item>>(list_arg.at(0));
438- parents.append(this_parent);
439- while (ready_spy.count() < 1)
440- {
441- ready_spy.wait(SIGNAL_WAIT_TIME);
442- }
443- list_arg = ready_spy.takeFirst();
444- this_parent = qvariant_cast<QList<Item>>(list_arg.at(0));
445- parents.append(this_parent);
446-
447- // Finished signal must be received.
448- if (status_spy.count() == 0)
449- {
450- status_spy.wait(SIGNAL_WAIT_TIME);
451- }
452- ASSERT_EQ(1, status_spy.count());
453- auto status_arg = status_spy.takeFirst();
454- EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
455-
456- // Child must have two parents.
457- ASSERT_EQ(2, parents.size());
458- EXPECT_EQ("root_id", parents[0].itemId());
459- EXPECT_EQ("child_folder_id", parents[1].itemId());
460- }
461+ }
462+ list_arg = ready_spy.takeFirst();
463+ this_parent = qvariant_cast<QList<Item>>(list_arg.at(0));
464+ parents.append(this_parent);
465+
466+ // Finished signal must be received.
467+ if (status_spy.count() == 0)
468+ {
469+ status_spy.wait(SIGNAL_WAIT_TIME);
470+ }
471+ ASSERT_EQ(1, status_spy.count());
472+ auto status_arg = status_spy.takeFirst();
473+ EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0)));
474+
475+ // Child must have two parents.
476+ ASSERT_EQ(2, parents.size());
477+ EXPECT_EQ("root_id", parents[0].itemId());
478+ EXPECT_EQ("child_folder_id", parents[1].itemId());
479 }
480
481 TEST_F(ParentsTest, two_parents_throw)
482@@ -1305,7 +1305,6 @@
483 child = j->item();
484 }
485
486- QList<Item> parents;
487 {
488 unique_ptr<ItemListJob> j(child.parents());
489 EXPECT_TRUE(j->isValid());
490@@ -1322,6 +1321,435 @@
491 }
492 }
493
494+TEST_F(CopyTest, basic)
495+{
496+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
497+
498+ Item root;
499+ {
500+ unique_ptr<ItemJob> j(acc_.get("root_id"));
501+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
502+ spy.wait(SIGNAL_WAIT_TIME);
503+ root = j->item();
504+ }
505+
506+ Item child;
507+ {
508+ unique_ptr<ItemJob> j(acc_.get("child_id"));
509+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
510+ spy.wait(SIGNAL_WAIT_TIME);
511+ child = j->item();
512+ }
513+
514+ unique_ptr<ItemJob> j(child.copy(root, "copied_item"));
515+ EXPECT_TRUE(j->isValid());
516+ EXPECT_EQ(ItemJob::Loading, j->status());
517+ EXPECT_EQ(StorageError::NoError, j->error().type());
518+
519+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
520+ spy.wait(SIGNAL_WAIT_TIME);
521+ ASSERT_EQ(1, spy.count());
522+ auto arg = spy.takeFirst();
523+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
524+ EXPECT_EQ(ItemJob::Finished, status);
525+
526+ EXPECT_TRUE(j->isValid());
527+ EXPECT_EQ(ItemJob::Finished, j->status());
528+ EXPECT_EQ(StorageError::NoError, j->error().type());
529+ auto copied_file = j->item();
530+ EXPECT_EQ("new_item_id", copied_file.itemId());
531+ EXPECT_EQ(root.itemId(), copied_file.parentIds()[0]);
532+ EXPECT_EQ("copied_item", copied_file.name());
533+}
534+
535+TEST_F(CopyTest, invalid)
536+{
537+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
538+
539+ Item root;
540+ {
541+ unique_ptr<ItemJob> j(acc_.get("root_id"));
542+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
543+ spy.wait(SIGNAL_WAIT_TIME);
544+ root = j->item();
545+ }
546+
547+ Item child;
548+ unique_ptr<ItemJob> j(child.copy(root, "copied_item"));
549+ EXPECT_FALSE(j->isValid());
550+ EXPECT_EQ(ItemJob::Error, j->status());
551+ EXPECT_EQ(StorageError::LogicError, j->error().type());
552+ EXPECT_EQ("LogicError", j->error().name());
553+ EXPECT_EQ("LogicError: Item::copy(): cannot create job from invalid item", j->error().errorString());
554+
555+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
556+ spy.wait(SIGNAL_WAIT_TIME);
557+ ASSERT_EQ(1, spy.count());
558+ auto arg = spy.takeFirst();
559+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
560+ EXPECT_EQ(ItemJob::Error, status);
561+
562+ EXPECT_FALSE(j->isValid());
563+ EXPECT_EQ(ItemJob::Error, j->status());
564+ EXPECT_EQ(StorageError::LogicError, j->error().type());
565+ EXPECT_EQ("LogicError", j->error().name());
566+ EXPECT_EQ("LogicError: Item::copy(): cannot create job from invalid item", j->error().errorString());
567+}
568+
569+TEST_F(CopyTest, invalid_parent)
570+{
571+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
572+
573+ Item root;
574+ {
575+ unique_ptr<ItemJob> j(acc_.get("root_id"));
576+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
577+ spy.wait(SIGNAL_WAIT_TIME);
578+ root = j->item();
579+ }
580+
581+ Item child;
582+ {
583+ unique_ptr<ItemJob> j(acc_.get("child_id"));
584+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
585+ spy.wait(SIGNAL_WAIT_TIME);
586+ child = j->item();
587+ }
588+
589+ Item invalid_parent;
590+ unique_ptr<ItemJob> j(child.copy(invalid_parent, "copied_item"));
591+ EXPECT_FALSE(j->isValid());
592+ EXPECT_EQ(ItemJob::Error, j->status());
593+ EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
594+ EXPECT_EQ("InvalidArgument: Item::copy(): newParent is invalid", j->error().errorString());
595+
596+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
597+ spy.wait(SIGNAL_WAIT_TIME);
598+ ASSERT_EQ(1, spy.count());
599+ auto arg = spy.takeFirst();
600+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
601+ EXPECT_EQ(ItemJob::Error, status);
602+
603+ EXPECT_FALSE(j->isValid());
604+ EXPECT_EQ(ItemJob::Error, j->status());
605+ EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
606+ EXPECT_EQ("InvalidArgument: Item::copy(): newParent is invalid", j->error().errorString());
607+}
608+
609+TEST_F(CopyTest, empty_name)
610+{
611+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
612+
613+ Item root;
614+ {
615+ unique_ptr<ItemJob> j(acc_.get("root_id"));
616+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
617+ spy.wait(SIGNAL_WAIT_TIME);
618+ root = j->item();
619+ }
620+
621+ Item child;
622+ {
623+ unique_ptr<ItemJob> j(acc_.get("child_id"));
624+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
625+ spy.wait(SIGNAL_WAIT_TIME);
626+ child = j->item();
627+ }
628+
629+ unique_ptr<ItemJob> j(child.copy(root, ""));
630+ EXPECT_FALSE(j->isValid());
631+ EXPECT_EQ(ItemJob::Error, j->status());
632+ EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
633+ EXPECT_EQ("InvalidArgument: Item::copy(): newName cannot be empty", j->error().errorString());
634+
635+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
636+ spy.wait(SIGNAL_WAIT_TIME);
637+ ASSERT_EQ(1, spy.count());
638+ auto arg = spy.takeFirst();
639+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
640+ EXPECT_EQ(ItemJob::Error, status);
641+
642+ EXPECT_FALSE(j->isValid());
643+ EXPECT_EQ(ItemJob::Error, j->status());
644+ EXPECT_EQ(StorageError::InvalidArgument, j->error().type());
645+ EXPECT_EQ("InvalidArgument: Item::copy(): newName cannot be empty", j->error().errorString());
646+}
647+
648+TEST_F(CopyTest, wrong_account)
649+{
650+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
651+
652+ auto test_account = runtime_->make_test_account(service_connection_->baseService(), object_path(), "test_account");
653+
654+ Item root1;
655+ {
656+ unique_ptr<ItemJob> j(test_account.get("root_id"));
657+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
658+ spy.wait(SIGNAL_WAIT_TIME);
659+ root1 = j->item();
660+ EXPECT_TRUE(root1.isValid());
661+ }
662+
663+ Item root2;
664+ {
665+ unique_ptr<ItemJob> j(acc_.get("root_id"));
666+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
667+ spy.wait(SIGNAL_WAIT_TIME);
668+ root2 = j->item();
669+ EXPECT_TRUE(root2.isValid());
670+ }
671+
672+ Item child;
673+ {
674+ unique_ptr<ItemJob> j(acc_.get("child_id"));
675+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
676+ spy.wait(SIGNAL_WAIT_TIME);
677+ child = j->item();
678+ EXPECT_TRUE(child.isValid());
679+ }
680+
681+ unique_ptr<ItemJob> j(child.copy(root1, "copied_Item"));
682+ EXPECT_FALSE(j->isValid());
683+ EXPECT_EQ(ItemJob::Error, j->status());
684+ EXPECT_EQ(StorageError::LogicError, j->error().type());
685+ EXPECT_EQ("LogicError: Item::copy(): source and target must belong to the same account", j->error().errorString());
686+
687+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
688+ spy.wait(SIGNAL_WAIT_TIME);
689+ ASSERT_EQ(1, spy.count());
690+ auto arg = spy.takeFirst();
691+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
692+ EXPECT_EQ(ItemJob::Error, status);
693+
694+ EXPECT_FALSE(j->isValid());
695+ EXPECT_EQ(ItemJob::Error, j->status());
696+ EXPECT_EQ(StorageError::LogicError, j->error().type());
697+ EXPECT_EQ("LogicError: Item::copy(): source and target must belong to the same account", j->error().errorString());
698+}
699+
700+TEST_F(CopyTest, wrong_type)
701+{
702+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
703+
704+ Item root;
705+ {
706+ unique_ptr<ItemJob> j(acc_.get("root_id"));
707+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
708+ spy.wait(SIGNAL_WAIT_TIME);
709+ root = j->item();
710+ }
711+
712+ Item child;
713+ {
714+ unique_ptr<ItemJob> j(acc_.get("child_id"));
715+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
716+ spy.wait(SIGNAL_WAIT_TIME);
717+ child = j->item();
718+ }
719+
720+ unique_ptr<ItemJob> j(child.copy(child, "copied_Item"));
721+ EXPECT_FALSE(j->isValid());
722+ EXPECT_EQ(ItemJob::Error, j->status());
723+ EXPECT_EQ(StorageError::LogicError, j->error().type());
724+ EXPECT_EQ("LogicError: Item::copy(): newParent cannot be a file", j->error().errorString()) << j->error().errorString().toStdString();
725+
726+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
727+ spy.wait(SIGNAL_WAIT_TIME);
728+ ASSERT_EQ(1, spy.count());
729+ auto arg = spy.takeFirst();
730+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
731+ EXPECT_EQ(ItemJob::Error, status);
732+
733+ EXPECT_FALSE(j->isValid());
734+ EXPECT_EQ(ItemJob::Error, j->status());
735+ EXPECT_EQ(StorageError::LogicError, j->error().type());
736+ EXPECT_EQ("LogicError: Item::copy(): newParent cannot be a file", j->error().errorString());
737+}
738+
739+TEST_F(CopyTest, type_mismatch)
740+{
741+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("copy_type_mismatch")));
742+
743+ Item root;
744+ {
745+ unique_ptr<ItemJob> j(acc_.get("root_id"));
746+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
747+ spy.wait(SIGNAL_WAIT_TIME);
748+ root = j->item();
749+ }
750+
751+ Item child;
752+ {
753+ unique_ptr<ItemJob> j(acc_.get("child_id"));
754+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
755+ spy.wait(SIGNAL_WAIT_TIME);
756+ child = j->item();
757+ }
758+
759+ unique_ptr<ItemJob> j(child.copy(root, "copied_Item"));
760+ EXPECT_TRUE(j->isValid());
761+
762+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
763+ spy.wait(SIGNAL_WAIT_TIME);
764+ ASSERT_EQ(1, spy.count());
765+ auto arg = spy.takeFirst();
766+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
767+ EXPECT_EQ(ItemJob::Error, status);
768+
769+ EXPECT_FALSE(j->isValid());
770+ EXPECT_EQ(ItemJob::Error, j->status());
771+ EXPECT_EQ(StorageError::LocalCommsError, j->error().type());
772+ EXPECT_EQ("LocalCommsError: Item::copy(): source and target item type differ", j->error().errorString());
773+}
774+
775+TEST_F(MoveTest, basic)
776+{
777+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
778+
779+ Item root;
780+ {
781+ unique_ptr<ItemJob> j(acc_.get("root_id"));
782+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
783+ spy.wait(SIGNAL_WAIT_TIME);
784+ root = j->item();
785+ }
786+
787+ Item child;
788+ {
789+ unique_ptr<ItemJob> j(acc_.get("child_id"));
790+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
791+ spy.wait(SIGNAL_WAIT_TIME);
792+ child = j->item();
793+ }
794+
795+ unique_ptr<ItemJob> j(child.move(root, "moved_item"));
796+ EXPECT_TRUE(j->isValid());
797+ EXPECT_EQ(ItemJob::Loading, j->status());
798+ EXPECT_EQ(StorageError::NoError, j->error().type());
799+
800+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
801+ spy.wait(SIGNAL_WAIT_TIME);
802+ ASSERT_EQ(1, spy.count());
803+ auto arg = spy.takeFirst();
804+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
805+ EXPECT_EQ(ItemJob::Finished, status);
806+
807+ EXPECT_TRUE(j->isValid());
808+ EXPECT_EQ(ItemJob::Finished, j->status());
809+ EXPECT_EQ(StorageError::NoError, j->error().type());
810+ auto moved_file = j->item();
811+ EXPECT_EQ("child_id", moved_file.itemId());
812+ EXPECT_EQ(root.itemId(), moved_file.parentIds()[0]);
813+ EXPECT_EQ("moved_item", moved_file.name());
814+}
815+
816+TEST_F(MoveTest, invalid)
817+{
818+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
819+
820+ Item root;
821+ {
822+ unique_ptr<ItemJob> j(acc_.get("root_id"));
823+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
824+ spy.wait(SIGNAL_WAIT_TIME);
825+ root = j->item();
826+ }
827+
828+ Item child;
829+ unique_ptr<ItemJob> j(child.move(root, "moved_item"));
830+ EXPECT_FALSE(j->isValid());
831+ EXPECT_EQ(ItemJob::Error, j->status());
832+ EXPECT_EQ(StorageError::LogicError, j->error().type());
833+ EXPECT_EQ("LogicError", j->error().name());
834+ EXPECT_EQ("LogicError: Item::move(): cannot create job from invalid item", j->error().errorString());
835+
836+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
837+ spy.wait(SIGNAL_WAIT_TIME);
838+ ASSERT_EQ(1, spy.count());
839+ auto arg = spy.takeFirst();
840+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
841+ EXPECT_EQ(ItemJob::Error, status);
842+
843+ EXPECT_FALSE(j->isValid());
844+ EXPECT_EQ(ItemJob::Error, j->status());
845+ EXPECT_EQ(StorageError::LogicError, j->error().type());
846+ EXPECT_EQ("LogicError", j->error().name());
847+ EXPECT_EQ("LogicError: Item::move(): cannot create job from invalid item", j->error().errorString());
848+}
849+
850+TEST_F(MoveTest, root_returned)
851+{
852+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("move_returns_root")));
853+
854+ Item root;
855+ {
856+ unique_ptr<ItemJob> j(acc_.get("root_id"));
857+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
858+ spy.wait(SIGNAL_WAIT_TIME);
859+ root = j->item();
860+ }
861+
862+ Item child;
863+ {
864+ unique_ptr<ItemJob> j(acc_.get("child_id"));
865+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
866+ spy.wait(SIGNAL_WAIT_TIME);
867+ child = j->item();
868+ }
869+
870+ unique_ptr<ItemJob> j(child.move(root, "moved_item"));
871+ EXPECT_TRUE(j->isValid());
872+
873+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
874+ spy.wait(SIGNAL_WAIT_TIME);
875+ ASSERT_EQ(1, spy.count());
876+ auto arg = spy.takeFirst();
877+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
878+ EXPECT_EQ(ItemJob::Error, status);
879+
880+ EXPECT_FALSE(j->isValid());
881+ EXPECT_EQ(ItemJob::Error, j->status());
882+ EXPECT_EQ(StorageError::LocalCommsError, j->error().type());
883+ EXPECT_EQ("LocalCommsError", j->error().name());
884+ EXPECT_EQ("LocalCommsError: Item::move(): impossible root item returned by server", j->error().errorString());
885+}
886+
887+TEST_F(MoveTest, type_mismatch)
888+{
889+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("move_type_mismatch")));
890+
891+ Item root;
892+ {
893+ unique_ptr<ItemJob> j(acc_.get("root_id"));
894+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
895+ spy.wait(SIGNAL_WAIT_TIME);
896+ root = j->item();
897+ }
898+
899+ Item child;
900+ {
901+ unique_ptr<ItemJob> j(acc_.get("child_id"));
902+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
903+ spy.wait(SIGNAL_WAIT_TIME);
904+ child = j->item();
905+ }
906+
907+ unique_ptr<ItemJob> j(child.move(root, "moved_Item"));
908+ EXPECT_TRUE(j->isValid());
909+
910+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
911+ spy.wait(SIGNAL_WAIT_TIME);
912+ ASSERT_EQ(1, spy.count());
913+ auto arg = spy.takeFirst();
914+ auto status = qvariant_cast<ItemJob::Status>(arg.at(0));
915+ EXPECT_EQ(ItemJob::Error, status);
916+
917+ EXPECT_FALSE(j->isValid());
918+ EXPECT_EQ(ItemJob::Error, j->status());
919+ EXPECT_EQ(StorageError::LocalCommsError, j->error().type());
920+ EXPECT_EQ("LocalCommsError: Item::move(): source and target item type differ", j->error().errorString());
921+}
922+
923 #if 0
924 TEST_F(RootTest, basic)
925 {

Subscribers

People subscribed via source and target branches

to all changes: