1 /**
2  * Copyright © 2020 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 "exception_utils.hpp"
17 #include "journal.hpp"
18 #include "mock_journal.hpp"
19 
20 #include <exception>
21 #include <stdexcept>
22 #include <string>
23 #include <vector>
24 
25 #include <gtest/gtest.h>
26 
27 using namespace phosphor::power::regulators;
28 
29 TEST(ExceptionUtilsTests, GetExceptions)
30 {
31     // Test where exception pointer is null
32     {
33         std::exception_ptr eptr;
34         std::vector<std::exception_ptr> exceptions =
35             exception_utils::getExceptions(eptr);
36         EXPECT_EQ(exceptions.size(), 0);
37     }
38 
39     // Test where exception pointer is not null
40     {
41         // Create nested exception with two nesting levels
42         std::exception_ptr eptr;
43         try
44         {
45             try
46             {
47                 throw std::logic_error{"JSON element is not an array"};
48             }
49             catch (...)
50             {
51                 std::throw_with_nested(
52                     std::runtime_error{"Unable to parse config file"});
53             }
54         }
55         catch (...)
56         {
57             eptr = std::current_exception();
58         }
59 
60         // Get vector containing exceptions
61         std::vector<std::exception_ptr> exceptions =
62             exception_utils::getExceptions(eptr);
63         EXPECT_EQ(exceptions.size(), 2);
64 
65         // Verify first exception in vector, which is the innermost exception
66         try
67         {
68             std::rethrow_exception(exceptions[0]);
69             ADD_FAILURE() << "Should not have reached this line.";
70         }
71         catch (const std::logic_error& e)
72         {
73             EXPECT_STREQ(e.what(), "JSON element is not an array");
74         }
75         catch (...)
76         {
77             ADD_FAILURE() << "Unexpected exception type";
78         }
79 
80         // Verify second exception in vector, which is the outermost exception
81         try
82         {
83             std::rethrow_exception(exceptions[1]);
84             ADD_FAILURE() << "Should not have reached this line.";
85         }
86         catch (const std::runtime_error& e)
87         {
88             EXPECT_STREQ(e.what(), "Unable to parse config file");
89         }
90         catch (...)
91         {
92             ADD_FAILURE() << "Unexpected exception type";
93         }
94     }
95 }
96 
97 TEST(ExceptionUtilsTests, GetMessages)
98 {
99     try
100     {
101         try
102         {
103             throw std::invalid_argument{"JSON element is not an array"};
104         }
105         catch (...)
106         {
107             std::throw_with_nested(
108                 std::logic_error{"Unable to parse config file"});
109         }
110     }
111     catch (const std::exception& e)
112     {
113         std::vector<std::string> messages = exception_utils::getMessages(e);
114         EXPECT_EQ(messages.size(), 2);
115         EXPECT_EQ(messages[0], "JSON element is not an array");
116         EXPECT_EQ(messages[1], "Unable to parse config file");
117     }
118 }
119 
120 TEST(ExceptionUtilsTests, InternalGetExceptions)
121 {
122     // Test where exception pointer is null
123     {
124         std::exception_ptr eptr;
125         std::vector<std::exception_ptr> exceptions;
126         exception_utils::internal::getExceptions(eptr, exceptions);
127         EXPECT_EQ(exceptions.size(), 0);
128     }
129 
130     // Test where exception is not nested
131     {
132         // Create exception
133         std::exception_ptr eptr;
134         try
135         {
136             throw std::logic_error{"JSON element is not an array"};
137         }
138         catch (...)
139         {
140             eptr = std::current_exception();
141         }
142 
143         // Build vector of exceptions
144         std::vector<std::exception_ptr> exceptions;
145         exception_utils::internal::getExceptions(eptr, exceptions);
146         EXPECT_EQ(exceptions.size(), 1);
147 
148         // Verify exception in vector
149         try
150         {
151             std::rethrow_exception(exceptions[0]);
152             ADD_FAILURE() << "Should not have reached this line.";
153         }
154         catch (const std::logic_error& e)
155         {
156             EXPECT_STREQ(e.what(), "JSON element is not an array");
157         }
158         catch (...)
159         {
160             ADD_FAILURE() << "Unexpected exception type";
161         }
162     }
163 
164     // Test where exception is nested
165     {
166         // Throw exception with three levels of nesting
167         std::exception_ptr eptr;
168         try
169         {
170             try
171             {
172                 try
173                 {
174                     throw std::string{"Invalid JSON element"};
175                 }
176                 catch (...)
177                 {
178                     std::throw_with_nested(
179                         std::logic_error{"JSON element is not an array"});
180                 }
181             }
182             catch (...)
183             {
184                 std::throw_with_nested(
185                     std::runtime_error{"Unable to parse config file"});
186             }
187         }
188         catch (...)
189         {
190             eptr = std::current_exception();
191         }
192 
193         // Build vector of exceptions
194         std::vector<std::exception_ptr> exceptions;
195         exception_utils::internal::getExceptions(eptr, exceptions);
196         EXPECT_EQ(exceptions.size(), 3);
197 
198         // Verify first exception in vector, which is the innermost exception
199         try
200         {
201             std::rethrow_exception(exceptions[0]);
202             ADD_FAILURE() << "Should not have reached this line.";
203         }
204         catch (const std::string& s)
205         {
206             EXPECT_EQ(s, "Invalid JSON element");
207         }
208         catch (...)
209         {
210             ADD_FAILURE() << "Unexpected exception type";
211         }
212 
213         // Verify second exception in vector
214         try
215         {
216             std::rethrow_exception(exceptions[1]);
217             ADD_FAILURE() << "Should not have reached this line.";
218         }
219         catch (const std::logic_error& e)
220         {
221             EXPECT_STREQ(e.what(), "JSON element is not an array");
222         }
223         catch (...)
224         {
225             ADD_FAILURE() << "Unexpected exception type";
226         }
227 
228         // Verify third exception in vector, which is the outermost exception
229         try
230         {
231             std::rethrow_exception(exceptions[2]);
232             ADD_FAILURE() << "Should not have reached this line.";
233         }
234         catch (const std::runtime_error& e)
235         {
236             EXPECT_STREQ(e.what(), "Unable to parse config file");
237         }
238         catch (...)
239         {
240             ADD_FAILURE() << "Unexpected exception type";
241         }
242     }
243 }
244 
245 TEST(ExceptionUtilsTests, InternalGetMessages)
246 {
247     // Test where exception is not nested
248     {
249         std::invalid_argument e{"JSON element is not an array"};
250         std::vector<std::string> messages{};
251         exception_utils::internal::getMessages(e, messages);
252         EXPECT_EQ(messages.size(), 1);
253         EXPECT_EQ(messages[0], "JSON element is not an array");
254     }
255 
256     // Test where exception is nested
257     try
258     {
259         try
260         {
261             try
262             {
263                 throw std::invalid_argument{"JSON element is not an array"};
264             }
265             catch (...)
266             {
267                 std::throw_with_nested(
268                     std::logic_error{"Unable to parse config file"});
269             }
270         }
271         catch (...)
272         {
273             std::throw_with_nested(
274                 std::runtime_error{"Unable to configure regulators"});
275         }
276     }
277     catch (const std::exception& e)
278     {
279         std::vector<std::string> messages{};
280         exception_utils::internal::getMessages(e, messages);
281         EXPECT_EQ(messages.size(), 3);
282         EXPECT_EQ(messages[0], "JSON element is not an array");
283         EXPECT_EQ(messages[1], "Unable to parse config file");
284         EXPECT_EQ(messages[2], "Unable to configure regulators");
285     }
286 
287     // Test where nested exception is not a child of std::exception
288     try
289     {
290         try
291         {
292             try
293             {
294                 throw "JSON element is not an array";
295             }
296             catch (...)
297             {
298                 std::throw_with_nested(
299                     std::logic_error{"Unable to parse config file"});
300             }
301         }
302         catch (...)
303         {
304             std::throw_with_nested(
305                 std::runtime_error{"Unable to configure regulators"});
306         }
307     }
308     catch (const std::exception& e)
309     {
310         std::vector<std::string> messages{};
311         exception_utils::internal::getMessages(e, messages);
312         EXPECT_EQ(messages.size(), 2);
313         EXPECT_EQ(messages[0], "Unable to parse config file");
314         EXPECT_EQ(messages[1], "Unable to configure regulators");
315     }
316 }
317