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