https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MooseUnitUtils.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
12#include "gtest/gtest.h"
13
14#include <filesystem>
15#include <string>
16#include <vector>
17
18#include "libmesh/utility.h"
19
20#include "MooseUtils.h"
21#include "Moose.h"
22
24{
32template <class ExceptionType = std::exception, class Action = bool>
33void
34assertThrows(const Action & action,
35 const std::optional<std::string> & contains = {},
36 const bool set_throw_on_error = false)
37{
38 static_assert(std::is_base_of_v<std::exception, ExceptionType>, "Not an exception");
39
40 std::unique_ptr<Moose::ScopedThrowOnError> scoped_throw_on_error;
41 if (set_throw_on_error)
42 scoped_throw_on_error = std::make_unique<Moose::ScopedThrowOnError>();
43
44 try
45 {
46 action();
47 FAIL() << "Expected " << MooseUtils::prettyCppType<ExceptionType>() << " not thrown";
48 }
49 catch (std::exception const & e)
50 {
51 if constexpr (!std::is_same_v<std::exception, ExceptionType>)
52 if (!dynamic_cast<const ExceptionType *>(&e))
53 FAIL() << "Threw " << demangle(typeid(e).name()) << " instead of "
54 << MooseUtils::prettyCppType<ExceptionType>() << " with message '" << e.what()
55 << "'";
56
57 if (contains)
58 {
59 ASSERT_TRUE(std::string(e.what()).find(*contains) != std::string::npos)
60 << "Exception \"" << e.what() << "\" does not contain \"" << *contains << "\"";
61 }
62 }
63}
64
68template <typename ExceptionType, bool exact, bool assert, bool set_throw_on_error, typename Func>
69void
70throwsWithMessage(Func && fn, const std::string_view message, const char * file, int line)
71{
72 static_assert(std::is_base_of_v<std::exception, ExceptionType>, "Not an exception");
73
74 std::ostringstream error;
75
76 try
77 {
78 std::unique_ptr<Moose::ScopedThrowOnError> scoped_throw_on_error;
79 if constexpr (set_throw_on_error)
80 scoped_throw_on_error = std::make_unique<Moose::ScopedThrowOnError>();
81
82 fn();
83
84 error << "Expected exception of type " << libMesh::demangle(typeid(ExceptionType).name())
85 << " but no exception was thrown.";
86 }
87 catch (const ExceptionType & ex)
88 {
89 // Exact match
90 if constexpr (exact)
91 {
92 if (std::string(ex.what()) == message)
93 return;
94 }
95 // Partial match
96 else
97 {
98 if (std::string(ex.what()).find(message) != std::string::npos)
99 return;
100 }
101
102 error << "Expected" << (exact ? "" : " partial") << " exception message: \"" << message
103 << "\"\n Actual exception message: \"" << ex.what() << "\"";
104 }
105 catch (const std::exception & ex)
106 {
107 error << "Expected exception of type " << libMesh::demangle(typeid(ExceptionType).name())
108 << " but exception of type " << libMesh::demangle(typeid(ex).name()) << " was thrown.";
109 }
110
111 ::testing::internal::AssertHelper(
112 ::testing::TestPartResult::kNonFatalFailure, file, line, error.str().c_str()) =
113 ::testing::Message();
114}
115
120{
121public:
122 TempFile();
123 ~TempFile();
124
128 const std::filesystem::path & path() const { return _path; }
129
130private:
131 const std::filesystem::path _path;
132};
133
141{
142public:
143 explicit ScopedTestDirectory(const std::vector<std::filesystem::path> & inputs);
145
148
152 const std::filesystem::path & path() const { return _path; }
153
154private:
155 static std::filesystem::path createPath();
156
158 const std::filesystem::path _original_path;
160 const std::filesystem::path _path;
161};
162
163} // namespace Moose::UnitUtils
164
166#define EXPECT_THROW_MSG(stmt, exc_type, expected_msg) \
167 ::Moose::UnitUtils::throwsWithMessage<exc_type, true, false, false>( \
168 [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
169
171#define ASSERT_THROW_MSG(stmt, exc_type, expected_msg) \
172 ::Moose::UnitUtils::throwsWithMessage<exc_type, true, true, false>( \
173 [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
174
176#define EXPECT_THROW_MSG_CONTAINS(stmt, exc_type, expected_substr) \
177 ::Moose::UnitUtils::throwsWithMessage<exc_type, false, false, false>( \
178 [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
179
181#define ASSERT_THROW_MSG_CONTAINS(stmt, exc_type, expected_substr) \
182 ::Moose::UnitUtils::throwsWithMessage<exc_type, false, true, false>( \
183 [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
184
186#define EXPECT_MOOSEERROR_MSG(stmt, expected_msg) \
187 ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, true, false, true>( \
188 [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
189
191#define ASSERT_MOOSEERROR_MSG(stmt, expected_msg) \
192 ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, true, true, true>( \
193 [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
194
196#define EXPECT_MOOSEERROR_MSG_CONTAINS(stmt, expected_substr) \
197 ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, false, false, true>( \
198 [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
199
201#define ASSERT_MOOSEERROR_MSG_CONTAINS(stmt, expected_substr) \
202 ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, false, true, true>( \
203 [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
Base class for actions.
Definition Action.h:38
Run a unit test from a unique temporary working directory.
const std::filesystem::path _original_path
Working directory to restore upon destruction.
static std::filesystem::path createPath()
ScopedTestDirectory & operator=(const ScopedTestDirectory &)=delete
const std::filesystem::path _path
Unique temporary working directory.
const std::filesystem::path & path() const
ScopedTestDirectory(const ScopedTestDirectory &)=delete
Create a temporary file and delete it upon destruction.
const std::filesystem::path _path
const std::filesystem::path & path() const
void assertThrows(const Action &action, const std::optional< std::string > &contains={}, const bool set_throw_on_error=false)
A helper for asserting that calling something throws an exception.
void throwsWithMessage(Func &&fn, const std::string_view message, const char *file, int line)
Helper for the [EXPECT,ASSERT]_[MOOSEERROR,THROW]_[MSG,MSG_CONTAINS] macros.
std::string demangle(const char *name)