1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <unordered_set>
19 
20 #include "gtest/gtest.h"
21 #include "linkerconfigparser.h"
22 #include "modules.h"
23 
24 namespace {
TraverseLink(const Namespace & ns,std::unordered_set<std::string> & visible_ns)25 inline void TraverseLink(const Namespace& ns, std::unordered_set<std::string>& visible_ns) {
26   if (visible_ns.count(ns.name) != 0) {
27     return;
28   }
29 
30   visible_ns.insert(ns.name);
31 
32   for (auto& [_, link] : ns.links) {
33     TraverseLink(*link.to, visible_ns);
34   }
35 }
36 
ValidateAllNamespacesAreVisible(const Section & section)37 inline void ValidateAllNamespacesAreVisible(const Section& section) {
38   std::unordered_set<std::string> visible_ns;
39   for (auto& [_, ns] : section.namespaces) {
40     if (ns.name == "default" || ns.is_visible) {
41       TraverseLink(ns, visible_ns);
42     }
43   }
44 
45   for (auto& [_, ns] : section.namespaces) {
46     EXPECT_EQ(1u, visible_ns.count(ns.name))
47         << "Namespace " << ns.name << " is not visible from section " << section.name;
48   }
49 }
50 
ValidateNamespace(const Namespace & target_namespace,const Section & parent_section)51 inline void ValidateNamespace(const Namespace& target_namespace, const Section& parent_section) {
52   EXPECT_FALSE(target_namespace.name.empty()) << "Namespace name should not be empty";
53   EXPECT_FALSE(target_namespace.name != "default" && target_namespace.search_path.empty() &&
54                target_namespace.permitted_path.empty())
55       << "Search path or permitted path should be defined in namespace " << target_namespace.name
56       << " from section " << parent_section.name;
57 }
58 
ValidateSection(const Section & section)59 inline void ValidateSection(const Section& section) {
60   EXPECT_FALSE(section.name.empty()) << "Section name should not be empty";
61   EXPECT_NE(0u, section.namespaces.size())
62       << "Section " << section.name << " should contain at least one namespace";
63   EXPECT_NE(0u, section.dirs.size())
64       << "Section " << section.name << "does not contain any directory as executable path";
65   EXPECT_TRUE(MapContainsKey(section.namespaces, std::string("default")))
66       << "Section " << section.name << " should contain namespace named 'default'";
67 
68   for (auto& [_, target_namespace] : section.namespaces) {
69     ValidateNamespace(target_namespace, section);
70   }
71 
72   ValidateAllNamespacesAreVisible(section);
73 }
74 
ValidateConfiguration(const Configuration & conf)75 inline void ValidateConfiguration(const Configuration& conf) {
76   EXPECT_NE(0u, conf.sections.size());
77   for (auto& [_, section] : conf.sections) {
78     ValidateSection(section);
79   }
80 }
81 }  // namespace
82 
VerifyConfiguration(const std::string & configuration_str)83 inline void VerifyConfiguration(const std::string& configuration_str) {
84   Configuration conf;
85   ParseConfiguration(configuration_str, conf);
86   ValidateConfiguration(conf);
87 }
88