265 lines
8.5 KiB
C++
265 lines
8.5 KiB
C++
/*
|
|
* mdJSON.cpp
|
|
*
|
|
* Created on: Jan 28, 2014
|
|
* Author: jdaugherty
|
|
*/
|
|
#define MD_JSON
|
|
#include "cliever-md.h"
|
|
#include <algorithm> // sort
|
|
#include <json/json.h>
|
|
#include <stdio.h>
|
|
#include <execinfo.h>
|
|
#include "mdJSON.hpp"
|
|
|
|
extern bool JSONBatchInProgress,bindDone;
|
|
extern const char *parms[MAX_OTE_CASE];
|
|
|
|
namespace ACPRODINOTE {
|
|
|
|
extern string thisDesc, thisRegistry, thisAccount, thatAccount;
|
|
extern testDescs theseSpecs;
|
|
extern testCases theseCases;
|
|
extern testFuncs theseFuncs;
|
|
extern int cmd,thisCase;
|
|
extern bool bindError,dryRun;
|
|
extern Json::Value theseParms;
|
|
|
|
}
|
|
using namespace std;
|
|
|
|
static std::string
|
|
readInputTestFile( const char *path )
|
|
{
|
|
FILE *file = fopen( path, "rb" );
|
|
if ( !file )
|
|
return std::string("");
|
|
fseek( file, 0, SEEK_END );
|
|
long size = ftell( file );
|
|
fseek( file, 0, SEEK_SET );
|
|
std::string text;
|
|
char *buffer = new char[size+1];
|
|
buffer[size] = 0;
|
|
if ( fread( buffer, 1, size, file ) == (unsigned long)size )
|
|
text = buffer;
|
|
fclose( file );
|
|
delete[] buffer;
|
|
return text;
|
|
}
|
|
|
|
bool mdJSON::run()
|
|
{
|
|
bool lastMemberWasString=false,parseError=false,done=false,parseOnly=false;;
|
|
int i=0, mCases=0, nCases =0, debug=100;
|
|
|
|
const Json::Value suite = root["testSuiteAC"];
|
|
|
|
if (!suite) {
|
|
theseLogs->logN(0,"No 'testSuiteAC' suite root, can't run.");
|
|
return true;
|
|
}
|
|
|
|
if (!suite.isObject()) {
|
|
theseLogs->logN(0,"'testSuiteAC' isn't an object, can't run.");
|
|
return true;
|
|
}
|
|
|
|
if (suite.empty()) {
|
|
theseLogs->logN(0,"'testSuiteAC' contains nothing, can't run.");
|
|
return true;
|
|
}
|
|
|
|
theseLogs->logN(1,"'testSuiteAC' - parse and bind %d fields and case objects.",suite.size());
|
|
Json::Value::Members itemNames = suite.getMemberNames();
|
|
string thisTestCase(""), thisTestCaseDesc("");
|
|
|
|
ACPRODINOTE::thisRegistry = string("");
|
|
ACPRODINOTE::thisAccount = string("");
|
|
ACPRODINOTE::thatAccount = string("");
|
|
ACPRODINOTE::dryRun = false;
|
|
|
|
for ( i = 0; i < itemNames.size(); ++i ) { const char *thisItem;
|
|
try {
|
|
thisItem = itemNames[i].c_str();
|
|
Json::Value thisMember = suite.get(thisItem,root);
|
|
if (debug > 100000)
|
|
theseLogs->logN(1,"item %s.",thisItem);
|
|
if (thisMember.isBool()) {
|
|
if (!stricmp(thisItem,"dryrun")) {
|
|
theseLogs->logN(0,"The script has toggled transactioning.");
|
|
ACPRODINOTE::dryRun = thisMember.asBool();
|
|
continue;
|
|
}
|
|
if (!stricmp(thisItem,"parseonly")) {
|
|
theseLogs->logN(0,"The script has toggled execution.");
|
|
parseOnly = thisMember.asBool();
|
|
continue;
|
|
}
|
|
}
|
|
if (thisMember.isString()) {
|
|
if (!stricmp(thisItem,"registry")) {
|
|
theseLogs->logN(1,"The primary name provider is '%s'",thisMember.asString().c_str());
|
|
ACPRODINOTE::thisRegistry = thisMember.asString();
|
|
continue;
|
|
}
|
|
if (!stricmp(thisItem,"accounta")) {
|
|
theseLogs->logN(1,"The first OTE account is '%s'",thisMember.asString().c_str());
|
|
ACPRODINOTE::thisAccount = thisMember.asString();
|
|
continue;
|
|
}
|
|
if (!stricmp(thisItem,"accountb")) {
|
|
theseLogs->logN(1,"The second OTE account is '%s'",thisMember.asString().c_str());
|
|
ACPRODINOTE::thatAccount = thisMember.asString();
|
|
continue;
|
|
}
|
|
if (strncmp(thisItem,"Case",4)) continue;
|
|
if (strlen(thisItem) < 6) continue;
|
|
if (mCases >= 1) { int k;
|
|
for (k=0;k < mCases;k++)
|
|
if (!strnicmp(ACPRODINOTE::theseSpecs[k].case_name.c_str(),thisItem,6)) {
|
|
parseError = true;
|
|
theseLogs->logN(1,"multiple '%s', not supported, use multiple files.",thisItem);
|
|
}
|
|
}
|
|
if (debug > 10000)
|
|
theseLogs->logN(1,"case desc: %s.",thisMember.asString().c_str());
|
|
ACPRODINOTE::theseSpecs[mCases].case_name = string(thisItem);
|
|
ACPRODINOTE::theseSpecs[mCases++].case_desc = thisMember.asString();
|
|
}
|
|
else { char w0[16];
|
|
if (strncmp(thisItem,"case",4)) continue;
|
|
if (strlen(thisItem) < 6) continue;
|
|
memcpy(w0,thisItem,6); w0[6] =0;
|
|
if (thisMember != root && thisMember.isObject() && !parseError) {
|
|
if (!ACPRODINOTE::theseFuncs[w0]) {
|
|
theseLogs->logN(1,"No logic to bind to '%s', need it.",thisItem);
|
|
return true;
|
|
}
|
|
parms[nCases] = itemNames[i].c_str();
|
|
ACPRODINOTE::theseCases[nCases].fBody = ACPRODINOTE::theseFuncs[w0];
|
|
ACPRODINOTE::theseCases[nCases++].caseName = thisItem;
|
|
}
|
|
}
|
|
}
|
|
catch (exception e)
|
|
{
|
|
//void *array[20];
|
|
//size_t size;
|
|
|
|
// get void*'s for all entries on the stack
|
|
//size = backtrace(array, 20);
|
|
|
|
theseLogs->logN(2,"Item %s fault: %s ",thisItem, e.what());
|
|
//backtrace_symbols_fd(array, size, thisConfig->);
|
|
|
|
AC_ASSERTIONP(false)
|
|
}
|
|
catch (...)
|
|
{
|
|
theseLogs->logN(1,"Test case parse exception: %s ",thisItem );
|
|
AC_ASSERTIONP(false)
|
|
}
|
|
}// for
|
|
|
|
if (mCases != nCases ) {
|
|
theseLogs->logN(2,"spec - case body mismatch (%d:%d).", mCases, nCases); parseError = true; }
|
|
|
|
if (ACPRODINOTE::thisRegistry.empty()) {
|
|
theseLogs->logN(0,"No primary name provider."); parseError = true; }
|
|
|
|
if (ACPRODINOTE::thisAccount.empty() && ACPRODINOTE::thatAccount.empty()) {
|
|
theseLogs->logN(0,"At least one account must be specified."); parseError = true; }
|
|
|
|
if (parseError) {
|
|
theseLogs->logN(0,"parse errors, script cannot be run");
|
|
return true;
|
|
}
|
|
|
|
bindDone = false;
|
|
ACPRODINOTE::bindError = false;
|
|
if (parseOnly) {
|
|
theseLogs->logN(0,"If you see no errors above, script is valid syntactically.");
|
|
JSONBatchInProgress = false;
|
|
goto endBind;
|
|
}
|
|
theseLogs->logN(1,"%d case(s) parsed, bind and queueing begins.",nCases);
|
|
|
|
for (i=0;i<ACPRODINOTE::theseCases.size();i++) { ACPRODINOTE::thisCase = i;
|
|
ACPRODINOTE::theseParms = suite.get(parms[i],root);
|
|
try{
|
|
theseLogs->logN(2,"%d Setup %s ...",i+1,ACPRODINOTE::theseCases[i].caseName );
|
|
ACPRODINOTE::theseCases[i].fBody();
|
|
theseLogs->logN(3,"%d ... %s %d parameter(s) ",i+1,ACPRODINOTE::theseCases[i].caseName,ACPRODINOTE::theseParms.size() );
|
|
}
|
|
catch (exception e)
|
|
{
|
|
theseLogs->logN(2,"Case %s fault: %s ",ACPRODINOTE::theseCases[i].caseName, e.what());
|
|
}
|
|
catch (...)
|
|
{
|
|
theseLogs->logN(1,"Unknown test case fault in %s ",ACPRODINOTE::theseCases[i].caseName );
|
|
}
|
|
}
|
|
if (ACPRODINOTE::bindError) {
|
|
theseLogs->logN(0,"binding errors, script cannot be run");
|
|
done = true;
|
|
goto endBind;
|
|
}
|
|
else
|
|
theseLogs->logN(0,"Suite 'testSuiteAC' bound and and queued for execution.");
|
|
endBind:
|
|
bindDone = true;
|
|
return done; // Should be false if no error.
|
|
|
|
}
|
|
static bool
|
|
parseValueTree( const std::string &input, const std::string &kind, Json::Value &root, const Json::Features &features)
|
|
{
|
|
Json::Reader reader( features );
|
|
bool parsingSuccessful = reader.parse( input, root );
|
|
if ( !parsingSuccessful )
|
|
{
|
|
theseLogs->logN(2, "Failed to parse %s file: %s",
|
|
kind.c_str(),
|
|
reader.getFormattedErrorMessages().c_str() );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool mdJSON::parse()
|
|
{
|
|
bool value = false;
|
|
Json::Features features;
|
|
|
|
try
|
|
{
|
|
std::string input = readInputTestFile( path.c_str() );
|
|
if ( input.empty() )
|
|
{
|
|
theseLogs->logN(1, "Failed to read input or empty input: %s", path.c_str() );
|
|
return 3;
|
|
}
|
|
|
|
return parseValueTree( input, "input", root, features );
|
|
|
|
}
|
|
catch ( const std::exception &e )
|
|
{
|
|
theseLogs->logN(1, "Unhandled exception: %s", e.what() );
|
|
value = true;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void mdJSON::setPath(char *fileName) {
|
|
|
|
path = string(fileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
|