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

Feature Request: BOOST_TEST_CONTEXT that doesn't require introducing a new scope with braces #197

Closed
dudamoos opened this Issue Jan 22, 2019 · 7 comments

Comments

Projects
None yet
2 participants
@dudamoos
Copy link

dudamoos commented Jan 22, 2019

I've been using Boost.Test for a project at work, and one thing I found annoying is that BOOST_TEST_CONTEXT requires you to create a new scope using braces, and the context information will only live as long as that new scope. What I originally though it would do (and what I really want it to do) is to make the additional context information last for the remainder of the enclosing scope. This allows me to slowly build context information as my test progresses without requiring excessive indentation.

My current workaround is to use a define as below (notice the declaration is no longer in an "if" condition):

#define MY_BOOST_TEST_CONTEXT( context_descr )                                                  \
    ::boost::test_tools::tt_detail::context_frame BOOST_JOIN( context_frame_, __LINE__ ) =      \
        ::boost::test_tools::tt_detail::context_frame( BOOST_TEST_LAZY_MSG( context_descr ) )

This allows me to do this:

for (int i = 8; i < 24; ++i) {
    MY_BOOST_TEST_CONTEXT("corrupting CRC bit " << i);
    // ...
}

Instead of this:

for (int i = 8; i < 24; ++i) {
    BOOST_TEST_CONTEXT("corrupting CRC bit " << i) {
        // ...
    }
}

This particular example may not look like much, but after 3 or 4 additions to the context as my test progresses the indentation starts to get excessive.

@raffienficiaud

This comment has been minimized.

Copy link
Member

raffienficiaud commented Feb 8, 2019

I may have better for you: making the context variadic, like this:

for (int i = 8; i < 24; ++i) {
    BOOST_TEST_CONTEXT("With level " << i, "Random value=" << some other value){

    }
}

Would that work for you? You can try it on the branch topic/GH-197-plural-context-in-single-scope

@dudamoos

This comment has been minimized.

Copy link
Author

dudamoos commented Feb 8, 2019

Unfortunately that doesn't actually do what I want it to. I need to build the context up as I generate data I want included in it so I can debug test failures. What I'm doing is something like this:

std::vector<uint8_t> data = ...; // generate data
MY_BOOST_TEST_CONTEXT("data      = " << data);
session->SendData(data, ... /* packet header fields */);

// RequirePacket() reads the data from the stream including the length header.
// It also does a few other checks to make sure the data isn't garbage.
const std::vector<uint32_t> packet = RequirePacket(numWords);
MY_BOOST_TEST_CONTEXT("packet    = " << packet);
// ... Do some other checks on the packet. ...
WriteSingleWord(TESTING_ACK); // Acknowledge the packet.

std::vector<uint8_t> parseData;
// ParsePacket() returns false if the packet was badly formatted or failed integrity checks.
BOOST_TEST(ParsePacket(packet, parseData, ... /* output parameters to receive header fields */));
MY_BOOST_TEST_CONTEXT("parseData = " << parseData);

// With all of the above context I can manually inspect the original data, sent packet, and parsed
// data in case this comparison fails.
BOOST_TEST(data == parseData, boost::test_tools::per_element());

I also use it to remove an extra level of indentation from the entire body of Require*() functions (like RequirePacket() above) like so:

#define RequirePacket(numWords) \
    Internal_RequirePacket((numWords), BOOST_TEST_L(__FILE__), static_cast<std::size_t>(__LINE__))
std::vector<uint32_t>
Internal_RequirePacket(unsigned numWords, boost::unit_test::const_string file, std::size_t line) {
    MY_BOOST_TEST_CONTEXT("RequirePacket() call-site: " << file << "(" << line << ")");

    // Code to read packet from stream and validate length and some other things.
    ...
}
@raffienficiaud

This comment has been minimized.

Copy link
Member

raffienficiaud commented Feb 8, 2019

I guess you have considered the assertion bound context ?

If a context needs to span several assertions, we need a scope, otherwise it will confuse users. If a context is associated to only one assertion, then BOOST_TEST_INFO is doing just fine.

What I did here is to have several information going into a single BOOST_TEST_CONTEXT, to avoid precisely having several scopes for a single context.

@dudamoos

This comment has been minimized.

Copy link
Author

dudamoos commented Feb 8, 2019

Yes. I need the context to span several assertions. I understand why you made BOOST_TEST_CONTEXT create a scope that the context will apply to. However, in my case I want the context to last for the rest of the enclosing scope. Is your last statement supposed to mean that adding context to the enclosing scope is an explicit non-goal?

@raffienficiaud

This comment has been minimized.

Copy link
Member

raffienficiaud commented Feb 8, 2019

It is not an explicit non-goal, but I need to think about it.

@raffienficiaud

This comment has been minimized.

Copy link
Member

raffienficiaud commented Feb 11, 2019

Ok, I implemented this via a new macro BOOST_TEST_INFO_SCOPE. Example of use

  for(int i = 0; i < 50; i++) {
    BOOST_TEST_INFO_SCOPE("trial " << i+1);
    int root1 = dis(gen);
    int root2 = dis(gen);
    if(root1 > root2) {
      std::swap(root1, root2);
    }
    BOOST_TEST_INFO_SCOPE("root1 = " << root1);
    BOOST_TEST_INFO_SCOPE("root2 = " << root2);

    std::pair<double, double> estimated = estimate_polynomial_roots(
      gen,
      [root1, root2](double x) -> double { return (x - root1) * (x - root2); });

    BOOST_TEST(estimated.first == double(root1), 10. % boost::test_tools::tolerance());
    BOOST_TEST(estimated.second == double(root2), 10. % boost::test_tools::tolerance());
  }

Let me know if that corresponds to what you asked (same branch as before if you want to give a try).

@dudamoos

This comment has been minimized.

Copy link
Author

dudamoos commented Feb 13, 2019

That fix does the trick. I'll work on getting everyone here using an upgraded or patched version. Thanks!

raffienficiaud added a commit that referenced this issue Feb 13, 2019

Merge branch 'topic/GH-197-plural-context-in-single-scope' into next-…
…internal

* topic/GH-197-plural-context-in-single-scope:
  Change log
  Making BOOST_TEST_CONTEXT variadic and adding sticky context

# Conflicts:
#	doc/closing_chapters/change_log.qbk

@raffienficiaud raffienficiaud added next and removed fix-proposed labels Feb 13, 2019

@raffienficiaud raffienficiaud added this to the 1.70 milestone Feb 13, 2019

@raffienficiaud raffienficiaud added develop and removed next labels Feb 14, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.