diff --git a/parameter/BitParameterType.cpp b/parameter/BitParameterType.cpp index 9992f9188..88040e449 100644 --- a/parameter/BitParameterType.cpp +++ b/parameter/BitParameterType.cpp @@ -127,7 +127,7 @@ bool CBitParameterType::toBlackboard(const string& strValue, uint64_t& uiValue, strStream << "Value " << strValue << " standing out of admitted range ["; - if (CUtility::isHexadecimal(strValue)) { + if (utility::isHexadecimal(strValue)) { strStream << "0x0, " << "0x" << std::hex << std::uppercase; } else { diff --git a/parameter/BooleanParameterType.cpp b/parameter/BooleanParameterType.cpp index 41a5c6e1a..cfbe45af0 100644 --- a/parameter/BooleanParameterType.cpp +++ b/parameter/BooleanParameterType.cpp @@ -59,7 +59,7 @@ bool CBooleanParameterType::toBlackboard(const std::string& strValue, uint32_t& } else { parameterAccessContext.setError(strValue + " value not part of numerical space {"); - if (CUtility::isHexadecimal(strValue)) { + if (utility::isHexadecimal(strValue)) { parameterAccessContext.appendToError("0x0, 0x1"); } else { diff --git a/parameter/ConfigurableDomain.cpp b/parameter/ConfigurableDomain.cpp index 956ef8e8d..cfdd3c584 100644 --- a/parameter/ConfigurableDomain.cpp +++ b/parameter/ConfigurableDomain.cpp @@ -301,7 +301,7 @@ bool CConfigurableDomain::parseConfigurableElements(const CXmlElement& xmlElemen core::Results infos; if (!addConfigurableElement(pConfigurableElement, NULL, infos)) { - CUtility::asString(infos, strError); + strError = utility::asString(infos); serializingContext.setError(strError); return false; diff --git a/parameter/FixedPointParameterType.cpp b/parameter/FixedPointParameterType.cpp index 7e056d9a0..fa3b13b06 100644 --- a/parameter/FixedPointParameterType.cpp +++ b/parameter/FixedPointParameterType.cpp @@ -116,7 +116,7 @@ bool CFixedPointParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerial bool CFixedPointParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const { - bool bValueProvidedAsHexa = CUtility::isHexadecimal(strValue); + bool bValueProvidedAsHexa = utility::isHexadecimal(strValue); // Check data integrity if (bValueProvidedAsHexa && !parameterAccessContext.valueSpaceIsRaw()) { @@ -161,7 +161,7 @@ void CFixedPointParameterType::setOutOfRangeError(const string& strValue, CParam strStream << "raw range ["; - if (CUtility::isHexadecimal(strValue)) { + if (utility::isHexadecimal(strValue)) { // Format Min strStream << "0x" << std::hex << std::uppercase << diff --git a/parameter/FloatingPointParameterType.cpp b/parameter/FloatingPointParameterType.cpp index 777399bc6..750dc8130 100644 --- a/parameter/FloatingPointParameterType.cpp +++ b/parameter/FloatingPointParameterType.cpp @@ -121,7 +121,7 @@ bool CFloatingPointParameterType::toBlackboard( CParameterAccessContext& parameterAccessContext) const { // Check Value integrity - if (CUtility::isHexadecimal(strValue) && !parameterAccessContext.valueSpaceIsRaw()) { + if (utility::isHexadecimal(strValue) && !parameterAccessContext.valueSpaceIsRaw()) { parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() @@ -198,7 +198,7 @@ void CFloatingPointParameterType::setOutOfRangeError( uint32_t uiMin = reinterpret_cast(_fMin); uint32_t uiMax = reinterpret_cast(_fMax); - if (CUtility::isHexadecimal(strValue)) { + if (utility::isHexadecimal(strValue)) { ostrStream << std::showbase << std::hex << std::setw(getSize() * 2) << std::setfill('0'); diff --git a/parameter/IntegerParameterType.cpp b/parameter/IntegerParameterType.cpp index 0efc0d09c..a9934eb2e 100644 --- a/parameter/IntegerParameterType.cpp +++ b/parameter/IntegerParameterType.cpp @@ -140,7 +140,7 @@ bool CIntegerParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializi bool CIntegerParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const { // Hexa - bool bValueProvidedAsHexa = CUtility::isHexadecimal(strValue); + bool bValueProvidedAsHexa = utility::isHexadecimal(strValue); // Get integer value from the string provided int64_t iData; diff --git a/parameter/MappingData.cpp b/parameter/MappingData.cpp index dbf7a12be..264e7fc7c 100644 --- a/parameter/MappingData.cpp +++ b/parameter/MappingData.cpp @@ -91,11 +91,7 @@ bool CMappingData::getValue(const std::string& strkey, const std::string*& pStrV std::string CMappingData::asString() const { - std::string strValue; - - CUtility::asString(_keyToValueMap, strValue, ", ", ":"); - - return strValue; + return utility::asString(_keyToValueMap, ", ", ":"); } bool CMappingData::addValue(const std::string& strkey, const std::string& strValue) diff --git a/parameter/ParameterMgr.cpp b/parameter/ParameterMgr.cpp index fc25b445f..1ded347de 100644 --- a/parameter/ParameterMgr.cpp +++ b/parameter/ParameterMgr.cpp @@ -811,7 +811,7 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::statusCommandProces // Show status /// General section - CUtility::appendTitle(strResult, "General:"); + utility::appendTitle(strResult, "General:"); // System class strResult += "System Class: "; strResult += pSystemClass->getName(); @@ -838,25 +838,23 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::statusCommandProces strResult += "\n"; /// Subsystem list - CUtility::appendTitle(strResult, "Subsystems:"); + utility::appendTitle(strResult, "Subsystems:"); string strSubsystemList; pSystemClass->listChildrenPaths(strSubsystemList); strResult += strSubsystemList; /// Last applied configurations - CUtility::appendTitle(strResult, "Last Applied [Pending] Configurations:"); + utility::appendTitle(strResult, "Last Applied [Pending] Configurations:"); string strLastAppliedConfigurations; getConfigurableDomains()->listLastAppliedConfigurations(strLastAppliedConfigurations); strResult += strLastAppliedConfigurations; /// Criteria states - CUtility::appendTitle(strResult, "Selection Criteria:"); + utility::appendTitle(strResult, "Selection Criteria:"); list lstrSelectionCriteria; getSelectionCriteria()->listSelectionCriteria(lstrSelectionCriteria, false, true); // Concatenate the criterion list as the command result - string strCriteriaStates; - CUtility::asString(lstrSelectionCriteria, strCriteriaStates); - strResult += strCriteriaStates; + strResult += utility::asString(lstrSelectionCriteria); return CCommandHandler::ESucceeded; } @@ -1028,7 +1026,7 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::listCriteriaCommand getSelectionCriteria()->listSelectionCriteria(lstrResult, true, bHumanReadable); // Concatenate the criterion list as the command result - CUtility::asString(lstrResult, strResult); + strResult += utility::asString(lstrResult); return CCommandHandler::ESucceeded; } @@ -1165,7 +1163,7 @@ CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::restoreConfiguratio core::Results result; if (!restoreConfiguration(remoteCommand.getArgument(0), remoteCommand.getArgument(1), result)) { //Concatenate the error list as the command result - CUtility::asString(result, strResult); + strResult = utility::asString(result); return CCommandHandler::EFailed; } @@ -1859,7 +1857,7 @@ bool CParameterMgr::sync(string& strError) core::Results error; if (! syncerSet.sync(*_pMainParameterBlackboard, false, &error)){ - CUtility::asString(error, strError); + strError = utility::asString(error); return false; }; @@ -2058,7 +2056,7 @@ bool CParameterMgr::addConfigurableElementToDomain(const string& strDomain, cons warning() << infos; } - CUtility::asString(infos, strError); + strError = utility::asString(infos); return isSuccess; } @@ -2126,7 +2124,7 @@ bool CParameterMgr::split(const string& strDomain, const string& strConfigurable warning() << infos; } - CUtility::asString(infos, strError); + strError = utility::asString(infos); return isSuccess; } diff --git a/parameter/SelectionCriterion.cpp b/parameter/SelectionCriterion.cpp index 256d35ffd..18ceb34ce 100644 --- a/parameter/SelectionCriterion.cpp +++ b/parameter/SelectionCriterion.cpp @@ -134,7 +134,7 @@ std::string CSelectionCriterion::getFormattedDescription(bool bWithTypeInfo, boo if (bWithTypeInfo) { // Display type info - CUtility::appendTitle(strFormattedDescription, getName() + ":"); + utility::appendTitle(strFormattedDescription, getName() + ":"); // States strFormattedDescription += "Possible states "; diff --git a/parameter/SystemClass.cpp b/parameter/SystemClass.cpp index a30286cc2..56f04f123 100644 --- a/parameter/SystemClass.cpp +++ b/parameter/SystemClass.cpp @@ -99,7 +99,7 @@ bool CSystemClass::loadSubsystems(string& strError, // Fill strError for caller, he has to decide if there is a problem depending on // bVirtualSubsystemFallback value - CUtility::asString(errors, strError); + strError = utility::asString(errors); return bLoadPluginsSuccess || bVirtualSubsystemFallback; } @@ -151,10 +151,8 @@ bool CSystemClass::loadSubsystemsFromSharedLibraries(core::Results& errors, if (!lstrPluginFiles.empty()) { // Unable to load at least one plugin - string strPluginUnloaded; - CUtility::asString(lstrPluginFiles, strPluginUnloaded, ", "); - - errors.push_back("Unable to load the following plugins: " + strPluginUnloaded + "."); + errors.push_back("Unable to load the following plugins: " + + utility::asString(lstrPluginFiles, ", ") + "."); return false; } diff --git a/parameter/log/include/log/LogWrapper.h b/parameter/log/include/log/LogWrapper.h index 79980c7ab..0c635ba6b 100644 --- a/parameter/log/include/log/LogWrapper.h +++ b/parameter/log/include/log/LogWrapper.h @@ -100,9 +100,8 @@ class LogWrapper */ LogWrapper& operator<<(const std::list& logs) { - std::string formatedLogs; std::string separator = "\n" + mProlog; - CUtility::asString(logs, formatedLogs, separator); + std::string formatedLogs = utility::asString(logs, separator); // Check if there is something in the log to know if we have to add a prefix if (!mLog.str().empty() && mLog.str()[mLog.str().length() - 1] == separator[0]) { diff --git a/remote-processor/RemoteCommandHandlerTemplate.h b/remote-processor/RemoteCommandHandlerTemplate.h index 16b6a72c3..b17f34331 100644 --- a/remote-processor/RemoteCommandHandlerTemplate.h +++ b/remote-processor/RemoteCommandHandlerTemplate.h @@ -208,17 +208,11 @@ class TRemoteCommandHandlerTemplate : public IRemoteCommandHandler std::string strUsage = pRemoteCommandParserItem->usage(); - strResult += strUsage; - // Align size_t spacesToAdd = _maxCommandUsageLength + 5 - strUsage.length(); - while (spacesToAdd--) { - - strResult += " "; - } - - strResult += std::string("=> ") + std::string(pRemoteCommandParserItem->getDescription()) + "\n"; + strResult += strUsage + std::string(spacesToAdd, ' ') + "=> " + + pRemoteCommandParserItem->getDescription() + '\n'; } } diff --git a/test/test-platform/main.cpp b/test/test-platform/main.cpp index 66746de18..c35cfac18 100644 --- a/test/test-platform/main.cpp +++ b/test/test-platform/main.cpp @@ -102,9 +102,7 @@ int main(int argc, char *argv[]) // All arguments should have been consumed if (not options.empty()) { - std::string extraArgs; - CUtility::asString(options, extraArgs); - showInvalidUsage("Unexpected extra arguments: " + extraArgs); + showInvalidUsage("Unexpected extra arguments: " + utility::asString(options)); return 3; } diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt index e87148277..0741b82ac 100644 --- a/utility/CMakeLists.txt +++ b/utility/CMakeLists.txt @@ -52,3 +52,12 @@ install(FILES Utility.h convert.hpp DESTINATION "include/utility") + +if(BUILD_TESTING) + # Add unit test + add_executable(utilityUnitTest test/utility.cpp) + + target_link_libraries(utilityUnitTest pfw_utility catch) + add_test(NAME utilityUnitTest + COMMAND utilityUnitTest) +endif() diff --git a/utility/Utility.cpp b/utility/Utility.cpp index 3ce6318aa..56e276751 100644 --- a/utility/Utility.cpp +++ b/utility/Utility.cpp @@ -32,61 +32,46 @@ #include #include -#include +#include using std::string; +namespace utility +{ + // Format string list -void CUtility::asString(const std::list& lstr, - std::string& strOutput, +std::string asString(const std::list& lstr, const std::string& strSeparator) { - std::ostringstream ostrFormatedList; - - std::copy(lstr.begin(), lstr.end(), - std::ostream_iterator(ostrFormatedList, strSeparator.c_str())); - - strOutput = ostrFormatedList.str(); - - // Remove last separator - if (strOutput.size() > strSeparator.size()) { - - strOutput.erase(strOutput.size() - strSeparator.size()); - } + return join(begin(lstr), end(lstr), + [strSeparator](string acc, string right) { + return acc + strSeparator + right; + }); } // Format string map -void CUtility::asString(const std::map& mapStr, - std::string& strOutput, - const std::string& strItemSeparator, - const std::string& strKeyValueSeparator) +std::string asString(const std::map& mapStr, + const std::string& strItemSeparator, + const std::string& strKeyValueSeparator) { std::list listKeysValues; - std::map::const_iterator iter; - - for(iter = mapStr.begin(); iter != mapStr.end(); ++iter) { - - listKeysValues.push_back(iter->first + strKeyValueSeparator + iter->second); + for (const auto & item: mapStr) { + listKeysValues.emplace_back(item.first + strKeyValueSeparator + item.second); } - CUtility::asString(listKeysValues, strOutput, strItemSeparator); + return asString(listKeysValues, strItemSeparator); } -void CUtility::appendTitle(string& strTo, const string& strTitle) +void appendTitle(string& strTo, const string& strTitle) { - strTo += "\n" + strTitle + "\n"; - - size_t uiLength = strTitle.size(); - - while (uiLength--) { - - strTo += "="; - } - strTo += "\n"; + strTo += "\n" + strTitle + "\n" + + string(strTitle.size(), '=') + "\n"; } -bool CUtility::isHexadecimal(const string& strValue) +bool isHexadecimal(const string& strValue) { return (strValue.compare(0, 2, "0x") == 0) or (strValue.compare(0, 2, "0X") == 0); } + +} // namespace utility diff --git a/utility/Utility.h b/utility/Utility.h index 38afc2937..55e5f0737 100644 --- a/utility/Utility.h +++ b/utility/Utility.h @@ -34,47 +34,64 @@ #include #include #include +#include -class CUtility +namespace utility { -public: - /** - * Format the items of a map into a string as a list of key-value pairs. The map must be - * composed of pairs of strings. - * - * @param[in] mapStr A map of strings - * @param[out] strOutput The output string - * @param[in] separator The separator to use between each item - */ - static void asString(const std::list& lstr, - std::string& strOutput, - const std::string& separator = "\n"); - /** - * Format the items of a map into a string as a list of key-value pairs. The map must be - * composed of pairs of strings. - * - * @param[in] mapStr A map of strings - * @param[out] strOutput The output string - * @param[in] strItemSeparator The separator to use between each item (key-value pair) - * @param[in] strKeyValueSeparator The separator to use between key and value - */ - static void asString(const std::map& mapStr, - std::string& strOutput, - const std::string& strItemSeparator = ", ", - const std::string& strKeyValueSeparator = ":"); +/** Join all elements in [first, last[ with op. + * + * If their is no element to join, return empty. + * + * @example let op = [](auto l, auto r){ return l + "|" + r; } + * let [first, last[ = list{"1", "2", "3"} + * then join(first, last, op) == "1|2|3" + */ +template +T join(InputIt first, InputIt last, BinaryOperation op, T empty = T{}) +{ + if (first == last) { return empty; } + auto init = *first++; + + return std::accumulate(first, last, init, op); +} + +/** +* Format the items of a map into a string as a list of key-value pairs. The map must be +* composed of pairs of strings. +* +* @param[in] mapStr A map of strings +* @param[in] separator The separator to use between each item +* +* @return the concatenated elements. +*/ +std::string asString(const std::list& lstr, + const std::string& separator = "\n"); - /** Utility to underline */ - static void appendTitle(std::string& strTo, const std::string& strTitle); +/** + * Format the items of a map into a string as a list of key-value pairs. The map must be + * composed of pairs of strings. + * + * @param[in] mapStr A map of strings + * @param[out] strOutput The output string + * @param[in] strItemSeparator The separator to use between each item (key-value pair) + * @param[in] strKeyValueSeparator The separator to use between key and value + */ +std::string asString(const std::map& mapStr, + const std::string& strItemSeparator = ", ", + const std::string& strKeyValueSeparator = ":"); + +/** Utility to underline */ +void appendTitle(std::string& strTo, const std::string& strTitle); - /** - * Checks if a string has the written representation of an hexadecimal - * number (Which is the prefix "0x" or "0X" in C++). - * - * @param[in] strValue value as string - * - * @return true if the string is written as hexa, false otherwise. - */ - static bool isHexadecimal(const std::string& strValue); +/** + * Checks if a string has the written representation of an hexadecimal + * number (Which is the prefix "0x" or "0X" in C++). + * + * @param[in] strValue value as string + * + * @return true if the string is written as hexa, false otherwise. + */ +bool isHexadecimal(const std::string& strValue); -}; +} // utility diff --git a/utility/test/utility.cpp b/utility/test/utility.cpp new file mode 100644 index 000000000..fe514302e --- /dev/null +++ b/utility/test/utility.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2011-2014, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Utility.h" + +#include +#include +#include + +using std::list; +using std::string; + +namespace utility +{ + +SCENARIO("join") { + struct Test + { + list input; + std::function binaryOpt; + int empty; + int result; + int resultNoEmpty; + }; + const list tests = + { + {{}, nullptr, 21, 21, 0}, + {{5}, nullptr, -1, 5, 5}, + {{5, 2}, [](int, int){return 73;}, -1, 73, 73}, + {{2, 3, 7}, [](int l, int r){return l * r ;}, -1, 42, 42}, + {{1, 10, 100}, [](int l, int r){return l + r ;}, -1, 111, 111} + }; + for (auto &test : tests) { + CAPTURE(Catch::toString(test.input)); + const auto &first = begin(test.input); + const auto &last = end(test.input); + REQUIRE(join(first, last, test.binaryOpt, test.empty) == test.result); + REQUIRE(join(first, last, test.binaryOpt) == test.resultNoEmpty); + } +} + + +SCENARIO("asString(list)") { + struct Test + { + string title; + list input; + string separator; + string result; + string resultNoSep; + }; + const list tests = + { + {"Empty list", {}, "aa", "", ""}, + {"One element", {"a"}, "<>", "a", "a"}, + {"Three elem list", {"1", "2", "3"}, "**", "1**2**3", "1\n2\n3"}, + {"No separator", {"12", "ab", "+-"}, "", "12ab+-", "12\nab\n+-"}, + {"empty elem list", {"a", "b", "", "d"}, "|", "a|b||d", "a\nb\n\nd"}, + }; + for (auto &test : tests) { + CAPTURE(Catch::toString(test.input)); + WHEN("Separator, " + test.title) { + CAPTURE(test.separator); + REQUIRE(asString(test.input, test.separator) == test.result); + } + THEN("No separator, " + test.title) { + REQUIRE(asString(test.input) == test.resultNoSep); + } + } +} + +SCENARIO("asString(map)") { + using std::map; + + using Map = map; + struct Test + { + Map input; + string itemSep; + string keyValueSep; + string result; + string resultNoKeyValueSep; + string resultNoSep; + }; + const list tests = + { + {{}, "itemSep", "keyValueSep", "", "", ""}, + { Map{{"a", "b"}, + {"c", "d"}, + {"e", "f"}}, // input + " - ", "\n", // item & keyValue sep + "a - b\nc - d\ne - f", //result + "a:b\nc:d\ne:f", //resultNoKeyValueSep + "a:b, c:d, e:f" //resultNoSep + } + }; + for (const auto &test : tests) { + CAPTURE(Catch::toString(test.input)); + CAPTURE(test.keyValueSep); + CAPTURE(test.itemSep); + REQUIRE(asString(test.input, test.keyValueSep, test.itemSep) == test.result); + REQUIRE(asString(test.input, test.keyValueSep) == test.resultNoKeyValueSep); + REQUIRE(asString(test.input) == test.resultNoSep); + } + +} + +SCENARIO("appendTitle") { + struct Test + { + string initial; + string title; + string result; + }; + const list tests = + { + {"", "abc", "\nabc\n===\n"}, + {"start", "title", "start\ntitle\n=====\n"} + }; + for (auto &test : tests) { + auto quote = [](std::string toQuote) { return '"' + toQuote + '"'; }; + + GIVEN("A title: " + quote(test.title)) { + CAPTURE(test.initial); + CAPTURE(test.title); + + WHEN("Appending to: " + quote(test.initial)) { + string output = test.initial; + THEN("Result should be:\n" + quote(test.result)) { + appendTitle(output, test.title); + CHECK(output == test.result); + } + } + } + } +} + +SCENARIO("isNotHexadecimal") { + for (auto &str : {"a", "0", "012", "13", "ABC", "Oxa"}) { + CAPTURE(str); + CHECK(not isHexadecimal(str)); + } +} + +SCENARIO("isHexadecimal") { + for (auto str : {"0xa", "0X0", "0x012", "0x13", "0xConsider as hexa as starting with 0x"}) { + CAPTURE(str); + CHECK(isHexadecimal(str)); + } +} + +} // namespace utility