Skip to content

Commit

Permalink
Merge pull request #21 from rock-core/bugfixes_mock
Browse files Browse the repository at this point in the history
Bugfixes and improvements to the mock context
  • Loading branch information
alcantara09 authored Sep 1, 2017
2 parents d5c8bf8 + 4702837 commit 07ef979
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 17 deletions.
8 changes: 7 additions & 1 deletion src/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,16 @@ void Driver::openURI(std::string const& uri)
}
else if (mode_idx == 5)
{ // test://
setMainStream(new TestStream);
if (!dynamic_cast<TestStream*>(getMainStream()))
openTestMode();
}
}

void Driver::openTestMode()
{
setMainStream(new TestStream);
}

bool Driver::openSerial(std::string const& port, int baud_rate)
{
setFileDescriptor(Driver::openSerialIO(port, baud_rate));
Expand Down
16 changes: 16 additions & 0 deletions src/Driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,22 @@ class Driver
*/
IOStream* getMainStream() const;

/** Open the IO in test mode
*
* It is mostly equivalent to openURI("test://"), but is not meant to be
* overloaded, allowing to test openURI:
*
* <code>
* openTestMode()
* // Feed data to the driver
* openURI();
*
* Moreover, it will always create
* a new test "channel", while openURI will create a new one only if the
* current main stream is not a test stream already.
*/
void openTestMode();

/** Add a listener stream. The object's ownership is taken by the Driver
* object.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/Exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class MockContextException : public std::exception
public:
const char * what() const throw()
{
return "IODRIVERS_BASE_MOCK Error: Expectation set outside Mock Context! Please call IODRIVERS_BASE_MOCK() before setting expectations\n";
return "IODRIVERS_BASE_MOCK Error: Expectation set outside Mock Context! Please call IODRIVERS_BASE_MOCK() before setting expectations";
}
};

Expand All @@ -46,7 +46,7 @@ class TestEndsWithExpectationsLeftException : public std::exception
public:
const char * what() const throw()
{
return "IODRIVERS_BASE_MOCK Error: Test reached its end without satisfying all expecations.\n";
return "IODRIVERS_BASE_MOCK Error: Test reached its end without satisfying all expecations";
}
};

Expand Down
12 changes: 11 additions & 1 deletion src/Fixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ namespace iodrivers_base
template<typename Driver>
struct Fixture
{
typedef Driver fixture_driver_t;

std::vector<uint8_t> packetBuffer;
Driver driver;

Expand All @@ -85,8 +87,10 @@ namespace iodrivers_base

/** Get the underlying TestStream
*/
TestStream* getStream() const
TestStream* getStream()
{
if (!driver.getMainStream())
driver.openTestMode();
return dynamic_cast<TestStream*>(driver.getMainStream());
}

Expand All @@ -100,6 +104,12 @@ namespace iodrivers_base
return packet;
}

/** Write data to the driver */
void writePacket(std::vector<uint8_t> const& data)
{
writePacket(data.data(), data.size());
}

/** Write data to the driver */
void writePacket(uint8_t const* buffer, size_t size)
{
Expand Down
2 changes: 1 addition & 1 deletion src/FixtureBoostTest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <boost/test/unit_test.hpp>
#include <iodrivers_base/Fixture.hpp>

#define IODRIVERS_BASE_MOCK() iodrivers_base::Fixture<Driver>::BoostMockContext __context(this);
#define IODRIVERS_BASE_MOCK() iodrivers_base::Fixture<fixture_driver_t>::BoostMockContext __context(this);

namespace iodrivers_base {
template<typename Driver>
Expand Down
2 changes: 1 addition & 1 deletion src/FixtureGTest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <gtest/gtest.h>
#include <iodrivers_base/Fixture.hpp>

#define IODRIVERS_BASE_MOCK() iodrivers_base::Fixture<Driver>::GTestMockContext __context(this);
#define IODRIVERS_BASE_MOCK() iodrivers_base::Fixture<fixture_driver_t>::GTestMockContext __context(this);

namespace iodrivers_base {
template<typename Driver>
Expand Down
27 changes: 23 additions & 4 deletions src/TestStream.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include <iodrivers_base/TestStream.hpp>
#include <iodrivers_base/Exceptions.hpp>
#include <cstring>
#include <sstream>
#include <iomanip>

using namespace std;
using namespace iodrivers_base;
Expand Down Expand Up @@ -51,22 +53,38 @@ size_t TestStream::write(uint8_t const* buffer, size_t buffer_size)
{
if(mock_mode)
{
from_driver.clear();
from_driver.insert(from_driver.end(), buffer, buffer + buffer_size);
if(expectations.empty())
throw std::runtime_error("Message received without any expecation set/left.");
{
std::stringstream msg;
msg << "Message received, but there are no expectations left:\n";
for (std::vector<uint8_t>::const_iterator it = from_driver.begin(); it != from_driver.end(); ++it)
msg << " " << setfill('0') << setw(2) << hex << static_cast<int>(*it);
throw std::runtime_error(msg.str());
}

if(from_driver == expectations.front())
{
to_driver.insert(to_driver.end(), replies.front().begin(), replies.front().end());
from_driver.clear();
expectations.pop_front();
replies.pop_front();
}
else
{
std::vector<uint8_t> const& expected = expectations.front();
std::stringstream msg;
msg << "IODRIVERS_BASE_MOCK failure";
msg << "\nExpected";
for (std::vector<uint8_t>::const_iterator it = expected.begin(); it != expected.end(); ++it)
msg << " " << setfill('0') << setw(2) << hex << static_cast<int>(*it);
msg << "\nBut got ";
for (std::vector<uint8_t>::const_iterator it = from_driver.begin(); it != from_driver.end(); ++it)
msg << " " << setfill('0') << setw(2) << hex << static_cast<int>(*it);

expectations.clear();
replies.clear();
throw std::invalid_argument("Message received doesn't the given expectations");
throw std::invalid_argument(msg.str());
}
return buffer_size;
}
Expand Down Expand Up @@ -97,4 +115,5 @@ bool TestStream::expectationsAreEmpty()
void TestStream::setMockMode(bool mode)
{
mock_mode = mode;
}
from_driver.clear();
}
157 changes: 152 additions & 5 deletions test/test_TestStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ struct Driver : iodrivers_base::Driver
Driver()
: iodrivers_base::Driver(100) {}

vector<uint8_t> openURIData;

void openURI(string const& uri)
{
iodrivers_base::Driver::openURI(uri);
uint8_t buffer[100];
try {
size_t packet_size = readPacket(buffer, 100);
openURIData = vector<uint8_t>(buffer, buffer + packet_size);
} catch (iodrivers_base::TimeoutError) {
}
}

int extractPacket(uint8_t const* buffer, size_t size) const
{
return size;
Expand All @@ -29,6 +42,17 @@ struct Fixture : iodrivers_base::Fixture<Driver>
}
};

struct FixtureNoOpen : iodrivers_base::Fixture<Driver>
{
};

BOOST_FIXTURE_TEST_CASE(it_allows_to_send_data_for_the_benefit_of_openURI_itself, FixtureNoOpen)
{
uint8_t data[] = { 0, 1, 2, 3 };
pushDataToDriver(data, data + 4);
driver.openURI("test://");
BOOST_REQUIRE(driver.openURIData == vector<uint8_t>(data, data + 4));
}

BOOST_FIXTURE_TEST_CASE(it_sends_data_to_the_Driver, Fixture)
{
Expand Down Expand Up @@ -66,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE(it_gives_access_to_the_bytes_sent_by_the_driver, Fixture
{
uint8_t data[] = { 0, 1, 2, 3 };
writePacket(data, 4);
std::vector<uint8_t> received = readDataFromDriver();
vector<uint8_t> received = readDataFromDriver();
BOOST_REQUIRE(received == vector<uint8_t>(data, data + 4));
}

Expand All @@ -75,7 +99,7 @@ BOOST_FIXTURE_TEST_CASE(it_accumulates_unread_bytes, Fixture)
uint8_t data[] = { 0, 1, 2, 3 };
writePacket(data, 2);
writePacket(data + 2, 2);
std::vector<uint8_t> received = readDataFromDriver();
vector<uint8_t> received = readDataFromDriver();
BOOST_REQUIRE(received == vector<uint8_t>(data, data + 4));
}

Expand All @@ -85,7 +109,7 @@ BOOST_FIXTURE_TEST_CASE(it_does_not_repeat_data_already_read_from_the_device, Fi
writePacket(data, 2);
readDataFromDriver();
writePacket(data + 2, 2);
std::vector<uint8_t> received = readDataFromDriver();
vector<uint8_t> received = readDataFromDriver();
BOOST_REQUIRE(received == vector<uint8_t>(data + 2, data + 4));
}

Expand All @@ -107,7 +131,7 @@ BOOST_FIXTURE_TEST_CASE(it_fails_expecation_with_data_sent_to_device, Fixture)
uint8_t msg[] = { 0, 1, 2, 4 };
uint8_t rep[] = { 3, 2, 1, 0 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
BOOST_REQUIRE_THROW(writePacket(msg,4), std::invalid_argument);
BOOST_REQUIRE_THROW(writePacket(msg,4), invalid_argument);

}

Expand Down Expand Up @@ -164,7 +188,130 @@ BOOST_FIXTURE_TEST_CASE(it_sends_more_messages_than_expecations_set, Fixture)
vector<uint8_t> received_1 = readPacket();
BOOST_REQUIRE(received_1 == vector<uint8_t>(rep1,rep1+4));

BOOST_REQUIRE_THROW(writePacket(exp2,5),std::runtime_error);
BOOST_REQUIRE_THROW(writePacket(exp2,5),runtime_error);
}

BOOST_FIXTURE_TEST_CASE(mock_modes_can_be_used_in_sequence, Fixture)
{
{ IODRIVERS_BASE_MOCK();
uint8_t exp[] = { 0, 1, 2, 3 };
uint8_t rep[] = { 3, 2, 1, 0 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
writePacket(exp,4);
vector<uint8_t> received = readPacket();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}

{ IODRIVERS_BASE_MOCK();
uint8_t exp[] = { 3, 2, 1, 0 };
uint8_t rep[] = { 0, 1, 2, 3 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
writePacket(exp,4);
vector<uint8_t> received = readPacket();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}
}

BOOST_FIXTURE_TEST_CASE(mock_modes_can_be_followed_by_raw_write, Fixture)
{
{ IODRIVERS_BASE_MOCK();
uint8_t exp[] = { 0, 1, 2, 3 };
uint8_t rep[] = { 3, 2, 1, 0 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
writePacket(exp,4);
vector<uint8_t> received = readPacket();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}

uint8_t rep[] = { 0, 1, 2, 3 };
pushDataToDriver(vector<uint8_t>(rep,rep+4));
vector<uint8_t> received = readPacket();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}

BOOST_FIXTURE_TEST_CASE(mock_modes_can_be_followed_by_raw_read, Fixture)
{
{ IODRIVERS_BASE_MOCK();
uint8_t exp[] = { 0, 1, 2, 3 };
uint8_t rep[] = { 3, 2, 1, 0 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
writePacket(exp,4);
vector<uint8_t> received = readPacket();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}

uint8_t rep[] = { 0, 1, 2, 3 };
writePacket(rep, 4);
vector<uint8_t> received = readDataFromDriver();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}

BOOST_FIXTURE_TEST_CASE(quitting_the_mock_mode_does_not_clear_the_data_unread_by_the_driver, Fixture)
{
uint8_t rep[] = { 3, 2, 1, 0 };

{ IODRIVERS_BASE_MOCK();
uint8_t exp[] = { 0, 1, 2, 3 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
writePacket(exp,4);
}

vector<uint8_t> received = readPacket();
BOOST_REQUIRE(received == vector<uint8_t>(rep,rep+4));
}

struct DriverClassNameDriver : Driver
{
virtual int extractPacket(uint8_t const* buffer, size_t buffer_length) const
{
return min(buffer_length, static_cast<size_t>(1));
}
};

struct DriverClassNameTestFixture : iodrivers_base::Fixture<DriverClassNameDriver>
{
};

BOOST_FIXTURE_TEST_CASE(the_mock_mode_can_be_used_with_a_driver_class_not_called_Driver, DriverClassNameTestFixture)
{
IODRIVERS_BASE_MOCK();
uint8_t exp[] = { 0, 1, 2, 3 };
uint8_t rep[] = { 3, 2, 1, 0 };
EXPECT_REPLY(vector<uint8_t>(exp, exp + 4),vector<uint8_t>(rep, rep + 4));
writePacket(exp,4);
vector<uint8_t> received = readPacket();

// This is an indirect test for the type of the driver used in the test. The
// DriverClassNameDriver returns one-byte "packets" while Driver returns the
// whole buffer
BOOST_REQUIRE_EQUAL(1, received.size());
}

struct openURIMockTestDriver : public Driver
{
vector<uint8_t> open(string const& uri)
{
Driver::openURI(uri);
uint8_t data[4] = { 0, 1, 2, 3 };
writePacket(data, 4);

uint8_t read[100];
size_t packet_size = readPacket(read, 100);
return vector<uint8_t>(read, read + packet_size);
}
};

struct openURIMockTestFixture : iodrivers_base::Fixture<openURIMockTestDriver>
{
};

BOOST_FIXTURE_TEST_CASE(the_mock_mode_can_be_used_to_test_openURI_itself, openURIMockTestFixture)
{ IODRIVERS_BASE_MOCK();
uint8_t data[] = { 0, 1, 2, 3 };
vector<uint8_t> packet(data, data + 4);
EXPECT_REPLY(packet, packet);
BOOST_REQUIRE(packet == driver.open("test://"));
}

BOOST_AUTO_TEST_SUITE_END()

Loading

0 comments on commit 07ef979

Please sign in to comment.