1 /**
2  * Copyright © 2019 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "action.hpp"
17 #include "action_environment.hpp"
18 #include "id_map.hpp"
19 #include "if_action.hpp"
20 #include "mock_action.hpp"
21 
22 #include <exception>
23 #include <memory>
24 #include <stdexcept>
25 #include <utility>
26 #include <vector>
27 
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30 
31 using namespace phosphor::power::regulators;
32 
33 using ::testing::Return;
34 using ::testing::Throw;
35 
36 TEST(IfActionTests, Constructor)
37 {
38     // Test where else clause is not specified
39     {
40         std::unique_ptr<Action> conditionAction =
41             std::make_unique<MockAction>();
42 
43         std::vector<std::unique_ptr<Action>> thenActions{};
44         thenActions.push_back(std::make_unique<MockAction>());
45         thenActions.push_back(std::make_unique<MockAction>());
46 
47         IfAction ifAction{std::move(conditionAction), std::move(thenActions)};
48         EXPECT_NE(ifAction.getConditionAction().get(), nullptr);
49         EXPECT_EQ(ifAction.getThenActions().size(), 2);
50         EXPECT_EQ(ifAction.getElseActions().size(), 0);
51     }
52 
53     // Test where else clause is specified
54     {
55         std::unique_ptr<Action> conditionAction =
56             std::make_unique<MockAction>();
57 
58         std::vector<std::unique_ptr<Action>> thenActions{};
59         thenActions.push_back(std::make_unique<MockAction>());
60         thenActions.push_back(std::make_unique<MockAction>());
61 
62         std::vector<std::unique_ptr<Action>> elseActions{};
63         elseActions.push_back(std::make_unique<MockAction>());
64 
65         IfAction ifAction{std::move(conditionAction), std::move(thenActions),
66                           std::move(elseActions)};
67         EXPECT_NE(ifAction.getConditionAction().get(), nullptr);
68         EXPECT_EQ(ifAction.getThenActions().size(), 2);
69         EXPECT_EQ(ifAction.getElseActions().size(), 1);
70     }
71 }
72 
73 TEST(IfActionTests, Execute)
74 {
75     // Create ActionEnvironment
76     IDMap idMap{};
77     ActionEnvironment env{idMap, ""};
78 
79     // Test where action throws an exception
80     try
81     {
82         // Create condition action that will return true
83         std::unique_ptr<MockAction> conditionAction =
84             std::make_unique<MockAction>();
85         EXPECT_CALL(*conditionAction, execute).Times(1).WillOnce(Return(true));
86 
87         // Create vector of actions for then clause
88         std::vector<std::unique_ptr<Action>> thenActions{};
89         std::unique_ptr<MockAction> thenAction;
90 
91         // First then action will throw an exception
92         thenAction = std::make_unique<MockAction>();
93         EXPECT_CALL(*thenAction, execute)
94             .Times(1)
95             .WillOnce(Throw(std::logic_error{"Communication error"}));
96         thenActions.push_back(std::move(thenAction));
97 
98         // Second then action should not get executed
99         thenAction = std::make_unique<MockAction>();
100         EXPECT_CALL(*thenAction, execute).Times(0);
101         thenActions.push_back(std::move(thenAction));
102 
103         IfAction ifAction{std::move(conditionAction), std::move(thenActions)};
104         ifAction.execute(env);
105         ADD_FAILURE() << "Should not have reached this line.";
106     }
107     catch (const std::exception& error)
108     {
109         EXPECT_STREQ(error.what(), "Communication error");
110     }
111 
112     // Test where condition is true: then clause returns true
113     try
114     {
115         // Create condition action that will return true
116         std::unique_ptr<MockAction> conditionAction =
117             std::make_unique<MockAction>();
118         EXPECT_CALL(*conditionAction, execute).Times(1).WillOnce(Return(true));
119 
120         // Create vector of actions for then clause: last action returns true
121         std::vector<std::unique_ptr<Action>> thenActions{};
122         std::unique_ptr<MockAction> thenAction = std::make_unique<MockAction>();
123         EXPECT_CALL(*thenAction, execute).Times(1).WillOnce(Return(true));
124         thenActions.push_back(std::move(thenAction));
125 
126         // Create vector of actions for else clause: should not be executed
127         std::vector<std::unique_ptr<Action>> elseActions{};
128         std::unique_ptr<MockAction> elseAction = std::make_unique<MockAction>();
129         EXPECT_CALL(*elseAction, execute).Times(0);
130         elseActions.push_back(std::move(elseAction));
131 
132         IfAction ifAction{std::move(conditionAction), std::move(thenActions),
133                           std::move(elseActions)};
134         EXPECT_EQ(ifAction.execute(env), true);
135     }
136     catch (const std::exception& error)
137     {
138         ADD_FAILURE() << "Should not have caught exception.";
139     }
140 
141     // Test where condition is true: then clause returns false
142     try
143     {
144         // Create condition action that will return true
145         std::unique_ptr<MockAction> conditionAction =
146             std::make_unique<MockAction>();
147         EXPECT_CALL(*conditionAction, execute).Times(1).WillOnce(Return(true));
148 
149         // Create vector of actions for then clause: last action returns false
150         std::vector<std::unique_ptr<Action>> thenActions{};
151         std::unique_ptr<MockAction> thenAction = std::make_unique<MockAction>();
152         EXPECT_CALL(*thenAction, execute).Times(1).WillOnce(Return(false));
153         thenActions.push_back(std::move(thenAction));
154 
155         // Create vector of actions for else clause: should not be executed
156         std::vector<std::unique_ptr<Action>> elseActions{};
157         std::unique_ptr<MockAction> elseAction = std::make_unique<MockAction>();
158         EXPECT_CALL(*elseAction, execute).Times(0);
159         elseActions.push_back(std::move(elseAction));
160 
161         IfAction ifAction{std::move(conditionAction), std::move(thenActions),
162                           std::move(elseActions)};
163         EXPECT_EQ(ifAction.execute(env), false);
164     }
165     catch (const std::exception& error)
166     {
167         ADD_FAILURE() << "Should not have caught exception.";
168     }
169 
170     // Test where condition is false: else clause returns true
171     try
172     {
173         // Create condition action that will return false
174         std::unique_ptr<MockAction> conditionAction =
175             std::make_unique<MockAction>();
176         EXPECT_CALL(*conditionAction, execute).Times(1).WillOnce(Return(false));
177 
178         // Create vector of actions for then clause: should not be executed
179         std::vector<std::unique_ptr<Action>> thenActions{};
180         std::unique_ptr<MockAction> thenAction = std::make_unique<MockAction>();
181         EXPECT_CALL(*thenAction, execute).Times(0);
182         thenActions.push_back(std::move(thenAction));
183 
184         // Create vector of actions for else clause: last action returns true
185         std::vector<std::unique_ptr<Action>> elseActions{};
186         std::unique_ptr<MockAction> elseAction = std::make_unique<MockAction>();
187         EXPECT_CALL(*elseAction, execute).Times(1).WillOnce(Return(true));
188         elseActions.push_back(std::move(elseAction));
189 
190         IfAction ifAction{std::move(conditionAction), std::move(thenActions),
191                           std::move(elseActions)};
192         EXPECT_EQ(ifAction.execute(env), true);
193     }
194     catch (const std::exception& error)
195     {
196         ADD_FAILURE() << "Should not have caught exception.";
197     }
198 
199     // Test where condition is false: else clause returns false
200     try
201     {
202         // Create condition action that will return false
203         std::unique_ptr<MockAction> conditionAction =
204             std::make_unique<MockAction>();
205         EXPECT_CALL(*conditionAction, execute).Times(1).WillOnce(Return(false));
206 
207         // Create vector of actions for then clause: should not be executed
208         std::vector<std::unique_ptr<Action>> thenActions{};
209         std::unique_ptr<MockAction> thenAction = std::make_unique<MockAction>();
210         EXPECT_CALL(*thenAction, execute).Times(0);
211         thenActions.push_back(std::move(thenAction));
212 
213         // Create vector of actions for else clause: last action returns false
214         std::vector<std::unique_ptr<Action>> elseActions{};
215         std::unique_ptr<MockAction> elseAction = std::make_unique<MockAction>();
216         EXPECT_CALL(*elseAction, execute).Times(1).WillOnce(Return(false));
217         elseActions.push_back(std::move(elseAction));
218 
219         IfAction ifAction{std::move(conditionAction), std::move(thenActions),
220                           std::move(elseActions)};
221         EXPECT_EQ(ifAction.execute(env), false);
222     }
223     catch (const std::exception& error)
224     {
225         ADD_FAILURE() << "Should not have caught exception.";
226     }
227 
228     // Test where condition is false: no else clause specified
229     try
230     {
231         // Create condition action that will return false
232         std::unique_ptr<MockAction> conditionAction =
233             std::make_unique<MockAction>();
234         EXPECT_CALL(*conditionAction, execute).Times(1).WillOnce(Return(false));
235 
236         // Create vector of actions for then clause: should not be executed
237         std::vector<std::unique_ptr<Action>> thenActions{};
238         std::unique_ptr<MockAction> thenAction = std::make_unique<MockAction>();
239         EXPECT_CALL(*thenAction, execute).Times(0);
240         thenActions.push_back(std::move(thenAction));
241 
242         IfAction ifAction{std::move(conditionAction), std::move(thenActions)};
243         EXPECT_EQ(ifAction.execute(env), false);
244     }
245     catch (const std::exception& error)
246     {
247         ADD_FAILURE() << "Should not have caught exception.";
248     }
249 }
250 
251 TEST(IfActionTests, GetConditionAction)
252 {
253     MockAction* conditionAction = new MockAction{};
254 
255     std::vector<std::unique_ptr<Action>> thenActions{};
256 
257     IfAction ifAction{std::unique_ptr<Action>{conditionAction},
258                       std::move(thenActions)};
259 
260     EXPECT_EQ(ifAction.getConditionAction().get(), conditionAction);
261 }
262 
263 TEST(IfActionTests, GetThenActions)
264 {
265     std::unique_ptr<Action> conditionAction = std::make_unique<MockAction>();
266 
267     std::vector<std::unique_ptr<Action>> thenActions{};
268 
269     MockAction* thenAction1 = new MockAction{};
270     thenActions.push_back(std::unique_ptr<MockAction>{thenAction1});
271 
272     MockAction* thenAction2 = new MockAction{};
273     thenActions.push_back(std::unique_ptr<MockAction>{thenAction2});
274 
275     IfAction ifAction{std::move(conditionAction), std::move(thenActions)};
276     EXPECT_EQ(ifAction.getThenActions().size(), 2);
277     EXPECT_EQ(ifAction.getThenActions()[0].get(), thenAction1);
278     EXPECT_EQ(ifAction.getThenActions()[1].get(), thenAction2);
279 }
280 
281 TEST(IfActionTests, GetElseActions)
282 {
283     std::unique_ptr<Action> conditionAction = std::make_unique<MockAction>();
284 
285     std::vector<std::unique_ptr<Action>> thenActions{};
286 
287     std::vector<std::unique_ptr<Action>> elseActions{};
288 
289     MockAction* elseAction1 = new MockAction{};
290     elseActions.push_back(std::unique_ptr<MockAction>{elseAction1});
291 
292     MockAction* elseAction2 = new MockAction{};
293     elseActions.push_back(std::unique_ptr<MockAction>{elseAction2});
294 
295     IfAction ifAction{std::move(conditionAction), std::move(thenActions),
296                       std::move(elseActions)};
297     EXPECT_EQ(ifAction.getElseActions().size(), 2);
298     EXPECT_EQ(ifAction.getElseActions()[0].get(), elseAction1);
299     EXPECT_EQ(ifAction.getElseActions()[1].get(), elseAction2);
300 }
301 
302 TEST(IfActionTests, ToString)
303 {
304     // Test where else clause is not specified
305     {
306         std::unique_ptr<Action> conditionAction =
307             std::make_unique<MockAction>();
308 
309         std::vector<std::unique_ptr<Action>> thenActions{};
310         thenActions.push_back(std::make_unique<MockAction>());
311 
312         IfAction ifAction{std::move(conditionAction), std::move(thenActions)};
313         EXPECT_EQ(ifAction.toString(),
314                   "if: { condition: { ... }, then: [ ... ] }");
315     }
316 
317     // Test where else clause is specified
318     {
319         std::unique_ptr<Action> conditionAction =
320             std::make_unique<MockAction>();
321 
322         std::vector<std::unique_ptr<Action>> thenActions{};
323         thenActions.push_back(std::make_unique<MockAction>());
324 
325         std::vector<std::unique_ptr<Action>> elseActions{};
326         elseActions.push_back(std::make_unique<MockAction>());
327 
328         IfAction ifAction{std::move(conditionAction), std::move(thenActions),
329                           std::move(elseActions)};
330         EXPECT_EQ(ifAction.toString(),
331                   "if: { condition: { ... }, then: [ ... ], else: [ ... ] }");
332     }
333 }
334