1 #include "helpers.hpp"
2 #include "utils/dbus_path_utils.hpp"
3 #include "utils/make_id_name.hpp"
4 #include "utils/string_utils.hpp"
5 
6 #include <sdbusplus/exception.hpp>
7 
8 #include <gmock/gmock.h>
9 
10 using namespace testing;
11 using namespace std::literals::string_literals;
12 using namespace utils::string_utils;
13 
14 class ScenarioBase : public Test
15 {
16   public:
17     std::string_view defaultName = "defName";
18     std::vector<std::string> conflicts;
19 };
20 
21 class ScenarioNameProvided : public ScenarioBase
22 {
23   public:
24     auto makeIdName(std::string_view id, std::string_view name) const
25     {
26         return utils::makeIdName(id, name, defaultName, conflicts);
27     }
28 };
29 
30 TEST_F(ScenarioNameProvided, throwsWhenProvidedNameIsTooLong)
31 {
32     EXPECT_THROW(this->makeIdName("", getTooLongName()),
33                  errors::InvalidArgument);
34 }
35 
36 class TestMakeIdNameNameProvided : public ScenarioNameProvided
37 {};
38 
39 TEST_F(TestMakeIdNameNameProvided, usesIdWhenProvided)
40 {
41     const std::string name = "name";
42 
43     EXPECT_THAT(this->makeIdName("id0", name), Eq(std::pair{"id0"s, name}));
44     EXPECT_THAT(this->makeIdName("prefix/id2", name),
45                 Eq(std::pair{"prefix/id2"s, name}));
46 }
47 
48 TEST_F(TestMakeIdNameNameProvided, usedDefaultWhenNothingProvided)
49 {
50     this->defaultName = "def";
51 
52     EXPECT_THAT(this->makeIdName("", ""), Eq(std::pair{"def"s, "def"s}));
53     EXPECT_THAT(this->makeIdName("abc/", ""),
54                 Eq(std::pair{"abc/def"s, "def"s}));
55 }
56 
57 TEST_F(TestMakeIdNameNameProvided, usedDefaultWhenNameContainsNoIdChars)
58 {
59     this->defaultName = "def";
60     const std::string name = " !";
61 
62     EXPECT_THAT(this->makeIdName("", name), Eq(std::pair{"def"s, name}));
63     EXPECT_THAT(this->makeIdName("prefix/", name),
64                 Eq(std::pair{"prefix/def"s, name}));
65 }
66 
67 class ScenarioNameNotProvided : public ScenarioBase
68 {
69   public:
70     auto makeIdName(std::string_view id, std::string_view name) const
71     {
72         return utils::makeIdName(id, "", name, conflicts);
73     }
74 };
75 
76 class TestMakeIdNameNameNotProvided : public ScenarioNameNotProvided
77 {};
78 
79 TEST_F(TestMakeIdNameNameNotProvided, usesIdAsNameWhenProvided)
80 {
81     EXPECT_THAT(this->makeIdName("id0", defaultName),
82                 Eq(std::pair{"id0"s, "id0"s}));
83     EXPECT_THAT(this->makeIdName("prefix/id2", defaultName),
84                 Eq(std::pair{"prefix/id2"s, "id2"s}));
85 }
86 
87 template <class Scenario>
88 class TestMakeIdName : public Scenario
89 {};
90 
91 using TestScenarios =
92     ::testing::Types<ScenarioNameProvided, ScenarioNameNotProvided>;
93 TYPED_TEST_SUITE(TestMakeIdName, TestScenarios);
94 
95 TYPED_TEST(TestMakeIdName, throwsWhenProvidedIdContainsIncorrectCharacters)
96 {
97     EXPECT_THROW(this->makeIdName("Id%@%!@%!%()%fooo/Id", "name"),
98                  errors::InvalidArgument);
99     EXPECT_THROW(this->makeIdName("Id/Id%@%!@%!%()%fooo", "name"),
100                  errors::InvalidArgument);
101     EXPECT_THROW(this->makeIdName("/123", "trigger"), errors::InvalidArgument);
102     EXPECT_THROW(this->makeIdName("/123/", "trigger"), errors::InvalidArgument);
103 }
104 
105 TYPED_TEST(TestMakeIdName, throwsWhenProvidedIdContainsTooLongSegment)
106 {
107     std::string longPrefix = getTooLongPrefix();
108     std::string longSuffix = getTooLongId();
109     EXPECT_THROW(this->makeIdName(longPrefix + "/", "name"),
110                  errors::InvalidArgument);
111     EXPECT_THROW(this->makeIdName(longPrefix + "/Id", "name"),
112                  errors::InvalidArgument);
113     EXPECT_THROW(this->makeIdName(longPrefix + "/" + longSuffix, "name"),
114                  errors::InvalidArgument);
115     EXPECT_THROW(this->makeIdName("Prefix/" + longSuffix, "name"),
116                  errors::InvalidArgument);
117     EXPECT_THROW(this->makeIdName(longSuffix, "name"), errors::InvalidArgument);
118 }
119 
120 TYPED_TEST(TestMakeIdName, throwsWhenProvidedIdOrPrefixTooLong)
121 {
122     EXPECT_THROW(this->makeIdName(getTooLongId(), "name"),
123                  errors::InvalidArgument);
124     EXPECT_THROW(this->makeIdName(getTooLongPrefix() + "/Id", "name"),
125                  errors::InvalidArgument);
126     EXPECT_THROW(this->makeIdName("Prefix/" + getTooLongId(), "trigger"),
127                  errors::InvalidArgument);
128 }
129 
130 TYPED_TEST(TestMakeIdName, throwsWhenIdContainsMoreThanOneSlash)
131 {
132     EXPECT_THROW(this->makeIdName("/12/", "name"), errors::InvalidArgument);
133     EXPECT_THROW(this->makeIdName("12//", "name"), errors::InvalidArgument);
134     EXPECT_THROW(this->makeIdName("12//123", "name"), errors::InvalidArgument);
135     EXPECT_THROW(this->makeIdName("12/12/123", "name"),
136                  errors::InvalidArgument);
137 }
138 
139 TYPED_TEST(TestMakeIdName, usesNameWhenThereAreConflicts)
140 {
141     this->conflicts = {"trigger"};
142     EXPECT_THAT(this->makeIdName("", "trigger"),
143                 Eq(std::pair{"trigger0"s, "trigger"s}));
144 
145     this->conflicts = {"trigger", "trigger0"};
146     EXPECT_THAT(this->makeIdName("", "trigger"),
147                 Eq(std::pair{"trigger1"s, "trigger"s}));
148 
149     this->conflicts = {getMaxId()};
150     std::string expectedId = getMaxId();
151     expectedId[expectedId.length() - 1] = '0';
152     EXPECT_THAT(this->makeIdName("", getMaxId()),
153                 Eq(std::pair{expectedId, getMaxId()}));
154 }
155 
156 TYPED_TEST(TestMakeIdName, throwsWhenProvidedIdIsTaken)
157 {
158     this->conflicts = {"id", "prefix/id"};
159 
160     EXPECT_THROW(this->makeIdName("id", "name"),
161                  sdbusplus::exception::SdBusError);
162     EXPECT_THROW(this->makeIdName("prefix/id", "name"),
163                  sdbusplus::exception::SdBusError);
164 }
165 
166 TYPED_TEST(TestMakeIdName, usesNameWhenIdNotProvided)
167 {
168     EXPECT_THAT(this->makeIdName("", "name"), Eq(std::pair{"name"s, "name"s}));
169     EXPECT_THAT(this->makeIdName("abc/", "name"),
170                 Eq(std::pair{"abc/name"s, "name"s}));
171     EXPECT_THAT(this->makeIdName("123/", "name"),
172                 Eq(std::pair{"123/name"s, "name"s}));
173 }
174 
175 TYPED_TEST(TestMakeIdName, usesNameWithoutInvalidCharactersWhenIdNotProvided)
176 {
177     EXPECT_THAT(this->makeIdName("", "n#a$/m@e"),
178                 Eq(std::pair{"name"s, "n#a$/m@e"s}));
179     EXPECT_THAT(this->makeIdName("", "n!^aŹ/me"),
180                 Eq(std::pair{"name"s, "n!^aŹ/me"s}));
181     EXPECT_THAT(this->makeIdName("p/", "n!^aŹ/m*(e"),
182                 Eq(std::pair{"p/name"s, "n!^aŹ/m*(e"s}));
183 }
184