Repository: doctest/doctest

Issue #567: `g_oss` is causing incorrect stringification results
Created: 2021-12-11T23:30:11Z
Edit: I have now published a possible fix at #569!
I'm currently working on a stringification utility for STL classes, and I've discovered an obscure bug that manifests in two slightly different ways:
1.
When an argument to a MessageBuilder is stringified via being written to an ostream (operator<<) the result of that stringification is accidentally prepended to the result of the MessageBuilder.
Example:
struct A { }; struct B { };
static std::ostream& operator<<(std::ostream& o, const A&) { o << "A"; return o; }
template<> struct doctest::StringMaker<B> {
	static String convert(const B&) { return toString(A()) + "B"; }
};
TEST_CASE("") { FAIL(B()); }
Expected result: AB
Actual result: AAB
This can be avoided by first writing the String into an object like so:
doctest::String s = doctest::toString(B());
FAIL(s);
2.
When an operator<< utilizes toString which in turn executes its function via writing to a stream.
Arguably this is a bit contrived, since you usually wouldn't use toString in an operator<< overload, but it still shows a weakness in design, which demonstrates that simply giving MessageBuilderss their own thread local osstream won't solve this problem entirely.
There might be a less contrived instance of this bug lurking somewhere!
Example:
struct A { }; struct B { };
static std::ostream& operator<<(std::ostream& o, const A&) { o << "A"; return o; }
static std::ostream& operator<<(std::ostream& o, const B&) { o << "C" << "B" + doctest::toString(A()); return o; }
TEST_CASE("") { String s = toString(B()); FAIL(s); /* Failure is not due to MessageBuilder! */ }
Expected result: CBA
Actual result: ACA
The stream that is used to stringify B needs to be used again to stringify A, this messes things up.
I'm honestly not entirely sure on how to solve this, I think the idea of having a single string buffer will need to be abandoned.
My first approach was simply moving the logic of resetting the buffer into the result function, this solves 1. but modifies 2.'s result to be BCA, which is still incorrect!
My current progress can be found on https://github.com/Saalvage/doctest/tree/tlss
Some input would be appreciated!
Extra information

doctest version: a384864 (dev head at the time of posting)
Operating System: Windows 10 Pro 19043
Compiler+version: MSVC 22 17.0.2

Duplicate issue #568: Compilation errors on MSVC 2015 after doctest update to 2.4.7
Created: 2021-12-12T09:51:39Z
Description
Code below doesn't compile on MSVC 2015 when doctest 2.4.7 is used (but compiles fine when doctest is 2.4.6).
Compiler output:
d:\doctest_bug\doctest.h(821): error C2440: 'return': cannot convert from 'const char [4]' to 'const char (&&)[4]'
d:\doctest_bug\doctest.h(821): note: You cannot bind an lvalue to an rvalue reference
d:\doctest_bug\doctest.h(1320): note: see reference to function template instantiation 'T (&&doctest::detail::forward<const R>(const char (&)[4]) noexcept)' being compiled
        with
        [
            T=char [4],
            R=char [4]
        ]
d:\doctest_bug\doctest_bug.cpp(7): note: see reference to function template instantiation 'doctest::detail::Result doctest::detail::Expression_lhs<const std::string &>::operator ==<char[4],0x0>(const R (&))' being compiled
        with
        [
            R=char [4]
        ]
d:\doctest_bug\doctest_bug.cpp(7): note: see reference to function template instantiation 'doctest::detail::Result doctest::detail::Expression_lhs<const std::string &>::operator ==<char[4],0x0>(const R (&))' being compiled
        with
        [
            R=char [4]
        ]

Steps to reproduce

Create file doctest_bug.cpp with following content:

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include <string>

TEST_CASE("string comparison") {
    std::string str = "ABC";
    CHECK(str == "ABC");
}

Compile it with MSVC 2015 and Doctest 2.4.7

Extra information

doctest version: 2.4.7
Operating System: Windows 10
Compiler+version: MSVC 2015

Closing comment (2021-12-13T17:27:32Z): Turns out the latest release was without MSVC 2015 testing due to the migration to a github org & relying solely on github actions - re-enabling appveyor now...
Just committed a test like your snippet (but changed so that it would assert: CHECK(str == "ABC2");) and holy cow:
https://github.com/doctest/doctest/runs/4509284329?check_suite_focus=true
seems that GCC & new versions of MSVC handle it properly, but clang & MSVC 2015 error on it, and in different ways.

MSVC cannot compile
clang constructs the stringified version incorrectly which might be related to #567 :

-  values: CHECK( ABC == ABC2 )
+  values: CHECK( ABC == ABCABC2 )