1 /*
2 	This file is part of solidity.
3 
4 	solidity is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation, either version 3 of the License, or
7 	(at your option) any later version.
8 
9 	solidity is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 /**
18  * @author Lefteris Karapetsas <lefteris@ethdev.com>
19  * @date 2014
20  * Unit tests for the solidity compiler JSON Interface output.
21  */
22 
23 #include <test/Common.h>
24 #include <string>
25 #include <libsolutil/JSON.h>
26 #include <libsolidity/interface/CompilerStack.h>
27 #include <liblangutil/Exceptions.h>
28 #include <libsolutil/Exceptions.h>
29 #include <libsolidity/interface/Natspec.h>
30 
31 #include <boost/test/unit_test.hpp>
32 
33 using namespace solidity::langutil;
34 
35 namespace solidity::frontend::test
36 {
37 
38 class DocumentationChecker
39 {
40 public:
checkNatspec(std::string const & _code,std::string const & _contractName,std::string const & _expectedDocumentationString,bool _userDocumentation)41 	void checkNatspec(
42 		std::string const& _code,
43 		std::string const& _contractName,
44 		std::string const& _expectedDocumentationString,
45 		bool _userDocumentation
46 	)
47 	{
48 		m_compilerStack.reset();
49 		m_compilerStack.setSources({{"", "pragma solidity >=0.0;\n" + _code}});
50 		m_compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
51 		BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
52 
53 		Json::Value generatedDocumentation;
54 		if (_userDocumentation)
55 			generatedDocumentation = m_compilerStack.natspecUser(_contractName);
56 		else
57 			generatedDocumentation = m_compilerStack.natspecDev(_contractName);
58 		Json::Value expectedDocumentation;
59 		util::jsonParseStrict(_expectedDocumentationString, expectedDocumentation);
60 
61 		expectedDocumentation["version"] = Json::Value(Natspec::c_natspecVersion);
62 		expectedDocumentation["kind"] = Json::Value(_userDocumentation ? "user" : "dev");
63 
64 		BOOST_CHECK_MESSAGE(
65 			expectedDocumentation == generatedDocumentation,
66 			"Expected:\n" << util::jsonPrettyPrint(expectedDocumentation) <<
67 			"\n but got:\n" << util::jsonPrettyPrint(generatedDocumentation)
68 		);
69 	}
70 
expectNatspecError(std::string const & _code)71 	void expectNatspecError(std::string const& _code)
72 	{
73 		m_compilerStack.reset();
74 		m_compilerStack.setSources({{"", "pragma solidity >=0.0;\n" + _code}});
75 		m_compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
76 		BOOST_CHECK(!m_compilerStack.parseAndAnalyze());
77 		BOOST_REQUIRE(Error::containsErrorOfType(m_compilerStack.errors(), Error::Type::DocstringParsingError));
78 	}
79 
80 protected:
81 	CompilerStack m_compilerStack;
82 };
83 
BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON,DocumentationChecker)84 BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker)
85 
86 BOOST_AUTO_TEST_CASE(user_empty_natspec_test)
87 {
88 	char const* sourceCode = R"(
89 		contract test {
90 			///
91 			///
92 			function f() public {
93 			}
94 		}
95 	)";
96 
97 	char const* natspec = R"(
98 	{
99 		"methods": {}
100 	}
101 	)";
102 
103 	checkNatspec(sourceCode, "test", natspec, true);
104 }
105 
BOOST_AUTO_TEST_CASE(user_newline_break)106 BOOST_AUTO_TEST_CASE(user_newline_break)
107 {
108 	char const* sourceCode = R"(
109 		contract test {
110 			///
111 			/// @notice hello
112 
113 			/// @notice world
114 			function f() public {
115 			}
116 		}
117 	)";
118 
119 	char const* natspec = R"ABCDEF(
120 	{
121 		"methods": {
122 			"f()":
123 			{
124 			"notice": "world"
125 			}
126 		}
127 	}
128 	)ABCDEF";
129 
130 	checkNatspec(sourceCode, "test", natspec, true);
131 }
132 
BOOST_AUTO_TEST_CASE(user_multiline_empty_lines)133 BOOST_AUTO_TEST_CASE(user_multiline_empty_lines)
134 {
135 	char const* sourceCode = R"(
136 	contract test {
137 		/**
138 		 *
139 		 *
140 		 * @notice hello world
141 		 */
142 		function f() public {
143 		}
144 	}
145 	)";
146 
147 	char const* natspec = R"ABCDEF(
148 	{
149 		"methods": {
150 			"f()": {
151 				"notice": "hello world"
152 			}
153 		}
154 	}
155 	)ABCDEF";
156 
157 	checkNatspec(sourceCode, "test", natspec, true);
158 }
159 
160 
BOOST_AUTO_TEST_CASE(user_basic_test)161 BOOST_AUTO_TEST_CASE(user_basic_test)
162 {
163 	char const* sourceCode = R"(
164 		contract test {
165 			/// @notice Multiplies `a` by 7
166 			function mul(uint a) public returns(uint d) { return a * 7; }
167 		}
168 	)";
169 
170 	char const* natspec = "{"
171 	"\"methods\":{"
172 	"    \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}"
173 	"}}";
174 
175 	checkNatspec(sourceCode, "test", natspec, true);
176 }
177 
BOOST_AUTO_TEST_CASE(dev_and_user_basic_test)178 BOOST_AUTO_TEST_CASE(dev_and_user_basic_test)
179 {
180 	char const* sourceCode = R"(
181 		contract test {
182 			/// @notice Multiplies `a` by 7
183 			/// @dev Multiplies a number by 7
184 			function mul(uint a) public returns (uint d) { return a * 7; }
185 		}
186 	)";
187 
188 	char const* devNatspec = "{"
189 	"\"methods\":{"
190 	"    \"mul(uint256)\":{ \n"
191 	"        \"details\": \"Multiplies a number by 7\"\n"
192 	"        }\n"
193 	"    }\n"
194 	"}}";
195 
196 	char const* userNatspec = "{"
197 	"\"methods\":{"
198 	"    \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}"
199 	"}}";
200 
201 	checkNatspec(sourceCode, "test", devNatspec, false);
202 	checkNatspec(sourceCode, "test", userNatspec, true);
203 }
204 
BOOST_AUTO_TEST_CASE(user_multiline_comment)205 BOOST_AUTO_TEST_CASE(user_multiline_comment)
206 {
207 	char const* sourceCode = R"(
208 		contract test {
209 			/// @notice Multiplies `a` by 7
210 			/// and then adds `b`
211 			function mul_and_add(uint a, uint256 b) public returns (uint256 d) {
212 				return (a * 7) + b;
213 			}
214 		}
215 	)";
216 
217 	char const* natspec = "{"
218 	"\"methods\":{"
219 	"    \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}"
220 	"}}";
221 
222 	checkNatspec(sourceCode, "test", natspec, true);
223 }
224 
BOOST_AUTO_TEST_CASE(user_multiple_functions)225 BOOST_AUTO_TEST_CASE(user_multiple_functions)
226 {
227 	char const* sourceCode = R"(
228 		contract test {
229 			/// @notice Multiplies `a` by 7 and then adds `b`
230 			function mul_and_add(uint a, uint256 b) public returns (uint256 d) {
231 				return (a * 7) + b;
232 			}
233 
234 			/// @notice Divides `input` by `div`
235 			function divide(uint input, uint div) public returns (uint d) {
236 				return input / div;
237 			}
238 
239 			/// @notice Subtracts 3 from `input`
240 			function sub(int input) public returns (int d) {
241 				return input - 3;
242 			}
243 		}
244 	)";
245 
246 	char const* natspec = "{"
247 	"\"methods\":{"
248 	"    \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"},"
249 	"    \"divide(uint256,uint256)\":{ \"notice\": \"Divides `input` by `div`\"},"
250 	"    \"sub(int256)\":{ \"notice\": \"Subtracts 3 from `input`\"}"
251 	"}}";
252 
253 	checkNatspec(sourceCode, "test", natspec, true);
254 }
255 
BOOST_AUTO_TEST_CASE(user_empty_contract)256 BOOST_AUTO_TEST_CASE(user_empty_contract)
257 {
258 	char const* sourceCode = R"(
259 		contract test { }
260 	)";
261 
262 	char const* natspec = "{\"methods\":{} }";
263 
264 	checkNatspec(sourceCode, "test", natspec, true);
265 }
266 
BOOST_AUTO_TEST_CASE(dev_and_user_no_doc)267 BOOST_AUTO_TEST_CASE(dev_and_user_no_doc)
268 {
269 	char const* sourceCode = R"(
270 		contract test {
271 			function mul(uint a) public returns (uint d) {
272 				return a * 7;
273 			}
274 			function sub(int input) public returns (int d) {
275 				return input - 3;
276 			}
277 		}
278 	)";
279 
280 	char const* devNatspec = "{\"methods\":{}}";
281 	char const* userNatspec = "{\"methods\":{}}";
282 
283 	checkNatspec(sourceCode, "test", devNatspec, false);
284 	checkNatspec(sourceCode, "test", userNatspec, true);
285 }
286 
BOOST_AUTO_TEST_CASE(public_state_variable)287 BOOST_AUTO_TEST_CASE(public_state_variable)
288 {
289 	char const* sourceCode = R"(
290 		contract test {
291 			/// @notice example of notice
292 			/// @dev example of dev
293 			/// @return returns state
294 			uint public state;
295 		}
296 	)";
297 
298 	char const* devDoc = R"R(
299 	{
300 		"methods" : {},
301 		"stateVariables" :
302 		{
303 			"state" :
304 			{
305 				"details" : "example of dev",
306 				"return" : "returns state",
307 				"returns" :
308 				{
309 					"_0" : "returns state"
310 				}
311 			}
312 		}
313 	}
314 	)R";
315 	checkNatspec(sourceCode, "test", devDoc, false);
316 
317 	char const* userDoc = R"R(
318 	{
319 		"methods" :
320 		{
321 			"state()" :
322 			{
323 				"notice": "example of notice"
324 			}
325 		}
326 	}
327 	)R";
328 	checkNatspec(sourceCode, "test", userDoc, true);
329 }
330 
BOOST_AUTO_TEST_CASE(public_state_variable_struct)331 BOOST_AUTO_TEST_CASE(public_state_variable_struct)
332 {
333 	char const* sourceCode = R"(
334 		contract Bank {
335 			struct Coin {
336 				string observeGraphicURL;
337 				string reverseGraphicURL;
338 			}
339 
340 			/// @notice Get the n-th coin I own
341 			/// @return observeGraphicURL Front pic
342 			/// @return reverseGraphicURL Back pic
343 			Coin[] public coinStack;
344 		}
345 	)";
346 
347 	char const* devDoc = R"R(
348 	{
349 		"methods" : {},
350 		"stateVariables" :
351 		{
352 			"coinStack" :
353 			{
354 				"returns" :
355 				{
356 					"observeGraphicURL" : "Front pic",
357 					"reverseGraphicURL" : "Back pic"
358 				}
359 			}
360 		}
361 	}
362 	)R";
363 	checkNatspec(sourceCode, "Bank", devDoc, false);
364 
365 	char const* userDoc = R"R(
366 	{
367 		"methods" :
368 		{
369 			"coinStack(uint256)" :
370 			{
371 				"notice": "Get the n-th coin I own"
372 			}
373 		}
374 	}
375 	)R";
376 	checkNatspec(sourceCode, "Bank", userDoc, true);
377 }
378 
BOOST_AUTO_TEST_CASE(public_state_variable_struct_repeated)379 BOOST_AUTO_TEST_CASE(public_state_variable_struct_repeated)
380 {
381 	char const* sourceCode = R"(
382 		contract Bank {
383 			struct Coin {
384 				string obverseGraphicURL;
385 				string reverseGraphicURL;
386 			}
387 
388 			/// @notice Get the n-th coin I own
389 			/// @return obverseGraphicURL Front pic
390 			/// @return obverseGraphicURL Front pic
391 			Coin[] public coinStack;
392 		}
393 	)";
394 
395 	expectNatspecError(sourceCode);
396 }
397 
BOOST_AUTO_TEST_CASE(private_state_variable)398 BOOST_AUTO_TEST_CASE(private_state_variable)
399 {
400 	char const* sourceCode = R"(
401 		contract test {
402 			/// @dev example of dev
403 			uint private state;
404 		}
405 	)";
406 
407 	char const* devDoc = R"(
408 	{
409 		"methods" : {},
410 		"stateVariables" :
411 		{
412 			"state" :
413 			{
414 				"details" : "example of dev"
415 			}
416 		}
417 	}
418 	)";
419 	checkNatspec(sourceCode, "test", devDoc, false);
420 
421 	char const* userDoc = R"(
422 	{
423 		"methods":{}
424 	}
425 	)";
426 	checkNatspec(sourceCode, "test", userDoc, true);
427 }
428 
BOOST_AUTO_TEST_CASE(event)429 BOOST_AUTO_TEST_CASE(event)
430 {
431 	char const* sourceCode = R"(
432 		contract ERC20 {
433 			/// @notice This event is emitted when a transfer occurs.
434 			/// @param from The source account.
435 			/// @param to The destination account.
436 			/// @param amount The amount.
437 			/// @dev A test case!
438 			event Transfer(address indexed from, address indexed to, uint amount);
439 		}
440 	)";
441 
442 	char const* devDoc = R"ABCDEF(
443 	{
444 		"events":
445 		{
446 			"Transfer(address,address,uint256)":
447 			{
448 				"details": "A test case!",
449 				"params":
450 				{
451 					"amount": "The amount.", "from": "The source account.", "to": "The destination account."
452 				}
453 			}
454 		},
455 		"methods": {}
456 	}
457 	)ABCDEF";
458 	checkNatspec(sourceCode, "ERC20", devDoc, false);
459 
460 	char const* userDoc = R"ABCDEF(
461 	{
462 		"events":
463 		{
464 			"Transfer(address,address,uint256)":
465 			{
466 				"notice": "This event is emitted when a transfer occurs."
467 			}
468 		},
469 		"methods": {}
470 	}
471 	)ABCDEF";
472 	checkNatspec(sourceCode, "ERC20", userDoc, true);
473 }
474 
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)475 BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
476 {
477 	char const* sourceCode = R"(
478 		contract test {
479 			/// @dev
480 			/// Multiplies a number by 7 and adds second parameter
481 			/// @param a Documentation for the first parameter
482 			/// @param second Documentation for the second parameter
483 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
484 		}
485 	)";
486 
487 	char const* natspec = "{"
488 	"\"methods\":{"
489 	"    \"mul(uint256,uint256)\":{ \n"
490 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
491 	"        \"params\": {\n"
492 	"            \"a\": \"Documentation for the first parameter\",\n"
493 	"            \"second\": \"Documentation for the second parameter\"\n"
494 	"        }\n"
495 	"    }\n"
496 	"}}";
497 
498 	checkNatspec(sourceCode, "test", natspec, false);
499 }
500 
BOOST_AUTO_TEST_CASE(dev_multiple_params)501 BOOST_AUTO_TEST_CASE(dev_multiple_params)
502 {
503 	char const* sourceCode = R"(
504 		contract test {
505 			/// @dev Multiplies a number by 7 and adds second parameter
506 			/// @param a Documentation for the first parameter
507 			/// @param second Documentation for the second parameter
508 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
509 		}
510 	)";
511 
512 	char const* natspec = "{"
513 	"\"methods\":{"
514 	"    \"mul(uint256,uint256)\":{ \n"
515 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
516 	"        \"params\": {\n"
517 	"            \"a\": \"Documentation for the first parameter\",\n"
518 	"            \"second\": \"Documentation for the second parameter\"\n"
519 	"        }\n"
520 	"    }\n"
521 	"}}";
522 
523 	checkNatspec(sourceCode, "test", natspec, false);
524 }
525 
BOOST_AUTO_TEST_CASE(dev_multiple_params_mixed_whitespace)526 BOOST_AUTO_TEST_CASE(dev_multiple_params_mixed_whitespace)
527 {
528 	char const* sourceCode = "contract test {\n"
529 	"  /// @dev	 Multiplies a number by 7 and adds second parameter\n"
530 	"  /// @param 	 a Documentation for the first parameter\n"
531 	"  /// @param	 second			 Documentation for the second parameter\n"
532 	"  function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }\n"
533 	"}\n";
534 
535 	char const* natspec = "{"
536 	"\"methods\":{"
537 	"    \"mul(uint256,uint256)\":{ \n"
538 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
539 	"        \"params\": {\n"
540 	"            \"a\": \"Documentation for the first parameter\",\n"
541 	"            \"second\": \"Documentation for the second parameter\"\n"
542 	"        }\n"
543 	"    }\n"
544 	"}}";
545 
546 	checkNatspec(sourceCode, "test", natspec, false);
547 }
548 
BOOST_AUTO_TEST_CASE(dev_mutiline_param_description)549 BOOST_AUTO_TEST_CASE(dev_mutiline_param_description)
550 {
551 	char const* sourceCode = R"(
552 		contract test {
553 			/// @dev Multiplies a number by 7 and adds second parameter
554 			/// @param a Documentation for the first parameter starts here.
555 			/// Since it's a really complicated parameter we need 2 lines
556 			/// @param second Documentation for the second parameter
557 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
558 		}
559 	)";
560 
561 	char const* natspec = "{"
562 	"\"methods\":{"
563 	"    \"mul(uint256,uint256)\":{ \n"
564 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
565 	"        \"params\": {\n"
566 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
567 	"            \"second\": \"Documentation for the second parameter\"\n"
568 	"        }\n"
569 	"    }\n"
570 	"}}";
571 
572 	checkNatspec(sourceCode, "test", natspec, false);
573 }
574 
BOOST_AUTO_TEST_CASE(dev_multiple_functions)575 BOOST_AUTO_TEST_CASE(dev_multiple_functions)
576 {
577 	char const* sourceCode = R"(
578 		contract test {
579 			/// @dev Multiplies a number by 7 and adds second parameter
580 			/// @param a Documentation for the first parameter
581 			/// @param second Documentation for the second parameter
582 			function mul(uint a, uint second) public returns (uint d) {
583 				return a * 7 + second;
584 			}
585 			/// @dev Divides 2 numbers
586 			/// @param input Documentation for the input parameter
587 			/// @param div Documentation for the div parameter
588 			function divide(uint input, uint div) public returns (uint d) {
589 				return input / div;
590 			}
591 			/// @dev Subtracts 3 from `input`
592 			/// @param input Documentation for the input parameter
593 			function sub(int input) public returns (int d) {
594 				return input - 3;
595 			}
596 		}
597 	)";
598 
599 	char const* natspec = "{"
600 	"\"methods\":{"
601 	"    \"mul(uint256,uint256)\":{ \n"
602 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
603 	"        \"params\": {\n"
604 	"            \"a\": \"Documentation for the first parameter\",\n"
605 	"            \"second\": \"Documentation for the second parameter\"\n"
606 	"        }\n"
607 	"    },\n"
608 	"    \"divide(uint256,uint256)\":{ \n"
609 	"        \"details\": \"Divides 2 numbers\",\n"
610 	"        \"params\": {\n"
611 	"            \"input\": \"Documentation for the input parameter\",\n"
612 	"            \"div\": \"Documentation for the div parameter\"\n"
613 	"        }\n"
614 	"    },\n"
615 	"    \"sub(int256)\":{ \n"
616 	"        \"details\": \"Subtracts 3 from `input`\",\n"
617 	"        \"params\": {\n"
618 	"            \"input\": \"Documentation for the input parameter\"\n"
619 	"        }\n"
620 	"    }\n"
621 	"}}";
622 
623 	checkNatspec(sourceCode, "test", natspec, false);
624 }
625 
BOOST_AUTO_TEST_CASE(dev_return_no_params)626 BOOST_AUTO_TEST_CASE(dev_return_no_params)
627 {
628 	char const* sourceCode = R"(
629 		contract test {
630 			/// @return d The result of the multiplication
631 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
632 		}
633 	)";
634 
635 	char const* natspec = R"ABCDEF(
636 	{
637 		"methods": {
638 			"mul(uint256,uint256)": {
639 				"returns": { "d": "The result of the multiplication"
640 			}
641 		}
642 	})ABCDEF";
643 
644 	checkNatspec(sourceCode, "test", natspec, false);
645 }
646 
BOOST_AUTO_TEST_CASE(dev_return)647 BOOST_AUTO_TEST_CASE(dev_return)
648 {
649 	char const* sourceCode = R"(
650 		contract test {
651 			/// @dev Multiplies a number by 7 and adds second parameter
652 			/// @param a Documentation for the first parameter starts here.
653 			/// Since it's a really complicated parameter we need 2 lines
654 			/// @param second Documentation for the second parameter
655 			/// @return d The result of the multiplication
656 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
657 		}
658 	)";
659 
660 	char const* natspec = "{"
661 	"\"methods\":{"
662 	"    \"mul(uint256,uint256)\":{ \n"
663 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
664 	"        \"params\": {\n"
665 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
666 	"            \"second\": \"Documentation for the second parameter\"\n"
667 	"        },\n"
668 	"        \"returns\": {\n"
669 	"            \"d\": \"The result of the multiplication\"\n"
670 	"        }\n"
671 	"    }\n"
672 	"}}";
673 
674 	checkNatspec(sourceCode, "test", natspec, false);
675 }
676 
BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl)677 BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl)
678 {
679 	char const* sourceCode = R"(
680 		contract test {
681 			/// @dev Multiplies a number by 7 and adds second parameter
682 			/// @param a Documentation for the first parameter starts here.
683 			/// Since it's a really complicated parameter we need 2 lines
684 			/// @param second Documentation for the second parameter
685 			/// @return
686 			/// d The result of the multiplication
687 			function mul(uint a, uint second) public returns (uint d) {
688 				return a * 7 + second;
689 			}
690 		}
691 	)";
692 
693 	char const* natspec = "{"
694 	"\"methods\":{"
695 	"    \"mul(uint256,uint256)\":{ \n"
696 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
697 	"        \"params\": {\n"
698 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
699 	"            \"second\": \"Documentation for the second parameter\"\n"
700 	"        },\n"
701 	"        \"returns\": {\n"
702 	"            \"d\": \"The result of the multiplication\"\n"
703 	"        }\n"
704 	"    }\n"
705 	"}}";
706 
707 	checkNatspec(sourceCode, "test", natspec, false);
708 }
709 
BOOST_AUTO_TEST_CASE(dev_return_desc_multiple_unamed_mixed)710 BOOST_AUTO_TEST_CASE(dev_return_desc_multiple_unamed_mixed)
711 {
712 	char const* sourceCode = R"(
713 		contract test {
714 			/// @dev Multiplies a number by 7 and adds second parameter
715 			/// @param a Documentation for the first parameter starts here.
716 			/// Since it's a really complicated parameter we need 2 lines
717 			/// @param second Documentation for the second parameter
718 			/// @return The result of the multiplication
719 			/// @return _cookies And cookies with nutella
720 			function mul(uint a, uint second) public returns (uint, uint _cookies) {
721 				uint mul = a * 7;
722 				return (mul, second);
723 			}
724 		}
725 	)";
726 
727 	char const* natspec = "{"
728 	"\"methods\":{"
729 	"    \"mul(uint256,uint256)\":{ \n"
730 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
731 	"        \"params\": {\n"
732 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
733 	"            \"second\": \"Documentation for the second parameter\"\n"
734 	"        },\n"
735 	"        \"returns\": {\n"
736 	"            \"_0\": \"The result of the multiplication\",\n"
737 	"            \"_cookies\": \"And cookies with nutella\"\n"
738 	"        }\n"
739 	"    }\n"
740 	"}}";
741 
742 	checkNatspec(sourceCode, "test", natspec, false);
743 }
744 
BOOST_AUTO_TEST_CASE(dev_return_desc_multiple_unamed_mixed_2)745 BOOST_AUTO_TEST_CASE(dev_return_desc_multiple_unamed_mixed_2)
746 {
747 	char const* sourceCode = R"(
748 		contract test {
749 			/// @dev Multiplies a number by 7 and adds second parameter
750 			/// @param a Documentation for the first parameter starts here.
751 			/// Since it's a really complicated parameter we need 2 lines
752 			/// @param second Documentation for the second parameter
753 			/// @return _cookies And cookies with nutella
754 			/// @return The result of the multiplication
755 			/// @return _milk And milk with nutella
756 			function mul(uint a, uint second) public returns (uint _cookies, uint, uint _milk) {
757 				uint mul = a * 7;
758 				uint milk = 4;
759 				return (mul, second, milk);
760 			}
761 		}
762 	)";
763 
764 	char const* natspec = "{"
765 	"\"methods\":{"
766 	"    \"mul(uint256,uint256)\":{ \n"
767 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
768 	"        \"params\": {\n"
769 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
770 	"            \"second\": \"Documentation for the second parameter\"\n"
771 	"        },\n"
772 	"        \"returns\": {\n"
773 	"            \"_cookies\": \"And cookies with nutella\",\n"
774 	"            \"_1\": \"The result of the multiplication\",\n"
775 	"            \"_milk\": \"And milk with nutella\"\n"
776 	"        }\n"
777 	"    }\n"
778 	"}}";
779 
780 	checkNatspec(sourceCode, "test", natspec, false);
781 }
782 
BOOST_AUTO_TEST_CASE(dev_return_desc_multiple_unamed)783 BOOST_AUTO_TEST_CASE(dev_return_desc_multiple_unamed)
784 {
785 	char const* sourceCode = R"(
786 		contract test {
787 			/// @dev Multiplies a number by 7 and adds second parameter
788 			/// @param a Documentation for the first parameter starts here.
789 			/// Since it's a really complicated parameter we need 2 lines
790 			/// @param second Documentation for the second parameter
791 			/// @return The result of the multiplication
792 			/// @return And cookies with nutella
793 			function mul(uint a, uint second) public returns (uint, uint) {
794 				uint mul = a * 7;
795 				return (mul, second);
796 			}
797 		}
798 	)";
799 
800 	char const* natspec = "{"
801 	"\"methods\":{"
802 	"    \"mul(uint256,uint256)\":{ \n"
803 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
804 	"        \"params\": {\n"
805 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
806 	"            \"second\": \"Documentation for the second parameter\"\n"
807 	"        },\n"
808 	"        \"returns\": {\n"
809 	"            \"_0\": \"The result of the multiplication\",\n"
810 	"            \"_1\": \"And cookies with nutella\"\n"
811 	"        }\n"
812 	"    }\n"
813 	"}}";
814 
815 	checkNatspec(sourceCode, "test", natspec, false);
816 }
817 
BOOST_AUTO_TEST_CASE(dev_return_desc_multiple)818 BOOST_AUTO_TEST_CASE(dev_return_desc_multiple)
819 {
820 	char const* sourceCode = R"(
821 		contract test {
822 			/// @dev Multiplies a number by 7 and adds second parameter
823 			/// @param a Documentation for the first parameter starts here.
824 			/// Since it's a really complicated parameter we need 2 lines
825 			/// @param second Documentation for the second parameter
826 			/// @return d The result of the multiplication
827 			/// @return f And cookies with nutella
828 			function mul(uint a, uint second) public returns (uint d, uint f) {
829 				uint mul = a * 7;
830 				return (mul, second);
831 			}
832 		}
833 	)";
834 
835 	char const* natspec = "{"
836 	"\"methods\":{"
837 	"    \"mul(uint256,uint256)\":{ \n"
838 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
839 	"        \"params\": {\n"
840 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
841 	"            \"second\": \"Documentation for the second parameter\"\n"
842 	"        },\n"
843 	"        \"returns\": {\n"
844 	"            \"d\": \"The result of the multiplication\",\n"
845 	"            \"f\": \"And cookies with nutella\"\n"
846 	"        }\n"
847 	"    }\n"
848 	"}}";
849 
850 	checkNatspec(sourceCode, "test", natspec, false);
851 }
852 
BOOST_AUTO_TEST_CASE(dev_multiline_return)853 BOOST_AUTO_TEST_CASE(dev_multiline_return)
854 {
855 	char const* sourceCode = R"(
856 		contract test {
857 			/// @dev Multiplies a number by 7 and adds second parameter
858 			/// @param a Documentation for the first parameter starts here.
859 			/// Since it's a really complicated parameter we need 2 lines
860 			/// @param second Documentation for the second parameter
861 			/// @return d The result of the multiplication
862 			/// and cookies with nutella
863 			function mul(uint a, uint second) public returns (uint d) {
864 				return a * 7 + second;
865 			}
866 		}
867 	)";
868 
869 	char const* natspec = "{"
870 	"\"methods\":{"
871 	"    \"mul(uint256,uint256)\":{ \n"
872 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
873 	"        \"params\": {\n"
874 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
875 	"            \"second\": \"Documentation for the second parameter\"\n"
876 	"        },\n"
877 	"        \"returns\": {\n"
878 	"            \"d\": \"The result of the multiplication and cookies with nutella\",\n"
879 	"        }\n"
880 	"    }\n"
881 	"}}";
882 
883 	checkNatspec(sourceCode, "test", natspec, false);
884 }
885 
BOOST_AUTO_TEST_CASE(dev_multiline_comment)886 BOOST_AUTO_TEST_CASE(dev_multiline_comment)
887 {
888 	char const* sourceCode = R"(
889 		contract test {
890 			/**
891 			 * @dev Multiplies a number by 7 and adds second parameter
892 			 * @param a Documentation for the first parameter starts here.
893 			 * Since it's a really complicated parameter we need 2 lines
894 			 * @param second Documentation for the second parameter
895 			 * @return d The result of the multiplication
896 			 * and cookies with nutella
897 			 */
898 			function mul(uint a, uint second) public returns (uint d) {
899 				return a * 7 + second;
900 			}
901 		}
902 	)";
903 
904 	char const* natspec = "{"
905 	"\"methods\":{"
906 	"    \"mul(uint256,uint256)\":{ \n"
907 	"        \"details\": \"Multiplies a number by 7 and adds second parameter\",\n"
908 	"        \"params\": {\n"
909 	"            \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n"
910 	"            \"second\": \"Documentation for the second parameter\"\n"
911 	"        },\n"
912 	"        \"returns\": {\n"
913 	"            \"d\": \"The result of the multiplication and cookies with nutella\",\n"
914 	"        }\n"
915 	"    }\n"
916 	"}}";
917 
918 	checkNatspec(sourceCode, "test", natspec, false);
919 }
920 
BOOST_AUTO_TEST_CASE(dev_documenting_no_return_paramname)921 BOOST_AUTO_TEST_CASE(dev_documenting_no_return_paramname)
922 {
923 	char const* sourceCode = R"(
924 		contract test {
925 			/// @dev Multiplies a number by 7 and adds second parameter
926 			/// @param a Documentation for the first parameter
927 			/// @param second Documentation for the second parameter
928 			/// @return
929 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
930 		}
931 	)";
932 
933 	expectNatspecError(sourceCode);
934 }
935 
BOOST_AUTO_TEST_CASE(dev_contract_no_doc)936 BOOST_AUTO_TEST_CASE(dev_contract_no_doc)
937 {
938 	char const* sourceCode = R"(
939 		contract test {
940 			/// @dev Mul function
941 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
942 		}
943 	)";
944 
945 	char const* natspec = "{"
946 	"    \"methods\":{"
947 	"        \"mul(uint256,uint256)\":{ \n"
948 	"            \"details\": \"Mul function\"\n"
949 	"        }\n"
950 	"    }\n"
951 	"}";
952 
953 	checkNatspec(sourceCode, "test", natspec, false);
954 }
955 
BOOST_AUTO_TEST_CASE(dev_contract_doc)956 BOOST_AUTO_TEST_CASE(dev_contract_doc)
957 {
958 	char const* sourceCode = R"(
959 		/// @author Lefteris
960 		/// @title Just a test contract
961 		contract test {
962 			/// @dev Mul function
963 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
964 		}
965 	)";
966 
967 	char const* natspec = "{"
968 	"    \"author\": \"Lefteris\","
969 	"    \"title\": \"Just a test contract\","
970 	"    \"methods\":{"
971 	"        \"mul(uint256,uint256)\":{ \n"
972 	"            \"details\": \"Mul function\"\n"
973 	"        }\n"
974 	"    }\n"
975 	"}";
976 
977 	checkNatspec(sourceCode, "test", natspec, false);
978 }
979 
BOOST_AUTO_TEST_CASE(dev_author_at_function)980 BOOST_AUTO_TEST_CASE(dev_author_at_function)
981 {
982 	char const* sourceCode = R"(
983 		/// @author Lefteris
984 		/// @title Just a test contract
985 		contract test {
986 			/// @dev Mul function
987 			/// @author John Doe
988 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
989 		}
990 	)";
991 
992 	expectNatspecError(sourceCode);
993 }
994 
BOOST_AUTO_TEST_CASE(natspec_notice_without_tag)995 BOOST_AUTO_TEST_CASE(natspec_notice_without_tag)
996 {
997 	char const* sourceCode = R"(
998 		contract test {
999 			/// I do something awesome
1000 			function mul(uint a) public returns (uint d) { return a * 7; }
1001 		}
1002 	)";
1003 
1004 
1005 	char const* natspec = R"ABCDEF(
1006 	{
1007 	   "methods" : {
1008 		  "mul(uint256)" : {
1009 			 "notice" : "I do something awesome"
1010 		  }
1011 	   }
1012 	}
1013 	)ABCDEF";
1014 
1015 	checkNatspec(sourceCode, "test", natspec, true);
1016 }
1017 
BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag)1018 BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag)
1019 {
1020 	char const* sourceCode = R"(
1021 		contract test {
1022 			/// I do something awesome
1023 			/// which requires two lines to explain
1024 			function mul(uint a) public returns (uint d) { return a * 7; }
1025 		}
1026 	)";
1027 
1028 	char const* natspec = R"ABCDEF(
1029 	{
1030 	   "methods" : {
1031 		  "mul(uint256)" : {
1032 			 "notice" : "I do something awesome which requires two lines to explain"
1033 		  }
1034 	   }
1035 	}
1036 	)ABCDEF";
1037 
1038 	checkNatspec(sourceCode, "test", natspec, true);
1039 }
1040 
BOOST_AUTO_TEST_CASE(empty_comment)1041 BOOST_AUTO_TEST_CASE(empty_comment)
1042 {
1043 	char const* sourceCode = R"(
1044 		//
1045 		contract test
1046 		{}
1047 	)";
1048 	char const* natspec = R"ABCDEF(
1049 	{
1050 	   "methods" : {}
1051 	}
1052 	)ABCDEF";
1053 
1054 	checkNatspec(sourceCode, "test", natspec, true);
1055 }
1056 
BOOST_AUTO_TEST_CASE(dev_title_at_function_error)1057 BOOST_AUTO_TEST_CASE(dev_title_at_function_error)
1058 {
1059 	char const* sourceCode = R"(
1060 		/// @author Lefteris
1061 		/// @title Just a test contract
1062 		contract test {
1063 			/// @dev Mul function
1064 			/// @title I really should not be here
1065 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
1066 		}
1067 	)";
1068 
1069 	expectNatspecError(sourceCode);
1070 }
1071 
BOOST_AUTO_TEST_CASE(dev_documenting_nonexistent_param)1072 BOOST_AUTO_TEST_CASE(dev_documenting_nonexistent_param)
1073 {
1074 	char const* sourceCode = R"(
1075 		contract test {
1076 			/// @dev Multiplies a number by 7 and adds second parameter
1077 			/// @param a Documentation for the first parameter
1078 			/// @param not_existing Documentation for the second parameter
1079 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
1080 		}
1081 	)";
1082 
1083 	expectNatspecError(sourceCode);
1084 }
1085 
BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname)1086 BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname)
1087 {
1088 	char const* sourceCode = R"(
1089 		contract test {
1090 			/// @dev Multiplies a number by 7 and adds second parameter
1091 			/// @param a Documentation for the first parameter
1092 			/// @param
1093 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
1094 		}
1095 	)";
1096 
1097 	expectNatspecError(sourceCode);
1098 }
1099 
BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname_end)1100 BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname_end)
1101 {
1102 	char const* sourceCode = R"(
1103 		contract test {
1104 			/// @dev Multiplies a number by 7 and adds second parameter
1105 			/// @param a Documentation for the first parameter
1106 			/// @param se
1107 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
1108 		}
1109 	)";
1110 
1111 	expectNatspecError(sourceCode);
1112 }
1113 
BOOST_AUTO_TEST_CASE(dev_documenting_no_param_description)1114 BOOST_AUTO_TEST_CASE(dev_documenting_no_param_description)
1115 {
1116 	char const* sourceCode = R"(
1117 		contract test {
1118 			/// @dev Multiplies a number by 7 and adds second parameter
1119 			/// @param a Documentation for the first parameter
1120 			/// @param second
1121 			function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
1122 		}
1123 	)";
1124 
1125 	expectNatspecError(sourceCode);
1126 }
1127 
BOOST_AUTO_TEST_CASE(user_constructor)1128 BOOST_AUTO_TEST_CASE(user_constructor)
1129 {
1130 	char const* sourceCode = R"(
1131 		contract test {
1132 			/// @notice this is a really nice constructor
1133 			constructor(uint a, uint second) { }
1134 		}
1135 	)";
1136 
1137 	char const* natspec = R"ABCDEF({
1138 	"methods": {
1139 		"constructor" : {
1140 			"notice": "this is a really nice constructor"
1141 		}
1142 	}
1143 	})ABCDEF";
1144 
1145 	checkNatspec(sourceCode, "test", natspec, true);
1146 }
1147 
BOOST_AUTO_TEST_CASE(user_constructor_and_function)1148 BOOST_AUTO_TEST_CASE(user_constructor_and_function)
1149 {
1150 	char const* sourceCode = R"(
1151 		contract test {
1152 			/// @notice this is a really nice constructor
1153 			constructor(uint a, uint second) { }
1154 			/// another multiplier
1155 			function mul(uint a, uint second) public returns(uint d) { return a * 7 + second; }
1156 		}
1157 	)";
1158 
1159 	char const* natspec = R"ABCDEF({
1160 	"methods" : {
1161 		"mul(uint256,uint256)" : {
1162 			"notice" : "another multiplier"
1163 		},
1164 		"constructor" : {
1165 			"notice" : "this is a really nice constructor"
1166 		}
1167 	}
1168 	})ABCDEF";
1169 
1170 	checkNatspec(sourceCode, "test", natspec, true);
1171 }
1172 
BOOST_AUTO_TEST_CASE(dev_constructor)1173 BOOST_AUTO_TEST_CASE(dev_constructor)
1174 {
1175 	char const *sourceCode = R"(
1176 		contract test {
1177 			/// @param a the parameter a is really nice and very useful
1178 			/// @param second the second parameter is not very useful, it just provides additional confusion
1179 			constructor(uint a, uint second) { }
1180 		}
1181 	)";
1182 
1183 	char const *natspec = R"ABCDEF({
1184 	"methods" : {
1185 		"constructor" : {
1186 			"params" : {
1187 				"a" : "the parameter a is really nice and very useful",
1188 				"second" : "the second parameter is not very useful, it just provides additional confusion"
1189 			}
1190 		}
1191 	}
1192 	})ABCDEF";
1193 
1194 	checkNatspec(sourceCode, "test", natspec, false);
1195 }
1196 
BOOST_AUTO_TEST_CASE(dev_constructor_return)1197 BOOST_AUTO_TEST_CASE(dev_constructor_return)
1198 {
1199 	char const* sourceCode = R"(
1200 		contract test {
1201 			/// @param a the parameter a is really nice and very useful
1202 			/// @param second the second parameter is not very useful, it just provides additional confusion
1203 			/// @return return should not work within constructors
1204 			constructor(uint a, uint second) { }
1205 		}
1206 	)";
1207 
1208 	expectNatspecError(sourceCode);
1209 }
1210 
BOOST_AUTO_TEST_CASE(dev_constructor_and_function)1211 BOOST_AUTO_TEST_CASE(dev_constructor_and_function)
1212 {
1213 	char const *sourceCode = R"(
1214 		contract test {
1215 			/// @param a the parameter a is really nice and very useful
1216 			/// @param second the second parameter is not very useful, it just provides additional confusion
1217 			constructor(uint a, uint second) { }
1218 			/// @dev Multiplies a number by 7 and adds second parameter
1219 			/// @param a Documentation for the first parameter starts here.
1220 			/// Since it's a really complicated parameter we need 2 lines
1221 			/// @param second Documentation for the second parameter
1222 			/// @return d The result of the multiplication
1223 			/// and cookies with nutella
1224 			function mul(uint a, uint second) public returns(uint d) {
1225 				return a * 7 + second;
1226 			}
1227 		}
1228 	)";
1229 
1230 	char const *natspec = R"ABCDEF({
1231 	"methods" : {
1232 		"mul(uint256,uint256)" : {
1233 			"details" : "Multiplies a number by 7 and adds second parameter",
1234 			"params" : {
1235 				"a" : "Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines",
1236 				"second" : "Documentation for the second parameter"
1237 			},
1238 			"returns" : {
1239 				"d": "The result of the multiplication and cookies with nutella"
1240 			}
1241 		},
1242 		"constructor" : {
1243 			"params" : {
1244 				"a" : "the parameter a is really nice and very useful",
1245 				"second" : "the second parameter is not very useful, it just provides additional confusion"
1246 			}
1247 		}
1248 	}
1249 	})ABCDEF";
1250 
1251 	checkNatspec(sourceCode, "test", natspec, false);
1252 }
1253 
1254 BOOST_AUTO_TEST_CASE(slash4)
1255 {
1256 	char const* sourceCode = R"(
1257 		contract test {
1258 			//// @notice lorem ipsum
1259 			function f() public { }
1260 		}
1261 	)";
1262 
1263 	char const* natspec = R"( { "methods": {} } )";
1264 
1265 	checkNatspec(sourceCode, "test", natspec, true);
1266 }
1267 
1268 BOOST_AUTO_TEST_CASE(star3)
1269 {
1270 	char const* sourceCode = R"(
1271 		contract test {
1272 			/***
1273 			 * @notice lorem ipsum
1274 			 */
1275 			function f() public { }
1276 		}
1277 	)";
1278 
1279 	char const* natspec = R"( { "methods": {} } )";
1280 
1281 	checkNatspec(sourceCode, "test", natspec, true);
1282 }
1283 
1284 BOOST_AUTO_TEST_CASE(slash3_slash3)
1285 {
1286 	char const* sourceCode = R"(
1287 		contract test {
1288 			/// @notice lorem
1289 			/// ipsum
1290 			function f() public { }
1291 		}
1292 	)";
1293 
1294 	char const* natspec = R"ABCDEF({
1295 		"methods": {
1296 			"f()": { "notice": "lorem ipsum" }
1297 		}
1298 	})ABCDEF";
1299 
1300 	checkNatspec(sourceCode, "test", natspec, true);
1301 }
1302 
1303 BOOST_AUTO_TEST_CASE(slash3_slash4)
1304 {
1305 	char const* sourceCode = R"(
1306 		contract test {
1307 			/// @notice lorem
1308 			//// ipsum
1309 			function f() public { }
1310 		}
1311 	)";
1312 
1313 	char const* natspec = R"ABCDEF({
1314 		"methods": {
1315 			"f()": { "notice": "lorem" }
1316 		}
1317 	})ABCDEF";
1318 
1319 	checkNatspec(sourceCode, "test", natspec, true);
1320 }
1321 
1322 BOOST_AUTO_TEST_CASE(dev_default_inherit_variable)
1323 {
1324 	char const *sourceCode = R"(
1325 		contract C {
1326 			/// @notice Hello world
1327 			/// @dev test
1328 			function x() virtual external returns (uint) {
1329 				return 1;
1330 			}
1331 		}
1332 
1333 		contract D is C {
1334 			uint public override x;
1335 		}
1336 	)";
1337 
1338 	char const *natspec = R"ABCDEF({
1339 		"methods": { "x()": { "details": "test" } }
1340 	})ABCDEF";
1341 
1342 	char const *natspec1 = R"ABCDEF({
1343 		"methods" : {},
1344 		"stateVariables" :
1345 		{
1346 			"x" :
1347 			{
1348 				"details" : "test"
1349 			}
1350 		}
1351 	})ABCDEF";
1352 
1353 	checkNatspec(sourceCode, "C", natspec, false);
1354 	checkNatspec(sourceCode, "D", natspec1, false);
1355 }
1356 
1357 BOOST_AUTO_TEST_CASE(user_default_inherit_variable)
1358 {
1359 	char const *sourceCode = R"(
1360 		contract C {
1361 			/// @notice Hello world
1362 			/// @dev test
1363 			function x() virtual external returns (uint) {
1364 				return 1;
1365 			}
1366 		}
1367 
1368 		contract D is C {
1369 			uint public override x;
1370 		}
1371 	)";
1372 
1373 	char const *natspec = R"ABCDEF({
1374 		"methods": { "x()": { "notice": "Hello world" } }
1375 	})ABCDEF";
1376 
1377 	checkNatspec(sourceCode, "C", natspec, true);
1378 	checkNatspec(sourceCode, "D", natspec, true);
1379 }
1380 
1381 BOOST_AUTO_TEST_CASE(dev_explicit_inherit_variable)
1382 {
1383 	char const *sourceCode = R"(
1384 		contract B {
1385 			function x() virtual external returns (uint) {
1386 				return 1;
1387 			}
1388 		}
1389 
1390 		contract C {
1391 			/// @notice Hello world
1392 			/// @dev test
1393 			function x() virtual external returns (uint) {
1394 				return 1;
1395 			}
1396 		}
1397 
1398 		contract D is C, B {
1399 			/// @inheritdoc C
1400 			uint public override(C, B) x;
1401 		}
1402 	)";
1403 
1404 	char const *natspec = R"ABCDEF({
1405 		"methods": { "x()": { "details": "test" } }
1406 	})ABCDEF";
1407 
1408 	char const *natspec1 = R"ABCDEF({
1409 		"methods" : {},
1410 		"stateVariables" :
1411 		{
1412 			"x" :
1413 			{
1414 				"details" : "test"
1415 			}
1416 		}
1417 	})ABCDEF";
1418 
1419 	checkNatspec(sourceCode, "C", natspec, false);
1420 	checkNatspec(sourceCode, "D", natspec1, false);
1421 }
1422 
1423 BOOST_AUTO_TEST_CASE(user_explicit_inherit_variable)
1424 {
1425 	char const *sourceCode = R"(
1426 		contract B {
1427 			function x() virtual external returns (uint) {
1428 				return 1;
1429 			}
1430 		}
1431 
1432 		contract C {
1433 			/// @notice Hello world
1434 			/// @dev test
1435 			function x() virtual external returns (uint) {
1436 				return 1;
1437 			}
1438 		}
1439 
1440 		contract D is C, B {
1441 			/// @inheritdoc C
1442 			uint public override(C, B) x;
1443 		}
1444 	)";
1445 
1446 	char const *natspec = R"ABCDEF({
1447 		"methods": { "x()": { "notice": "Hello world" } }
1448 	})ABCDEF";
1449 
1450 	checkNatspec(sourceCode, "C", natspec, true);
1451 	checkNatspec(sourceCode, "D", natspec, true);
1452 }
1453 
1454 BOOST_AUTO_TEST_CASE(dev_default_inherit)
1455 {
1456 	char const *sourceCode = R"(
1457 		interface ERC20 {
1458 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1459 			/// Second line.
1460 			/// @dev test
1461 			/// @param to address to transfer to
1462 			/// @param amount amount to transfer
1463 			function transfer(address to, uint amount) external returns (bool);
1464 		}
1465 
1466 		contract Middle is ERC20 {
1467 			function transfer(address to, uint amount) virtual override external returns (bool)
1468 			{
1469 			return false;
1470 		  }
1471 		}
1472 
1473 		contract Token is Middle {
1474 			function transfer(address to, uint amount) override external returns (bool)
1475 			{
1476 				return false;
1477 			}
1478 		}
1479 	)";
1480 
1481 	char const *natspec = R"ABCDEF({
1482 		"methods":
1483 		{
1484 			"transfer(address,uint256)":
1485 			{
1486 				"details": "test",
1487 				"params":
1488 				{
1489 					"amount": "amount to transfer",
1490 					"to": "address to transfer to"
1491 				}
1492 			}
1493 		}
1494 	})ABCDEF";
1495 
1496 	checkNatspec(sourceCode, "ERC20", natspec, false);
1497 	checkNatspec(sourceCode, "Middle", natspec, false);
1498 	checkNatspec(sourceCode, "Token", natspec, false);
1499 }
1500 
1501 BOOST_AUTO_TEST_CASE(user_default_inherit)
1502 {
1503 	char const *sourceCode = R"(
1504 		interface ERC20 {
1505 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1506 			/// Second line.
1507 			/// @dev test
1508 			/// @param to address to transfer to
1509 			/// @param amount amount to transfer
1510 			function transfer(address to, uint amount) external returns (bool);
1511 		}
1512 
1513 		contract Middle is ERC20 {
1514 			function transfer(address to, uint amount) virtual override external returns (bool)
1515 			{
1516 			return false;
1517 		  }
1518 		}
1519 
1520 		contract Token is Middle {
1521 			function transfer(address to, uint amount) override external returns (bool)
1522 			{
1523 				return false;
1524 			}
1525 		}
1526 	)";
1527 
1528 	char const *natspec = R"ABCDEF({
1529 		"methods":
1530 		{
1531 			"transfer(address,uint256)":
1532 			{
1533 				"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``. Second line."
1534 			}
1535 		}
1536 	})ABCDEF";
1537 
1538 	checkNatspec(sourceCode, "ERC20", natspec, true);
1539 	checkNatspec(sourceCode, "Middle", natspec, true);
1540 	checkNatspec(sourceCode, "Token", natspec, true);
1541 }
1542 
1543 BOOST_AUTO_TEST_CASE(dev_explicit_inherit)
1544 {
1545 	char const *sourceCode = R"(
1546 		interface ERC20 {
1547 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1548 			/// @dev test
1549 			/// @param to address to transfer to
1550 			/// @param amount amount to transfer
1551 			function transfer(address to, uint amount) external returns (bool);
1552 		}
1553 
1554 		contract ERC21 {
1555 			function transfer(address to, uint amount) virtual external returns (bool) {
1556 				return false;
1557 			}
1558 		}
1559 
1560 		contract Token is ERC21, ERC20 {
1561 			/// @inheritdoc ERC20
1562 			function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
1563 				return false;
1564 			}
1565 		}
1566 	)";
1567 
1568 	char const *natspec = R"ABCDEF({
1569 		"methods":
1570 		{
1571 			"transfer(address,uint256)":
1572 			{
1573 				"details": "test",
1574 				"params":
1575 				{
1576 					"amount": "amount to transfer",
1577 					"to": "address to transfer to"
1578 				}
1579 			}
1580 		}
1581 	})ABCDEF";
1582 
1583 	checkNatspec(sourceCode, "ERC20", natspec, false);
1584 	checkNatspec(sourceCode, "Token", natspec, false);
1585 }
1586 
1587 BOOST_AUTO_TEST_CASE(user_explicit_inherit)
1588 {
1589 	char const *sourceCode = R"(
1590 		interface ERC20 {
1591 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1592 			/// @dev test
1593 			/// @param to address to transfer to
1594 			/// @param amount amount to transfer
1595 			function transfer(address to, uint amount) external returns (bool);
1596 		}
1597 
1598 		contract ERC21 {
1599 			function transfer(address to, uint amount) virtual external returns (bool) {
1600 				return false;
1601 			}
1602 		}
1603 
1604 		contract Token is ERC21, ERC20 {
1605 			/// @inheritdoc ERC20
1606 			function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
1607 				return false;
1608 			}
1609 		}
1610 	)";
1611 
1612 	char const *natspec = R"ABCDEF({
1613 		"methods":
1614 		{
1615 			"transfer(address,uint256)":
1616 			{
1617 				"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
1618 			}
1619 		}
1620 	})ABCDEF";
1621 
1622 	checkNatspec(sourceCode, "ERC20", natspec, true);
1623 	checkNatspec(sourceCode, "Token", natspec, true);
1624 }
1625 
1626 BOOST_AUTO_TEST_CASE(dev_explicit_inherit2)
1627 {
1628 	char const *sourceCode = R"(
1629 		interface ERC20 {
1630 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1631 			/// @dev test
1632 			/// @param to address to transfer to
1633 			/// @param amount amount to transfer
1634 			function transfer(address to, uint amount) external returns (bool);
1635 		}
1636 
1637 		contract ERC21 is ERC20 {
1638 			function transfer(address to, uint amount) virtual override external returns (bool) {
1639 				return false;
1640 			}
1641 		}
1642 
1643 		contract Token is ERC20 {
1644 			/// @inheritdoc ERC20
1645 			function transfer(address to, uint amount) override external returns (bool) {
1646 				return false;
1647 			}
1648 		}
1649 	)";
1650 
1651 	char const *natspec = R"ABCDEF({
1652 		"methods":
1653 		{
1654 			"transfer(address,uint256)":
1655 			{
1656 				"details": "test",
1657 				"params":
1658 				{
1659 					"amount": "amount to transfer",
1660 					"to": "address to transfer to"
1661 				}
1662 			}
1663 		}
1664 	})ABCDEF";
1665 
1666 	checkNatspec(sourceCode, "ERC20", natspec, false);
1667 	checkNatspec(sourceCode, "ERC21", natspec, false);
1668 	checkNatspec(sourceCode, "Token", natspec, false);
1669 }
1670 
1671 BOOST_AUTO_TEST_CASE(user_explicit_inherit2)
1672 {
1673 	char const *sourceCode = R"(
1674 		interface ERC20 {
1675 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1676 			/// @dev test
1677 			/// @param to address to transfer to
1678 			/// @param amount amount to transfer
1679 			function transfer(address to, uint amount) external returns (bool);
1680 		}
1681 
1682 		contract ERC21 is ERC20 {
1683 			function transfer(address to, uint amount) virtual override external returns (bool) {
1684 				return false;
1685 			}
1686 		}
1687 
1688 		contract Token is ERC20 {
1689 			/// @inheritdoc ERC20
1690 			function transfer(address to, uint amount) override external returns (bool) {
1691 				return false;
1692 			}
1693 		}
1694 	)";
1695 
1696 	char const *natspec = R"ABCDEF({
1697 		"methods":
1698 		{
1699 			"transfer(address,uint256)":
1700 			{
1701 				"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
1702 			}
1703 		}
1704 	})ABCDEF";
1705 
1706 	checkNatspec(sourceCode, "ERC20", natspec, true);
1707 	checkNatspec(sourceCode, "ERC21", natspec, true);
1708 	checkNatspec(sourceCode, "Token", natspec, true);
1709 }
1710 
1711 BOOST_AUTO_TEST_CASE(dev_explicit_inherit_partial2)
1712 {
1713 	char const *sourceCode = R"(
1714 		interface ERC20 {
1715 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1716 			/// @dev test
1717 			/// @param to address to transfer to
1718 			/// @param amount amount to transfer
1719 			function transfer(address to, uint amount) external returns (bool);
1720 		}
1721 
1722 		contract ERC21 is ERC20 {
1723 			/// @inheritdoc ERC20
1724 			/// @dev override dev comment
1725 			/// @notice override notice
1726 			function transfer(address to, uint amount) virtual override external returns (bool) {
1727 				return false;
1728 			}
1729 		}
1730 
1731 		contract Token is ERC21 {
1732 			function transfer(address to, uint amount) override external returns (bool) {
1733 				return false;
1734 			}
1735 		}
1736 	)";
1737 
1738 	char const *natspec = R"ABCDEF({
1739 		"methods":
1740 		{
1741 			"transfer(address,uint256)":
1742 			{
1743 				"details": "test",
1744 				"params":
1745 				{
1746 					"amount": "amount to transfer",
1747 					"to": "address to transfer to"
1748 				}
1749 			}
1750 		}
1751 	})ABCDEF";
1752 
1753 	char const *natspec2 = R"ABCDEF({
1754 		"methods":
1755 		{
1756 			"transfer(address,uint256)":
1757 			{
1758 				"details": "override dev comment",
1759 				"params":
1760 				{
1761 					"amount": "amount to transfer",
1762 					"to": "address to transfer to"
1763 				}
1764 			}
1765 		}
1766 	})ABCDEF";
1767 
1768 	checkNatspec(sourceCode, "ERC20", natspec, false);
1769 	checkNatspec(sourceCode, "Token", natspec2, false);
1770 }
1771 
1772 BOOST_AUTO_TEST_CASE(user_explicit_inherit_partial2)
1773 {
1774 	char const *sourceCode = R"(
1775 		interface ERC20 {
1776 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1777 			/// @dev test
1778 			/// @param to address to transfer to
1779 			/// @param amount amount to transfer
1780 			function transfer(address to, uint amount) external returns (bool);
1781 		}
1782 
1783 		contract ERC21 is ERC20 {
1784 			/// @inheritdoc ERC20
1785 			/// @dev override dev comment
1786 			/// @notice override notice
1787 			function transfer(address to, uint amount) virtual override external returns (bool) {
1788 				return false;
1789 			}
1790 		}
1791 
1792 		contract Token is ERC21 {
1793 			function transfer(address to, uint amount) override external returns (bool) {
1794 				return false;
1795 			}
1796 		}
1797 	)";
1798 
1799 	char const *natspec = R"ABCDEF({
1800 		"methods":
1801 		{
1802 			"transfer(address,uint256)":
1803 			{
1804 				"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
1805 			}
1806 		}
1807 	})ABCDEF";
1808 
1809 	char const *natspec2 = R"ABCDEF({
1810 		"methods":
1811 		{
1812 			"transfer(address,uint256)":
1813 			{
1814 				"notice": "override notice"
1815 			}
1816 		}
1817 	})ABCDEF";
1818 
1819 	checkNatspec(sourceCode, "ERC20", natspec, true);
1820 	checkNatspec(sourceCode, "Token", natspec2, true);
1821 }
1822 
1823 BOOST_AUTO_TEST_CASE(dev_explicit_inherit_partial)
1824 {
1825 	char const *sourceCode = R"(
1826 		interface ERC20 {
1827 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1828 			/// @dev test
1829 			/// @param to address to transfer to
1830 			/// @param amount amount to transfer
1831 			function transfer(address to, uint amount) external returns (bool);
1832 		}
1833 
1834 		contract ERC21 {
1835 			function transfer(address to, uint amount) virtual external returns (bool) {
1836 				return false;
1837 			}
1838 		}
1839 
1840 		contract Token is ERC21, ERC20 {
1841 			/// @inheritdoc ERC20
1842 			/// @dev override dev comment
1843 			/// @notice override notice
1844 			function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
1845 				return false;
1846 			}
1847 		}
1848 	)";
1849 
1850 	char const *natspec = R"ABCDEF({
1851 		"methods":
1852 		{
1853 			"transfer(address,uint256)":
1854 			{
1855 				"details": "test",
1856 				"params":
1857 				{
1858 					"amount": "amount to transfer",
1859 					"to": "address to transfer to"
1860 				}
1861 			}
1862 		}
1863 	})ABCDEF";
1864 
1865 	char const *natspec2 = R"ABCDEF({
1866 		"methods":
1867 		{
1868 			"transfer(address,uint256)":
1869 			{
1870 				"details": "override dev comment",
1871 				"params":
1872 				{
1873 					"amount": "amount to transfer",
1874 					"to": "address to transfer to"
1875 				}
1876 			}
1877 		}
1878 	})ABCDEF";
1879 
1880 	checkNatspec(sourceCode, "ERC20", natspec, false);
1881 	checkNatspec(sourceCode, "Token", natspec2, false);
1882 }
1883 
1884 BOOST_AUTO_TEST_CASE(user_explicit_inherit_partial)
1885 {
1886 	char const *sourceCode = R"(
1887 		interface ERC20 {
1888 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1889 			/// @dev test
1890 			/// @param to address to transfer to
1891 			/// @param amount amount to transfer
1892 			function transfer(address to, uint amount) external returns (bool);
1893 		}
1894 
1895 		contract ERC21 {
1896 			function transfer(address to, uint amount) virtual external returns (bool) {
1897 				return false;
1898 			}
1899 		}
1900 
1901 		contract Token is ERC21, ERC20 {
1902 			/// @inheritdoc ERC20
1903 			/// @dev override dev comment
1904 			/// @notice override notice
1905 			function transfer(address to, uint amount) override(ERC21, ERC20) external returns (bool) {
1906 				return false;
1907 			}
1908 		}
1909 	)";
1910 
1911 	char const *natspec = R"ABCDEF({
1912 		"methods":
1913 		{
1914 			"transfer(address,uint256)":
1915 			{
1916 				"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
1917 			}
1918 		}
1919 	})ABCDEF";
1920 
1921 	char const *natspec2 = R"ABCDEF({
1922 		"methods":
1923 		{
1924 			"transfer(address,uint256)":
1925 			{
1926 				"notice": "override notice"
1927 			}
1928 		}
1929 	})ABCDEF";
1930 
1931 	checkNatspec(sourceCode, "ERC20", natspec, true);
1932 	checkNatspec(sourceCode, "Token", natspec2, true);
1933 }
1934 
1935 BOOST_AUTO_TEST_CASE(dev_inherit_parameter_mismatch)
1936 {
1937 	char const *sourceCode = R"(
1938 		interface ERC20 {
1939 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1940 			/// @dev test
1941 			/// @param to address to transfer to
1942 			/// @param amount amount to transfer
1943 			function transfer(address to, uint amount) external returns (bool);
1944 		}
1945 
1946 		contract Middle is ERC20 {
1947 			function transfer(address to, uint amount) override virtual external returns (bool) {
1948 				return false;
1949 			}
1950 		}
1951 
1952 		contract Token is Middle {
1953 			function transfer(address too, uint amount) override external returns (bool) {
1954 				return false;
1955 			}
1956 		}
1957 	)";
1958 
1959 	char const *natspec = R"ABCDEF({
1960 		"methods":
1961 		{
1962 			"transfer(address,uint256)":
1963 			{
1964 				"details": "test",
1965 				"params":
1966 				{
1967 					"amount": "amount to transfer",
1968 					"to": "address to transfer to"
1969 				}
1970 			}
1971 		}
1972 	})ABCDEF";
1973 
1974 	char const *natspec2 = R"ABCDEF({
1975 		"methods": { }
1976 	})ABCDEF";
1977 
1978 	checkNatspec(sourceCode, "ERC20", natspec, false);
1979 	checkNatspec(sourceCode, "Middle", natspec, false);
1980 	checkNatspec(sourceCode, "Token", natspec2, false);
1981 }
1982 
1983 BOOST_AUTO_TEST_CASE(user_inherit_parameter_mismatch)
1984 {
1985 	char const *sourceCode = R"(
1986 		interface ERC20 {
1987 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
1988 			/// @dev test
1989 			/// @param to address to transfer to
1990 			/// @param amount amount to transfer
1991 			function transfer(address to, uint amount) external returns (bool);
1992 		}
1993 
1994 		contract Middle is ERC20 {
1995 			function transfer(address to, uint amount) override virtual external returns (bool) {
1996 				return false;
1997 			}
1998 		}
1999 
2000 		contract Token is Middle {
2001 			function transfer(address too, uint amount) override external returns (bool) {
2002 				return false;
2003 			}
2004 		}
2005 	)";
2006 
2007 	char const *natspec = R"ABCDEF({
2008 		"methods":
2009 		{
2010 			"transfer(address,uint256)":
2011 			{
2012 				"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
2013 			}
2014 		}
2015 	})ABCDEF";
2016 
2017 	char const *natspec2 = R"ABCDEF({
2018 		"methods": { }
2019 	})ABCDEF";
2020 
2021 	checkNatspec(sourceCode, "ERC20", natspec, true);
2022 	checkNatspec(sourceCode, "Middle", natspec, true);
2023 	checkNatspec(sourceCode, "Token", natspec2, true);
2024 }
2025 
2026 BOOST_AUTO_TEST_CASE(dev_explicit_inehrit_complex)
2027 {
2028 	char const *sourceCode1 = R"(
2029 		interface ERC20 {
2030 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
2031 			/// @dev test
2032 			/// @param to address to transfer to
2033 			/// @param amount amount to transfer
2034 			function transfer(address to, uint amount) external returns (bool);
2035 		}
2036 
2037 		interface ERC21 {
2038 			/// Transfer ``amount`` from ``msg.sender`` to ``to``.
2039 			/// @dev test2
2040 			/// @param to address to transfer to
2041 			/// @param amount amount to transfer
2042 			function transfer(address to, uint amount) external returns (bool);
2043 		}
2044 	)";
2045 
2046 	char const *sourceCode2 = R"(
2047 		import "Interfaces.sol" as myInterfaces;
2048 
2049 		contract Token is myInterfaces.ERC20, myInterfaces.ERC21 {
2050 			/// @inheritdoc myInterfaces.ERC20
2051 			function transfer(address too, uint amount)
2052 				override(myInterfaces.ERC20, myInterfaces.ERC21) external returns (bool) {
2053 				return false;
2054 			}
2055 		}
2056 	)";
2057 
2058 	char const *natspec = R"ABCDEF({
2059 		"methods":
2060 		{
2061 			"transfer(address,uint256)":
2062 			{
2063 				"details": "test",
2064 				"params":
2065 				{
2066 					"amount": "amount to transfer",
2067 					"to": "address to transfer to"
2068 				}
2069 			}
2070 		}
2071 	})ABCDEF";
2072 
2073 	m_compilerStack.reset();
2074 	m_compilerStack.setSources({
2075 		{"Interfaces.sol", "pragma solidity >=0.0;\n" + std::string(sourceCode1)},
2076 		{"Testfile.sol", "pragma solidity >=0.0;\n" + std::string(sourceCode2)}
2077 	});
2078 
2079 	m_compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
2080 
2081 	BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
2082 
2083 	Json::Value generatedDocumentation = m_compilerStack.natspecDev("Token");
2084 	Json::Value expectedDocumentation;
2085 	util::jsonParseStrict(natspec, expectedDocumentation);
2086 
2087 	expectedDocumentation["version"] = Json::Value(Natspec::c_natspecVersion);
2088 	expectedDocumentation["kind"] = Json::Value("dev");
2089 
2090 	BOOST_CHECK_MESSAGE(
2091 		expectedDocumentation == generatedDocumentation,
2092 		"Expected:\n" << util::jsonPrettyPrint(expectedDocumentation) <<
2093 		"\n but got:\n" << util::jsonPrettyPrint(generatedDocumentation)
2094 	);
2095 }
2096 
2097 BOOST_AUTO_TEST_CASE(dev_different_return_name)
2098 {
2099 	char const *sourceCode = R"(
2100 		contract A {
2101 			/// @return y value
2102 			function g(int x) public pure virtual returns (int y) { return x; }
2103 		}
2104 
2105 		contract B is A {
2106 			function g(int x) public pure override returns (int z) { return x; }
2107 		}
2108 	)";
2109 
2110 	char const *natspec = R"ABCDEF({
2111 		"methods":
2112 		{
2113 			"g(int256)":
2114 			{
2115 				"returns":
2116 				{
2117 					"y": "value"
2118 				}
2119 			}
2120 		}
2121 	})ABCDEF";
2122 
2123 	char const *natspec2 = R"ABCDEF({
2124 		"methods":
2125 		{
2126 			"g(int256)":
2127 			{
2128 				"returns":
2129 				{
2130 					"z": "value"
2131 				}
2132 			}
2133 		}
2134 	})ABCDEF";
2135 
2136 	checkNatspec(sourceCode, "A", natspec, false);
2137 	checkNatspec(sourceCode, "B", natspec2, false);
2138 }
2139 
2140 BOOST_AUTO_TEST_CASE(dev_different_return_name_multiple)
2141 {
2142 	char const *sourceCode = R"(
2143 		contract A {
2144 			/// @return a value A
2145 			/// @return b value B
2146 			function g(int x) public pure virtual returns (int a, int b) { return (1, 2); }
2147 		}
2148 
2149 		contract B is A {
2150 			function g(int x) public pure override returns (int z, int y) { return (1, 2); }
2151 		}
2152 	)";
2153 
2154 	char const *natspec = R"ABCDEF({
2155 		"methods":
2156 		{
2157 			"g(int256)":
2158 			{
2159 				"returns":
2160 				{
2161 					"a": "value A",
2162 					"b": "value B"
2163 				}
2164 			}
2165 		}
2166 	})ABCDEF";
2167 
2168 	char const *natspec2 = R"ABCDEF({
2169 		"methods":
2170 		{
2171 			"g(int256)":
2172 			{
2173 				"returns":
2174 				{
2175 					"z": "value A",
2176 					"y": "value B"
2177 				}
2178 			}
2179 		}
2180 	})ABCDEF";
2181 
2182 	checkNatspec(sourceCode, "A", natspec, false);
2183 	checkNatspec(sourceCode, "B", natspec2, false);
2184 }
2185 
2186 BOOST_AUTO_TEST_CASE(dev_different_return_name_multiple_partly_unnamed)
2187 {
2188 	char const *sourceCode = R"(
2189 		contract A {
2190 			/// @return value A
2191 			/// @return b value B
2192 			function g(int x) public pure virtual returns (int, int b) { return (1, 2); }
2193 		}
2194 
2195 		contract B is A {
2196 			function g(int x) public pure override returns (int z, int) { return (1, 2); }
2197 		}
2198 	)";
2199 
2200 	char const *natspec = R"ABCDEF({
2201 		"methods":
2202 		{
2203 			"g(int256)":
2204 			{
2205 				"returns":
2206 				{
2207 					"_0": "value A",
2208 					"b": "value B"
2209 				}
2210 			}
2211 		}
2212 	})ABCDEF";
2213 
2214 	char const *natspec2 = R"ABCDEF({
2215 		"methods":
2216 		{
2217 			"g(int256)":
2218 			{
2219 				"returns":
2220 				{
2221 					"z": "value A",
2222 					"_1": "value B"
2223 				}
2224 			}
2225 		}
2226 	})ABCDEF";
2227 
2228 	checkNatspec(sourceCode, "A", natspec, false);
2229 	checkNatspec(sourceCode, "B", natspec2, false);
2230 }
2231 
2232 BOOST_AUTO_TEST_CASE(dev_different_return_name_multiple_unnamed)
2233 {
2234 	char const *sourceCode = R"(
2235 		contract A {
2236 			/// @return value A
2237 			/// @return value B
2238 			function g(int x) public pure virtual returns (int, int) { return (1, 2); }
2239 		}
2240 
2241 		contract B is A {
2242 			function g(int x) public pure override returns (int z, int y) { return (1, 2); }
2243 		}
2244 	)";
2245 
2246 	char const *natspec = R"ABCDEF({
2247 		"methods":
2248 		{
2249 			"g(int256)":
2250 			{
2251 				"returns":
2252 				{
2253 					"_0": "value A",
2254 					"_1": "value B"
2255 				}
2256 			}
2257 		}
2258 	})ABCDEF";
2259 
2260 	char const *natspec2 = R"ABCDEF({
2261 		"methods":
2262 		{
2263 			"g(int256)":
2264 			{
2265 				"returns":
2266 				{
2267 					"z": "value A",
2268 					"y": "value B"
2269 				}
2270 			}
2271 		}
2272 	})ABCDEF";
2273 
2274 	checkNatspec(sourceCode, "A", natspec, false);
2275 	checkNatspec(sourceCode, "B", natspec2, false);
2276 }
2277 
2278 BOOST_AUTO_TEST_CASE(dev_return_name_no_description)
2279 {
2280 	char const *sourceCode = R"(
2281 		contract A {
2282 			/// @return a
2283 			function g(int x) public pure virtual returns (int a) { return 2; }
2284 		}
2285 
2286 		contract B is A {
2287 			function g(int x) public pure override returns (int b) { return 2; }
2288 		}
2289 	)";
2290 
2291 	char const *natspec = R"ABCDEF({
2292 		"methods":
2293 		{
2294 			"g(int256)":
2295 			{
2296 				"returns":
2297 				{
2298 					"a": "a",
2299 				}
2300 			}
2301 		}
2302 	})ABCDEF";
2303 
2304 	char const *natspec2 = R"ABCDEF({
2305 		"methods":
2306 		{
2307 			"g(int256)":
2308 			{
2309 				"returns":
2310 				{
2311 					"b": "a",
2312 				}
2313 			}
2314 		}
2315 	})ABCDEF";
2316 
2317 	checkNatspec(sourceCode, "A", natspec, false);
2318 	checkNatspec(sourceCode, "B", natspec2, false);
2319 }
2320 
2321 BOOST_AUTO_TEST_CASE(error)
2322 {
2323 	char const* sourceCode = R"(
2324 		contract test {
2325 			/// Something failed.
2326 			/// @dev an error.
2327 			/// @param a first parameter
2328 			/// @param b second parameter
2329 			error E(uint a, uint b);
2330 		}
2331 	)";
2332 
2333 	char const* devdoc = R"X({
2334 		"errors":{
2335 			"E(uint256,uint256)": [{
2336 				"details" : "an error.",
2337 				"params" :
2338 				{
2339 					"a" : "first parameter",
2340 					"b" : "second parameter"
2341 				}
2342 			}]
2343 		},
2344 		"methods": {}
2345 	})X";
2346 
2347 	checkNatspec(sourceCode, "test", devdoc, false);
2348 
2349 	char const* userdoc = R"X({
2350 		"errors":{
2351 			"E(uint256,uint256)": [{
2352 				"notice" : "Something failed."
2353 			}]
2354 		},
2355 		"methods": {}
2356 	})X";
2357 	checkNatspec(sourceCode, "test", userdoc, true);
2358 }
2359 
2360 BOOST_AUTO_TEST_CASE(error_multiple)
2361 {
2362 	char const* sourceCode = R"(
2363 		contract A {
2364 			/// Something failed.
2365 			/// @dev an error.
2366 			/// @param x first parameter
2367 			/// @param y second parameter
2368 			error E(uint x, uint y);
2369 		}
2370 		contract test {
2371 			/// X Something failed.
2372 			/// @dev X an error.
2373 			/// @param a X first parameter
2374 			/// @param b X second parameter
2375 			error E(uint a, uint b);
2376 			function f(bool a) public pure {
2377 				if (a)
2378 					revert E(1, 2);
2379 				else
2380 					revert A.E(5, 6);
2381 			}
2382 		}
2383 	)";
2384 
2385 	char const* devdoc = R"X({
2386 		"methods": {},
2387 		"errors": {
2388 			"E(uint256,uint256)": [
2389 				{
2390 					"details" : "an error.",
2391 					"params" :
2392 					{
2393 						"x" : "first parameter",
2394 						"y" : "second parameter"
2395 					}
2396 				},
2397 				{
2398 					"details" : "X an error.",
2399 					"params" :
2400 					{
2401 						"a" : "X first parameter",
2402 						"b" : "X second parameter"
2403 					}
2404 				}
2405 			]
2406 		}
2407 	})X";
2408 
2409 	checkNatspec(sourceCode, "test", devdoc, false);
2410 
2411 	char const* userdoc = R"X({
2412 		"errors":{
2413 			"E(uint256,uint256)": [
2414 				{ "notice" : "Something failed." },
2415 				{ "notice" : "X Something failed." }
2416 			]
2417 		},
2418 		"methods": {}
2419 	})X";
2420 	checkNatspec(sourceCode, "test", userdoc, true);
2421 }
2422 
2423 BOOST_AUTO_TEST_CASE(custom)
2424 {
2425 	char const* sourceCode = R"(
2426 		/// @custom:x one two three
2427 		/// @custom:y line
2428 		/// break
2429 		/// @custom:t one
2430 		/// @custom:t two
2431 		contract A {
2432 			/// @custom:note statevar
2433 			uint x;
2434 			/// @custom:since 2014
2435 			function g(int x) public pure virtual returns (int, int) { return (1, 2); }
2436 		}
2437 	)";
2438 
2439 	char const* natspec = R"ABCDEF({
2440 		"custom:t": "onetwo",
2441 		"custom:x": "one two three",
2442 		"custom:y": "line break",
2443 		"methods":
2444 		{
2445 			"g(int256)":
2446 			{
2447 				"custom:since": "2014"
2448 			}
2449 		},
2450 		"stateVariables": { "x": { "custom:note": "statevar" } }
2451 	})ABCDEF";
2452 
2453 	checkNatspec(sourceCode, "A", natspec, false);
2454 }
2455 
2456 BOOST_AUTO_TEST_CASE(custom_inheritance)
2457 {
2458 	char const *sourceCode = R"(
2459 		contract A {
2460 			/// @custom:since 2014
2461 			function g(uint x) public pure virtual {}
2462 		}
2463 		contract B is A {
2464 			function g(uint x) public pure override {}
2465 		}
2466 	)";
2467 
2468 	char const* natspecA = R"ABCDEF({
2469 		"methods":
2470 		{
2471 			"g(uint256)":
2472 			{
2473 				"custom:since": "2014"
2474 			}
2475 		}
2476 	)ABCDEF";
2477 	char const* natspecB = R"ABCDEF({
2478 		"methods": {}
2479 	})ABCDEF";
2480 
2481 	checkNatspec(sourceCode, "A", natspecA, false);
2482 	checkNatspec(sourceCode, "B", natspecB, false);
2483 }
2484 
2485 BOOST_AUTO_TEST_CASE(dev_different_amount_return_parameters)
2486 {
2487 	char const *sourceCode = R"(
2488 		interface IThing {
2489 			/// @return x a number
2490 			/// @return y another number
2491 			function value() external view returns (uint128 x, uint128 y);
2492 		}
2493 
2494 		contract Thing is IThing {
2495 			struct Value {
2496 				uint128 x;
2497 				uint128 y;
2498 			}
2499 
2500 			Value public override value;
2501 		}
2502 	)";
2503 
2504 	char const *natspec = R"ABCDEF({
2505 		"methods":
2506 		{
2507 			"value()":
2508 			{
2509 			  "returns":
2510 			  {
2511 				"x": "a number",
2512 				"y": "another number"
2513 			  }
2514 			}
2515 		}
2516 	})ABCDEF";
2517 
2518 	char const *natspec2 = R"ABCDEF({
2519 		"methods": {},
2520 		"stateVariables":
2521 		{
2522 			"value":
2523 			{
2524 				"returns":
2525 				{
2526 					"x": "a number",
2527 					"y": "another number"
2528 				}
2529 			}
2530 		}
2531 	})ABCDEF";
2532 
2533 	checkNatspec(sourceCode, "IThing", natspec, false);
2534 	checkNatspec(sourceCode, "Thing", natspec2, false);
2535 }
2536 
2537 }
2538 
2539 BOOST_AUTO_TEST_SUITE_END()
2540