Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Lime
Jul 20, 2004

Slurps Mad Rips posted:

Bit of a waste, since shared_ptr allocates a control block. Now you've got two ref counts, *and* you're wasting a lot of extra space for just one pointer. 🤷‍♀️

Oh yeah, for sure. I only suggest it because it's dead simple and OP said they'd prefer using a standard library type.

Adbot
ADBOT LOVES YOU

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
DIY is probably less code than trying to use any existing helper. Binding to external refcounting is really simple, if slightly error-prone.

big black turnout
Jan 13, 2009



Fallen Rib
Yeah I ended up rolling my own because it's something I'm working on for fun, and rolling my own was fun, and also because I didn't want to deal with adding boost.

Gonna take a look at that proposal one though.

edit: also because the boost version relies on free functions to handle increment/decrement and I can just call the one method I need.

big black turnout fucked around with this message at 06:28 on Jul 21, 2019

big black turnout
Jan 13, 2009



Fallen Rib

Slurps Mad Rips posted:

I might suggest looking into my proposed (and currently on track for C++23) retain_ptr instead, since you don't have to worry about the "retain by default" semantic and having to pass "false" everywhere you want to adopt a pointer :v:

https://github.com/slurps-mad-rips/retain-ptr/

There's a bug with the builtin mixin type, but just specialize a retain_traits<YourType> and you're good to go

Yeah, I like this a lot better than the boost version, I think. I chose to go the opposite direction of yours and call my method release instead of detach. I also lol'd at

quote:

Comedy Option:
`auto_ptr`

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
retain_ptr does look really nice, actually!

Nostalgamus
Sep 28, 2010

I'm trying to figure out a linking error I'm stuck with at work. For the record, I do not have a firm grasp on C++ in general.

I'm working on an (ancient) application that refers to a third party DLL for several important functions. This DLL is used through explicit linking, and I've recently replaced it with a newer version of the DLL that had renamed most of the functions. So far so good.

However, to work with the new version, we need to convert our source files to the format the new version of the DLL expects. We've been provided another DLL file which provides a function for this, and I tried to set that up similar to the existing implementations. We are not given .lib files, so implicit linking is out.

The header file for the conversion DLL was not provided, but I was given enough information about the single function it contained that I was able to create one. I've also added relevant calls to LoadLibrary and GetProcAddress, and implemented a call to the conversion function at the appropriate time. At this point the application compiles without errors, but I then get linking errors (LNK2019 and LNK2028, both referring to the same function call).

Based on my (limited) understanding of explicit linking, this should not be happening - even if the function header is completely different from the actual function in the DLL, since nothing actually checks whether the function exits until runtime.

I've been trying to find differences with the other DLL and header file we were provided, but I'm coming up short. Apparently the conversion dll isn't using _stdcall (the other dll does for all functions) - but again, this is something that to my understanding would not be relevant until runtime.

Google isn't helpful, since it apparently decided that "implicit" and "explicit" are interchangeable words.

Any known common culprits for this?

Absurd Alhazred
Mar 27, 2010

by Athanatos

Nostalgamus posted:

I'm trying to figure out a linking error I'm stuck with at work. For the record, I do not have a firm grasp on C++ in general.

I'm working on an (ancient) application that refers to a third party DLL for several important functions. This DLL is used through explicit linking, and I've recently replaced it with a newer version of the DLL that had renamed most of the functions. So far so good.

However, to work with the new version, we need to convert our source files to the format the new version of the DLL expects. We've been provided another DLL file which provides a function for this, and I tried to set that up similar to the existing implementations. We are not given .lib files, so implicit linking is out.

The header file for the conversion DLL was not provided, but I was given enough information about the single function it contained that I was able to create one. I've also added relevant calls to LoadLibrary and GetProcAddress, and implemented a call to the conversion function at the appropriate time. At this point the application compiles without errors, but I then get linking errors (LNK2019 and LNK2028, both referring to the same function call).

Based on my (limited) understanding of explicit linking, this should not be happening - even if the function header is completely different from the actual function in the DLL, since nothing actually checks whether the function exits until runtime.

I've been trying to find differences with the other DLL and header file we were provided, but I'm coming up short. Apparently the conversion dll isn't using _stdcall (the other dll does for all functions) - but again, this is something that to my understanding would not be relevant until runtime.

Google isn't helpful, since it apparently decided that "implicit" and "explicit" are interchangeable words.

Any known common culprits for this?

If you're explicitly loading the library, then you shouldn't be statically linking to it at all. Either create your own functions with the same signatures that will be essentially callbacks working through the function pointers provided from the DLL, or just create a wrapper for the new functionality, or both, depending on what'll make things easier for you.

Harik
Sep 9, 2001

From the hard streets of Moscow
First dog to touch the stars


Plaster Town Cop
Yes, it's been a month because I accidentally took this thread off my control panel, but:

qsvui posted:

What type information? :imunfunny:

code:
typedef struct {
	void * priv;
} Dong;

void dong(Dong d) {
	(void) d;
}

int main() {
	Dong d = { 0 };
	void * vp = 0;
	dong(d);
	dong(vp); // incompatible type for argument 1 of 'dong'
	return(0);
}
I'm dumb though: I mixed up two things. As you and Z both pointed out: you should use a forward struct declaration. I was thinking of "integers that have special meaning" so struct FartVolume { int v; } prevents you from just passing raw integers to something expecting it. I mixed that up with naked void pointers being common as state for "generic" c callbacks, since there's not really any great way to carry that state around.

Anyway, C++/unit testing question:

You nearly always want to only test the public interface of a class, so close to always it's basically universal.

Except an edge case: handle allocation rollover, timer rollover - things that a class keeps as state but requires a long runtime to possibly expose bugs on.

As an example, a resource manager returns opaque handles that must be unique over a reasonable time period. A pointer to the memory isn't unique in that sense because you can release a resource and immediately request one and get the exact same pointer. A serial number works, but eventually rolls over, so a long-lived resource at ID 0 will be duplicated eventually.

How do you unit test without looping to MAXINT? Something like this is clearly a self-contained piece of functionalty that screams to be made into a generic class, but you still have to expose the internal serial number state to advance it in a test, and that makes the details of the implementation part of the API.

I'm thinking protected visibility instead of private, and extend it into a TestableFoo class which just adds getters/setters. Has anyone solved it in a different, probably better way?

qsvui
Aug 23, 2003
some crazy thing
One thought that comes to mind is to move that functionality into a generic class like you suggested and then to require a reference to that class in your resource manager's constructor. If you don't want to specify a concrete type for that reference, you could use an abstract interface or a template parameter. Then in your tests, you use fake versions of the serial number class.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Harik posted:

I'm thinking protected visibility instead of private, and extend it into a TestableFoo class which just adds getters/setters. Has anyone solved it in a different, probably better way?
Leave it private, give it a friend test class or friend test functions.

Captain Cappy
Aug 7, 2008

#define private public
#define protected public
#define class struct

Harik
Sep 9, 2001

From the hard streets of Moscow
First dog to touch the stars


Plaster Town Cop

qsvui posted:

One thought that comes to mind is to move that functionality into a generic class like you suggested and then to require a reference to that class in your resource manager's constructor. If you don't want to specify a concrete type for that reference, you could use an abstract interface or a template parameter. Then in your tests, you use fake versions of the serial number class.
You mean dependency inject what amounts to a counter? That's what I'd do for anything time-based so it's probably right. Or anything that has a random() input, or anything with any input that impacts how it operates, really. It also decouples the implementation from "monotonically incrementing counter" to "anything that can return a next() value", since I don't care what the handles are, only that they're unique and not immediately reused on release.

That smells right, and the rest of the resource-creation is heavy enough that that an extra dereference would not remotely be an issue. Thanks!

Dren
Jan 5, 2001

Pillbug
Another technique is to use a pimpl and structure your library code like this:
code:
include/
  mylib/
    mylib.h
src/
  mylib.cpp
  allocator.h
  allocator.cpp
test/
  test.cpp
Stuff that's under include/ is public, stuff that's under src/ is private. Tests are special and are allowed to #include from src/. This way you can pull the allocator out into its own class and unit test it without exposing it as part of the public interface.

Aramis
Sep 22, 2009



Honestly, I've switched to just making "private but accessible to tests" members public with a python style underscore postfix. It's just not a fight worth fighting. It's obvious, trivial to catch in a code review, and prevents me from comprimising designs just for the sake of testability. Maybe one day I'll write a clang-tidy tool to check for that, but I seriously doubt that'll actually improve anything.

Aramis fucked around with this message at 21:32 on Jul 29, 2019

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Aramis posted:

Honestly, I've switched to just making "private but accessible to tests" members public with a python style underscore postfix. It's just not a fight worth fighting. It's obvious, trivial to catch in a code review, and prevents me from comprimising designs just for the sake of testability. Maybe one day I'll write a clang-tidy tool to check for that, but I seriously doubt that'll actually improve anything.
I feel like people thought it was a joke when I said use a friend class.

But like this: real header file
code:
class Butt {
  public:
    Butt() : _secret(5);

  private:
    int _secret;
    friend class Testicle;
}
Test cc file something like
code:
class Testicle {
  public:
    Butt &butt;
    Testicle(Butt &butt) : butt(butt) {}
    int secret() { return butt._secret; }
}

void testSecretOrWhatever() {
  Butt buttToTest;
  Testicle testicle(butt);
  EXPECT(testicle.secret(), Equals(5));
}
You can also inject stuff into private variables too, but only from a Testicle. It's only one line more in each header file and a few lines in the test file, and it makes your intent clear (versus annotation-based "kinda private" that is only clear if you're familiar with the local annotation). An escaping underscore isn't that easy to catch in code review, but an escaping Testicle is very easy.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Couldn’t you write a static analysis that methods ending in __ are only called from within the class or within files starting with `test-`?

Absurd Alhazred
Mar 27, 2010

by Athanatos
Why not work with C++ and Intellisense or whatever the equivalent is in other IDE's? Why create another layer you need to conform with that won't pop up as easily?

Adhemar
Jan 21, 2004

Kellner, da ist ein scheussliches Biest in meiner Suppe.
Y’all are solving the wrong problem; you shouldn’t be testing the internal implementation details of your classes like that, it creates very brittle tests. If you can’t test your class using only its public methods, it’s doing too much and needs to be broken into pieces that can be tested individually.

Dren
Jan 5, 2001

Pillbug

Aramis posted:

Honestly, I've switched to just making "private but accessible to tests" members public with a python style underscore postfix. It's just not a fight worth fighting. It's obvious, trivial to catch in a code review, and prevents me from comprimising designs just for the sake of testability. Maybe one day I'll write a clang-tidy tool to check for that, but I seriously doubt that'll actually improve anything.

But in python there’s name mangling on __ prefixed stuff to prevent an accident. __ prefix is both trivial to catch in a code review and trivial to miss in a code review. And it’s very tempting for someone who is new or under time pressure to use the public as a public. The friend method seems preferable to this solution. Adding #ifdef TESTING around the friend declaration and building the test with -DTESTING would further clarify the intent and ensure that the friend declaration never shows up in production.

Adhemar posted:

Y’all are solving the wrong problem; you shouldn’t be testing the internal implementation details of your classes like that, it creates very brittle tests. If you can’t test your class using only its public methods, it’s doing too much and needs to be broken into pieces that can be tested individually.

Nah. Sometimes a class has a private thing that isn’t part of the public interface but is nonetheless important to test on its own. And nothing else uses that thing so breaking it out is overkill.

Related: have you guys heard about fseam for mocking?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Dren posted:

Nah. Sometimes a class has a private thing that isn’t part of the public interface but is nonetheless important to test on its own. And nothing else uses that thing so breaking it out is overkill.
Or more often, sometimes a class has internal state that's important to trigger behaviors you want to test, and a pain to provoke from outside the class, like if you have a cache class it's much clearer to be able to go "cache class with mock fetcher, give me this thing: is it populated as expected in the private stuff?" rather than the unclear "cache class with mock fetcher, give me this thing, now give me it again, did it give me the same thing twice and only ask the fetcher for it once?" And that's the simple kind of example - I had a cache that stored a rolling time-range of recent content, for example, that was streamed to as the data was written, and if you request a thing from the recent content you get it from that cache, but if you request something older it pulls it from the archive data store. Testing that kind of thing without being able to inspect and inject the internal state is just hideous, you end up with a monolithic "write some things, read some things, read some other things" single long test. Which is great as an integration test, but some unit testing in smaller pieces is much more helpful for debugging.

Edit: oh, also if you asked it for data newer than the latest streamed data the request would block until newer data comes in, or a timeout. Testing all that in one giant mess test is no bueno.

Adhemar
Jan 21, 2004

Kellner, da ist ein scheussliches Biest in meiner Suppe.

Dren posted:

Nah. Sometimes a class has a private thing that isn’t part of the public interface but is nonetheless important to test on its own. And nothing else uses that thing so breaking it out is overkill.

That’s not the only criterion for breaking something out. If a class is this complex, the inability to properly test it is a symptom of that, not the problem. Breaking the class up can help. You may even find a use for the newly extracted piece later, but that’s not required.

Dren
Jan 5, 2001

Pillbug

Adhemar posted:

That’s not the only criterion for breaking something out. If a class is this complex, the inability to properly test it is a symptom of that, not the problem. Breaking the class up can help. You may even find a use for the newly extracted piece later, but that’s not required.

I like this better if it falls in with my physical layout suggestion from earlier for a library:
code:
include/
  resman/
    ResHandle.h
src/
  ResHandle.cpp
  ResHandleImpl.h
  ResHandleImpl.cpp
test/
  test.cpp
I'll do OP's original problem statement:

Harik posted:

As an example, a resource manager returns opaque handles that must be unique over a reasonable time period. A pointer to the memory isn't unique in that sense because you can release a resource and immediately request one and get the exact same pointer. A serial number works, but eventually rolls over, so a long-lived resource at ID 0 will be duplicated eventually.

How do you unit test without looping to MAXINT? Something like this is clearly a self-contained piece of functionalty that screams to be made into a generic class, but you still have to expose the internal serial number state to advance it in a test, and that makes the details of the implementation part of the API.

I'm thinking protected visibility instead of private, and extend it into a TestableFoo class which just adds getters/setters. Has anyone solved it in a different, probably better way?

stuff in include/ - the public interface

ResHandle.h - opaque handle to resource
code:
class ResHandleImpl;

class ResHandle {
public:
  ResHandle(/* some args specifying what you wanna allocate, I dunno */);
private:
  std::unique_ptr<ResHandleImpl> _pimpl;
};
stuff in src/ - the private implementation

ResHandle.cpp
code:
#include "resman/ResMan.h"
#include "ResHandleImpl.h"

ResHandle::ResHandle(/* some args specifying what you wanna allocate, I dunno */) {
  _pimpl = std::make_unique<ResHandleImpl>(/* whatever the args are here */);
}
ResHandleImpl.h
code:
struct ResHandleImpl {
  ResHandleImpl(/* args */);
  ~ResHandleImpl();
  uint64_t serial_number;
};
ResHandleImpl.cpp
code:
#include "ResHandleImpl.h"

static uint64_t counter = 0;

ResHandleImpl::ResHandleImpl(/* args */) {
  // allocate stuff
  serial_number = counter++; // set the serial number
}

ResHandleImpl::~ResHandleImpl() {
  // deallocate stuff
}
test code in test/

The tests are allowed to include from src/ so they can see the private implementations that aren't normally exposed publicly.
test.cpp
code:
#include "ResHandleImpl.h"

void mytest() {
  ResHandleImpl x;
  ResHandleImpl y;
  assert(x.serial_number != y.serial_number);
}
If someone doesn't want to or can't structure their code in such a way as to keep the privates hidden from the external interface then the friend thing is good.

Dren fucked around with this message at 16:54 on Jul 30, 2019

qsvui
Aug 23, 2003
some crazy thing
If you're tempted to use friends, you might as well just cut out the middleman and make the data public or create a public accessor. You can also give this accessor a name that stands out as being for testing only so that it can be caught at code reviews.

I'd argue that breaking up functionality and using dependency injection does more than just enable testing and so it should be preferred. But if you can't be bothered then I don't see the point in being cute. If someone abuses a public function that's labelled test only, would they really be discouraged from using a test only friend?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Why the heck would I use a special name and require people to catch misuse in code reviews, when I could accomplish the exact same thing in a way where the compiler will prevent any misuse?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

qsvui posted:

If you're tempted to use friends, you might as well just cut out the middleman and make the data public or create a public accessor. You can also give this accessor a name that stands out as being for testing only so that it can be caught at code reviews.

I'd argue that breaking up functionality and using dependency injection does more than just enable testing and so it should be preferred. But if you can't be bothered then I don't see the point in being cute. If someone abuses a public function that's labelled test only, would they really be discouraged from using a test only friend?
What? "If you're tempted to use friends, you might as well just do something that's objectively much worse in every way and isn't even any easier."

Public accessor functions would be functions that you're putting into your real non-test code and hoping the compiler/linker will strip out as unused in non-test builds. A friend declaration always compiles to literally nothing, and the associated functions (if any) are in a test file that's not part of a non-test build.

I think you're trying to say dependency injection is better, and sure, in many circumstances it is. But saying "so if you don't use dependency injection you might as well just take a huge poo poo on your code for no reason" is ridiculous.

roomforthetuna fucked around with this message at 05:50 on Jul 31, 2019

qsvui
Aug 23, 2003
some crazy thing
Admittedly, I didn't consider compiling the friend classes separately. But even so, what's to prevent someone just creating their own class of the same friend name and using it in a non-test build? If someone is already ignoring a clear convention, then one extra hoop to jump through won't stop them.

I've heard it argued that your tests are also a client of your code. If the client can't use your code, then the code is not fulfilling all of its requirements. Making things public is one way to meet them.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Yes, forcing someone to jump through hoops in order to do the wrong thing is way better than making it trivially easy to do the wrong thing. I'm not sure how that's even a point of discussion.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

qsvui posted:

Admittedly, I didn't consider compiling the friend classes separately. But even so, what's to prevent someone just creating their own class of the same friend name and using it in a non-test build? If someone is already ignoring a clear convention, then one extra hoop to jump through won't stop them.
It's not about stopping someone from doing the wrong thing on purpose, it's about stopping someone from doing the wrong thing by mistake because they're not familiar with some weird convention someone just made up, like the original proposal of an underscore prefix meaning "treat this as private unless you're a test even though it's literally public". It's also about not compiling poo poo into your real code that isn't actually being used. Dependency injection suffers from that - if it's something you're only doing in aid of tests, is it really worth having an actual performance penalty and additional complexity in your real code so that you can test something, when you could have done it another way, that isn't any harder, without that performance penalty or complexity?

It depends on the thing. Sometimes injection makes it clearer and testing easier, like if you inject the same thing in multiple places and/or have a well defined fake or mock for it then dependency injection can be great. But if you find yourself doing dependency injection as a one-off specifically for testing one class that you could test directly if you had access to a few private variables, just use a friend test, it's a good clean solution.

Deffon
Mar 28, 2010

You can't really stop actively malicious users from modifying your objects anyway, since they can just reinterpret cast them. Exposing the member variables means that they will be shown as autocomplete suggestions for all usages of the class.

qsvui
Aug 23, 2003
some crazy thing

roomforthetuna posted:

It's not about stopping someone from doing the wrong thing on purpose, it's about stopping someone from doing the wrong thing by mistake because they're not familiar with some weird convention someone just made up, like the original proposal of an underscore prefix meaning "treat this as private unless you're a test even though it's literally public". It's also about not compiling poo poo into your real code that isn't actually being used. Dependency injection suffers from that - if it's something you're only doing in aid of tests, is it really worth having an actual performance penalty and additional complexity in your real code so that you can test something, when you could have done it another way, that isn't any harder, without that performance penalty or complexity?

It depends on the thing. Sometimes injection makes it clearer and testing easier, like if you inject the same thing in multiple places and/or have a well defined fake or mock for it then dependency injection can be great. But if you find yourself doing dependency injection as a one-off specifically for testing one class that you could test directly if you had access to a few private variables, just use a friend test, it's a good clean solution.

The convention doesn't have to be that weird. If you have a function called GetTestOnlyStuff() or some other obnoxious name, then you'd have to be willfully ignorant in claiming that you didn't know that you weren't supposed to use it in production code.

Also, you can still compile the test only stuff separately. For example:

C++ code:
// Widget.h
class Widget
{
public:
  // stuff...

  Details GetTestOnlyStuff();

private:
  // details...
};
C++ code:
// Widget.cpp
// normal implementation details
C++ code:
// WidgetTestOnly.cpp
Details Widget::GetTestOnlyStuff()
{
  // ...
}
My point was that all of these methods that attempt to selectively expose private details only to tests rely on convention. If you can establish other conventions, then you wouldn't need to bother creating test only classes that feature heavy amounts of boilerplate.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Compilers get a lot of poo poo for not being sufficiently smart but they are sufficiently smarter than code reviewers.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You seem to vastly overestimate the amount of 'boilerplate' involved in making something a friend class (serious request here: can you put a number on how much you think it costs?), and vastly underestimate the costs of your proposed bespoke conventions.

Why are you so opposed to having the compiler enforce visibility?

qsvui
Aug 23, 2003
some crazy thing

Jabor posted:

You seem to vastly overestimate the amount of 'boilerplate' involved in making something a friend class (serious request here: can you put a number on how much you think it costs?), and vastly underestimate the costs of your proposed bespoke conventions.

Why are you so opposed to having the compiler enforce visibility?

I don't mean to give that impression, I was just trying to convey what I considered to be a pragmatic option even though it may not be considered "proper OO design". And by cost, I don't know if you mean computing resources, but test code is still code you have to maintain. I don't know how common this friend class usage is, but writing several of these have to be tedious. Maybe you can come up with a generic solution but I'm sure there will have to be special cases for which you have to come up with bespoke code.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You can literally just write friend class MyClassTest;

nielsm
Jun 1, 2009



qsvui posted:

I don't mean to give that impression, I was just trying to convey what I considered to be a pragmatic option even though it may not be considered "proper OO design". And by cost, I don't know if you mean computing resources, but test code is still code you have to maintain. I don't know how common this friend class usage is, but writing several of these have to be tedious. Maybe you can come up with a generic solution but I'm sure there will have to be special cases for which you have to come up with bespoke code.

C++ code:
// src/business.h
class MyBusinessClass {
  friend class Test_MyBusinessClass;
  int _business_stuff;
public:
  bool VerifyBusinessStuff(int value);
};

//test/test_business.cpp
#include "../src/business.h"

class Test_MyBusinessClass : public Test {
public:
  bool RunTest() override {
    MyBusinessClass bc;
    bc._business_stuff = 42;
    return bc.VerifyBusinessStuff(43);
  }
};
You literally just declare in the main class that the test class is allowed to access its privates.

qsvui
Aug 23, 2003
some crazy thing
Hmm, I was using the earlier given Testicle class as a reference. I've never used a test framework that required you to create classes that derive from a test hook base class (I assume that's what's going on).

nielsm
Jun 1, 2009



The test class deriving from a base doesn't matter for the friend declaration to work, as long as the test code is in a named class that named class can be declared friend.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
An alternative option would be to write a TESTONLY macro that evaluates to public in a test, but private otherwise, and then writing something like:

code:

class Foo {
  public:
    void PublicApi();
  private:
    int privateData;
  TESTONLY:
    int internalFunctionThatWeWantToUseFromATest();
}

Though you have to be a bit careful there, because then your unit tests will still pass if someone inadvertantly uses the test-only api in the real code.

qsvui
Aug 23, 2003
some crazy thing

nielsm posted:

The test class deriving from a base doesn't matter for the friend declaration to work, as long as the test code is in a named class that named class can be declared friend.

Yeah, I meant that I never used a framework where you have to override something like a RunTest method. That looks neater for this case, but if you're using a framework like the one in that Testicle example earlier, then your class has to have that constructor and you have to define accessors for each thing that you're interested in that does nothing more than return the value, etc.

Adbot
ADBOT LOVES YOU

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

qsvui posted:

Yeah, I meant that I never used a framework where you have to override something like a RunTest method. That looks neater for this case, but if you're using a framework like the one in that Testicle example earlier, then your class has to have that constructor and you have to define accessors for each thing that you're interested in that does nothing more than return the value, etc.
Even the Testicle model is still literally only 6 lines (friend declaration, class declaration, 'public', the contained class to inspect, constructor, and closing brace of the class declaration) more than the public accessors with special annotations you were suggesting as an alternative. And if you split the test accessor functions into their own file as you suggested with GetTestOnlyStuff then that takes a comparable amount of additional boilerplate already.

You've already needed three of those lines for the test framework with the override, but somehow that's more convincing to you. I guess that has the advantage that you *don't* need any kind of accessor functions any more.

Joke option that's less boilerplate, at the top of your test file #define private public and #define protected public, now it's only two lines of boilerplate and you can access all the things you want from tests!

roomforthetuna fucked around with this message at 16:11 on Jul 31, 2019

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply