diff --git a/doc/tutorials/validation.md b/doc/tutorials/validation.md index 0e8101e8c80..5ae1438822c 100644 --- a/doc/tutorials/validation.md +++ b/doc/tutorials/validation.md @@ -310,26 +310,26 @@ Only string keys are validated! Binary keys are skipped! ```sh # mount test config file and set a value -sudo kdb mount testvalidate.ini /tests/validate range dump -kdb set user:/tests/validate/x 10 +sudo kdb mount range.ecf /tests/range range dump -# add range check to value -kdb meta-set spec:/tests/validate/x check/range "1-10" +# set value +kdb set user:/tests/range/value 5 + +# add range check to all keys under /tests/range/ +kdb meta-set spec:/tests/range/_ check/range "1-10" # check if validate passes -kdb validate /tests/validate +kdb validate /tests/range -# change allowed range -kdb meta-set -f spec:/tests/validate/x check/range "1-5" +# set new key to invalid value (with kdb set -f) +kdb set -f user:/tests/range/value2 11 # validation fails now -kdb validate /tests/validate +kdb validate /tests/range # RET:1 # clean up -kdb rm -r /tests/validate -sudo kdb umount /tests/validate - -$end +kdb rm -r /tests/range/ +sudo kdb umount /tests/range ``` \ No newline at end of file diff --git a/src/libs/tools/include/errors/baseNotification.hpp b/src/libs/tools/include/errors/baseNotification.hpp index af2908d5682..cc94ab4400b 100644 --- a/src/libs/tools/include/errors/baseNotification.hpp +++ b/src/libs/tools/include/errors/baseNotification.hpp @@ -64,9 +64,6 @@ class BaseNotification protected: BaseNotification () = default; - /* Can be overwritten by subclasses to change the text representation */ - std::ostream& toString (std::ostream& outputStream) const; - /** * @brief Compare to another notification object * @@ -80,6 +77,21 @@ class BaseNotification */ virtual bool compare(const BaseNotification& other) const; + /* Can be overwritten by subclasses to change the text representation */ + + /** + * @brief Get a text representation of the notification. + * + * Is used in operator<<. + * Can be overloaded by subclasses to append additional text. + * + * @param outputStream The stream to append the text to, + * used by the operator `<<` + * + * @return The given stream with additional text appended. + */ + virtual std::ostream& toString (std::ostream& outputStream) const; + private: std::string m_reason; std::string m_module; diff --git a/src/libs/tools/include/errors/error.hpp b/src/libs/tools/include/errors/error.hpp index 649dd11dc55..1bd23987d0d 100644 --- a/src/libs/tools/include/errors/error.hpp +++ b/src/libs/tools/include/errors/error.hpp @@ -65,6 +65,22 @@ class Error : public BaseNotification * @return true if objects are equal */ bool compare(const BaseNotification& other) const override; + + /** + * @brief Create a text representation of the Error + * + * A string that contains the text representation + * defined by baseNotification.cpp as well as the + * text representation of all warnings that the + * Error object contains appended to the given stream. + * + * @param outputStream The stream were the string representations + * should be appended. + * + * @return The given stream with the created string + * written to it. + */ + std::ostream & toString (std::ostream & outputStream) const override; }; } // namespace errors } // namespace tools diff --git a/src/libs/tools/include/errors/errorTypes.hpp b/src/libs/tools/include/errors/errorTypes.hpp index d66f46a4a7b..18f09221227 100644 --- a/src/libs/tools/include/errors/errorTypes.hpp +++ b/src/libs/tools/include/errors/errorTypes.hpp @@ -1,7 +1,6 @@ #ifndef ELEKTRA_ERRORTYPES_HPP #define ELEKTRA_ERRORTYPES_HPP - #include "error.hpp" namespace kdb diff --git a/src/libs/tools/src/errors/baseNotification.cpp b/src/libs/tools/src/errors/baseNotification.cpp index 96a06cf99d2..e3213641f96 100644 --- a/src/libs/tools/src/errors/baseNotification.cpp +++ b/src/libs/tools/src/errors/baseNotification.cpp @@ -30,14 +30,14 @@ void BaseNotification::setData (const std::string & reason, const std::string & /* String representation */ std::ostream& BaseNotification::toString (std::ostream & outputStream) const { - return outputStream << "Code: " << code() - << "\nDescription: " << description() - << "\nReason: " << m_reason - << "\nModule: " << m_module - << "\nFile: " << m_file - << "\nMount point: " << m_mountPoint - << "\nConfig file: " << m_configFile - << "\nLine: " << std::to_string (m_line); + return outputStream << "Code: " << code () << std::endl + << "Description: " << description () << std::endl + << "Reason: " << m_reason << std::endl + << "Module: " << m_module << std::endl + << "File: " << m_file << std::endl + << "Mount point: " << m_mountPoint << std::endl + << "Config file: " << m_configFile << std::endl + << "Line: " << std::to_string (m_line); } std::ostream& operator <<(std::ostream& outputStream, const BaseNotification& eb) @@ -53,15 +53,15 @@ bool BaseNotification::compare(const BaseNotification& other ELEKTRA_UNUSED) con bool BaseNotification::operator== (const BaseNotification& other) const { - return code() == other.code() - && description() == other.description() - && reason() == other.reason() - && module() == other.module() - && file() == other.file() - && mountPoint() == other.mountPoint() - && configFile() == other.configFile() - && line() == other.line() - && this->compare(other); + return code () == other.code () + && description () == other.description () + && reason () == other.reason () + && module () == other.module () + && file () == other.file () + && mountPoint () == other.mountPoint () + && configFile () == other.configFile () + && line () == other.line () + && this->compare (other); } bool BaseNotification::operator!= (const BaseNotification& other) const @@ -70,12 +70,12 @@ bool BaseNotification::operator!= (const BaseNotification& other) const } /* setters */ -std::string& BaseNotification::reason() { return m_reason; } -std::string& BaseNotification::module() { return m_module; } -std::string& BaseNotification::file() { return m_file; } -std::string& BaseNotification::mountPoint() { return m_mountPoint; } -std::string& BaseNotification::configFile() { return m_configFile; } -kdb::long_t& BaseNotification::line() { return m_line; } +std::string & BaseNotification::reason() { return m_reason; } +std::string & BaseNotification::module() { return m_module; } +std::string & BaseNotification::file() { return m_file; } +std::string & BaseNotification::mountPoint() { return m_mountPoint; } +std::string & BaseNotification::configFile() { return m_configFile; } +kdb::long_t & BaseNotification::line() { return m_line; } /* getters */ const std::string & BaseNotification::reason () const { return m_reason; } diff --git a/src/libs/tools/src/errors/error.cpp b/src/libs/tools/src/errors/error.cpp index 61638f867d0..490989f6627 100644 --- a/src/libs/tools/src/errors/error.cpp +++ b/src/libs/tools/src/errors/error.cpp @@ -48,18 +48,17 @@ bool Error::compare(const BaseNotification& other) const else { /* compare warnings */ - for (Warning *w : warnings) + for (const Warning *w : warnings) { - /*TODO: Decide if ordering of warnings should be considered for equality. - * Currently two errors are equal if they contain the same warnings (compared by member values), - * even if they have different orders in the internal vector.*/ + /* Two errors are equal if they contain the same warnings (compared by member values), + * even if they have different orders in the internal vector. */ - /*TODO: Currently copies of warnings are stored by the addWarning(Warning&) method. + /* TODO: Currently copies of warnings are stored by the addWarning(Warning&) method. * If we decide to store the original warnings, then we have to decide if * two different Warnings (not the same address in mem) are considered equal - * if the member values are equal.*/ + * if the member values are equal. */ bool equalWarningFound = false; - for (Warning *ow : pOtherError->warnings) + for (const Warning *ow : pOtherError->warnings) { if (*w == *ow) { @@ -83,6 +82,22 @@ Error::~Error () delete w; } +std::ostream & Error::toString (std::ostream & outputStream) const +{ + BaseNotification::toString (outputStream); + + kdb::long_t i = 0; + if (warnings.size() > 0) + { + outputStream << std::endl << std::endl << "The following warnings were attachted to the Error: " << std::endl << std::endl; + for (const Warning *w : warnings) + outputStream << "Warning " << ++i << ": " << std::endl << *w << std::endl; + } + + + return outputStream; +} + } // namespace errors } // namespace tools diff --git a/src/tools/kdb/validate.cpp b/src/tools/kdb/validate.cpp index e971c6863b5..83763a71612 100644 --- a/src/tools/kdb/validate.cpp +++ b/src/tools/kdb/validate.cpp @@ -7,12 +7,11 @@ */ #include - #include #include -#include #include #include +#include /* for removeNamespace (Key) */ using namespace std; using namespace kdb; @@ -39,37 +38,38 @@ int ValidateCommand::execute (Cmdline const & cl) throw invalid_argument ("1 argument needed"); } - cout << "The given path was: " << cl.arguments[0] << endl; - KeySet ksUnfiltered; + /* use the given cmd line argument as the start key */ Key root = cl.createKey (0); - /* if -f (force) was given, the namespace is kept - * and check-constraints in the spec:/ namespace - * are not considered --> the key can be set to a - * value that does not pass the validation criteria, - * otherwise a cascading key is created for the - * following kdb.get() */ - // Key parentKey = cl.getParentKey (root); + if (cl.verbose) + { + cout << "The name of the root key is: " + root.getName() << endl; + } + + /* Remove namespace -> create cascading key, so that + * check-constraints in the spec:/ namespace are considered. */ + Key parentKey = removeNamespace (root); // do not resume on any get errors // otherwise the user might break // the config kdb.get (ksUnfiltered, root); - stringstream streamWarnings; - //printWarnings (streamWarnings, root, cl.verbose, cl.debug); + /* Convert result of kdb.get to Error object of the C++ errors/warnings API */ + tools::errors::Error *result = tools::errors::ErrorFactory::fromKey (root); - string strWarnings = streamWarnings.str (); - if (strWarnings.empty ()) //TODO: currently not working (always as with -f) because of disabled printWarnings above + /* If no warnings or errors occurred, the ErrorFactory returns a nullptr. */ + if (result) { - cout << getFormattedSuccessString ("No warnings were issued! :)") << endl; - } - else - { - cerr << strWarnings; - root.clear (); + cout << getFormattedInfoString ("The following warnings were issued while" + " trying to get the values of the keys: ") << endl << endl; + + cerr << *result << endl << endl; + + /* After printing the Warnings, the object is no longer needed. */ + delete result; if (cl.force) { @@ -77,9 +77,6 @@ int ValidateCommand::execute (Cmdline const & cl) "Because -f was given, we now try to set the values " "despite warnings during getting them...") << endl; - - // TODO: Check how to handle, printWarnings consumed the warnings - //root = cl.createKey (0); } else { @@ -87,10 +84,13 @@ int ValidateCommand::execute (Cmdline const & cl) "The validation was stopped because of warnings " "while getting the values!") << endl; - kdb.close (); return 1; } } + else + { + cout << getFormattedSuccessString ("No warnings were issued! :)") << endl; + } KeySet ksPart (ksUnfiltered.cut (root)); @@ -118,36 +118,36 @@ int ValidateCommand::execute (Cmdline const & cl) try { kdb.set (ksPart, root); - }catch (KDBException & k) { - /* TODO: remove test code & refactor to use new c++ classes for whole function (instead of printWarnigns and printError) */ - std::cout << std::endl << "################" << std::endl << "TEST NEW C++ CLASS:" << std::endl; - tools::errors::Error *err = tools::errors::ErrorFactory::fromKey (root); - std::cout << *err << std::endl << "INCLUDED WARNINGS: " << std::endl; - for (tools::errors::Warning *w : *err) - std::cout << *w << std::endl << "---------------" << std::endl; - delete err; - std::cout << "err deleted!" << std::endl << "################" << std::endl << std::endl; + return 0; + } + catch (KDBException & k) + { + cout << getFormattedInfoString ("The following error was issued while trying to set the values back: ") << endl << endl; + result = tools::errors::ErrorFactory::fromKey (root); + cerr << *result << endl; + delete result; + return 1; } - - printWarnings (streamWarnings, root, cl.verbose, cl.debug); - printError (cerr, root, cl.verbose, cl.debug); - - kdb.close (); - return 0; } std::string ValidateCommand::getFormattedErrorString (const std::string & str) { - return getErrorColor (ANSI_COLOR::BOLD) + getErrorColor (ANSI_COLOR::MAGENTA) + str + getErrorColor (ANSI_COLOR::RESET); + return getErrorColor (ANSI_COLOR::BOLD) + + getErrorColor (ANSI_COLOR::MAGENTA) + str + + getErrorColor (ANSI_COLOR::RESET); } std::string ValidateCommand::getFormattedSuccessString (const std::string & str) { - return getStdColor (ANSI_COLOR::BOLD) + getStdColor (ANSI_COLOR::GREEN) + str + getStdColor (ANSI_COLOR::RESET); + return getStdColor (ANSI_COLOR::BOLD) + + getStdColor (ANSI_COLOR::GREEN) + str + + getStdColor (ANSI_COLOR::RESET); } std::string ValidateCommand::getFormattedInfoString (const std::string & str) { - return getStdColor (ANSI_COLOR::BOLD) + getStdColor (ANSI_COLOR::YELLOW) + str + getStdColor (ANSI_COLOR::RESET); + return getStdColor (ANSI_COLOR::BOLD) + + getStdColor (ANSI_COLOR::YELLOW) + str + + getStdColor (ANSI_COLOR::RESET); }