| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4a87ad6 commit 5919d01
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -158,13 +158,18 @@ class GTEST_API_ [[nodiscard]] AssertionResult { | |||
| 158 | 158 | // The second parameter prevents this overload from being considered if | |
| 159 | 159 | // the argument is implicitly convertible to AssertionResult. In that case | |
| 160 | 160 | // we want AssertionResult's copy constructor to be used. | |
| 161 | - template <typename T> | ||
| 162 | - explicit AssertionResult( | ||
| 163 | - const T& success, | ||
| 164 | - std::enable_if_t<!std::is_convertible_v<T, AssertionResult>>* | ||
| 165 | - /*enabler*/ | ||
| 166 | - = nullptr) | ||
| 167 | - : success_(success) {} | ||
| 161 | + template <typename T, | ||
| 162 | + std::enable_if_t<!std::is_convertible_v<T, AssertionResult> && | ||
| 163 | + !std::is_trivially_constructible_v<bool, T>, | ||
| 164 | + int> = 0> | ||
| 165 | + explicit AssertionResult(T&& success) : success_(std::forward<T>(success)) {} | ||
| 166 | + | ||
| 167 | + // Similar to the mutable overload, but for cases where mutability is | ||
| 168 | + // unnecessary or problematic (e.g., bitfields). | ||
| 169 | + template <typename T, | ||
| 170 | + std::enable_if_t<!std::is_convertible_v<const T&, AssertionResult>, | ||
| 171 | + int> = 0> | ||
| 172 | + explicit AssertionResult(const T& success) : success_(success) {} | ||
| 168 | 173 | ||
| 169 | 174 | #if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) | |
| 170 | 175 | GTEST_DISABLE_MSC_WARNINGS_POP_() | |
@@ -226,6 +231,24 @@ class GTEST_API_ [[nodiscard]] AssertionResult { | |||
| 226 | 231 | std::unique_ptr< ::std::string> message_; | |
| 227 | 232 | }; | |
| 228 | 233 | ||
| 234 | + namespace internal { | ||
| 235 | + | ||
| 236 | + // A pair containing the result that an assertion is evaluating, and the | ||
| 237 | + // expected result (true, false). | ||
| 238 | + // | ||
| 239 | + // Contains a conversion operator that indicates whether the two match. | ||
| 240 | + struct AssertionResultExpectation { | ||
| 241 | + testing::AssertionResult assertion_result; | ||
| 242 | + bool expected_result; | ||
| 243 | + | ||
| 244 | + explicit operator bool() const { | ||
| 245 | + bool converted(assertion_result); | ||
| 246 | + return converted == expected_result; | ||
| 247 | + } | ||
| 248 | + }; | ||
| 249 | + | ||
| 250 | + } // namespace internal | ||
| 251 | + | ||
| 229 | 252 | // Makes a successful assertion result. | |
| 230 | 253 | GTEST_API_ AssertionResult AssertionSuccess(); | |
| 231 | 254 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -945,13 +945,13 @@ template <typename T> | |||
| 945 | 945 | class [[nodiscard]] UniversalPrinter<std::optional<T>> { | |
| 946 | 946 | public: | |
| 947 | 947 | static void Print(const std::optional<T>& value, ::std::ostream* os) { | |
| 948 | - *os << '('; | ||
| 949 | 948 | if (!value) { | |
| 950 | - *os << "nullopt"; | ||
| 949 | + UniversalPrint(std::nullopt, os); | ||
| 951 | 950 | } else { | |
| 951 | + *os << '('; | ||
| 952 | 952 | UniversalPrint(*value, os); | |
| 953 | + *os << ')'; | ||
| 953 | 954 | } | |
| 954 | - *os << ')'; | ||
| 955 | 955 | } | |
| 956 | 956 | }; | |
| 957 | 957 | ||
@@ -961,27 +961,38 @@ class [[nodiscard]] UniversalPrinter<std::nullopt_t> { | |||
| 961 | 961 | static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } | |
| 962 | 962 | }; | |
| 963 | 963 | ||
| 964 | + struct UniversalPrinterVisitor { | ||
| 965 | + template <typename T> | ||
| 966 | + void operator()(const T& arg) const { | ||
| 967 | + *os << "'" << GetTypeName<T>() << "(index = " << index << ")' with value "; | ||
| 968 | + UniversalPrint(arg, os); | ||
| 969 | + } | ||
| 970 | + ::std::ostream* os; | ||
| 971 | + std::size_t index; | ||
| 972 | + }; | ||
| 973 | + | ||
| 964 | 974 | // Printer for std::variant | |
| 965 | 975 | template <typename... T> | |
| 966 | 976 | class [[nodiscard]] UniversalPrinter<std::variant<T...>> { | |
| 967 | 977 | public: | |
| 968 | 978 | static void Print(const std::variant<T...>& value, ::std::ostream* os) { | |
| 969 | - *os << '('; | ||
| 970 | - std::visit(Visitor{os, value.index()}, value); | ||
| 971 | - *os << ')'; | ||
| 979 | + if (value.valueless_by_exception()) { | ||
| 980 | + *os << "(valueless)"; | ||
| 981 | + } else { | ||
| 982 | + *os << '('; | ||
| 983 | + std::visit(UniversalPrinterVisitor{os, value.index()}, value); | ||
| 984 | + *os << ')'; | ||
| 985 | + } | ||
| 972 | 986 | } | |
| 987 | + }; | ||
| 973 | 988 | ||
| 974 | - private: | ||
| 975 | - struct Visitor { | ||
| 976 | - template <typename U> | ||
| 977 | - void operator()(const U& u) const { | ||
| 978 | - *os << "'" << GetTypeName<U>() << "(index = " << index | ||
| 979 | - << ")' with value "; | ||
| 980 | - UniversalPrint(u, os); | ||
| 981 | - } | ||
| 982 | - ::std::ostream* os; | ||
| 983 | - std::size_t index; | ||
| 984 | - }; | ||
| 989 | + // Printer for std::monostate | ||
| 990 | + template <> | ||
| 991 | + class [[nodiscard]] UniversalPrinter<std::monostate> { | ||
| 992 | + public: | ||
| 993 | + static void Print(std::monostate, ::std::ostream* os) { | ||
| 994 | + *os << "(monostate)"; | ||
| 995 | + } | ||
| 985 | 996 | }; | |
| 986 | 997 | ||
| 987 | 998 | // UniversalPrintArray(begin, len, os) prints an array of 'len' | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1818,14 +1818,13 @@ class [[nodiscard]] TestWithParam : public Test, | |||
| 1818 | 1818 | #define GTEST_EXPECT_TRUE(condition) \ | |
| 1819 | 1819 | GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ | |
| 1820 | 1820 | GTEST_NONFATAL_FAILURE_) | |
| 1821 | - #define GTEST_EXPECT_FALSE(condition) \ | ||
| 1822 | - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ | ||
| 1821 | + #define GTEST_EXPECT_FALSE(condition) \ | ||
| 1822 | + GTEST_TEST_BOOLEAN_(condition, #condition, true, false, \ | ||
| 1823 | 1823 | GTEST_NONFATAL_FAILURE_) | |
| 1824 | 1824 | #define GTEST_ASSERT_TRUE(condition) \ | |
| 1825 | 1825 | GTEST_TEST_BOOLEAN_(condition, #condition, false, true, GTEST_FATAL_FAILURE_) | |
| 1826 | - #define GTEST_ASSERT_FALSE(condition) \ | ||
| 1827 | - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ | ||
| 1828 | - GTEST_FATAL_FAILURE_) | ||
| 1826 | + #define GTEST_ASSERT_FALSE(condition) \ | ||
| 1827 | + GTEST_TEST_BOOLEAN_(condition, #condition, true, false, GTEST_FATAL_FAILURE_) | ||
| 1829 | 1828 | ||
| 1830 | 1829 | // Define these macros to 1 to omit the definition of the corresponding | |
| 1831 | 1830 | // EXPECT or ASSERT, which clashes with some users' own code. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1453,12 +1453,12 @@ class [[nodiscard]] NeverThrown { | |||
| 1453 | 1453 | // representation of expression as it was passed into the EXPECT_TRUE. | |
| 1454 | 1454 | #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ | |
| 1455 | 1455 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ | |
| 1456 | - if (const ::testing::AssertionResult gtest_ar_ = \ | ||
| 1457 | - ::testing::AssertionResult(expression)) \ | ||
| 1456 | + if (::testing::internal::AssertionResultExpectation gtest_are_ = { \ | ||
| 1457 | + ::testing::AssertionResult(expression), expected}) \ | ||
| 1458 | 1458 | ; \ | |
| 1459 | 1459 | else \ | |
| 1460 | 1460 | fail(::testing::internal::GetBoolAssertionFailureMessage( \ | |
| 1461 | - gtest_ar_, text, #actual, #expected)) | ||
| 1461 | + gtest_are_.assertion_result, text, #actual, #expected)) | ||
| 1462 | 1462 | ||
| 1463 | 1463 | #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ | |
| 1464 | 1464 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -363,18 +363,24 @@ | |||
| 363 | 363 | #define GTEST_DISABLE_MSC_WARNINGS_POP_() | |
| 364 | 364 | #endif | |
| 365 | 365 | ||
| 366 | - // Clang on Windows does not understand MSVC's pragma warning. | ||
| 367 | - // We need clang-specific way to disable function deprecation warning. | ||
| 368 | - #ifdef __clang__ | ||
| 369 | - #define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ | ||
| 366 | + // Pragmas to disable function deprecation warnings. | ||
| 367 | + #if defined(__clang__) | ||
| 368 | + #define GTEST_DISABLE_DEPRECATED_PUSH_() \ | ||
| 370 | 369 | _Pragma("clang diagnostic push") \ | |
| 371 | 370 | _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ | |
| 372 | 371 | _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") | |
| 373 | - #define GTEST_DISABLE_MSC_DEPRECATED_POP_() _Pragma("clang diagnostic pop") | ||
| 372 | + #define GTEST_DISABLE_DEPRECATED_POP_() _Pragma("clang diagnostic pop") | ||
| 373 | + #elif defined(__GNUC__) | ||
| 374 | + #define GTEST_DISABLE_DEPRECATED_PUSH_() \ | ||
| 375 | + _Pragma("GCC diagnostic push") \ | ||
| 376 | + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") | ||
| 377 | + #define GTEST_DISABLE_DEPRECATED_POP_() _Pragma("GCC diagnostic pop") | ||
| 378 | + #elif defined(_MSC_VER) | ||
| 379 | + #define GTEST_DISABLE_DEPRECATED_PUSH_() GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) | ||
| 380 | + #define GTEST_DISABLE_DEPRECATED_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_() | ||
| 374 | 381 | #else | |
| 375 | - #define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ | ||
| 376 | - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) | ||
| 377 | - #define GTEST_DISABLE_MSC_DEPRECATED_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_() | ||
| 382 | + #define GTEST_DISABLE_DEPRECATED_PUSH_() | ||
| 383 | + #define GTEST_DISABLE_DEPRECATED_POP_() | ||
| 378 | 384 | #endif | |
| 379 | 385 | ||
| 380 | 386 | // Brings in definitions for functions used in the testing::internal::posix | |
@@ -2119,7 +2125,7 @@ inline int IsATTY(int fd) { | |||
| 2119 | 2125 | ||
| 2120 | 2126 | // Functions deprecated by MSVC 8.0. | |
| 2121 | 2127 | ||
| 2122 | - GTEST_DISABLE_MSC_DEPRECATED_PUSH_() | ||
| 2128 | + GTEST_DISABLE_DEPRECATED_PUSH_() | ||
| 2123 | 2129 | ||
| 2124 | 2130 | // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and | |
| 2125 | 2131 | // StrError() aren't needed on Windows CE at this time and thus not | |
@@ -2181,7 +2187,7 @@ inline const char* GetEnv(const char* name) { | |||
| 2181 | 2187 | #endif | |
| 2182 | 2188 | } | |
| 2183 | 2189 | ||
| 2184 | - GTEST_DISABLE_MSC_DEPRECATED_POP_() | ||
| 2190 | + GTEST_DISABLE_DEPRECATED_POP_() | ||
| 2185 | 2191 | ||
| 2186 | 2192 | #ifdef GTEST_OS_WINDOWS_MOBILE | |
| 2187 | 2193 | // Windows CE has no C library. The abort() function is used in | |
@@ -2302,22 +2308,29 @@ using TimeInMillis = int64_t; // Represents time in milliseconds. | |||
| 2302 | 2308 | ||
| 2303 | 2309 | // Macros for defining flags. | |
| 2304 | 2310 | #define GTEST_DEFINE_bool_(name, default_val, doc) \ | |
| 2311 | + GTEST_DECLARE_bool_(name); \ | ||
| 2305 | 2312 | namespace testing { \ | |
| 2306 | 2313 | GTEST_API_ bool GTEST_FLAG(name) = (default_val); \ | |
| 2307 | 2314 | } \ | |
| 2308 | 2315 | static_assert(true, "no-op to require trailing semicolon") | |
| 2309 | 2316 | #define GTEST_DEFINE_int32_(name, default_val, doc) \ | |
| 2317 | + GTEST_DECLARE_int32_(name); \ | ||
| 2310 | 2318 | namespace testing { \ | |
| 2311 | 2319 | GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val); \ | |
| 2312 | 2320 | } \ | |
| 2313 | 2321 | static_assert(true, "no-op to require trailing semicolon") | |
| 2314 | 2322 | #define GTEST_DEFINE_string_(name, default_val, doc) \ | |
| 2323 | + GTEST_DECLARE_string_(name); \ | ||
| 2315 | 2324 | namespace testing { \ | |
| 2316 | 2325 | GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val); \ | |
| 2317 | 2326 | } \ | |
| 2318 | 2327 | static_assert(true, "no-op to require trailing semicolon") | |
| 2319 | 2328 | ||
| 2320 | 2329 | // Macros for declaring flags. | |
| 2330 | + // | ||
| 2331 | + // We also need to declare the flag in the public namespace to avoid triggering | ||
| 2332 | + // -Wmissing-variable-declarations warnings, as reported here: | ||
| 2333 | + // https://github.com/google/googletest/issues/4897 | ||
| 2321 | 2334 | #define GTEST_DECLARE_bool_(name) \ | |
| 2322 | 2335 | namespace testing { \ | |
| 2323 | 2336 | GTEST_API_ extern bool GTEST_FLAG(name); \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -587,7 +587,7 @@ class GTEST_API_ UnitTestImpl { | |||
| 587 | 587 | // total_test_suite_count() - 1. If i is not in that range, returns NULL. | |
| 588 | 588 | const TestSuite* GetTestSuite(int i) const { | |
| 589 | 589 | const int index = GetElementOr(test_suite_indices_, i, -1); | |
| 590 | - return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)]; | ||
| 590 | + return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)]; | ||
| 591 | 591 | } | |
| 592 | 592 | ||
| 593 | 593 | // Legacy API is deprecated but still available | |
@@ -1106,7 +1106,7 @@ class StreamingListener : public EmptyTestEventListener { | |||
| 1106 | 1106 | GTEST_CHECK_(sockfd_ != -1) | |
| 1107 | 1107 | << "Send() can be called only when there is a connection."; | |
| 1108 | 1108 | ||
| 1109 | - const auto len = static_cast<size_t>(message.length()); | ||
| 1109 | + const size_t len = message.length(); | ||
| 1110 | 1110 | if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) { | |
| 1111 | 1111 | GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " | |
| 1112 | 1112 | << host_name_ << ":" << port_num_; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1069,7 +1069,7 @@ GTestLog::~GTestLog() { | |||
| 1069 | 1069 | ||
| 1070 | 1070 | // Disable Microsoft deprecation warnings for POSIX functions called from | |
| 1071 | 1071 | // this class (creat, dup, dup2, and close) | |
| 1072 | - GTEST_DISABLE_MSC_DEPRECATED_PUSH_() | ||
| 1072 | + GTEST_DISABLE_DEPRECATED_PUSH_() | ||
| 1073 | 1073 | ||
| 1074 | 1074 | namespace { | |
| 1075 | 1075 | ||
@@ -1095,10 +1095,12 @@ class CapturedStream { | |||
| 1095 | 1095 | 0, // Generate unique file name. | |
| 1096 | 1096 | temp_file_path); | |
| 1097 | 1097 | GTEST_CHECK_(success != 0) | |
| 1098 | - << "Unable to create a temporary file in " << temp_dir_path; | ||
| 1098 | + << "Failed to create temporary file in " << temp_dir_path | ||
| 1099 | + << " with error " << ::GetLastError(); | ||
| 1099 | 1100 | const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); | |
| 1100 | 1101 | GTEST_CHECK_(captured_fd != -1) | |
| 1101 | - << "Unable to open temporary file " << temp_file_path; | ||
| 1102 | + << "Failed to open temporary file " << temp_file_path << " with error " | ||
| 1103 | + << ::GetLastError(); | ||
| 1102 | 1104 | filename_ = temp_file_path; | |
| 1103 | 1105 | #else | |
| 1104 | 1106 | // There's no guarantee that a test has write access to the current | |
@@ -1200,7 +1202,7 @@ class CapturedStream { | |||
| 1200 | 1202 | CapturedStream& operator=(const CapturedStream&) = delete; | |
| 1201 | 1203 | }; | |
| 1202 | 1204 | ||
| 1203 | - GTEST_DISABLE_MSC_DEPRECATED_POP_() | ||
| 1205 | + GTEST_DISABLE_DEPRECATED_POP_() | ||
| 1204 | 1206 | ||
| 1205 | 1207 | static CapturedStream* g_captured_stderr = nullptr; | |
| 1206 | 1208 | static CapturedStream* g_captured_stdout = nullptr; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1209,7 +1209,7 @@ int UnitTestImpl::test_to_run_count() const { | |||
| 1209 | 1209 | // trace but Bar() and CurrentOsStackTraceExceptTop() won't. | |
| 1210 | 1210 | std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { | |
| 1211 | 1211 | return os_stack_trace_getter()->CurrentStackTrace( | |
| 1212 | - static_cast<int>(GTEST_FLAG_GET(stack_trace_depth)), skip_count + 1 | ||
| 1212 | + GTEST_FLAG_GET(stack_trace_depth), skip_count + 1 | ||
| 1213 | 1213 | // Skips the user-specified number of frames plus this function | |
| 1214 | 1214 | // itself. | |
| 1215 | 1215 | ); // NOLINT | |
@@ -2700,7 +2700,7 @@ Result HandleSehExceptionsInMethodIfSupported(T* object, Result (T::*method)(), | |||
| 2700 | 2700 | } | |
| 2701 | 2701 | ||
| 2702 | 2702 | // Runs the given method and catches and reports C++ and/or SEH-style | |
| 2703 | - // exceptions, if they are supported; returns the 0-value for type | ||
| 2703 | + // exceptions, if they are supported; returns the default-value for type | ||
| 2704 | 2704 | // Result in case of an SEH exception. | |
| 2705 | 2705 | template <class T, typename Result> | |
| 2706 | 2706 | Result HandleExceptionsInMethodIfSupported(T* object, Result (T::*method)(), | |
@@ -2748,7 +2748,7 @@ Result HandleExceptionsInMethodIfSupported(T* object, Result (T::*method)(), | |||
| 2748 | 2748 | TestPartResult::kFatalFailure, | |
| 2749 | 2749 | FormatCxxExceptionMessage(nullptr, location)); | |
| 2750 | 2750 | } | |
| 2751 | - return static_cast<Result>(0); | ||
| 2751 | + return Result(); | ||
| 2752 | 2752 | #else | |
| 2753 | 2753 | return HandleSehExceptionsInMethodIfSupported(object, method, location); | |
| 2754 | 2754 | #endif // GTEST_HAS_EXCEPTIONS | |
@@ -4239,8 +4239,7 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, | |||
| 4239 | 4239 | for (;;) { | |
| 4240 | 4240 | const char* const next_segment = strstr(segment, "]]>"); | |
| 4241 | 4241 | if (next_segment != nullptr) { | |
| 4242 | - stream->write(segment, | ||
| 4243 | - static_cast<std::streamsize>(next_segment - segment)); | ||
| 4242 | + stream->write(segment, next_segment - segment); | ||
| 4244 | 4243 | *stream << "]]>]]><![CDATA["; | |
| 4245 | 4244 | segment = next_segment + strlen("]]>"); | |
| 4246 | 4245 | } else { | |
@@ -5172,9 +5171,12 @@ class ScopedPrematureExitFile { | |||
| 5172 | 5171 | // create the file with a single "0" character in it. I/O | |
| 5173 | 5172 | // errors are ignored as there's nothing better we can do and we | |
| 5174 | 5173 | // don't want to fail the test because of this. | |
| 5175 | - FILE* pfile = posix::FOpen(premature_exit_filepath_.c_str(), "w"); | ||
| 5176 | - fwrite("0", 1, 1, pfile); | ||
| 5177 | - fclose(pfile); | ||
| 5174 | + if (FILE* pfile = posix::FOpen(premature_exit_filepath_.c_str(), "w")) { | ||
| 5175 | + fwrite("0", 1, 1, pfile); | ||
| 5176 | + fclose(pfile); | ||
| 5177 | + } else { | ||
| 5178 | + premature_exit_filepath_.clear(); | ||
| 5179 | + } | ||
| 5178 | 5180 | } | |
| 5179 | 5181 | } | |
| 5180 | 5182 | ||
@@ -5192,7 +5194,7 @@ class ScopedPrematureExitFile { | |||
| 5192 | 5194 | } | |
| 5193 | 5195 | ||
| 5194 | 5196 | private: | |
| 5195 | - const std::string premature_exit_filepath_; | ||
| 5197 | + std::string premature_exit_filepath_; | ||
| 5196 | 5198 | ||
| 5197 | 5199 | ScopedPrematureExitFile(const ScopedPrematureExitFile&) = delete; | |
| 5198 | 5200 | ScopedPrematureExitFile& operator=(const ScopedPrematureExitFile&) = delete; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments