Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from Catch to GoogleTest & always terminate on contract violation #831

Merged
merged 16 commits into from
Jan 7, 2020

Conversation

JordanMaples
Copy link
Contributor

@JordanMaples JordanMaples commented Dec 3, 2019

Eliminate throwing options from the contract violation behavior of Expects and Ensures. Contract violation will always result in termination.

Removes Catch as the unit testing framework to use GoogleTest instead.
Unit tests that test contract violation that previously relied on throw/catch logic will now be tested using EXPECT_DEATH.

@JordanMaples
Copy link
Contributor Author

JordanMaples commented Dec 3, 2019

The build appears to be failing because of warnings emanating from within gtest itself.

Need to investigate why the warnings aren't being treated as "SYSTEM" as specified in the CMake file.

@JordanMaples
Copy link
Contributor Author

JordanMaples commented Dec 3, 2019

MSVC x86 is failing, it appears that gtest is set to x64.

@JordanMaples JordanMaples changed the title [DRAFT] Migrate from Catch to GoogleTest Migrate from Catch to GoogleTest Dec 10, 2019
@JordanMaples JordanMaples changed the title Migrate from Catch to GoogleTest Migrate from Catch to GoogleTest & always terminate on contract violation Dec 11, 2019
tests/CMakeLists.txt Outdated Show resolved Hide resolved
@JordanMaples
Copy link
Contributor Author

JordanMaples commented Dec 12, 2019

Update readme.md, it still lists catch as the test harness.

@JordanMaples
Copy link
Contributor Author

JordanMaples commented Dec 12, 2019

Set terminate handlers for each of the death tests and emit a test relevant message to avoid the ".*" regex.

Copy link

@sunnychatterjee sunnychatterjee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Jordan,

Nice work in getting the changes together. I've left some comments for your consideration.

Thank you,
Sunny

#define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond)

#endif // GSL_THROW_ON_CONTRACT_VIOLATION

#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expects(cond) and Ensures(cond): Should we remove the definitions using GSL_CONTRACT_CHECK?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the test failures will are easily accessible using the verbose output in the command line or using the test explorer in VS. With this information, there's no need to have the additional messages.
If a developer wants additional messages in their own execution, they can set up their own termination handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm comfortable removing them. The test failures will are easily accessible using the verbose output in the command line or using the test explorer in VS. With this information, there's no need to have the additional messages.
If a developer wants additional messages in their own execution, they can set up their own termination handler.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thoughts, let's just leave them as-is for now for the purposes of this PR.

target_compile_options(gsl_tests_config_noexcept INTERFACE
${GSL_CPLUSPLUS_OPT}
/EHsc

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed for the google test library?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i believe it is needed by them. Before adding it, I was unable to get it to build.

tests/algorithm_tests.cpp Outdated Show resolved Hide resolved
include/gsl/gsl_assert Show resolved Hide resolved
tests/algorithm_tests.cpp Outdated Show resolved Hide resolved
@@ -133,3 +150,6 @@ static constexpr bool test_constexpr()
static_assert(test_constexpr(), "FAIL");
#endif

#if __clang__ || __GNUC__

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the warnings are just in gtest header, this move up right after the include of the header.

@@ -20,7 +20,18 @@
#pragma warning(disable : 26440 26426) // from catch
#endif

#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK_THROW...
#if __clang__ || __GNUC__
//disable warnings from gtest

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Don't like warning suppressions in code. Are there issues tracking these warnings in gtest? If not, could you please file them?
  • Is there any way this snippet can be included in a common header since it's being repeated in a number of tests? I understand this might not be possible if the scope of suppression extends beyond the inclusion of gtest.h.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move them to a standalone header that also adds gtest.h. I'll add a comment with it's include so the corresponding GCC diagnostic pop at the bottom doesn't cause any confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided against moving the push and suppression into a standalone header. This was due to the pop that is required at the end of the file. It struck me as odd that there would be a standalone pop. Even with comments, I wasn't satisfied with it.
Since there wasn't an elegant solution, I decided to leave them in the individual files.

@JordanMaples
Copy link
Contributor Author

@sunnychatterjee Did I sufficiently address all of your comments and concerns?

As an additional note: I published an official release, v2.1.0, earlier today. Users who are against adopting the new contract violation behavior and test harness can opt to use that instead.

Copy link

@sunnychatterjee sunnychatterjee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Thanks!

@JordanMaples JordanMaples merged commit 7786da9 into microsoft:master Jan 7, 2020
@JordanMaples JordanMaples deleted the dev/jomaples/gtest branch January 10, 2020 19:14
@reddwarf69
Copy link
Contributor

reddwarf69 commented Jan 28, 2020

What was the logic behind this?

It seems to imply a history like:

  • Everybody accepts Catch is better than Google Test, so you went with Catch
  • But Catch doesn't support death tests, so GSL_THROW_ON_CONTRACT_VIOLATION was added
  • And since there was an option why not also add GSL_UNENFORCED_ON_CONTRACT_VIOLATION?
  • .... time passes ...
  • Having the options is a problem because... some reason?
  • You want to remove the options so badly that you are willing to use Google Test, even if you prefer Catch otherwise.

But it's unclear what "some reason" is.

From outside what it looks like is:

  • The options are being removed for no reason
  • It breaks anyone's code that relied on GSL_THROW_ON_CONTRACT_VIOLATION to use Catch to detect contract violations using GSL.
  • It removes the option to disable the checks if somebody wants to have them only enabled in tests but not in production.

@grahamreeds
Copy link

grahamreeds commented Jan 28, 2020 via email

@JordanMaples
Copy link
Contributor Author

The goal of this PR was to align the GSL's contract violation behaviors to those outlined in the Core Guidelines. Specifically, in isocpp/CppCoreGuidelines#1512 it was discussed that contract violation should result in terminating behavior. So removal of the alternative contract violation behavior was necessary. I created a snapshot of the GSL just before this PR was merged in case you would like to have the old behavior. https://github.com/microsoft/GSL/releases/tag/v2.1.0

@grahamreeds Unfortunately, I was not involved with the GSL during the migration from UnitTest++ to Catch and am unfamiliar with UnitTest++.

@irrenhaus3
Copy link

New year, new comment: I found that the (new?) wording on https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-assertions states that Expects is allowed an alternative to program termination. I'd like to request the return of fail_fast or a similar exception so that unit test frameworks licke Catch that aren't capable of Death Tests can still test for contract violations that way.

@beinhaerter
Copy link
Contributor

I found that the (new?) wording on https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-assertions states that Expects is allowed an alternative to program termination.

This is no new wording, this is the same wording since 2015 (Compare git log --topo-order --graph -u -L 21233,21245:CppCoreGuidelines.md).

The latest discussion linked by JordanMaples is from September 2019. This is 4 years after the last change to the GSL.assert section in the CoreGuidelines.

Regarding your change request I agree that the status is unfortunate. As reddwarf69 points out in isocpp/CppCoreGuidelines#1512 (comment) there are open questions to which hsutter has not yet replied.

  • CoreGuidelines text says "Expects(p) terminates the program unless p == true" which is the default behaviour and it says "Expects is under control of some options (enforcement, error message, alternatives to terminate)" which would allow to configure other behaviour
  • The CoreGuidelines editors say "GSL.assert currently requires Expects to terminate the program if the condition is false. This is intended to mean std::terminate which permits a terminate_handler to do things like log some final information before restarting the process to try again. There is nothing in the Guidelines today about Expects throwing on contract violations." where the last sentence in my opinion contradicts the text of the CoreGuidelines
  • The CoreGuideline issue is still open, so hsutter's answer might not have been the final answer
  • The GSL code was changed directly in reply to the editors call because "removal of the alternative contract violation behavior was necessary." which seems a bit eager especially since the CoreGuideline issue is not yet closed

I asked hsutter in the CoreGuidelines issue if he can reply to the open questions. Maybe this helps close the discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants