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

Don't use define private public in test files #913

Closed
horenmar opened this issue Jan 14, 2018 · 6 comments · Fixed by #2352
Closed

Don't use define private public in test files #913

horenmar opened this issue Jan 14, 2018 · 6 comments · Fixed by #2352
Assignees
Labels
release item: 🔨 further change solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@horenmar
Copy link

horenmar commented Jan 14, 2018

Bug Report

I wanted to check whether Catch 2.1.0 fixed all perf. regression from Catch Classic on a real world test suite, but using #define private public in test files causes compilation errors because of ODR violations.

One example:

In file included from /mnt/c/ubuntu/json/src/json.hpp:1800:0,
                 from /mnt/c/ubuntu/json/test/src/unit-iterators1.cpp:32:
/usr/include/c++/5/sstream:300:7: error: ‘struct std::__cxx11::basic_stringbuf<_CharT, _Traits, _Alloc>::__xfer_bufptrs’ redeclared with different access
       struct __xfer_bufptrs
       ^
test/CMakeFiles/test-iterators1.dir/build.make:62: recipe for target 'test/CMakeFiles/test-iterators1.dir/src/unit-iterators1.cpp.o' failed

This is caused by Catch no longer including <sstream> everywhere, so an attempt to redefine private to public also hits <sstream> header. It can be temporarily fixed by just force including <sstream> before including the json.hpp header, but it should be noted that doing #define private public and having it affect any part of the standard library in any TU using the standard library is UB.

Note: There are also several test files that rely on transitive stdlib includes from Catch and will not compile with newer version.

OS & Compiler: g++ 5.4 under WSL

@nlohmann
Copy link
Owner

I only added #define private public to test suites that contain tests calling private functions or classes. Is there a better way to achieve this without changing the actual library?

@nlohmann nlohmann added the state: help needed the issue needs help to proceed label Jan 14, 2018
@nlohmann
Copy link
Owner

(And I like the idea of using a more recent version of Catch. I tried an early 2.0 version, but the performance of the tests was worse.)

@horenmar
Copy link
Author

As far as I know, there is no way of doing this with no changes to the header.

There are two ways these things are usually solved:

  1. Add a friend declaration for class that holds the test fixtures.
  2. Have a conditional access modifier:
#ifndef UNDER_TEST
#define INTERNAL_BLOCK private
#else
#define INTERNAL_BLOCK public
#endif
class foo {
public:
    foo() { ... }
INTERNAL_BLOCK:
    bool helper_1(){ ... }
    int helper_2() { ... }
    ...
};

A common argument is also that if a private method needs to be made accessible to be tested, then the class is too complex and should be breaked apart (because a class should be defined by its external api, not implementation details), but I admit that I don't particularly subscribe to that philosophy.

@theodelrieu
Copy link
Contributor

With the recent basic_json refactoring, I think tests could be rewritten to use the low-level constructs (e.g. iterators/lexer etc...).

Those would remain unexposed by the basic_json class, but the need for the #define private public hack should disappear.

@nlohmann
Copy link
Owner

This still would not allow a unit test to check the value of a private member variable. Though such a check may be expressed in terms of the public API in some cases, refactoring the code for the edge cases would be a lot of work.

@nlohmann nlohmann added the solution: wontfix the issue will not be fixed (either it is impossible or deemed out of scope) label Jan 17, 2018
@chen3feng
Copy link

#define keyword is an undefined behavior in C++ std. And in gcc, access may change managed function name. I think using friend is a better way.

@nlohmann nlohmann added release item: 🔨 further change solution: proposed fix a fix for the issue has been proposed and waits for confirmation and removed solution: wontfix the issue will not be fixed (either it is impossible or deemed out of scope) state: help needed the issue needs help to proceed labels Aug 12, 2020
@nlohmann nlohmann added this to the Release 3.9.2 milestone Aug 12, 2020
@nlohmann nlohmann self-assigned this Aug 13, 2020
falbrechtskirchinger added a commit to falbrechtskirchinger/json that referenced this issue May 1, 2022
Fixes:
  error nlohmann#913: invalid multibyte character sequence
falbrechtskirchinger added a commit to falbrechtskirchinger/json that referenced this issue May 1, 2022
Fixes:
  error nlohmann#913: invalid multibyte character sequence
falbrechtskirchinger added a commit to falbrechtskirchinger/json that referenced this issue May 1, 2022
Fixes:
  error nlohmann#913: invalid multibyte character sequence
falbrechtskirchinger added a commit to falbrechtskirchinger/json that referenced this issue May 1, 2022
Fixes:
  error nlohmann#913: invalid multibyte character sequence
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release item: 🔨 further change solution: proposed fix a fix for the issue has been proposed and waits for confirmation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants