From e45abaa84c01e6925e2e3601026035f381c019d0 Mon Sep 17 00:00:00 2001 From: Sourabh Mehta <73165318+soumeh01@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:14:29 +0200 Subject: [PATCH] [projmgr] csolution option --context-set inconsistency * [projmgr] csolution option --context-set inconsistency * Added tests --- tools/projmgr/include/ProjMgr.h | 1 + tools/projmgr/include/ProjMgrWorker.h | 6 + tools/projmgr/include/ProjMgrYamlEmitter.h | 4 +- tools/projmgr/src/ProjMgr.cpp | 108 +++++++++++------- tools/projmgr/src/ProjMgrWorker.cpp | 72 +++++++++--- tools/projmgr/src/ProjMgrYamlEmitter.cpp | 18 ++- .../novalid_context.csolution.yml | 4 - tools/projmgr/test/src/ProjMgrUnitTests.cpp | 67 +++++++++-- 8 files changed, 192 insertions(+), 88 deletions(-) diff --git a/tools/projmgr/include/ProjMgr.h b/tools/projmgr/include/ProjMgr.h index 5663dbcad..de2525599 100644 --- a/tools/projmgr/include/ProjMgr.h +++ b/tools/projmgr/include/ProjMgr.h @@ -169,6 +169,7 @@ class ProjMgr { bool Configure(); bool GenerateYMLConfigurationFiles(); void updateRte(); + bool ParseAndValidateContexts(); }; #endif // PROJMGR_H diff --git a/tools/projmgr/include/ProjMgrWorker.h b/tools/projmgr/include/ProjMgrWorker.h index 4032b5747..43d5e2dfb 100644 --- a/tools/projmgr/include/ProjMgrWorker.h +++ b/tools/projmgr/include/ProjMgrWorker.h @@ -590,6 +590,12 @@ class ProjMgrWorker { const std::vector& contextSelection, const bool checkCbuildSet = false); + /** + * @brief get the list of selected contexts + * @return list of selected contexts + */ + std::vector GetSelectedContexts() const; + /** * @brief check if context is selected * @param context name diff --git a/tools/projmgr/include/ProjMgrYamlEmitter.h b/tools/projmgr/include/ProjMgrYamlEmitter.h index 09bb21602..57e2c1e0e 100644 --- a/tools/projmgr/include/ProjMgrYamlEmitter.h +++ b/tools/projmgr/include/ProjMgrYamlEmitter.h @@ -67,13 +67,13 @@ class ProjMgrYamlEmitter { /** * @brief generate cbuild set file - * @param contexts vector with pointers to contexts + * @param contexts list of selected contexts * @param selectedCompiler name of the selected compiler * @param cbuildSetFile path to *.cbuild-set file to be generated * @param boolean check schema of generated file * @return true if executed successfully */ - static bool GenerateCbuildSet(const std::vector contexts, + static bool GenerateCbuildSet(const std::vector selectedContexts, const std::string& selectedCompiler, const std::string& cbuildSetFile, bool checkSchema); /** diff --git a/tools/projmgr/src/ProjMgr.cpp b/tools/projmgr/src/ProjMgr.cpp index 67e3a71a0..95ab9086e 100644 --- a/tools/projmgr/src/ProjMgr.cpp +++ b/tools/projmgr/src/ProjMgr.cpp @@ -166,16 +166,16 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) { {"update-rte", { false, {context, contextSet, debug, load, quiet, schemaCheck, toolchain, verbose, frozenPacks}}}, {"convert", { false, {context, contextSet, debug, exportSuffix, load, quiet, schemaCheck, noUpdateRte, output, outputAlt, toolchain, verbose, frozenPacks, cbuild2cmake}}}, {"run", { false, {context, contextSet, debug, generator, load, quiet, schemaCheck, verbose, dryRun}}}, - {"list packs", { true, {context, debug, filter, load, missing, quiet, schemaCheck, toolchain, verbose, relativePaths}}}, - {"list boards", { true, {context, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, - {"list devices", { true, {context, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, - {"list configs", { true, {context, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, - {"list components", { true, {context, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, - {"list dependencies", { false, {context, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, + {"list packs", { true, {context, contextSet, debug, filter, load, missing, quiet, schemaCheck, toolchain, verbose, relativePaths}}}, + {"list boards", { true, {context, contextSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, + {"list devices", { true, {context, contextSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, + {"list configs", { true, {context, contextSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, + {"list components", { true, {context, contextSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, + {"list dependencies", { false, {context, contextSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, {"list contexts", { false, {debug, filter, quiet, schemaCheck, verbose, ymlOrder}}}, - {"list generators", { false, {context, debug, load, quiet, schemaCheck, toolchain, verbose}}}, - {"list layers", { false, {context, debug, load, clayerSearchPath, quiet, schemaCheck, toolchain, verbose, updateIdx}}}, - {"list toolchains", { false, {context, debug, quiet, toolchain, verbose}}}, + {"list generators", { false, {context, contextSet, debug, load, quiet, schemaCheck, toolchain, verbose}}}, + {"list layers", { false, {context, contextSet, debug, load, clayerSearchPath, quiet, schemaCheck, toolchain, verbose, updateIdx}}}, + {"list toolchains", { false, {context, contextSet, debug, quiet, toolchain, verbose}}}, {"list environment", { true, {}}}, }; @@ -509,22 +509,6 @@ bool ProjMgr::GenerateYMLConfigurationFiles() { bool result = true; - // Generate cbuild set file - if (m_contextSet) { - const string& cbuildSetFile = m_parser.GetCsolution().directory + "/" + - m_parser.GetCsolution().name + ".cbuild-set.yml"; - - if ((m_context.size() == 0) && (RteFsUtils::Exists(cbuildSetFile) == false)) { - ProjMgrLogger::Warn("unable to locate " + cbuildSetFile + " file."); - } - else if (!m_processedContexts.empty()) { - // Generate cbuild-set file - if (!m_emitter.GenerateCbuildSet(m_processedContexts, m_selectedToolchain, cbuildSetFile, m_checkSchema)) { - result = false; - } - } - } - // Generate cbuild files for (auto& contextItem : m_processedContexts) { if (!m_emitter.GenerateCbuild(contextItem, m_checkSchema)) { @@ -544,25 +528,47 @@ bool ProjMgr::GenerateYMLConfigurationFiles() { return result; } -bool ProjMgr::Configure() { - // Parse all input files and populate contexts inputs - if (!PopulateContexts()) { - return false; - } - - bool checkCbuildSet = (m_context.size() == 0) && m_contextSet; +bool ProjMgr::ParseAndValidateContexts() { + const string& cbuildSetFile = m_parser.GetCsolution().directory + "/" + + m_parser.GetCsolution().name + ".cbuild-set.yml"; + bool fileExist = RteFsUtils::Exists(cbuildSetFile); + bool writeCbuildSetFile = m_contextSet && (!fileExist || !m_selectedToolchain.empty()); + // Parse context selection - if (!m_worker.ParseContextSelection(m_context, checkCbuildSet)) { + if (!m_worker.ParseContextSelection(m_context, m_contextSet)) { return false; } // validate and restrict the input contexts when used with -S option if (!m_context.empty() && m_contextSet) { - if (!m_worker.ValidateContexts(m_context, false)){ + if (!m_worker.ValidateContexts(m_context, false)) { return false; } } + if (writeCbuildSetFile) { + const auto& selectedContexts = m_worker.GetSelectedContexts(); + if (!selectedContexts.empty()) { + // Generate cbuild-set file + if (!m_emitter.GenerateCbuildSet(selectedContexts, m_selectedToolchain, cbuildSetFile, m_checkSchema)) { + return false; + } + } + } + + return true; +} + +bool ProjMgr::Configure() { + // Parse all input files and populate contexts inputs + if (!PopulateContexts()) { + return false; + } + + if (!ParseAndValidateContexts()) { + return false; + } + if (m_worker.HasVarDefineError()) { auto undefVars = m_worker.GetUndefLayerVars(); string errMsg = "undefined variables in "+ fs::path(m_csolutionFile).filename().generic_string() +":\n"; @@ -688,10 +694,12 @@ bool ProjMgr::RunListPacks(void) { return false; } } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector packs; bool ret = m_worker.ListPacks(packs, m_missingPacks, m_filter); for (const auto& pack : packs) { @@ -707,10 +715,12 @@ bool ProjMgr::RunListBoards(void) { return false; } } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector boards; if (!m_worker.ListBoards(boards, m_filter)) { ProjMgrLogger::Error("processing boards list failed"); @@ -729,10 +739,12 @@ bool ProjMgr::RunListDevices(void) { return false; } } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector devices; if (!m_worker.ListDevices(devices, m_filter)) { ProjMgrLogger::Error("processing devices list failed"); @@ -751,10 +763,12 @@ bool ProjMgr::RunListComponents(void) { return false; } } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector components; if (!m_worker.ListComponents(components, m_filter)) { ProjMgrLogger::Error("processing components list failed"); @@ -780,10 +794,12 @@ bool ProjMgr::RunListConfigs() { return false; } } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector configFiles; if (!m_worker.ListConfigs(configFiles, m_filter)) { ProjMgrLogger::Error("processing config list failed"); @@ -807,10 +823,12 @@ bool ProjMgr::RunListDependencies(void) { if (!PopulateContexts()) { return false; } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector dependencies; if (!m_worker.ListDependencies(dependencies, m_filter)) { ProjMgrLogger::Error("processing dependencies list failed"); @@ -848,10 +866,12 @@ bool ProjMgr::RunListGenerators(void) { if (!PopulateContexts()) { return false; } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + // Get generators vector generators; if (!m_worker.ListGenerators(generators)) { @@ -877,7 +897,7 @@ bool ProjMgr::RunListLayers(void) { } // Step2 : Parse selected contexts - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } @@ -1000,10 +1020,12 @@ bool ProjMgr::RunListToolchains(void) { return false; } } + // Parse context selection - if (!m_worker.ParseContextSelection(m_context)) { + if (!ParseAndValidateContexts()) { return false; } + vector toolchains; bool success = m_worker.ListToolchains(toolchains); diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 4603547a8..ce106b076 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -4165,33 +4165,62 @@ bool ProjMgrWorker::ProcessSequencesRelatives(ContextItem& context, BuildType& b bool ProjMgrWorker::ParseContextSelection( const vector& contextSelection, const bool checkCbuildSet) { - vector contexts; - ListContexts(contexts); + vector ymlOrderedContexts; + ListContexts(ymlOrderedContexts, RteUtils::EMPTY_STRING, true); - auto csolutionItem = m_parser->GetCsolution(); - string cbuildSetFile = csolutionItem.directory + "/" + csolutionItem.name + ".cbuild-set.yml"; - if (checkCbuildSet && RteFsUtils::Exists(cbuildSetFile)) { - if (!m_parser->ParseCbuildSet(cbuildSetFile, m_checkSchema)) { - return false; - } - const auto& cbuildSetItem = m_parser->GetCbuildSetItem(); - m_selectedContexts = cbuildSetItem.contexts; - if (m_selectedToolchain.empty()) { - m_selectedToolchain = cbuildSetItem.compiler; - } - if (!ValidateContexts(m_selectedContexts, true)) { - return false; - } - } - else { + if (!checkCbuildSet) { + // selected all contexts to process, when contextSelection is empty + // otherwise process contexts from contextSelection const auto& filterError = ProjMgrUtils::GetSelectedContexts( - m_selectedContexts, contexts, contextSelection); + m_selectedContexts, ymlOrderedContexts, contextSelection); if (filterError) { ProjMgrLogger::Error(filterError.m_errMsg); return false; } } + else + { + auto csolutionItem = m_parser->GetCsolution(); + string cbuildSetFile = csolutionItem.directory + "/" + csolutionItem.name + ".cbuild-set.yml"; + + if (contextSelection.empty()) { + if (RteFsUtils::Exists(cbuildSetFile)) { + // Parse the existing cbuild-set file + if (!m_parser->ParseCbuildSet(cbuildSetFile, m_checkSchema)) { + return false; + } + + // Read contexts info from the file + const auto& cbuildSetItem = m_parser->GetCbuildSetItem(); + m_selectedContexts = cbuildSetItem.contexts; + + // Select toolchain if not already selected + if (m_selectedToolchain.empty()) { + m_selectedToolchain = cbuildSetItem.compiler; + } + + if (!ValidateContexts(m_selectedContexts, true)) { + return false; + } + } + else { + m_selectedContexts.clear(); + //first context in yml ordered context should be processed + m_selectedContexts.push_back(ymlOrderedContexts.front()); + } + } + else { + // Contexts are specified in contextSelection + const auto& filterError = ProjMgrUtils::GetSelectedContexts( + m_selectedContexts, ymlOrderedContexts, contextSelection); + if (filterError) { + ProjMgrLogger::Error(filterError.m_errMsg); + return false; + } + } + } + // Process the selected contexts if (!((m_selectedContexts.size() == 1) && (m_selectedContexts.front() == RteUtils::EMPTY_STRING))) { for (const auto& context : m_selectedContexts) { if (!ParseContextLayers(m_contexts[context])) { @@ -4199,9 +4228,14 @@ bool ProjMgrWorker::ParseContextSelection( } } } + return true; } +vector ProjMgrWorker::GetSelectedContexts() const { + return m_selectedContexts; +} + bool ProjMgrWorker::IsContextSelected(const string& context) { if (find(m_selectedContexts.begin(), m_selectedContexts.end(), context) != m_selectedContexts.end()) { return true; diff --git a/tools/projmgr/src/ProjMgrYamlEmitter.cpp b/tools/projmgr/src/ProjMgrYamlEmitter.cpp index 5b5071566..4e0206af3 100644 --- a/tools/projmgr/src/ProjMgrYamlEmitter.cpp +++ b/tools/projmgr/src/ProjMgrYamlEmitter.cpp @@ -47,7 +47,7 @@ class ProjMgrYamlBase { class ProjMgrYamlCbuild : public ProjMgrYamlBase { private: friend class ProjMgrYamlEmitter; - ProjMgrYamlCbuild(YAML::Node node, const vector& processedContexts, const string& selectedCompiler, bool checkSchema); + ProjMgrYamlCbuild(YAML::Node node, const vector& selectedContexts, const string& selectedCompiler, bool checkSchema); ProjMgrYamlCbuild(YAML::Node node, const ContextItem* context, const string& generatorId, const string& generatorPack, bool checkSchema); ProjMgrYamlCbuild(YAML::Node node, const vector& siblings, const string& type, const string& output, const string& gendir, bool checkSchema); void SetContextNode(YAML::Node node, const ContextItem* context, const string& generatorId, const string& generatorPack); @@ -396,16 +396,14 @@ ProjMgrYamlCbuild::ProjMgrYamlCbuild(YAML::Node node, const ContextItem* context } ProjMgrYamlCbuild::ProjMgrYamlCbuild(YAML::Node node, - const vector& processedContexts, const string& selectedCompiler, bool checkSchema) + const vector& selectedContexts, const string& selectedCompiler, bool checkSchema) { SetNodeValue(node[YAML_GENERATED_BY], ORIGINAL_FILENAME + string(" version ") + VERSION_STRING); YAML::Node contextsNode = node[YAML_CONTEXTS]; - for (const auto& context : processedContexts) { - if (context) { - YAML::Node contextNode; - SetNodeValue(contextNode[YAML_CONTEXT], context->name); - contextsNode.push_back(contextNode); - } + for (const auto& context : selectedContexts) { + YAML::Node contextNode; + SetNodeValue(contextNode[YAML_CONTEXT], context); + contextsNode.push_back(contextNode); } if (!selectedCompiler.empty()) { SetNodeValue(node[YAML_COMPILER], selectedCompiler); @@ -1055,11 +1053,11 @@ bool ProjMgrYamlEmitter::GenerateCbuild(ContextItem* context, bool checkSchema, return cbuild.WriteFile(rootNode, filename); } -bool ProjMgrYamlEmitter::GenerateCbuildSet(const std::vector contexts, +bool ProjMgrYamlEmitter::GenerateCbuildSet(const std::vector selectedContexts, const string& selectedCompiler, const string& cbuildSetFile, bool checkSchema) { YAML::Node rootNode; - ProjMgrYamlCbuild cbuild(rootNode[YAML_CBUILD_SET], contexts, selectedCompiler, checkSchema); + ProjMgrYamlCbuild cbuild(rootNode[YAML_CBUILD_SET], selectedContexts, selectedCompiler, checkSchema); return cbuild.WriteFile(rootNode, cbuildSetFile); } diff --git a/tools/projmgr/test/data/TestSolution/novalid_context.csolution.yml b/tools/projmgr/test/data/TestSolution/novalid_context.csolution.yml index 660ed8cda..f00ac4f75 100644 --- a/tools/projmgr/test/data/TestSolution/novalid_context.csolution.yml +++ b/tools/projmgr/test/data/TestSolution/novalid_context.csolution.yml @@ -8,10 +8,6 @@ solution: - type: Error compiler: GCC - target-types: - - type: RteTest_ARMCM3 - device: RteTest_ARMCM3 - projects: - project: toolchain.cproject.yml diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index d5177161a..a7353968e 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -2205,7 +2205,7 @@ error csolution: undefined variables in variables-notdefined.csolution.yml:.*\ .*/ARM/RteTest_DFP/0.2.0/Layers/board1.clayer.yml \\(layer type: Board\\).*\ .*/ARM/RteTest_DFP/0.2.0/Layers/board2.clayer.yml \\(layer type: Board\\).*\ .*/ARM/RteTest_DFP/0.2.0/Layers/board3.clayer.yml \\(layer type: Board\\).*\ -no valid combination of clayers was found\ +no valid combination of clayers was found.*\ "; string errStr = streamRedirect.GetErrorString(); @@ -2244,7 +2244,7 @@ error csolution: undefined variables in variables-notdefined.csolution.yml:.*\ - \\$NotDefined\\$.*\ debug csolution: check for context \\'variables-notdefined\\.BuildType\\+TargetType\\'.*\ clayer of type 'Board' was uniquely found:\ - .*/TestLayers/variables/target1.clayer.yml\ + .*/TestLayers/variables/target1.clayer.yml.*\ "; string errStr = streamRedirect.GetErrorString(); @@ -4933,8 +4933,8 @@ TEST_F(ProjMgrUnitTests, RunProjMgrSolution_cbuildset_file) { CleanUp(); StdStreamRedirect streamRedirect; // Test 2: Run without contexts specified (no existing cbuild-set file with -S) - // Expectation: *.cbuild-set.yml file should not be generated and all available - // contexts should be processed + // Expectation: *.cbuild-set.yml file should be generated and only first build and + // target types should be selected with first project argv[1] = (char*)"convert"; argv[2] = (char*)"--solution"; argv[3] = (char*)csolution.c_str(); @@ -4943,13 +4943,11 @@ TEST_F(ProjMgrUnitTests, RunProjMgrSolution_cbuildset_file) { argv[6] = (char*)"-S"; EXPECT_EQ(0, RunProjMgr(7, argv, m_envp)); - EXPECT_FALSE(RteFsUtils::Exists(cbuildSetFile)); + EXPECT_TRUE(RteFsUtils::Exists(cbuildSetFile)); EXPECT_TRUE(RteFsUtils::Exists(outputDir + "/test2.Debug+CM0.cbuild.yml")); - EXPECT_TRUE(RteFsUtils::Exists(outputDir + "/test1.Debug+CM0.cbuild.yml")); - EXPECT_TRUE(RteFsUtils::Exists(outputDir + "/test2.Debug+CM3.cbuild.yml")); - EXPECT_TRUE(RteFsUtils::Exists(outputDir + "/test1.Release+CM0.cbuild.yml")); - const auto& errStr = streamRedirect.GetErrorString(); - EXPECT_NE(string::npos, errStr.find("warning csolution: unable to locate " + cbuildSetFile + " file.")); + EXPECT_FALSE(RteFsUtils::Exists(outputDir + "/test1.Debug+CM0.cbuild.yml")); + EXPECT_FALSE(RteFsUtils::Exists(outputDir + "/test2.Debug+CM3.cbuild.yml")); + EXPECT_FALSE(RteFsUtils::Exists(outputDir + "/test1.Release+CM0.cbuild.yml")); } { @@ -6086,3 +6084,52 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_MultiVariantComponent) { EXPECT_NE(string::npos, errMsg.find("multiple variants of the same component are specified:\n - Device:Test variant\n - Device:Test variant&Variant name")); } + +TEST_F(ProjMgrUnitTests, RunProjMgr_ListPacks_ContextSet) { + char* argv[6]; + StdStreamRedirect streamRedirect; + const string& csolution = testinput_folder + "/TestSolution/contexts.csolution.yml"; + + // list packs + argv[1] = (char*)"list"; + argv[2] = (char*)"packs"; + argv[3] = (char*)"--solution"; + argv[4] = (char*)csolution.c_str(); + argv[5] = (char*)"-S"; + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + auto outStr = streamRedirect.GetOutString(); + EXPECT_NE(outStr.find("ARM::RteTest_DFP@0.2.0"), string::npos); +} + +TEST_F(ProjMgrUnitTests, RunProjMgr_ListBoards_ContextSet) { + char* argv[6]; + StdStreamRedirect streamRedirect; + const string& csolution = testinput_folder + "/TestSolution/contexts.csolution.yml"; + + argv[1] = (char*)"list"; + argv[2] = (char*)"boards"; + argv[3] = (char*)"--solution"; + argv[4] = (char*)csolution.c_str(); + argv[5] = (char*)"-S"; + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + auto outStr = streamRedirect.GetOutString(); + EXPECT_NE(outStr.find("Keil::RteTest Dummy board:1.2.3 (ARM::RteTest_DFP@0.2.0)"), string::npos); +} + +TEST_F(ProjMgrUnitTests, RunProjMgr_ListDevices_ContextSet) { + char* argv[6]; + StdStreamRedirect streamRedirect; + const string& csolution = testinput_folder + "/TestSolution/contexts.csolution.yml"; + + argv[1] = (char*)"list"; + argv[2] = (char*)"devices"; + argv[3] = (char*)"--solution"; + argv[4] = (char*)csolution.c_str(); + argv[5] = (char*)"-S"; + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + auto outStr = streamRedirect.GetOutString(); + EXPECT_NE(outStr.find("ARM::RteTest_ARMCM0 (ARM::RteTest_DFP@0.2.0)"), string::npos); +}