blob: 449d5f0722a48ca8af0bf120bc47af782cce01f6 [file] [log] [blame]
Jonas Orelanded99dae2022-03-09 09:28:10 +01001/*
2 * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "test/scoped_key_value_config.h"
12
Jonas Orelande62c2f22022-03-29 11:04:48 +020013#include "api/field_trials_view.h"
Jonas Orelanded99dae2022-03-09 09:28:10 +010014#include "rtc_base/checks.h"
Jonas Orelandd7f95502022-03-22 16:52:08 +010015#include "system_wrappers/include/field_trial.h"
Jonas Orelanded99dae2022-03-09 09:28:10 +010016#include "test/field_trial.h"
17
18namespace {
19
20// This part is copied from system_wrappers/field_trial.cc.
Danil Chapovalov385b6c52022-04-08 16:01:50 +020021void InsertIntoMap(
22 std::map<std::string, std::string, std::less<>>& key_value_map,
23 absl::string_view s) {
Jonas Orelanded99dae2022-03-09 09:28:10 +010024 std::string::size_type field_start = 0;
25 while (field_start < s.size()) {
26 std::string::size_type separator_pos = s.find('/', field_start);
27 RTC_CHECK_NE(separator_pos, std::string::npos)
28 << "Missing separator '/' after field trial key.";
29 RTC_CHECK_GT(separator_pos, field_start)
30 << "Field trial key cannot be empty.";
Danil Chapovalov385b6c52022-04-08 16:01:50 +020031 std::string key(s.substr(field_start, separator_pos - field_start));
Jonas Orelanded99dae2022-03-09 09:28:10 +010032 field_start = separator_pos + 1;
33
34 RTC_CHECK_LT(field_start, s.size())
35 << "Missing value after field trial key. String ended.";
36 separator_pos = s.find('/', field_start);
37 RTC_CHECK_NE(separator_pos, std::string::npos)
38 << "Missing terminating '/' in field trial string.";
39 RTC_CHECK_GT(separator_pos, field_start)
40 << "Field trial value cannot be empty.";
Danil Chapovalov385b6c52022-04-08 16:01:50 +020041 std::string value(s.substr(field_start, separator_pos - field_start));
Jonas Orelanded99dae2022-03-09 09:28:10 +010042 field_start = separator_pos + 1;
43
44 key_value_map[key] = value;
45 }
46 // This check is technically redundant due to earlier checks.
47 // We nevertheless keep the check to make it clear that the entire
48 // string has been processed, and without indexing past the end.
49 RTC_CHECK_EQ(field_start, s.size());
50}
51
52} // namespace
53
54namespace webrtc {
55namespace test {
56
57ScopedKeyValueConfig::ScopedKeyValueConfig()
58 : ScopedKeyValueConfig(nullptr, "") {}
59
Danil Chapovalov385b6c52022-04-08 16:01:50 +020060ScopedKeyValueConfig::ScopedKeyValueConfig(absl::string_view s)
Jonas Orelanded99dae2022-03-09 09:28:10 +010061 : ScopedKeyValueConfig(nullptr, s) {}
62
63ScopedKeyValueConfig::ScopedKeyValueConfig(ScopedKeyValueConfig& parent,
Danil Chapovalov385b6c52022-04-08 16:01:50 +020064 absl::string_view s)
Jonas Orelanded99dae2022-03-09 09:28:10 +010065 : ScopedKeyValueConfig(&parent, s) {}
66
67ScopedKeyValueConfig::ScopedKeyValueConfig(ScopedKeyValueConfig* parent,
Danil Chapovalov385b6c52022-04-08 16:01:50 +020068 absl::string_view s)
Jonas Orelanded99dae2022-03-09 09:28:10 +010069 : parent_(parent), leaf_(nullptr) {
70 InsertIntoMap(key_value_map_, s);
Jonas Oreland8ca06132022-03-14 12:52:48 +010071
72 if (!s.empty()) {
73 // Also store field trials in global string (until we get rid of it).
74 scoped_field_trials_ = std::make_unique<ScopedFieldTrials>(s);
75 }
Jonas Orelanded99dae2022-03-09 09:28:10 +010076
77 if (parent == nullptr) {
78 // We are root, set leaf_.
79 leaf_ = this;
80 } else {
81 // Link root to new leaf.
82 GetRoot(parent)->leaf_ = this;
83 RTC_DCHECK(leaf_ == nullptr);
84 }
85}
86
87ScopedKeyValueConfig::~ScopedKeyValueConfig() {
88 if (parent_) {
89 GetRoot(parent_)->leaf_ = parent_;
90 }
91}
92
93ScopedKeyValueConfig* ScopedKeyValueConfig::GetRoot(ScopedKeyValueConfig* n) {
94 while (n->parent_ != nullptr) {
95 n = n->parent_;
96 }
97 return n;
98}
99
100std::string ScopedKeyValueConfig::Lookup(absl::string_view key) const {
101 if (parent_ == nullptr) {
102 return leaf_->LookupRecurse(key);
103 } else {
104 return LookupRecurse(key);
105 }
106}
107
108std::string ScopedKeyValueConfig::LookupRecurse(absl::string_view key) const {
Danil Chapovalov385b6c52022-04-08 16:01:50 +0200109 auto it = key_value_map_.find(key);
Jonas Orelanded99dae2022-03-09 09:28:10 +0100110 if (it != key_value_map_.end())
111 return it->second;
112
113 if (parent_) {
114 return parent_->LookupRecurse(key);
115 }
116
Jonas Orelandd7f95502022-03-22 16:52:08 +0100117 // When at the root, check the global string so that test programs using
118 // a mix between ScopedKeyValueConfig and the global string continue to work
119 return webrtc::field_trial::FindFullName(std::string(key));
Jonas Orelanded99dae2022-03-09 09:28:10 +0100120}
121
122} // namespace test
123} // namespace webrtc