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

CombinationApprovals snippet does not compile with single header #90

Closed
claremacrae opened this issue Jan 16, 2020 · 6 comments
Closed
Labels

Comments

@claremacrae
Copy link
Collaborator

claremacrae commented Jan 16, 2020

Steps to reproduce:

  • Create a main.cpp with the usual two lines for Catch
#define APPROVALS_CATCH
#include "ApprovalTests.hpp"
  • Create a copy of ApprovalTests.v.7.0.0.hpp (from the releases page) called ApprovalTests.v.7.0.0_hacked_catch_include.hpp - with this change:
-#include "catch.hpp"
+#include "catch2/catch.hpp"
  • Create a second cpp with this code:
#include "catch2/catch.hpp"
#include "ApprovalTests.v.7.0.0_hacked_catch_include.hpp"
#include "PairUtilities.h"

using namespace ApprovalTests;

// begin-snippet: YouCanVerifyCombinationsOf2
TEST_CASE("YouCanVerifyCombinationsOf2")
{
    std::vector<std::string> v{"hello", "world"};
    std::vector<int> numbers{1, 2, 3};
    CombinationApprovals::verifyAllCombinations(
        [](std::string s, int i) { return std::make_pair(s, i); }, v, numbers);
}
// end-snippet
  • Build it on Mac, with XCode generator, ninja and unity build:
cmake -G "Ninja" -DCMAKE_UNITY_BUILD=yes

It will fail to compile - as noted in #89 (comment)

I believe that this is related to Catch's issue 1405 - linked from the comment above.

@claremacrae claremacrae changed the title CombinationApprovals documentation snippet does not compile in Unity builds CombinationApprovals snippet does not compile with single header in Unity builds Jan 16, 2020
@claremacrae
Copy link
Collaborator Author

The build output is:

[1/2] Building CXX object approval_tests_cpp_proj/build/examples/build_failure_test/CMakeFiles/build_failure_test.dir/CombinationTests.cpp.o
FAILED: approval_tests_cpp_proj/build/examples/build_failure_test/CMakeFiles/build_failure_test.dir/CombinationTests.cpp.o 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++  -DCATCH_CONFIG_FAST_COMPILE -DDUMMY_TEST_DEFINE -I/Users/clare/Documents/develop/cpp/Catch2/single_include -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk   -Wall -Wextra -Wpedantic -Werror -std=gnu++1z -MD -MT approval_tests_cpp_proj/build/examples/build_failure_test/CMakeFiles/build_failure_test.dir/CombinationTests.cpp.o -MF approval_tests_cpp_proj/build/examples/build_failure_test/CMakeFiles/build_failure_test.dir/CombinationTests.cpp.o.d -o approval_tests_cpp_proj/build/examples/build_failure_test/CMakeFiles/build_failure_test.dir/CombinationTests.cpp.o -c /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp
In file included from /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:2:
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/ApprovalTests.v.7.0.0_hacked_catch_include.hpp:2467:24: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
        out << ") => " << converter(input1, inputs...) << '\n';
                       ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/ApprovalTests.v.7.0.0_hacked_catch_include.hpp:923:12: note: in instantiation of function template specialization 'ApprovalTests::CombinationApprovals::Detail::serialize<(lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:13:9)>::operator()<std::__1::basic_string<char>, int>' requested here
    return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
           ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/ApprovalTests.v.7.0.0_hacked_catch_include.hpp:1047:17: note: in instantiation of function template specialization 'ApprovalTests::CartesianProduct::Detail::apply<ApprovalTests::CombinationApprovals::Detail::serialize<(lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:13:9)>, std::__1::tuple<std::__1::basic_string<char>, int> >' requested here
        Detail::apply(std::forward<F>(f), Detail::transform<Detail::dereference_iterator>(its));
                ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/ApprovalTests.v.7.0.0_hacked_catch_include.hpp:2476:23: note: in instantiation of function template specialization 'ApprovalTests::CartesianProduct::cartesian_product<ApprovalTests::CombinationApprovals::Detail::serialize<(lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:13:9)>, std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, std::__1::vector<int, std::__1::allocator<int> > >' requested here
    CartesianProduct::cartesian_product(Detail::serialize<Converter>{s, std::forward<Converter>(converter)}, input0, inputs...);
                      ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/ApprovalTests.v.7.0.0_hacked_catch_include.hpp:2484:5: note: in instantiation of function template specialization 'ApprovalTests::CombinationApprovals::verifyAllCombinations<(lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:13:9), std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, std::__1::vector<int, std::__1::allocator<int> > >' requested here
    verifyAllCombinations(DefaultReporter(), std::forward<Converter>(converter), inputs...);
    ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:12:27: note: in instantiation of function template specialization 'ApprovalTests::CombinationApprovals::verifyAllCombinations<(lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/CombinationTests.cpp:13:9), std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, std::__1::vector<int, std::__1::allocator<int> > >' requested here
    CombinationApprovals::verifyAllCombinations(
                          ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/examples/build_failure_test/PairUtilities.h:9:26: note: 'operator<<' should be declared prior to the call site
    inline std::ostream& operator<<(std::ostream& os,
                         ^
1 error generated.
ninja: build stopped: subcommand failed.

@claremacrae
Copy link
Collaborator Author

This is a minimal example that fails to compile with XCode:

#include "catch2/catch.hpp"
#include "ApprovalTests/CombinationApprovals.h"
#include "PairUtilities.h"

using namespace ApprovalTests;

TEST_CASE("YouCanVerifyCombinationsOf2")
{
    std::vector<std::string> v{"hello", "world"};
    std::vector<int> numbers{1, 2, 3};
    CombinationApprovals::verifyAllCombinations(
        [](std::string s, int i) { return std::make_pair(s, i); }, v, numbers);
}

Output is:

/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/ApprovalTests/../ApprovalTests/CombinationApprovals.h:40:36: 
error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
                    out << ") => " << converter(input1, inputs...) << '\n';
                                   ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/ApprovalTests/../ApprovalTests/utilities/CartesianProduct.h:57:24:
 note: in instantiation of function template specialization 'ApprovalTests::CombinationApprovals::Detail::serialize<(
     lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/CombinationTests.cpp:12:9)>::operator()<std::__1::basic_string<char>, int>' requested here
                return std::forward<F>(f)(
                       ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/ApprovalTests/../ApprovalTests/utilities/CartesianProduct.h:215:25:
 note: in instantiation of function template specialization 
 'ApprovalTests::CartesianProduct::Detail::apply<ApprovalTests::CombinationApprovals::Detail::serialize<(
     lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/CombinationTests.cpp:12:9)>,
      std::__1::tuple<std::__1::basic_string<char>, int> >' requested here
                Detail::apply(
                        ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/ApprovalTests/../ApprovalTests/CombinationApprovals.h:52:31:
 note: in instantiation of function template specialization 
 'ApprovalTests::CartesianProduct::cartesian_product<ApprovalTests::CombinationApprovals::Detail::serialize<(
     lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/CombinationTests.cpp:12:9)>,
      std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, std::__1::vector<int, std::__1::allocator<int> > >' requested here
            CartesianProduct::cartesian_product(
                              ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/ApprovalTests/../ApprovalTests/CombinationApprovals.h:65:13:
 note: in instantiation of function template specialization 'ApprovalTests::CombinationApprovals::verifyAllCombinations<(
     lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/CombinationTests.cpp:12:9),
      std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, std::__1::vector<int, std::__1::allocator<int> > >' requested here
            verifyAllCombinations(DefaultReporter(),
            ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/CombinationTests.cpp:11:27: note:
 in instantiation of function template specialization 'ApprovalTests::CombinationApprovals::verifyAllCombinations<(
     lambda at /Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/CombinationTests.cpp:12:9),
      std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, std::__1::vector<int, std::__1::allocator<int> > >' requested here
    CombinationApprovals::verifyAllCombinations(
                          ^
/Users/clare/Documents/develop/ApprovalTests/ApprovalTests.cpp/tests/Catch2_Tests/PairUtilities.h:9:26: note: 'operator<<' should be declared prior to the call site
    inline std::ostream& operator<<(std::ostream& os,
                         ^
1 error generated.
make[3]: *** [tests/Catch2_Tests/CMakeFiles/Catch2_Tests.dir/CombinationTests.cpp.o] Error 1
make[2]: *** [tests/Catch2_Tests/CMakeFiles/Catch2_Tests.dir/all] Error 2
make[1]: *** [tests/Catch2_Tests/CMakeFiles/Catch2_Tests.dir/rule] Error 2
make: *** [Catch2_Tests] Error 2

@claremacrae
Copy link
Collaborator Author

This is a minimal example that fails to compile with XCode:

#include "catch2/catch.hpp"
#include "ApprovalTests/CombinationApprovals.h"
#include "PairUtilities.h"

If I switch the 2nd and 3rd header, it works fine:

#include "catch2/catch.hpp"
#include "PairUtilities.h"
#include "ApprovalTests/CombinationApprovals.h"

Is this actually reasonable behaviour?

Or do we need to do something like in catchorg/Catch2#1405

@claremacrae claremacrae pinned this issue Jan 25, 2020
@claremacrae
Copy link
Collaborator Author

I wonder if this is a rediscovery of #6

@claremacrae claremacrae changed the title CombinationApprovals snippet does not compile with single header in Unity builds CombinationApprovals snippet does not compile with single header Mar 3, 2020
@claremacrae
Copy link
Collaborator Author

Notes for future us:

One issue is that we are not releasing the PairUtilities.h function - so the snippet code, as published, is expected not to work.

We could work around that by adding this code - but adding code to std is not legal, so it's still not a full workaround:

namespace std
{
    std::ostream& operator<<(std::ostream& os,
                             const std::pair<std::string, int>& pair)
    {
        os << "(" << pair.first << ", " << pair.second << ")";
        return os;
    }
}

@isidore isidore closed this as completed Aug 18, 2021
@isidore
Copy link
Member

isidore commented Aug 18, 2021

The code above is no longer in the documentation

@claremacrae claremacrae unpinned this issue Sep 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants