nlib
testing/param_type/param_type.cpp
The sample for the typing test. Describes how to use the TYPED_TEST_CASE( ) macro and the TYPED_TEST( ) macro.
The sample test code tests whether the target class fulfills the group definition. This means that the following are valid for all objects a,b,c that are part of a class.
  • a + (b + c) == (a + b) + c (Associative Law)
  • 0 + a == a + 0 (Identity Element)
  • 0 + a == a + 0 (Inverse Element)
These operations correspond to the following test codes.
Integer 4 modulo(Z4), quaternion(Q4), and integer 256 modulo(unsigned char) are provided as the test target class (type).
// define NLIB_USE_GTEST to use googletest
// #define NLIB_USE_GTEST
// Z4: factor group of 'x mod 4'
class Z4 {
public:
Z4() : m_Value(0) {}
explicit Z4(int x) : m_Value(x > 0 ? (x & 3) : ((-x) & 3)) {}
bool operator==(const Z4& rhs) const { return m_Value == rhs.m_Value; }
bool operator!=(const Z4& rhs) const { return m_Value != rhs.m_Value; }
Z4& operator+=(const Z4& rhs) {
m_Value = (m_Value + rhs.m_Value) & 3;
return *this;
}
int value() const { return m_Value; }
Z4& operator++() {
m_Value = (m_Value + 1) & 3;
return *this;
}
private:
int m_Value;
};
NLIB_TESTING_OSTREAM& operator<<(NLIB_TESTING_OSTREAM& str, const Z4& data) {
str << "Z4(" << data.value() << ")";
return str;
}
Z4 operator+(const Z4& lhs, const Z4& rhs) {
Z4 result(lhs);
result += rhs;
return result;
}
// quaternion group
class Q4 {
public:
enum ValueType {
ONE = 0,
I = 1,
J = 2,
K = 3,
MINUS_ONE = 4,
MINUS_I = 5,
MINUS_J = 6,
MINUS_K = 7
};
Q4() : m_Value(ONE) {}
explicit Q4(int x) : m_Value(static_cast<ValueType>(x > 0 ? x % 8 : -x % 8)) {}
bool operator==(const Q4& rhs) const { return m_Value == rhs.m_Value; }
bool operator!=(const Q4& rhs) const { return m_Value != rhs.m_Value; }
Q4& operator+=(const Q4& rhs);
ValueType value() const { return m_Value; }
Q4& operator++() {
m_Value = static_cast<ValueType>((m_Value + 1) % 8);
return *this;
}
private:
ValueType m_Value;
};
Q4& Q4::operator+=(const Q4& rhs) {
// ii = jj == kk = ijk = -1
// ij = -ij = k
// jk = -kj = i
// ki = -ik = j
// This sample uses operator+=() for binary operation.
static const ValueType table[8][8] = {{ONE, I, J, K, MINUS_ONE, MINUS_I, MINUS_J, MINUS_K},
{I, MINUS_ONE, K, MINUS_J, MINUS_I, ONE, MINUS_K, J},
{J, MINUS_K, MINUS_ONE, I, MINUS_J, K, ONE, MINUS_I},
{K, J, MINUS_I, MINUS_ONE, MINUS_K, MINUS_J, I, ONE},
{MINUS_ONE, MINUS_I, MINUS_J, MINUS_K, ONE, I, J, K},
{MINUS_I, ONE, MINUS_K, J, I, MINUS_ONE, K, MINUS_J},
{MINUS_J, K, ONE, MINUS_I, J, MINUS_K, MINUS_ONE, I},
{MINUS_K, MINUS_J, I, ONE, K, J, MINUS_I, MINUS_ONE}};
m_Value = table[m_Value][rhs.m_Value];
return *this;
}
NLIB_TESTING_OSTREAM& operator<<(NLIB_TESTING_OSTREAM& str, const Q4& data) {
switch (data.value()) {
case Q4::ONE:
str << "1";
break;
case Q4::I:
str << "i";
break;
case Q4::J:
str << "j";
break;
case Q4::K:
str << "k";
break;
case Q4::MINUS_ONE:
str << "-1";
break;
case Q4::MINUS_I:
str << "-i";
break;
case Q4::MINUS_J:
str << "-j";
break;
case Q4::MINUS_K:
str << "-k";
break;
default:
str << "ERROR";
break;
}
return str;
}
Q4 operator+(const Q4& lhs, const Q4& rhs) {
Q4 result(lhs);
result += rhs;
return result;
}
template <class T>
class GroupTest : public ::testing::Test {
public:
// you can define text fixtures here
};
// check if Z4, Q4, and unsigned char satisfy the definition of group
typedef ::testing::Types<Z4, Q4, unsigned char> MyTypes;
TYPED_TEST_CASE(GroupTest, MyTypes);
TYPED_TEST(GroupTest, BasicInterface) {
TypeParam x = TypeParam(); // check if TypeParam has a default constructor
TypeParam y = TypeParam(x); // check if TypeParam has a copy constructor
x = y; // check if TypeParam has an assignment operator
TypeParam z = x;
++z; // check if operator++() is defined.
// it is used for convenience, to get the next element.
EXPECT_EQ(x, y); // check if operator==() is defined, and x == y
EXPECT_EQ(TypeParam(), TypeParam(0)); // default value is equal to an identity element
}
TYPED_TEST(GroupTest, AssociativeLaw) {
// Associative law:
// a + (b + c) == (a + b) + c
// for all elements
TypeParam e = TypeParam();
TypeParam a = TypeParam();
TypeParam b = TypeParam();
TypeParam c = TypeParam();
do {
do {
do {
ASSERT_EQ(a + (b + c), (a + b) + c) << "a = " << a << ", "
<< "b = " << b << ", "
<< "c = " << c;
++c;
} while (e != c);
++b;
} while (e != b);
++a;
} while (e != a);
}
TYPED_TEST(GroupTest, IdentityElement) {
// existence of an identity element:
// 0 + a == a + 0
// for all elements
TypeParam e = TypeParam();
TypeParam a = TypeParam();
ASSERT_EQ(e, TypeParam());
do {
ASSERT_EQ(e + a, a + e) << a;
++a;
} while (e != a);
}
TYPED_TEST(GroupTest, InverseElement) {
// existence of inverse elements:
// there is an inverse element 'b' for all 'a' such that
// 0 == a + b
TypeParam e = TypeParam();
TypeParam a = TypeParam();
do {
bool success = false;
TypeParam b = TypeParam();
do {
if (e == a + b) {
success = true;
break;
}
} while (e != b);
ASSERT_TRUE(success) << a;
} while (e != a);
}
NLIB_PATHMAPPER_FORSAMPLE
bool SampleMain(int argc, char** argv) {
InitPathMapperForSample();
char path[512];
char buf[512];
size_t count;
g_PathMapper.ResolvePath(&count, path, "nlibpath:///readwrite/param_type.xml");
nlib_snprintf(&count, buf, "xml:%s", path);
::testing::GTEST_FLAG(output) = buf;
// RUN_ALL_TESTS returns 0 if all the tests are successful.
// You can use the return value of main() function.
return RUN_ALL_TESTS() == 0;
}
NLIB_MAINFUNC