StringTokenGenerator
is an interface (or abstract class) I've created to the specific task of generating a string token of a given character set. It allows appending characters to it and then it can be used to receive a string token. I wrote this for the second version of ExpressGenGen a code generator generator. Second version uses TDD as the development practice.
At first there is the header only abstract class, and after that I have included it's implementations, and then Test class. I'm using Google Mock and Google Test for testing.
Note that I'm generating the TestHelper
. See here to see how it's done.
What I want reviewed:
- Am I following C++/C++11 idioms correctly?
- Does it need a better API design?
- Is there better ways to utilize Google Mock and Google Test?
- Is it too much abstraction?
- Does this adhere to the const correctness principle?
- Am I following good object oriented design principles?
- Do I need to apply DRY principle somewhere in this code?
- Am I following good practices when It comes to TDD?
- Can the test cases be written better?
- Am I missing any corner cases in the test cases?
StringTokenGenerator.h
#ifndef _STRING_TOKEN_GENERATOR_H_
#define _STRING_TOKEN_GENERATOR_H_
//--------------------------------------------
// Has
//
//--------------------------------------------
// Inherits
//
//--------------------------------------------
// Uses
#include <string>
//--------------------------------------------
class StringTokenGenerator {
public:
virtual void Append(char c) = 0;
virtual std::string GetToken() = 0 ;
virtual ~StringTokenGenerator() {}
private:
};
//-------------------------------------------
#endif // _STRING_TOKEN_GENERATOR_H_
DoubleQuoteStringTokenGenerator.h
#ifndef _DOUBLE_QUOTE_STRING_TOKEN_GENERATOR_H_
#define _DOUBLE_QUOTE_STRING_TOKEN_GENERATOR_H_
//--------------------------------------------
// Has
//
//--------------------------------------------
// Inherits
#include "StringTokenGenerator.h"
//--------------------------------------------
// Uses
#include <memory>
//--------------------------------------------
class DoubleQuoteStringTokenGenerator : public StringTokenGenerator {
public:
DoubleQuoteStringTokenGenerator();
virtual void Append(char c);
virtual std::string GetToken();
private:
std::unique_ptr<std::string> mToken;
};
//-------------------------------------------
#endif // _DOUBLE_QUOTE_STRING_TOKEN_GENERATOR_H_
DoubleQuoteStringTokenGenerator.cpp
//--------------------------------------------
// Definition
#include "DoubleQuoteStringTokenGenerator.h"
//--------------------------------------------
// Uses
//
//--------------------------------------------
DoubleQuoteStringTokenGenerator::DoubleQuoteStringTokenGenerator()
: mToken(new std::string())
{
}
void DoubleQuoteStringTokenGenerator::Append(char c)
{
switch (c) {
case '"':
mToken->append("\\\"");
break;
case '\\':
mToken->append("\\\\");
break;
default:
mToken->push_back(c);
break;
}
}
std::string DoubleQuoteStringTokenGenerator::GetToken()
{
std::string token("\"");
token.append(*mToken);
token.append("\"");
mToken->clear();
return token;
}
//--------------------------------------------
SingleQuoteStringTokenGenerator.h
#ifndef _SINGLE_QUOTE_STRING_TOKEN_GENERATOR_H_
#define _SINGLE_QUOTE_STRING_TOKEN_GENERATOR_H_
//--------------------------------------------
// Has
//
//--------------------------------------------
// Inherits
#include "StringTokenGenerator.h"
//--------------------------------------------
// Uses
#include <string>
#include <memory>
//--------------------------------------------
class SingleQuoteStringTokenGenerator : public StringTokenGenerator {
public:
SingleQuoteStringTokenGenerator();
virtual void Append(char c);
virtual std::string GetToken();
private:
std::unique_ptr<std::string> mToken;
};
//-------------------------------------------
#endif // _SINGLE_QUOTE_STRING_TOKEN_GENERATOR_H_
SingleQuoteStringTokenGenerator.cpp
//--------------------------------------------
// Definition
#include "SingleQuoteStringTokenGenerator.h"
//--------------------------------------------
// Uses
//
//--------------------------------------------
SingleQuoteStringTokenGenerator::SingleQuoteStringTokenGenerator()
: mToken(new std::string())
{
}
void SingleQuoteStringTokenGenerator::Append(char c)
{
switch (c) {
case '\'':
mToken->append("\\'");
break;
case '\\':
mToken->append("\\\\");
break;
default:
mToken->push_back(c);
break;
}
}
std::string SingleQuoteStringTokenGenerator::GetToken()
{
std::string token("'");
token.append(*mToken);
token.append("'");
mToken->clear();
return token;
}
//--------------------------------------------
TestStringTokenGenerator.cpp
//--------------------------------------------
// Definition
//
//--------------------------------------------
// Uses
#include "TestHelper.h"
//--------------------------------------------
// ---->>> Double Quote <<<----
TEST(StringTokenGenerator, DoubleQuoteStringTokenGeneratorBasicTest)
{
auto tokenGen(std::make_shared<DoubleQuoteStringTokenGenerator>());
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
tokenGen->Append('h');
tokenGen->Append('e');
tokenGen->Append('l');
tokenGen->Append('l');
tokenGen->Append('o');
// Should translate to {"hello"}
ASSERT_EQ(tokenGen->GetToken(), "\"hello\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
}
TEST(StringTokenGenerator, DoubleQuoteStringTokenGeneratorEscapeDoubleQuote)
{
auto tokenGen(std::make_shared<DoubleQuoteStringTokenGenerator>());
tokenGen->Append('"');
tokenGen->Append('o');
tokenGen->Append('n');
tokenGen->Append('e');
tokenGen->Append('"');
// Should translate to {"\"one\""}
ASSERT_EQ(tokenGen->GetToken(), "\"\\\"one\\\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
}
TEST(StringTokenGenerator, DoubleQuoteStringTokenGeneratorEscapeAll)
{
auto tokenGen(std::make_shared<DoubleQuoteStringTokenGenerator>());
tokenGen->Append('"');
tokenGen->Append('C');
tokenGen->Append(':');
tokenGen->Append('\\');
tokenGen->Append('"');
// Should translate to {"\"C:\\\""}
ASSERT_EQ(tokenGen->GetToken(), "\"\\\"C:\\\\\\\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
}
TEST(StringTokenGenerator, DoubleQuoteEmptyFromBegining)
{
auto tokenGen(std::make_shared<DoubleQuoteStringTokenGenerator>());
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
ASSERT_EQ(tokenGen->GetToken(), "\"\"");
}
// ---->>> Single Quote <<<----
TEST(StringTokenGenerator, SingleQuoteStringTokenGeneratorBasicTest)
{
auto tokenGen(std::make_shared<SingleQuoteStringTokenGenerator>());
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
tokenGen->Append('h');
tokenGen->Append('e');
tokenGen->Append('l');
tokenGen->Append('l');
tokenGen->Append('o');
// Should translate to {'hello'}
ASSERT_EQ(tokenGen->GetToken(), "'hello'");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
}
TEST(StringTokenGenerator, SingleQuoteStringTokenGeneratorEscapeSingleQuote)
{
auto tokenGen(std::make_shared<SingleQuoteStringTokenGenerator>());
tokenGen->Append('\'');
tokenGen->Append('o');
tokenGen->Append('n');
tokenGen->Append('e');
tokenGen->Append('\'');
// Should translate to {'\'one\''}
ASSERT_EQ(tokenGen->GetToken(), "'\\'one\\''");
ASSERT_EQ(tokenGen->GetToken(), "''");
}
TEST(StringTokenGenerator, SingleQuoteStringTokenGeneratorEscapeAll)
{
auto tokenGen(std::make_shared<SingleQuoteStringTokenGenerator>());
tokenGen->Append('\'');
tokenGen->Append('C');
tokenGen->Append(':');
tokenGen->Append('\\');
tokenGen->Append('\'');
// Should translate to {'\'C:\\\''}
ASSERT_EQ(tokenGen->GetToken(), "'\\'C:\\\\\\''");
ASSERT_EQ(tokenGen->GetToken(), "''");
}
TEST(StringTokenGenerator, SingleQuoteEmptyFromBegining)
{
auto tokenGen(std::make_shared<SingleQuoteStringTokenGenerator>());
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
ASSERT_EQ(tokenGen->GetToken(), "''");
}
//--------------------------------------------