https://mooseframework.inl.gov
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 
17 #include "libmesh/utility.h"
18 
19 #include "MooseUtils.h"
20 #include "Moose.h"
21 
23 {
31 template <class ExceptionType = std::exception, class Action = bool>
32 void
33 assertThrows(const Action & action,
34  const std::optional<std::string> & contains = {},
35  const bool set_throw_on_error = false)
36 {
37  static_assert(std::is_base_of_v<std::exception, ExceptionType>, "Not an exception");
38 
39  std::unique_ptr<Moose::ScopedThrowOnError> scoped_throw_on_error;
40  if (set_throw_on_error)
41  scoped_throw_on_error = std::make_unique<Moose::ScopedThrowOnError>();
42 
43  try
44  {
45  action();
46  FAIL() << "Expected " << MooseUtils::prettyCppType<ExceptionType>() << " not thrown";
47  }
48  catch (std::exception const & e)
49  {
50  if constexpr (!std::is_same_v<std::exception, ExceptionType>)
51  if (!dynamic_cast<const ExceptionType *>(&e))
52  FAIL() << "Threw " << demangle(typeid(e).name()) << " instead of "
53  << MooseUtils::prettyCppType<ExceptionType>() << " with message '" << e.what()
54  << "'";
55 
56  if (contains)
57  {
58  ASSERT_TRUE(std::string(e.what()).find(*contains) != std::string::npos)
59  << "Exception \"" << e.what() << "\" does not contain \"" << *contains << "\"";
60  }
61  }
62 }
63 
67 template <typename ExceptionType, bool exact, bool assert, bool set_throw_on_error, typename Func>
68 void
69 throwsWithMessage(Func && fn, const std::string_view message, const char * file, int line)
70 {
71  static_assert(std::is_base_of_v<std::exception, ExceptionType>, "Not an exception");
72 
73  std::ostringstream error;
74 
75  try
76  {
77  std::unique_ptr<Moose::ScopedThrowOnError> scoped_throw_on_error;
78  if constexpr (set_throw_on_error)
79  scoped_throw_on_error = std::make_unique<Moose::ScopedThrowOnError>();
80 
81  fn();
82 
83  error << "Expected exception of type " << libMesh::demangle(typeid(ExceptionType).name())
84  << " but no exception was thrown.";
85  }
86  catch (const ExceptionType & ex)
87  {
88  // Exact match
89  if constexpr (exact)
90  {
91  if (std::string(ex.what()) == message)
92  return;
93  }
94  // Partial match
95  else
96  {
97  if (std::string(ex.what()).find(message) != std::string::npos)
98  return;
99  }
100 
101  error << "Expected" << (exact ? "" : " partial") << " exception message: \"" << message
102  << "\"\n Actual exception message: \"" << ex.what() << "\"";
103  }
104  catch (const std::exception & ex)
105  {
106  error << "Expected exception of type " << libMesh::demangle(typeid(ExceptionType).name())
107  << " but exception of type " << libMesh::demangle(typeid(ex).name()) << " was thrown.";
108  }
109 
110  ::testing::internal::AssertHelper(
111  ::testing::TestPartResult::kNonFatalFailure, file, line, error.str().c_str()) =
112  ::testing::Message();
113 }
114 
118 class TempFile
119 {
120 public:
121  TempFile();
122  ~TempFile();
123 
127  const std::filesystem::path & path() const { return _path; }
128 
129 private:
130  static std::filesystem::path generatePath();
131 
132  const std::filesystem::path _path;
133 };
134 
135 } // namespace Moose::UnitUtils
136 
138 #define EXPECT_THROW_MSG(stmt, exc_type, expected_msg) \
139  ::Moose::UnitUtils::throwsWithMessage<exc_type, true, false, false>( \
140  [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
141 
143 #define ASSERT_THROW_MSG(stmt, exc_type, expected_msg) \
144  ::Moose::UnitUtils::throwsWithMessage<exc_type, true, true, false>( \
145  [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
146 
148 #define EXPECT_THROW_MSG_CONTAINS(stmt, exc_type, expected_substr) \
149  ::Moose::UnitUtils::throwsWithMessage<exc_type, false, false, false>( \
150  [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
151 
153 #define ASSERT_THROW_MSG_CONTAINS(stmt, exc_type, expected_substr) \
154  ::Moose::UnitUtils::throwsWithMessage<exc_type, false, true, false>( \
155  [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
156 
158 #define EXPECT_MOOSEERROR_MSG(stmt, expected_msg) \
159  ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, true, false, true>( \
160  [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
161 
163 #define ASSERT_MOOSEERROR_MSG(stmt, expected_msg) \
164  ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, true, true, true>( \
165  [&]() { stmt; }, expected_msg, __FILE__, __LINE__)
166 
168 #define EXPECT_MOOSEERROR_MSG_CONTAINS(stmt, expected_substr) \
169  ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, false, false, true>( \
170  [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
171 
173 #define ASSERT_MOOSEERROR_MSG_CONTAINS(stmt, expected_substr) \
174  ::Moose::UnitUtils::throwsWithMessage<MooseRuntimeError, false, true, true>( \
175  [&]() { stmt; }, expected_substr, __FILE__, __LINE__)
std::string name(const ElemQuality q)
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
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.
Base class for actions.
Definition: Action.h:34
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.
const std::filesystem::path _path
bool contains(std::string_view superstring, std::string_view substring)
std::string demangle(const char *name)
Create a temporary file and delete it upon destruction.
const std::filesystem::path & path() const
static std::filesystem::path generatePath()