I'm trying to test a function using gtest. Here is the pseudo-code:
**Function to Test:**
void ClassAdd::Display(int num) {
for (int n = 1; n <= num; ++num) {
status = ClassInterface_.Function1(...);
...
for (int i = 1; i <= 5; i++) {
status = ClassInterface_.Function2(...);
...
}
for (int j = 1; j <= 3; j++) {
status = ClassInterface_.Function3(...);
...
}
}
}
**Test Code:**
TEST(Test, TestName) {
InSequence s;
for (int num = 1; num < 3; ++num) {
EXPECT_CALL(*(mockClassInterface_.get()), Function1(_))
.WillOnce(Return(true));
EXPECT_CALL(*(mockClassInterface_.get()), Function2(_, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(*(mockClassInterface_.get()), Function3(_, _, _, _))
.WillRepeatedly(Return(true));
}
ClassAdd* test1 = new ClassAdd();
ASSERT_TRUE(test1->Display(3));
}
I know why it is not working. It expects Function1 followed by Function2 and Function3. But in the next iteration, EXPECT_CALL is not being called and returns false by default. Hence, the test is failing. Here is the error I see when I run:
tried expectation #0: EXPECT_CALL(*(mockClassInterface_.get()), Function1(_))
Expected: the expectation is active
Actual: it is retired
Expected: to be called any number of times
Actual: never called - satisfied and retired
Any tips on how to achieve this?
I suggest you read this link, especially the section "Using Mocks in Tests"
From what I understand of your pseudo-code, you have a Display function that calls Function1, Function2 and Function3 a certain amount of time.
To test that these functions are correctly called, and to add a return value, you should rather use the "Times" function.
For instance:
EXPECT_CALL(*(mockClassInterface_.get()), Function1(_)).Times(3).WillRepeatedly(Return(true));
This call means "I want the Function1 function to be called 3 times with any parameter, and it shall always return true".
Also note that by using Times, you don't need to use a for loop to define your EXPECT_CALL expectations.
Related
Is there any ASSERT_AND_RETURN macro in Google Test that tests something, and if it is false, raises an assertion and returns a value?
Actually every ASSERT_XXX returns from function - but it does not return value - it is assumed that the function (in most cases functions created by TESTxx macros) are void function.
This is sometimes issue when you use ASSERT_XXX within function called from another function. To check if function failed on assert - you need to use ASSERT_NO_FATAL_FAILURE.
See example
void assertNotNull(int *p)
{
ASSERT_THAT(p, NotNull(p));
}
void assertSizeIs(int actual, int expected)
{
ASSERT_EQ(actual, expected);
}
TEST(A, B)
{
std::pair<int*,int> p = createArray(7);
ASSERT_NO_FATAL_FAILURE(assertNotNull(p.first));
ASSERT_NO_FATAL_FAILURE(assertSizeIs(p.second, 7));
for( int i = 0; i < 7; ++i)
ASSERT_EQ(0, p.first[i]);
}
I am using this method in a Cocos2d X game.
void OpponentNode::discard(int cardNum)
{
log("\nOpponentNode::discard <%d>\n", cardNum);
for (int i = 0; i < vecOpponentHand.size(); i++)
{
if (vecOpponentHand.at(i) == cardNum)
{
vecOpponentHand.erase(vecOpponentHand.begin() + i);
break;
}
}
CardSprite * discardedCard;
for (int i = 0; i < vecOpponentCards.size(); i++)
{
if (vecOpponentCards.at(i)->getTag() == cardNum)
{
discardedCard = vecOpponentCards.at(i);
vecOpponentCards.erase(vecOpponentCards.begin() + i);
break;
}
}
log("\nOpponentNode::discard <%d>\n", cardNum);
discardedCard->makeFaceUp();
RotateTo * rotate = RotateTo::create(0.4 * SPEED_MULTIPLIER, 0);
MoveTo * move = MoveTo::create(0.4 * SPEED_MULTIPLIER,
origin + Vec2(visibleSize.width * 0.75, visibleSize.height * 0.6));
Spawn * spawn = Spawn::create(rotate, move, NULL);
CallFunc * callFunc = CallFunc::create(
[&]()
{
log("\nOpponentNode::discard <%d>\n", cardNum); //this one shows garbage/different value
if (delegate)
{
delegate->opponentNodeDidFinishDiscard(this, cardNum);
}
this->removeChild(discardedCard);
});
discardedCard->runAction(Sequence::create(spawn, callFunc, NULL));
log("\nOpponentNode::discard <%d>\n", cardNum);
}
Strangely, when I log the integer cardNum like above, I get different value from the log inside the lambda function. For example, I get "OpponentNode::discard <402>" from the top 2 logs and the bottom most log but get "OpponentNode::discard <64>" from the log inside the lambda function.
Other points:
The lambda block is executed last.
I mostly get values like 64 or garbage values like -15493456.
My guess is the integer cardNum is getting deallocated before the execution. Can anyone point me to the right direction?
You're capturing a reference to the cardNum parameter. I would think you want to capture that one by value.
It's not clear to me what delegate is. Assuming it's a class member then I think you just need [this, discardedCard, cardNum]. Which you could abbreviate to just [=], although I think the explicit one is clearer.
Strange tests behaviour.
I have class that generate random values.
std::random_device RandomProvider::rd;
std::mt19937 RandomProvider::rnb(RandomProvider::rd());
#define mainDataType unsigned int
mainDataType RandomProvider::GetNextValue(mainDataType upperLimit)
{
static std::uniform_int_distribution<int> uniform_dist(1, upperLimit);
return uniform_dist(rnb);
}
And unit-test that test it's behavior.
TEST_METHOD(TestRandomNumber)
{
CreateOper(RandomNumber);
int one = 0, two = 0, three = 0, unlim = 0;
const int cycles = 10000;
for (int i = 0; i < cycles; i++)
{
mainDataType res = RandomProvider::GetNextValue(3);
if (res == 1) one++;
if (res == 2) two++;
if (res == 3) three++;
}
double onePerc = one / (double)cycles;
double twoPerc = two / (double)cycles;
double threePerc = three / (double)cycles;
Assert::IsTrue(onePerc > 0.20 && onePerc < 0.40);
Assert::IsTrue(twoPerc > 0.20 && twoPerc < 0.40);
Assert::IsTrue(threePerc > 0.20 && threePerc < 0.40);
}
Test passed all-times in debug and if i chose it and Run only it. But it fails all times when i
run it with other tests. I added debug output to text file and got unreal values onePerc = 0.0556, twoPerc= 0.0474 and threePerc = 0.0526... What is going on here? (i am using VS2013 RC)
Since you use a static uniform_int_distribution the first time you call GetNextValue the max limit is set, never being changed in any subsequent call. Presumably in the test case you mentioned, your first call to GetNextValue had a different value than 3. Judging from the values returned it looks like probably either 19 or 20 was used in the first such call.
I am receiving the following error:
error: expected constructor, destructor, or type conversion before ‘(’ token
Here is the source code that I have written:
void setup() {
pinMode(1,OUTPUT);
[...]
pinMode(13,INPUT);
}
int i = 1;
bool pushed = digitalRead(13);
bool val = 0;
randomSeed(analogRead(0));
void loop() {
if (pushed == 1) {
for (i = 1; i < 9; i++) {
val = random(2);
digitalWrite(i,val);
}
}
}
The variables and the setup are OK; the error is located on the for line. Can anyone tell me how to fix this?
(edit : added the begining of the script, and sorry for the presentation (first question here)
(edit : looks like the error is not in the "i" definition. I'm using an Arduino UNO SMD Edition, if that helps (and the arduino alpha 0022 linux version of the IDE) )
EDIT: okay guys, solved now. It appears that my version of Arduino IDE was not completely downloaded, and that I put the randomSeed in the wrong place (it should be in the setup function.) (when i did put it in the setup function before updating, it shown an error message, saying /opt/arduino/lib/math.h was missing something (or something like that, i don't have the full message) ). Thanks for your help and i hope i'll be able to help you in arduino soon!
for (int i = 1; i < 9; i++)
is valid in C99/C11 but not valid in C89.
If you use a C89 compiler you have to define i outside the for loop clauses:
int i;
for (i = 1; i < 9; i++)
Also in C89, all declarations have to follow the left brace of a block, you cannot freely mix declarations and statements.
You appear to have a statement randomSeed(analogRead(0)); floating in between your setup() and loop() function definitions.
Move it and any other IO operations to the end of the setup() function so you read after setting up the pin directions:
int i = 1;
bool pushed;
bool val = 0;
void setup() {
pinMode(1,OUTPUT);
[...]
pinMode(13,INPUT);
pushed = digitalRead(13);
randomSeed(analogRead(0));
}
void loop() {
if (pushed == 1) {
for (i = 1; i < 9; i++) {
val = random(2);
digitalWrite(i,val);
}
}
}
That will reading the value of pin 13 into pushed only once ( e.g. you are holding a button when powering it on ); depending what you want it to do you may want to move the read to the start of loop() so writes random values whenever the button is pressed.
In C (previous to C99), it's not permissible to define a new variable in the first expression of a for loop. Try declaring your variable i at the top of the function instead.
#define pinMode1 1
#define pinMode2 13
bool pushed;
bool val = 0;
void setup() {
// Declare OUTPUT pin.
pinMode(pinMode1, OUTPUT);
// Declare INPUT pin.
pinMode(pinMode2, INPUT);
// Set digitalRead().
pushed = digitalRead(pinMode2);
// Initializes the pseudo-random number generator.
randomSeed(analogRead(0));
}
void loop() {
if (pushed == 1) {
for (int i = 1; i < 9; i++) {
val = random(2);
// Set i to HIGH or LOW.
digitalWrite(i, val);
}
}
}
I've written a simple, though highly multi-threaded, prime numbers generator.
The algorithm goes like this:
Thread 0: generates consecutive numbers.
Threads 1 .. N: filter out numbers that are not prime.
Upon each 'new' prime discovery, a new filter thread is added.
Take I: no flow control at all.
Thread 0 'send's numbers absolutely freely.
The program finishes with signal 11 (seg. fault), rarely signal 8, even more rarely finishes successfully.
Take II: flow control with 'setMaxMailboxSize' to 1.
Most of the time, everything works well.
Take III:
Now, if it all was a result of some internal unheld overflow, it should do well with 'setMaxMailboxSize' to 2 (or even 10), am I wrong ?
Thread 0 becomes stuck after it blocks for the first time.
Could someone please direct me what do I miss ?
Note 1:
I use DMD v2.053 under Ubuntu 10.04
Note 2:
This is my code:
#!/usr/bin/dmd -run
import std.stdio;
import std.conv;
import std.concurrency;
void main(string[] args)
{
/* parse command line arguments */
if (args.length < 2) {
writeln("Usage: prime <number of primes to generate>");
return;
}
auto nPrimes = to!int(args[1]);
auto tid = spawn(&generate, thisTid);
/* gather produced primes */
for (;;) {
auto prime = receiveOnly!int();
writeln(prime);
if (--nPrimes <= 0) {
break;
}
}
tid.send("stop");
}
void generate(Tid parentTid)
{
bool terminate = false;
// filter stage 1
auto tid = spawn(&filter_stage, parentTid);
/* WHAT DO I MISS HERE ? */
setMaxMailboxSize(tid, 1, OnCrowding.block);
for (int i = 2; !terminate; i++) {
receiveTimeout(0,
(string cmd) {
writeln(cmd);
terminate = true;
}
);
tid.send(i);
}
}
void filter_stage(Tid parentTid)
{
auto prime = receiveOnly!int();
parentTid.send(prime);
// filter stage 'N'
auto tid = spawn(&filter_stage, parentTid);
filter(prime, tid);
}
void filter(int prime, Tid tid)
{
for (;;) {
receive (
(int number) {
if (number % prime != 0) {
tid.send(number);
}
}
);
}
}
Sounds like a bug in std.concurrency. Try upgrading DMD to 2.055. I'm not sure if this specific bug is fixed but there are a lot of bug fixes between 2.053 and 2.055. If it's still broken then please file a bug report at http://d.puremagic.com/issues/.