chriseth
10 years ago
10 changed files with 867 additions and 55 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