1#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
8#![allow(
15 clippy::cast_precision_loss,
16 clippy::cast_possible_truncation,
17 clippy::cast_sign_loss
18)]
19
20use std::fmt;
21
22use crate::checker::Checker;
23use crate::macros::implement_metric_trait;
24use crate::*;
25
26#[derive(Debug, Clone, PartialEq)]
31#[non_exhaustive]
32pub struct Stats {
33 fn_nargs: usize,
34 closure_nargs: usize,
35 fn_nargs_sum: usize,
36 closure_nargs_sum: usize,
37 fn_nargs_min: usize,
38 closure_nargs_min: usize,
39 fn_nargs_max: usize,
40 closure_nargs_max: usize,
41 total_functions: usize,
42 total_closures: usize,
43}
44
45impl Default for Stats {
46 fn default() -> Self {
47 Self {
48 fn_nargs: 0,
49 closure_nargs: 0,
50 fn_nargs_sum: 0,
51 closure_nargs_sum: 0,
52 fn_nargs_min: usize::MAX,
53 closure_nargs_min: usize::MAX,
54 fn_nargs_max: 0,
55 closure_nargs_max: 0,
56 total_functions: 0,
57 total_closures: 0,
58 }
59 }
60}
61
62impl fmt::Display for Stats {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 write!(
65 f,
66 "function_args: {}, closure_args: {}, function_args_average: {}, closure_args_average: {}, total: {}, average: {}, function_args_min: {}, function_args_max: {}, closure_args_min: {}, closure_args_max: {}",
67 self.function_args_sum(),
68 self.closure_args_sum(),
69 self.function_args_average(),
70 self.closure_args_average(),
71 self.total(),
72 self.average(),
73 self.function_args_min(),
74 self.function_args_max(),
75 self.closure_args_min(),
76 self.closure_args_max()
77 )
78 }
79}
80
81impl Stats {
82 pub fn merge(&mut self, other: &Stats) {
84 self.closure_nargs_min = self.closure_nargs_min.min(other.closure_nargs_min);
85 self.closure_nargs_max = self.closure_nargs_max.max(other.closure_nargs_max);
86 self.fn_nargs_min = self.fn_nargs_min.min(other.fn_nargs_min);
87 self.fn_nargs_max = self.fn_nargs_max.max(other.fn_nargs_max);
88 self.fn_nargs_sum += other.fn_nargs_sum;
89 self.closure_nargs_sum += other.closure_nargs_sum;
90 }
91
92 #[inline]
94 #[must_use]
95 pub fn function_args(&self) -> u64 {
96 self.fn_nargs as u64
97 }
98
99 #[inline]
101 #[must_use]
102 pub fn closure_args(&self) -> u64 {
103 self.closure_nargs as u64
104 }
105
106 #[inline]
108 #[must_use]
109 pub fn function_args_sum(&self) -> u64 {
110 self.fn_nargs_sum as u64
111 }
112
113 #[inline]
115 #[must_use]
116 pub fn closure_args_sum(&self) -> u64 {
117 self.closure_nargs_sum as u64
118 }
119
120 #[inline]
122 #[must_use]
123 pub fn function_args_average(&self) -> f64 {
124 crate::metrics::average(self.fn_nargs_sum as f64, self.total_functions)
125 }
126
127 #[inline]
129 #[must_use]
130 pub fn closure_args_average(&self) -> f64 {
131 crate::metrics::average(self.closure_nargs_sum as f64, self.total_closures)
132 }
133
134 #[inline]
137 #[must_use]
138 pub fn total(&self) -> u64 {
139 self.function_args_sum() + self.closure_args_sum()
140 }
141
142 #[inline]
147 #[must_use]
148 pub fn average(&self) -> f64 {
149 crate::metrics::average(
150 self.total() as f64,
151 self.total_functions + self.total_closures,
152 )
153 }
154 #[inline]
160 #[must_use]
161 pub fn function_args_min(&self) -> u64 {
162 if self.fn_nargs_min == usize::MAX {
163 0
164 } else {
165 self.fn_nargs_min as u64
166 }
167 }
168 #[inline]
170 #[must_use]
171 pub fn function_args_max(&self) -> u64 {
172 self.fn_nargs_max as u64
173 }
174 #[inline]
178 #[must_use]
179 pub fn closure_args_min(&self) -> u64 {
180 if self.closure_nargs_min == usize::MAX {
181 0
182 } else {
183 self.closure_nargs_min as u64
184 }
185 }
186 #[inline]
188 #[must_use]
189 pub fn closure_args_max(&self) -> u64 {
190 self.closure_nargs_max as u64
191 }
192 #[inline]
193 pub(crate) fn compute_sum(&mut self) {
194 self.closure_nargs_sum += self.closure_nargs;
195 self.fn_nargs_sum += self.fn_nargs;
196 }
197 #[inline]
198 pub(crate) fn compute_minmax(&mut self) {
199 self.closure_nargs_min = self.closure_nargs_min.min(self.closure_nargs);
200 self.closure_nargs_max = self.closure_nargs_max.max(self.closure_nargs);
201 self.fn_nargs_min = self.fn_nargs_min.min(self.fn_nargs);
202 self.fn_nargs_max = self.fn_nargs_max.max(self.fn_nargs);
203 self.compute_sum();
204 }
205 pub(crate) fn finalize(&mut self, total_functions: usize, total_closures: usize) {
206 self.total_functions = total_functions;
207 self.total_closures = total_closures;
208 }
209}
210
211#[inline]
212fn compute_args<T: Checker>(node: &Node, nargs: &mut usize) {
213 if let Some(params) = node.child_by_field_name("parameters") {
214 let node_params = params;
215 node_params.act_on_child(&mut |n| {
216 if !T::is_non_arg(n) {
217 *nargs += 1;
218 }
219 });
220 } else if node.child_by_field_name("parameter").is_some() {
221 *nargs += 1;
226 }
227}
228
229#[doc(hidden)]
230pub(crate) trait NArgs
232where
233 Self: Checker,
234 Self: std::marker::Sized,
235{
236 fn compute(node: &Node, stats: &mut Stats) {
239 if Self::is_func(node) {
240 compute_args::<Self>(node, &mut stats.fn_nargs);
241 return;
242 }
243
244 if Self::is_closure(node) {
245 compute_args::<Self>(node, &mut stats.closure_nargs);
246 }
247 }
248}
249
250impl NArgs for CppCode {
251 fn compute(node: &Node, stats: &mut Stats) {
252 if Self::is_func(node) {
253 if let Some(declarator) = node.child_by_field_name("declarator") {
254 let new_node = declarator;
255 compute_args::<Self>(&new_node, &mut stats.fn_nargs);
256 }
257 return;
258 }
259
260 if Self::is_closure(node)
261 && let Some(declarator) = node.child_by_field_name("declarator")
262 {
263 let new_node = declarator;
264 compute_args::<Self>(&new_node, &mut stats.closure_nargs);
265 }
266 }
267}
268
269impl NArgs for CCode {
270 fn compute(node: &Node, stats: &mut Stats) {
271 if Self::is_func(node) {
272 if let Some(declarator) = node.child_by_field_name("declarator") {
273 let new_node = declarator;
274 compute_args::<Self>(&new_node, &mut stats.fn_nargs);
275 }
276 return;
277 }
278
279 if Self::is_closure(node)
280 && let Some(declarator) = node.child_by_field_name("declarator")
281 {
282 let new_node = declarator;
283 compute_args::<Self>(&new_node, &mut stats.closure_nargs);
284 }
285 }
286}
287
288impl NArgs for MozcppCode {
289 fn compute(node: &Node, stats: &mut Stats) {
290 if Self::is_func(node) {
291 if let Some(declarator) = node.child_by_field_name("declarator") {
292 let new_node = declarator;
293 compute_args::<Self>(&new_node, &mut stats.fn_nargs);
294 }
295 return;
296 }
297
298 if Self::is_closure(node)
299 && let Some(declarator) = node.child_by_field_name("declarator")
300 {
301 let new_node = declarator;
302 compute_args::<Self>(&new_node, &mut stats.closure_nargs);
303 }
304 }
305}
306
307impl NArgs for ObjcCode {
317 fn compute(node: &Node, stats: &mut Stats) {
318 match node.kind_id().into() {
319 Objc::FunctionDefinition | Objc::FunctionDefinition2 => {
320 if let Some(declarator) = node.child_by_field_name("declarator") {
321 compute_args::<Self>(&declarator, &mut stats.fn_nargs);
322 }
323 }
324 Objc::MethodDefinition => {
325 node.act_on_child(&mut |n| {
331 if matches!(
332 n.kind_id().into(),
333 Objc::MethodParameter | Objc::MethodParameter2
334 ) {
335 stats.fn_nargs += 1;
336 }
337 });
338 }
339 Objc::BlockLiteral => {
340 if let Some(params) = node.first_child(|id| Objc::ParameterList == id) {
341 params.act_on_child(&mut |n| {
342 if matches!(
343 n.kind_id().into(),
344 Objc::ParameterDeclaration | Objc::VariadicParameter
345 ) {
346 stats.closure_nargs += 1;
347 }
348 });
349 }
350 }
351 _ => {}
352 }
353 }
354}
355
356fn compute_go_args(node: &Node, nargs: &mut usize) {
361 let Some(params) = node.child_by_field_name("parameters") else {
362 return;
363 };
364 *nargs += params
365 .children()
366 .map(|child| match child.kind_id().into() {
367 Go::ParameterDeclaration => child
368 .children()
369 .filter(|c| c.kind_id() == Go::Identifier)
370 .count()
371 .max(1),
372 Go::VariadicParameterDeclaration => 1,
373 _ => 0,
374 })
375 .sum::<usize>();
376}
377
378impl NArgs for GoCode {
379 fn compute(node: &Node, stats: &mut Stats) {
380 if Self::is_func(node) {
381 compute_go_args(node, &mut stats.fn_nargs);
382 return;
383 }
384
385 if Self::is_closure(node) {
386 compute_go_args(node, &mut stats.closure_nargs);
387 }
388 }
389}
390
391fn compute_kotlin_func_args(node: &Node, nargs: &mut usize) {
392 if let Some(params) = node
393 .children()
394 .find(|c| c.kind_id() == Kotlin::FunctionValueParameters)
395 {
396 params.act_on_child(&mut |n| {
397 if n.kind_id() == Kotlin::Parameter {
398 *nargs += 1;
399 }
400 });
401 }
402}
403
404fn compute_kotlin_lambda_args(node: &Node, nargs: &mut usize) {
405 if let Some(params) = node
409 .children()
410 .find(|c| c.kind_id() == Kotlin::LambdaParameters)
411 {
412 params.act_on_child(&mut |n| {
413 if n.kind_id() != Kotlin::COMMA {
414 *nargs += 1;
415 }
416 });
417 }
418}
419
420impl NArgs for KotlinCode {
421 fn compute(node: &Node, stats: &mut Stats) {
422 if Self::is_func(node) {
423 compute_kotlin_func_args(node, &mut stats.fn_nargs);
424 return;
425 }
426
427 if Self::is_closure(node) {
428 if node.kind_id() == Kotlin::LambdaLiteral {
429 compute_kotlin_lambda_args(node, &mut stats.closure_nargs);
430 } else {
431 compute_kotlin_func_args(node, &mut stats.closure_nargs);
432 }
433 }
434 }
435}
436
437fn compute_lua_args(node: &Node, nargs: &mut usize) {
438 let Some(params) = node.child_by_field_name("parameters") else {
439 return;
440 };
441 *nargs += params
442 .children()
443 .filter(|c| matches!(c.kind_id().into(), Lua::Identifier | Lua::VarargExpression))
444 .count();
445}
446
447impl NArgs for LuaCode {
448 fn compute(node: &Node, stats: &mut Stats) {
449 if Self::is_func(node) {
450 compute_lua_args(node, &mut stats.fn_nargs);
451 } else if Self::is_closure(node) {
452 compute_lua_args(node, &mut stats.closure_nargs);
453 }
454 }
455}
456
457fn compute_tcl_args(node: &Node, nargs: &mut usize) {
458 let Some(params) = node.child_by_field_name("arguments") else {
459 return;
460 };
461 *nargs += params
462 .children()
463 .filter(|c| c.kind_id() == Tcl::Argument)
464 .count();
465}
466
467impl NArgs for TclCode {
468 fn compute(node: &Node, stats: &mut Stats) {
469 if Self::is_func(node) {
470 compute_tcl_args(node, &mut stats.fn_nargs);
471 }
472 }
473}
474
475fn compute_irules_args(node: &Node, nargs: &mut usize) {
481 let Some(params) = node.child_by_field_name("arguments") else {
482 return;
483 };
484 *nargs += params
485 .children()
486 .filter(|c| c.kind_id() == Irules::Argument)
487 .count();
488}
489
490impl NArgs for IrulesCode {
491 fn compute(node: &Node, stats: &mut Stats) {
492 if Self::is_func(node) {
493 compute_irules_args(node, &mut stats.fn_nargs);
494 }
495 }
496}
497
498implement_metric_trait!(
499 [NArgs],
500 PythonCode,
501 MozjsCode,
502 JavascriptCode,
503 TypescriptCode,
504 TsxCode,
505 RustCode,
506 PreprocCode,
507 CcommentCode,
508 JavaCode,
509 PerlCode,
510 BashCode,
511 PhpCode,
512 CsharpCode,
513 ElixirCode,
514 RubyCode
515);
516
517impl NArgs for GroovyCode {
522 fn compute(node: &Node, stats: &mut Stats) {
523 use crate::languages::language_groovy::Groovy;
524
525 if Self::is_func(node) {
526 compute_args::<Self>(node, &mut stats.fn_nargs);
527 return;
528 }
529
530 if Self::is_closure(node)
531 && let Some(params) = node.first_child(|id| id == Groovy::ClosureParameters)
532 {
533 params.act_on_child(&mut |n| {
534 if n.kind_id() == Groovy::ClosureParameter {
535 stats.closure_nargs += 1;
536 }
537 });
538 }
539 }
540}
541
542#[cfg(test)]
543#[allow(
544 clippy::float_cmp,
545 clippy::cast_precision_loss,
546 clippy::cast_possible_truncation,
547 clippy::cast_sign_loss,
548 clippy::similar_names,
549 clippy::doc_markdown,
550 clippy::needless_raw_string_hashes,
551 clippy::too_many_lines
552)]
553mod tests {
554 use crate::tools::check_metrics;
555
556 use super::*;
557
558 #[test]
563 fn nargs_empty_file_min_is_zero() {
564 let stats = Stats::default();
565 assert_eq!(stats.function_args_min(), 0);
566 assert_eq!(stats.closure_args_min(), 0);
567 }
568
569 #[test]
570 fn python_no_functions_and_closures() {
571 check_metrics::<PythonParser>("a = 42", "foo.py", |metric| {
572 insta::assert_json_snapshot!(
574 metric.nargs,
575 @r#"
576 {
577 "function_args": 0,
578 "closure_args": 0,
579 "function_args_average": 0.0,
580 "closure_args_average": 0.0,
581 "total": 0,
582 "average": 0.0,
583 "function_args_min": 0,
584 "function_args_max": 0,
585 "closure_args_min": 0,
586 "closure_args_max": 0
587 }
588 "#
589 );
590 });
591 }
592
593 #[test]
594 fn rust_no_functions_and_closures() {
595 check_metrics::<RustParser>("let a = 42;", "foo.rs", |metric| {
596 insta::assert_json_snapshot!(
598 metric.nargs,
599 @r#"
600 {
601 "function_args": 0,
602 "closure_args": 0,
603 "function_args_average": 0.0,
604 "closure_args_average": 0.0,
605 "total": 0,
606 "average": 0.0,
607 "function_args_min": 0,
608 "function_args_max": 0,
609 "closure_args_min": 0,
610 "closure_args_max": 0
611 }
612 "#
613 );
614 });
615 }
616
617 #[test]
618 fn cpp_no_functions_and_closures() {
619 check_metrics::<CppParser>("int a = 42;", "foo.cpp", |metric| {
620 insta::assert_json_snapshot!(
622 metric.nargs,
623 @r#"
624 {
625 "function_args": 0,
626 "closure_args": 0,
627 "function_args_average": 0.0,
628 "closure_args_average": 0.0,
629 "total": 0,
630 "average": 0.0,
631 "function_args_min": 0,
632 "function_args_max": 0,
633 "closure_args_min": 0,
634 "closure_args_max": 0
635 }
636 "#
637 );
638 });
639 }
640
641 #[test]
642 fn javascript_no_functions_and_closures() {
643 check_metrics::<JavascriptParser>("var a = 42;", "foo.js", |metric| {
644 insta::assert_json_snapshot!(
646 metric.nargs,
647 @r#"
648 {
649 "function_args": 0,
650 "closure_args": 0,
651 "function_args_average": 0.0,
652 "closure_args_average": 0.0,
653 "total": 0,
654 "average": 0.0,
655 "function_args_min": 0,
656 "function_args_max": 0,
657 "closure_args_min": 0,
658 "closure_args_max": 0
659 }
660 "#
661 );
662 });
663 }
664
665 #[test]
666 fn python_single_function() {
667 check_metrics::<PythonParser>(
668 "def f(a, b):
669 if a:
670 return a",
671 "foo.py",
672 |metric| {
673 insta::assert_json_snapshot!(
675 metric.nargs,
676 @r#"
677 {
678 "function_args": 2,
679 "closure_args": 0,
680 "function_args_average": 2.0,
681 "closure_args_average": 0.0,
682 "total": 2,
683 "average": 2.0,
684 "function_args_min": 0,
685 "function_args_max": 2,
686 "closure_args_min": 0,
687 "closure_args_max": 0
688 }
689 "#
690 );
691 },
692 );
693 }
694
695 #[test]
696 fn rust_single_function() {
697 check_metrics::<RustParser>(
698 "fn f(a: bool, b: usize) {
699 if a {
700 return a;
701 }
702 }",
703 "foo.rs",
704 |metric| {
705 insta::assert_json_snapshot!(
707 metric.nargs,
708 @r#"
709 {
710 "function_args": 2,
711 "closure_args": 0,
712 "function_args_average": 2.0,
713 "closure_args_average": 0.0,
714 "total": 2,
715 "average": 2.0,
716 "function_args_min": 0,
717 "function_args_max": 2,
718 "closure_args_min": 0,
719 "closure_args_max": 0
720 }
721 "#
722 );
723 },
724 );
725 }
726
727 #[test]
728 fn c_single_function() {
729 check_metrics::<CParser>(
730 "int f(int a, int b) {
731 if (a) {
732 return a;
733 }
734 }",
735 "foo.c",
736 |metric| {
737 insta::assert_json_snapshot!(
739 metric.nargs,
740 @r#"
741 {
742 "function_args": 2,
743 "closure_args": 0,
744 "function_args_average": 2.0,
745 "closure_args_average": 0.0,
746 "total": 2,
747 "average": 2.0,
748 "function_args_min": 0,
749 "function_args_max": 2,
750 "closure_args_min": 0,
751 "closure_args_max": 0
752 }
753 "#
754 );
755 },
756 );
757 }
758
759 #[test]
760 fn javascript_single_function() {
761 check_metrics::<JavascriptParser>(
762 "function f(a, b) {
763 return a * b;
764 }",
765 "foo.js",
766 |metric| {
767 insta::assert_json_snapshot!(
769 metric.nargs,
770 @r#"
771 {
772 "function_args": 2,
773 "closure_args": 0,
774 "function_args_average": 2.0,
775 "closure_args_average": 0.0,
776 "total": 2,
777 "average": 2.0,
778 "function_args_min": 0,
779 "function_args_max": 2,
780 "closure_args_min": 0,
781 "closure_args_max": 0
782 }
783 "#
784 );
785 },
786 );
787 }
788
789 #[test]
790 fn python_single_lambda() {
791 check_metrics::<PythonParser>("bar = lambda a: True", "foo.py", |metric| {
792 insta::assert_json_snapshot!(
794 metric.nargs,
795 @r#"
796 {
797 "function_args": 0,
798 "closure_args": 1,
799 "function_args_average": 0.0,
800 "closure_args_average": 1.0,
801 "total": 1,
802 "average": 1.0,
803 "function_args_min": 0,
804 "function_args_max": 0,
805 "closure_args_min": 1,
806 "closure_args_max": 1
807 }
808 "#
809 );
810 });
811 }
812
813 #[test]
814 fn rust_single_closure() {
815 check_metrics::<RustParser>("let bar = |i: i32| -> i32 { i + 1 };", "foo.rs", |metric| {
816 insta::assert_json_snapshot!(
818 metric.nargs,
819 @r#"
820 {
821 "function_args": 0,
822 "closure_args": 1,
823 "function_args_average": 0.0,
824 "closure_args_average": 1.0,
825 "total": 1,
826 "average": 1.0,
827 "function_args_min": 0,
828 "function_args_max": 0,
829 "closure_args_min": 0,
830 "closure_args_max": 1
831 }
832 "#
833 );
834 });
835 }
836
837 #[test]
838 fn cpp_single_lambda() {
839 check_metrics::<CppParser>(
840 "auto bar = [](int x, int y) -> int { return x + y; };",
841 "foo.cpp",
842 |metric| {
843 insta::assert_json_snapshot!(
845 metric.nargs,
846 @r#"
847 {
848 "function_args": 0,
849 "closure_args": 2,
850 "function_args_average": 0.0,
851 "closure_args_average": 2.0,
852 "total": 2,
853 "average": 2.0,
854 "function_args_min": 0,
855 "function_args_max": 0,
856 "closure_args_min": 2,
857 "closure_args_max": 2
858 }
859 "#
860 );
861 },
862 );
863 }
864
865 #[test]
866 fn javascript_single_closure() {
867 check_metrics::<JavascriptParser>("function (a, b) {return a + b};", "foo.js", |metric| {
868 insta::assert_json_snapshot!(
870 metric.nargs,
871 @r#"
872 {
873 "function_args": 0,
874 "closure_args": 2,
875 "function_args_average": 0.0,
876 "closure_args_average": 2.0,
877 "total": 2,
878 "average": 2.0,
879 "function_args_min": 0,
880 "function_args_max": 0,
881 "closure_args_min": 0,
882 "closure_args_max": 2
883 }
884 "#
885 );
886 });
887 }
888
889 #[test]
890 fn python_functions() {
891 check_metrics::<PythonParser>(
892 "def f(a, b):
893 if a:
894 return a
895 def f(a, b):
896 if b:
897 return b",
898 "foo.py",
899 |metric| {
900 insta::assert_json_snapshot!(
902 metric.nargs,
903 @r#"
904 {
905 "function_args": 4,
906 "closure_args": 0,
907 "function_args_average": 2.0,
908 "closure_args_average": 0.0,
909 "total": 4,
910 "average": 2.0,
911 "function_args_min": 0,
912 "function_args_max": 2,
913 "closure_args_min": 0,
914 "closure_args_max": 0
915 }
916 "#
917 );
918 },
919 );
920
921 check_metrics::<PythonParser>(
922 "def f(a, b):
923 if a:
924 return a
925 def f(a, b, c):
926 if b:
927 return b",
928 "foo.py",
929 |metric| {
930 insta::assert_json_snapshot!(
932 metric.nargs,
933 @r#"
934 {
935 "function_args": 5,
936 "closure_args": 0,
937 "function_args_average": 2.5,
938 "closure_args_average": 0.0,
939 "total": 5,
940 "average": 2.5,
941 "function_args_min": 0,
942 "function_args_max": 3,
943 "closure_args_min": 0,
944 "closure_args_max": 0
945 }
946 "#
947 );
948 },
949 );
950 }
951
952 #[test]
953 fn rust_functions() {
954 check_metrics::<RustParser>(
955 "fn f(a: bool, b: usize) {
956 if a {
957 return a;
958 }
959 }
960 fn f1(a: bool, b: usize) {
961 if a {
962 return a;
963 }
964 }",
965 "foo.rs",
966 |metric| {
967 insta::assert_json_snapshot!(
969 metric.nargs,
970 @r#"
971 {
972 "function_args": 4,
973 "closure_args": 0,
974 "function_args_average": 2.0,
975 "closure_args_average": 0.0,
976 "total": 4,
977 "average": 2.0,
978 "function_args_min": 0,
979 "function_args_max": 2,
980 "closure_args_min": 0,
981 "closure_args_max": 0
982 }
983 "#
984 );
985 },
986 );
987
988 check_metrics::<RustParser>(
989 "fn f(a: bool, b: usize) {
990 if a {
991 return a;
992 }
993 }
994 fn f1(a: bool, b: usize, c: usize) {
995 if a {
996 return a;
997 }
998 }",
999 "foo.rs",
1000 |metric| {
1001 insta::assert_json_snapshot!(
1003 metric.nargs,
1004 @r#"
1005 {
1006 "function_args": 5,
1007 "closure_args": 0,
1008 "function_args_average": 2.5,
1009 "closure_args_average": 0.0,
1010 "total": 5,
1011 "average": 2.5,
1012 "function_args_min": 0,
1013 "function_args_max": 3,
1014 "closure_args_min": 0,
1015 "closure_args_max": 0
1016 }
1017 "#
1018 );
1019 },
1020 );
1021 }
1022
1023 #[test]
1027 fn rust_method_excludes_self_receiver() {
1028 check_metrics::<RustParser>(
1029 "struct S;
1030 impl S {
1031 fn a(self) {} // self -> 0 args
1032 fn b(&self, x: i32) {} // &self + 1 -> 1 arg
1033 fn c(&mut self, x: i32, y: i32) {} // &mut self + 2 -> 2 args
1034 }",
1035 "foo.rs",
1036 |metric| {
1037 let s = &metric.nargs;
1040 assert_eq!(s.function_args_sum(), 3);
1041 assert_eq!(s.function_args_max(), 2);
1042 },
1043 );
1044
1045 check_metrics::<RustParser>(
1052 "use std::rc::Rc;
1053 use std::pin::Pin;
1054 struct S;
1055 impl S {
1056 fn a(self: Box<Self>, x: i32, y: i32) {} // receiver + 2 -> 2
1057 fn b(self: Rc<Self>, x: i32) {} // receiver + 1 -> 1
1058 fn c(self: Pin<&mut Self>) {} // receiver -> 0
1059 }",
1060 "foo.rs",
1061 |metric| {
1062 let s = &metric.nargs;
1065 assert_eq!(s.function_args_sum(), 3);
1066 assert_eq!(s.function_args_max(), 2);
1067 },
1068 );
1069 }
1070
1071 #[test]
1072 fn c_functions() {
1073 check_metrics::<CParser>(
1074 "int f(int a, int b) {
1075 if (a) {
1076 return a;
1077 }
1078 }
1079 int f1(int a, int b) {
1080 if (a) {
1081 return a;
1082 }
1083 }",
1084 "foo.c",
1085 |metric| {
1086 insta::assert_json_snapshot!(
1088 metric.nargs,
1089 @r#"
1090 {
1091 "function_args": 4,
1092 "closure_args": 0,
1093 "function_args_average": 2.0,
1094 "closure_args_average": 0.0,
1095 "total": 4,
1096 "average": 2.0,
1097 "function_args_min": 0,
1098 "function_args_max": 2,
1099 "closure_args_min": 0,
1100 "closure_args_max": 0
1101 }
1102 "#
1103 );
1104 },
1105 );
1106
1107 check_metrics::<CppParser>(
1108 "int f(int a, int b) {
1109 if (a) {
1110 return a;
1111 }
1112 }
1113 int f1(int a, int b, int c) {
1114 if (a) {
1115 return a;
1116 }
1117 }",
1118 "foo.c",
1119 |metric| {
1120 insta::assert_json_snapshot!(
1122 metric.nargs,
1123 @r#"
1124 {
1125 "function_args": 5,
1126 "closure_args": 0,
1127 "function_args_average": 2.5,
1128 "closure_args_average": 0.0,
1129 "total": 5,
1130 "average": 2.5,
1131 "function_args_min": 0,
1132 "function_args_max": 3,
1133 "closure_args_min": 0,
1134 "closure_args_max": 0
1135 }
1136 "#
1137 );
1138 },
1139 );
1140 }
1141
1142 #[test]
1143 fn javascript_functions() {
1144 check_metrics::<JavascriptParser>(
1145 "function f(a, b) {
1146 return a * b;
1147 }
1148 function f1(a, b) {
1149 return a * b;
1150 }",
1151 "foo.js",
1152 |metric| {
1153 insta::assert_json_snapshot!(
1155 metric.nargs,
1156 @r#"
1157 {
1158 "function_args": 4,
1159 "closure_args": 0,
1160 "function_args_average": 2.0,
1161 "closure_args_average": 0.0,
1162 "total": 4,
1163 "average": 2.0,
1164 "function_args_min": 0,
1165 "function_args_max": 2,
1166 "closure_args_min": 0,
1167 "closure_args_max": 0
1168 }
1169 "#
1170 );
1171 },
1172 );
1173
1174 check_metrics::<JavascriptParser>(
1175 "function f(a, b) {
1176 return a * b;
1177 }
1178 function f1(a, b, c) {
1179 return a * b;
1180 }",
1181 "foo.js",
1182 |metric| {
1183 insta::assert_json_snapshot!(
1185 metric.nargs,
1186 @r#"
1187 {
1188 "function_args": 5,
1189 "closure_args": 0,
1190 "function_args_average": 2.5,
1191 "closure_args_average": 0.0,
1192 "total": 5,
1193 "average": 2.5,
1194 "function_args_min": 0,
1195 "function_args_max": 3,
1196 "closure_args_min": 0,
1197 "closure_args_max": 0
1198 }
1199 "#
1200 );
1201 },
1202 );
1203 }
1204
1205 #[test]
1206 fn python_nested_functions() {
1207 check_metrics::<PythonParser>(
1208 "def f(a, b):
1209 def foo(a):
1210 if a:
1211 return 1
1212 bar = lambda a: lambda b: b or True or True
1213 return bar(foo(a))(a)",
1214 "foo.py",
1215 |metric| {
1216 insta::assert_json_snapshot!(
1218 metric.nargs,
1219 @r#"
1220 {
1221 "function_args": 3,
1222 "closure_args": 2,
1223 "function_args_average": 1.5,
1224 "closure_args_average": 1.0,
1225 "total": 5,
1226 "average": 1.25,
1227 "function_args_min": 0,
1228 "function_args_max": 2,
1229 "closure_args_min": 0,
1230 "closure_args_max": 2
1231 }
1232 "#
1233 );
1234 },
1235 );
1236 }
1237
1238 #[test]
1239 fn rust_nested_functions() {
1240 check_metrics::<RustParser>(
1241 "fn f(a: i32, b: i32) -> i32 {
1242 fn foo(a: i32) -> i32 {
1243 return a;
1244 }
1245 let bar = |a: i32, b: i32| -> i32 { a + 1 };
1246 let bar1 = |b: i32| -> i32 { b + 1 };
1247 return bar(foo(a), a);
1248 }",
1249 "foo.rs",
1250 |metric| {
1251 insta::assert_json_snapshot!(
1253 metric.nargs,
1254 @r#"
1255 {
1256 "function_args": 3,
1257 "closure_args": 3,
1258 "function_args_average": 1.5,
1259 "closure_args_average": 1.5,
1260 "total": 6,
1261 "average": 1.5,
1262 "function_args_min": 0,
1263 "function_args_max": 2,
1264 "closure_args_min": 0,
1265 "closure_args_max": 2
1266 }
1267 "#
1268 );
1269 },
1270 );
1271 }
1272
1273 #[test]
1274 fn cpp_nested_functions() {
1275 check_metrics::<CppParser>(
1276 "int f(int a, int b, int c) {
1277 auto foo = [](int x) -> int { return x; };
1278 auto bar = [](int x, int y) -> int { return x + y; };
1279 return bar(foo(a), a);
1280 }",
1281 "foo.cpp",
1282 |metric| {
1283 insta::assert_json_snapshot!(
1285 metric.nargs,
1286 @r#"
1287 {
1288 "function_args": 3,
1289 "closure_args": 3,
1290 "function_args_average": 3.0,
1291 "closure_args_average": 1.5,
1292 "total": 6,
1293 "average": 2.0,
1294 "function_args_min": 0,
1295 "function_args_max": 3,
1296 "closure_args_min": 0,
1297 "closure_args_max": 3
1298 }
1299 "#
1300 );
1301 },
1302 );
1303 }
1304
1305 #[test]
1309 fn cpp_default_arguments() {
1310 check_metrics::<CppParser>(
1311 "int f(int a, int b, int c = 0) {
1312 return a + b + c;
1313 }",
1314 "foo.cpp",
1315 |metric| {
1316 let s = &metric.nargs;
1318 assert_eq!(s.function_args_sum(), 3);
1319 assert_eq!(s.function_args_max(), 3);
1320 insta::assert_json_snapshot!(
1321 metric.nargs,
1322 @r#"
1323 {
1324 "function_args": 3,
1325 "closure_args": 0,
1326 "function_args_average": 3.0,
1327 "closure_args_average": 0.0,
1328 "total": 3,
1329 "average": 3.0,
1330 "function_args_min": 0,
1331 "function_args_max": 3,
1332 "closure_args_min": 0,
1333 "closure_args_max": 0
1334 }
1335 "#
1336 );
1337 },
1338 );
1339 }
1340
1341 #[test]
1346 fn c_variadic_function() {
1347 check_metrics::<CParser>(
1348 "int printf(const char* fmt, ...) {
1349 return 0;
1350 }",
1351 "foo.c",
1352 |metric| {
1353 let s = &metric.nargs;
1355 assert_eq!(s.function_args_sum(), 2);
1356 assert_eq!(s.function_args_max(), 2);
1357 insta::assert_json_snapshot!(
1358 metric.nargs,
1359 @r#"
1360 {
1361 "function_args": 2,
1362 "closure_args": 0,
1363 "function_args_average": 2.0,
1364 "closure_args_average": 0.0,
1365 "total": 2,
1366 "average": 2.0,
1367 "function_args_min": 0,
1368 "function_args_max": 2,
1369 "closure_args_min": 0,
1370 "closure_args_max": 0
1371 }
1372 "#
1373 );
1374 },
1375 );
1376 }
1377
1378 #[test]
1385 fn cpp_template_parameter_pack() {
1386 check_metrics::<CppParser>(
1387 "template<typename... Args>
1388 int sum(int seed, Args... args) {
1389 return seed;
1390 }",
1391 "foo.cpp",
1392 |metric| {
1393 let s = &metric.nargs;
1395 assert_eq!(s.function_args_sum(), 2);
1396 assert_eq!(s.function_args_max(), 2);
1397 insta::assert_json_snapshot!(
1398 metric.nargs,
1399 @r#"
1400 {
1401 "function_args": 2,
1402 "closure_args": 0,
1403 "function_args_average": 2.0,
1404 "closure_args_average": 0.0,
1405 "total": 2,
1406 "average": 2.0,
1407 "function_args_min": 0,
1408 "function_args_max": 2,
1409 "closure_args_min": 0,
1410 "closure_args_max": 0
1411 }
1412 "#
1413 );
1414 },
1415 );
1416 }
1417
1418 #[test]
1423 fn cpp_lambda_capture_not_counted() {
1424 check_metrics::<CppParser>(
1425 "int f() {
1426 int x = 1;
1427 int y = 2;
1428 auto g = [=, &x](int a, int b) -> int { return a + b + x + y; };
1429 return g(1, 2);
1430 }",
1431 "foo.cpp",
1432 |metric| {
1433 let s = &metric.nargs;
1435 assert_eq!(s.function_args_sum(), 0);
1436 assert_eq!(s.closure_args_sum(), 2);
1437 assert_eq!(s.closure_args_max(), 2);
1438 insta::assert_json_snapshot!(
1439 metric.nargs,
1440 @r#"
1441 {
1442 "function_args": 0,
1443 "closure_args": 2,
1444 "function_args_average": 0.0,
1445 "closure_args_average": 2.0,
1446 "total": 2,
1447 "average": 1.0,
1448 "function_args_min": 0,
1449 "function_args_max": 0,
1450 "closure_args_min": 0,
1451 "closure_args_max": 2
1452 }
1453 "#
1454 );
1455 },
1456 );
1457 }
1458
1459 #[test]
1464 fn cpp_member_function_this_not_counted() {
1465 check_metrics::<CppParser>(
1466 "struct S {
1467 int x;
1468 int set(int a) { // implicit `this` is NOT counted
1469 this->x = a;
1470 return a;
1471 }
1472 };",
1473 "foo.cpp",
1474 |metric| {
1475 let s = &metric.nargs;
1477 assert_eq!(s.function_args_sum(), 1);
1478 assert_eq!(s.function_args_max(), 1);
1479 insta::assert_json_snapshot!(
1480 metric.nargs,
1481 @r#"
1482 {
1483 "function_args": 1,
1484 "closure_args": 0,
1485 "function_args_average": 1.0,
1486 "closure_args_average": 0.0,
1487 "total": 1,
1488 "average": 1.0,
1489 "function_args_min": 0,
1490 "function_args_max": 1,
1491 "closure_args_min": 0,
1492 "closure_args_max": 0
1493 }
1494 "#
1495 );
1496 },
1497 );
1498 }
1499
1500 #[test]
1501 fn go_zero_args() {
1502 check_metrics::<GoParser>(
1503 "package main
1504 func f() {}",
1505 "foo.go",
1506 |metric| {
1507 insta::assert_json_snapshot!(
1508 metric.nargs,
1509 @r#"
1510 {
1511 "function_args": 0,
1512 "closure_args": 0,
1513 "function_args_average": 0.0,
1514 "closure_args_average": 0.0,
1515 "total": 0,
1516 "average": 0.0,
1517 "function_args_min": 0,
1518 "function_args_max": 0,
1519 "closure_args_min": 0,
1520 "closure_args_max": 0
1521 }
1522 "#
1523 );
1524 },
1525 );
1526 }
1527
1528 #[test]
1529 fn go_multiple_args() {
1530 check_metrics::<GoParser>(
1531 "package main
1532 func f(a int, b string, c bool) {}",
1533 "foo.go",
1534 |metric| {
1535 insta::assert_json_snapshot!(
1536 metric.nargs,
1537 @r#"
1538 {
1539 "function_args": 3,
1540 "closure_args": 0,
1541 "function_args_average": 3.0,
1542 "closure_args_average": 0.0,
1543 "total": 3,
1544 "average": 3.0,
1545 "function_args_min": 0,
1546 "function_args_max": 3,
1547 "closure_args_min": 0,
1548 "closure_args_max": 0
1549 }
1550 "#
1551 );
1552 },
1553 );
1554 }
1555
1556 #[test]
1557 fn go_method_excludes_receiver() {
1558 check_metrics::<GoParser>(
1559 "package main
1560 type T struct{}
1561 func (t *T) Greet(name string) string {
1562 return name
1563 }",
1564 "foo.go",
1565 |metric| {
1566 insta::assert_json_snapshot!(
1568 metric.nargs,
1569 @r#"
1570 {
1571 "function_args": 1,
1572 "closure_args": 0,
1573 "function_args_average": 1.0,
1574 "closure_args_average": 0.0,
1575 "total": 1,
1576 "average": 1.0,
1577 "function_args_min": 0,
1578 "function_args_max": 1,
1579 "closure_args_min": 0,
1580 "closure_args_max": 0
1581 }
1582 "#
1583 );
1584 },
1585 );
1586 }
1587
1588 #[test]
1589 fn go_variadic() {
1590 check_metrics::<GoParser>(
1591 "package main
1592 func f(args ...int) {}",
1593 "foo.go",
1594 |metric| {
1595 insta::assert_json_snapshot!(
1596 metric.nargs,
1597 @r#"
1598 {
1599 "function_args": 1,
1600 "closure_args": 0,
1601 "function_args_average": 1.0,
1602 "closure_args_average": 0.0,
1603 "total": 1,
1604 "average": 1.0,
1605 "function_args_min": 0,
1606 "function_args_max": 1,
1607 "closure_args_min": 0,
1608 "closure_args_max": 0
1609 }
1610 "#
1611 );
1612 },
1613 );
1614 }
1615
1616 #[test]
1617 fn go_grouped_params() {
1618 check_metrics::<GoParser>(
1619 "package main
1620 func f(a, b int, c string) {}",
1621 "foo.go",
1622 |metric| {
1623 insta::assert_json_snapshot!(
1626 metric.nargs,
1627 @r#"
1628 {
1629 "function_args": 3,
1630 "closure_args": 0,
1631 "function_args_average": 3.0,
1632 "closure_args_average": 0.0,
1633 "total": 3,
1634 "average": 3.0,
1635 "function_args_min": 0,
1636 "function_args_max": 3,
1637 "closure_args_min": 0,
1638 "closure_args_max": 0
1639 }
1640 "#
1641 );
1642 },
1643 );
1644 }
1645
1646 #[test]
1647 fn go_func_literal_args() {
1648 check_metrics::<GoParser>(
1649 "package main
1650 var f = func(x, y int) int { return x + y }",
1651 "foo.go",
1652 |metric| {
1653 insta::assert_json_snapshot!(
1655 metric.nargs,
1656 @r#"
1657 {
1658 "function_args": 0,
1659 "closure_args": 2,
1660 "function_args_average": 0.0,
1661 "closure_args_average": 2.0,
1662 "total": 2,
1663 "average": 2.0,
1664 "function_args_min": 0,
1665 "function_args_max": 0,
1666 "closure_args_min": 0,
1667 "closure_args_max": 2
1668 }
1669 "#
1670 );
1671 },
1672 );
1673 }
1674
1675 #[test]
1676 fn javascript_nested_functions() {
1677 check_metrics::<JavascriptParser>(
1678 "function f(a, b) {
1679 function foo(a, c) {
1680 return a;
1681 }
1682 var bar = function (a, b) {return a + b};
1683 function (a) {return a};
1684 return bar(foo(a), a);
1685 }",
1686 "foo.js",
1687 |metric| {
1688 insta::assert_json_snapshot!(
1690 metric.nargs,
1691 @r#"
1692 {
1693 "function_args": 6,
1694 "closure_args": 1,
1695 "function_args_average": 2.0,
1696 "closure_args_average": 1.0,
1697 "total": 7,
1698 "average": 1.75,
1699 "function_args_min": 0,
1700 "function_args_max": 2,
1701 "closure_args_min": 0,
1702 "closure_args_max": 1
1703 }
1704 "#
1705 );
1706 },
1707 );
1708 }
1709
1710 #[test]
1711 fn perl_no_functions_and_closures() {
1712 check_metrics::<PerlParser>(
1713 "my $x = 1;
1714 print $x;",
1715 "foo.pl",
1716 |metric| {
1717 assert_eq!(metric.nom.functions_sum(), 0);
1722 assert_eq!(metric.nom.closures_sum(), 0);
1723 insta::assert_json_snapshot!(
1724 metric.nargs,
1725 @r#"
1726 {
1727 "function_args": 0,
1728 "closure_args": 0,
1729 "function_args_average": 0.0,
1730 "closure_args_average": 0.0,
1731 "total": 0,
1732 "average": 0.0,
1733 "function_args_min": 0,
1734 "function_args_max": 0,
1735 "closure_args_min": 0,
1736 "closure_args_max": 0
1737 }
1738 "#
1739 );
1740 },
1741 );
1742 }
1743
1744 #[test]
1745 fn perl_single_function() {
1746 check_metrics::<PerlParser>(
1751 "sub greet {
1752 my ($name) = @_;
1753 print \"hi $name\";
1754 }",
1755 "foo.pl",
1756 |metric| {
1757 assert_eq!(metric.nom.functions_sum(), 1);
1758 assert_eq!(metric.nom.closures_sum(), 0);
1759 insta::assert_json_snapshot!(
1760 metric.nargs,
1761 @r#"
1762 {
1763 "function_args": 0,
1764 "closure_args": 0,
1765 "function_args_average": 0.0,
1766 "closure_args_average": 0.0,
1767 "total": 0,
1768 "average": 0.0,
1769 "function_args_min": 0,
1770 "function_args_max": 0,
1771 "closure_args_min": 0,
1772 "closure_args_max": 0
1773 }
1774 "#
1775 );
1776 },
1777 );
1778 }
1779
1780 #[test]
1781 fn perl_single_closure() {
1782 check_metrics::<PerlParser>(
1786 "my $f = sub {
1787 my ($x) = @_;
1788 return $x + 1;
1789 };",
1790 "foo.pl",
1791 |metric| {
1792 assert_eq!(metric.nom.functions_sum(), 0);
1793 assert_eq!(metric.nom.closures_sum(), 1);
1794 insta::assert_json_snapshot!(
1795 metric.nargs,
1796 @r#"
1797 {
1798 "function_args": 0,
1799 "closure_args": 0,
1800 "function_args_average": 0.0,
1801 "closure_args_average": 0.0,
1802 "total": 0,
1803 "average": 0.0,
1804 "function_args_min": 0,
1805 "function_args_max": 0,
1806 "closure_args_min": 0,
1807 "closure_args_max": 0
1808 }
1809 "#
1810 );
1811 },
1812 );
1813 }
1814
1815 #[test]
1816 fn perl_multiple_functions() {
1817 check_metrics::<PerlParser>(
1820 "sub a { return 1; }
1821 sub b {
1822 my ($x, $y) = @_;
1823 return $x + $y;
1824 }",
1825 "foo.pl",
1826 |metric| {
1827 assert_eq!(metric.nom.functions_sum(), 2);
1828 assert_eq!(metric.nom.closures_sum(), 0);
1829 insta::assert_json_snapshot!(
1830 metric.nargs,
1831 @r#"
1832 {
1833 "function_args": 0,
1834 "closure_args": 0,
1835 "function_args_average": 0.0,
1836 "closure_args_average": 0.0,
1837 "total": 0,
1838 "average": 0.0,
1839 "function_args_min": 0,
1840 "function_args_max": 0,
1841 "closure_args_min": 0,
1842 "closure_args_max": 0
1843 }
1844 "#
1845 );
1846 },
1847 );
1848 }
1849
1850 #[test]
1851 fn perl_nested_closure() {
1852 check_metrics::<PerlParser>(
1855 "sub outer {
1856 my $inner = sub { return 42; };
1857 return $inner->();
1858 }",
1859 "foo.pl",
1860 |metric| {
1861 assert_eq!(metric.nom.functions_sum(), 1);
1862 assert_eq!(metric.nom.closures_sum(), 1);
1863 insta::assert_json_snapshot!(
1864 metric.nargs,
1865 @r#"
1866 {
1867 "function_args": 0,
1868 "closure_args": 0,
1869 "function_args_average": 0.0,
1870 "closure_args_average": 0.0,
1871 "total": 0,
1872 "average": 0.0,
1873 "function_args_min": 0,
1874 "function_args_max": 0,
1875 "closure_args_min": 0,
1876 "closure_args_max": 0
1877 }
1878 "#
1879 );
1880 },
1881 );
1882 }
1883
1884 #[test]
1885 fn java_no_functions() {
1886 check_metrics::<JavaParser>(
1887 "class Foo {
1888 int x = 42;
1889 String name = \"hello\";
1890 }",
1891 "foo.java",
1892 |metric| {
1893 insta::assert_json_snapshot!(
1894 metric.nargs,
1895 @r#"
1896 {
1897 "function_args": 0,
1898 "closure_args": 0,
1899 "function_args_average": 0.0,
1900 "closure_args_average": 0.0,
1901 "total": 0,
1902 "average": 0.0,
1903 "function_args_min": 0,
1904 "function_args_max": 0,
1905 "closure_args_min": 0,
1906 "closure_args_max": 0
1907 }
1908 "#
1909 );
1910 },
1911 );
1912 }
1913
1914 #[test]
1915 fn java_single_method() {
1916 check_metrics::<JavaParser>(
1917 "class Foo {
1918 void greet(String name, int count) {
1919 return;
1920 }
1921 }",
1922 "foo.java",
1923 |metric| {
1924 insta::assert_json_snapshot!(
1925 metric.nargs,
1926 @r#"
1927 {
1928 "function_args": 2,
1929 "closure_args": 0,
1930 "function_args_average": 2.0,
1931 "closure_args_average": 0.0,
1932 "total": 2,
1933 "average": 2.0,
1934 "function_args_min": 0,
1935 "function_args_max": 2,
1936 "closure_args_min": 0,
1937 "closure_args_max": 0
1938 }
1939 "#
1940 );
1941 },
1942 );
1943 }
1944
1945 #[test]
1946 fn java_multiple_methods() {
1947 check_metrics::<JavaParser>(
1948 "class Foo {
1949 void a(int x) {
1950 return;
1951 }
1952 void b(int x, int y, int z) {
1953 return;
1954 }
1955 }",
1956 "foo.java",
1957 |metric| {
1958 insta::assert_json_snapshot!(
1959 metric.nargs,
1960 @r#"
1961 {
1962 "function_args": 4,
1963 "closure_args": 0,
1964 "function_args_average": 2.0,
1965 "closure_args_average": 0.0,
1966 "total": 4,
1967 "average": 2.0,
1968 "function_args_min": 0,
1969 "function_args_max": 3,
1970 "closure_args_min": 0,
1971 "closure_args_max": 0
1972 }
1973 "#
1974 );
1975 },
1976 );
1977 }
1978
1979 #[test]
1980 fn java_constructor_args() {
1981 check_metrics::<JavaParser>(
1982 "class Foo {
1983 Foo(String name, int age) {
1984 return;
1985 }
1986 }",
1987 "foo.java",
1988 |metric| {
1989 insta::assert_json_snapshot!(
1990 metric.nargs,
1991 @r#"
1992 {
1993 "function_args": 2,
1994 "closure_args": 0,
1995 "function_args_average": 2.0,
1996 "closure_args_average": 0.0,
1997 "total": 2,
1998 "average": 2.0,
1999 "function_args_min": 0,
2000 "function_args_max": 2,
2001 "closure_args_min": 0,
2002 "closure_args_max": 0
2003 }
2004 "#
2005 );
2006 },
2007 );
2008 }
2009
2010 #[test]
2016 fn java_method_excludes_explicit_receiver() {
2017 check_metrics::<JavaParser>(
2018 "class S {
2019 void m(S this, int a) {} // receiver + 1 -> 1 arg
2020 void n(int a, int b) {} // control: 2 real params
2021 void r(S this) {} // receiver only -> 0 args
2022 }",
2023 "foo.java",
2024 |metric| {
2025 let s = &metric.nargs;
2029 assert_eq!(s.function_args_sum(), 3);
2030 assert_eq!(s.function_args_max(), 2);
2031 },
2032 );
2033 }
2034
2035 #[test]
2036 fn java_lambda_args() {
2037 check_metrics::<JavaParser>(
2038 "class Foo {
2039 void run() {
2040 Runnable r = (int a, int b) -> a + b;
2041 }
2042 }",
2043 "foo.java",
2044 |metric| {
2045 insta::assert_json_snapshot!(
2046 metric.nargs,
2047 @r#"
2048 {
2049 "function_args": 0,
2050 "closure_args": 2,
2051 "function_args_average": 0.0,
2052 "closure_args_average": 2.0,
2053 "total": 2,
2054 "average": 1.0,
2055 "function_args_min": 0,
2056 "function_args_max": 0,
2057 "closure_args_min": 0,
2058 "closure_args_max": 2
2059 }
2060 "#
2061 );
2062 },
2063 );
2064 }
2065
2066 #[test]
2067 fn groovy_no_functions_and_closures() {
2068 check_metrics::<GroovyParser>("int x = 1", "foo.groovy", |metric| {
2069 assert_eq!(metric.nargs.total(), 0);
2070 });
2071 }
2072
2073 #[test]
2074 fn groovy_single_method() {
2075 check_metrics::<GroovyParser>(
2076 "class A {
2077 void greet(String name, int times) {
2078 println(name)
2079 }
2080 }",
2081 "foo.groovy",
2082 |metric| {
2083 assert_eq!(metric.nargs.function_args_sum(), 2);
2084 assert_eq!(metric.nargs.closure_args_sum(), 0);
2085 },
2086 );
2087 }
2088
2089 #[test]
2090 fn groovy_multiple_methods() {
2091 check_metrics::<GroovyParser>(
2092 "class A {
2093 int add(int x, int y) { x + y }
2094 int sub(int x, int y, int z) { x - y - z }
2095 }",
2096 "foo.groovy",
2097 |metric| {
2098 assert_eq!(metric.nargs.function_args_sum(), 5);
2099 },
2100 );
2101 }
2102
2103 #[test]
2104 fn groovy_lambda_args() {
2105 check_metrics::<GroovyParser>(
2111 "class Foo {
2112 void run() {
2113 def f = { int a, int b -> a + b }
2114 }
2115 }",
2116 "foo.groovy",
2117 |metric| {
2118 assert_eq!(metric.nargs.closure_args_sum(), 2);
2119 },
2120 );
2121 }
2122
2123 #[test]
2124 fn groovy_implicit_it_not_counted() {
2125 check_metrics::<GroovyParser>(
2129 "class A {
2130 void apply() {
2131 [1, 2, 3].each { println(it) }
2132 }
2133 }",
2134 "foo.groovy",
2135 |metric| {
2136 assert_eq!(metric.nargs.closure_args_sum(), 0);
2137 },
2138 );
2139 }
2140
2141 #[test]
2142 fn csharp_no_functions() {
2143 check_metrics::<CsharpParser>(
2144 "class Foo {
2145 int x = 42;
2146 string Name = \"hello\";
2147 }",
2148 "foo.cs",
2149 |metric| {
2150 insta::assert_json_snapshot!(
2151 metric.nargs,
2152 @r#"
2153 {
2154 "function_args": 0,
2155 "closure_args": 0,
2156 "function_args_average": 0.0,
2157 "closure_args_average": 0.0,
2158 "total": 0,
2159 "average": 0.0,
2160 "function_args_min": 0,
2161 "function_args_max": 0,
2162 "closure_args_min": 0,
2163 "closure_args_max": 0
2164 }
2165 "#
2166 );
2167 },
2168 );
2169 }
2170
2171 #[test]
2172 fn csharp_single_method() {
2173 check_metrics::<CsharpParser>(
2174 "class Foo {
2175 void Greet(string name, int count) {
2176 return;
2177 }
2178 }",
2179 "foo.cs",
2180 |metric| {
2181 insta::assert_json_snapshot!(
2182 metric.nargs,
2183 @r#"
2184 {
2185 "function_args": 2,
2186 "closure_args": 0,
2187 "function_args_average": 2.0,
2188 "closure_args_average": 0.0,
2189 "total": 2,
2190 "average": 2.0,
2191 "function_args_min": 0,
2192 "function_args_max": 2,
2193 "closure_args_min": 0,
2194 "closure_args_max": 0
2195 }
2196 "#
2197 );
2198 },
2199 );
2200 }
2201
2202 #[test]
2203 fn csharp_multiple_methods() {
2204 check_metrics::<CsharpParser>(
2205 "class Foo {
2206 void A(int x) {
2207 return;
2208 }
2209 void B(int x, int y, int z) {
2210 return;
2211 }
2212 }",
2213 "foo.cs",
2214 |metric| {
2215 insta::assert_json_snapshot!(
2216 metric.nargs,
2217 @r#"
2218 {
2219 "function_args": 4,
2220 "closure_args": 0,
2221 "function_args_average": 2.0,
2222 "closure_args_average": 0.0,
2223 "total": 4,
2224 "average": 2.0,
2225 "function_args_min": 0,
2226 "function_args_max": 3,
2227 "closure_args_min": 0,
2228 "closure_args_max": 0
2229 }
2230 "#
2231 );
2232 },
2233 );
2234 }
2235
2236 #[test]
2237 fn csharp_constructor_args() {
2238 check_metrics::<CsharpParser>(
2239 "class Foo {
2240 public Foo(string name, int age) {
2241 return;
2242 }
2243 }",
2244 "foo.cs",
2245 |metric| {
2246 insta::assert_json_snapshot!(
2247 metric.nargs,
2248 @r#"
2249 {
2250 "function_args": 2,
2251 "closure_args": 0,
2252 "function_args_average": 2.0,
2253 "closure_args_average": 0.0,
2254 "total": 2,
2255 "average": 2.0,
2256 "function_args_min": 0,
2257 "function_args_max": 2,
2258 "closure_args_min": 0,
2259 "closure_args_max": 0
2260 }
2261 "#
2262 );
2263 },
2264 );
2265 }
2266
2267 #[test]
2268 fn csharp_lambda_args() {
2269 check_metrics::<CsharpParser>(
2270 "class Foo {
2271 void Run() {
2272 System.Func<int, int, int> f = (int a, int b) => a + b;
2273 }
2274 }",
2275 "foo.cs",
2276 |metric| {
2277 insta::assert_json_snapshot!(
2278 metric.nargs,
2279 @r#"
2280 {
2281 "function_args": 0,
2282 "closure_args": 2,
2283 "function_args_average": 0.0,
2284 "closure_args_average": 2.0,
2285 "total": 2,
2286 "average": 1.0,
2287 "function_args_min": 0,
2288 "function_args_max": 0,
2289 "closure_args_min": 0,
2290 "closure_args_max": 2
2291 }
2292 "#
2293 );
2294 },
2295 );
2296 }
2297
2298 #[test]
2299 fn tsx_function_and_arrow() {
2300 check_metrics::<TsxParser>(
2301 "function add(a: number, b: number): number {
2302 return a + b;
2303 }
2304 const multiply = (x: number, y: number) => x * y;",
2305 "foo.tsx",
2306 |metric| {
2307 insta::assert_json_snapshot!(
2308 metric.nargs,
2309 @r#"
2310 {
2311 "function_args": 4,
2312 "closure_args": 0,
2313 "function_args_average": 2.0,
2314 "closure_args_average": 0.0,
2315 "total": 4,
2316 "average": 2.0,
2317 "function_args_min": 0,
2318 "function_args_max": 2,
2319 "closure_args_min": 0,
2320 "closure_args_max": 0
2321 }
2322 "#
2323 );
2324 },
2325 );
2326 }
2327
2328 #[test]
2329 fn typescript_typed_and_optional_params() {
2330 check_metrics::<TypescriptParser>(
2331 "function format(value: number, prefix?: string, suffix?: string): string {
2332 return (prefix ?? '') + value.toString() + (suffix ?? '');
2333 }
2334 const identity = (x: number): number => x;",
2335 "foo.ts",
2336 |metric| {
2337 insta::assert_json_snapshot!(
2338 metric.nargs,
2339 @r#"
2340 {
2341 "function_args": 4,
2342 "closure_args": 0,
2343 "function_args_average": 2.0,
2344 "closure_args_average": 0.0,
2345 "total": 4,
2346 "average": 2.0,
2347 "function_args_min": 0,
2348 "function_args_max": 3,
2349 "closure_args_min": 0,
2350 "closure_args_max": 0
2351 }
2352 "#
2353 );
2354 },
2355 );
2356 }
2357
2358 #[test]
2359 fn mozjs_single_function() {
2360 check_metrics::<MozjsParser>(
2361 "function f(a, b) {
2362 return a * b;
2363 }",
2364 "foo.js",
2365 |metric| {
2366 insta::assert_json_snapshot!(
2367 metric.nargs,
2368 @r#"
2369 {
2370 "function_args": 2,
2371 "closure_args": 0,
2372 "function_args_average": 2.0,
2373 "closure_args_average": 0.0,
2374 "total": 2,
2375 "average": 2.0,
2376 "function_args_min": 0,
2377 "function_args_max": 2,
2378 "closure_args_min": 0,
2379 "closure_args_max": 0
2380 }
2381 "#
2382 );
2383 },
2384 );
2385 }
2386
2387 #[test]
2388 fn mozjs_closure_args() {
2389 check_metrics::<MozjsParser>("function (a, b) {return a + b};", "foo.js", |metric| {
2390 insta::assert_json_snapshot!(
2391 metric.nargs,
2392 @r#"
2393 {
2394 "function_args": 0,
2395 "closure_args": 2,
2396 "function_args_average": 0.0,
2397 "closure_args_average": 2.0,
2398 "total": 2,
2399 "average": 2.0,
2400 "function_args_min": 0,
2401 "function_args_max": 0,
2402 "closure_args_min": 0,
2403 "closure_args_max": 2
2404 }
2405 "#
2406 );
2407 });
2408 }
2409
2410 #[test]
2420 fn javascript_bare_arrow_function() {
2421 check_metrics::<JavascriptParser>("const f = x => x;", "foo.js", |metric| {
2422 assert_eq!(metric.nargs.total(), 1);
2423 });
2424 }
2425
2426 #[test]
2427 fn javascript_async_bare_arrow_function() {
2428 check_metrics::<JavascriptParser>("const f = async x => x;", "foo.js", |metric| {
2429 assert_eq!(metric.nargs.total(), 1);
2430 });
2431 }
2432
2433 #[test]
2434 fn javascript_parenthesized_arrow_function() {
2435 check_metrics::<JavascriptParser>("const f = (x) => x;", "foo.js", |metric| {
2436 assert_eq!(metric.nargs.total(), 1);
2437 });
2438 }
2439
2440 #[test]
2441 fn javascript_multi_parenthesized_arrow_function() {
2442 check_metrics::<JavascriptParser>("const f = (x, y) => x + y;", "foo.js", |metric| {
2443 assert_eq!(metric.nargs.total(), 2);
2444 });
2445 }
2446
2447 #[test]
2448 fn typescript_bare_arrow_function() {
2449 check_metrics::<TypescriptParser>("const f = x => x;", "foo.ts", |metric| {
2450 assert_eq!(metric.nargs.total(), 1);
2451 });
2452 }
2453
2454 #[test]
2455 fn typescript_async_bare_arrow_function() {
2456 check_metrics::<TypescriptParser>("const f = async x => x;", "foo.ts", |metric| {
2457 assert_eq!(metric.nargs.total(), 1);
2458 });
2459 }
2460
2461 #[test]
2462 fn typescript_parenthesized_arrow_function() {
2463 check_metrics::<TypescriptParser>("const f = (x: number) => x;", "foo.ts", |metric| {
2464 assert_eq!(metric.nargs.total(), 1);
2465 });
2466 }
2467
2468 #[test]
2469 fn typescript_multi_parenthesized_arrow_function() {
2470 check_metrics::<TypescriptParser>(
2471 "const f = (x: number, y: number) => x + y;",
2472 "foo.ts",
2473 |metric| {
2474 assert_eq!(metric.nargs.total(), 2);
2475 },
2476 );
2477 }
2478
2479 #[test]
2480 fn tsx_bare_arrow_function() {
2481 check_metrics::<TsxParser>("const f = x => x;", "foo.tsx", |metric| {
2482 assert_eq!(metric.nargs.total(), 1);
2483 });
2484 }
2485
2486 #[test]
2487 fn tsx_async_bare_arrow_function() {
2488 check_metrics::<TsxParser>("const f = async x => x;", "foo.tsx", |metric| {
2489 assert_eq!(metric.nargs.total(), 1);
2490 });
2491 }
2492
2493 #[test]
2494 fn tsx_parenthesized_arrow_function() {
2495 check_metrics::<TsxParser>("const f = (x: number) => x;", "foo.tsx", |metric| {
2496 assert_eq!(metric.nargs.total(), 1);
2497 });
2498 }
2499
2500 #[test]
2501 fn tsx_multi_parenthesized_arrow_function() {
2502 check_metrics::<TsxParser>(
2503 "const f = (x: number, y: number) => x + y;",
2504 "foo.tsx",
2505 |metric| {
2506 assert_eq!(metric.nargs.total(), 2);
2507 },
2508 );
2509 }
2510
2511 #[test]
2512 fn mozjs_bare_arrow_function() {
2513 check_metrics::<MozjsParser>("const f = x => x;", "foo.js", |metric| {
2514 assert_eq!(metric.nargs.total(), 1);
2515 });
2516 }
2517
2518 #[test]
2519 fn mozjs_async_bare_arrow_function() {
2520 check_metrics::<MozjsParser>("const f = async x => x;", "foo.js", |metric| {
2521 assert_eq!(metric.nargs.total(), 1);
2522 });
2523 }
2524
2525 #[test]
2526 fn mozjs_parenthesized_arrow_function() {
2527 check_metrics::<MozjsParser>("const f = (x) => x;", "foo.js", |metric| {
2528 assert_eq!(metric.nargs.total(), 1);
2529 });
2530 }
2531
2532 #[test]
2533 fn mozjs_multi_parenthesized_arrow_function() {
2534 check_metrics::<MozjsParser>("const f = (x, y) => x + y;", "foo.js", |metric| {
2535 assert_eq!(metric.nargs.total(), 2);
2536 });
2537 }
2538
2539 #[test]
2540 fn kotlin_nargs_functions_and_closures() {
2541 check_metrics::<KotlinParser>(
2542 "fun add(a: Int, b: Int): Int {
2543 val transform = { x: Int, y: Int -> x + y }
2544 return transform(a, b)
2545 }",
2546 "foo.kt",
2547 |metric| {
2548 insta::assert_json_snapshot!(
2549 metric.nargs,
2550 @r#"
2551 {
2552 "function_args": 2,
2553 "closure_args": 2,
2554 "function_args_average": 2.0,
2555 "closure_args_average": 2.0,
2556 "total": 4,
2557 "average": 2.0,
2558 "function_args_min": 0,
2559 "function_args_max": 2,
2560 "closure_args_min": 0,
2561 "closure_args_max": 2
2562 }
2563 "#
2564 );
2565 },
2566 );
2567 }
2568
2569 #[test]
2570 fn lua_no_functions_and_closures() {
2571 check_metrics::<LuaParser>("local x = 1", "foo.lua", |metric| {
2572 assert_eq!(metric.nargs.function_args_sum(), 0);
2574 assert_eq!(metric.nargs.closure_args_sum(), 0);
2575 insta::assert_json_snapshot!(metric.nargs);
2576 });
2577 }
2578
2579 #[test]
2580 fn lua_single_function() {
2581 check_metrics::<LuaParser>("function f(a, b) return a + b end", "foo.lua", |metric| {
2582 assert_eq!(metric.nargs.function_args_sum(), 2);
2584 assert_eq!(metric.nargs.closure_args_sum(), 0);
2585 insta::assert_json_snapshot!(metric.nargs);
2586 });
2587 }
2588
2589 #[test]
2590 fn lua_single_closure() {
2591 check_metrics::<LuaParser>(
2592 "local f = function(a, b) return a + b end",
2593 "foo.lua",
2594 |metric| {
2595 assert_eq!(metric.nargs.function_args_sum(), 0);
2597 assert_eq!(metric.nargs.closure_args_sum(), 2);
2598 insta::assert_json_snapshot!(metric.nargs);
2599 },
2600 );
2601 }
2602
2603 #[test]
2604 fn lua_functions() {
2605 check_metrics::<LuaParser>(
2606 "function f(a) return a end
2607function g(x, y, z) return x + y + z end",
2608 "foo.lua",
2609 |metric| {
2610 assert_eq!(metric.nargs.function_args_sum(), 4);
2612 assert_eq!(metric.nargs.closure_args_sum(), 0);
2613 insta::assert_json_snapshot!(metric.nargs);
2614 },
2615 );
2616 }
2617
2618 #[test]
2619 fn lua_vararg_function() {
2620 check_metrics::<LuaParser>("function f(a, ...) return a end", "foo.lua", |metric| {
2622 assert_eq!(metric.nargs.function_args_sum(), 2);
2624 assert_eq!(metric.nargs.closure_args_sum(), 0);
2625 insta::assert_json_snapshot!(metric.nargs);
2626 });
2627 }
2628
2629 #[test]
2630 fn lua_colon_method_nargs() {
2631 check_metrics::<LuaParser>(
2634 "function obj:method(a, b) return a + b end",
2635 "foo.lua",
2636 |metric| {
2637 assert_eq!(metric.nargs.function_args_sum(), 2);
2639 assert_eq!(metric.nargs.closure_args_sum(), 0);
2640 insta::assert_json_snapshot!(metric.nargs);
2641 },
2642 );
2643 }
2644
2645 #[test]
2646 fn tcl_no_functions() {
2647 check_metrics::<TclParser>("set x 1", "foo.tcl", |metric| {
2648 assert_eq!(metric.nargs.function_args_sum(), 0);
2650 assert_eq!(metric.nargs.closure_args_sum(), 0);
2651 insta::assert_json_snapshot!(metric.nargs);
2652 });
2653 }
2654
2655 #[test]
2656 fn tcl_single_function() {
2657 check_metrics::<TclParser>("proc f {a b} { puts $a }", "foo.tcl", |metric| {
2658 assert_eq!(metric.nargs.function_args_sum(), 2);
2660 assert_eq!(metric.nargs.closure_args_sum(), 0);
2661 insta::assert_json_snapshot!(metric.nargs);
2662 });
2663 }
2664
2665 #[test]
2666 fn tcl_single_function_no_args() {
2667 check_metrics::<TclParser>("proc f {} { puts hello }", "foo.tcl", |metric| {
2668 assert_eq!(metric.nargs.function_args_sum(), 0);
2670 assert_eq!(metric.nargs.closure_args_sum(), 0);
2671 insta::assert_json_snapshot!(metric.nargs);
2672 });
2673 }
2674
2675 #[test]
2676 fn tcl_functions() {
2677 check_metrics::<TclParser>(
2678 "proc f {a b} { puts $a }
2679proc g {x y z} { puts $x }",
2680 "foo.tcl",
2681 |metric| {
2682 assert_eq!(metric.nargs.function_args_sum(), 5);
2684 assert_eq!(metric.nargs.closure_args_sum(), 0);
2685 insta::assert_json_snapshot!(metric.nargs);
2686 },
2687 );
2688 }
2689
2690 #[test]
2691 fn tcl_nested_functions() {
2692 check_metrics::<TclParser>(
2693 "proc outer {a} {
2694 proc inner {x y} { puts $x }
2695 inner $a $a
2696}",
2697 "foo.tcl",
2698 |metric| {
2699 assert_eq!(metric.nargs.function_args_sum(), 3);
2701 assert_eq!(metric.nargs.closure_args_sum(), 0);
2702 insta::assert_json_snapshot!(metric.nargs);
2703 },
2704 );
2705 }
2706
2707 #[test]
2708 fn tcl_args_vararg() {
2709 check_metrics::<TclParser>("proc f {a b args} { puts $a }", "foo.tcl", |metric| {
2711 assert_eq!(metric.nargs.function_args_sum(), 3);
2713 assert_eq!(metric.nargs.closure_args_sum(), 0);
2714 insta::assert_json_snapshot!(metric.nargs);
2715 });
2716 }
2717
2718 #[test]
2719 fn tcl_default_arg() {
2720 check_metrics::<TclParser>(
2722 "proc greet {{name World} greeting} {
2723 puts \"$greeting, $name!\"
2724}",
2725 "foo.tcl",
2726 |metric| {
2727 assert_eq!(metric.nargs.function_args_sum(), 2);
2729 assert_eq!(metric.nargs.closure_args_sum(), 0);
2730 insta::assert_json_snapshot!(metric.nargs);
2731 },
2732 );
2733 }
2734
2735 #[test]
2736 fn kotlin_zero_args() {
2737 check_metrics::<KotlinParser>("fun f(): Int { return 42 }", "foo.kt", |metric| {
2738 assert_eq!(metric.nargs.function_args_sum(), 0);
2740 assert_eq!(metric.nargs.closure_args_sum(), 0);
2741 insta::assert_json_snapshot!(metric.nargs);
2742 });
2743 }
2744
2745 #[test]
2746 fn kotlin_single_arg() {
2747 check_metrics::<KotlinParser>(
2748 "fun double(x: Int): Int { return x * 2 }",
2749 "foo.kt",
2750 |metric| {
2751 assert_eq!(metric.nargs.function_args_sum(), 1);
2753 assert_eq!(metric.nargs.closure_args_sum(), 0);
2754 insta::assert_json_snapshot!(metric.nargs);
2755 },
2756 );
2757 }
2758
2759 #[test]
2760 fn kotlin_multiple_args() {
2761 check_metrics::<KotlinParser>(
2762 "fun add(a: Int, b: Int, c: Int): Int { return a + b + c }",
2763 "foo.kt",
2764 |metric| {
2765 assert_eq!(metric.nargs.function_args_sum(), 3);
2767 assert_eq!(metric.nargs.closure_args_sum(), 0);
2768 insta::assert_json_snapshot!(metric.nargs);
2769 },
2770 );
2771 }
2772
2773 #[test]
2774 fn kotlin_default_args() {
2775 check_metrics::<KotlinParser>(
2776 "fun greet(name: String = \"World\", greeting: String = \"Hello\"): String {
2777 return \"$greeting, $name!\"
2778 }",
2779 "foo.kt",
2780 |metric| {
2781 assert_eq!(metric.nargs.function_args_sum(), 2);
2783 assert_eq!(metric.nargs.closure_args_sum(), 0);
2784 insta::assert_json_snapshot!(metric.nargs);
2785 },
2786 );
2787 }
2788
2789 #[test]
2790 fn kotlin_empty_lambda() {
2791 check_metrics::<KotlinParser>(
2799 "fun f() {
2800 val two = { x: Int, y: Int -> x + y }
2801 val zero = { -> 42 }
2802 }",
2803 "foo.kt",
2804 |metric| {
2805 assert_eq!(metric.nargs.function_args_sum(), 0);
2809 assert_eq!(metric.nargs.closure_args_sum(), 2);
2810 insta::assert_json_snapshot!(metric.nargs);
2811 },
2812 );
2813 }
2814
2815 #[test]
2816 fn kotlin_anonymous_function() {
2817 check_metrics::<KotlinParser>(
2821 "val add = fun(x: Int, y: Int): Int = x + y",
2822 "foo.kt",
2823 |metric| {
2824 assert_eq!(metric.nargs.function_args_sum(), 0);
2826 assert_eq!(metric.nargs.closure_args_sum(), 2);
2827 insta::assert_json_snapshot!(metric.nargs);
2828 },
2829 );
2830 }
2831
2832 #[test]
2833 fn php_no_functions_and_closures() {
2834 check_metrics::<PhpParser>("<?php $a = 42;", "foo.php", |metric| {
2835 insta::assert_json_snapshot!(
2836 metric.nargs,
2837 @r#"
2838 {
2839 "function_args": 0,
2840 "closure_args": 0,
2841 "function_args_average": 0.0,
2842 "closure_args_average": 0.0,
2843 "total": 0,
2844 "average": 0.0,
2845 "function_args_min": 0,
2846 "function_args_max": 0,
2847 "closure_args_min": 0,
2848 "closure_args_max": 0
2849 }
2850 "#
2851 );
2852 });
2853 }
2854
2855 #[test]
2856 fn php_single_function() {
2857 check_metrics::<PhpParser>(
2859 "<?php
2860 function f(bool $a, int $b): bool {
2861 if ($a) { return $a; }
2862 return false;
2863 }",
2864 "foo.php",
2865 |metric| {
2866 insta::assert_json_snapshot!(
2867 metric.nargs,
2868 @r#"
2869 {
2870 "function_args": 2,
2871 "closure_args": 0,
2872 "function_args_average": 2.0,
2873 "closure_args_average": 0.0,
2874 "total": 2,
2875 "average": 2.0,
2876 "function_args_min": 0,
2877 "function_args_max": 2,
2878 "closure_args_min": 0,
2879 "closure_args_max": 0
2880 }
2881 "#
2882 );
2883 },
2884 );
2885 }
2886
2887 #[test]
2888 fn php_single_closure() {
2889 check_metrics::<PhpParser>(
2892 "<?php
2893 $f = function (int $a, int $b) { return $a + $b; };
2894 $g = fn (int $x) => $x * 2;",
2895 "foo.php",
2896 |metric| {
2897 insta::assert_json_snapshot!(
2898 metric.nargs,
2899 @r#"
2900 {
2901 "function_args": 0,
2902 "closure_args": 3,
2903 "function_args_average": 0.0,
2904 "closure_args_average": 1.5,
2905 "total": 3,
2906 "average": 1.5,
2907 "function_args_min": 0,
2908 "function_args_max": 0,
2909 "closure_args_min": 0,
2910 "closure_args_max": 2
2911 }
2912 "#
2913 );
2914 },
2915 );
2916 }
2917
2918 #[test]
2919 fn php_functions() {
2920 check_metrics::<PhpParser>(
2922 "<?php
2923 function a(int $x): int { return $x; }
2924 function b(int $x, int $y): int { return $x + $y; }",
2925 "foo.php",
2926 |metric| {
2927 insta::assert_json_snapshot!(
2928 metric.nargs,
2929 @r#"
2930 {
2931 "function_args": 3,
2932 "closure_args": 0,
2933 "function_args_average": 1.5,
2934 "closure_args_average": 0.0,
2935 "total": 3,
2936 "average": 1.5,
2937 "function_args_min": 0,
2938 "function_args_max": 2,
2939 "closure_args_min": 0,
2940 "closure_args_max": 0
2941 }
2942 "#
2943 );
2944 },
2945 );
2946 }
2947
2948 #[test]
2949 fn php_nested_functions() {
2950 check_metrics::<PhpParser>(
2954 "<?php
2955 class A {
2956 public function outer(int $a): int {
2957 $f = function (int $b) use ($a) { return $a + $b; };
2958 return $f($a);
2959 }
2960 }",
2961 "foo.php",
2962 |metric| {
2963 insta::assert_json_snapshot!(
2964 metric.nargs,
2965 @r#"
2966 {
2967 "function_args": 1,
2968 "closure_args": 1,
2969 "function_args_average": 1.0,
2970 "closure_args_average": 1.0,
2971 "total": 2,
2972 "average": 1.0,
2973 "function_args_min": 0,
2974 "function_args_max": 1,
2975 "closure_args_min": 0,
2976 "closure_args_max": 1
2977 }
2978 "#
2979 );
2980 },
2981 );
2982 }
2983
2984 #[test]
2985 fn elixir_default_nargs_is_zero() {
2986 check_metrics::<ElixirParser>(
2995 "defmodule Foo do\n def add(a, b), do: a + b\n def use_anon do\n add2 = fn x, y -> x + y end\n add2.(1, 2)\n end\nend\n",
2996 "foo.ex",
2997 |metric| {
2998 assert_eq!(metric.nargs.function_args_sum(), 0);
2999 assert_eq!(metric.nargs.closure_args_sum(), 0);
3000 },
3001 );
3002 }
3003
3004 #[test]
3005 fn ruby_no_functions_and_closures() {
3006 check_metrics::<RubyParser>("a = 42\n", "foo.rb", |metric| {
3007 assert_eq!(metric.nargs.function_args_sum(), 0);
3008 assert_eq!(metric.nargs.closure_args_sum(), 0);
3009 });
3010 }
3011
3012 #[test]
3013 fn ruby_single_function() {
3014 check_metrics::<RubyParser>("def foo(a, b, c)\n a + b + c\nend\n", "foo.rb", |metric| {
3016 assert_eq!(metric.nargs.function_args_sum(), 3);
3017 assert_eq!(metric.nargs.closure_args_sum(), 0);
3018 });
3019 }
3020
3021 #[test]
3022 fn ruby_single_closure() {
3023 check_metrics::<RubyParser>("[1, 2, 3].each { |x| puts x }\n", "foo.rb", |metric| {
3026 assert_eq!(metric.nargs.function_args_sum(), 0);
3027 assert_eq!(metric.nargs.closure_args_sum(), 1);
3028 });
3029 }
3030
3031 #[test]
3032 fn ruby_functions() {
3033 check_metrics::<RubyParser>(
3035 "def add(a, b)\n a + b\nend\n\ndef neg(x)\n -x\nend\n\nf = ->(a, b) { a * b }\n",
3036 "foo.rb",
3037 |metric| {
3038 assert_eq!(metric.nargs.function_args_sum(), 3);
3039 assert_eq!(metric.nargs.closure_args_sum(), 2);
3040 },
3041 );
3042 }
3043
3044 #[test]
3045 fn ruby_nested_functions() {
3046 check_metrics::<RubyParser>(
3048 "def outer(a)\n def inner(b, c)\n b + c\n end\n inner(a, a)\nend\n",
3049 "foo.rb",
3050 |metric| {
3051 assert_eq!(metric.nargs.function_args_sum(), 3);
3052 assert_eq!(metric.nargs.closure_args_sum(), 0);
3053 },
3054 );
3055 }
3056
3057 #[test]
3062 fn python_both_parameter_separators() {
3063 check_metrics::<PythonParser>(
3065 "def f(pos_only, /, normal, *, kw_only): pass",
3066 "foo.py",
3067 |metric| {
3068 assert_eq!(metric.nargs.function_args_sum(), 3);
3069 assert_eq!(metric.nargs.closure_args_sum(), 0);
3070 },
3071 );
3072 }
3073
3074 #[test]
3076 fn python_positional_separator_only() {
3077 check_metrics::<PythonParser>("def f(a, b, /): pass", "foo.py", |metric| {
3079 assert_eq!(metric.nargs.function_args_sum(), 2);
3080 assert_eq!(metric.nargs.closure_args_sum(), 0);
3081 });
3082 }
3083
3084 #[test]
3087 fn python_keyword_separator_only() {
3088 check_metrics::<PythonParser>("def f(*, a, b): pass", "foo.py", |metric| {
3090 assert_eq!(metric.nargs.function_args_sum(), 2);
3091 assert_eq!(metric.nargs.closure_args_sum(), 0);
3092 });
3093 }
3094
3095 #[test]
3098 fn python_lambda_keyword_separator() {
3099 check_metrics::<PythonParser>("g = lambda a, *, b: a", "foo.py", |metric| {
3101 assert_eq!(metric.nargs.function_args_sum(), 0);
3102 assert_eq!(metric.nargs.closure_args_sum(), 2);
3103 });
3104 }
3105
3106 #[test]
3110 fn python_args_kwargs_still_counted() {
3111 check_metrics::<PythonParser>("def f(a, *args, **kwargs): pass", "foo.py", |metric| {
3113 assert_eq!(metric.nargs.function_args_sum(), 3);
3114 assert_eq!(metric.nargs.closure_args_sum(), 0);
3115 });
3116 }
3117
3118 #[test]
3121 fn irules_no_functions_and_closures() {
3122 check_metrics::<IrulesParser>("set x 1\nlog local0. $x\n", "foo.irule", |metric| {
3123 assert_eq!(metric.nargs.function_args_sum(), 0);
3124 assert_eq!(metric.nargs.closure_args_sum(), 0);
3125 });
3126 }
3127
3128 #[test]
3132 fn irules_handler_zero_args() {
3133 check_metrics::<IrulesParser>(
3134 "when HTTP_REQUEST { log local0. \"hit\" }\n",
3135 "foo.irule",
3136 |metric| {
3137 assert_eq!(metric.nargs.function_args_sum(), 0);
3138 assert_eq!(metric.nargs.closure_args_sum(), 0);
3139 assert_eq!(metric.nom.functions_sum(), 1);
3141 },
3142 );
3143 }
3144
3145 #[test]
3147 fn irules_single_proc() {
3148 check_metrics::<IrulesParser>("proc f { a b } { return $a }\n", "foo.irule", |metric| {
3149 assert_eq!(metric.nargs.function_args_sum(), 2);
3150 assert_eq!(metric.nargs.closure_args_sum(), 0);
3151 });
3152 }
3153
3154 #[test]
3156 fn irules_proc_no_args() {
3157 check_metrics::<IrulesParser>("proc f { } { return 1 }\n", "foo.irule", |metric| {
3158 assert_eq!(metric.nargs.function_args_sum(), 0);
3159 });
3160 }
3161
3162 #[test]
3166 fn irules_proc_arg_defaults() {
3167 check_metrics::<IrulesParser>(
3168 "proc f { a {b 5} c } { return $a }\n",
3169 "foo.irule",
3170 |metric| {
3171 assert_eq!(metric.nargs.function_args_sum(), 3);
3172 },
3173 );
3174 }
3175
3176 #[test]
3179 fn irules_multiple_functions() {
3180 check_metrics::<IrulesParser>(
3181 "proc add { a b } { return [expr { $a + $b }] }
3182when HTTP_REQUEST { log local0. \"hit\" }
3183",
3184 "foo.irule",
3185 |metric| {
3186 assert_eq!(metric.nargs.function_args_sum(), 2);
3187 assert_eq!(metric.nom.functions_sum(), 2);
3188 },
3189 );
3190 }
3191
3192 #[test]
3194 fn objc_no_args() {
3195 check_metrics::<ObjcParser>(
3196 "@implementation Foo
3197- (void)foo {
3198 [self doWork];
3199}
3200@end
3201",
3202 "foo.m",
3203 |metric| {
3204 assert_eq!(metric.nargs.total(), 0);
3205 insta::assert_json_snapshot!(metric.nargs, @r#"
3206 {
3207 "function_args": 0,
3208 "closure_args": 0,
3209 "function_args_average": 0.0,
3210 "closure_args_average": 0.0,
3211 "total": 0,
3212 "average": 0.0,
3213 "function_args_min": 0,
3214 "function_args_max": 0,
3215 "closure_args_min": 0,
3216 "closure_args_max": 0
3217 }
3218 "#);
3219 },
3220 );
3221 }
3222
3223 #[test]
3226 fn objc_method_two_args() {
3227 check_metrics::<ObjcParser>(
3228 "@implementation Foo
3229- (void)foo:(int)a bar:(int)b {
3230 [self use:a];
3231}
3232@end
3233",
3234 "foo.m",
3235 |metric| {
3236 assert_eq!(metric.nargs.function_args_sum(), 2);
3237 insta::assert_json_snapshot!(metric.nargs, @r#"
3238 {
3239 "function_args": 2,
3240 "closure_args": 0,
3241 "function_args_average": 2.0,
3242 "closure_args_average": 0.0,
3243 "total": 2,
3244 "average": 2.0,
3245 "function_args_min": 0,
3246 "function_args_max": 2,
3247 "closure_args_min": 0,
3248 "closure_args_max": 0
3249 }
3250 "#);
3251 },
3252 );
3253 }
3254
3255 #[test]
3258 fn objc_function_args() {
3259 check_metrics::<ObjcParser>(
3260 "void f(int a, int b, int c) {
3261 return;
3262}
3263",
3264 "foo.m",
3265 |metric| {
3266 assert_eq!(metric.nargs.function_args_sum(), 3);
3267 insta::assert_json_snapshot!(metric.nargs, @r#"
3268 {
3269 "function_args": 3,
3270 "closure_args": 0,
3271 "function_args_average": 3.0,
3272 "closure_args_average": 0.0,
3273 "total": 3,
3274 "average": 3.0,
3275 "function_args_min": 0,
3276 "function_args_max": 3,
3277 "closure_args_min": 0,
3278 "closure_args_max": 0
3279 }
3280 "#);
3281 },
3282 );
3283 }
3284
3285 #[test]
3289 fn objc_block_args() {
3290 check_metrics::<ObjcParser>(
3291 "@implementation Foo
3292- (void)bar {
3293 void (^blk)(int, int) = ^(int x, int y){
3294 [self use:x];
3295 };
3296 blk(1, 2);
3297}
3298@end
3299",
3300 "foo.m",
3301 |metric| {
3302 assert_eq!(metric.nargs.closure_args_sum(), 2);
3303 insta::assert_json_snapshot!(metric.nargs, @r#"
3304 {
3305 "function_args": 0,
3306 "closure_args": 2,
3307 "function_args_average": 0.0,
3308 "closure_args_average": 2.0,
3309 "total": 2,
3310 "average": 1.0,
3311 "function_args_min": 0,
3312 "function_args_max": 0,
3313 "closure_args_min": 0,
3314 "closure_args_max": 2
3315 }
3316 "#);
3317 },
3318 );
3319 }
3320
3321 #[test]
3331 fn display_headline_matches_sum_for_nested_functions() {
3332 check_metrics::<PythonParser>(
3333 "def f(a, b):
3334 def foo(a):
3335 if a:
3336 return 1
3337 bar = lambda a: lambda b: b or True or True
3338 return bar(foo(a))(a)",
3339 "foo.py",
3340 |metric| {
3341 let stats = &metric.nargs;
3342 assert_eq!(stats.function_args_sum(), 3);
3344 assert_eq!(stats.closure_args_sum(), 2);
3345
3346 let rendered = stats.to_string();
3348 assert!(
3349 rendered.starts_with(&format!(
3350 "function_args: {}, closure_args: {},",
3351 stats.function_args_sum(),
3352 stats.closure_args_sum()
3353 )),
3354 "Display headline diverged from the summed accessors: {rendered}"
3355 );
3356 },
3357 );
3358 }
3359}