Artur Zawłocki
10 years ago
13 changed files with 870 additions and 56 deletions
@ -0,0 +1,278 @@ |
|||||
|
|
||||
|
#include <libsolidity/InterfaceHandler.h> |
||||
|
#include <libsolidity/AST.h> |
||||
|
#include <libsolidity/CompilerStack.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
|
||||
|
/* -- public -- */ |
||||
|
|
||||
|
InterfaceHandler::InterfaceHandler() |
||||
|
{ |
||||
|
m_lastTag = DOCTAG_NONE; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(std::shared_ptr<ContractDefinition> _contractDef, |
||||
|
enum DocumentationType _type) |
||||
|
{ |
||||
|
switch(_type) |
||||
|
{ |
||||
|
case NATSPEC_USER: |
||||
|
return getUserDocumentation(_contractDef); |
||||
|
case NATSPEC_DEV: |
||||
|
return getDevDocumentation(_contractDef); |
||||
|
case ABI_INTERFACE: |
||||
|
return getABIInterface(_contractDef); |
||||
|
} |
||||
|
|
||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); |
||||
|
return nullptr; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(std::shared_ptr<ContractDefinition> _contractDef) |
||||
|
{ |
||||
|
Json::Value methods(Json::arrayValue); |
||||
|
|
||||
|
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) |
||||
|
{ |
||||
|
Json::Value method; |
||||
|
Json::Value inputs(Json::arrayValue); |
||||
|
Json::Value outputs(Json::arrayValue); |
||||
|
|
||||
|
auto populateParameters = [](std::vector<ASTPointer<VariableDeclaration>> const& _vars) |
||||
|
{ |
||||
|
Json::Value params(Json::arrayValue); |
||||
|
for (ASTPointer<VariableDeclaration> const& var: _vars) |
||||
|
{ |
||||
|
Json::Value input; |
||||
|
input["name"] = var->getName(); |
||||
|
input["type"] = var->getType()->toString(); |
||||
|
params.append(input); |
||||
|
} |
||||
|
return params; |
||||
|
}; |
||||
|
|
||||
|
method["name"] = f->getName(); |
||||
|
method["inputs"] = populateParameters(f->getParameters()); |
||||
|
method["outputs"] = populateParameters(f->getReturnParameters()); |
||||
|
methods.append(method); |
||||
|
} |
||||
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods))); |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(std::shared_ptr<ContractDefinition> _contractDef) |
||||
|
{ |
||||
|
Json::Value doc; |
||||
|
Json::Value methods(Json::objectValue); |
||||
|
|
||||
|
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) |
||||
|
{ |
||||
|
Json::Value user; |
||||
|
auto strPtr = f->getDocumentation(); |
||||
|
if (strPtr) |
||||
|
{ |
||||
|
resetUser(); |
||||
|
parseDocString(*strPtr); |
||||
|
if (!m_notice.empty()) |
||||
|
{// since @notice is the only user tag if missing function should not appear
|
||||
|
user["notice"] = Json::Value(m_notice); |
||||
|
methods[f->getName()] = user; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
doc["methods"] = methods; |
||||
|
|
||||
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc))); |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(std::shared_ptr<ContractDefinition> _contractDef) |
||||
|
{ |
||||
|
// LTODO: Somewhere in this function warnings for mismatch of param names
|
||||
|
// should be thrown
|
||||
|
Json::Value doc; |
||||
|
Json::Value methods(Json::objectValue); |
||||
|
|
||||
|
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) |
||||
|
{ |
||||
|
Json::Value method; |
||||
|
auto strPtr = f->getDocumentation(); |
||||
|
if (strPtr) |
||||
|
{ |
||||
|
resetDev(); |
||||
|
parseDocString(*strPtr); |
||||
|
|
||||
|
if (!m_dev.empty()) |
||||
|
method["details"] = Json::Value(m_dev); |
||||
|
Json::Value params(Json::objectValue); |
||||
|
for (auto const& pair: m_params) |
||||
|
params[pair.first] = pair.second; |
||||
|
|
||||
|
if (!m_params.empty()) |
||||
|
method["params"] = params; |
||||
|
if (!m_return.empty()) |
||||
|
method["return"] = m_return; |
||||
|
|
||||
|
if (!method.empty()) // add the function, only if we have any documentation to add
|
||||
|
methods[f->getName()] = method; |
||||
|
} |
||||
|
} |
||||
|
doc["methods"] = methods; |
||||
|
|
||||
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc))); |
||||
|
} |
||||
|
|
||||
|
/* -- private -- */ |
||||
|
void InterfaceHandler::resetUser() |
||||
|
{ |
||||
|
m_notice.clear(); |
||||
|
} |
||||
|
|
||||
|
void InterfaceHandler::resetDev() |
||||
|
{ |
||||
|
m_dev.clear(); |
||||
|
m_return.clear(); |
||||
|
m_params.clear(); |
||||
|
} |
||||
|
|
||||
|
static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, |
||||
|
std::string::const_iterator _end) |
||||
|
{ |
||||
|
return (_nlPos == _end) ? _end : ++_nlPos; |
||||
|
} |
||||
|
|
||||
|
std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end, |
||||
|
std::string& _tagString, |
||||
|
enum DocTagType _tagType) |
||||
|
{ |
||||
|
auto nlPos = std::find(_pos, _end, '\n'); |
||||
|
std::copy(_pos, nlPos, back_inserter(_tagString)); |
||||
|
m_lastTag = _tagType; |
||||
|
return skipLineOrEOS(nlPos, _end); |
||||
|
} |
||||
|
|
||||
|
std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end) |
||||
|
{ |
||||
|
// find param name
|
||||
|
auto currPos = std::find(_pos, _end, ' '); |
||||
|
if (currPos == _end) |
||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end))); |
||||
|
|
||||
|
|
||||
|
auto paramName = std::string(_pos, currPos); |
||||
|
|
||||
|
currPos += 1; |
||||
|
auto nlPos = std::find(currPos, _end, '\n'); |
||||
|
auto paramDesc = std::string(currPos, nlPos); |
||||
|
m_params.push_back(std::make_pair(paramName, paramDesc)); |
||||
|
|
||||
|
m_lastTag = DOCTAG_PARAM; |
||||
|
return skipLineOrEOS(nlPos, _end); |
||||
|
} |
||||
|
|
||||
|
std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end) |
||||
|
{ |
||||
|
// Should never be called with an empty vector
|
||||
|
if (asserts(!m_params.empty())) |
||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); |
||||
|
|
||||
|
auto pair = m_params.back(); |
||||
|
pair.second += " "; |
||||
|
auto nlPos = std::find(_pos, _end, '\n'); |
||||
|
std::copy(_pos, nlPos, back_inserter(pair.second)); |
||||
|
|
||||
|
m_params.at(m_params.size() - 1) = pair; |
||||
|
|
||||
|
return skipLineOrEOS(nlPos, _end); |
||||
|
} |
||||
|
|
||||
|
std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end, |
||||
|
std::string const& _tag) |
||||
|
{ |
||||
|
// LTODO: need to check for @(start of a tag) between here and the end of line
|
||||
|
// for all cases
|
||||
|
if (m_lastTag == DOCTAG_NONE || _tag != "") |
||||
|
{ |
||||
|
if (_tag == "dev") |
||||
|
return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV); |
||||
|
else if (_tag == "notice") |
||||
|
return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE); |
||||
|
else if (_tag == "return") |
||||
|
return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN); |
||||
|
else if (_tag == "param") |
||||
|
return parseDocTagParam(_pos, _end); |
||||
|
else |
||||
|
{ |
||||
|
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered")); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
return appendDocTag(_pos, _end); |
||||
|
} |
||||
|
|
||||
|
std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end) |
||||
|
{ |
||||
|
switch (m_lastTag) |
||||
|
{ |
||||
|
case DOCTAG_DEV: |
||||
|
m_dev += " "; |
||||
|
return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV); |
||||
|
case DOCTAG_NOTICE: |
||||
|
m_notice += " "; |
||||
|
return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE); |
||||
|
case DOCTAG_RETURN: |
||||
|
m_return += " "; |
||||
|
return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN); |
||||
|
case DOCTAG_PARAM: |
||||
|
return appendDocTagParam(_pos, _end); |
||||
|
default: |
||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end) |
||||
|
{ |
||||
|
auto spacePos = std::find(_pos, _end, ' '); |
||||
|
auto nlPos = std::find(_pos, _end, '\n'); |
||||
|
return (spacePos < nlPos) ? spacePos : nlPos; |
||||
|
} |
||||
|
|
||||
|
void InterfaceHandler::parseDocString(std::string const& _string) |
||||
|
{ |
||||
|
auto currPos = _string.begin(); |
||||
|
auto end = _string.end(); |
||||
|
|
||||
|
while (currPos != end) |
||||
|
{ |
||||
|
auto tagPos = std::find(currPos, end, '@'); |
||||
|
auto nlPos = std::find(currPos, end, '\n'); |
||||
|
|
||||
|
if (tagPos != end && tagPos < nlPos) |
||||
|
{ |
||||
|
// we found a tag
|
||||
|
auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end); |
||||
|
if (tagNameEndPos == end) |
||||
|
BOOST_THROW_EXCEPTION(DocstringParsingError() << |
||||
|
errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); |
||||
|
|
||||
|
currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos)); |
||||
|
} |
||||
|
else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag
|
||||
|
currPos = appendDocTag(currPos + 1, end); |
||||
|
else if (currPos != end) // skip the line if a newline was found
|
||||
|
currPos = nlPos + 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} //solidity NS
|
||||
|
} // dev NS
|
@ -0,0 +1,110 @@ |
|||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum 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. |
||||
|
|
||||
|
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/**
|
||||
|
* @author Lefteris <lefteris@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Takes the parsed AST and produces the Natspec |
||||
|
* documentation and the ABI interface |
||||
|
* https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format
|
||||
|
* |
||||
|
* Can generally deal with JSON files |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <string> |
||||
|
#include <memory> |
||||
|
#include <jsonrpc/json/json.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
|
||||
|
// Forward declarations
|
||||
|
class ContractDefinition; |
||||
|
enum DocumentationType: unsigned short; |
||||
|
|
||||
|
enum DocTagType |
||||
|
{ |
||||
|
DOCTAG_NONE = 0, |
||||
|
DOCTAG_DEV, |
||||
|
DOCTAG_NOTICE, |
||||
|
DOCTAG_PARAM, |
||||
|
DOCTAG_RETURN |
||||
|
}; |
||||
|
|
||||
|
class InterfaceHandler |
||||
|
{ |
||||
|
public: |
||||
|
InterfaceHandler(); |
||||
|
|
||||
|
/// Get the given type of documentation
|
||||
|
/// @param _contractDef The contract definition
|
||||
|
/// @param _type The type of the documentation. Can be one of the
|
||||
|
/// types provided by @c DocumentationType
|
||||
|
/// @return A unique pointer contained string with the json
|
||||
|
/// representation of provided type
|
||||
|
std::unique_ptr<std::string> getDocumentation(std::shared_ptr<ContractDefinition> _contractDef, |
||||
|
enum DocumentationType _type); |
||||
|
/// Get the ABI Interface of the contract
|
||||
|
/// @param _contractDef The contract definition
|
||||
|
/// @return A unique pointer contained string with the json
|
||||
|
/// representation of the contract's ABI Interface
|
||||
|
std::unique_ptr<std::string> getABIInterface(std::shared_ptr<ContractDefinition> _contractDef); |
||||
|
/// Get the User documentation of the contract
|
||||
|
/// @param _contractDef The contract definition
|
||||
|
/// @return A unique pointer contained string with the json
|
||||
|
/// representation of the contract's user documentation
|
||||
|
std::unique_ptr<std::string> getUserDocumentation(std::shared_ptr<ContractDefinition> _contractDef); |
||||
|
/// Get the Developer's documentation of the contract
|
||||
|
/// @param _contractDef The contract definition
|
||||
|
/// @return A unique pointer contained string with the json
|
||||
|
/// representation of the contract's developer documentation
|
||||
|
std::unique_ptr<std::string> getDevDocumentation(std::shared_ptr<ContractDefinition> _contractDef); |
||||
|
|
||||
|
private: |
||||
|
void resetUser(); |
||||
|
void resetDev(); |
||||
|
|
||||
|
std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end, |
||||
|
std::string& _tagString, |
||||
|
enum DocTagType _tagType); |
||||
|
std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end); |
||||
|
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end); |
||||
|
void parseDocString(std::string const& _string); |
||||
|
std::string::const_iterator appendDocTag(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end); |
||||
|
std::string::const_iterator parseDocTag(std::string::const_iterator _pos, |
||||
|
std::string::const_iterator _end, |
||||
|
std::string const& _tag); |
||||
|
|
||||
|
Json::StyledWriter m_writer; |
||||
|
|
||||
|
// internal state
|
||||
|
enum DocTagType m_lastTag; |
||||
|
std::string m_notice; |
||||
|
std::string m_dev; |
||||
|
std::string m_return; |
||||
|
std::vector<std::pair<std::string, std::string>> m_params; |
||||
|
}; |
||||
|
|
||||
|
} //solidity NS
|
||||
|
} // dev NS
|
@ -0,0 +1,400 @@ |
|||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum 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. |
||||
|
|
||||
|
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/**
|
||||
|
* @author Lefteris Karapetsas <lefteris@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Unit tests for the solidity compiler JSON Interface output. |
||||
|
*/ |
||||
|
|
||||
|
#include <boost/test/unit_test.hpp> |
||||
|
#include <libsolidity/CompilerStack.h> |
||||
|
#include <jsonrpc/json/json.h> |
||||
|
#include <libdevcore/Exceptions.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
namespace test |
||||
|
{ |
||||
|
|
||||
|
class DocumentationChecker |
||||
|
{ |
||||
|
public: |
||||
|
void checkNatspec(std::string const& _code, |
||||
|
std::string const& _expectedDocumentationString, |
||||
|
bool _userDocumentation) |
||||
|
{ |
||||
|
std::string generatedDocumentationString; |
||||
|
try |
||||
|
{ |
||||
|
m_compilerStack.parse(_code); |
||||
|
} |
||||
|
catch (const std::exception& e) |
||||
|
{ |
||||
|
std::string const* extra = boost::get_error_info<errinfo_comment>(e); |
||||
|
std::string msg = std::string("Parsing contract failed with: ") + |
||||
|
e.what() + std::string("\n"); |
||||
|
if (extra) |
||||
|
msg += *extra; |
||||
|
BOOST_FAIL(msg); |
||||
|
} |
||||
|
|
||||
|
if (_userDocumentation) |
||||
|
generatedDocumentationString = m_compilerStack.getJsonDocumentation(NATSPEC_USER); |
||||
|
else |
||||
|
generatedDocumentationString = m_compilerStack.getJsonDocumentation(NATSPEC_DEV); |
||||
|
Json::Value generatedDocumentation; |
||||
|
m_reader.parse(generatedDocumentationString, generatedDocumentation); |
||||
|
Json::Value expectedDocumentation; |
||||
|
m_reader.parse(_expectedDocumentationString, expectedDocumentation); |
||||
|
BOOST_CHECK_MESSAGE(expectedDocumentation == generatedDocumentation, |
||||
|
"Expected " << _expectedDocumentationString << |
||||
|
"\n but got:\n" << generatedDocumentationString); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
CompilerStack m_compilerStack; |
||||
|
Json::Reader m_reader; |
||||
|
}; |
||||
|
|
||||
|
BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker) |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(user_basic_test) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @notice Multiplies `a` by 7\n" |
||||
|
" function mul(uint a) returns(uint d) { return a * 7; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, true); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @notice Multiplies `a` by 7\n" |
||||
|
" /// @dev Multiplies a number by 7\n" |
||||
|
" function mul(uint a) returns(uint d) { return a * 7; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* devNatspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7\"\n" |
||||
|
" }\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
char const* userNatspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, devNatspec, false); |
||||
|
checkNatspec(sourceCode, userNatspec, true); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(user_multiline_comment) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @notice Multiplies `a` by 7\n" |
||||
|
" /// and then adds `b`\n" |
||||
|
" function mul_and_add(uint a, uint256 b) returns(uint256 d)\n" |
||||
|
" {\n" |
||||
|
" return (a * 7) + b;\n" |
||||
|
" }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, true); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(user_multiple_functions) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @notice Multiplies `a` by 7 and then adds `b`\n" |
||||
|
" function mul_and_add(uint a, uint256 b) returns(uint256 d)\n" |
||||
|
" {\n" |
||||
|
" return (a * 7) + b;\n" |
||||
|
" }\n" |
||||
|
"\n" |
||||
|
" /// @notice Divides `input` by `div`\n" |
||||
|
" function divide(uint input, uint div) returns(uint d)\n" |
||||
|
" {\n" |
||||
|
" return input / div;\n" |
||||
|
" }\n" |
||||
|
" /// @notice Subtracts 3 from `input`\n" |
||||
|
" function sub(int input) returns(int d)\n" |
||||
|
" {\n" |
||||
|
" return input - 3;\n" |
||||
|
" }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," |
||||
|
" \"divide\":{ \"notice\": \"Divides `input` by `div`\"}," |
||||
|
" \"sub\":{ \"notice\": \"Subtracts 3 from `input`\"}" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, true); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(user_empty_contract) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{\"methods\":{} }"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, true); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_and_user_no_doc) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" function mul(uint a) returns(uint d) { return a * 7; }\n" |
||||
|
" function sub(int input) returns(int d)\n" |
||||
|
" {\n" |
||||
|
" return input - 3;\n" |
||||
|
" }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* devNatspec = "{\"methods\":{}}"; |
||||
|
|
||||
|
char const* userNatspec = "{\"methods\":{}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, devNatspec, false); |
||||
|
checkNatspec(sourceCode, userNatspec, true); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_desc_after_nl) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev\n" |
||||
|
" /// Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \" Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" }\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_multiple_params) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" }\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter starts here.\n" |
||||
|
" /// Since it's a really complicated parameter we need 2 lines\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" }\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_multiple_functions) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
" \n" |
||||
|
" /// @dev Divides 2 numbers\n" |
||||
|
" /// @param input Documentation for the input parameter\n" |
||||
|
" /// @param div Documentation for the div parameter\n" |
||||
|
" function divide(uint input, uint div) returns(uint d)\n" |
||||
|
" {\n" |
||||
|
" return input / div;\n" |
||||
|
" }\n" |
||||
|
" /// @dev Subtracts 3 from `input`\n" |
||||
|
" /// @param input Documentation for the input parameter\n" |
||||
|
" function sub(int input) returns(int d)\n" |
||||
|
" {\n" |
||||
|
" return input - 3;\n" |
||||
|
" }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" }\n" |
||||
|
" },\n" |
||||
|
" \"divide\":{ \n" |
||||
|
" \"details\": \"Divides 2 numbers\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"input\": \"Documentation for the input parameter\",\n" |
||||
|
" \"div\": \"Documentation for the div parameter\"\n" |
||||
|
" }\n" |
||||
|
" },\n" |
||||
|
" \"sub\":{ \n" |
||||
|
" \"details\": \"Subtracts 3 from `input`\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"input\": \"Documentation for the input parameter\"\n" |
||||
|
" }\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_return) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter starts here.\n" |
||||
|
" /// Since it's a really complicated parameter we need 2 lines\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" /// @return The result of the multiplication\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" },\n" |
||||
|
" \"return\": \"The result of the multiplication\"\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter starts here.\n" |
||||
|
" /// Since it's a really complicated parameter we need 2 lines\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" /// @return\n" |
||||
|
" /// The result of the multiplication\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" },\n" |
||||
|
" \"return\": \" The result of the multiplication\"\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE(dev_multiline_return) |
||||
|
{ |
||||
|
char const* sourceCode = "contract test {\n" |
||||
|
" /// @dev Multiplies a number by 7 and adds second parameter\n" |
||||
|
" /// @param a Documentation for the first parameter starts here.\n" |
||||
|
" /// Since it's a really complicated parameter we need 2 lines\n" |
||||
|
" /// @param second Documentation for the second parameter\n" |
||||
|
" /// @return The result of the multiplication\n" |
||||
|
" /// and cookies with nutella\n" |
||||
|
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" |
||||
|
"}\n"; |
||||
|
|
||||
|
char const* natspec = "{" |
||||
|
"\"methods\":{" |
||||
|
" \"mul\":{ \n" |
||||
|
" \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" |
||||
|
" \"params\": {\n" |
||||
|
" \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" |
||||
|
" \"second\": \"Documentation for the second parameter\"\n" |
||||
|
" },\n" |
||||
|
" \"return\": \"The result of the multiplication and cookies with nutella\"\n" |
||||
|
" }\n" |
||||
|
"}}"; |
||||
|
|
||||
|
checkNatspec(sourceCode, natspec, false); |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_SUITE_END() |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue