chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
Hi,

I’m trying to fake a class which has CString as a variable.

When I fake it, the fake object initializes all the variables except the CString. It shows the CString as a <Bad ptr> and hence whenever I try to call methods of that class which uses that CString variable ,an exception is caused.

Here is the code snippet:

Mysampleclass.h file

#if _MSC_VER > 1000
#pragma once
#endif

class ravisample
{
public:
ravisample(void);
~ravisample(void);

public:
int GetValue();

private:
int a;
string CheckString;
CString CheckCString;
};

MyTestFile.cpp
#include "stdafx.h"
#include "gtest/gtest.h"
#include <Isolator.h>
#include "ravisample.h"

class ChangeReturnValue : public ::testing::Test
{
public:
void SetUp()
{
}

void TearDown()
{
//ISOLATOR_CLEANUP();
}
};

TEST_F(ChangeReturnValue,SampleTestClassForCheck)
{
ravisample *fakeravisample=FAKE<ravisample>();

//WHEN_CALLED(fakeravisample->GetValue()).ReturnVal(1);

ASSERT_TRUE(2 == fakeravisample->GetValue());
}

Thanks in advance!!
Regards,
Ravi
asked by manneni392 (1.3k points)

7 Answers

0 votes
Hi,

Isolator initializes the fake object fields to zero
<Bad ptr> is just the way the debugger represents an initialized CString.

If you debug the next example:

struct Data
{
   int x;
   int* p;
   CString s;
};

void main()
{
   int n = 5;
   Data d;
   d.x = 1;
   d.p = &n;

   memset(&d, 0, sizeof(Data));   // break point here

}


You will see the same behavior on CString in the debugger.
answered by alex (17k points)
0 votes
Hi ,

I'm still skeptical about this because when i try to assign the CString some value it gives an exception but in the same case if i try to assign the string variable(also part of the same class) it doesnt give any exception .

I'll post the code may be that will clarify the issue i'm facing.

ravisample.h


#if _MSC_VER > 1000
#pragma once
#endif

class ravisample
{
public:
ravisample(void);
~ravisample(void);

public:
void SetValue(LPCSTR name);
LPCSTR GetValue();
void SetStringValue(string name2);
string GetStringValue();

private:
string CheckString;
CString CheckCString;
};

ravisample.cpp
#include "stdafx.h"
#include "ravisample.h"

ravisample::ravisample(void)
{
}

ravisample::~ravisample(void)
{
}

void ravisample::SetValue(LPCSTR name)
{
CheckCString = name;
}

LPCSTR ravisample::GetValue()
{
return CheckCString;
}

void ravisample::SetStringValue(std::string name2)
{
CheckString=name2;
}

string ravisample::GetStringValue()
{
return CheckString;
}

Mytest.cpp

#include "stdafx.h"
#include "gtest/gtest.h"
#include <Isolator.h>
#include "String.h"
#include "ravisample.h"

class ChangeReturnValue : public ::testing::Test
{
public:
void SetUp()
{
}

void TearDown()
{
ISOLATOR_CLEANUP();
}
};

TEST_F(ChangeReturnValue,SampleTestClassForCheck)
{
ravisample *fakeravisample=FAKE<ravisample>();

string temp="ravi";

LPCSTR temp2 = temp.c_str();

WHEN_CALLED(fakeravisample->SetValue(temp2)).CallOriginal();

WHEN_CALLED(fakeravisample->SetStringValue(temp)).CallOriginal();

fakeravisample->SetStringValue(temp); //this doesn't cause an error

ASSERT_TRUE(temp == fakeravisample->GetStringValue());

fakeravisample->SetValue(temp2); //this causes an exception as its trying to assign a value to the CString variable

ASSERT_TRUE(temp2 == fakeravisample->GetValue());
}
answered by manneni392 (1.3k points)
0 votes
This is the exception that is displayed in the command prompt

Unknown file : SEH exception with code 0xc0000005 trown in test body
answered by manneni392 (1.3k points)
0 votes
Hi

The reason for this behavior is that the underline implementation is different between CString and std::string.
Try to run the code below:
string str;
memset (&str, 0, sizeof(string)); // the Isolator zeros the returned fake instance
str = "abc";

CString mstr;
memset (&mstr, 0, sizeof(CString));
mstr = "abc";


My guess is that in std:string the buffer that holds the string is defined as array:
char buf[1024];
While CString buffer is defined as a pointer:
char* buf;
When you set the std:string instance to zero you still have a valid pointer to buffer with zero length string which is legal detestation for a string.
CString instance has a null pointer to string which in result gives you the access violation exception.

Example:
// like std:string 
class A
{
public:
   char buf[1024];
};

// like CString
class B
{
public:
   char *buf;
};

// main
A a;
memset (&a, 0, sizeof(A));
B b;
memset(&b, 0, sizeof(B));

strcpy (a.buf, "abc");  // <== ok
strcpy (b.buf, "abc");  // <== access violation exception


That been said we are looking for a solution or at least workaround for this problem.
I'll update you as soon as will have something.
answered by ohad (35.4k points)
0 votes
Hi Ravi,

Looking closely at the test, it seems like you are trying to use partial fake. Partial fake means that you are using the original implementation on faked instance.
This usually leads to errors when the test runs.

In your case it seems like the best solution is to fake a method that returns the fake value.
So your test will be something like this:
// in ravisample class
CString GetCString()
{
   return CheckCStr
}

// in test code
ravisample *fakeravisample = FAKE<ravisample>();
CString s("ravi");
WHEN_CALLED(fakeravisample->GetCString()).ReturnPtr(&s);


Please let me know if it helps.
answered by ohad (35.4k points)
0 votes
Hi ohad,
Thanks for the reply.

But that doesn't actually solve my problem
class Test
{
CString str;
void CreateCString(some arg)
{
//Based on args some logic here to create the string
CString str = something;////basically its like a setter function
}
}



How should i test this method or How should i test the CString that is created in the above method??

Regards,
Ravi
answered by manneni392 (1.3k points)
0 votes
Hi Ravi,

Usually you don't want to fake the class that you want to test, instead you should fake the class dependencies.
In the case that you posted I see no reason to fake the class.
In the test that you posted I can see that you called the original implementation of the class methods.
Is there any reason to fake the class in this case?

There are non trivial cases where you want to fake the class and call its original implementation. In those cases I guess that what is missing here from the Isolator API is the ability to call the original implementation of the constructor.
answered by ohad (35.4k points)
...