/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ #pragma once #include #include #include namespace solidity::frontend::test { /** * All soltest tokens. */ #define SOLT_TOKEN_LIST(T, K) \ T(Unknown, "unknown", 0) \ T(Invalid, "invalid", 0) \ T(EOS, "EOS", 0) \ T(Whitespace, "_", 0) \ /* punctuations */ \ T(LParen, "(", 0) \ T(RParen, ")", 0) \ T(LBrack, "[", 0) \ T(RBrack, "]", 0) \ T(LBrace, "{", 0) \ T(RBrace, "}", 0) \ T(Sub, "-", 0) \ T(Colon, ":", 0) \ T(Comma, ",", 0) \ T(Period, ".", 0) \ T(Arrow, "->", 0) \ T(Newline, "//", 0) \ /* Literals & identifier */ \ T(Comment, "#", 0) \ T(Number, "number", 0) \ T(HexNumber, "hex_number", 0) \ T(String, "string", 0) \ T(Identifier, "identifier", 0) \ /* type keywords */ \ K(Ether, "ether", 0) \ K(Wei, "wei", 0) \ K(Hex, "hex", 0) \ K(Boolean, "boolean", 0) \ /* special keywords */ \ K(Left, "left", 0) \ K(Library, "library", 0) \ K(Right, "right", 0) \ K(Failure, "FAILURE", 0) \ namespace soltest { enum class Token : unsigned int { #define T(name, string, precedence) name, SOLT_TOKEN_LIST(T, T) NUM_TOKENS #undef T }; /// Prints a friendly string representation of \param _token. inline std::string formatToken(Token _token) { switch (_token) { #define T(name, string, precedence) case Token::name: return string; SOLT_TOKEN_LIST(T, T) #undef T default: // Token::NUM_TOKENS: return ""; } } } /** * The purpose of the ABI type is the storage of type information * retrieved while parsing a test. This information is used * for the conversion of human-readable function arguments and * return values to `bytes` and vice-versa. * Defaults to None, a 0-byte representation. 0-bytes * can also be interpreted as Failure, which means * either a REVERT or another EVM failure. */ struct ABIType { enum Type { None, Failure, Boolean, UnsignedDec, SignedDec, Hex, HexString, String }; enum Align { AlignLeft, AlignRight, AlignNone, }; explicit ABIType( Type _type, Align _align = ABIType::AlignRight, size_t _size = 32 ): type(_type), align(_align), size(_size) {} Type type = ABIType::None; Align align = ABIType::AlignRight; size_t size = 32; bool alignDeclared = false; }; /** * Helper that can hold format information retrieved * while scanning through a parameter list in soltest. */ struct FormatInfo { bool newline = false; }; /** * Parameter abstraction used for the encoding and decoding of * function parameter and expectation / return value lists. * A parameter list is usually a comma-separated list of literals. * It should not be possible to create a parameter holding * an identifier, but if so, the ABI type would be invalid. */ struct Parameter { enum Alignment { Left, Right, None, }; /// ABI encoded / decoded `bytes` of values. /// These `bytes` are used to pass values to function calls /// and also to store expected return vales. These are /// compared to the actual result of a function call /// and used for validating it. bytes rawBytes; /// Stores the raw string representation of this parameter. /// Used to print the unformatted arguments of a function call. std::string rawString; /// Types that were used to encode `rawBytes`. Expectations /// are usually comma separated literals. Their type is auto- /// detected and retained in order to format them later on. ABIType abiType = ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; /// Format info attached to the parameter. It handles newlines given /// in the declaration of it. FormatInfo format; /// Stores the parsed alignment, which can be either left(...) or right(...). Alignment alignment = Alignment::None; /// Compares _bytes to the bytes stored in this object. bool matchesBytes(bytes const& _bytes) const { return rawBytes == _bytes; } }; using ParameterList = std::vector; /** * Represents the expected result of a function call after it has been executed. This may be a single * return value or a comma-separated list of return values. It also contains the detected input * formats used to convert the values to `bytes` needed for the comparison with the actual result * of a call. In addition to that, it also stores the expected transaction status. * An optional comment can be assigned. */ struct FunctionCallExpectations { /// Representation of the comma-separated (or empty) list of expected result values /// attached to the function call object. It is checked against the actual result of /// a function call when used in test framework. ParameterList result; /// Expected status of the transaction. It can be either /// a REVERT or a different EVM failure (e.g. out-of-gas). bool failure = true; /// A Comment that can be attached to the expectations, /// that is retained and can be displayed. std::string comment; /// ABI encoded `bytes` of parsed expected return values. It is checked /// against the actual result of a function call when used in test framework. bytes rawBytes() const { bytes raw; for (auto const& param: result) raw += param.rawBytes; return raw; } }; /** * Represents the arguments passed to a function call. This can be a single * argument or a comma-separated list of arguments. It also contains the detected input * formats used to convert the arguments to `bytes` needed for the call. * An optional comment can be assigned. */ struct FunctionCallArgs { /// Types that were used to encode `rawBytes`. Parameters /// are usually comma separated literals. Their type is auto- /// detected and retained in order to format them later on. ParameterList parameters; /// A Comment that can be attached to the expectations, /// that is retained and can be displayed. std::string comment; /// ABI encoded `bytes` of parsed parameters. These `bytes` /// passed to the function call. bytes rawBytes() const { bytes raw; for (auto const& param: parameters) raw += param.rawBytes; return raw; } }; /// Units that can be used to express function value enum class FunctionValueUnit { Wei, Ether }; /// Holds value along with unit it was expressed in originally. /// @a value is always in wei - it is converted back when stringifying again. struct FunctionValue { u256 value; FunctionValueUnit unit = FunctionValueUnit::Wei; }; /** * Represents a function call read from an input stream. It contains the signature, the * arguments, an optional ether value and an expected execution result. */ struct FunctionCall { /// Signature of the function call, e.g. `f(uint256, uint256)`. std::string signature; /// Optional value that can be sent with the call. /// Value is expressed in wei, smallest unit of ether /// Value has a field unit which represents denomination on which value was expressed originally FunctionValue value; /// Object that holds all function parameters in their `bytes` /// representations given by the contract ABI. FunctionCallArgs arguments; /// Object that holds all function call expectation in /// their `bytes` representations given by the contract ABI. /// They are checked against the actual results and their /// `bytes` representation, as well as the transaction status. FunctionCallExpectations expectations; /// single / multi-line mode will be detected as follows: /// every newline (//) in source results in a function call /// that has its display mode set to multi-mode. Function and /// result parameter lists are an exception: a single parameter /// stores a format information that contains a newline definition. enum DisplayMode { SingleLine, MultiLine }; DisplayMode displayMode = DisplayMode::SingleLine; /// Marks this function call as the constructor. bool isConstructor = false; /// If this function call's signature has no name and no arguments, /// a low-level call with unstructured calldata will be issued. bool useCallWithoutSignature = false; /// Marks this function call as "short-handed", meaning /// no `->` declared. bool omitsArrow = true; /// Marks a library deployment call. bool isLibrary = false; }; }