diff options
author | Kevin Smith <git@kismith.co.uk> | 2012-03-01 08:03:50 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2012-03-03 09:00:30 (GMT) |
commit | fde71bd59b1412ae475c06f2d4100ce088e86af6 (patch) | |
tree | 4f3d85c700942d666c5ac5d032c757bc45bb1593 /Swift/Controllers/Settings | |
parent | 5271144cb6c0ecf3dc237af25197fa72a8737c09 (diff) | |
download | swift-contrib-fde71bd59b1412ae475c06f2d4100ce088e86af6.zip swift-contrib-fde71bd59b1412ae475c06f2d4100ce088e86af6.tar.bz2 |
Unit tests for SettingsProviderHierachy
Also fixing up errors they found and an uninitialised read left-over from the original patch.
Diffstat (limited to 'Swift/Controllers/Settings')
7 files changed, 138 insertions, 10 deletions
diff --git a/Swift/Controllers/Settings/DummySettingsProvider.h b/Swift/Controllers/Settings/DummySettingsProvider.h index bb7d2e6..1d6059f 100644 --- a/Swift/Controllers/Settings/DummySettingsProvider.h +++ b/Swift/Controllers/Settings/DummySettingsProvider.h @@ -7,46 +7,53 @@ #pragma once #include <Swift/Controllers/Settings/SettingsProvider.h> #include <map> namespace Swift { class DummySettingsProvider : public SettingsProvider { public: virtual ~DummySettingsProvider() {} virtual std::string getSetting(const Setting<std::string>& setting) { return stringValues.find(setting.getKey()) != stringValues.end() ? stringValues[setting.getKey()] : setting.getDefaultValue(); }; virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) { stringValues[setting.getKey()] = value; onSettingChanged(setting.getKey()); }; virtual bool getSetting(const Setting<bool>& setting) { return boolValues.find(setting.getKey()) != boolValues.end() ? boolValues[setting.getKey()] : setting.getDefaultValue(); }; virtual void storeSetting(const Setting<bool>& setting, const bool& value) { boolValues[setting.getKey()] = value; onSettingChanged(setting.getKey()); }; virtual int getSetting(const Setting<int>& setting) { return intValues.find(setting.getKey()) != intValues.end() ? intValues[setting.getKey()] : setting.getDefaultValue(); }; virtual void storeSetting(const Setting<int>& setting, const int& value) { intValues[setting.getKey()] = value; onSettingChanged(setting.getKey()); }; virtual std::vector<std::string> getAvailableProfiles() {return std::vector<std::string>();} virtual void createProfile(const std::string& ) {} virtual void removeProfile(const std::string& ) {} - virtual bool getIsSettingFinal(const std::string& ) {return false;} + virtual bool getIsSettingFinal(const std::string& settingPath) {return finals.count(settingPath);} + void setFinal(const std::string& settingPath) { + finals.insert(settingPath); + } + virtual bool hasSetting(const std::string& key) { + return stringValues.find(key) != stringValues.end() || intValues.find(key) != intValues.end() || boolValues.find(key) != boolValues.end(); + } private: std::map<std::string, std::string> stringValues; std::map<std::string, int> intValues; std::map<std::string, bool> boolValues; + std::set<std::string> finals; }; } diff --git a/Swift/Controllers/Settings/SettingsProvider.h b/Swift/Controllers/Settings/SettingsProvider.h index e884add..458653b 100644 --- a/Swift/Controllers/Settings/SettingsProvider.h +++ b/Swift/Controllers/Settings/SettingsProvider.h @@ -23,51 +23,52 @@ class SettingsProvider { } const std::string& getKey() const { return key; } const T& getDefaultValue() const { return defaultValue; } private: std::string key; T defaultValue; }; public: virtual ~SettingsProvider() {} virtual std::string getSetting(const Setting<std::string>& setting) = 0; virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) = 0; virtual bool getSetting(const Setting<bool>& setting) = 0; virtual void storeSetting(const Setting<bool>& setting, const bool& value) = 0; virtual int getSetting(const Setting<int>& setting) = 0; virtual void storeSetting(const Setting<int>& setting, const int& value) = 0; virtual std::vector<std::string> getAvailableProfiles() = 0; virtual void createProfile(const std::string& profile) = 0; virtual void removeProfile(const std::string& profile) = 0; /** A final setting is one that this settings provider says may not be overriden by lower priority profiles. * e.g. An Administrator-set configuration to disallow saving user passwords could not be overridden by the user. */ template<typename T> bool getIsSettingFinal(const Setting<T>& setting) { return getIsSettingFinal(setting.getKey()); } + virtual bool hasSetting(const std::string& key) = 0; friend class SettingsProviderHierachy; protected: virtual bool getIsSettingFinal(const std::string& settingPath) = 0; public: /** * Emitted when a setting is changed. */ boost::signal<void (const std::string& /*Setting's Path*/)> onSettingChanged; }; } diff --git a/Swift/Controllers/Settings/SettingsProviderHierachy.cpp b/Swift/Controllers/Settings/SettingsProviderHierachy.cpp index 3b7d13c..40a9025 100644 --- a/Swift/Controllers/Settings/SettingsProviderHierachy.cpp +++ b/Swift/Controllers/Settings/SettingsProviderHierachy.cpp @@ -1,90 +1,111 @@ /* * Copyright (c) 2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swift/Controllers/Settings/SettingsProviderHierachy.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/Log.h> namespace Swift { SettingsProviderHierachy::~SettingsProviderHierachy() { } +bool SettingsProviderHierachy::hasSetting(const std::string& key) { + foreach (SettingsProvider* provider, providers_) { + if (provider->hasSetting(key)) { + return true; + } + } + return false; +} + std::string SettingsProviderHierachy::getSetting(const Setting<std::string>& setting) { + std::string value = setting.getDefaultValue(); foreach (SettingsProvider* provider, providers_) { std::string providerSetting = provider->getSetting(setting); - if (providerSetting != setting.getDefaultValue()) { - return providerSetting; + if (provider->hasSetting(setting.getKey())) { + value = providerSetting; + } + if (provider->getIsSettingFinal(setting.getKey())) { + return value; } } - return setting.getDefaultValue(); + return value; } void SettingsProviderHierachy::storeSetting(const Setting<std::string>& setting, const std::string& settingValue) { if (!getIsSettingFinal(setting.getKey())) { getWritableProvider()->storeSetting(setting, settingValue); } } bool SettingsProviderHierachy::getSetting(const Setting<bool>& setting) { + bool value = setting.getDefaultValue(); foreach (SettingsProvider* provider, providers_) { bool providerSetting = provider->getSetting(setting); - if (providerSetting != setting.getDefaultValue()) { - return providerSetting; + if (provider->hasSetting(setting.getKey())) { + value = providerSetting; + if (provider->getIsSettingFinal(setting.getKey())) { + return providerSetting; + } } } - return setting.getDefaultValue(); + return value; } void SettingsProviderHierachy::storeSetting(const Setting<bool>& setting, const bool& settingValue) { if (!getIsSettingFinal(setting.getKey())) { getWritableProvider()->storeSetting(setting, settingValue); } } int SettingsProviderHierachy::getSetting(const Setting<int>& setting) { + int value = setting.getDefaultValue(); foreach (SettingsProvider* provider, providers_) { int providerSetting = provider->getSetting(setting); - if (providerSetting != setting.getDefaultValue()) { - return providerSetting; + if (provider->hasSetting(setting.getKey())) { + value = providerSetting; + if (provider->getIsSettingFinal(setting.getKey())) { + return providerSetting; + } } } - return setting.getDefaultValue(); + return value; } void SettingsProviderHierachy::storeSetting(const Setting<int>& setting, const int& settingValue) { if (!getIsSettingFinal(setting.getKey())) { getWritableProvider()->storeSetting(setting, settingValue); } } std::vector<std::string> SettingsProviderHierachy::getAvailableProfiles() { /* Always pull profiles from the topmost */ return getWritableProvider()->getAvailableProfiles(); } void SettingsProviderHierachy::createProfile(const std::string& profile) { return getWritableProvider()->createProfile(profile); } void SettingsProviderHierachy::removeProfile(const std::string& profile) { return getWritableProvider()->removeProfile(profile); } bool SettingsProviderHierachy::getIsSettingFinal(const std::string& settingPath) { bool isFinal = false; foreach (SettingsProvider* provider, providers_) { isFinal |= provider->getIsSettingFinal(settingPath); } return isFinal; } SettingsProvider* SettingsProviderHierachy::getWritableProvider() { return providers_.back(); } void SettingsProviderHierachy::addProviderToTopOfStack(SettingsProvider* provider) { providers_.push_back(provider); diff --git a/Swift/Controllers/Settings/SettingsProviderHierachy.h b/Swift/Controllers/Settings/SettingsProviderHierachy.h index b7f6961..b16b33e 100644 --- a/Swift/Controllers/Settings/SettingsProviderHierachy.h +++ b/Swift/Controllers/Settings/SettingsProviderHierachy.h @@ -1,46 +1,47 @@ /* * Copyright (c) 2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <Swift/Controllers/Settings/SettingsProvider.h> namespace Swift { class SettingsProviderHierachy : public SettingsProvider { public: virtual ~SettingsProviderHierachy(); virtual std::string getSetting(const Setting<std::string>& setting); virtual void storeSetting(const Setting<std::string>& setting, const std::string& value); virtual bool getSetting(const Setting<bool>& setting); virtual void storeSetting(const Setting<bool>& setting, const bool& value); virtual int getSetting(const Setting<int>& setting); virtual void storeSetting(const Setting<int>& setting, const int& value); virtual std::vector<std::string> getAvailableProfiles(); virtual void createProfile(const std::string& profile); virtual void removeProfile(const std::string& profile); + virtual bool hasSetting(const std::string& key); protected: virtual bool getIsSettingFinal(const std::string& settingPath); public: /** * Adds a provider less significant than any already added. * This means that if an existing provider has a setting, this provider won't be asked. * Any settings will be pushed into the topmost (least significant) provider. * Does not take ownership of provider. */ void addProviderToTopOfStack(SettingsProvider* provider); private: SettingsProvider* getWritableProvider(); private: /* Start/Left is most significant (lowest), left overrides right.*/ std::vector<SettingsProvider*> providers_; }; } diff --git a/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp b/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp new file mode 100644 index 0000000..aa4d14f --- /dev/null +++ b/Swift/Controllers/Settings/UnitTest/SettingsProviderHierachyTest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swift/Controllers/Settings/SettingsProviderHierachy.h> +#include <Swift/Controllers/Settings/DummySettingsProvider.h> +#include <Swift/Controllers/Settings/XMLSettingsProvider.h> + +using namespace Swift; +using namespace std; + +class SettingsProviderHierachyTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(SettingsProviderHierachyTest); + CPPUNIT_TEST(testEmpty); + CPPUNIT_TEST(testTop); + CPPUNIT_TEST(testBottom); + CPPUNIT_TEST(testBoth); + CPPUNIT_TEST(testTopDefault); + CPPUNIT_TEST(testBottomOverrides); + CPPUNIT_TEST(testFinal); + CPPUNIT_TEST_SUITE_END(); + +public: + SettingsProviderHierachyTest() : setting1("somekey", 42) {}; + + void setUp() { + bottom = new DummySettingsProvider(); + top = new DummySettingsProvider(); + testling = new SettingsProviderHierachy(); + testling->addProviderToTopOfStack(bottom); + testling->addProviderToTopOfStack(top); + } + + void tearDown() { + delete testling; + delete top; + delete bottom; + } + + void testEmpty() { + CPPUNIT_ASSERT_EQUAL(42, testling->getSetting(setting1)); + } + + void testTop() { + top->storeSetting(setting1, 37); + CPPUNIT_ASSERT_EQUAL(37, testling->getSetting(setting1)); + } + + void testBottom() { + bottom->storeSetting(setting1, 17); + CPPUNIT_ASSERT_EQUAL(17, testling->getSetting(setting1)); + } + + void testBoth() { + bottom->storeSetting(setting1, 17); + top->storeSetting(setting1, 37); + CPPUNIT_ASSERT_EQUAL(37, testling->getSetting(setting1)); + } + + void testTopDefault() { + bottom->storeSetting(setting1, 17); + top->storeSetting(setting1, 42); + CPPUNIT_ASSERT_EQUAL(42, testling->getSetting(setting1)); + } + + void testBottomOverrides() { + bottom->storeSetting(setting1, 17); + bottom->setFinal(setting1.getKey()); + top->storeSetting(setting1, 5); + CPPUNIT_ASSERT_EQUAL(17, testling->getSetting(setting1)); + } + + void testFinal() { + bottom->storeSetting(setting1, 17); + bottom->setFinal(setting1.getKey()); + testling->storeSetting(setting1, 5); + CPPUNIT_ASSERT_EQUAL(17, testling->getSetting(setting1)); + } +private: + SettingsProviderHierachy* testling; + DummySettingsProvider* bottom; + DummySettingsProvider* top; + SettingsProvider::Setting<int> setting1; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SettingsProviderHierachyTest); diff --git a/Swift/Controllers/Settings/XMLSettingsProvider.cpp b/Swift/Controllers/Settings/XMLSettingsProvider.cpp index 3710072..e83ed24 100644 --- a/Swift/Controllers/Settings/XMLSettingsProvider.cpp +++ b/Swift/Controllers/Settings/XMLSettingsProvider.cpp @@ -4,70 +4,75 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swift/Controllers/Settings/XMLSettingsProvider.h> #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> #include <Swiften/Parser/PlatformXMLParserFactory.h> #include <Swiften/Parser/XMLParser.h> #include <Swiften/Base/Log.h> namespace Swift { XMLSettingsProvider::XMLSettingsProvider(const std::string& xmlConfig) : level_(0) { if (!xmlConfig.empty()) { PlatformXMLParserFactory factory; XMLParser* parser = factory.createXMLParser(this); if (parser->parse(xmlConfig)) { SWIFT_LOG(debug) << "Found and parsed system config" << std::endl; } else { SWIFT_LOG(debug) << "Found invalid system config" << std::endl; } delete parser; } else { SWIFT_LOG(debug) << "No system config found" << std::endl; } } XMLSettingsProvider::~XMLSettingsProvider() { } +bool XMLSettingsProvider::hasSetting(const std::string& key) { + return (values_.find(key) != values_.end()); +} + + std::string XMLSettingsProvider::getSetting(const Setting<std::string>& setting) { if (values_.find(setting.getKey()) != values_.end()) { std::string value = values_[setting.getKey()]; return value; } return setting.getDefaultValue(); } void XMLSettingsProvider::storeSetting(const Setting<std::string>& /*settingPath*/, const std::string& /*settingValue*/) { assert(false); } bool XMLSettingsProvider::getSetting(const Setting<bool>& setting) { if (values_.find(setting.getKey()) != values_.end()) { std::string value = values_[setting.getKey()]; return boost::iequals(value, "true") || value == "1"; } return setting.getDefaultValue(); } void XMLSettingsProvider::storeSetting(const Setting<bool>& /*settingPath*/, const bool& /*settingValue*/) { assert(false); } int XMLSettingsProvider::getSetting(const Setting<int>& setting) { if (values_.find(setting.getKey()) != values_.end()) { std::string value = values_[setting.getKey()]; try { return value.empty() ? setting.getDefaultValue() : boost::lexical_cast<int>(value);; } catch(boost::bad_lexical_cast &) {} } return setting.getDefaultValue(); } diff --git a/Swift/Controllers/Settings/XMLSettingsProvider.h b/Swift/Controllers/Settings/XMLSettingsProvider.h index 61abd11..e03d3c1 100644 --- a/Swift/Controllers/Settings/XMLSettingsProvider.h +++ b/Swift/Controllers/Settings/XMLSettingsProvider.h @@ -1,56 +1,58 @@ /* * Copyright (c) 2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swiften/Parser/XMLParserClient.h> #include <map> #include <set> namespace Swift { class XMLSettingsProvider : public SettingsProvider, public XMLParserClient { public: XMLSettingsProvider(const std::string& xmlConfig); virtual ~XMLSettingsProvider(); virtual std::string getSetting(const Setting<std::string>& setting); virtual void storeSetting(const Setting<std::string>& setting, const std::string& value); virtual bool getSetting(const Setting<bool>& setting); virtual void storeSetting(const Setting<bool>& setting, const bool& value); virtual int getSetting(const Setting<int>& setting); virtual void storeSetting(const Setting<int>& setting, const int& value); virtual std::vector<std::string> getAvailableProfiles(); virtual void createProfile(const std::string& profile); virtual void removeProfile(const std::string& profile); + virtual bool hasSetting(const std::string& key); + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); virtual void handleEndElement(const std::string& element, const std::string& ns); virtual void handleCharacterData(const std::string& data); protected: virtual bool getIsSettingFinal(const std::string& settingPath); private: std::map<std::string /*settingPath*/, std::string /*settingValue*/> values_; /* Settings that are final*/ std::set<std::string /*settingPath*/> finals_; enum Level { TopLevel = 0, SettingLevel = 2 }; int level_; std::string currentElement_; std::string currentText_; }; } |