Summary
 There’s plenty more we could do (such as actually checking whether the queue is empty/full before popping/pushing!), but that’s the end of this kata. Congratulations on learning how to apply Google Test/Google Mock to interaction-style TDD-ing in C++!
I used to really struggle writing tests in C++. BoostTest and Mockpp were the best solutions I had found to date. These are reasonable frameworks, but the ease of use of Google Test/Google Mock blows them away IMO.
In summary: I'm very impressed with both Google Test and Google Mock and look forward to using them more in the future.
Back to the beginning of this kata
Full source code:
QueueControl.h
#ifndef __QUEUE_CONTROL_H_
#define __QUEUE_CONTROL_H_
class QueueControl {
public:
virtual ~QueueControl() {}
virtual void Resume() = 0;
virtual void Pause() = 0;
};
#endifBoundedQueueTest.cpp
#include "BoundedQueue.h"
#include <gmock/gmock.h>
class MockQueueControl : public QueueControl {
public:
MOCK_METHOD0(Resume, void());
MOCK_METHOD0(Pause, void());
};
class BoundedQueueTest : public ::testing::Test {
public:
BoundedQueueTest() : q(SetUpProducer(), SetUpConsumer(), BOUND) {
Mock::VerifyAndClear(&producer);
Mock::VerifyAndClear(&consumer);
}
MockQueueControl& SetUpProducer() {
EXPECT_CALL(producer, Resume());
return producer;
}
MockQueueControl& SetUpConsumer() {
EXPECT_CALL(consumer, Pause());
return consumer;
}
MockQueueControl producer;
MockQueueControl consumer;
static const size_t BOUND = 3;
BoundedQueue<int> q;
};
TEST_F(BoundedQueueTest, CreateResumesProducer) {
EXPECT_CALL(producer, Resume());
BoundedQueue<int> q(producer, consumer);
}
TEST_F(BoundedQueueTest, CreatePausesConsumer) {
EXPECT_CALL(consumer, Pause());
BoundedQueue<int> q(producer, consumer);
}
TEST_F(BoundedQueueTest, EnqueueResumesConsumer) {
EXPECT_CALL(consumer, Resume());
q.enqueue(5);
}
TEST_F(BoundedQueueTest, FirstInFirstOut) {
q.enqueue(1);
q.enqueue(2);
ASSERT_EQ(1, q.dequeue());
ASSERT_EQ(2, q.dequeue());
}
TEST_F(BoundedQueueTest, EnqueueResumesConsumerOnFirstItemOnly) {
EXPECT_CALL(consumer, Resume()).Times(1);
q.enqueue(5);
q.enqueue(5);
}
TEST_F(BoundedQueueTest, DequeuePausesConsumerWhenQueueIsEmpty) {
q.enqueue(3);
q.enqueue(6);
EXPECT_CALL(consumer, Pause());
q.dequeue();
q.dequeue();
}
TEST_F(BoundedQueueTest, EnqueuePausesProducerWhenQueueIsFull) {
EXPECT_CALL(producer, Pause());
q.enqueue(4);
q.enqueue(4);
q.enqueue(4);
}BoundedQueue.h
#ifndef __bounded_queue_h_
#define __bounded_queue_h_
#include "QueueControl.h"
#include <queue>
template <typename T>
class BoundedQueue {
public:
public:
BoundedQueue(QueueControl& producer, QueueControl& consumer, size_t size = 100)
: producer(producer), consumer(consumer), max_size(size) {
producer.Resume();
consumer.Pause();
}
void enqueue(const T& item) {
q.push(item);
if (q.size() == 1) {
consumer.Resume();
}
if (q.size() == max_size) {
producer.Pause();
}
}
const T& dequeue() {
const T& item = q.front();
q.pop();
if (q.size() == 0) {
consumer.Pause();
}
return item;
}
private:
QueueControl& consumer;
QueueControl& producer;
std::queue<T> q;
size_t max_size;
};
#endifMakefile
LIB = /usr/local/lib
all: BoundedQueueTest
./BoundedQueueTest
BoundedQueueTest: BoundedQueueTest.o
g++ -o BoundedQueueTest $(LIB)/libgmock_main.a $(LIB)/libgmock.a $(LIB)/libgtest.a BoundedQueueTest.o
BoundedQueueTest.o: BoundedQueueTest.cpp BoundedQueue.h QueueControl.h
g++ -c BoundedQueueTest.cpp
clean:
rm *.o
rm BoundedQueueTest