locked
Test runner undoes call to _set_invalid_parameter_handler RRS feed

  • Question

  • Some of my unit tests create tasks, wait for them and later check their outcome.

    Since assertions can kill the test runner, I applied the modifications documented by Microsoft, i.e. calling _set_invalid_parameter_handler() and _CrtSetReportMode().

    Though this does work when debugging a unit test, it does not work when just running it.

    void ThrowInvalidParameterException(LPCWSTR expression, LPCWSTR, LPCWSTR, UINT, uintptr_t)
    {
      throw expression;
    }
    
    struct Foo
    {
      Foo()
      {
        Logger::WriteMessage(L"Foo constructor called");
        _set_invalid_parameter_handler(ThrowInvalidParameterException); // (A)
        _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);  // Avoids assertion popup
      }
    } foo;
    
    namespace Test1
    {
      TEST_CLASS(UnitTest1)
      {
      public:
        TEST_METHOD_INITIALIZE(Initialize)
        {
          Logger::WriteMessage(L"Initialize called");
          _set_invalid_parameter_handler(ThrowInvalidParameterException); // (B)
        }
    
        TEST_METHOD(TestMethod1)
        {
          _set_invalid_parameter_handler(ThrowInvalidParameterException);  // (C)
          create_task([] { clamp(5, 20, 10); }).get();
          concurrency::wait(100);
        }
      };
    }

    The logger output verifies that lines (A), (B), and (C) are always executed in that order. But if I run the test, then the test runner apparently calls _set_invalid_parameter_handler(someOtherAddress), undoing the calls in (A) and (B) and making line (C) necessary in each and every test method. I also verified this by logging the value obtained using _get_invalid_parameter_handler(). If I debug the test, then line (C) is not necessary.

    Debugging the test:

    Message: Unhandled C++ Exception

    in the Test Explorer window (correct behavior)

    Running the test:

    The active test run was aborted.Reason: c:\....\algorithm(4333) : Assertion failed : invalid bounds arguments passed to std::clamp

    in the Tests output pane (wrong behavior)

    What is going on?

    Friday, January 5, 2018 9:39 AM

All replies

  • Hi Frank Heimes,

    >> Though this does work when debugging a unit test, it does not work when just running it.

    It is mentioned in this Microsoft docs:

    Please rebuild the CRT yourself have a try.

    I reference Hans Passant’s reply in this similar thread.

    Regards,

    Judyzh


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, January 8, 2018 8:09 AM
  • Hi Judyzh,

    thank you for answering my question. However, I think you missed my point.

    You point out that the arguments provided to the handler function are NULL in Release build. This is true, but that's not the problem. Switching from DEBUG- to RELEASE-Build and running the test turns this message:

    The active test run was aborted.Reason: c:\....\algorithm(4333) : Assertion failed : invalid bounds arguments passed to std::clamp

    into this one:

    The active test run was aborted.Reason:

    So the assertion message looses its useful guts.

    But my problem is that the assertion is issued at all and terminates the test runner even though I had supplied an alternative assertion handler.

    In both cases - while running the test as well as while debugging it interactively - I had built it for the DEBUG configuration.

    At this point, I think the test runner lies to the programmer (i.e. it's a bug):

    1. It loads the test DLL
    2. It executes the function declared using TEST_METHOD_INITIALIZE()
    3. It calls _set_invalid_parameter_handler(someOtherAddress), if not running an interactive debugging session
    4. It executes a function declared using TEST_METHOD()

    Since step 3. is not documented anywhere, I consider this surprising and a bug.

    Monday, January 8, 2018 11:08 AM
  • Hi Frank Heimes,

    I'm trying to involve some senior engineers into this issue, and it might take some time.

    Your patience will be greatly appreciated.

    Thanks for your understanding.

    Regards,

    Judyzh


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, January 10, 2018 7:25 AM
  • It do calls _set_invalid_parameter_handler just as you thought. You can check this section in "CppUnitTest.h" for details:

    CrtHandlersSetter()
                {
                    if(IsDebuggerAttached())
                    {
                        debuggerAttached = true;
                        return;
                    }
                
                    debuggerAttached = false;
                    // Suppress the assert failure dialog.
                    oldReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
                    oldReportFile = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
                    // Set the handler
                    oldInvalidParameterHandler = _set_invalid_parameter_handler(reinterpret_cast<INVALID_PARAMETER_HANDLER>(InvalidParameterHandler));
                }
            
                ~CrtHandlersSetter()
                {
                    if(debuggerAttached)
                    {
                        return;
                    }
                
                    _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
                    _CrtSetReportFile(_CRT_ASSERT, oldReportFile);
                    _set_invalid_parameter_handler(oldInvalidParameterHandler);
                }


    Tuesday, January 16, 2018 5:02 AM