| 88 | } |
| 89 | |
| 90 | static void validateToplevelConfig(std::string name) |
| 91 | { |
| 92 | ConfigProto config = findConfig(name); |
| 93 | |
| 94 | /* Don't test extension configs. */ |
| 95 | |
| 96 | if (config.is_extension()) |
| 97 | return; |
| 98 | |
| 99 | /* Collate options. */ |
| 100 | |
| 101 | std::map<std::string, const OptionProto*> optionProtos; |
| 102 | std::vector<std::vector<std::string>> optionGroups; |
| 103 | auto checkOption = [&](const auto& option) |
| 104 | { |
| 105 | if (optionProtos.find(option.name()) != optionProtos.end()) |
| 106 | configError("{}: option name '{}' is used more than once", |
| 107 | name, |
| 108 | option.name()); |
| 109 | |
| 110 | if (!option.has_comment()) |
| 111 | configError("{}: option '{}' has no comment", name, option.name()); |
| 112 | |
| 113 | optionProtos[option.name()] = &option; |
| 114 | }; |
| 115 | |
| 116 | for (const auto& group : config.option_group()) |
| 117 | { |
| 118 | auto& v = optionGroups.emplace_back(); |
| 119 | for (const auto& option : group.option()) |
| 120 | { |
| 121 | checkOption(option); |
| 122 | v.push_back(option.name()); |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | for (const auto& option : config.option()) |
| 127 | { |
| 128 | checkOption(option); |
| 129 | optionGroups.emplace_back(std::vector<std::string>{"", option.name()}); |
| 130 | } |
| 131 | |
| 132 | /* For each permutation of options, verify the complete config. */ |
| 133 | |
| 134 | auto combinations = generateCombinations(optionGroups); |
| 135 | if (combinations.empty()) |
| 136 | validateConfigWithOptions(name, {}, config); |
| 137 | else |
| 138 | for (const auto& group : combinations) |
| 139 | { |
| 140 | ConfigProto configWithOption = config; |
| 141 | for (const auto& optionName : group) |
| 142 | { |
| 143 | if (!optionName.empty()) |
| 144 | configWithOption.MergeFrom( |
| 145 | optionProtos.at(optionName)->config()); |
| 146 | } |
| 147 | validateConfigWithOptions(name, group, configWithOption); |
no test coverage detected