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