From 8612403378a13b498bb93b48bc7881e128a01bf2 Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Fri, 7 Jul 2023 10:34:16 +0200 Subject: [PATCH 1/2] [projmgr] Check file references portability --- tools/projmgr/include/ProjMgrYamlParser.h | 29 ++-- tools/projmgr/src/ProjMgr.cpp | 4 - tools/projmgr/src/ProjMgrYamlParser.cpp | 154 +++++++++++------- .../TestSolution/Portability/artifact.elf | 1 + .../Portability/bs/bs.cproject.yml | 16 ++ .../Portability/case/case.cproject.yml | 16 ++ .../TestSolution/Portability/layer.clayer.yml | 1 + .../TestSolution/Portability/linker_script.ld | 1 + .../Portability/portability.csolution.yml | 20 +++ .../Portability/portability2.csolution.yml | 10 ++ .../data/TestSolution/contexts.cproject.yml | 3 + .../data/TestSolution/multiple.csolution.yml | 6 +- tools/projmgr/test/src/ProjMgrUnitTests.cpp | 138 +++++++++++++--- 13 files changed, 298 insertions(+), 101 deletions(-) create mode 100644 tools/projmgr/test/data/TestSolution/Portability/artifact.elf create mode 100644 tools/projmgr/test/data/TestSolution/Portability/bs/bs.cproject.yml create mode 100644 tools/projmgr/test/data/TestSolution/Portability/case/case.cproject.yml create mode 100644 tools/projmgr/test/data/TestSolution/Portability/layer.clayer.yml create mode 100644 tools/projmgr/test/data/TestSolution/Portability/linker_script.ld create mode 100644 tools/projmgr/test/data/TestSolution/Portability/portability.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/Portability/portability2.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/contexts.cproject.yml diff --git a/tools/projmgr/include/ProjMgrYamlParser.h b/tools/projmgr/include/ProjMgrYamlParser.h index 087ad025d..40f3a8d32 100644 --- a/tools/projmgr/include/ProjMgrYamlParser.h +++ b/tools/projmgr/include/ProjMgrYamlParser.h @@ -182,23 +182,23 @@ class ProjMgrYamlParser { void ParseVector(const YAML::Node& parent, const std::string& key, std::vector& value); void ParseVectorOfStringPairs(const YAML::Node& parent, const std::string& key, std::vector>& value); void ParseVectorOrString(const YAML::Node& parent, const std::string& key, std::vector& value); - bool ParseBuildType(const YAML::Node& parent, BuildType& buildType); - void ParseOutput(const YAML::Node& parent, OutputItem& output); - void ParseOutputDirs(const YAML::Node& parent, struct DirectoriesItem& directories); - void ParseGenerators(const YAML::Node& parent, GeneratorsItem& generators); + bool ParseBuildType(const YAML::Node& parent, const std::string& file, BuildType& buildType); + void ParseOutput(const YAML::Node& parent, const std::string& file, OutputItem& output); + void ParseOutputDirs(const YAML::Node& parent, const std::string& file, struct DirectoriesItem& directories); + void ParseGenerators(const YAML::Node& parent, const std::string& file, GeneratorsItem& generators); void ParseConnections(const YAML::Node& parent, std::vector& connects); - bool ParseTargetType(const YAML::Node& parent, TargetType& targetType); - bool ParseBuildTypes(const YAML::Node& parent, std::map& buildTypes); - bool ParseTargetTypes(const YAML::Node& parent, std::map& targetTypes); + bool ParseTargetType(const YAML::Node& parent, const std::string& file, TargetType& targetType); + bool ParseBuildTypes(const YAML::Node& parent, const std::string& file, std::map& buildTypes); + bool ParseTargetTypes(const YAML::Node& parent, const std::string& file, std::map& targetTypes); bool ParseContexts(const YAML::Node& parent, CsolutionItem& contexts); - bool ParseComponents(const YAML::Node& parent, std::vector& components); - bool ParseFiles(const YAML::Node& parent, std::vector& files); - bool ParseGroups(const YAML::Node& parent, std::vector& groups); - bool ParseLayers(const YAML::Node& parent, std::vector& layers); - bool ParseSetups(const YAML::Node& parent, std::vector& setups); + bool ParseComponents(const YAML::Node& parent, const std::string& file, std::vector& components); + bool ParseFiles(const YAML::Node& parent, const std::string& file, std::vector& files); + bool ParseGroups(const YAML::Node& parent, const std::string& file, std::vector& groups); + bool ParseLayers(const YAML::Node& parent, const std::string& file, std::vector& layers); + bool ParseSetups(const YAML::Node& parent, const std::string& file, std::vector& setups); bool ParseTypeFilter(const YAML::Node& parent, TypeFilter& type); bool ParseTypePair(std::vector& vec, std::vector& typeVec); - bool ParseLinker(const YAML::Node& parent, std::vector& linker); + bool ParseLinker(const YAML::Node& parent, const std::string& file, std::vector& linker); void ParseRte(const YAML::Node& parent, std::string& rteBaseDir); bool GetTypes(const std::string& type, std::string& buildType, std::string& targetType); bool ValidateCdefault(const std::string& input, const YAML::Node& root); @@ -208,6 +208,9 @@ class ProjMgrYamlParser { bool ValidateKeys(const std::string& input, const YAML::Node& parent, const std::set& keys); bool ValidateSequence(const std::string& input, const YAML::Node& parent, const std::string& seqKey); bool ValidateMapping(const std::string& input, const YAML::Node& parent, const std::string& seqKey); + void ParsePortablePath(const YAML::Node& parent, const std::string& file, const std::string& key, std::string& value, bool checkExist = true); + void ParsePortablePaths(const YAML::Node& parent, const std::string& file, const std::string& key, std::vector& value); + void CheckPortability(const std::string& file, const YAML::Mark& mark, const std::string& key, const std::string& value, bool checkExist); }; diff --git a/tools/projmgr/src/ProjMgr.cpp b/tools/projmgr/src/ProjMgr.cpp index c90022329..504a7fc0b 100644 --- a/tools/projmgr/src/ProjMgr.cpp +++ b/tools/projmgr/src/ProjMgr.cpp @@ -380,10 +380,6 @@ bool ProjMgr::PopulateContexts(void) { if (cprojectFile.empty()) { ProjMgrLogger::Error(cproject, "cproject file was not found"); return false; - } else if (fs::path(cprojectFile).filename().string() != fs::path(cproject).filename().string()) { - ProjMgrLogger::Error(cproject, "cproject filename has case inconsistency"); - ProjMgrLogger::Info(fs::path(cprojectFile).filename().string(), "should be used instead"); - return false; } if (!m_parser.ParseCproject(cprojectFile, m_checkSchema)) { return false; diff --git a/tools/projmgr/src/ProjMgrYamlParser.cpp b/tools/projmgr/src/ProjMgrYamlParser.cpp index c5b62324a..b0ab7fdfd 100644 --- a/tools/projmgr/src/ProjMgrYamlParser.cpp +++ b/tools/projmgr/src/ProjMgrYamlParser.cpp @@ -79,20 +79,20 @@ bool ProjMgrYamlParser::ParseCsolution(const string& input, return false; } - if (!ParseTargetTypes(solutionNode, csolution.targetTypes)) { + if (!ParseTargetTypes(solutionNode, csolution.path, csolution.targetTypes)) { ProjMgrLogger::Error(input, "target-types not found"); return false; } - if (!ParseBuildTypes(solutionNode, csolution.buildTypes)) { + if (!ParseBuildTypes(solutionNode, csolution.path, csolution.buildTypes)) { return false; } - ParseOutputDirs(solutionNode, csolution.directories); - if (!ParseTargetType(solutionNode, csolution.target)) { + ParseOutputDirs(solutionNode, csolution.path, csolution.directories); + if (!ParseTargetType(solutionNode, csolution.path, csolution.target)) { return false; } ParsePacks(solutionNode, csolution.packs); csolution.enableCdefault = solutionNode[YAML_CDEFAULT].IsDefined(); - ParseGenerators(solutionNode, csolution.generators); + ParseGenerators(solutionNode, csolution.path, csolution.generators); } catch (YAML::Exception& e) { ProjMgrLogger::Error(input, e.mark.line + 1, e.mark.column + 1, e.msg); @@ -124,30 +124,30 @@ bool ProjMgrYamlParser::ParseCproject(const string& input, const YAML::Node& projectNode = root[YAML_PROJECT]; - ParseOutput(projectNode, cproject.output); + ParseOutput(projectNode, cproject.path, cproject.output); - ParseTargetType(projectNode, cproject.target); + ParseTargetType(projectNode, cproject.path, cproject.target); ParsePacks(projectNode, cproject.packs); - if (!ParseComponents(projectNode, cproject.components)) { + if (!ParseComponents(projectNode, cproject.path, cproject.components)) { return false; } - if (!ParseGroups(projectNode, cproject.groups)) { + if (!ParseGroups(projectNode, cproject.path, cproject.groups)) { return false; } - if (!ParseLayers(projectNode, cproject.clayers)) { + if (!ParseLayers(projectNode, cproject.path, cproject.clayers)) { return false; } - if (!ParseSetups(projectNode, cproject.setups)) { + if (!ParseSetups(projectNode, cproject.path, cproject.setups)) { return false; } ParseConnections(projectNode, cproject.connections); - ParseLinker(projectNode, cproject.linker); + ParseLinker(projectNode, cproject.path, cproject.linker); - ParseGenerators(projectNode, cproject.generators); + ParseGenerators(projectNode, cproject.path, cproject.generators); ParseRte(projectNode, cproject.rteBaseDir); @@ -199,22 +199,22 @@ bool ProjMgrYamlParser::ParseClayer(const string& input, ParseString(layerNode, item.first, item.second); } - ParseTargetType(layerNode, clayer.target); + ParseTargetType(layerNode, clayer.path, clayer.target); ParsePacks(layerNode, clayer.packs); - if (!ParseComponents(layerNode, clayer.components)) { + if (!ParseComponents(layerNode, clayer.path, clayer.components)) { return false; } - if (!ParseGroups(layerNode, clayer.groups)) { + if (!ParseGroups(layerNode, clayer.path, clayer.groups)) { return false; } ParseConnections(layerNode, clayer.connections); - ParseLinker(layerNode, clayer.linker); + ParseLinker(layerNode, clayer.path, clayer.linker); - ParseGenerators(layerNode, clayer.generators); + ParseGenerators(layerNode, clayer.path, clayer.generators); } catch (YAML::Exception& e) { ProjMgrLogger::Error(input, e.mark.line + 1, e.mark.column + 1, e.msg); @@ -224,6 +224,44 @@ bool ProjMgrYamlParser::ParseClayer(const string& input, return true; } +void ProjMgrYamlParser::CheckPortability(const string& file, const YAML::Mark& mark, const string& key, const string& value, bool checkExist) { + if (value.find('\\') != string::npos) { + ProjMgrLogger::Warn(file, mark.line + 1, mark.column + 1, "'" + value + "' contains non-portable backslash, use forward slash instead"); + } + if (!value.empty()) { + if (fs::path(value).is_absolute()) { + ProjMgrLogger::Warn(file, mark.line + 1, mark.column + 1, "absolute path '" + value + "' is not portable, use relative path instead"); + } else { + const string parentDir = RteFsUtils::ParentPath(file); + const string original = fs::path(parentDir).append(value).lexically_normal().generic_string(); + if (RteFsUtils::Exists(original)) { + error_code ec; + string canonical = fs::canonical(original, ec).generic_string(); + if (!canonical.empty() && (original != canonical)) { + ProjMgrLogger::Warn(file, mark.line + 1, mark.column + 1, "'" + value + "' has case inconsistency, use '" + RteFsUtils::RelativePath(canonical, parentDir) + "' instead"); + } + } else if (checkExist) { + ProjMgrLogger::Warn(file, mark.line + 1, mark.column + 1, "path '" + value + "' was not found"); + } + } + } +} + +void ProjMgrYamlParser::ParsePortablePath(const YAML::Node& parent, const string& file, const string& key, string& value, bool checkExist) { + ParseString(parent, key, value); + YAML::Mark mark = parent[key].IsDefined() ? parent[key].Mark() : YAML::Mark(); + CheckPortability(file, mark, key, value, checkExist); +} + +void ProjMgrYamlParser::ParsePortablePaths(const YAML::Node& parent, const string& file, const string& key, vector& value) { + ParseVector(parent, key, value); + auto node = parent[key].begin(); + for (const auto& item : value) { + YAML::Mark mark = (*node++).Mark(); + CheckPortability(file, mark, key, item, true); + } +} + void ProjMgrYamlParser::ParseString(const YAML::Node& parent, const string& key, string& value) { if (parent[key].IsDefined()) { value = parent[key].as(); @@ -307,7 +345,7 @@ void ProjMgrYamlParser::ParseProcessor(const YAML::Node& parent, ProcessorItem& } } -bool ProjMgrYamlParser::ParseComponents(const YAML::Node& parent, vector& components) { +bool ProjMgrYamlParser::ParseComponents(const YAML::Node& parent, const string& file, vector& components) { if (parent[YAML_COMPONENTS].IsDefined()) { const YAML::Node& componentsNode = parent[YAML_COMPONENTS]; for (const auto& componentEntry : componentsNode) { @@ -318,7 +356,7 @@ bool ProjMgrYamlParser::ParseComponents(const YAML::Node& parent, vector& p } } -bool ProjMgrYamlParser::ParseFiles(const YAML::Node& parent, vector& files) { +bool ProjMgrYamlParser::ParseFiles(const YAML::Node& parent, const string& file, vector& files) { if (parent[YAML_FILES].IsDefined()) { const YAML::Node& filesNode = parent[YAML_FILES]; for (const auto& fileEntry : filesNode) { @@ -446,10 +484,10 @@ bool ProjMgrYamlParser::ParseFiles(const YAML::Node& parent, vector& f if (!ParseTypeFilter(fileEntry, fileItem.type)) { return false; } - ParseString(fileEntry, YAML_FILE, fileItem.file); + ParsePortablePath(fileEntry, file, YAML_FILE, fileItem.file); ParseVectorOrString(fileEntry, YAML_FORCOMPILER, fileItem.forCompiler); ParseString(fileEntry, YAML_CATEGORY, fileItem.category); - if (!ParseBuildType(fileEntry, fileItem.build)) { + if (!ParseBuildType(fileEntry, file, fileItem.build)) { return false; } files.push_back(fileItem); @@ -458,7 +496,7 @@ bool ProjMgrYamlParser::ParseFiles(const YAML::Node& parent, vector& f return true; } -bool ProjMgrYamlParser::ParseGroups(const YAML::Node& parent, vector& groups) { +bool ProjMgrYamlParser::ParseGroups(const YAML::Node& parent, const string& file, vector& groups) { if (parent[YAML_GROUPS].IsDefined()) { const YAML::Node& groupsNode = parent[YAML_GROUPS]; for (const auto& groupEntry : groupsNode) { @@ -466,22 +504,22 @@ bool ProjMgrYamlParser::ParseGroups(const YAML::Node& parent, vector& if (!ParseTypeFilter(groupEntry, groupItem.type)) { return false; } - if (!ParseFiles(groupEntry, groupItem.files)) { + if (!ParseFiles(groupEntry, file, groupItem.files)) { return false; } ParseString(groupEntry, YAML_GROUP, groupItem.group); ParseVectorOrString(groupEntry, YAML_FORCOMPILER, groupItem.forCompiler); - if (!ParseBuildType(groupEntry, groupItem.build)) { + if (!ParseBuildType(groupEntry, file, groupItem.build)) { return false; } - ParseGroups(groupEntry, groupItem.groups); + ParseGroups(groupEntry, file, groupItem.groups); groups.push_back(groupItem); } } return true; } -bool ProjMgrYamlParser::ParseLayers(const YAML::Node& parent, vector& layers) { +bool ProjMgrYamlParser::ParseLayers(const YAML::Node& parent, const string& file, vector& layers) { if (parent[YAML_LAYERS].IsDefined()) { const YAML::Node& layersNode = parent[YAML_LAYERS]; for (const auto& layerEntry : layersNode) { @@ -489,7 +527,7 @@ bool ProjMgrYamlParser::ParseLayers(const YAML::Node& parent, vector& if (!ParseTypeFilter(layerEntry, layerItem.typeFilter)) { return false; } - ParseString(layerEntry, YAML_LAYER, layerItem.layer); + ParsePortablePath(layerEntry, file, YAML_LAYER, layerItem.layer); ParseString(layerEntry, YAML_TYPE, layerItem.type); layers.push_back(layerItem); } @@ -497,7 +535,7 @@ bool ProjMgrYamlParser::ParseLayers(const YAML::Node& parent, vector& return true; } -bool ProjMgrYamlParser::ParseSetups(const YAML::Node& parent, vector& setups) { +bool ProjMgrYamlParser::ParseSetups(const YAML::Node& parent, const string& file, vector& setups) { if (parent[YAML_SETUPS].IsDefined()) { const YAML::Node& setupsNode = parent[YAML_SETUPS]; for (const auto& setupEntry : setupsNode) { @@ -507,11 +545,11 @@ bool ProjMgrYamlParser::ParseSetups(const YAML::Node& parent, vector& } ParseString(setupEntry, YAML_SETUP, setupItem.description); ParseVectorOrString(setupEntry, YAML_FORCOMPILER, setupItem.forCompiler); - if (!ParseBuildType(setupEntry, setupItem.build)) { + if (!ParseBuildType(setupEntry, file, setupItem.build)) { return false; } - ParseOutput(setupEntry, setupItem.output); - ParseLinker(setupEntry, setupItem.linker); + ParseOutput(setupEntry, file, setupItem.output); + ParseLinker(setupEntry, file, setupItem.linker); ParseProcessor(setupEntry, setupItem.build.processor); setups.push_back(setupItem); } @@ -527,15 +565,19 @@ bool ProjMgrYamlParser::ParseContexts(const YAML::Node& parent, CsolutionItem& c if (!ParseTypeFilter(projectsEntry, descriptor.type)) { return false; } - ParseString(projectsEntry, YAML_PROJECT, descriptor.cproject); - csolution.contexts.push_back(descriptor); - ProjMgrUtils::PushBackUniquely(csolution.cprojects, descriptor.cproject); + ParsePortablePath(projectsEntry, csolution.path, YAML_PROJECT, descriptor.cproject); + error_code ec; + descriptor.cproject = RteFsUtils::RelativePath(fs::canonical(fs::path(csolution.directory).append(descriptor.cproject), ec).generic_string(), csolution.directory); + if (!descriptor.cproject.empty()) { + csolution.contexts.push_back(descriptor); + ProjMgrUtils::PushBackUniquely(csolution.cprojects, descriptor.cproject); + } } } return true; } -bool ProjMgrYamlParser::ParseBuildTypes(const YAML::Node& parent, map& buildTypes) { +bool ProjMgrYamlParser::ParseBuildTypes(const YAML::Node& parent, const string& file, map& buildTypes) { std::vector invalidBuildTypes; if (parent[YAML_BUILDTYPES].IsDefined()) { const YAML::Node& buildTypesNode = parent[YAML_BUILDTYPES]; @@ -547,7 +589,7 @@ bool ProjMgrYamlParser::ParseBuildTypes(const YAML::Node& parent, map outputDirsChildren = { @@ -573,11 +615,7 @@ void ProjMgrYamlParser::ParseOutputDirs(const YAML::Node& parent, struct Directo {YAML_OUTPUT_OUTDIR, directories.outdir}, }; for (const auto& item : outputDirsChildren) { - ParseString(outputDirsNode, item.first, item.second); - if (!fs::path(item.second).is_relative()) { - ProjMgrLogger::Warn("custom " + item.first + " '" + item.second + "' is not a relative path"); - item.second.clear(); - } + ParsePortablePath(outputDirsNode, file, item.first, item.second, false); } } } @@ -602,7 +640,7 @@ void ProjMgrYamlParser::ParseConnections(const YAML::Node& parent, vector& linker) { +bool ProjMgrYamlParser::ParseLinker(const YAML::Node& parent, const string& file, vector& linker) { if (parent[YAML_LINKER].IsDefined()) { const YAML::Node& linkerNode = parent[YAML_LINKER]; for (const auto& linkerEntry : linkerNode) { @@ -612,15 +650,15 @@ bool ProjMgrYamlParser::ParseLinker(const YAML::Node& parent, vector } ParseDefine(linkerEntry, linkerItem.defines); ParseVectorOrString(linkerEntry, YAML_FORCOMPILER, linkerItem.forCompiler); - ParseString(linkerEntry, YAML_REGIONS, linkerItem.regions); - ParseString(linkerEntry, YAML_SCRIPT, linkerItem.script); + ParsePortablePath(linkerEntry, file, YAML_REGIONS, linkerItem.regions); + ParsePortablePath(linkerEntry, file, YAML_SCRIPT, linkerItem.script); linker.push_back(linkerItem); } } return true; } -bool ProjMgrYamlParser::ParseTargetTypes(const YAML::Node& parent, map& targetTypes) { +bool ProjMgrYamlParser::ParseTargetTypes(const YAML::Node& parent, const string& file, map& targetTypes) { std::vector invalidTargetTypes; const YAML::Node& targetTypesNode = parent[YAML_TARGETTYPES]; for (const auto& typeEntry : targetTypesNode) { @@ -631,7 +669,7 @@ bool ProjMgrYamlParser::ParseTargetTypes(const YAML::Node& parent, map 0) { @@ -645,7 +683,7 @@ bool ProjMgrYamlParser::ParseTargetTypes(const YAML::Node& parent, map buildChildren = { {YAML_COMPILER, buildType.compiler}, {YAML_OPTIMIZE, buildType.optimize}, @@ -661,7 +699,7 @@ bool ProjMgrYamlParser::ParseBuildType(const YAML::Node& parent, BuildType& buil ParseMisc(parent, buildType.misc); ParseDefine(parent, buildType.defines); ParseVector(parent, YAML_UNDEFINE, buildType.undefines); - ParseVector(parent, YAML_ADDPATH, buildType.addpaths); + ParsePortablePaths(parent, file, YAML_ADDPATH, buildType.addpaths); ParseVector(parent, YAML_DELPATH, buildType.delpaths); ParseVectorOfStringPairs(parent, YAML_VARIABLES, buildType.variables); @@ -687,7 +725,7 @@ bool ProjMgrYamlParser::ParseBuildType(const YAML::Node& parent, BuildType& buil return true; } -bool ProjMgrYamlParser::ParseTargetType(const YAML::Node& parent, TargetType& targetType) { +bool ProjMgrYamlParser::ParseTargetType(const YAML::Node& parent, const string& file, TargetType& targetType) { map targetChildren = { {YAML_BOARD, targetType.board}, {YAML_DEVICE, targetType.device}, @@ -695,7 +733,7 @@ bool ProjMgrYamlParser::ParseTargetType(const YAML::Node& parent, TargetType& ta for (const auto& item : targetChildren) { ParseString(parent, item.first, item.second); } - return ParseBuildType(parent, targetType.build); + return ParseBuildType(parent, file, targetType.build); } // Validation Maps diff --git a/tools/projmgr/test/data/TestSolution/Portability/artifact.elf b/tools/projmgr/test/data/TestSolution/Portability/artifact.elf new file mode 100644 index 000000000..d90960d67 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/artifact.elf @@ -0,0 +1 @@ +// artifact.elf diff --git a/tools/projmgr/test/data/TestSolution/Portability/bs/bs.cproject.yml b/tools/projmgr/test/data/TestSolution/Portability/bs/bs.cproject.yml new file mode 100644 index 000000000..eb45e699b --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/bs/bs.cproject.yml @@ -0,0 +1,16 @@ +project: + + linker: + - script: ..\linker_script.ld + + layers: + - layer: ..\layer.clayer.yml + + output: + base-name: ..\artifact.elf + + generators: + base-dir: ..\..\Portability + options: + - generator: GeneratorID + path: ..\..\Portability diff --git a/tools/projmgr/test/data/TestSolution/Portability/case/case.cproject.yml b/tools/projmgr/test/data/TestSolution/Portability/case/case.cproject.yml new file mode 100644 index 000000000..7391e17f4 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/case/case.cproject.yml @@ -0,0 +1,16 @@ +project: + + linker: + - script: ../linker_Script.ld + + layers: + - layer: ../laYer.clayer.yml + + output: + base-name: ../Artifact.elf + + generators: + base-dir: ../../PortAbility + options: + - generator: GeneratorID + path: ../../PortAbility diff --git a/tools/projmgr/test/data/TestSolution/Portability/layer.clayer.yml b/tools/projmgr/test/data/TestSolution/Portability/layer.clayer.yml new file mode 100644 index 000000000..9cd2a2b2f --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/layer.clayer.yml @@ -0,0 +1 @@ +layer: diff --git a/tools/projmgr/test/data/TestSolution/Portability/linker_script.ld b/tools/projmgr/test/data/TestSolution/Portability/linker_script.ld new file mode 100644 index 000000000..ab14af839 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/linker_script.ld @@ -0,0 +1 @@ +// linker_script.ld diff --git a/tools/projmgr/test/data/TestSolution/Portability/portability.csolution.yml b/tools/projmgr/test/data/TestSolution/Portability/portability.csolution.yml new file mode 100644 index 000000000..0d46d0e2a --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/portability.csolution.yml @@ -0,0 +1,20 @@ +solution: + compiler: AC6 + + target-types: + - type: RteTest_ARMCM3 + device: RteTest_ARMCM3 + + projects: + - project: case/case.cproject.yml + - project: bs/bs.cproject.yml + + add-path: + - ../PortAbility + - ..\Portability + - /absolute/path/unix + - C:/absolute/path/win + + output-dirs: + intdir: ../PortAbility + outdir: ..\Portability diff --git a/tools/projmgr/test/data/TestSolution/Portability/portability2.csolution.yml b/tools/projmgr/test/data/TestSolution/Portability/portability2.csolution.yml new file mode 100644 index 000000000..05da798a1 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/Portability/portability2.csolution.yml @@ -0,0 +1,10 @@ +solution: + compiler: AC6 + + target-types: + - type: RteTest_ARMCM3 + device: RteTest_ARMCM3 + + projects: + - project: ./Case/caSe.cproject.yml + - project: .\bs\bs.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/contexts.cproject.yml b/tools/projmgr/test/data/TestSolution/contexts.cproject.yml new file mode 100644 index 000000000..f21e87543 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/contexts.cproject.yml @@ -0,0 +1,3 @@ +project: + components: + - component: CORE diff --git a/tools/projmgr/test/data/TestSolution/multiple.csolution.yml b/tools/projmgr/test/data/TestSolution/multiple.csolution.yml index a2a2e6b35..4aef32fdf 100644 --- a/tools/projmgr/test/data/TestSolution/multiple.csolution.yml +++ b/tools/projmgr/test/data/TestSolution/multiple.csolution.yml @@ -9,6 +9,6 @@ solution: - type: Debug compiler: AC6 projects: - - project: project1.cproject.yml - - project: subfolder/project2.cproject.yml - - project: project3.cproject.yml + - project: TestProject4/test.cproject.yml + - project: TestProject1/test1.cproject.yml + - project: TestProject4/test_board_and_device.cproject.yml diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 24179315f..4aaaecbe0 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -1569,7 +1569,7 @@ TEST_F(ProjMgrUnitTests, RunListContexts_Without_BuildTypes) { TEST_F(ProjMgrUnitTests, AddContextFailed) { ContextDesc descriptor; const string& filenameInput = testinput_folder + "/TestSolution/test_missing_project.csolution.yml"; - EXPECT_TRUE(m_parser.ParseCsolution(filenameInput, false)); + EXPECT_FALSE(m_parser.ParseCsolution(filenameInput, false)); EXPECT_FALSE(m_worker.AddContexts(m_parser, descriptor, filenameInput)); } @@ -1612,7 +1612,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgrSolution_processor) { TEST_F(ProjMgrUnitTests, RunProjMgrLayers_missing_project_file) { char* argv[6]; StdStreamRedirect streamRedirect; - const string& expected = "./unknown.cproject.yml - error csolution: cproject file was not found\n"; + const vector expectedVec = { +{"test_missing_project.csolution.yml:73:16 - warning csolution: path './unknown.cproject.yml' was not found"}, +{"test_missing_project.csolution.yml - error csolution: projects not found"} + }; const string& csolutionFile = testinput_folder + "/TestSolution/test_missing_project.csolution.yml"; argv[1] = (char*)"convert"; argv[2] = (char*)"--solution"; @@ -1621,7 +1624,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgrLayers_missing_project_file) { argv[5] = (char*)testoutput_folder.c_str(); EXPECT_EQ(1, RunProjMgr(6, argv, 0)); const string& errStr = streamRedirect.GetErrorString(); - EXPECT_STREQ(errStr.c_str(), expected.c_str()); + + for (const auto& expected : expectedVec) { + EXPECT_TRUE(errStr.find(expected) != string::npos) << "Missing Expected: " + expected; + } } TEST_F(ProjMgrUnitTests, RunProjMgrLayers_pname) { @@ -2398,7 +2404,7 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_LoadPacksPolicy_Required) { argv[5] = (char*)"required"; EXPECT_EQ(1, RunProjMgr(6, argv, 0)); auto errorStr = streamRedirect.GetErrorString(); - EXPECT_EQ(0, errorStr.find("error csolution: required packs must be specified\n")); + EXPECT_TRUE(errorStr.find("error csolution: required packs must be specified") != string::npos); } TEST_F(ProjMgrUnitTests, RunProjMgr_LoadPacksPolicy_Invalid) { @@ -2744,7 +2750,7 @@ TEST_F(ProjMgrUnitTests, OutputDirsAbsolutePath) { EXPECT_EQ(0, RunProjMgr(4, argv, 0)); auto errStr = streamRedirect.GetErrorString(); - EXPECT_TRUE(regex_match(errStr, regex("warning csolution: custom .* is not a relative path\n"))); + EXPECT_TRUE(regex_search(errStr, regex("warning csolution: absolute path .* is not portable, use relative path instead"))); } TEST_F(ProjMgrUnitTests, ProjectSetup) { @@ -3114,13 +3120,15 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_LinkerOptions_Redefinition) { EXPECT_EQ(1, RunProjMgr(7, argv, 0)); // Check error messages - const string expected = "\ -error csolution: redefinition from '.*/linkerScript.ld' into '.*/linkerScript2.ld' is not allowed\n\ -error csolution: processing context 'linker.Redefinition\\+RteTest_ARMCM3' failed\n\ -"; + const vector expectedVec = { +{"error csolution: redefinition from '.*/linkerScript.ld' into '.*/linkerScript2.ld' is not allowed"}, +{"error csolution: processing context 'linker.Redefinition\\+RteTest_ARMCM3' failed"} + }; auto errStr = streamRedirect.GetErrorString(); - EXPECT_TRUE(regex_match(errStr, regex(expected))); + for (const auto& expected : expectedVec) { + EXPECT_TRUE(regex_search(errStr, regex(expected))) << "Missing Expected: " + expected; + } } TEST_F(ProjMgrUnitTests, RunProjMgr_StandardLibrary) { @@ -3154,12 +3162,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_MultipleProject_SameFolder) { EXPECT_EQ(1, RunProjMgr(5, argv, 0)); // Check warning message - const string expected = "\ -.*/TestSolution/multiple.csolution.yml - warning csolution: cproject.yml files should be placed in separate sub-directories\n\ -.*\n"; + const string expected = ".*/TestSolution/multiple.csolution.yml - warning csolution: cproject.yml files should be placed in separate sub-directories"; auto errStr = streamRedirect.GetErrorString(); - EXPECT_TRUE(regex_match(errStr, regex(expected))); + EXPECT_TRUE(regex_search(errStr, regex(expected))); } TEST_F(ProjMgrUnitTests, RunProjMgr_ListEnvironment) { @@ -3435,13 +3441,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_YamlEmitterFileCaseIssue) { const string& cproject1 = testinput_folder + "/TestSolution/FilenameCase/filename.cproject.yml"; const string& cproject2 = testinput_folder + "/TestSolution/FilenameCase/Filename.cproject.yml"; - string expectedErrMsg; - - if (fs::exists(fs::path(cproject1)) && fs::exists(fs::path(cproject2))) { - expectedErrMsg = "cproject filename has case inconsistency"; - } else { - expectedErrMsg = "cproject file was not found"; - } + bool cprojectsExist = fs::exists(fs::path(cproject1)) && fs::exists(fs::path(cproject2)); + const string expectedErrMsg = cprojectsExist ? + "warning csolution: 'filename.cproject.yml' has case inconsistency, use 'Filename.cproject.yml' instead" : + "error csolution: projects not found"; char* argv[5]; argv[1] = (char*)"convert"; @@ -3449,9 +3452,9 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_YamlEmitterFileCaseIssue) { argv[3] = (char*)"-o"; argv[4] = (char*)testoutput_folder.c_str(); - EXPECT_EQ(1, RunProjMgr(5, argv, 0)); + EXPECT_EQ(cprojectsExist ? 0 : 1, RunProjMgr(5, argv, 0)); auto errStr = streamRedirect.GetErrorString(); - EXPECT_NE(string::npos, errStr.find(expectedErrMsg)); + EXPECT_NE(string::npos, errStr.find(expectedErrMsg)) << "errStr: " + errStr; } TEST_F(ProjMgrUnitTests, RunProjMgr_Reverse_Context_Syntax) { @@ -3493,3 +3496,92 @@ TEST_F(ProjMgrUnitTests, FileLanguageAndScope) { ProjMgrTestEnv::CompareFile(testoutput_folder + "/lang-scope.Debug_AC6+RteTest_ARMCM3.cbuild.yml", testinput_folder + "/TestSolution/LanguageAndScope/ref/lang-scope.Debug_AC6+RteTest_ARMCM3.cbuild.yml"); } + +TEST_F(ProjMgrUnitTests, CheckPortability) { + const string host = CrossPlatformUtils::GetHostType(); + const string cproject1 = testinput_folder + "/TestSolution/Portability/case/case.cproject.yml"; + const string cproject2 = testinput_folder + "/TestSolution/Portability/CASE/CASE.cproject.yml"; + bool cprojectsExist = fs::exists(fs::path(cproject1)) && fs::exists(fs::path(cproject2)); + + // WSL is identified as 'linux' host but with case insensitive file system + if (cprojectsExist && (host == "linux")) { + GTEST_SKIP() << "Skip portability test in WSL"; + } + + StdStreamRedirect streamRedirect; + char* argv[6]; + const string csolution = testinput_folder + "/TestSolution/Portability/portability.csolution.yml"; + const string csolution2 = testinput_folder + "/TestSolution/Portability/portability2.csolution.yml"; + argv[1] = (char*)"convert"; + argv[3] = (char*)"-o"; + argv[4] = (char*)testoutput_folder.c_str(); + argv[5] = (char*)"-n"; + + const vector expectedSeparator = { +{"portability.csolution.yml:20:13 - warning csolution: '..\\Portability' contains non-portable backslash, use forward slash instead"}, +{"portability.csolution.yml:14:7 - warning csolution: '..\\Portability' contains non-portable backslash, use forward slash instead"}, +{"bs/bs.cproject.yml:10:16 - warning csolution: '..\\artifact.elf' contains non-portable backslash, use forward slash instead"}, +{"bs/bs.cproject.yml:7:14 - warning csolution: '..\\layer.clayer.yml' contains non-portable backslash, use forward slash instead"}, +{"bs/bs.cproject.yml:4:15 - warning csolution: '..\\linker_script.ld' contains non-portable backslash, use forward slash instead"}, +{"bs/bs.cproject.yml:13:15 - warning csolution: '..\\..\\Portability' contains non-portable backslash, use forward slash instead"}, +{"bs/bs.cproject.yml:16:15 - warning csolution: '..\\..\\Portability' contains non-portable backslash, use forward slash instead"}, +{"portability2.csolution.yml:10:16 - warning csolution: '.\\bs\\bs.cproject.yml' contains non-portable backslash, use forward slash instead"}, + }; + + const vector expectedCase = { +{"portability.csolution.yml:19:13 - warning csolution: '../PortAbility' has case inconsistency, use '.' instead"}, +{"portability.csolution.yml:13:7 - warning csolution: '../PortAbility' has case inconsistency, use '.' instead"}, +{"case/case.cproject.yml:10:16 - warning csolution: '../Artifact.elf' has case inconsistency, use '../artifact.elf' instead"}, +{"case/case.cproject.yml:7:14 - warning csolution: '../laYer.clayer.yml' has case inconsistency, use '../layer.clayer.yml' instead"}, +{"case/case.cproject.yml:4:15 - warning csolution: '../linker_Script.ld' has case inconsistency, use '../linker_script.ld' instead"}, +{"case/case.cproject.yml:13:15 - warning csolution: '../../PortAbility' has case inconsistency, use '..' instead"}, +{"case/case.cproject.yml:16:15 - warning csolution: '../../PortAbility' has case inconsistency, use '..' instead"}, +{"portability2.csolution.yml:9:16 - warning csolution: './Case/caSe.cproject.yml' has case inconsistency, use 'case/case.cproject.yml' instead"}, + }; + + const vector expectedNotFound = { +{"portability.csolution.yml:13:7 - warning csolution: path '../PortAbility' was not found"}, +{"portability.csolution.yml:14:7 - warning csolution: path '..\\Portability' was not found"}, +{"bs/bs.cproject.yml:7:14 - warning csolution: path '..\\layer.clayer.yml' was not found"}, +{"bs/bs.cproject.yml:4:15 - warning csolution: path '..\\linker_script.ld' was not found"}, +{"bs/bs.cproject.yml:13:15 - warning csolution: path '..\\..\\Portability' was not found"}, +{"bs/bs.cproject.yml:16:15 - warning csolution: path '..\\..\\Portability' was not found"}, +{"case/case.cproject.yml:7:14 - warning csolution: path '../laYer.clayer.yml' was not found"}, +{"case/case.cproject.yml:4:15 - warning csolution: path '../linker_Script.ld' was not found"}, +{"case/case.cproject.yml:13:15 - warning csolution: path '../../PortAbility' was not found"}, +{"case/case.cproject.yml:16:15 - warning csolution: path '../../PortAbility' was not found"}, +{"portability2.csolution.yml:9:16 - warning csolution: path './Case/caSe.cproject.yml' was not found"}, +{"portability2.csolution.yml:10:16 - warning csolution: path '.\\bs\\bs.cproject.yml' was not found"}, + }; + + const vector expectedAbsPathWin = { +{"portability.csolution.yml:15:7 - warning csolution: path '/absolute/path/unix' was not found"}, +{"portability.csolution.yml:16:7 - warning csolution: absolute path 'C:/absolute/path/win' is not portable, use relative path instead"}, + }; + + const vector expectedAbsPathUnix = { +{"portability.csolution.yml:15:7 - warning csolution: absolute path '/absolute/path/unix' is not portable, use relative path instead"}, +{"portability.csolution.yml:16:7 - warning csolution: path 'C:/absolute/path/win' was not found"}, + }; + + vector expectedVec = expectedSeparator; + if (host == "linux") { + expectedVec.insert(expectedVec.end(), expectedNotFound.begin(), expectedNotFound.end()); + expectedVec.insert(expectedVec.end(), expectedAbsPathUnix.begin(), expectedAbsPathUnix.end()); + } else if (host == "win") { + expectedVec.insert(expectedVec.end(), expectedCase.begin(), expectedCase.end()); + expectedVec.insert(expectedVec.end(), expectedAbsPathWin.begin(), expectedAbsPathWin.end()); + } else if (host == "darwin") { + expectedVec.insert(expectedVec.end(), expectedCase.begin(), expectedCase.end()); + expectedVec.insert(expectedVec.end(), expectedAbsPathUnix.begin(), expectedAbsPathUnix.end()); + } + argv[2] = (char*)csolution.c_str(); + EXPECT_EQ(host == "linux" ? 1 : 0, RunProjMgr(6, argv, 0)); + argv[2] = (char*)csolution2.c_str(); + EXPECT_EQ(host == "linux" ? 1 : 0, RunProjMgr(6, argv, 0)); + + string errStr = streamRedirect.GetErrorString(); + for (const auto& expected : expectedVec) { + EXPECT_TRUE(errStr.find(expected) != string::npos) << " Missing Expected: " + expected; + } +} From 6f86462902b6cccc65280473c99529642debf7dd Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Fri, 7 Jul 2023 11:03:56 +0200 Subject: [PATCH 2/2] Fix portability test for macOS --- tools/projmgr/test/src/ProjMgrUnitTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 4aaaecbe0..91efa5293 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -3576,7 +3576,7 @@ TEST_F(ProjMgrUnitTests, CheckPortability) { expectedVec.insert(expectedVec.end(), expectedAbsPathUnix.begin(), expectedAbsPathUnix.end()); } argv[2] = (char*)csolution.c_str(); - EXPECT_EQ(host == "linux" ? 1 : 0, RunProjMgr(6, argv, 0)); + EXPECT_EQ(host != "win" ? 1 : 0, RunProjMgr(6, argv, 0)); argv[2] = (char*)csolution2.c_str(); EXPECT_EQ(host == "linux" ? 1 : 0, RunProjMgr(6, argv, 0));