Skip to content

Instantly share code, notes, and snippets.

@ashishnegi
Last active August 29, 2015 14:19
Show Gist options
  • Save ashishnegi/193825a627a7472cd34d to your computer and use it in GitHub Desktop.
Save ashishnegi/193825a627a7472cd34d to your computer and use it in GitHub Desktop.
Gets the function name and arguments : (problem with default values in function signature)
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cctype>
#include <map>
namespace patch
{
template < typename T > std::string to_string( const T& n )
{
std::ostringstream stm ;
stm << n ;
return stm.str() ;
}
}
auto funcSpace = [](unsigned char const c) { return std::isspace(c); };
std::string trim (std::string str) {
std::size_t i = 0;
while (i < str.length()) {
if (!std::isspace(str[i]))
break;
++i;
}
str = str.erase(0, i);
i = str.length() - 1;
while (i >= 0) {
if (!std::isspace(str[i]))
break;
--i;
}
str = str.erase(i+1);
return str;
}
bool makeValidLine(std::string & line) {
using namespace std;
line = trim(line);
size_t firstNonDelimCharPos = 0;
const size_t lineLen = line.size();
while (firstNonDelimCharPos < lineLen) {
const char & ch = line[firstNonDelimCharPos];
if ((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z'))
break;
firstNonDelimCharPos += 1;
}
if (firstNonDelimCharPos == lineLen)
return false;
line = line.substr(firstNonDelimCharPos); // line changes.
// auto pos = line.find_last_of(";");
// if (pos == std::string::npos)
// return false;
// line = line.substr(0, pos);
static const string virtualWord = "virtual";
if ((virtualWord == (line.substr(0, virtualWord.size()))) &&
line.length() > virtualWord.size() &&
(std::isspace(line[virtualWord.size()])))
return true;
return false;
}
int main () {
std::string line;
std::map<std::string, std::size_t> allFunctions;
while (std::getline(std::cin, line, '\n')) {
if (!makeValidLine(line))
continue;
// keep appending to line untill you get a terminator ;
while (std::string::npos == line.find_last_of(";")) {
std::string nextLine;
std::getline(std::cin, nextLine, '\n');
line += nextLine;
}
const std::string originalLine(line);
{
// ok .. this line "now" starts with word `virtual `.
// it is highly unlikely that we would have word virtual in the start of c++ code.
// unless it is a comment. <- would handle later.
}
auto pos = line.find_first_of("(", 0);
if (std::string::npos == pos) {
std::cerr << "0: Unable to generate mock for line : " + line << std::endl;
continue;
}
// word before '(' would be function-name.
// virtual return-type function-name (
std::string functionName;
std::size_t functionStartIndex = 0;
{
std::size_t index = pos ;
index -= 1; // start in reverse order from '('.
while (index > 0) { // remove all delimiters.
if (!std::isspace(line[index]))
break;
index -= 1;
}
// find the word.
const std::size_t functionEnd = index;
index -= 1; // find next space.
while (index > 0) {
if (!std::isalpha(line[index]))
break;
index -= 1;
}
const std::size_t functionStart = index+1;
functionName = trim(line.substr(functionStart, functionEnd - functionStart + 1));
{
int iteration = 1;
const std::string originalFunctionName(functionName);
while (allFunctions.find(functionName) != allFunctions.end() && (iteration < 10))
functionName = originalFunctionName + patch::to_string((long)iteration++);
if (iteration == 10)
continue;
allFunctions[functionName] += 1;
}
functionStartIndex = functionStart;
}
if (0 == functionName.size()) {
std::cerr << "1. Unable to generate mock for line : " + line << std::endl;
continue;
}
// return type is after word `virtual` --return-type-- function-start-index.
const std::size_t virtualLen = std::string("virtual ").length();
const std::string returnType = trim(line.substr(virtualLen, functionStartIndex - virtualLen));
// Get the arguments to the function.
// (Type var-name, Typ var-name)
// Type can have spaces.. std::vector < int >
// but var-name can not.
const auto closingBracePos = line.find_first_of(")");
if (std::string::npos == closingBracePos) {
std::cerr << "2: Unable to generate mock for line : " + line << std::endl;
continue;
}
const std::size_t startBracePos = line.find_first_of("(");
if (std::string::npos == startBracePos || (startBracePos >= closingBracePos)){
std::cerr << "3: Unable to generate mock for line : " + line << std::endl;
continue;
}
const std::string arguments = line.substr(startBracePos,
closingBracePos - startBracePos + 1);
// pair of {type, name}
std::vector< std::pair<std::string, std::string> > argumentPairs;
{
std::size_t prev = 0, pos;
std::vector<std::string> pairOfTypeVarnameVector;
while ((pos = arguments.find_first_of("(,)", prev)) != std::string::npos)
{
if (pos > prev)
pairOfTypeVarnameVector.push_back(trim(arguments.substr(prev, pos-prev)));
prev = pos+1;
}
if (prev < arguments.length())
pairOfTypeVarnameVector.push_back(trim(line.substr(prev, std::string::npos)));
// each entry in pairOfTypeVarnameVector has last word as var-name or no var-name.
// if there are 1 word : it is type.
// if there are > 1 word , we treat last word as var-name.
std::for_each(pairOfTypeVarnameVector.begin(),
pairOfTypeVarnameVector.end(),
[&argumentPairs](const std::string & typeVarName) {
if (0 == typeVarName.size())
return;
auto pos = typeVarName.find_last_of(" \t*&");
if (pos == std::string::npos) {
{
int i =0;
while (i < typeVarName.size()) {
if (std::isspace(typeVarName[i])) {
i++; continue;
} else break;
}
if (i == typeVarName.size())
return;
}
argumentPairs.push_back(std::make_pair(trim(typeVarName), "a"));
return;
} else {
const std::size_t indexPos = pos;
argumentPairs.push_back(std::make_pair(trim(typeVarName.substr(0, indexPos+1)),
trim(typeVarName.substr(indexPos+1))));
}
});
}
const bool constWord = line.find("const", closingBracePos) != std::string::npos;
std::string functionArguments;
for(auto it = argumentPairs.begin(), lastIt = --argumentPairs.end(); it != argumentPairs.end(); ++it) {
functionArguments += it->second ;
if (it != lastIt)
functionArguments += " , ";
}
// so now we have everything ..
std::cout << "std::function< " << returnType << arguments << " >" << " mMock" << functionName << " ;\n"
// i can not put the original here because original may not have variable-names and then i would suck.
<< "virtual " << returnType << " " << functionName << " (" ;
for(auto it = argumentPairs.begin(), lastIt = --argumentPairs.end(); it != argumentPairs.end(); ++it) {
std::cout << it->first << " " << it->second;
if (it != lastIt)
std::cout << ", ";
}
std::cout << ") "
<< (constWord ? "const" : "")
<< " override {\n"
<< " if (!mMock" << functionName << ")\n"
<< " return BaseClassName::" << functionName << "(" << functionArguments << ");\n"
<< " return mMock" << functionName << "(" << functionArguments << ");\n"
<< "}\n";
// std::cout << "function:" << functionName << "\nreturn:" << returnType << "\n";
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment