./ 0000755 0000156 0000165 00000000000 12676763577 011127 5 ustar jenkins jenkins ./cmake/ 0000755 0000156 0000165 00000000000 12676763577 012207 5 ustar jenkins jenkins ./cmake/UseGSettings.cmake 0000644 0000156 0000165 00000003715 12676763577 015603 0 ustar jenkins jenkins # GSettings.cmake, CMake macros written for Marlin, feel free to re-use them.
option (GSETTINGS_LOCALINSTALL "Install GSettings Schemas locally instead of to the GLib prefix" ${LOCAL_INSTALL})
option (GSETTINGS_COMPILE "Compile GSettings Schemas after installation" ${GSETTINGS_LOCALINSTALL})
if(GSETTINGS_LOCALINSTALL)
message(STATUS "GSettings schemas will be installed locally.")
endif()
if(GSETTINGS_COMPILE)
message(STATUS "GSettings shemas will be compiled.")
endif()
macro(add_schema SCHEMA_NAME)
set(PKG_CONFIG_EXECUTABLE pkg-config)
# Have an option to not install the schema into where GLib is
if (GSETTINGS_LOCALINSTALL)
SET (GSETTINGS_DIR "${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas/")
else (GSETTINGS_LOCALINSTALL)
execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} glib-2.0 --variable prefix OUTPUT_VARIABLE _glib_prefix OUTPUT_STRIP_TRAILING_WHITESPACE)
SET (GSETTINGS_DIR "${_glib_prefix}/share/glib-2.0/schemas/")
endif (GSETTINGS_LOCALINSTALL)
# Run the validator and error if it fails
execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas OUTPUT_VARIABLE _glib_comple_schemas OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND ${_glib_comple_schemas} --dry-run --schema-file=${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME} ERROR_VARIABLE _schemas_invalid OUTPUT_STRIP_TRAILING_WHITESPACE)
if (_schemas_invalid)
message (SEND_ERROR "Schema validation error: ${_schemas_invalid}")
endif (_schemas_invalid)
# Actually install and recomple schemas
message (STATUS "GSettings schemas will be installed into ${GSETTINGS_DIR}")
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME} DESTINATION ${GSETTINGS_DIR} OPTIONAL)
if (GSETTINGS_COMPILE)
install (CODE "message (STATUS \"Compiling GSettings schemas\")")
install (CODE "execute_process (COMMAND ${_glib_comple_schemas} ${GSETTINGS_DIR})")
endif ()
endmacro()
./scope/ 0000755 0000156 0000165 00000000000 12676763577 012240 5 ustar jenkins jenkins ./scope/tests/ 0000755 0000156 0000165 00000000000 12676763577 013402 5 ustar jenkins jenkins ./scope/tests/fake_launcher/ 0000755 0000156 0000165 00000000000 12676763577 016171 5 ustar jenkins jenkins ./scope/tests/fake_launcher/fake_launcher.h 0000644 0000156 0000165 00000007074 12676763577 021141 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#ifndef _FAKE_LAUNCHER_H_
#define _FAKE_LAUNCHER_H_
#include
#include
#include
#include
#include
class FakeIcon : public QObject {
Q_OBJECT
public:
explicit FakeIcon(QString title, QString icon_url, QObject *parent=0)
: QObject(parent), title(title), icon_url(icon_url)
{
}
void downloadFound(Download& download);
void complete(QString app_id);
private slots:
void handleProgress(qulonglong transferred, qulonglong total);
void handleDownloadError(Error* error);
private:
Download* download;
QString title;
QString icon_url;
void failure(QString message);
};
class FakeLauncher : public QObject {
Q_OBJECT
public:
explicit FakeLauncher(QObject *parent=0) : QObject(parent)
{
manager = Ubuntu::DownloadManager::Manager::createSessionManager();
connect(manager, SIGNAL(downloadsWithMetadataFound(QString,QString,DownloadsList*)),
this, SLOT(handleDownloadsFound(QString,QString,DownloadsList*)));
}
public slots:
void startInstallation(QString title, QString icon_url, QString package_name);
void completeInstallation(QString package_name, QString app_id);
private slots:
void handleDownloadsFound(const QString& key, const QString& value, DownloadsList* downloads);
signals:
private:
Ubuntu::DownloadManager::Manager* manager;
QMap installations;
};
class FakeLauncherAdaptor : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", LAUNCHER_INTERFACE)
private:
FakeLauncher *_launcher;
public:
FakeLauncherAdaptor(FakeLauncher *launcher) : QDBusAbstractAdaptor(launcher), _launcher(launcher)
{
}
public slots:
Q_NOREPLY void startInstallation(QString title, QString icon_url, QString package_name)
{
_launcher->startInstallation(title, icon_url, package_name);
}
Q_NOREPLY void completeInstallation(QString package_name, QString app_id)
{
_launcher->completeInstallation(package_name, app_id);
}
};
#endif /* _FAKE_LAUNCHER_H_ */
./scope/tests/fake_launcher/fake_launcher.cpp 0000644 0000156 0000165 00000007747 12676763577 021503 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void FakeLauncher::startInstallation(QString title, QString icon_url, QString package_name)
{
qDebug() << "startInstallation" << title << icon_url << package_name;
installations.insert(package_name, new FakeIcon(title, icon_url, this));
manager->getAllDownloadsWithMetadata("package_name", package_name);
}
void FakeLauncher::handleDownloadsFound(const QString& key, const QString& value, DownloadsList *download_list)
{
Q_UNUSED(key)
Q_UNUSED(value)
foreach (const QSharedPointer download, download_list->downloads()) {
QString package_name{download->metadata()["package_name"].toString()};
qDebug() << "download found for" << package_name;
installations[package_name]->downloadFound(*download);
}
}
void FakeLauncher::completeInstallation(QString package_name, QString app_id)
{
qDebug() << "completeInstallation" << package_name << app_id;
installations[package_name]->complete(app_id);
}
void FakeIcon::downloadFound(Download& download)
{
connect(&download, SIGNAL(progress(qulonglong,qulonglong)), this, SLOT(handleProgress(qulonglong,qulonglong)));
connect(&download, SIGNAL(error(Error*)), this, SLOT(handleDownloadError(Error*)));
qDebug() << title << "starting installation";
// TODO: add icon to the launcher
}
void FakeIcon::handleProgress(qulonglong transferred, qulonglong total)
{
qDebug() << title << "download progress" << double(transferred)/total*80;
// TODO: update progress bar
}
void FakeIcon::handleDownloadError(Error *error)
{
failure(error->errorString());
}
void FakeIcon::failure(QString message)
{
qDebug() << title << "installation failed" << message;
// TODO: remove icon from the launcher
}
void FakeIcon::complete(QString app_id)
{
if (app_id.isEmpty()) {
failure("Failed to install");
} else {
qDebug() << title << "installation completed" << app_id;
// TODO: update icon with proper app_id
}
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
FakeLauncher launcher;
new FakeLauncherAdaptor(&launcher);
qDebug() << "starting";
auto bus = QDBusConnection::sessionBus();
bus.registerObject(LAUNCHER_OBJECT_PATH, &launcher);
bus.registerService(LAUNCHER_BUSNAME);
return app.exec();
}
./scope/tests/fake_launcher/CMakeLists.txt 0000644 0000156 0000165 00000000401 12676763577 020724 0 ustar jenkins jenkins set(FAKE_LAUNCHER_TARGET fake_launcher)
include_directories (
${CMAKE_SOURCE_DIR}/scope/click
)
add_executable (${FAKE_LAUNCHER_TARGET}
fake_launcher.cpp
fake_launcher.h
)
target_link_libraries (${FAKE_LAUNCHER_TARGET}
${STORE_LIB_UNVERSIONED}
)
./scope/tests/test_apps_query.cpp 0000644 0000156 0000165 00000034772 12676763577 017352 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "test_helpers.h"
using namespace click::test::helpers;
using namespace ::testing;
class ResultPusherTest : public ::testing::Test
{
protected:
scopes::SearchReplyProxy reply;
public:
ResultPusherTest()
{
reply.reset(new scopes::testing::MockSearchReply());
}
};
class MockClickInterface : public click::Interface
{
public:
MockClickInterface() = default;
MOCK_METHOD4(find_installed_apps, std::vector(const std::string&, const std::vector&, const std::string&, const std::shared_ptr&));
};
class MockAppsQuery : public click::apps::Query
{
private:
std::shared_ptr click_iface;
public:
MockAppsQuery(unity::scopes::CannedQuery const& query, std::shared_ptr depts_db, scopes::SearchMetadata const& metadata,
const std::shared_ptr& click_iface)
: click::apps::Query(query, depts_db, metadata),
click_iface(click_iface)
{
}
click::Interface& clickInterfaceInstance() override
{
return *click_iface;
}
};
MATCHER_P(HasApplicationTitle, n, "") { return arg["title"].get_string() == n; }
TEST_F(ResultPusherTest, testPushTopAndLocalResults)
{
std::string categoryTemplate("{}");
std::vector apps {
{"app1", "App1", 0.0f, "icon", "url", "", "sshot", ""},
{"app2", "App2", 0.0f, "icon", "url", "", "sshot", ""},
{"app3", "App3", 0.0f, "icon", "url", "", "sshot", ""},
{"", "App4", 0.0f, "icon", "application:///app4.desktop", "", "sshot", ""} // a non-click app
};
click::apps::ResultPusher pusher(reply, {"app2_fooappname", "app4"});
auto mockreply = (scopes::testing::MockSearchReply*)reply.get();
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(*mockreply, register_category(_, _, _, _)).WillRepeatedly(Return(ptrCat));
EXPECT_CALL(*mockreply, push(Matcher(HasApplicationTitle(std::string("App2")))));
EXPECT_CALL(*mockreply, push(Matcher(HasApplicationTitle(std::string("App4")))));
EXPECT_CALL(*mockreply, push(Matcher(HasApplicationTitle(std::string("App1")))));
EXPECT_CALL(*mockreply, push(Matcher(HasApplicationTitle(std::string("App3")))));
pusher.push_top_results(apps, categoryTemplate);
pusher.push_local_results(apps, categoryTemplate, true);
}
MATCHER_P(ResultUriMatchesCannedQuery, q, "") {
auto const query = unity::scopes::CannedQuery::from_uri(arg.uri());
return query.scope_id() == q.scope_id()
&& query.query_string() == q.query_string()
&& query.department_id() == q.department_id();
}
MATCHER_P(CategoryTitleContains, s, "") { return arg.find(s) != std::string::npos; }
TEST(Query, testUbuntuStoreFakeResult)
{
const scopes::SearchMetadata metadata("en_EN", "phone");
const unity::scopes::CannedQuery query("foo.scope", "FooBar", "");
const unity::scopes::CannedQuery query2("foo.scope", "Metallica", "");
click::apps::Query q(query, nullptr, metadata);
click::apps::Query q2(query2, nullptr, metadata);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
const unity::scopes::CannedQuery target_query("com.canonical.scopes.clickstore", "FooBar", "");
EXPECT_CALL(mock_reply, register_category("store", CategoryTitleContains("FooBar"), _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, push(Matcher(ResultUriMatchesCannedQuery(target_query))));
scopes::testing::MockSearchReply mock_reply2;
scopes::SearchReplyProxy reply2(&mock_reply2, [](unity::scopes::SearchReply*){});
const unity::scopes::CannedQuery target_query2("com.canonical.scopes.clickstore", "Metallica", "");
EXPECT_CALL(mock_reply2, register_category("store", CategoryTitleContains("Metallica"), _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply2, push(Matcher(ResultUriMatchesCannedQuery(target_query2))));
q.add_fake_store_app(reply);
q2.add_fake_store_app(reply2);
}
TEST(Query, testUbuntuStoreFakeResultWithDepartment)
{
const scopes::SearchMetadata metadata("en_EN", "phone");
const unity::scopes::CannedQuery query("foo.scope", "", "music-department");
click::apps::Query q(query, nullptr, metadata);
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
const unity::scopes::CannedQuery target_query("com.canonical.scopes.clickstore", "", "music-department");
EXPECT_CALL(mock_reply, register_category("store", _, _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, push(Matcher(ResultUriMatchesCannedQuery(target_query))));
q.add_fake_store_app(reply);
}
class DepartmentsTest : public ::testing::Test {
protected:
virtual void SetUp() override
{
ASSERT_EQ(setenv("GSETTINGS_SCHEMA_DIR", TEST_SCHEMA_DIR, 1), 0);
ASSERT_EQ(setenv("GSETTINGS_BACKEND", "memory", 1), 0);
std::cerr << "SCHEMA dir: " << TEST_SCHEMA_DIR << std::endl;
}
virtual void TearDown() override
{
ASSERT_EQ(unsetenv("GSETTINGS_BACKEND"), 0);
ASSERT_EQ(unsetenv("GSETTINGS_SCHEMA_DIR"), 0);
}
const std::vector installed_apps = {
{"app1", "App1", 0.0f, "icon", "url", "descr", "scrshot", "", "games-rpg"},
{"app2", "App2", 0.0f, "icon", "url", "descr", "scrshot", "", "video"}
};
const scopes::SearchMetadata metadata{"en_EN", "phone"};
const scopes::CategoryRenderer renderer{"{}"};
const std::list expected_locales {"en_EN", "en_US"};
};
TEST_F(DepartmentsTest, testRootDepartment)
{
auto clickif = std::make_shared();
auto ptrCat = std::make_shared("id", "", "", renderer);
auto depts_db = std::make_shared(":memory:", true);
// query for root of the departments tree
{
const unity::scopes::CannedQuery query("foo.scope", "", "");
MockAppsQuery q(query, depts_db, metadata, clickif);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
// no apps in 'books' department, thus excluded
std::list expected_departments({{"", "games", "video"}});
EXPECT_CALL(*clickif, find_installed_apps(_, _, _, _)).WillOnce(Return(installed_apps));
EXPECT_CALL(mock_reply, register_category("predefined", _, _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_category("local", StrNe(""), _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_category("store", _, _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_departments(MatchesDepartments(expected_departments)));
EXPECT_CALL(mock_reply, push(Matcher(_))).Times(3).WillRepeatedly(Return(true));
ON_CALL(*depts_db, is_descendant_of_department(_, _)).WillByDefault(Return(false));
ON_CALL(*depts_db, is_descendant_of_department("games", "")).WillByDefault(Return(true));
ON_CALL(*depts_db, is_descendant_of_department("games-rpg", "games")).WillByDefault(Return(true));
ON_CALL(*depts_db, is_descendant_of_department("books", "")).WillByDefault(Return(true));
ON_CALL(*depts_db, is_descendant_of_department("video", "")).WillByDefault(Return(true));
EXPECT_CALL(*depts_db, get_department_name("games", expected_locales)).WillOnce(Return("Games"));
EXPECT_CALL(*depts_db, get_department_name("video", expected_locales)).WillOnce(Return("Video"));
EXPECT_CALL(*depts_db, is_empty("games")).WillRepeatedly(Return(false));
EXPECT_CALL(*depts_db, is_empty("video")).WillRepeatedly(Return(false));
EXPECT_CALL(*depts_db, is_empty("books")).WillRepeatedly(Return(false));
EXPECT_CALL(*depts_db, is_descendant_of_department(_, _)).Times(AnyNumber());
EXPECT_CALL(*depts_db, get_children_departments("")).WillOnce(Return(
std::list({
{"video", true},
{"books", true},
{"games", true}
}))
);
q.run(reply);
}
}
TEST_F(DepartmentsTest, testLeafDepartment)
{
auto clickif = std::make_shared();
auto ptrCat = std::make_shared("id", "", "", renderer);
auto depts_db = std::make_shared(":memory:", true);
// query for a leaf department
{
const unity::scopes::CannedQuery query("foo.scope", "", "games");
MockAppsQuery q(query, depts_db, metadata, clickif);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
std::list expected_departments({"", "games"});
EXPECT_CALL(*clickif, find_installed_apps(_, _, _, _)).WillOnce(Return(installed_apps));
EXPECT_CALL(mock_reply, register_category("local", StrEq(""), _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_category("store", _, _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_departments(MatchesDepartments(expected_departments)));
EXPECT_CALL(mock_reply, push(Matcher(_))).Times(3).WillRepeatedly(Return(true));
EXPECT_CALL(*depts_db, get_parent_department_id("games")).WillOnce(Return(""));
EXPECT_CALL(*depts_db, get_department_name("games", expected_locales)).WillOnce(Return("Games"));
EXPECT_CALL(*depts_db, get_children_departments("games")).WillOnce(Return(
std::list({})
));
q.run(reply);
}
}
TEST_F(DepartmentsTest, testNoDepartmentSearch)
{
auto clickif = std::make_shared();
auto ptrCat = std::make_shared("id", "", "", renderer);
auto depts_db = std::make_shared(":memory:", true);
// query for department-less search
{
const unity::scopes::CannedQuery query("foo.scope", "App", "");
MockAppsQuery q(query, depts_db, metadata, clickif);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(*clickif, find_installed_apps(_, _, _, _)).WillOnce(Return(installed_apps));
EXPECT_CALL(mock_reply, register_category("local", StrEq(""), _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_category("store", _, _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, push(Matcher(_))).Times(3).WillRepeatedly(Return(true));
q.run(reply);
}
}
TEST_F(DepartmentsTest, testSearchInDepartment)
{
auto clickif = std::make_shared();
auto ptrCat = std::make_shared("id", "", "", renderer);
auto depts_db = std::make_shared(":memory:", true);
// query for a leaf department
{
const unity::scopes::CannedQuery query("foo.scope", "Fooo", "games");
MockAppsQuery q(query, depts_db, metadata, clickif);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
std::list expected_departments({"", "games"});
EXPECT_CALL(*clickif, find_installed_apps("Fooo", _, "games", _)).WillOnce(Return(installed_apps));
EXPECT_CALL(mock_reply, register_category("local", StrEq(""), _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(mock_reply, register_category("store", _, _, _)).WillOnce(Return(ptrCat));
EXPECT_CALL(*depts_db, get_department_name("games", expected_locales)).WillOnce(Return("Games"));
EXPECT_CALL(*depts_db, get_children_departments("games")).WillOnce(Return(
std::list({})
));
EXPECT_CALL(mock_reply, register_departments(MatchesDepartments(expected_departments)));
EXPECT_CALL(mock_reply, push(Matcher(_))).Times(3).WillRepeatedly(Return(true));
q.run(reply);
}
}
./scope/tests/test_runner.h 0000644 0000156 0000165 00000006445 12676763577 016134 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#ifndef TEST_RUNNER_H
#define TEST_RUNNER_H
#include
#include
#include
#include
#include
class TestRunner {
public:
static TestRunner& Instance() {
static TestRunner instance;
return instance;
}
template
char RegisterTest(char* name) {
if(!_tests.contains(name)) {
QSharedPointer test(new T());
_tests.insert(name, QSharedPointer(test));
}
return char(1);
}
int RunAll(int argc, char *argv[]) {
// provide command line to run a single test case
QCoreApplication* app = QCoreApplication::instance();
QStringList args = app->arguments();
if (args.contains("-testcase")) {
int index = args.indexOf("-testcase");
if (args.count() > index + 1) {
QString testcase = args[index + 1];
if (_tests.contains(testcase)) {
args.removeAt(index + 1);
args.removeAt(index);
return QTest::qExec(_tests[testcase].data(), args);
} else {
return -1;
}
} else {
return -1;
}
} else {
int errorCode = 0;
foreach (QString const &testName, _tests.keys()) {
errorCode |= QTest::qExec(_tests[testName].data(), argc, argv);
std::cout << std::endl;
}
return errorCode;
}
}
private:
QMap > _tests;
};
// Use this macro after your test declaration
#define DECLARE_TEST(className)\
static char test_##className = TestRunner::Instance().RegisterTest(const_cast(#className));
// Use this macro to execute all tests
#define RUN_ALL_QTESTS(argc, argv)\
TestRunner::Instance().RunAll(argc, argv);
#endif // TEST_RUNNER_H
./scope/tests/test_store_scope.cpp 0000644 0000156 0000165 00000017125 12676763577 017500 0 ustar jenkins jenkins /*
* Copyright (C) 2014-2015 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include
#include
#include
#include
using namespace ::testing;
class StoreScopeTest : public Test {
protected:
const std::string FAKE_SHA512 = "FAKE_SHA512";
click::Scope scope;
unity::scopes::testing::Result result;
unity::scopes::ActionMetadata metadata;
unity::scopes::VariantMap metadict;
public:
StoreScopeTest() : metadata("en_EN", "phone") {
metadict["download_url"] = "fake_download_url";
metadict["download_sha512"] = FAKE_SHA512;
metadict["rating"] = unity::scopes::Variant(4.0f);
metadict["review"] = "This is a review.";
metadata.set_scope_data(unity::scopes::Variant(metadict));
}
};
TEST_F(StoreScopeTest, testPurchaseCompletedPassesHash)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
"purchaseCompleted");
auto response = activation->activate();
EXPECT_EQ(FAKE_SHA512, response.scope_data().get_dict()["download_sha512"].get_string());
EXPECT_TRUE(response.scope_data().get_dict()["purchased"].get_bool());
}
TEST_F(StoreScopeTest, testPurchaseError)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
"purchaseError");
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::DOWNLOAD_FAILED].get_bool());
}
TEST_F(StoreScopeTest, testInstallClickPassesHash)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::INSTALL_CLICK);
auto response = activation->activate();
EXPECT_EQ(FAKE_SHA512, response.scope_data().get_dict()["download_sha512"].get_string());
}
TEST_F(StoreScopeTest, testDownloadFailed)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::DOWNLOAD_FAILED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::DOWNLOAD_FAILED].get_bool());
}
TEST_F(StoreScopeTest, testDownloadCompleted)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::DOWNLOAD_COMPLETED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::DOWNLOAD_COMPLETED].get_bool());
EXPECT_TRUE(response.scope_data().get_dict()["installed"].get_bool());
}
TEST_F(StoreScopeTest, testCancelPurchaseInstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CANCEL_PURCHASE_INSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CANCEL_PURCHASE_INSTALLED].get_bool());
}
TEST_F(StoreScopeTest, testCancelPurchaseUninstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CANCEL_PURCHASE_UNINSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CANCEL_PURCHASE_UNINSTALLED].get_bool());
}
TEST_F(StoreScopeTest, testUninstallClick)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::UNINSTALL_CLICK);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::UNINSTALL_CLICK].get_bool());
}
TEST_F(StoreScopeTest, testShowUninstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::SHOW_UNINSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::SHOW_UNINSTALLED].get_bool());
}
TEST_F(StoreScopeTest, testShowInstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::SHOW_INSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::SHOW_INSTALLED].get_bool());
}
TEST_F(StoreScopeTest, testConfirmUninstall)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CONFIRM_UNINSTALL);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CONFIRM_UNINSTALL].get_bool());
}
TEST_F(StoreScopeTest, testConfirmCancelPurchaseUninstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_UNINSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_UNINSTALLED].get_bool());
}
TEST_F(StoreScopeTest, testConfirmCancelPurcahseInstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_INSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_INSTALLED].get_bool());
}
TEST_F(StoreScopeTest, testStoreScopeRatingNew)
{
auto activation = scope.perform_action(result, metadata, "rating",
click::Preview::Actions::RATED);
auto response = activation->activate();
EXPECT_EQ("rating", response.scope_data().get_dict()["widget_id"].get_string());
}
TEST_F(StoreScopeTest, testStoreScopeRatingEdit)
{
auto activation = scope.perform_action(result, metadata, "93345",
click::Preview::Actions::RATED);
auto response = activation->activate();
EXPECT_EQ("93345", response.scope_data().get_dict()["widget_id"].get_string());
}
./scope/tests/test_apps_scope.cpp 0000644 0000156 0000165 00000012425 12676763577 017305 0 ustar jenkins jenkins /*
* Copyright (C) 2015 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include
#include
#include
#include
#include
using namespace ::testing;
class AppsScopeTest : public Test {
protected:
click::Scope scope;
unity::scopes::testing::Result result;
unity::scopes::ActionMetadata metadata;
unity::scopes::VariantMap metadict;
public:
AppsScopeTest() : metadata("en_EN", "phone") {
metadict["rating"] = unity::scopes::Variant(4.0f);
metadict["review"] = "This is a review.";
metadata.set_scope_data(unity::scopes::Variant(metadict));
}
};
TEST_F(AppsScopeTest, DISABLED_testConfirmUninstall)
{
result.set_title("foo");
result[click::apps::Query::ResultKeys::NAME] = "foo.name";
result[click::apps::Query::ResultKeys::VERSION] = "0.1";
auto activation = scope.perform_action(result, metadata, "widget",
click::Preview::Actions::CONFIRM_UNINSTALL);
auto response = activation->activate();
}
TEST_F(AppsScopeTest, testCancelPurchaseInstalled)
{
auto activation = scope.perform_action(result, metadata, "button",
click::Preview::Actions::CANCEL_PURCHASE_INSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CANCEL_PURCHASE_INSTALLED].get_bool());
}
TEST_F(AppsScopeTest, testCancelPurchaseUninstalled)
{
auto activation = scope.perform_action(result, metadata, "button",
click::Preview::Actions::CANCEL_PURCHASE_UNINSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CANCEL_PURCHASE_UNINSTALLED].get_bool());
}
TEST_F(AppsScopeTest, testShowInstalled)
{
auto activation = scope.perform_action(result, metadata, "button",
click::Preview::Actions::SHOW_INSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::SHOW_INSTALLED].get_bool());
}
TEST_F(AppsScopeTest, testShowUninstalled)
{
auto activation = scope.perform_action(result, metadata, "button",
click::Preview::Actions::SHOW_UNINSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::SHOW_UNINSTALLED].get_bool());
}
TEST_F(AppsScopeTest, testConfirmCancelPurchaseUninstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_UNINSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_UNINSTALLED].get_bool());
}
TEST_F(AppsScopeTest, testConfirmCancelPurcahseInstalled)
{
auto activation = scope.perform_action(result, metadata, "widget_id",
click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_INSTALLED);
auto response = activation->activate();
EXPECT_TRUE(response.scope_data().get_dict()[click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_INSTALLED].get_bool());
}
TEST_F(AppsScopeTest, testRatingNew)
{
auto activation = scope.perform_action(result, metadata, "rating",
click::Preview::Actions::RATED);
auto response = activation->activate();
EXPECT_EQ("rating", response.scope_data().get_dict()["widget_id"].get_string());
}
TEST_F(AppsScopeTest, testRatingEdit)
{
auto activation = scope.perform_action(result, metadata, "93345",
click::Preview::Actions::RATED);
auto response = activation->activate();
EXPECT_EQ("93345", response.scope_data().get_dict()["widget_id"].get_string());
}
./scope/tests/click_interface_tool/ 0000755 0000156 0000165 00000000000 12676763577 017544 5 ustar jenkins jenkins ./scope/tests/click_interface_tool/CMakeLists.txt 0000644 0000156 0000165 00000000460 12676763577 022304 0 ustar jenkins jenkins set(CLICK_INTERFACE_TOOL_TARGET click_interface_tool)
include_directories (
${CMAKE_SOURCE_DIR}/libclickscope
${CMAKE_SOURCE_DIR}/scope
)
add_executable (${CLICK_INTERFACE_TOOL_TARGET}
click_interface_tool.cpp
)
target_link_libraries (${CLICK_INTERFACE_TOOL_TARGET}
${STORE_LIB_UNVERSIONED}
)
./scope/tests/click_interface_tool/click_interface_tool.cpp 0000644 0000156 0000165 00000005113 12676763577 024412 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSharedPointer keyFileLocator(new click::KeyFileLocator());
click::Interface ci(keyFileLocator);
QTimer timer;
timer.setSingleShot(true);
QObject::connect(&timer, &QTimer::timeout, [&]() {
ci.get_dotdesktop_filename(std::string(argv[1]),
[&a] (std::string val, click::InterfaceError error){
if (error == click::InterfaceError::NoError) {
std::cout << " Success, got dotdesktop:" << val << std::endl;
} else {
std::cout << " Error:" << val << std::endl;
}
a.quit();
});
} );
timer.start(0);
qInstallMessageHandler(0);
return a.exec();
}
./scope/tests/test_query.cpp 0000644 0000156 0000165 00000067520 12676763577 016324 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include "clickstore/store-query.h"
#include
#include
#include
#include
#include "click/qtbridge.h"
#include "click/index.h"
#include "clickstore/store-query.h"
#include "click/application.h"
#include "click/departments-db.h"
#include "test_helpers.h"
#include "click/package.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace ::testing;
using namespace click;
using namespace click::test::helpers;
namespace
{
class MockQueryBase : public click::Query {
public:
MockQueryBase(const unity::scopes::CannedQuery& query, click::Index& index,
click::DepartmentLookup& depts,
std::shared_ptr depts_db,
click::HighlightList& highlights,
scopes::SearchMetadata const& metadata,
pay::Package& in_package) :
click::Query(query, index, depts, depts_db, highlights, metadata, in_package)
{
}
void run_under_qt(const std::function &task) {
// when testing, do not actually run under qt
task();
}
};
class MockQuery : public MockQueryBase {
public:
MockQuery(const unity::scopes::CannedQuery& query, click::Index& index,
click::DepartmentLookup& depts,
std::shared_ptr depts_db,
click::HighlightList& highlights,
scopes::SearchMetadata const& metadata,
pay::Package& in_package) :
MockQueryBase(query, index, depts, depts_db, highlights, metadata, in_package)
{
}
void wrap_add_available_apps(const scopes::SearchReplyProxy &searchReply,
const PackageSet &installedPackages,
const std::string& categoryTemplate)
{
add_available_apps(searchReply, installedPackages, categoryTemplate);
}
MOCK_METHOD2(push_result, bool(scopes::SearchReplyProxy const&, scopes::CategorisedResult const&));
MOCK_METHOD0(clickInterfaceInstance, click::Interface&());
MOCK_METHOD1(finished, void(scopes::SearchReplyProxy const&));
MOCK_METHOD5(register_category, scopes::Category::SCPtr(const scopes::SearchReplyProxy &searchReply,
const std::string &id,
const std::string &title,
const std::string &icon,
const scopes::CategoryRenderer &renderer_template));
using click::Query::get_installed_packages; // allow tests to access protected method
using click::Query::push_package;
};
class MockQueryRun : public MockQueryBase {
public:
MockQueryRun(const unity::scopes::CannedQuery& query, click::Index& index,
click::DepartmentLookup& depts,
std::shared_ptr depts_db,
click::HighlightList& highlights,
scopes::SearchMetadata const& metadata,
pay::Package& in_package) :
MockQueryBase(query, index, depts, depts_db, highlights, metadata, in_package)
{
}
MOCK_METHOD3(add_available_apps,
void(scopes::SearchReplyProxy const&searchReply,
const PackageSet &locallyInstalledApps,
const std::string& categoryTemplate));
MOCK_METHOD3(push_local_results, void(scopes::SearchReplyProxy const &replyProxy,
std::vector const &apps,
std::string& categoryTemplate));
MOCK_METHOD0(get_installed_packages, PackageSet());
};
} // namespace
TEST(QueryTest, testAddAvailableAppsCallsClickIndex)
{
MockIndex mock_index;
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
scopes::SearchMetadata metadata("en_EN", "phone");
MockPayPackage pay_pkg;
PackageSet no_installed_packages;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _)).Times(1);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
}
MATCHER_P(CategoryHasNumberOfResults, number, "") { return arg.find(std::to_string(number)) != std::string::npos; }
TEST(QueryTest, testAddAvailableAppsPushesResults)
{
click::Packages packages {
{"name", "title", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
scopes::SearchMetadata metadata("en_EN", "phone");
MockPayPackage pay_pkg;
PackageSet no_installed_packages;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
ON_CALL(q, register_category(_, _, _, _, _)).WillByDefault(Return(ptrCat));
EXPECT_CALL(q, register_category(_, "appstore", CategoryHasNumberOfResults(1), _, _));
EXPECT_CALL(q, register_category(_, "recommends", _, _, _));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
auto expected_title = packages.front().title;
EXPECT_CALL(q, push_result(_, Property(&scopes::CategorisedResult::title, expected_title)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
}
TEST(QueryTest, testAddAvailableAppsCallsFinished)
{
click::Packages packages {
{"name", "title", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
scopes::SearchMetadata metadata("en_EN", "phone");
MockPayPackage pay_pkg;
PackageSet no_installed_packages;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(_, _));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
}
TEST(QueryTest, testQueryRunCallsAddAvailableApps)
{
click::Packages packages {
{"name", "title", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
scopes::SearchMetadata metadata("en_EN", "phone");
MockPayPackage pay_pkg;
PackageSet no_installed_packages;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQueryRun q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
auto reply = scopes::SearchReplyProxy();
EXPECT_CALL(q, get_installed_packages()).WillOnce(Return(no_installed_packages));
EXPECT_CALL(q, add_available_apps(reply, no_installed_packages, _));
// No need to test purchases in this testcase
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "0", 1), 0);
q.run(reply);
}
MATCHER_P(HasPackageName, n, "") { return arg[click::Query::ResultKeys::NAME].get_string() == n; }
MATCHER_P(IsInstalled, b, "") { return arg[click::Query::ResultKeys::INSTALLED].get_bool() == b; }
TEST(QueryTest, testDuplicatesNotFilteredAnymore)
{
click::Packages packages {
{"org.example.app1", "app title1", 0.0, "icon", "uri"},
{"org.example.app2", "app title2", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet one_installed_package {
{"org.example.app2", "0.2"}
};
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
auto expected_name1 = packages.front().name;
EXPECT_CALL(q, push_result(_, HasPackageName(expected_name1)));
auto expected_name2 = packages.back().name;
EXPECT_CALL(q, push_result(_, HasPackageName(expected_name2)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE);
}
TEST(QueryTest, testInstalledPackagesFlaggedAsSuch)
{
click::Packages packages {
{"org.example.app1", "app title1", 0.0, "icon", "uri"},
{"org.example.app2", "app title2", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet one_installed_package {
{"org.example.app2", "0.2"}
};
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(_, IsInstalled(true)));
EXPECT_CALL(q, push_result(_, IsInstalled(false)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE);
}
TEST(QueryTest, testDepartmentsDbIsUpdated)
{
auto dept1 = std::make_shared("1", "Department one", "http://one.com", true);
dept1->set_subdepartments({
std::make_shared("1-1", "Department two", "http://two.com", false),
std::make_shared("1-2", "Department three", "http://three.com", false)
});
DepartmentList init_departments({dept1});
auto depts_db = std::make_shared(":memory:", true);
EXPECT_CALL(*depts_db, store_department_name(_, _, _)).Times(3);
EXPECT_CALL(*depts_db, store_department_mapping("1", ""));
EXPECT_CALL(*depts_db, store_department_mapping("1-1", "1"));
EXPECT_CALL(*depts_db, store_department_mapping("1-2", "1"));
MockIndex mock_index(click::Packages(), click::DepartmentList(), init_departments);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet one_installed_package {
{"org.example.app2", "0.2"}
};
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, depts_db, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE);
}
TEST(QueryTest, testSearchInDepartment)
{
auto dept1 = std::make_shared("1", "Department one", "http://one.com", true);
DepartmentList init_departments({dept1});
auto depts_db = std::make_shared(":memory:", true);
MockIndex mock_index(click::Packages(), click::DepartmentList(), init_departments);
scopes::SearchMetadata metadata("en_EN", "phone");
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "1");
MockQuery q(query, mock_index, dept_lookup, depts_db, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, "1", _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
std::list expected_departments({"", "1"});
scopes::testing::MockSearchReply mock_reply;
EXPECT_CALL(mock_reply, register_departments(MatchesDepartments(expected_departments)));
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, PackageSet(), FAKE_CATEGORY_TEMPLATE);
}
class FakeInterface : public click::Interface
{
public:
MOCK_METHOD1(get_installed_packages, void(std::function callback));
};
TEST(QueryTest, testGetInstalledPackages)
{
click::Packages uninstalled_packages {
{"name", "title", 0.0, "icon", "uri"}
};
MockIndex mock_index(uninstalled_packages);
scopes::SearchMetadata metadata("en_EN", "phone");
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
PackageSet installed_packages{{"package_1", "0.1"}};
FakeInterface fake_interface;
EXPECT_CALL(q, clickInterfaceInstance()).WillOnce(ReturnRef(fake_interface));
EXPECT_CALL(fake_interface, get_installed_packages(_)).WillOnce(Invoke(
[&](std::function callback){
callback(installed_packages, click::InterfaceError::NoError);
}));
ASSERT_EQ(q.get_installed_packages(), installed_packages);
}
typedef std::pair _PurchasedValues;
MATCHER_P(PurchasedProperties, b, "") { return arg[click::Query::ResultKeys::PURCHASED].get_bool() == b.first && arg[click::Query::ResultKeys::INSTALLED].get_bool() == b.second; }
TEST(QueryTest, testQueryRunPurchased)
{
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "1", 1), 0);
click::Packages packages {
{"name", "title", 0.99, "icon", "uri"}
};
MockIndex mock_index(packages);
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
scopes::SearchMetadata metadata("en_EN", "phone");
MockPayPackage pay_pkg;
PackageSet no_installed_packages;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
q.purchased_apps.insert({"name"});
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
ON_CALL(q, register_category(_, _, _, _, _)).WillByDefault(Return(ptrCat));
EXPECT_CALL(q, register_category(_, "appstore", _, _, _));
EXPECT_CALL(q, register_category(_, "recommends", _, _, _));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(_, PurchasedProperties(_PurchasedValues{true, false}))).Times(1);
EXPECT_CALL(q, finished(_));
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
ASSERT_EQ(unsetenv(Configuration::PURCHASES_ENVVAR), 0);
}
TEST(QueryTest, testQueryRunPurchasedAndInstalled)
{
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "1", 1), 0);
click::Packages packages {
{"name", "title", 0.99, "icon", "uri"}
};
PackageSet one_installed_package {
{"name", "0.2"}
};
MockIndex mock_index(packages);
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
scopes::SearchMetadata metadata("en_EN", "phone");
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
q.purchased_apps.insert({"name"});
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
ON_CALL(q, register_category(_, _, _, _, _)).WillByDefault(Return(ptrCat));
EXPECT_CALL(q, register_category(_, "appstore", _, _, _));
EXPECT_CALL(q, register_category(_, "recommends", _, _, _));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(_, PurchasedProperties(_PurchasedValues{true, true}))).Times(1);
EXPECT_CALL(q, finished(_));
q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE);
ASSERT_EQ(unsetenv(Configuration::PURCHASES_ENVVAR), 0);
}
TEST(QueryTest, testPushPackageSkipsPricedApps)
{
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "0", 1), 0);
click::Packages packages {
{"org.example.app1", "app title1", 1.99, "icon", "uri"},
{"org.example.app2", "app title2", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet no_installed_packages;
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
auto expected_name2 = packages.back().name;
EXPECT_CALL(q, push_result(_, HasPackageName(expected_name2)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
ASSERT_EQ(unsetenv(Configuration::PURCHASES_ENVVAR), 0);
}
TEST(QueryTest, testPushPackagePushesPricedApps)
{
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "1", 1), 0);
click::Packages packages {
{"org.example.app1", "app title1", 1.99, "icon", "uri"},
{"org.example.app2", "app title2", 0.0, "icon", "uri"}
};
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet no_installed_packages;
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
auto expected_name1 = packages.front().name;
EXPECT_CALL(q, push_result(_, HasPackageName(expected_name1)));
auto expected_name2 = packages.back().name;
EXPECT_CALL(q, push_result(_, HasPackageName(expected_name2)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
ASSERT_EQ(unsetenv(Configuration::PURCHASES_ENVVAR), 0);
}
MATCHER_P(HasAttributes, b, "") { return (!arg["attributes"].is_null()) == b; }
TEST(QueryTest, testPushPackagePushesAttributes)
{
click::Packages packages {
{"org.example.app1", "app title1", 0.0, "icon", "uri"},
};
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet no_installed_packages;
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(_, HasAttributes(true)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
}
MATCHER_P(HasPrice, price, "") { return arg["price"].get_double() == price; }
TEST(QueryTest, testPushPackagePushesPriceUSD)
{
ASSERT_EQ(unsetenv(Configuration::CURRENCY_ENVVAR), 0);
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "1", 1), 0);
Json::Value root;
Json::Reader().parse(FAKE_JSON_SEARCH_RESULT_ONE, root);
auto const embedded = root[Package::JsonKeys::embedded];
auto const ci_package = embedded[Package::JsonKeys::ci_package];
Packages packages = package_list_from_json_node(ci_package);
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet no_installed_packages;
DepartmentLookup dept_lookup;
HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", "", "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(reply, HasPrice(1.99)));
q.push_package(reply, ptrCat, no_installed_packages, packages[0]);
ASSERT_EQ(unsetenv(Configuration::PURCHASES_ENVVAR), 0);
}
TEST(QueryTest, testPushPackagePushesPriceEUR)
{
ASSERT_EQ(setenv(Configuration::CURRENCY_ENVVAR, "EUR", 1), 0);
ASSERT_EQ(setenv(Configuration::PURCHASES_ENVVAR, "1", 1), 0);
Json::Value root;
Json::Reader().parse(FAKE_JSON_SEARCH_RESULT_ONE, root);
auto const embedded = root[Package::JsonKeys::embedded];
auto const ci_package = embedded[Package::JsonKeys::ci_package];
Packages packages = package_list_from_json_node(ci_package);
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet no_installed_packages;
DepartmentLookup dept_lookup;
HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", "", "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(reply, HasPrice(1.69)));
q.push_package(reply, ptrCat, no_installed_packages, packages[0]);
ASSERT_EQ(unsetenv(Configuration::CURRENCY_ENVVAR), 0);
ASSERT_EQ(unsetenv(Configuration::PURCHASES_ENVVAR), 0);
}
MATCHER_P(HasVersion, v, "") { return arg[click::Query::ResultKeys::VERSION].get_string() == v; }
TEST(QueryTest, testPushPackagePushesVersion)
{
auto const fake_version = "0.83b";
click::Packages packages {
{"org.example.app1", "app title1", 0.0, "icon", "uri", fake_version, "scope"},
};
MockIndex mock_index(packages);
scopes::SearchMetadata metadata("en_EN", "phone");
PackageSet no_installed_packages;
click::DepartmentLookup dept_lookup;
click::HighlightList highlights;
MockPayPackage pay_pkg;
const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg);
EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
scopes::CategoryRenderer renderer("{}");
auto ptrCat = std::make_shared("id", "", "", renderer);
EXPECT_CALL(q, register_category(_, _, _, _, _)).Times(2).WillRepeatedly(Return(ptrCat));
scopes::testing::MockSearchReply mock_reply;
scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
EXPECT_CALL(q, push_result(_, HasVersion(fake_version)));
EXPECT_CALL(q, finished(_)).Times(1);
q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
}
./scope/tests/test_helpers.h 0000644 0000156 0000165 00000007220 12676763577 016255 0 ustar jenkins jenkins #ifndef TEST_HELPERS_H
#define TEST_HELPERS_H
#include
#include
#include "click/index.h"
#include
#include
#include
namespace click
{
namespace test
{
namespace helpers
{
static const std::string FAKE_QUERY {"FAKE_QUERY"};
static const std::string FAKE_CATEGORY_TEMPLATE {"{}"};
// this matcher expects a list of department ids in depts:
// first on the list is the root, followed by children ids.
// the arg of the matcher is unity::scopes::Department ptr.
MATCHER_P(MatchesDepartments, depts, "") {
auto it = depts.begin();
if (arg->id() != *it)
return false;
auto const subdeps = arg->subdepartments();
if (subdeps.size() != depts.size() - 1)
return false;
for (auto const& sub: subdeps)
{
if (sub->id() != *(++it))
return false;
}
return true;
}
class MockIndex : public click::Index {
click::Packages packages;
click::Packages recommends;
click::DepartmentList departments;
click::DepartmentList bootstrap_departments;
click::HighlightList bootstrap_highlights;
public:
MockIndex(click::Packages packages = click::Packages(),
click::DepartmentList departments = click::DepartmentList(),
click::DepartmentList boot_departments = click::DepartmentList())
: Index(QSharedPointer()),
packages(packages),
departments(departments),
bootstrap_departments(boot_departments)
{
}
click::web::Cancellable search(const std::string &query, const std::string &department, std::function callback) override
{
do_search(query, department, callback);
callback(packages, recommends);
return click::web::Cancellable();
}
click::web::Cancellable bootstrap(std::function callback) override
{
callback(bootstrap_departments, bootstrap_highlights, click::Index::Error::NoError, 0);
return click::web::Cancellable();
}
MOCK_METHOD3(do_search,
void(const std::string&, const std::string&,
std::function));
};
class MockDepartmentsDb : public click::DepartmentsDb
{
public:
MockDepartmentsDb(const std::string& name, bool create)
: click::DepartmentsDb(name, create)
{
}
MOCK_METHOD2(get_department_name, std::string(const std::string&, const std::list&));
MOCK_METHOD2(get_packages_for_department, std::unordered_set(const std::string&, bool));
MOCK_METHOD1(get_parent_department_id, std::string(const std::string&));
MOCK_METHOD1(get_children_departments, std::list(const std::string&));
MOCK_METHOD1(is_empty, bool(const std::string&));
MOCK_METHOD2(is_descendant_of_department, bool(const std::string&, const std::string&));
MOCK_METHOD2(store_package_mapping, void(const std::string&, const std::string&));
MOCK_METHOD2(store_department_mapping, void(const std::string&, const std::string&));
MOCK_METHOD3(store_department_name, void(const std::string&, const std::string&, const std::string&));
};
class FakeCategory : public scopes::Category
{
public:
FakeCategory(std::string const& id, std::string const& title,
std::string const& icon, scopes::CategoryRenderer const& renderer) :
scopes::Category(id, title, icon, renderer)
{
}
};
} // namespace helpers
} // namespace test
} // namespace click
#endif // TEST_HELPERS_H
./scope/tests/CMakeLists.txt 0000644 0000156 0000165 00000006560 12676763577 016151 0 ustar jenkins jenkins set (CLICKSCOPE_TESTS_TARGET click-scope-tests)
set (APPS_SCOPE_TESTS_TARGET apps-scope-tests)
find_package(Threads)
# Qt5 bits
SET (CMAKE_INCLUDE_CURRENT_DIR ON)
SET (CMAKE_AUTOMOC ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Sql REQUIRED)
include_directories (
${CMAKE_SOURCE_DIR}/libclickscope
${CMAKE_SOURCE_DIR}/scope
${JSON_CPP_INCLUDE_DIRS}
${GTEST_INCLUDE_DIR}
${GMOCK_INCLUDE_DIR}
)
add_executable (${CLICKSCOPE_TESTS_TARGET}
test_query.cpp
test_store_scope.cpp
${CMAKE_SOURCE_DIR}/libclickscope/tests/fake_json.cpp
)
add_executable (${APPS_SCOPE_TESTS_TARGET}
test_apps_query.cpp
test_apps_scope.cpp
)
qt5_use_modules(${CLICKSCOPE_TESTS_TARGET} Core DBus Network Test Sql)
qt5_use_modules(${APPS_SCOPE_TESTS_TARGET} Core DBus Network Test Sql)
target_link_libraries(${CLICKSCOPE_TESTS_TARGET}
${STORE_LIB_UNVERSIONED}
${SCOPE_LIB_NAME}
${UNITY_SCOPES_LDFLAGS}
${UBUNTUONE_LDFLAGS}
${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
${JSON_CPP_LDFLAGS}
gmock
gmock_main
${CMAKE_THREAD_LIBS_INIT}
)
target_link_libraries(${APPS_SCOPE_TESTS_TARGET}
${APPS_LIB_UNVERSIONED}
${SCOPE_LIB_NAME}
${UNITY_SCOPES_LDFLAGS}
${UBUNTUONE_LDFLAGS}
${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
${JSON_CPP_LDFLAGS}
gmock
gmock_main
${CMAKE_THREAD_LIBS_INIT}
)
add_custom_target (test-click-scope
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${CLICKSCOPE_TESTS_TARGET}
DEPENDS ${CLICKSCOPE_TESTS_TARGET}
)
add_custom_target(test-click-scope-valgrind
COMMAND valgrind --tool=memcheck ${CMAKE_CURRENT_BINARY_DIR}/${CLICKSCOPE_TESTS_TARGET}
DEPENDS ${CLICKSCOPE_TESTS_TARGET}
)
add_custom_target(test-click-scope-leaks
COMMAND valgrind --tool=memcheck --track-origins=yes --num-callers=40 --leak-resolution=high --leak-check=full ${CMAKE_CURRENT_BINARY_DIR}/${CLICKSCOPE_TESTS_TARGET}
DEPENDS ${CLICKSCOPE_TESTS_TARGET}
)
add_custom_target (test-click-scope-disabled
COMMAND GTEST_ALSO_RUN_DISABLED_TESTS=1 ${CMAKE_CURRENT_BINARY_DIR}/${CLICKSCOPE_TESTS_TARGET}
DEPENDS ${CLICKSCOPE_TESTS_TARGET}
)
# ---
set(TEST_SCHEMA_DIR ${CMAKE_CURRENT_BINARY_DIR})
add_definitions(-DTEST_SCHEMA_DIR="${TEST_SCHEMA_DIR}")
execute_process (
COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas
OUTPUT_VARIABLE COMPILE_SCHEMA_EXECUTABLE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_custom_target (gschemas.compiled
COMMAND cp -f ${CMAKE_SOURCE_DIR}/data/*gschema.xml ${TEST_SCHEMA_DIR}
COMMAND ${COMPILE_SCHEMA_EXECUTABLE} ${TEST_SCHEMA_DIR}
)
add_custom_target (test-apps-scope
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
DEPENDS ${APPS_SCOPE_TESTS_TARGET} gschemas.compiled
)
add_custom_target(test-apps-scope-valgrind
COMMAND valgrind --tool=memcheck ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
DEPENDS ${APPS_SCOPE_TESTS_TARGET}
)
add_custom_target(test-apps-scope-leaks
COMMAND valgrind --tool=memcheck --track-origins=yes --num-callers=40 --leak-resolution=high --leak-check=full ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
DEPENDS ${APPS_SCOPE_TESTS_TARGET}
)
add_custom_target (test-apps-scope-disabled
COMMAND GTEST_ALSO_RUN_DISABLED_TESTS=1 ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
DEPENDS ${APPS_SCOPE_TESTS_TARGET}
)
add_subdirectory(click_interface_tool)
add_subdirectory(fake_launcher)
./scope/clickapps/ 0000755 0000156 0000165 00000000000 12676763604 014200 5 ustar jenkins jenkins ./scope/clickapps/clickscope.ini.in.in 0000644 0000156 0000165 00000000371 12676763577 020044 0 ustar jenkins jenkins [ScopeConfig]
_DisplayName=Apps
_Description=Scope for searching installed apps
Author=Canonical Ltd.
Art=@APPS_DATA_DIR@/clickscope-screenshot.jpg
Icon=@APPS_DATA_DIR@/apps-scope.png
_SearchHint=Search apps
[Appearance]
LogoOverlayColor=#ffffffff
./scope/clickapps/apps-scope.h 0000644 0000156 0000165 00000005533 12676763604 016431 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#ifndef APPS_SCOPE_H
#define APPS_SCOPE_H
#include
#include
#include
#include
#include
#include
#include
#include
namespace scopes = unity::scopes;
namespace click
{
class DepartmentsDb;
class Scope : public scopes::ScopeBase
{
public:
Scope();
~Scope();
virtual void start(std::string const&) override;
virtual void run() override;
virtual void stop() override;
virtual scopes::SearchQueryBase::UPtr search(scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata) override;
unity::scopes::PreviewQueryBase::UPtr preview(const unity::scopes::Result&,
const unity::scopes::ActionMetadata& hints) override;
virtual unity::scopes::ActivationQueryBase::UPtr perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& widget_id, std::string const& action_id) override;
private:
QSharedPointer nam;
QSharedPointer client;
QSharedPointer index;
QSharedPointer pay_package;
QSharedPointer dm;
std::shared_ptr depts_db;
std::string installApplication(unity::scopes::Result const& result);
};
}
#endif // CLICK_SCOPE_H
./scope/clickapps/apps-query.cpp 0000644 0000156 0000165 00000035267 12676763577 017040 0 ustar jenkins jenkins /*
* Copyright (C) 2014-2015 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "apps-query.h"
#include
namespace
{
static const std::string CATEGORY_APPS_DISPLAY = R"(
{
"schema-version" : 1,
"template" : {
"category-layout" : "grid",
"collapsed-rows": 0,
"card-size": "small"
},
"components" : {
"title" : "title",
"art" : {
"field": "art",
"aspect-ratio": 1.6,
"fill-mode": "fit",
"fallback": "image://theme/placeholder-app-icon"
}
}
}
)";
static const char CATEGORY_STORE[] = R"(
{
"template": {
"category-layout": "grid",
"overlay": true,
"card-size": "small",
"card-background": "color:///#DD4814"
},
"components": {
"title": "title",
"art": {
"aspect-ratio": 0.55,
"field": "art"
},
"overlay-color": "overlay-color"
}
}
)";
}
click::apps::ResultPusher::ResultPusher(const scopes::SearchReplyProxy &replyProxy, const std::vector& apps)
: replyProxy(replyProxy)
{
for (auto const& app: apps)
{
//
// click entries in the dconf key are expected to be in the format of
// "foo.bar.package_appname"; split on underscore and just use the first part
// for now (second part should be honored when we support multiple apps per package).
auto i = app.find("_");
if (i != std::string::npos)
{
const std::string pkg = app.substr(0, i);
core_apps.push_back(pkg);
top_apps_lookup.insert(pkg);
}
else
{
core_apps.push_back(app);
top_apps_lookup.insert(app);
}
}
}
void click::apps::ResultPusher::push_result(scopes::Category::SCPtr& cat, const click::Application& a)
{
scopes::CategorisedResult res(cat);
res.set_title(a.title);
res.set_art(a.icon_url);
res.set_uri(a.url);
res[click::apps::Query::ResultKeys::NAME] = a.name;
res[click::apps::Query::ResultKeys::DESCRIPTION] = a.description;
res[click::apps::Query::ResultKeys::MAIN_SCREENSHOT] = a.main_screenshot;
res[click::apps::Query::ResultKeys::INSTALLED] = true;
res[click::apps::Query::ResultKeys::VERSION] = a.version;
replyProxy->push(res);
}
//
// Return an application identifier used to match applications against core-apps dconf key;
// For click apps, it just returns application name (e.g. com.canonical.calculator).
// For non-click apps, it return the desktop file name (without extension), taken from app uri.
std::string click::apps::ResultPusher::get_app_identifier(const click::Application& app)
{
static const std::string app_prefix("application:///");
if (!app.name.empty())
{
return app.name;
}
if (app.url.size() > app_prefix.size())
{
auto i = app.url.rfind('.');
if (i != std::string::npos)
{
return app.url.substr(app_prefix.size(), i - app_prefix.size());
}
}
throw std::runtime_error("Cannot determine application identifier for" + app.url);
}
void click::apps::ResultPusher::push_local_results(
const std::vector &apps,
const std::string &categoryTemplate,
bool show_title)
{
const scopes::CategoryRenderer rdr(categoryTemplate);
auto cat = replyProxy->register_category("local", show_title ? _("Apps") : "", "", rdr);
for(const auto & a: apps)
{
try
{
if (top_apps_lookup.size() == 0 || top_apps_lookup.find(get_app_identifier(a)) == top_apps_lookup.end())
{
push_result(cat, a);
}
}
catch (const std::runtime_error &e)
{
qWarning() << QString::fromStdString(e.what());
}
}
}
void click::apps::ResultPusher::push_top_results(
const std::vector& apps,
const std::string& categoryTemplate)
{
const scopes::CategoryRenderer rdr(categoryTemplate);
auto cat = replyProxy->register_category("predefined", "", "", rdr);
//
// iterate over all apps, insert those matching core apps into top_apps_to_push
std::map top_apps_to_push;
for (const auto& a: apps)
{
try
{
const auto id = get_app_identifier(a);
if (top_apps_lookup.find(id) != top_apps_lookup.end())
{
top_apps_to_push[id] = a;
if (core_apps.size() == top_apps_to_push.size())
{
// no need to iterate over remaining apps
break;
}
}
}
catch (const std::runtime_error &e)
{
qWarning() << QString::fromStdString(e.what());
}
}
//
// iterate over core apps and insert them based on top_apps_to_push;
// this way the order of core apps is preserved.
for (const auto &a: core_apps)
{
auto const it = top_apps_to_push.find(a);
if (it != top_apps_to_push.end())
{
push_result(cat, it->second);
}
}
}
struct click::apps::Query::Private
{
Private(std::shared_ptr depts_db, const scopes::SearchMetadata& metadata)
: depts_db(depts_db),
meta(metadata)
{
}
std::shared_ptr depts_db;
scopes::SearchMetadata meta;
click::Configuration configuration;
};
click::apps::Query::Query(unity::scopes::CannedQuery const& query, std::shared_ptr depts_db,
scopes::SearchMetadata const& metadata)
: unity::scopes::SearchQueryBase(query, metadata),
impl(new Private(depts_db, metadata))
{
}
void click::apps::Query::cancelled()
{
qDebug() << "cancelling search of" << QString::fromStdString(query().query_string());
}
click::apps::Query::~Query()
{
qDebug() << "destroying search";
}
click::Interface& click::apps::Query::clickInterfaceInstance()
{
static QSharedPointer keyFileLocator(new click::KeyFileLocator());
static click::Interface iface(keyFileLocator);
return iface;
}
void click::apps::Query::add_fake_store_app(scopes::SearchReplyProxy const& searchReply)
{
static const std::string title = _("Ubuntu Store");
std::string cat_title = _("Get more apps from the store");
const std::string querystr = query().query_string();
if (!querystr.empty())
{
char tmp[512];
if (snprintf(tmp, sizeof(tmp), _("Search for '%s' in the store"), querystr.c_str()) > 0)
{
cat_title = tmp;
}
}
else if (!query().department_id().empty())
{
cat_title = _("Get more apps like this from the Store");
}
scopes::CategoryRenderer rdr(CATEGORY_STORE);
auto cat = searchReply->register_category("store", cat_title, "", rdr);
const unity::scopes::CannedQuery store_scope("com.canonical.scopes.clickstore", querystr, querystr.empty() ? query().department_id() : "");
scopes::CategorisedResult res(cat);
res.set_title(title);
res.set_art(STORE_DATA_DIR "/store-scope-icon.svg");
res.set_uri(store_scope.to_uri());
res[click::apps::Query::ResultKeys::NAME] = title;
res[click::apps::Query::ResultKeys::DESCRIPTION] = "";
res[click::apps::Query::ResultKeys::MAIN_SCREENSHOT] = "";
res[click::apps::Query::ResultKeys::INSTALLED] = true;
res[click::apps::Query::ResultKeys::VERSION] = "";
res["overlay-color"] = "transparent";
searchReply->push(res);
}
void click::apps::Query::push_local_departments(scopes::SearchReplyProxy const& replyProxy, const std::vector& apps)
{
auto const current_dep_id = query().department_id();
const std::list locales = { search_metadata().locale(), "en_US" };
//
// create helper lookup of all departments of currently installed apps.
// note that apps that are passed here are supposed to be already filterd by current department
// that means we only have subdepartments of current department (or subdepartment(s) of subdepartment(s)
// and so on of current department, as the hierarchy may be of arbitrary depth.
std::unordered_set all_subdepartments;
for (auto const app: apps)
{
all_subdepartments.insert(app.real_department);
}
unity::scopes::Department::SPtr root;
try
{
static const std::string all_dept_name = _("All");
// create node for current department
auto name = current_dep_id == "" ? all_dept_name : impl->depts_db->get_department_name(current_dep_id, locales);
unity::scopes::Department::SPtr current = unity::scopes::Department::create(current_dep_id, query(), name);
unity::scopes::DepartmentList children;
// attach subdepartments to it
for (auto const& subdep: impl->depts_db->get_children_departments(current_dep_id))
{
//
// check if this subdepartment either directly matches a subdepartment of installed app,
// or is any of the departments of installed apps is a descendant of current subdepartment.
// the latter means we have app somewhere in the subtree of the current subdepartment, so it
// needs to be shown.
bool show_subdepartment = false;
auto it = all_subdepartments.find(subdep.id);
if (it != all_subdepartments.end())
{
// subdepartment id matches directly one of the ids from all_subdepartments
show_subdepartment = true;
all_subdepartments.erase(it);
}
else
{
// no direct match - we need to check descendants of this subdepartment
// by querying the db
for (auto it = all_subdepartments.begin(); it != all_subdepartments.end(); it++)
{
if (impl->depts_db->is_descendant_of_department(*it, subdep.id))
{
show_subdepartment = true;
all_subdepartments.erase(it);
break;
}
}
}
if (show_subdepartment)
{
// if single supdepartment fails, then ignore it and continue with others
try
{
name = impl->depts_db->get_department_name(subdep.id, locales);
unity::scopes::Department::SPtr dep = unity::scopes::Department::create(subdep.id, query(), name);
dep->set_has_subdepartments(subdep.has_children);
children.push_back(dep);
}
catch (const std::exception &e)
{
qWarning() << "Failed to create subdeparment:" << QString::fromStdString(e.what());
}
}
}
if (children.size() > 0)
{
const std::locale loc("");
children.sort([&loc](const unity::scopes::Department::SCPtr &d1, const unity::scopes::Department::SCPtr &d2) -> bool {
return loc(d1->label(), d2->label()) > 0;
});
current->set_subdepartments(children);
}
// if current is not the top, then gets its parent
if (current_dep_id != "")
{
auto const parent_dep_id = impl->depts_db->get_parent_department_id(current_dep_id);
root = unity::scopes::Department::create(parent_dep_id, query(), parent_dep_id == "" ? all_dept_name :
impl->depts_db->get_department_name(parent_dep_id, locales));
root->add_subdepartment(current);
}
else
{
root = current;
}
replyProxy->register_departments(root);
}
catch (const std::exception& e)
{
qWarning() << "Failed to push departments: " << QString::fromStdString(e.what());
}
}
void click::apps::Query::run(scopes::SearchReplyProxy const& searchReply)
{
const std::string categoryTemplate = CATEGORY_APPS_DISPLAY;
auto const current_dept = query().department_id();
auto const querystr = query().query_string();
const bool show_top_apps = querystr.empty() && current_dept.empty();
ResultPusher pusher(searchReply, show_top_apps ? impl->configuration.get_core_apps() : std::vector());
auto const ignoredApps = impl->configuration.get_ignored_apps();
auto const localResults = clickInterfaceInstance().find_installed_apps(querystr, ignoredApps, current_dept, impl->depts_db);
if (impl->depts_db)
{
push_local_departments(searchReply, localResults);
}
if (show_top_apps)
{
pusher.push_top_results(localResults, categoryTemplate);
}
const bool show_cat_title = current_dept.empty() && querystr.empty();
pusher.push_local_results(
localResults,
categoryTemplate,
show_cat_title);
add_fake_store_app(searchReply);
}
./scope/clickapps/apps-scope.cpp 0000644 0000156 0000165 00000016423 12676763604 016764 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include "apps-scope.h"
#include "apps-query.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace click;
click::Scope::Scope()
{
nam.reset(new click::network::AccessManager());
client.reset(new click::web::Client(nam));
index.reset(new click::Index(client));
pay_package.reset(new pay::Package(client));
try
{
depts_db = click::DepartmentsDb::open(false);
}
catch (const std::runtime_error& e)
{
std::cerr << "Failed to open departments db: " << e.what() << std::endl;
}
}
click::Scope::~Scope()
{
}
void click::Scope::start(std::string const&)
{
setlocale(LC_ALL, "");
bindtextdomain(GETTEXT_PACKAGE, GETTEXT_LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
click::Date::setup_system_locale();
}
void click::Scope::run()
{
static const int zero = 0;
auto emptyCb = [this]()
{
dm.reset(Ubuntu::DownloadManager::Manager::createSessionManager());
};
qt::core::world::build_and_run(zero, nullptr, emptyCb);
}
void click::Scope::stop()
{
qt::core::world::destroy();
}
scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata)
{
return scopes::SearchQueryBase::UPtr(new click::apps::Query(q, depts_db, metadata));
}
unity::scopes::PreviewQueryBase::UPtr click::Scope::preview(const unity::scopes::Result& result,
const unity::scopes::ActionMetadata& metadata) {
qDebug() << "Scope::preview() called.";
auto preview = new click::Preview(result, metadata);
preview->choose_strategy(client, pay_package, dm, depts_db);
return unity::scopes::PreviewQueryBase::UPtr{preview};
}
unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata,
std::string const& widget_id, std::string const& action_id)
{
if (action_id == click::Preview::Actions::CONFIRM_UNINSTALL) {
auto response = unity::scopes::ActivationResponse(unity::scopes::ActivationResponse::ShowDash);
return scopes::ActivationQueryBase::UPtr(new PerformUninstallAction(result, metadata, response));
}
auto activation = new ScopeActivation(result, metadata);
qDebug() << "perform_action called with action_id" << QString().fromStdString(action_id);
if (action_id == click::Preview::Actions::UNINSTALL_CLICK) {
activation->setHint(click::Preview::Actions::UNINSTALL_CLICK, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::CANCEL_PURCHASE_INSTALLED) {
activation->setHint(click::Preview::Actions::CANCEL_PURCHASE_INSTALLED, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::CANCEL_PURCHASE_UNINSTALLED) {
activation->setHint(click::Preview::Actions::CANCEL_PURCHASE_UNINSTALLED, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::SHOW_INSTALLED) {
activation->setHint(click::Preview::Actions::SHOW_INSTALLED, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::SHOW_UNINSTALLED) {
activation->setHint(click::Preview::Actions::SHOW_UNINSTALLED, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_UNINSTALLED) {
activation->setHint(click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_UNINSTALLED, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_INSTALLED) {
activation->setHint(click::Preview::Actions::CONFIRM_CANCEL_PURCHASE_INSTALLED, unity::scopes::Variant(true));
activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
} else if (action_id == click::Preview::Actions::RATED) {
scopes::VariantMap rating_info = metadata.scope_data().get_dict();
// Cast to int because widget gives us double, which is wrong.
int rating = ((int)rating_info["rating"].get_double());
std::string review_text = rating_info["review"].get_string();
// We have to get the values and then set them as hints here, to be
// able to pass them on to the Preview, which actually makes the
// call to submit.
activation->setHint("rating", scopes::Variant(rating));
activation->setHint("review", scopes::Variant(review_text));
activation->setHint(click::Preview::Actions::RATED,
scopes::Variant(true));
activation->setHint("widget_id", scopes::Variant(widget_id));
activation->setStatus(scopes::ActivationResponse::Status::ShowPreview);
}
return scopes::ActivationQueryBase::UPtr(activation);
}
#define EXPORT __attribute__ ((visibility ("default")))
extern "C"
{
EXPORT
unity::scopes::ScopeBase*
// cppcheck-suppress unusedFunction
UNITY_SCOPE_CREATE_FUNCTION()
{
return new click::Scope();
}
EXPORT
void
// cppcheck-suppress unusedFunction
UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base)
{
delete scope_base;
}
}
./scope/clickapps/CMakeLists.txt 0000644 0000156 0000165 00000002537 12676763577 016760 0 ustar jenkins jenkins SET (CMAKE_INCLUDE_CURRENT_DIR ON)
SET (CMAKE_AUTOMOC ON)
find_package (Qt5Core REQUIRED)
find_package (Qt5Sql REQUIRED)
pkg_check_modules(JSON_CPP REQUIRED jsoncpp)
add_definitions(
-DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"
-DGETTEXT_LOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LOCALEDIR}\"
-DSTORE_DATA_DIR="${STORE_DATA_DIR}"
)
add_library(${APPS_LIB_UNVERSIONED} SHARED
apps-query.cpp
apps-scope.cpp
)
set_target_properties(${APPS_LIB_UNVERSIONED} PROPERTIES PREFIX "")
include_directories(
${CMAKE_SOURCE_DIR}/libclickscope
${JSON_CPP_INCLUDE_DIRS}
)
qt5_use_modules (${APPS_LIB_UNVERSIONED} Network Sql)
target_link_libraries (${APPS_LIB_UNVERSIONED}
${SCOPE_LIB_NAME}
${JSON_CPP_LDFLAGS}
${UNITY_SCOPES_LDFLAGS}
${UBUNTUONE_LDFLAGS}
${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
)
install(
TARGETS ${APPS_LIB_UNVERSIONED}
LIBRARY DESTINATION "${APPS_LIB_DIR}"
)
set(APPS_INI_TARGET clickscope.ini)
configure_file(
${APPS_INI_TARGET}.in.in
${APPS_INI_TARGET}.in
)
add_custom_target(${APPS_INI_TARGET} ALL
COMMENT "Merging translations into ${APPS_INI_TARGET}"
COMMAND LC_ALL=C ${INTLTOOL_MERGE} -d -u ${CMAKE_SOURCE_DIR}/po ${APPS_INI_TARGET}.in ${APPS_INI_TARGET} >/dev/null
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/${APPS_INI_TARGET}"
DESTINATION "${APPS_LIB_DIR}"
)
./scope/clickapps/apps-query.h 0000644 0000156 0000165 00000007115 12676763577 016474 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#ifndef APPS_QUERY_H
#define APPS_QUERY_H
#include
namespace scopes = unity::scopes;
#include
#include
#include
#include
namespace click
{
class Application;
class Configuration;
class DepartmentsDb;
namespace apps
{
class Query : public scopes::SearchQueryBase
{
public:
struct ResultKeys
{
ResultKeys() = delete;
constexpr static const char* NAME{"name"};
constexpr static const char* DESCRIPTION{"description"};
constexpr static const char* MAIN_SCREENSHOT{"main_screenshot"};
constexpr static const char* INSTALLED{"installed"};
constexpr static const char* VERSION{"version"};
};
Query(unity::scopes::CannedQuery const& query, std::shared_ptr depts_db, scopes::SearchMetadata const& metadata);
virtual ~Query();
virtual void cancelled() override;
virtual void run(scopes::SearchReplyProxy const& reply) override;
virtual void add_fake_store_app(scopes::SearchReplyProxy const &replyProxy);
virtual void push_local_departments(scopes::SearchReplyProxy const& replyProxy, const std::vector& apps);
protected:
virtual click::Interface& clickInterfaceInstance();
private:
struct Private;
QSharedPointer impl;
};
class ResultPusher
{
const scopes::SearchReplyProxy &replyProxy;
std::vector core_apps;
std::unordered_set top_apps_lookup;
public:
ResultPusher(const scopes::SearchReplyProxy &replyProxy, const std::vector& core_apps);
virtual ~ResultPusher() = default;
virtual void push_local_results(const std::vector &apps,
const std::string& categoryTemplate,
bool show_title);
virtual void push_top_results(
const std::vector& apps,
const std::string& categoryTemplate);
protected:
virtual void push_result(scopes::Category::SCPtr& cat, const click::Application& a);
static std::string get_app_identifier(const click::Application& app);
};
} // namespace apps
} // namespace query
#endif // CLICK_QUERY_H
./scope/CMakeLists.txt 0000644 0000156 0000165 00000000121 12676763577 014772 0 ustar jenkins jenkins add_subdirectory(clickstore)
add_subdirectory(clickapps)
add_subdirectory(tests)
./scope/clickstore/ 0000755 0000156 0000165 00000000000 12676763604 014371 5 ustar jenkins jenkins ./scope/clickstore/store-query.h 0000644 0000156 0000165 00000011557 12676763577 017063 0 ustar jenkins jenkins /*
* Copyright (C) 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#ifndef STORE_QUERY_H
#define STORE_QUERY_H
#include
#include
namespace scopes = unity::scopes;
#include
#include
#include
#include
#include
#include
#include
namespace click
{
class Application;
class Index;
class DepartmentLookup;
class DepartmentsDb;
class Query : public scopes::SearchQueryBase
{
public:
struct ResultKeys
{
ResultKeys() = delete;
constexpr static const char* NAME{"name"};
constexpr static const char* DESCRIPTION{"description"};
constexpr static const char* MAIN_SCREENSHOT{"main_screenshot"};
constexpr static const char* INSTALLED{"installed"};
constexpr static const char* PURCHASED{"purchased"};
constexpr static const char* REFUNDABLE_UNTIL{"refundable_until"};
constexpr static const char* VERSION{"version"};
};
Query(unity::scopes::CannedQuery const& query,
click::Index& index,
click::DepartmentLookup& dept_lookup,
std::shared_ptr depts_db,
click::HighlightList& highlights,
scopes::SearchMetadata const& metadata,
pay::Package& in_package);
virtual ~Query();
virtual void cancelled() override;
virtual void run(scopes::SearchReplyProxy const& reply) override;
pay::PurchaseSet purchased_apps;
protected:
virtual unity::scopes::Department::SPtr fromClickDepartment(const click::Department::SCPtr click_dept, const std::string& current_dept_id, const click::DepartmentList& subdepts);
virtual unity::scopes::Department::SPtr populate_departments(const click::DepartmentList& depts, const std::string& current_department_id);
virtual void store_departments(const click::DepartmentList& depts);
virtual void push_departments(const scopes::SearchReplyProxy& searchReply, const scopes::Department::SCPtr& root);
virtual void push_departments(scopes::SearchReplyProxy const& searchReply);
virtual void add_highlights(scopes::SearchReplyProxy const& searchReply, const PackageSet& installedPackages);
virtual void add_available_apps(const scopes::SearchReplyProxy &searchReply, const PackageSet &installedPackages, const std::string &category);
virtual click::Interface& clickInterfaceInstance();
virtual PackageSet get_installed_packages();
virtual bool push_result(const scopes::SearchReplyProxy &searchReply, scopes::CategorisedResult const& res);
virtual void finished(const scopes::SearchReplyProxy &searchReply);
virtual scopes::Category::SCPtr register_category(scopes::SearchReplyProxy const& searchReply,
std::string const& id,
std::string const& title,
std::string const& icon,
scopes::CategoryRenderer const& renderer_template);
virtual void push_package(const scopes::SearchReplyProxy& searchReply, scopes::Category::SCPtr category, const PackageSet &locallyInstalledApps,
const click::Package& pkg);
virtual void push_highlights(const scopes::SearchReplyProxy& searchReply, const HighlightList& highlights, const PackageSet &locallyInstalledApps);
virtual void run_under_qt(const std::function &task);
private:
struct Private;
QSharedPointer impl;
};
}
#endif // CLICK_QUERY_H
./scope/clickstore/store-query.cpp 0000644 0000156 0000165 00000057227 12676763577 017422 0 ustar jenkins jenkins /*
* Copyright (C) 2014-2015 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include "store-query.h"
#include "store-scope.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include