Closed kirk0830 closed 1 year ago
After some search, I find that access check is not invoked in explicit template instantiation, and there's already some repo/code available on github which exploit this behavior for non-invasive tests:
https://github.com/martong/access_private https://gist.github.com/dabrahams/1528856
This behavior is stated in the following paragraph from the C++11 standdard (14.7.2, paragraph 12) https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf
"The usual access checking rules do not apply to names used to specify explicit instantiations. [ Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible. — end note ]"
The tool in https://github.com/martong/access_private is simply one header file, and the usage is non-invasive, i.e., no modification to the origional source file is required. I think if testing private functions is really necessary, this might be something we can introduce (or simply learn the idea & write our own) to our unit test procedure. What are your opinions @baixiaokuang @hongriTianqi ?
The following is an example with googletest.
PS: The test/test.cpp in https://github.com/martong/access_private contains more examples, including static member & functions, etc.
testee.h (the class under test)
#ifndef TESTEE_H_
#define TESTEE_H_
#include <iostream>
class Testee {
public:
Testee() : num_(0) {}
~Testee() {};
void set(int i) { num_ = i; }
int get() const { return num_; }
private:
int num_;
void addone() { num_ += 1; }
int times_a_plus_b(int a, int b) { return a * num_ + b; }
};
#endif
unit test source file:
#include "testee.h"
#include "../include/access_private.hpp"
#include <gtest/gtest.h>
ACCESS_PRIVATE_FUN(Testee, void(), addone);
ACCESS_PRIVATE_FUN(Testee, int(int,int), times_a_plus_b);
ACCESS_PRIVATE_FIELD(Testee, int, num_)
class Tester : public ::testing::Test {
protected:
void SetUp();
void TearDown();
Testee t;
};
void Tester::SetUp() {
t.set(0);
}
void Tester::TearDown() {
}
TEST_F(Tester, test1) {
int n = 9;
t.set(n);
call_private::addone(t);
EXPECT_EQ(t.get(), n+1);
t.set(n);
int a = 2;
int b = 5;
int res = call_private::times_a_plus_b(t, a, b);
EXPECT_EQ(res, a*n+b);
n = 22;
t.set(n);
EXPECT_EQ(access_private::num_(t), n);
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
return result;
}
@jinzx10 @kirk0830 Good Idea. I think we should learn from the author, and implement our own.
Private functions have been tested indirectly by testing public functions which call those private: They are: readin_C4(),init_TableOne(), init_Faln(). Function allocate_C4() should be tested in unit test of ModuleBase::RealArray.
Meet trouble when adding unit test on module_io/bessel_basis. Relevant issue #2614 .
Discussed in https://github.com/deepmodeling/abacus-develop/discussions/2659