JD2022-TU1/main/extern/dtest/dtcore/inc/dtscript.h

473 lines
23 KiB
C++

#pragma once
#include "dtcore/inc/dttest.h"
#include "dtcore/inc/dtstream.h"
#include "dtcore/inc/dtscriptobject.h"
#include "dtcore/inc/dtscriptstate.h"
#include "dtcore/inc/dtscriptstatementexpressionparserinfo.h"
namespace dt
{
// Use this macro to register your script statement to the ScriptStatementFactory
#define DT_REGISTER_SCRIPT_STATEMENT(className) \
extern dt::ScriptStatementDescriptor dtScriptStatementDescriptor##className; \
dt::ScriptStatementFactory::RegisterScriptStatementDescriptor(&dtScriptStatementDescriptor##className);
// Use this macro to declare a script statement. The base class should be or derive from dt::ScriptStatement
// example: DT_DECLARE_SCRIPT_STATEMENT(yourstatementname, "do stuff") : public dt::ScriptStatementLeaf
#define DT_DECLARE_SCRIPT_STATEMENT(className, expression, ...) \
class className; \
static dt::ScriptStatementDescriptor dtScriptStatementDescriptor##className( \
#className, \
__FILE__, \
__LINE__, \
expression, \
&dt::ScriptStatementFactory::CreateScriptStatement<className>, \
&dt::ScriptStatementFactory::DestroyScriptStatement); \
class __VA_ARGS__ className
//////////////////////////////////////////////////////////////////////////
class ScriptParserState;
class ScriptStatementDescriptor;
class ScriptStatementImpl;
// Base class for a script step called a statement. The relation
// of this class is one to one with the script lines (one instance
// per script line). Normally your custom statement will not
// derive directly from this class but from one of these three:
//
// - ScriptStatementLeaf: simple, single line statement
// - ScriptStatementInSequence: compound statement with nested
// statements within a block surrounded by { }. All nested
// statements executes in sequence.
// - ScriptStatementInParallel: compound statement with nested
// statements within a block surrounded by { }. All nested
// statements executes in parallel.
class ScriptStatement
{
public:
// Default constructor, no work with side effect shall be
// performed here, only initialization.
DT_CORE_DLL_ENTRY ScriptStatement();
DT_CORE_DLL_ENTRY virtual ~ScriptStatement();
// The initialize function is where you can safely init object from the agent.
// This function is called repetitively until SetCompleted() is
// called. Override as needed.
DT_CORE_DLL_ENTRY virtual void Initialize() { SetCompleted(); }
// The run function is where the real work is done. This
// function is called repetitively until SetCompleted() is
// called. The function should not block unless the tests are
// run in background thread mode.
DT_CORE_DLL_ENTRY virtual void Run() { SetCompleted(); }
// The run function is where the cleanup work is done. This
// function is called repetitively until SetCompleted() is
// called. The function should not block unless the tests are
// run in background thread mode. The function is only called
// if Run() was called.
DT_CORE_DLL_ENTRY virtual void Cleanup() { SetCompleted(); }
// Override as needed. This function is called when the
// statement or test times out. You can insert a DT_FAIL macro
// in here to override the timeout failure message of the test
// to add contextual information. Per example, if this
// statement is performing a login, the timeout could be
// "timed out while login in"
DT_CORE_DLL_ENTRY virtual void OnTimeout() {}
// when called, the statement move on to the next state
DT_CORE_DLL_ENTRY virtual void SetCompleted() = 0;
// when called, the statement and its children, if applicable, will be skipped
DT_CORE_DLL_ENTRY virtual void Skip() = 0;
// Get the value of a variable of the specified name. Returns
// false if the variable does not exists.
DT_CORE_DLL_ENTRY bool TryGetVariable(const String& name, const ScriptObject** value);
// Get the value of a variable of the specified name. If the
// variable does not exists, the test fails and this function
// never returns.
DT_CORE_DLL_ENTRY const ScriptObject& GetVariable(const String& name) const;
// Create or update a variable of the specified name. If the
// variable does not exists, it is created in the current
// scope.
DT_CORE_DLL_ENTRY void SetVariable(const String& name, const ScriptObject& value);
// Create a variable of the specified name. if the variable
// already exists, the test fails and this function never
// returns.
DT_CORE_DLL_ENTRY void DeclareVariable(const String& name);
// Get the user ids for which this statement applies to. The
// statement will only run on agent where the user are
// associated. But in case of multiple users per agent, this
// function is used to know on which user it applies.
DT_CORE_DLL_ENTRY const Vector<UserId>& GetUserIds() const;
// Returns all optional zone names that where matches in the
// current script line.
DT_CORE_DLL_ENTRY const Set<String>& GetMatchedOptionalZoneNames() const;
// Returns true if the specified optional zone name was matches.
DT_CORE_DLL_ENTRY bool IsOptionalZoneMatched(const String& zoneName) const;
// Retrieve the statement descriptor that matched the statement.
DT_CORE_DLL_ENTRY const ScriptStatementDescriptor* GetDescriptor() const;
// Retrieve the script filename
DT_CORE_DLL_ENTRY const ScriptLine& GetScriptLine() const;
// Retrieve the timeout period of this statement. INVALID_VALUE
// means no timeout is applicable. Note that timeouts are
// handled internally. This information is exposed for information
// only.
DT_CORE_DLL_ENTRY Seconds GetTimeoutInSec() const;
// Get a unique id of this statement.
DT_CORE_DLL_ENTRY int GetId() const;
DT_CORE_DLL_ENTRY virtual bool InternalUpdate() = 0;
DT_CORE_DLL_ENTRY virtual void InternalTimeout() = 0;
// Returns true if this statement is a function
DT_CORE_DLL_ENTRY virtual bool IsFunction() const;
protected:
DT_CORE_DLL_ENTRY ScriptState* GetScriptState() const;
DT_CORE_DLL_ENTRY const Map<String, ScriptObject>& GetParameters() const;
DT_CORE_DLL_ENTRY bool HandleExecutionTimeout();
private:
friend class ScriptParserImpl;
friend class ScriptStatementCompound;
friend class ScriptStatementCompoundImpl;
friend class ScriptStatementLeafImpl;
friend class ServiceScript;
friend class ServiceScriptImpl;
friend class ScriptState;
friend class ScriptStatementFunctionCheckOptionalZone;
friend class StatementUtilsImpl;
const ScriptStatementCompound* GetParentStatement() const;
void SetParentStatement(const ScriptStatementCompound* parent);
void SetInformation(const ScriptStatementCompound* parent,
const ScriptLine& line,
const ScriptStatementDescriptor* descriptor,
const Map<String, ScriptObject>& parameters,
const Vector<UserId>& users,
const Set<String>& matchedOptionalZoneNames,
Seconds timeout);
DT_CORE_DLL_ENTRY virtual bool IsCompound() const;
bool IsInParallelBlock() const;
DT_CORE_DLL_ENTRY virtual bool IsRunningChildrenInParallel() const;
DT_CORE_DLL_ENTRY virtual void SetScriptState(ScriptState* state);
const ScriptStatement* GetFirstCommonStatementInHierarchy(const ScriptStatement* other);
void PushStack();
void PopStack();
void Synchronize();
bool IsSynchronized() const;
void SynchronizationEnable();
void SynchronizationDisable();
bool AppliesToCurrentAgentIndex() const;
ShowProgressionMode GetShowProgressionMode() const;
private:
ScriptStatementImpl* m_Impl;
};
typedef Vector<ScriptStatement*> ScriptStatements;
//////////////////////////////////////////////////////////////////////////
// This class is created by the DT_DECLARE_SCRIPT_STATEMENT macro and is
// used to store the statement declaration information.
class ScriptStatementDescriptor
{
public:
typedef ScriptStatement* (*CreateFunction)();
typedef void(*DestroyFunction)(ScriptStatement*);
DT_CORE_DLL_ENTRY ScriptStatementDescriptor(const char* className,
const char* file,
int line,
const char* expression,
CreateFunction createFunction,
DestroyFunction destroyFunction);
// returns the class name of the ScriptStatement
DT_CORE_DLL_ENTRY const char* GetName() const { return m_ClassName; }
// returns the filename where the script statement was declared
DT_CORE_DLL_ENTRY const char* GetFilename() const { return m_Filename; }
// returns the line where the script statement was declared
DT_CORE_DLL_ENTRY int GetLineNumber() const { return m_LineNumber; }
// returns the expression specified in DT_DECLARE_SCRIPT_STATEMENT
DT_CORE_DLL_ENTRY const char* GetExpression() const { return m_Expression; }
// returns a create function to create the Statement of this type
DT_CORE_DLL_ENTRY CreateFunction GetCreateFunction() const { return m_CreateFunction; }
// returns a destroy function to delete the Statement of this type
DT_CORE_DLL_ENTRY DestroyFunction GetDestroyFunction() const { return m_DestroyFunction; }
private:
const char* m_ClassName;
const char* m_Filename;
const char* m_Expression;
CreateFunction m_CreateFunction;
DestroyFunction m_DestroyFunction;
int m_LineNumber;
};
typedef Vector<ScriptStatementDescriptor*> ScriptStatementDescriptors;
//////////////////////////////////////////////////////////////////////////
class ScriptStatementScannerImpl;
// This class is used by ScriptStatementExpressionParsers to parse
// the script lines and identify which ScriptStatement class to
// instantiate. This class is created internally and passed to the
// ScriptStatementExpressionParser::Parse() function.
class ScriptStatementScanner
{
public:
DT_CORE_DLL_ENTRY ScriptStatementScanner(ScriptParserState& parentState, const String& line);
DT_CORE_DLL_ENTRY ~ScriptStatementScanner();
DT_CORE_DLL_ENTRY const ScriptParserState& GetParentState() const;
DT_CORE_DLL_ENTRY ScriptParserState& GetParentState();
// returns the complete script line being parsed
DT_CORE_DLL_ENTRY const String& GetLine() const;
// returns the position offset on the line where the scanner is
DT_CORE_DLL_ENTRY SizeT GetPosition() const;
// returns the char at the current position of the scanner or '\0' if at end
DT_CORE_DLL_ENTRY char Peek() const;
// returns true if the scanner is at the end of the line
DT_CORE_DLL_ENTRY bool End() const;
// pre and post increment the current scanner position and
// return the next or current char
DT_CORE_DLL_ENTRY char operator++();
DT_CORE_DLL_ENTRY char operator++(int);
// util functions
DT_CORE_DLL_ENTRY static bool IsValidIntegerFirstChar(char c);
DT_CORE_DLL_ENTRY static bool IsValidIntegerChar(char c);
DT_CORE_DLL_ENTRY static bool IsValidIdentifierFirstChar(char c);
DT_CORE_DLL_ENTRY static bool IsValidIdentifierChar(char c);
DT_CORE_DLL_ENTRY static bool IsValidJsonFirstChar(char c);
DT_CORE_DLL_ENTRY static bool IsWhiteSpaceChar(char c);
// increment the scanner position until non white space is found
DT_CORE_DLL_ENTRY void SkipWhiteSpace();
// increment the scanner position by the number of char specified
DT_CORE_DLL_ENTRY void Skip(int count);
// increment the scanner position by the length of str if the line
// at the scanner position matches the str specified.
DT_CORE_DLL_ENTRY bool SkipLiteralIfEqual(const char* str);
// parse a variable reference, a identifier enclosed within parenthesis.
// returns a reference to a script object
// returns true if a reference was found
DT_CORE_DLL_ENTRY bool ParseReference(ScriptObject* out);
// parse a Json expression
// returns the JsonValue corresponding to the expression
// returns true if a Json expression was found and is valid
DT_CORE_DLL_ENTRY bool ParseJsonExpression(JsonValue* out);
// parse an identifier. An identifier starts with a letter and contains 0 or more
// letters, numbers or underscores.
// returns the identifier
// returns true if an identifier was found
DT_CORE_DLL_ENTRY bool ParseIdentifier(String* out);
// parse a 32 bit signed integer
// returns the integer
// returns true if a valid signed 32 bits integer was found
DT_CORE_DLL_ENTRY bool ParseInteger(S32* out);
// parse a 64 bit signed integer
// returns the integer
// returns true if a valid signed 64 bits integer was found
DT_CORE_DLL_ENTRY bool ParseInteger(S64* out);
// parse a 64 bit unsigned integer
// returns the unsigned integer
// returns true if a valid unsigned 64 bits integer was found
DT_CORE_DLL_ENTRY bool ParseInteger(U64* out);
// parse a 64 bit signed double
// returns the double
// returns true if a valid signed double was found
DT_CORE_DLL_ENTRY bool ParseDouble(double* out);
// parse a string enclosed in double quotes
// returns the string
// returns true if a valid string was found
DT_CORE_DLL_ENTRY bool ParseString(String* out);
// parse a bool
// returns the bool
// returns true if a valid bool was found
DT_CORE_DLL_ENTRY bool ParseBool(bool* out);
// returns the current longest matched position of the scanner
DT_CORE_DLL_ENTRY SizeT GetBestPosition() const;
// updates the longest matched position of the scanner
DT_CORE_DLL_ENTRY void UpdateBestPosition(SizeT possibleBestPosition);
// resets the longest matched position
DT_CORE_DLL_ENTRY void ResetBestPosition();
// save the current scanner position into a stack. Each push
// must be followed by one pop.
DT_CORE_DLL_ENTRY void PushPosition();
// pop the current position and if apply is true, restore the
// previously pushed position.
DT_CORE_DLL_ENTRY void PopPosition(bool apply = true);
// change the current scanner position
DT_CORE_DLL_ENTRY void SetPosition(SizeT newPosition);
private:
ScriptStatementScannerImpl* m_Impl;
};
//////////////////////////////////////////////////////////////////////////
// Use this macro to register your script statement expression
// parser to the ScriptStatementFactory
#define DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER(className) \
extern dt::ScriptStatementExpressionParserDescriptor dtScriptStatementExpressionParserDescriptor##className; \
dt::ScriptStatementFactory::RegisterScriptStatementExpressionParserDescriptor(&dtScriptStatementExpressionParserDescriptor##className);
// Use this macro to declare a script statement expression
// parser. The base class should be or derive from
// dt::ScriptStatementExpressionParser.
// example: DT_DECLARE_SCRIPT_STATEMENT_EXPRESSION_PARSER(yourstatementexpressionparsername, "apple") : public dt::ScriptStatementExpressionParser
#define DT_DECLARE_SCRIPT_STATEMENT_EXPRESSION_PARSER(className, expression, ...) \
class className; \
static dt::ScriptStatementExpressionParserDescriptor dtScriptStatementExpressionParserDescriptor##className( \
#className, \
expression, \
&dt::ScriptStatementFactory::CreateScriptStatementExpressionParser<className>, \
&dt::ScriptStatementFactory::DestroyScriptStatementExpressionParser); \
class __VA_ARGS__ className
// Base class to implement new expression parsers. Expression
// parsers allow parsing part of a statement, retrieve some data
// and store it in native format to allow statement code to use
// it.
class ScriptStatementExpressionParser
{
public:
DT_CORE_DLL_ENTRY ScriptStatementExpressionParser();
DT_CORE_DLL_ENTRY virtual ~ScriptStatementExpressionParser() {};
// The parse method has to be overridden. The scanner contains
// the script line to be parsed and helper functions to do so.
// The parserInfo->GetContext() is the key to be used to store the
// corresponding parsed value in the outParameters map. Per example,
// if a class parses apple types, then the apple type would be
// stored in outParameters:
//
// outParameters->Insert(parserInfo->GetContext(), appleType);
//
// Returns true if the expression parses successfully matched,
// or otherwise return false. This class shall not generate
// any errors using DT_FAIL as the script parser tries all
// combinations on every line of script
DT_CORE_DLL_ENTRY virtual bool Parse(ScriptStatementScanner& scanner,
const ScriptStatementExpressionParserInfo& parserInfo,
Map<String, ScriptObject>* outParameters,
Set<String>* outOptionalZones) = 0;
};
//////////////////////////////////////////////////////////////////////////
// This class is created by the
// DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER macro and is
// used to store the statement expression parser declaration
// information.
class ScriptStatementExpressionParserDescriptor
{
public:
typedef ScriptStatementExpressionParser* (*CreateFunction)();
typedef void(*DestroyFunction)(ScriptStatementExpressionParser*);
DT_CORE_DLL_ENTRY ScriptStatementExpressionParserDescriptor(const char* className,
const char* expression,
CreateFunction createFunction,
DestroyFunction destroyFunction);
// returns the class name of the ScriptStatementExpressionParser
DT_CORE_DLL_ENTRY const char* GetName() const { return m_ClassName; }
// returns the expression of the parser, the second parameter
// of the DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER macro
DT_CORE_DLL_ENTRY const char* GetExpression() const { return m_Expression; }
// returns a create function to create the Statement of this type
DT_CORE_DLL_ENTRY CreateFunction GetCreateFunction() const { return m_CreateFunction; }
// returns a destroy function to delete the Statement of this type
DT_CORE_DLL_ENTRY DestroyFunction GetDestroyFunction() const { return m_DestroyFunction; }
private:
const char* m_ClassName;
const char* m_Expression;
CreateFunction m_CreateFunction;
DestroyFunction m_DestroyFunction;
};
typedef Vector<ScriptStatementExpressionParserDescriptor*> ScriptStatementExpressionParserDescriptors;
//////////////////////////////////////////////////////////////////////////
// This class is used by the following macros to register a
// statement or statement expression parser class to be created
// automatically by the script parser.
// - DT_REGISTER_SCRIPT_STATEMENT
// - DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER
class ScriptStatementFactory
{
public:
// Register a script statement descriptor
DT_CORE_DLL_ENTRY static void RegisterScriptStatementDescriptor(ScriptStatementDescriptor* stmDescriptor);
// Register all built in script statements
DT_CORE_DLL_ENTRY static void RegisterBuiltInStatements();
// Clear all registered script statements
DT_CORE_DLL_ENTRY static void ClearScriptStatementDescriptors();
// Helper function to create a script statement
template <typename T> static ScriptStatement* CreateScriptStatement();
// Destroy function for script statement
DT_CORE_DLL_ENTRY static void DestroyScriptStatement(ScriptStatement* stm);
// Returns the list of all known script statement descriptors
DT_CORE_DLL_ENTRY static void GetScriptStatementDescriptors(ScriptStatementDescriptors* out);
// Returns the script statement descriptor specified
DT_CORE_DLL_ENTRY static ScriptStatementDescriptor* GetScriptStatementDescriptor(const String& expression);
// Register a script statement descriptor expression parser
DT_CORE_DLL_ENTRY static void RegisterScriptStatementExpressionParserDescriptor(ScriptStatementExpressionParserDescriptor* parserDescriptor);
// Register all built in expression parsers
DT_CORE_DLL_ENTRY static void RegisterBuiltInExpressionParsers();
// Clear all registered script statement expression parsers
DT_CORE_DLL_ENTRY static void ClearScriptStatementExpressionParserDescriptors();
// Helper function to create a script statement expression parser
template <typename T> static ScriptStatementExpressionParser* CreateScriptStatementExpressionParser();
// Destroy function for script statement expression parser
DT_CORE_DLL_ENTRY static void DestroyScriptStatementExpressionParser(ScriptStatementExpressionParser* parser);
// Returns the list of all known script statement descriptors expression parser
DT_CORE_DLL_ENTRY static void GetScriptStatementExpressionParserDescriptors(ScriptStatementExpressionParserDescriptors* out);
// Returns the script statement descriptor expression parser specified
DT_CORE_DLL_ENTRY static ScriptStatementExpressionParserDescriptor* GetScriptStatementExpressionParserDescriptor(const String& expression);
public:
// This section is meant for INTERNAL USE only.
DT_CORE_DLL_ENTRY static void CreateFunctionScriptStatementDescriptors(const Map<String, ScriptDescriptor>& testFunctions);
DT_CORE_DLL_ENTRY static void GetFunctionScriptStatementDescriptors(ScriptStatementDescriptors* out);
DT_CORE_DLL_ENTRY static void DestroyFunctionScriptStatementDescriptors();
};
template <typename T> inline ScriptStatement* ScriptStatementFactory::CreateScriptStatement()
{
return DT_NEW(T)();
}
template <typename T> inline ScriptStatementExpressionParser* ScriptStatementFactory::CreateScriptStatementExpressionParser()
{
return DT_NEW(T)();
}
}