I want to mock a function which has a pointer argument
class I_Shaft
{
public:
virtual ~I_Shaft() {
}
virtual void GetFloor(I_Floor* FloorPointer) = 0;
};
the mocked interface:
class Mock_I_Shaft : public I_Shaft
{
public:
MOCK_METHOD1(GetFloor, void(I_Floor* FloorPointer));
};
the mocked interface Mock_I_Floor which needs a default and a copy constructor (otherwise it won't get compiled):
class Mock_I_Floor : public I_Floor
{
public:
Mock_I_Floor() {}
Mock_I_Floor(const Mock_I_Floor& f) {}
virtual ~Mock_I_Floor() {};
MOCK_METHOD0(GetPosition, uint16_t());
};
the implementation that is to be tested:
C_HZS::C_HZS(I_Shaft& refShaft) : //constructor initializing refShaft
refShaft(refShaft)
{
}
void C_HZS::run(void)
{
I_Floor* ptrFloor = NULL;
refShaft.GetFloor(ptrFloor);
if(ptrFloor == NULL){
std::cerr << "there is no valid pointer" <<std::endl;
return;
}
floorPosition = ptrFloor->GetPosition();
std::cout << "floorPosition: " << floorPosition << std::endl;
}
and here is my test:
TEST(HZS, testFloorPosition) {
Mock_I_Shaft shaft;
Mock_I_Floor floor;
Mock_I_Floor* pFloorMocked= &floor;
C_HZS dutObj(shaft);
EXPECT_CALL(shaft, GetFloor(_))
.Times(AtLeast(1))
.WillOnce(SetArgPointee<0>(*pFloorMocked)
);
dutObj.run();
EXPECT_FALSE(...);
}
The problem is: I am not able to inject pFloorMocked into the mocked function. Within the run() function ptrFloor always stays NULL. What is the reason for this? Is there another way to mock this function?
Related
Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};
I'm trying to move playerSpaceShip by keyboard. The function is changing its position (checked in the console by getcoordinates()) but it's not displaying it on the screen(sprite is not moving). Anyone can figure out why?
player.cpp
void player::movePlayer(sf::Vector2f distance)
{
playerSpaceShipSprite.move(playerMoveSpeed * distance.x, playerMoveSpeed * distance.y);
}
void player::render(sf::RenderTarget* target)
{
target->draw(playerSpaceShipSprite);
}
game.cpp
void game::update()
{
while (window->isOpen())
{
while (window->pollEvent(sfEvent))
{
if (sfEvent.type == sf::Event::Closed)
window->close();
playerMovement(sfEvent);
}
}
}
void game::renderPlayer()
{
if (Player)
Player->render(window);
}
void game::render()
{
window->clear();
renderBackground();
renderPlayer();
renderBlueAlien();
window->display();
}
void game::playerMovement(sf::Event sfEvent)
{
if (sfEvent.type == sf::Event::EventType::KeyPressed)
{
switch (sfEvent.key.code)
{
case sf::Keyboard::Left:
{
Player->movePlayer(sf::Vector2f(-1,0));
std::cout << "Left key pressed\n";
break;
}
case sf::Keyboard::Right:
{
Player->movePlayer(sf::Vector2f(1, 0));
std::cout << "Right key pressed\n";
break;
}
case sf::Keyboard::Up:
{
Player->movePlayer(sf::Vector2f(0, -1));
std::cout << "Up key pressed\n";
break;
}
case sf::Keyboard::Down:
{
Player->movePlayer(sf::Vector2f(0, 1));
std::cout << "Down key pressed\n";
break;
}
case sf::Keyboard::Space:
{
std::cout << "Space key pressed\n";
break;
}
}
}
}
void game::run()
{
while (window->isOpen())
{
render();
update();
}
}
void game::update() has while (window->isOpen()) at the start.
This means that the update function never returns back to void game::run(), where your second while (window->isOpen()) statement is, and since it never returns to there, void game::render() never gets called again.
The player is moving, but the screen is not updating to show the player moving. Getting rid of while (window->isOpen()) in void game::update() solves the problem.
I solved this using a debugger, setting a breakpoint inside void player::movePlayer(sf::Vector2f distance), and stepping through the code until I came across the problem.
I am using the below code to check the phone status(if phone is up or down). When phone is down sends an alarm. However this doesn't show when 8800 series phones are down. Is there any other method to check the Phone register/unregister status?
#Override public void terminalChangedEvent(TermEv[] eventList) {
if ( eventList != null ) {
for (TermEv eventList1 : eventList) {
if (eventList1 instanceof CiscoTermInServiceEv){
if(terminalInService.test()==true){
LogSQL.removeLog(terminal.getName());
}
System.out.println(terminal.getName());
terminalInService.set();
return;
} else if (eventList1 instanceof CiscoTermOutOfServiceEv &&
terminalInService.test()==true) {
offline();
}
}
}
}
Second Question, I was not able to find the methods or documentation about "com.cisco.cti.util.Condition" class. What does Condition.set() and Condition.test() methods do?
Looks like you have the right general idea - JTAPI should work fine for 88xx models, assuming you have the correct device->user association, and user permissions (Standard CTI Enabled, and Standard CTI Allow Control of Phones supporting Connected Xfer and conf needed for 88xx).
Here is my version working on CUCM 11.5:
package com.mycompany.app;
import com.cisco.jtapi.extensions.*;
import java.util.*;
import javax.telephony.*;
import javax.telephony.events.*;
import javax.telephony.callcontrol.*;
import javax.telephony.callcontrol.events.*;
import com.cisco.cti.util.Condition;
public class DataTerm implements ProviderObserver, TerminalObserver {
public static final int OUT_OF_SERVICE = 0;
public static final int IN_SERVICE = 1;
private Address destAddress;
private CiscoTerminal observedTerminal;
private boolean addressInService;
private boolean terminalInService;
protected int state = OUT_OF_SERVICE;
Condition conditionInService = new Condition();
Provider provider;
public DataTerm(String[] args) {
try {
System.out.println("Initializing Jtapi");
String providerName = "ds-ucm115-1.cisco.com";
String login = "dstaudt";
String passwd = "password";
String dest = "2999";
JtapiPeer peer = JtapiPeerFactory.getJtapiPeer(null);
String providerString = providerName + ";login=" + login + ";passwd=" + passwd;
System.out.println("Opening " + providerString + "...\n");
provider = peer.getProvider(providerString);
provider.addObserver(this);
conditionInService.waitTrue();
this.destAddress = provider.getAddress(dest);
this.observedTerminal = (CiscoTerminal) destAddress.getTerminals()[0];
try {
if (destAddress != null) {
System.out.println("Adding Terminal Observer to Terminal" + observedTerminal.getName());
observedTerminal.addObserver(this);
}
} catch (Exception e) {
}
} catch (Exception e) {
System.out.println("Caught exception " + e);
}
}
public void terminalChangedEvent(TermEv[] events) {
for (int i = 0; i < events.length; i++) {
Terminal terminal = events[i].getTerminal();
switch (events[i].getID()) {
case CiscoTermInServiceEv.ID:
System.out.println("Received " + events[i] + "for " + terminal.getName());
terminalInService = true;
break;
case CiscoTermOutOfServiceEv.ID:
System.out.println("Received " + events[i] + "for " + terminal.getName());
terminalInService = false;
if (state != OUT_OF_SERVICE) { // you only want to notify when you had notified earlier that you are IN_SERVICE
state = OUT_OF_SERVICE;
}
break;
}
}
}
public void providerChangedEvent(ProvEv[] eventList) {
if (eventList != null) {
for (int i = 0; i < eventList.length; i++) {
if (eventList[i] instanceof ProvInServiceEv) {
conditionInService.set();
}
}
}
}
}
The "com.cisco.cti.util.Condition" seems to be based on this pattern:
public interface Condition
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html
I am trying to override the default value of enum passed as a parameter, but I am getting the default value.
class MyClass
{
public:
enum MyCalculation
{
SUM,
DIVIDE,
MULTIPLY,
NOCALCULATION
};
void foo(MyCalculation cal = NOCALCULATION);
void DoCalculation();
};
void MyClass::DoCalculation()
{
MyCalculation cal;
// here I am getting the enum value at runtime
int val = // get enum value
switch(val)
{
case 0:
cal = MyClass::SUM;
break;
case 1:
cal = MyClass::DIVIDE;
break;
case 2:
cal = MyClass::MULTIPLY;
break;
}
foo(cal);
}
void MyClass::foo(MyCalculation getCal)
{
cout << getCal;
}
I tried passing by reference in DoCalculation method, but I am always getting NOCALCULATION in foo.
Do I need to do something else?
After searching all over and scratching my head a lot, I'm still not able to figure this out. haven't used smart pointers,vectors much before. Please help.
I'm trying to make deep copy of class A and i'm getting this error. the Error points to microsoft's xutility.cpp's "Template Function Copy" if this matters.
classA
{
public:
ClassA (const ClassA& origClassA)
{
ClassA::Copy(origClassA);
}
ClassA & ClassA ::operator=(const ClassA & origClassA )
{
if (this != &origClassA )
{
ClassA ::Clear();
ClassA ::Copy(origClassA );
}
return *this;
}
void ClassA ::Clear()
{
m_nId = 0;
m_pType = nullptr;
}
void ClassA ::Copy(const ClassA & fromClassA )
{
m_nId = fromClassA .m_nId;
if (fromClassA.m_pType)
{
if (!m_pType)
m_pType = std::make_unique<int>();
*m_pType = *fromClassA.m_pType;
}
}
private:
int m_nId;
std::unique_ptr<int> m_pType;
}
Class B
{
public:
ClassB(const ClassB& origClassB)
{
classB::Copy(origClassB);
}
classB& operator=(const classB& fromclassB)
{
if (this != &origClassA )
{
classB::Clear();
classB::Copy(origClassA );
}
return *this;
}
void classB::Clear()
{
m_vectorclassA.Clear();
}
void Copy(const classB& fromclassB)
{
m_vectorclassA = fromclassB.m_vectorclassA;
}
void SetVector(const std::vector<std::unique_ptr<classA>>& vectorclassA )
{
std::vector<std::unique_ptr<classA>>::const_iterator Iterator;
for (Iterator = vectorclassA.begin(); Iterator != vectorClassA.end(); Iterator++)
{
m_vectorclassA.push_back(std::make_unique<classA>(*(*Iterator)));
}
}
private:
std::vector<std::unique_ptr<classA>> m_vectorclassA;
}
m_vectorclassA = fromclassB.m_vectorclassA
Was the line causing the problem as pointed by user Igor Tandetnik