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