1 /*
2 * Copyright 2019 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 "rtc_base/experiments/field_trial_list.h"
12
13 #include "rtc_base/gunit.h"
14 #include "test/gmock.h"
15
16 using testing::ElementsAre;
17 using testing::IsEmpty;
18
19 namespace webrtc {
20
21 struct Garment {
22 int price = 0;
23 std::string color = "";
24
25 // Only needed for testing.
26 Garment() = default;
Garmentwebrtc::Garment27 Garment(int p, std::string c) : price(p), color(c) {}
28
operator ==webrtc::Garment29 bool operator==(const Garment& other) const {
30 return price == other.price && color == other.color;
31 }
32 };
33
TEST(FieldTrialListTest,ParsesListParameter)34 TEST(FieldTrialListTest, ParsesListParameter) {
35 FieldTrialList<int> my_list("l", {5});
36 EXPECT_THAT(my_list.Get(), ElementsAre(5));
37 // If one element is invalid the list is unchanged.
38 ParseFieldTrial({&my_list}, "l:1|2|hat");
39 EXPECT_THAT(my_list.Get(), ElementsAre(5));
40 ParseFieldTrial({&my_list}, "l");
41 EXPECT_THAT(my_list.Get(), IsEmpty());
42 ParseFieldTrial({&my_list}, "l:1|2|3");
43 EXPECT_THAT(my_list.Get(), ElementsAre(1, 2, 3));
44 ParseFieldTrial({&my_list}, "l:-1");
45 EXPECT_THAT(my_list.Get(), ElementsAre(-1));
46
47 FieldTrialList<std::string> another_list("l", {"hat"});
48 EXPECT_THAT(another_list.Get(), ElementsAre("hat"));
49 ParseFieldTrial({&another_list}, "l");
50 EXPECT_THAT(another_list.Get(), IsEmpty());
51 ParseFieldTrial({&another_list}, "l:");
52 EXPECT_THAT(another_list.Get(), ElementsAre(""));
53 ParseFieldTrial({&another_list}, "l:scarf|hat|mittens");
54 EXPECT_THAT(another_list.Get(), ElementsAre("scarf", "hat", "mittens"));
55 ParseFieldTrial({&another_list}, "l:scarf");
56 EXPECT_THAT(another_list.Get(), ElementsAre("scarf"));
57 }
58
59 // Normal usage.
TEST(FieldTrialListTest,ParsesStructList)60 TEST(FieldTrialListTest, ParsesStructList) {
61 FieldTrialStructList<Garment> my_list(
62 {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }),
63 FieldTrialStructMember("price", [](Garment* g) { return &g->price; })},
64 {{1, "blue"}, {2, "red"}});
65
66 ParseFieldTrial({&my_list},
67 "color:mauve|red|gold,"
68 "price:10|20|30,"
69 "other_param:asdf");
70
71 ASSERT_THAT(my_list.Get(),
72 ElementsAre(Garment{10, "mauve"}, Garment{20, "red"},
73 Garment{30, "gold"}));
74 }
75
76 // One FieldTrialList has the wrong length, so we use the user-provided default
77 // list.
TEST(FieldTrialListTest,StructListKeepsDefaultWithMismatchingLength)78 TEST(FieldTrialListTest, StructListKeepsDefaultWithMismatchingLength) {
79 FieldTrialStructList<Garment> my_list(
80 {FieldTrialStructMember("wrong_length",
81 [](Garment* g) { return &g->color; }),
82 FieldTrialStructMember("price", [](Garment* g) { return &g->price; })},
83 {{1, "blue"}, {2, "red"}});
84
85 ParseFieldTrial({&my_list},
86 "wrong_length:mauve|magenta|chartreuse|indigo,"
87 "garment:hat|hat|crown,"
88 "price:10|20|30");
89
90 ASSERT_THAT(my_list.Get(),
91 ElementsAre(Garment{1, "blue"}, Garment{2, "red"}));
92 }
93
94 // One list is missing. We set the values we're given, and the others remain
95 // as whatever the Garment default constructor set them to.
TEST(FieldTrialListTest,StructListUsesDefaultForMissingList)96 TEST(FieldTrialListTest, StructListUsesDefaultForMissingList) {
97 FieldTrialStructList<Garment> my_list(
98 {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }),
99 FieldTrialStructMember("price", [](Garment* g) { return &g->price; })},
100 {{1, "blue"}, {2, "red"}});
101
102 ParseFieldTrial({&my_list}, "price:10|20|30");
103
104 ASSERT_THAT(my_list.Get(),
105 ElementsAre(Garment{10, ""}, Garment{20, ""}, Garment{30, ""}));
106 }
107
108 // The user haven't provided values for any lists, so we use the default list.
TEST(FieldTrialListTest,StructListUsesDefaultListWithoutValues)109 TEST(FieldTrialListTest, StructListUsesDefaultListWithoutValues) {
110 FieldTrialStructList<Garment> my_list(
111 {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }),
112 FieldTrialStructMember("price", [](Garment* g) { return &g->price; })},
113 {{1, "blue"}, {2, "red"}});
114
115 ParseFieldTrial({&my_list}, "");
116
117 ASSERT_THAT(my_list.Get(),
118 ElementsAre(Garment{1, "blue"}, Garment{2, "red"}));
119 }
120
121 // Some lists are provided and all are empty, so we return a empty list.
TEST(FieldTrialListTest,StructListHandlesEmptyLists)122 TEST(FieldTrialListTest, StructListHandlesEmptyLists) {
123 FieldTrialStructList<Garment> my_list(
124 {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }),
125 FieldTrialStructMember("price", [](Garment* g) { return &g->price; })},
126 {{1, "blue"}, {2, "red"}});
127
128 ParseFieldTrial({&my_list}, "color,price");
129
130 ASSERT_EQ(my_list.Get().size(), 0u);
131 }
132
133 } // namespace webrtc
134