I'm trying to compare two lists of pointers via googletest, and everytime I do that my test stops running at that test block. it doesn't give me an error or something, just stops.
here is my code:
TEST_F(WorkerTest, checkCtor)
{
Worker oved(m_id,m_job,m);
EXPECT_EQ(oved.getId(),m_id);
EXPECT_TRUE(m_job == oved.getJob() );
EXPECT_TRUE(m == oved.getMoviesOfWorker()); //PROBLEMATIC LINE
}
here is my code for getMoviesOfWorker:
list<Movie*> Worker::getMoviesOfWorker(){
std::list<Movie*> m;
return m;
}
my constructor of Worker looks like this:
Worker(int m_id, std::string m_job, std::list<Movie*> moviesToWorker){};
and my WorkerTest class looks like this:
#include "gtest/gtest.h"
#include "Worker.h"
#include <list>
class WorkerTest : public ::testing::Test {
protected:
int sizeBefore;
std::list<Movie*> m;
std::string m_job;
int m_id;
virtual void SetUp(){};
virtual void TearDown(){};
public:
WorkerTest() : sizeBefore(), m(), m_id(), m_job(){}
};
I don't understand in general why would googleTest stop, and btw I don't have implementation for any of my functions (getId or getJob), and even when I do return some list in getMoviesOfWorker() it still crashes.. HELP?
Related
I am trying to implement 2 or more classes that are going to use the same shared memory through a wrapper class as a dependency.
My doubt: Can shared pointer substitute Singleton ?
Note: I am trying to avoid Singleton for unit-test purpose.
Below is sample code for reference. Is this implementation fine or violates any C++ Principles?
IShmWrapper.h
#pragma once
class IShmWrapper
{
public:
virtual bool writeToSharedMemory() = 0;
virtual bool readFromSharedMemory() = 0;
};
ShmWrapper.h
#include "IShmWrapper.h"
class ShmWrapper : public IShmWrapper
{
public:
bool writeToSharedMemory() override; //Write operation on shared memory
bool readFromSharedMemory() override;//Read operation on shared memory
};
ShmWrapper.cpp
#include "ShmWrapper.h"
bool ShmWrapper::writeToSharedMemory()
{
//Write operation on shared memory
}
bool ShmWrapper::readFromSharedMemory()
{
//Read operation on shared memory
}
ShmUserA.h
#include "IShmWrapper.h"
#include <memory>
class ShmUserA
{
private:
std::shared_ptr<IShmWrapper> m_shmWrapperA;
public:
ShmUserA(std::shared_ptr<IShmWrapper> shmWrapper);
};
ShmUserA.cpp
#include "ShmUserA.h"
ShmUserA::ShmUserA(std::shared_ptr<IShmWrapper> shmWrapper)
: m_shmWrapperA(std::move(shmWrapper))
{
// Do Additional initialization
}
ShmUserB.h
#include "IShmWrapper.h"
#include <memory>
class ShmUserB
{
private:
std::shared_ptr<IShmWrapper> m_shmWrapperB;
public:
ShmUserB(std::shared_ptr<IShmWrapper> shmWrapper);
};
ShmUserB.cpp
#include "ShmUserB.h"
ShmUserB::ShmUserB(std::shared_ptr<IShmWrapper> shmWrapper)
: m_shmWrapperB(std::move(shmWrapper))
{
// Do Additional initialization
}
Main.cpp
#include<iostream>
#include<IShmWrapper.h>
#include<ShmWrapper.h>
#include<ShmUserA.h>
#include<ShmUserB.h>
int main()
{
std::shared_ptr<IShmWrapper> shmInstance = std::make_shared<ShmWrapper>();
std::unique_ptr<ShmUserA> shmUserA = std::make_unique<ShmUserA>(shmInstance);
std::unique_ptr<ShmUserB> shmUserB = std::make_unique<ShmUserB>(shmInstance);
while(1)
{
//Do Processing of data for incoming requests
}
return 0;
}
I've got a base class Container with a derived class Player_Inventory. There can only be one Player_Inventory so my code throws an exception if for some reason a second one is created.
The problem I'm having is that my code is failing my test as it throws the exception even on what is supposed to be the very first construction of the Player_Inventory class. I've debugged the code and two things are happening which I don't quite understand - the number attribute is not tracked by the debugger (at least not in the GUI on VSC), and it seems that right after hitting the first REQUIRE statement, the constructor is called again, thus triggering the exception.
Can anyone help?
After rewriting my constructor method, I'm still getting a similar error.
My revised code is as follows:
containers.h
#include<iostream>
#include<string>
#include<vector>
class Item { // Placeholder class for items
public:
std::string name;
Item(std::string n) : name{n} {};
};
class Container {
protected:
std::string name;
std::string description;
std::vector<Item> contents;
public:
Container(std::string, std::string);
std::string get_name() {return name;}
std::string get_description() {return description;}
std::vector<Item> get_contents() {return contents;}
};
containers.cpp (there are more methods defined in this file which aren't used here)
#include<iostream>
#include<string>
#include "containers.h"
Container::Container(std::string n, std::string desc) : name{n}, description{desc} {};
player_inventory.h
#include "containers.h"
class Player_Inventory : public Container {
public:
static int number;
Player_Inventory(std::string, std::string);
};
player_inventory.cpp
#include<iostream>
#include<stdexcept>
#include "player_inventory.h"
Player_Inventory::Player_Inventory(std::string n, std::string desc): Container(n, desc) {
number += 1;
if (number > 1){
throw std::invalid_argument("You can only have one inventory!");
}
};
int Player_Inventory::number = 0;
test_file.cpp
#include "../lib/Catch2/catch.hpp"
#include "player_inventory.h"
#include<iostream>
#include<string>
#include<vector>
SCENARIO("A player can have an inventory.") {
WHEN("A player inventory is created.") {
Player_Inventory myInventory("My Inventory", "Inventory for the player");
THEN("The created inventory has the correct attribute values.") {
REQUIRE(myInventory.get_name() == "My Inventory");
REQUIRE(myInventory.get_description() == "Inventory for the player");
REQUIRE(myInventory.get_contents().empty());
} // The code works fine when only up to here is included
AND_THEN("Only one player inventory can exist.") { // as soon as this line is included it tries to create another player_inventory object, causing the fail
REQUIRE_THROWS((Player_Inventory myOtherInventory("Second Inventory", "Testing for another one"))); // These two lines were not included but I've included them here as this is the test I wanted to run
REQUIRE(myInventory.get_number() == 1);
}
}
}
Not sure if related, but that's how you should call the Base constructor:
Player_Inventory(std::string n, std::string desc) : Container(n, desc) {
}
Given the following example
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdint.h>
using namespace ::testing;
class Tested
{
public:
virtual void setArray(const uint32_t[3]) {};
};
class Tested_mock: public Tested
{
public:
MOCK_METHOD1(setArray, void(const uint32_t[3]));
};
class TestRunner: public ::testing::Test
{
public:
StrictMock<Tested_mock> t;
};
TEST_F(TestRunner, test)
{
uint32_t a[3] = {1UL, 2UL, 3UL};
EXPECT_CALL(t, setArray(_)).With(ElementsAreArray(a));
t.setArray(a);
}
i don't understand why i'm not able to compile this snippet while changing the argument to uint32_t* works. Does Gmock have a problem with fixed-size-array arguments ?
You could find the compilation output here https://pastebin.com/72b4iYqs
Late to party but I had the same issue.
The problem is that the testing framework also wants to know the size of the actual array to check if it's the same as expected.
In the end I ended up defining my own Matcher that takes the size as an argument:
MATCHER_P2(FixedSizeArrayMatches, expected, elements, "")
{
return memcmp(arg, expected, elements * sizeof(expected[0])) == 0;
}
This can then be used like this:
EXPECT_CALL(t, setArray(FixedSizeArrayMatches(a, 3));
I am implementing a Visitor class in C++ that generates XML output for a parse tree.
When I compile with Clion on Windows the code compiles but when it runs after it outputs what is expected it crashes. The error code is this
Process finished with exit code -1073741819 (0xC0000005)
When I try to compile using gcc (without Clion) I get the error message
Undefined Reference to 'vtable for PrintXMLVisitor'.
My code is the following. I have distilled it down to the least amount the produces the error
ASTNode.h
#ifndef MINILANG_ASTNODE_H
#define MINILANG_ASTNODE_H
#include <memory>
class Visitor;
class ASTNode {
public:
virtual void accept(std::shared_ptr<Visitor> visitor) = 0;
};
#endif //MINILANG_ASTNODE_H
ASTTypeNode.h
#ifndef MINILANG_ASTTYPENODE_H
#define MINILANG_ASTTYPENODE_H
#include "ASTNode.h"
class ASTTypeNode: public ASTNode {
public:
enum Type {Real, Int, Bool, String};
ASTTypeNode(Type type);
Type getType() const;
void accept(std::shared_ptr<Visitor> visitor) override;
private:
Type type;
};
#endif //MINILANG_ASTTYPENODE_H
ASTTypeNode.cpp
#include "ASTTypeNode.h"
#include "Visitor.h"
ASTTypeNode::ASTTypeNode(ASTTypeNode::Type type)
: type(type)
{
}
ASTTypeNode::Type ASTTypeNode::getType() const {
return type;
}
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) {
visitor->visit(std::shared_ptr<ASTTypeNode>(this));
}
Visitor.h
#ifndef MINILANG_VISITOR_H
#define MINILANG_VISITOR_H
#include <memory>
#include "ASTTypeNode.h"
class Visitor {
public:
virtual void visit(std::shared_ptr<ASTTypeNode> typeNode) = 0;
};
#endif //MINILANG_VISITOR_H
PrintXMLVisitor.h
#ifndef MINILANG_PRINTXMLVISITOR_H
#define MINILANG_PRINTXMLVISITOR_H
#include "Visitor.h"
class PrintXMLVisitor: public Visitor {
public:
void visit(std::shared_ptr<ASTTypeNode> typeNode) override;
};
#endif //MINILANG_PRINTXMLVISITOR_H
PrintXMLVisitor.cpp
#include "PrintXMLVisitor.h"
#include <iostream>
void PrintXMLVisitor::visit(std::shared_ptr<ASTTypeNode> typeNode) {
std::string typeName;
switch(typeNode->getType())
{
case ASTTypeNode::Type::Real:
typeName = "Real";
break;
case ASTTypeNode::Type::Int:
typeName = "Int";
break;
case ASTTypeNode::Type::Bool:
typeName = "Bool";
break;
case ASTTypeNode::Type::String:
typeName = "String";
break;
default:
typeName = "Error";
exit(22);
}
std::cout << "<TypeNode>" << typeName << "</TypeNode>" << std:: endl;
}
main.cpp
#include <iostream>
#include "Lexer.h"
#include "ASTTypeNode.h"
#include "PrintXMLVisitor.h"
int main() {
ASTTypeNode astTypeNode (ASTTypeNode::Type::Int);
astTypeNode.accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
Your crafting a shared pointer that isn't dynamic. Specifically,
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) {
visitor->visit(std::shared_ptr<ASTTypeNode>(this)); // <=== HERE
}
The this in that statement refers to:
int main()
{
ASTTypeNode astTypeNode (ASTTypeNode::Type::Int); // <== this object
astTypeNode.accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
Changing toolchains isn't going to fix this problem you have options, the two most obvious being:
Stop using a std::shared_ptr for the visit parameter.
Manage all ASTNodeType instances a requiring being std::shared_ptr managed and share from this using the std:enable_shared_from_this capabilities of the standard library.
The former of these is obvious (or at least it is now), so I'll not discuss it further. The latter is not necessarily trivial, as it mandates any instances of your underlying class that utilize shared_from_this must be managed by std::shared_ptr wrappers. I.e., there are no concrete constructions like you're currently doing in main(). This could have significant impact on your overall code base, so choose this carefully.
An example of how the above would work in your case:
First, change the derivation chain of ASTNodeType to look like this:
class ASTTypeNode
: public ASTNode
, public std::enable_shared_from_this<ASTTypeNode> // ADDED
Next, utilize shared_from_this as follows:
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor)
{
visitor->visit(shared_from_this()); // HERE
}
And finally, honor the warrant you've made that ASTNodeType instances are shared-ptr managed by doing this:
int main()
{
std::shared_ptr<ASTTypeNode> astTypeNode = std::make_shared<ASTTypeNode>(ASTTypeNode::Type::Int);
astTypeNode->accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
That should work. Read more about the things used in the above code here:
std::enable_shared_from_this
std::enable_shared_from_this::shared_from_this
As I said, all of this is to facilitate using a std::shared_ptr from an object given only a this pointer. If you can remove that requirement in the first place, it may be an easier path to take, and I would consider that first.
I am aware that there is quite a few topics around this, but I just can't figure it out.
I am working for a Signal driven input manager for my game and since I need to control multiple players, I need to connect a member function of a PlayerController instance to my vector of signals.
Problem is, that there is not only going to be a PlayerController, but also a MenuController etc. So I will need to connect a member function of a MenuController to the signal aswell.
I am pretty sure I am close to the solution, but I just can't seem to figure it out.
Can someone help me with the registerEvent function signature and how to call the connect method.
InputManager.tcc
#include "boost/function.hpp"
template<class T>
void InputManager::registerEvent(SDL_Keycode key,KeyState state,boost::function<void ()> const& function)
{
auto &inputEvents = (state == KeyState::Up) ? m_keyUpEvents : m_keyDownEvents;
if(inputEvents.find(key) == inputEvents.end())
{
inputEvents.insert(std::make_pair(key, boost::signals2::signal<void()>()));
m_keyStates[key] = KeyState::Up;
}
inputEvents[key].connect(boost::bind(T::function, instance));
}
InputManager.hpp:
#ifndef SSB_INPUTMANAGER_HPP
#define SSB_INPUTMANAGER_HPP
#include <functional>
#include <algorithm>
#include <vector>
#include <map>
#include <SDL_keycode.h>
#include <SDL_events.h>
#include <boost/signals2.hpp>
enum KeyState{
Down,
Up
};
class InputManager
{
public:
InputManager();
template<class T>
void registerEvent(SDL_Keycode key,KeyState state, boost::function<void ()> const& function);
void pollEvent(SDL_Event event);
private:
std::map<SDL_Keycode, boost::signals2::signal<void ()>> m_keyDownEvents;
std::map<SDL_Keycode, boost::signals2::signal<void ()>> m_keyUpEvents;
std::map<SDL_Keycode, KeyState> m_keyStates;
};
#include "InputManager.tcc"
#endif //SSB_INPUTMANAGER_HPP
PlayerController.hpp
#ifndef SSB_PLAYERCONTROLLER_HPP
#define SSB_PLAYERCONTROLLER_HPP
class PlayerController
{
public:
void jump();
private:
Player m_player;
};
#endif //SSB_PLAYERCONTROLLER_HPP
Then I want to call in an initialization method somewhere in my game:
PlayerController playerController;
InputManager inputController;
inputController.registerEvent(SDLK_0, KeyState::Down, playerController.jump());
Both boost::function<> and std::function<> already do type erasure. This means that they "abstract" away any bound parameters.
The this* argument is really just that: a parameter. So, the same goes for it.
Live On Coliru (c++11)
#include <boost/function.hpp>
#include <boost/signals2.hpp>
#include <map>
#include <iostream>
enum SDL_Keycode { K_A, K_B, K_C, K_Up, K_Down, K_Right, K_Left, K_LCtrl, /*etc....*/ };
enum KeyState { Down, Up };
struct InputManager {
void registerEvent(SDL_Keycode key, KeyState state, boost::function<void()> const &function) {
auto& map = state == Up? m_keyUpEvents : m_keyDownEvents;
map[key].connect(function);
}
void poll_event() {
// hardcoded for demo
m_keyDownEvents[K_B]();
}
private:
std::map<SDL_Keycode, boost::signals2::signal<void()>> m_keyDownEvents;
std::map<SDL_Keycode, boost::signals2::signal<void()>> m_keyUpEvents;
std::map<SDL_Keycode, KeyState> m_keyStates;
};
struct Player {};
class PlayerController {
public:
void jump() {
std::cout << "Player jumped\n";
}
private:
Player m_player;
};
class CowController {
public:
void moo() {
std::cout << "Cow mooed\n";
}
};
int main() {
InputManager inputController;
PlayerController p;
inputController.poll_event(); // nothing
inputController.registerEvent(K_B, Down, [&] { p.jump(); });
inputController.poll_event(); // player jumps
CowController c;
inputController.registerEvent(K_B, Down, [&] { c.moo(); });
inputController.poll_event(); // player jumps, cow moos
}
Prints
Player jumped
Player jumped
Cow mooed
C++03
If you don't have lambdas, you can use Boost Bind (or std::tr1::bind):
inputController.registerEvent(K_B, Down, boost::bind(&PlayerController::jump, boost::ref(p)));
inputController.poll_event(); // player jumps
CowController c;
inputController.registerEvent(K_B, Down, boost::bind(&CowController::moo, boost::ref(c)));
See it Live On Coliru