Merge lp:~mvo/unity-scope-click/lp1292645-use-libclick into lp:unity-scope-click/devel

Proposed by Michael Vogt
Status: Rejected
Rejected by: Alejandro J. Cura
Proposed branch: lp:~mvo/unity-scope-click/lp1292645-use-libclick
Merge into: lp:unity-scope-click/devel
Diff against target: 483 lines (+93/-248)
9 files modified
debian/control (+1/-0)
debian/tests/control (+1/-0)
scope/click/CMakeLists.txt (+3/-0)
scope/click/configuration.cpp (+16/-2)
scope/click/configuration.h (+0/-3)
scope/click/interface.cpp (+67/-57)
scope/click/interface.h (+0/-4)
scope/tests/test_configuration.cpp (+4/-44)
scope/tests/test_interface.cpp (+1/-138)
To merge this branch: bzr merge lp:~mvo/unity-scope-click/lp1292645-use-libclick
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) Needs Information
PS Jenkins bot (community) continuous-integration Approve
Michael Vogt (community) Abstain
dobey (community) Needs Fixing
Review via email: mp+220061@code.launchpad.net

Commit message

Use libclick instead of spawning "click {info,list}"

Description of the change

This branch uses libclick to get the data of installed apps instead of doing run_process().

Please let me know how you want the tests. E.g. do you still want to test for the json parsing exception? Can gmock mock external libs and should I do this?

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

Can you please do "bzr commit --fixes=lp:1292645" to link the bug if this branch is fixing it? Thanks.

review: Needs Fixing
266. By Michael Vogt

* add missing --fixes=lp:1292645

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks, I commited the missing --fixes as the r266 to this branch.

review: Needs Resubmitting
Revision history for this message
dobey (dobey) wrote :

Please don't vote "resubmit" on your own MPs. It's not necessary to vote on your own MP (can you please change your vote to "Abstain" instead)? That is not how one resubmits an MP (it's a vote by a reviewer that the submitter should resubmit for whatever provided reason). There's no need to generally resubmit reviews for every change made to satisfy a review request. :)

Revision history for this message
Michael Vogt (mvo) :
review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Hi mvo, thanks for working on this.

We can drop the tests that do the specific things that are now done on libclick, but I'd like to keep at least some of the tests that apply to these functions, so eg, looking at:
http://bazaar.launchpad.net/~mvo/unity-scope-click/lp1292645/revision/223

in that branch I see that we can keep getAvailableFrameworksTwoResults and getAvailableFrameworksNoResults if we can mock the result returned by click_framework_get_frameworks.

But gmock can only mock non-static methods, so the workaround is adding yet another class, like explained here: https://code.google.com/p/googlemock/wiki/FrequentlyAskedQuestions#My_code_calls_a_static/global_function.__Can_I_mock_it?

I started preparing a branch that show how to do this:
https://code.launchpad.net/~alecu/unity-scope-click/lp1292645

That branch is missing a way to create fake Framework instances, because their constructor is private; what should happen is that a new GObject type should be created that has the same "name" property as Framework. Or, perhaps simpler, its constructor should be made public in the vala library. I'm travelling tomorrow to the sprint, so I won't be able to continue working on this for a few days; feel free to take over it, or else I can work on my return.

In any case, I agree that this is a lot of work to test these functions that look so simple, so I'm open to discussing alternative options.

review: Needs Information
Revision history for this message
Thomas Voß (thomas-voss) wrote :

Hey Michael,

thanks for getting this started. Looking at the code, we might want to have a click::Database abstract base-class, with simple structs Manifest and Framework summarizing all the attributes that the scope is interested in. With that, we could have:

namespace click
{
struct Manifest
{
    // Omitting details here.
};

struct Framework
{
    // Omitting details here.
};

class Database
{
public:
    // Omitting boilerplate here

    virtual void for_each_framework(std::function<void(const click::Framework&)> f) = 0;
    virtual void for_each_manifest(std::function<void(const click::Manifest&)> f) = 0;
};
}

We then could think about having a:

namespace libclick
{
class Database : public click::Database
{
};
}

and would still be able to easily create instances of Manifest and Framework without requiring an instance of click::Database.

What do you think?

Revision history for this message
Michael Vogt (mvo) wrote :

This is now superseeded by https://code.launchpad.net/~mvo/unity-scope-click/lp1292645-use-libclick2/+merge/220433 - please either reject or alternatively I can delete the MP (but that will loose the discussion history AIUI that was very helpful).

Unmerged revisions

266. By Michael Vogt

* add missing --fixes=lp:1292645

265. By Michael Vogt

fix typo

264. By Michael Vogt

use libclick instead of run_process("click {info,list}")

263. By Michael Vogt

use libclick instead of using list_folder() to get available frameworks

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2014-05-16 13:09:36 +0000
+++ debian/control 2014-05-19 18:49:23 +0000
@@ -6,6 +6,7 @@
6 dh-translations,6 dh-translations,
7 google-mock,7 google-mock,
8 intltool,8 intltool,
9 libclick-0.4-dev,
9 libglib2.0-dev (>= 2.32),10 libglib2.0-dev (>= 2.32),
10 libjsoncpp-dev,11 libjsoncpp-dev,
11 libubuntu-download-manager-client-dev (>= 0.3+14.10.20140430-0ubuntu1),12 libubuntu-download-manager-client-dev (>= 0.3+14.10.20140430-0ubuntu1),
1213
=== modified file 'debian/tests/control'
--- debian/tests/control 2013-12-17 17:56:49 +0000
+++ debian/tests/control 2014-05-19 18:49:23 +0000
@@ -5,6 +5,7 @@
5 dh-autoreconf,5 dh-autoreconf,
6 gnome-common,6 gnome-common,
7 libaccounts-glib-dev,7 libaccounts-glib-dev,
8 libclick-0.4-dev,
8 libdee-dev (>= 1.2.5),9 libdee-dev (>= 1.2.5),
9 libgee-dev,10 libgee-dev,
10 libglib2.0-dev (>= 2.32),11 libglib2.0-dev (>= 2.32),
1112
=== modified file 'scope/click/CMakeLists.txt'
--- scope/click/CMakeLists.txt 2014-05-13 19:32:29 +0000
+++ scope/click/CMakeLists.txt 2014-05-19 18:49:23 +0000
@@ -2,6 +2,7 @@
2SET (CMAKE_AUTOMOC ON)2SET (CMAKE_AUTOMOC ON)
3find_package (Qt5Core REQUIRED)3find_package (Qt5Core REQUIRED)
4pkg_check_modules(JSON_CPP REQUIRED jsoncpp)4pkg_check_modules(JSON_CPP REQUIRED jsoncpp)
5pkg_check_modules(CLICK REQUIRED click-0.4)
56
6add_definitions(7add_definitions(
7 -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"8 -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"
@@ -30,6 +31,7 @@
30include_directories(31include_directories(
31 ${CMAKE_SOURCE_DIR}/libclickscope32 ${CMAKE_SOURCE_DIR}/libclickscope
32 ${JSON_CPP_INCLUDE_DIRS}33 ${JSON_CPP_INCLUDE_DIRS}
34 ${CLICK_INCLUDE_DIRS}
33)35)
3436
35qt5_use_modules (${SCOPE_LIB_UNVERSIONED} Network)37qt5_use_modules (${SCOPE_LIB_UNVERSIONED} Network)
@@ -42,6 +44,7 @@
42 ${UBUNTUONE_LDFLAGS}44 ${UBUNTUONE_LDFLAGS}
43 ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}45 ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
44 ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}46 ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
47 ${CLICK_LDFLAGS}
45)48)
4649
47install(50install(
4851
=== modified file 'scope/click/configuration.cpp'
--- scope/click/configuration.cpp 2014-05-01 21:04:23 +0000
+++ scope/click/configuration.cpp 2014-05-19 18:49:23 +0000
@@ -27,6 +27,10 @@
27 * files in the program, then also delete it here.27 * files in the program, then also delete it here.
28 */28 */
2929
30#include <glib.h>
31#include <click.h>
32
33
30#include <string>34#include <string>
31#include <vector>35#include <vector>
3236
@@ -57,10 +61,20 @@
5761
58std::vector<std::string> Configuration::get_available_frameworks()62std::vector<std::string> Configuration::get_available_frameworks()
59{63{
64 GList *l = nullptr;
65 GList *frameworks = l = click_framework_get_frameworks();
66
60 std::vector<std::string> result;67 std::vector<std::string> result;
61 for (auto f: list_folder(FRAMEWORKS_FOLDER, FRAMEWORKS_PATTERN)) {68 while (l != nullptr) {
62 result.push_back(f.substr(0, f.size()-FRAMEWORKS_EXTENSION_LENGTH));69 gchar *framework_name = nullptr;
70 GObject *framework = (GObject *)l->data;
71 g_object_get(framework, "name", &framework_name, nullptr);
72 result.push_back(framework_name);
73 l = g_list_next(l);
74 g_free(framework_name);
63 }75 }
76 g_list_free_full(frameworks, g_object_unref);
77
64 return result;78 return result;
65}79}
6680
6781
=== modified file 'scope/click/configuration.h'
--- scope/click/configuration.h 2014-05-01 21:04:23 +0000
+++ scope/click/configuration.h 2014-05-19 18:49:23 +0000
@@ -39,9 +39,6 @@
39class Configuration39class Configuration
40{40{
41public:41public:
42 constexpr static const char* FRAMEWORKS_FOLDER {"/usr/share/click/frameworks/"};
43 constexpr static const char* FRAMEWORKS_PATTERN {"*.framework"};
44 constexpr static const int FRAMEWORKS_EXTENSION_LENGTH = 10; // strlen(".framework")
45 constexpr static const char* LANGUAGE_ENVVAR {"LANGUAGE"};42 constexpr static const char* LANGUAGE_ENVVAR {"LANGUAGE"};
4643
47 virtual std::vector<std::string> get_available_frameworks();44 virtual std::vector<std::string> get_available_frameworks();
4845
=== modified file 'scope/click/interface.cpp'
--- scope/click/interface.cpp 2014-05-13 19:32:29 +0000
+++ scope/click/interface.cpp 2014-05-19 18:49:23 +0000
@@ -27,6 +27,8 @@
27 * files in the program, then also delete it here.27 * files in the program, then also delete it here.
28 */28 */
2929
30#include <click-0.4/click.h>
31
30#include <QDebug>32#include <QDebug>
31#include <QDir>33#include <QDir>
32#include <QProcess>34#include <QProcess>
@@ -323,39 +325,76 @@
323325
324void Interface::get_manifests(std::function<void(ManifestList, ManifestError)> callback)326void Interface::get_manifests(std::function<void(ManifestList, ManifestError)> callback)
325{327{
326 std::string command = "click list --manifest";328 ClickDB *db = click_db_new();
327 qDebug() << "Running command:" << command.c_str();329 GError *error = NULL;
328 run_process(command, [callback](int code, const std::string& stdout_data, const std::string&) {330 char *c_output = NULL;
329 if (code == 0) {331 std::string manifest_data;
330 try {332
331 ManifestList manifests = manifest_list_from_json(stdout_data);333 c_output = click_db_get_manifests_as_string(db, false, &error);
332 callback(manifests, ManifestError::NoError);334 g_object_unref(db);
333 } catch (...) {335 if (error != NULL)
334 callback(ManifestList(), ManifestError::ParseError);336 {
335 }337 g_error_free(error);
336 } else {338 // FIXME: pass the GError details on
337 callback(ManifestList(), ManifestError::CallError);339 callback(ManifestList(), ManifestError::CallError);
338 }340 }
339 });341 manifest_data = c_output;
342 g_free(c_output);
343
344 try {
345 ManifestList manifests = manifest_list_from_json(manifest_data);
346 callback(manifests, ManifestError::NoError);
347 } catch (...) {
348 callback(ManifestList(), ManifestError::ParseError);
349 }
340}350}
341351
342void Interface::get_manifest_for_app(const std::string &app_id,352void Interface::get_manifest_for_app(const std::string &app_id,
343 std::function<void(Manifest, ManifestError)> callback)353 std::function<void(Manifest, ManifestError)> callback)
344{354{
345 std::string command = "click info " + app_id;355 GError *error = NULL;
346 qDebug() << "Running command:" << command.c_str();356 ClickDB *db = NULL;
347 run_process(command, [callback](int code, const std::string& stdout_data, const std::string&) {357 ClickUser *user = NULL;
348 if (code == 0) {358 char *c_output = NULL;
349 try {359
350 Manifest manifest = manifest_from_json(stdout_data);360 db = click_db_new();
351 callback(manifest, ManifestError::NoError);361 click_db_read(db, NULL, &error);
352 } catch (...) {362 if (error != NULL) {
353 callback(Manifest(), ManifestError::ParseError);363 g_error_free (error);
354 }364 g_object_unref(db);
355 } else {365 // FIXME: pass error data along
356 callback(Manifest(), ManifestError::CallError);366 callback(Manifest(), ManifestError::CallError);
357 }367 }
358 });368
369 user = click_user_new_for_user(db, NULL, &error);
370 if (error != NULL) {
371 g_error_free (error);
372 g_object_unref(db);
373 // FIXME: pass error data along
374 callback(Manifest(), ManifestError::CallError);
375 }
376 if (click_user_has_package_name(user, app_id.c_str()) == false) {
377 g_error_free (error);
378 g_object_unref(db);
379 g_object_unref(user);
380 // FIXME: hm, not a call error as such really more a NotInstalledError ?
381 callback(Manifest(), ManifestError::CallError);
382 }
383
384 c_output = click_user_get_manifest_as_string (user, app_id.c_str(), &error);
385 std::string json_output = c_output;
386
387 g_free(c_output);
388 g_object_unref(db);
389 g_object_unref(user);
390
391 try {
392 Manifest manifest = manifest_from_json(json_output);
393 callback(manifest, ManifestError::NoError);
394 } catch (...) {
395 callback(Manifest(), ManifestError::ParseError);
396 }
397
359}398}
360399
361void Interface::get_dotdesktop_filename(const std::string &app_id,400void Interface::get_dotdesktop_filename(const std::string &app_id,
@@ -380,33 +419,4 @@
380 });419 });
381}420}
382421
383void Interface::run_process(const std::string& command,
384 std::function<void(int code,
385 const std::string& stdout_data,
386 const std::string& stderr_data)> callback)
387{
388 QSharedPointer<QProcess> process(new QProcess());
389 typedef void(QProcess::*QProcessFinished)(int, QProcess::ExitStatus);
390 typedef void(QProcess::*QProcessError)(QProcess::ProcessError);
391 QObject::connect(process.data(),
392 static_cast<QProcessFinished>(&QProcess::finished),
393 [callback, process](int code, QProcess::ExitStatus /*status*/) {
394 qDebug() << "command finished with exit code:" << code;
395 auto data = process.data()->readAllStandardOutput().data();
396 auto errors = process.data()->readAllStandardError().data();
397 callback(code, data, errors);
398 } );
399
400 QObject::connect(process.data(),
401 static_cast<QProcessError>(&QProcess::error),
402 [callback, process](QProcess::ProcessError error) {
403 qCritical() << "error running command:" << error;
404 auto data = process.data()->readAllStandardOutput().data();
405 auto errors = process.data()->readAllStandardError().data();
406 callback(process.data()->exitCode(), data, errors);
407 } );
408
409 process->start(command.c_str());
410}
411
412} // namespace click422} // namespace click
413423
=== modified file 'scope/click/interface.h'
--- scope/click/interface.h 2014-05-06 19:17:30 +0000
+++ scope/click/interface.h 2014-05-19 18:49:23 +0000
@@ -95,10 +95,6 @@
95 virtual bool is_visible_app(const unity::util::IniParser& keyFile);95 virtual bool is_visible_app(const unity::util::IniParser& keyFile);
96 virtual bool show_desktop_apps();96 virtual bool show_desktop_apps();
9797
98 virtual void run_process(const std::string& command,
99 std::function<void(int code,
100 const std::string& stdout_data,
101 const std::string& stderr_data)> callback);
102private:98private:
103 QSharedPointer<KeyFileLocator> keyFileLocator;99 QSharedPointer<KeyFileLocator> keyFileLocator;
104};100};
105101
=== modified file 'scope/tests/test_configuration.cpp'
--- scope/tests/test_configuration.cpp 2014-05-01 21:04:23 +0000
+++ scope/tests/test_configuration.cpp 2014-05-19 18:49:23 +0000
@@ -46,50 +46,10 @@
4646
47}47}
4848
4949TEST(Configuration, getAvailableFrameworksSmokeTest)
50TEST(Configuration, getAvailableFrameworksUsesRightFolder)50{
51{51 FakeConfiguration locator;
52 using namespace ::testing;52 std::vector<std::string> frameworks = locator.get_available_frameworks();
53 FakeConfiguration locator;
54 EXPECT_CALL(locator, list_folder(Configuration::FRAMEWORKS_FOLDER, _))
55 .Times(1).WillOnce(Return(std::vector<std::string>()));
56 locator.get_available_frameworks();
57}
58
59TEST(Configuration, getAvailableFrameworksUsesRightPattern)
60{
61 using namespace ::testing;
62 FakeConfiguration locator;
63 EXPECT_CALL(locator, list_folder(_, Configuration::FRAMEWORKS_PATTERN))
64 .Times(1).WillOnce(Return(std::vector<std::string>()));
65 locator.get_available_frameworks();
66}
67
68TEST(Configuration, getAvailableFrameworksTwoResults)
69{
70 using namespace ::testing;
71
72 FakeConfiguration locator;
73 std::vector<std::string> response = {"abc.framework", "def.framework"};
74 EXPECT_CALL(locator, list_folder(_, _))
75 .Times(1)
76 .WillOnce(Return(response));
77 auto frameworks = locator.get_available_frameworks();
78 std::vector<std::string> expected = {"abc", "def"};
79 EXPECT_EQ(expected, frameworks);
80}
81
82TEST(Configuration, getAvailableFrameworksNoResults)
83{
84 using namespace ::testing;
85
86 FakeConfiguration locator;
87 std::vector<std::string> response = {};
88 EXPECT_CALL(locator, list_folder(_, _))
89 .Times(1)
90 .WillOnce(Return(response));
91 auto frameworks = locator.get_available_frameworks();
92 EXPECT_EQ(0, frameworks.size());
93}53}
9454
95TEST(Configuration, getLanguageCorrect)55TEST(Configuration, getLanguageCorrect)
9656
=== modified file 'scope/tests/test_interface.cpp'
--- scope/tests/test_interface.cpp 2014-05-06 19:17:30 +0000
+++ scope/tests/test_interface.cpp 2014-05-19 18:49:23 +0000
@@ -130,7 +130,6 @@
130 FakeClickInterface() {}130 FakeClickInterface() {}
131131
132 MOCK_METHOD0(show_desktop_apps, bool());132 MOCK_METHOD0(show_desktop_apps, bool());
133 MOCK_METHOD2(run_process, void(const std::string&, std::function<void(int, const std::string&, const std::string&)>));
134};133};
135134
136TEST(ClickInterface, testIsNonClickAppFalse)135TEST(ClickInterface, testIsNonClickAppFalse)
@@ -320,140 +319,4 @@
320 EXPECT_FALSE(iface.show_desktop_apps());319 EXPECT_FALSE(iface.show_desktop_apps());
321}320}
322321
323TEST(ClickInterface, testGetManifestForAppCorrectCommand)322// FIXME: re-add tests by mocking libclick
324{
325 FakeClickInterface iface;
326 std::string command = "click info " + FAKE_PACKAGENAME;
327 EXPECT_CALL(iface, run_process(command, _)).
328 Times(1);
329 iface.get_manifest_for_app(FAKE_PACKAGENAME, [](Manifest, ManifestError){});
330}
331
332TEST_F(ClickInterfaceTest, testGetManifestForAppParseError)
333{
334 FakeClickInterface iface;
335 EXPECT_CALL(iface, run_process(_, _)).
336 Times(1).
337 WillOnce(Invoke([&](const std::string&,
338 std::function<void(int, const std::string&,
339 const std::string&)> callback){
340 callback(0, "INVALID JSON", "");
341 }));
342 EXPECT_CALL(*this, manifest_callback(_, ManifestError::ParseError));
343 iface.get_manifest_for_app(FAKE_PACKAGENAME, [this](Manifest manifest,
344 ManifestError error){
345 manifest_callback(manifest, error);
346 });
347}
348
349TEST_F(ClickInterfaceTest, testGetManifestForAppCommandFailed)
350{
351 FakeClickInterface iface;
352 EXPECT_CALL(iface, run_process(_, _)).
353 Times(1).
354 WillOnce(Invoke([&](const std::string&,
355 std::function<void(int, const std::string&,
356 const std::string&)> callback){
357 callback(-1, "", "CRITICAL: FAIL");
358 }));
359 EXPECT_CALL(*this, manifest_callback(_, ManifestError::CallError));
360 iface.get_manifest_for_app(FAKE_PACKAGENAME, [this](Manifest manifest,
361 ManifestError error){
362 manifest_callback(manifest, error);
363 });
364}
365
366TEST_F(ClickInterfaceTest, testGetManifestForAppIsRemovable)
367{
368 FakeClickInterface iface;
369 EXPECT_CALL(iface, run_process(_, _)).
370 Times(1).
371 WillOnce(Invoke([&](const std::string&,
372 std::function<void(int, const std::string&,
373 const std::string&)> callback){
374 callback(0, FAKE_JSON_MANIFEST_REMOVABLE, "");
375 }));
376 iface.get_manifest_for_app(FAKE_PACKAGENAME, [](Manifest manifest,
377 ManifestError error){
378 ASSERT_TRUE(error == ManifestError::NoError);
379 ASSERT_TRUE(manifest.removable);
380 });
381}
382
383TEST_F(ClickInterfaceTest, testGetManifestForAppIsNotRemovable)
384{
385 FakeClickInterface iface;
386 EXPECT_CALL(iface, run_process(_, _)).
387 Times(1).
388 WillOnce(Invoke([&](const std::string&,
389 std::function<void(int, const std::string&,
390 const std::string&)> callback){
391 callback(0, FAKE_JSON_MANIFEST_NONREMOVABLE, "");
392 }));
393 iface.get_manifest_for_app(FAKE_PACKAGENAME, [](Manifest manifest,
394 ManifestError error){
395 ASSERT_TRUE(error == ManifestError::NoError);
396 ASSERT_FALSE(manifest.removable);
397 });
398}
399
400TEST(ClickInterface, testGetManifestsCorrectCommand)
401{
402 FakeClickInterface iface;
403 std::string command = "click list --manifest";
404 EXPECT_CALL(iface, run_process(command, _)).
405 Times(1);
406 iface.get_manifests([](ManifestList, ManifestError){});
407}
408
409TEST_F(ClickInterfaceTest, testGetManifestsParseError)
410{
411 FakeClickInterface iface;
412 EXPECT_CALL(iface, run_process(_, _)).
413 Times(1).
414 WillOnce(Invoke([&](const std::string&,
415 std::function<void(int, const std::string&,
416 const std::string&)> callback){
417 callback(0, "INVALID JSON", "");
418 }));
419 EXPECT_CALL(*this, manifests_callback(_, ManifestError::ParseError));
420 iface.get_manifests([this](ManifestList manifests, ManifestError error){
421 manifests_callback(manifests, error);
422 });
423}
424
425TEST_F(ClickInterfaceTest, testGetManifestsCommandFailed)
426{
427 FakeClickInterface iface;
428 EXPECT_CALL(iface, run_process(_, _)).
429 Times(1).
430 WillOnce(Invoke([&](const std::string&,
431 std::function<void(int, const std::string&,
432 const std::string&)> callback){
433 callback(-1, "", "CRITICAL: FAIL");
434 }));
435 EXPECT_CALL(*this, manifests_callback(_, ManifestError::CallError));
436 iface.get_manifests([this](ManifestList manifests, ManifestError error){
437 manifests_callback(manifests, error);
438 });
439}
440
441TEST_F(ClickInterfaceTest, testGetManifestsParsed)
442{
443 FakeClickInterface iface;
444 std::string expected_str = "[" + FAKE_JSON_MANIFEST_NONREMOVABLE + "," +
445 FAKE_JSON_MANIFEST_REMOVABLE + "]";
446 ManifestList expected = manifest_list_from_json(expected_str);
447
448 EXPECT_CALL(iface, run_process(_, _)).
449 Times(1).
450 WillOnce(Invoke([&](const std::string&,
451 std::function<void(int, const std::string&,
452 const std::string&)> callback){
453 callback(0, expected_str, "");
454 }));
455 iface.get_manifests([expected](ManifestList manifests, ManifestError error){
456 ASSERT_TRUE(error == ManifestError::NoError);
457 ASSERT_TRUE(manifests.size() == expected.size());
458 });
459}

Subscribers

People subscribed via source and target branches

to all changes: