#include "UniversalSwitchLog.hpp"
#include <memory>
-#include <vector>
-class Singleton
+class SingletonBase
{
protected:
- Singleton() = default;
- Singleton(const Singleton &) = delete;
- Singleton(Singleton &&) = delete;
- Singleton &operator = (const Singleton &) = delete;
- Singleton &operator = (Singleton &&) = delete;
+ SingletonBase() = default;
+ SingletonBase(const SingletonBase &) = delete;
+ SingletonBase(SingletonBase &&) = delete;
+ SingletonBase &operator = (const SingletonBase &) = delete;
+ SingletonBase &operator = (SingletonBase &&) = delete;
};
template <class Interface>
-class MockableSingleton : public Singleton
+class MockableSingleton : protected SingletonBase
{
public:
using InterfaceType = Interface;
static std::unique_ptr<InterfaceType> implementation;
};
-template<class MockableSingletonType>
-class CallbackHandlerKeeper
-{
-public:
- ~CallbackHandlerKeeper()
- {
- for (auto e : handlers)
- MockableSingletonType::instance().unregisterCb(e);
- }
-
- void add(typename MockableSingletonType::InterfaceType::CallbackHandle handler)
- {
- handlers.push_back(std::move(handler));
- }
-
-private:
- std::vector<typename MockableSingletonType::InterfaceType::CallbackHandle> handlers;
-};
-
#endif
-
#include "VConf.hpp"
+
#include <vconf.h>
#include <unordered_map>
+#include <tuple>
+#include <map>
+#include <limits>
namespace
{
template <class ValueType>
- using CallbackMap = std::unordered_map<int, std::function<void(ValueType)>>;
+ using CallbackMap = std::map<int, std::function<void(ValueType)>>;
template <class ValueType>
using KeyMap = std::unordered_map<std::string, CallbackMap<ValueType>>;
+ static std::string inCallbackKeyGuard;
- static int idxCount = 0;
+ static int idxCurrent = std::numeric_limits<int>::max();
static KeyMap<int> intCallbackMap;
static KeyMap<bool> boolCallbackMap;
static KeyMap<double> doubleCallbackMap;
template<class KeyMapType, class VconfCbType, class CallbackType>
inline int vconfRegisterKeyChangedCb(KeyMapType &keyMap, VconfCbType &vconfCb, const std::string &key, CallbackType &&callback)
{
- auto idx = ++idxCount;
+ auto idx = --idxCurrent;
auto iterator = keyMap.find(key);
if (iterator == keyMap.end()) {
iterator = keyMap.emplace(key, typename KeyMapType::mapped_type()).first;
}
if (iterator->second.erase(idx) != 1)
ERROR("Vconf: could not remove callback for key: %s with idx: %d", key.c_str(), idx);
- if (iterator->second.empty()) {
+ if (iterator->second.empty() && inCallbackKeyGuard != key) {
keyMap.erase(iterator);
if (vconf_ignore_key_changed(key.c_str(), vconfCb) != VCONF_OK) {
ERROR("Vconf: cant unregister callback for key: %s", key.c_str());
}
}
- template<class KeyMapType, class vconfGetType>
- inline void vconfCb(KeyMapType &keyMap, const vconfGetType &vconfGetFunction, const char *expectedType, int vconfType, keynode_t *keynode, void *data)
+
+
+ template<class KeyMapType, class VconfCbType, class vconfGetType>
+ inline void vconfCbRun(KeyMapType &keyMap, VconfCbType &vconfCb, const vconfGetType &vconfGetFunction, const char *expectedType, int vconfType, keynode_t *keynode, void *data)
{
+ std::string key = vconf_keynode_get_name(keynode);
if (vconf_keynode_get_type(keynode) != vconfType) {
- ERROR("vconf error: got '%s' changed with type: %d, expected type: %s", vconf_keynode_get_name(keynode), vconf_keynode_get_type(keynode), expectedType);
+ ERROR("vconf error: got '%s' changed with type: %d, expected type: %s", key.c_str(), vconf_keynode_get_type(keynode), expectedType);
return;
}
+ auto value = vconfGetFunction(keynode);
auto callbackMapPtr = (typename KeyMapType::mapped_type *)data;
- for (auto &idx : *callbackMapPtr) {
- auto &callback = idx.second;
- callback(vconfGetFunction(keynode));
+ ASSERT(!callbackMapPtr->empty(), "vconf error: no callbacks registered");
+
+ //we allow register and unregister callbacks during a callbeck call
+ {
+ //make sure we don't delete callbackMap during callbacks execution
+ inCallbackKeyGuard = key;
+ int idx = 0;
+ typename KeyMapType::mapped_type::iterator callbackIterator;
+ while ((callbackIterator = callbackMapPtr->upper_bound(idx)) != callbackMapPtr->end()) {
+ idx = callbackIterator->first;
+ auto callback = callbackIterator->second;
+ callback(value);
+ }
+ inCallbackKeyGuard.clear();
+ if (callbackMapPtr->empty()) {
+ //all callbacks removed
+ keyMap.erase(key);
+ if (vconf_ignore_key_changed(key.c_str(), vconfCb) != VCONF_OK) {
+ ERROR("Vconf: cant unregister callback for key: %s", key.c_str());
+ }
+ }
}
}
void vconfIntCb(keynode_t *key, void *data)
{
- vconfCb(intCallbackMap, vconf_keynode_get_int, "int", VCONF_TYPE_INT, key, data);
+ vconfCbRun(intCallbackMap, vconfIntCb, vconf_keynode_get_int, "int", VCONF_TYPE_INT, key, data);
}
void vconfBoolCb(keynode_t *key, void *data)
{
- vconfCb(boolCallbackMap, vconf_keynode_get_bool, "bool", VCONF_TYPE_BOOL, key, data);
+ vconfCbRun(boolCallbackMap, vconfBoolCb, vconf_keynode_get_bool, "bool", VCONF_TYPE_BOOL, key, data);
}
void vconfDoubleCb(keynode_t *key, void *data)
{
- vconfCb(doubleCallbackMap, vconf_keynode_get_dbl, "double", VCONF_TYPE_DOUBLE, key, data);
+ vconfCbRun(doubleCallbackMap, vconfDoubleCb, vconf_keynode_get_dbl, "double", VCONF_TYPE_DOUBLE, key, data);
}
void vconfStringCb(keynode_t *key, void *data)
{
- vconfCb(stringCallbackMap, vconf_keynode_get_str, "char*", VCONF_TYPE_STRING, key, data);
+ vconfCbRun(stringCallbackMap, vconfStringCb, vconf_keynode_get_str, "char*", VCONF_TYPE_STRING, key, data);
}
-
}
+
class VConfImpl : public VConfInterface
{
public:
+ enum class VConfRecordType {INT, BOOL, DOUBLE, STRING};
+
+ struct Handle : public HandleBase {
+ std::string key;
+ int callbackIdx;
+ VConfRecordType vconfRecordType;
+
+ Handle(std::string key, int callbackIdx, VConfRecordType vconfRecordType)
+ : key{std::move(key)}, callbackIdx{callbackIdx}, vconfRecordType{vconfRecordType}
+ {}
+
+ ~Handle() override
+ {
+ switch (vconfRecordType) {
+ case VConfRecordType::INT:
+ vconfUnregisterCb(intCallbackMap, vconfIntCb, key, callbackIdx);
+ break;
+ case VConfRecordType::BOOL:
+ vconfUnregisterCb(boolCallbackMap, vconfBoolCb, key, callbackIdx);
+ break;
+ case VConfRecordType::DOUBLE:
+ vconfUnregisterCb(doubleCallbackMap, vconfDoubleCb, key, callbackIdx);
+ break;
+ case VConfRecordType::STRING:
+ vconfUnregisterCb(stringCallbackMap, vconfStringCb, key, callbackIdx);
+ break;
+ }
+ }
+ };
int get(const std::string &key, int value) const override
{
CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(int)> callback) override
{
auto idx = vconfRegisterKeyChangedCb(intCallbackMap, vconfIntCb, key, std::move(callback));
- return std::make_tuple(key, idx, VConfRecordType::INT);
+ return CallbackHandle{ new Handle{key, idx, VConfRecordType::INT} };
}
CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(bool)> callback) override
{
auto idx = vconfRegisterKeyChangedCb(boolCallbackMap, vconfBoolCb, key, std::move(callback));
- return std::make_tuple(key, idx, VConfRecordType::BOOL);
+ return CallbackHandle{ new Handle{key, idx, VConfRecordType::BOOL} };
}
CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(double)> callback) override
{
auto idx = vconfRegisterKeyChangedCb(doubleCallbackMap, vconfDoubleCb, key, std::move(callback));
- return std::make_tuple(key, idx, VConfRecordType::DOUBLE);
+ return CallbackHandle{ new Handle{key, idx, VConfRecordType::DOUBLE} };
}
CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(std::string)> callback) override
{
auto idx = vconfRegisterKeyChangedCb(stringCallbackMap, vconfStringCb, key, std::move(callback));
- return std::make_tuple(key, idx, VConfRecordType::STRING);
- }
-
-
- void unregisterCb(const CallbackHandle &ch) override
- {
- auto &key = std::get<0>(ch);
- auto idx = std::get<1>(ch);
- switch (std::get<2>(ch)) {
- case VConfRecordType::INT:
- return vconfUnregisterCb(intCallbackMap, vconfIntCb, key, idx);
- case VConfRecordType::BOOL:
- return vconfUnregisterCb(boolCallbackMap, vconfBoolCb, key, idx);
- case VConfRecordType::DOUBLE:
- return vconfUnregisterCb(doubleCallbackMap, vconfDoubleCb, key, idx);
- case VConfRecordType::STRING:
- return vconfUnregisterCb(stringCallbackMap, vconfStringCb, key, idx);
- }
+ return CallbackHandle{ new Handle{key, idx, VConfRecordType::STRING} };
}
};
-
template<>
std::unique_ptr<VConfInterface> VConfSingleton::implementation = std::unique_ptr<VConfInterface>(new VConfImpl);
#ifndef VCONF_HPP
#define VCONF_HPP
+#include "UniversalSwitchLog.hpp"
#include "Singleton.hpp"
+
#include <string>
#include <functional>
-#include <tuple>
+#include <memory>
class VConfInterface
{
public:
- enum class VConfRecordType {INT, BOOL, DOUBLE, STRING};
- using CallbackHandle = std::tuple<std::string, int, VConfRecordType>;
+ struct HandleBase {
+ virtual ~HandleBase() = default;
+ };
+ using CallbackHandle = std::unique_ptr<HandleBase>;
virtual int get(const std::string &key, int defaultValue) const = 0;
virtual bool get(const std::string &key, bool defaultValue) const = 0;
virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(bool)>) = 0;
virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(double)>) = 0;
virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(std::string)>) = 0;
- virtual void unregisterCb(const CallbackHandle &cb) = 0;
template<class T>
inline CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(T)> callback)
return registerKeyChangedCb(key, callback);
}
+ template<class T>
+ CallbackHandle registerAndGet(const std::string &key, T defaultValue, std::function<void(T)> callback)
+ {
+ auto handle = registerKeyChangedCb(key, callback);
+ callback(get(key, defaultValue));
+ return handle;
+ }
};
using VConfSingleton = MockableSingleton<VConfInterface>;
#include "VConf.hpp"
#include <gtest/gtest.h>
#include <glib.h>
+#include <iostream>
void restoreDefault()
TEST(VconfImplTest, registerKeyChangedCb_int)
{
INFO("registerKeyChangedCb_int");
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", testCallback);
+ auto h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", testCallback);
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 132);
});
EXPECT_EQ(testCallbackValue, 132);
- VConfSingleton::instance().unregisterCb(h);
-
}
TEST(VconfImplTest, registerKeyChangedCb_int_lambda)
{
int v = 0;
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ int count = 0;
+ auto h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
v = x;
+ count++;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 133);
});
EXPECT_EQ(v, 133);
- VConfSingleton::instance().unregisterCb(h);
-
+ EXPECT_EQ(count, 1);
}
TEST(VconfImplTest, registerKeyChangedCb_bool_lambda)
{
bool v = false;
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<bool>("VconfImplTest/int/20", [&](bool x) {
+ int count = 0;
+ auto h = VConfSingleton::instance().registerKeyChangedCb<bool>("VconfImplTest/int/20", [&](bool x) {
v = x;
+ count++;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", true);
VConfSingleton::instance().set("VconfImplTest/int/20", false);
});
EXPECT_EQ(v, false);
- VConfSingleton::instance().unregisterCb(h);
+ EXPECT_EQ(count, 2);
}
TEST(VconfImplTest, registerKeyChangedCb_double_lambda)
{
double v = 0.0;
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<double>("VconfImplTest/int/20", [&](double x) {
+ auto h = VConfSingleton::instance().registerKeyChangedCb<double>("VconfImplTest/int/20", [&](double x) {
v = x;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 13.6);
});
EXPECT_EQ(v, 13.6);
- VConfSingleton::instance().unregisterCb(h);
}
TEST(VconfImplTest, registerKeyChangedCb_string_lambda)
{
std::string v;
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<std::string>("VconfImplTest/int/20", [&](std::string x) {
+ auto h = VConfSingleton::instance().registerKeyChangedCb<std::string>("VconfImplTest/int/20", [&](std::string x) {
v = x;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", std::string("foo2"));
});
EXPECT_EQ(v, "foo2");
- VConfSingleton::instance().unregisterCb(h);
}
TEST(VconfImplTest, registerKeyChangedCb_int_unregister)
{
int v = 0;
+ int count = 0;
{
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ auto h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
v = x;
+ count++;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 1);
VConfSingleton::instance().set("VconfImplTest/int/20", 2);
});
EXPECT_EQ(v, 2);
- VConfSingleton::instance().unregisterCb(h);
}
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 3);
});
EXPECT_EQ(v, 2);
+ EXPECT_EQ(count, 2);
}
TEST(VconfImplTest, registerKeyChangedCb_int_unregister_2x)
{
+ int count = 0;
{
int v = 0;
{
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ auto h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
v = x;
+ count++;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 11);
VConfSingleton::instance().set("VconfImplTest/int/20", 12);
});
EXPECT_EQ(v, 12);
- VConfSingleton::instance().unregisterCb(h);
}
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 13);
{
int v = 0;
{
- VConfInterface::CallbackHandle h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ auto h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
v = x;
+ count++;
});
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 21);
VConfSingleton::instance().set("VconfImplTest/int/20", 22);
});
EXPECT_EQ(v, 22);
- VConfSingleton::instance().unregisterCb(h);
}
eventLoop::run([]() {
VConfSingleton::instance().set("VconfImplTest/int/20", 23);
EXPECT_EQ(v, 22);
}
- restoreDefault();
+ EXPECT_EQ(count, 4);
}
bool b = false;
double v = 0.0;
std::string s("empty");
+ int count1 = 0, count2 = 0, count3 = 0, count4 = 0;
- VConfInterface::CallbackHandle h1 = VConfSingleton::instance().registerKeyChangedCb<bool>("VconfImplTest/int/20", [&](bool x) {
+ auto h1 = VConfSingleton::instance().registerKeyChangedCb<bool>("VconfImplTest/int/20", [&](bool x) {
b = x;
+ count1++;
});
- VConfInterface::CallbackHandle h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ auto h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
i = x;
+ count2++;
});
- VConfInterface::CallbackHandle h3 = VConfSingleton::instance().registerKeyChangedCb<double>("VconfImplTest/int/20", [&](double x) {
+ auto h3 = VConfSingleton::instance().registerKeyChangedCb<double>("VconfImplTest/int/20", [&](double x) {
v = x;
+ count3++;
});
- VConfInterface::CallbackHandle h4 = VConfSingleton::instance().registerKeyChangedCb<std::string>("VconfImplTest/int/20", [&](std::string x) {
+ auto h4 = VConfSingleton::instance().registerKeyChangedCb<std::string>("VconfImplTest/int/20", [&](std::string x) {
s = x;
+ count4++;
});
eventLoop::run([]() {
EXPECT_EQ(v, 20.2);
EXPECT_EQ(s, "foo");
- VConfSingleton::instance().unregisterCb(h1);
- VConfSingleton::instance().unregisterCb(h2);
- VConfSingleton::instance().unregisterCb(h3);
- VConfSingleton::instance().unregisterCb(h4);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 1);
+ EXPECT_EQ(count3, 1);
+ EXPECT_EQ(count4, 1);
+
+}
+
+TEST(VconfImplTest, registerKeyChangedCb_unregisterInCallback)
+{
+ int v = 0;
+ int count = 0;
+ VConfInterface::CallbackHandle h;
+ h = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v = x;
+ count++;
+ h.reset();
+ });
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 13);
+ });
+ EXPECT_EQ(v, 13);
+ EXPECT_EQ(count, 1);
+ EXPECT_EQ(h, nullptr);
+}
+
+TEST(VconfImplTest, registerKeyChangedCb_unregisterSecondInCallback)
+{
+ int v1 = 1, v2 = 2, v3 = 3;
+ int count1 = 0, count2 = 0, count3 = 0;
+ VConfInterface::CallbackHandle h1, h2, h3;
+ h1 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v1 = x;
+ count1++;
+ });
+ h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v2 = x;
+ count2++;
+ });
+ h3 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v3 = x;
+ h2.reset();
+ count3++;
+ });
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 14);
+ });
+ EXPECT_EQ(v1, 14);
+ EXPECT_EQ(v2, 2);
+ EXPECT_EQ(v3, 14);
+ EXPECT_NE(h1, nullptr);
+ EXPECT_EQ(h2, nullptr);
+ EXPECT_NE(h3, nullptr);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 0);
+ EXPECT_EQ(count3, 1);
+}
+
+
+TEST(VconfImplTest, registerKeyChangedCb_registerInCallback)
+{
+ int v1 = 1, v2 = 2;
+ int count1 = 0, count2 = 0;
+
+ VConfInterface::CallbackHandle h1, h2;
+ h1 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v1 = x;
+ count1++;
+ h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v2 = x;
+ count2++;
+ });
+ });
+ EXPECT_EQ(h2, nullptr);
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 15);
+ });
+ EXPECT_EQ(v1, 15);
+ EXPECT_EQ(v2, 2);
+ EXPECT_NE(h2, nullptr);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 0);
+
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 16);
+ });
+
+ EXPECT_EQ(v1, 16);
+ EXPECT_EQ(v2, 16);
+ EXPECT_EQ(count1, 2);
+ EXPECT_EQ(count2, 1);
+}
+
+TEST(VconfImplTest, registerKeyChangedCb_unregisterAndRegisterInCallback)
+{
+ int v1 = 1, v2 = 2;
+ int count1 = 0, count2 = 0;
+ VConfInterface::CallbackHandle h1, h2;
+ h1 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v1 = x;
+ count1++;
+ h1.reset();
+ h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v2 = x;
+ count2++;
+ });
+ });
+ EXPECT_EQ(h2, nullptr);
+ eventLoop::run([&]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 115);
+ });
+ EXPECT_NE(h2, nullptr);
+ EXPECT_EQ(v1, 115);
+ EXPECT_EQ(v2, 2);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 0);
+ eventLoop::run([&]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 116);
+ });
+ EXPECT_EQ(v1, 115);
+ EXPECT_EQ(v2, 116);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 1);
+
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 117);
+ });
+
+ EXPECT_EQ(v1, 115);
+ EXPECT_EQ(v2, 117);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 2);
+}
+
+TEST(VconfImplTest, registerKeyChangedCb_registerAndUnregisterInCallback)
+{
+ int v1 = 1, v2 = 2;
+ int count1 = 0, count2 = 0;
+ VConfInterface::CallbackHandle h1, h2;
+ h1 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v1 = x;
+ count1++;
+ h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v2 = x;
+ count2++;
+ });
+ h1.reset();
+ });
+ EXPECT_EQ(h2, nullptr);
+ eventLoop::run([&]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 115);
+ });
+ EXPECT_NE(h2, nullptr);
+ EXPECT_EQ(v1, 115);
+ EXPECT_EQ(v2, 2);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 0);
+ eventLoop::run([&]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 116);
+ });
+ EXPECT_EQ(v1, 115);
+ EXPECT_EQ(v2, 116);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 1);
+
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 117);
+ });
+
+ EXPECT_EQ(v1, 115);
+ EXPECT_EQ(v2, 117);
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 2);
+}
+
+
+TEST(VconfImplTest, registerKeyChangedCb_callbackOrder)
+{
+ int v = 1;
+ int count1 = 0, count2 = 0, count3 = 0;
+ VConfInterface::CallbackHandle h1, h2, h3;
+ h1 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v += 2;
+ v *= 3;
+ count1++;
+ });
+ h2 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v += 5;
+ v *= 7;
+ count2++;
+ });
+ h3 = VConfSingleton::instance().registerKeyChangedCb<int>("VconfImplTest/int/20", [&](int x) {
+ v += 11;
+ v *= 13;
+ count3++;
+ });
+ eventLoop::run([]() {
+ VConfSingleton::instance().set("VconfImplTest/int/20", 14);
+ });
+ EXPECT_EQ(v, (((((1 + 11) * 13) + 5) * 7) + 2) * 3); //calbacks are called in reverse order
+ EXPECT_EQ(count1, 1);
+ EXPECT_EQ(count2, 1);
+ EXPECT_EQ(count3, 1);
+}
+
+
+TEST(VconfImplTest, registerKeyChangedCb_restoreDefault)
+{
restoreDefault();
}
+