Skip to main content

codelore_rca/metrics/
nargs.rs

1use serde::Serialize;
2use serde::ser::{SerializeStruct, Serializer};
3use std::fmt;
4
5use crate::checker::Checker;
6use crate::macros::implement_metric_trait;
7use crate::*;
8
9/// The `NArgs` metric.
10///
11/// This metric counts the number of arguments
12/// of functions/closures.
13#[derive(Debug, Clone)]
14pub struct Stats {
15    fn_nargs: usize,
16    closure_nargs: usize,
17    fn_nargs_sum: usize,
18    closure_nargs_sum: usize,
19    fn_nargs_min: usize,
20    closure_nargs_min: usize,
21    fn_nargs_max: usize,
22    closure_nargs_max: usize,
23    total_functions: usize,
24    total_closures: usize,
25}
26
27impl Default for Stats {
28    fn default() -> Self {
29        Self {
30            fn_nargs: 0,
31            closure_nargs: 0,
32            fn_nargs_sum: 0,
33            closure_nargs_sum: 0,
34            fn_nargs_min: usize::MAX,
35            closure_nargs_min: usize::MAX,
36            fn_nargs_max: 0,
37            closure_nargs_max: 0,
38            total_functions: 0,
39            total_closures: 0,
40        }
41    }
42}
43
44impl Serialize for Stats {
45    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
46    where
47        S: Serializer,
48    {
49        let mut st = serializer.serialize_struct("nargs", 10)?;
50        st.serialize_field("total_functions", &self.fn_args_sum())?;
51        st.serialize_field("total_closures", &self.closure_args_sum())?;
52        st.serialize_field("average_functions", &self.fn_args_average())?;
53        st.serialize_field("average_closures", &self.closure_args_average())?;
54        st.serialize_field("total", &self.nargs_total())?;
55        st.serialize_field("average", &self.nargs_average())?;
56        st.serialize_field("functions_min", &self.fn_args_min())?;
57        st.serialize_field("functions_max", &self.fn_args_max())?;
58        st.serialize_field("closures_min", &self.closure_args_min())?;
59        st.serialize_field("closures_max", &self.closure_args_max())?;
60        st.end()
61    }
62}
63
64impl fmt::Display for Stats {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        write!(
67            f,
68            "total_functions: {}, total_closures: {}, average_functions: {}, average_closures: {}, total: {}, average: {}, functions_min: {}, functions_max: {}, closures_min: {}, closures_max: {}",
69            self.fn_args(),
70            self.closure_args(),
71            self.fn_args_average(),
72            self.closure_args_average(),
73            self.nargs_total(),
74            self.nargs_average(),
75            self.fn_args_min(),
76            self.fn_args_max(),
77            self.closure_args_min(),
78            self.closure_args_max()
79        )
80    }
81}
82
83impl Stats {
84    /// Merges a second `NArgs` metric into the first one
85    pub fn merge(&mut self, other: &Stats) {
86        self.closure_nargs_min = self.closure_nargs_min.min(other.closure_nargs_min);
87        self.closure_nargs_max = self.closure_nargs_max.max(other.closure_nargs_max);
88        self.fn_nargs_min = self.fn_nargs_min.min(other.fn_nargs_min);
89        self.fn_nargs_max = self.fn_nargs_max.max(other.fn_nargs_max);
90        self.fn_nargs_sum += other.fn_nargs_sum;
91        self.closure_nargs_sum += other.closure_nargs_sum;
92    }
93
94    /// Returns the number of function arguments in a space.
95    #[inline(always)]
96    pub fn fn_args(&self) -> f64 {
97        self.fn_nargs as f64
98    }
99
100    /// Returns the number of closure arguments in a space.
101    #[inline(always)]
102    pub fn closure_args(&self) -> f64 {
103        self.closure_nargs as f64
104    }
105
106    /// Returns the number of function arguments sum in a space.
107    #[inline(always)]
108    pub fn fn_args_sum(&self) -> f64 {
109        self.fn_nargs_sum as f64
110    }
111
112    /// Returns the number of closure arguments sum in a space.
113    #[inline(always)]
114    pub fn closure_args_sum(&self) -> f64 {
115        self.closure_nargs_sum as f64
116    }
117
118    /// Returns the average number of functions arguments in a space.
119    #[inline(always)]
120    pub fn fn_args_average(&self) -> f64 {
121        self.fn_nargs_sum as f64 / self.total_functions.max(1) as f64
122    }
123
124    /// Returns the average number of closures arguments in a space.
125    #[inline(always)]
126    pub fn closure_args_average(&self) -> f64 {
127        self.closure_nargs_sum as f64 / self.total_closures.max(1) as f64
128    }
129
130    /// Returns the total number of arguments of each function and
131    /// closure in a space.
132    #[inline(always)]
133    pub fn nargs_total(&self) -> f64 {
134        self.fn_args_sum() + self.closure_args_sum()
135    }
136
137    /// Returns the `NArgs` metric average value
138    ///
139    /// This value is computed dividing the `NArgs` value
140    /// for the total number of functions/closures in a space.
141    #[inline(always)]
142    pub fn nargs_average(&self) -> f64 {
143        self.nargs_total() / (self.total_functions + self.total_closures).max(1) as f64
144    }
145    /// Returns the minimum number of function arguments in a space.
146    #[inline(always)]
147    pub fn fn_args_min(&self) -> f64 {
148        self.fn_nargs_min as f64
149    }
150    /// Returns the maximum number of function arguments in a space.
151    #[inline(always)]
152    pub fn fn_args_max(&self) -> f64 {
153        self.fn_nargs_max as f64
154    }
155    /// Returns the minimum number of closure arguments in a space.
156    #[inline(always)]
157    pub fn closure_args_min(&self) -> f64 {
158        self.closure_nargs_min as f64
159    }
160    /// Returns the maximum number of closure arguments in a space.
161    #[inline(always)]
162    pub fn closure_args_max(&self) -> f64 {
163        self.closure_nargs_max as f64
164    }
165    #[inline(always)]
166    pub(crate) fn compute_sum(&mut self) {
167        self.closure_nargs_sum += self.closure_nargs;
168        self.fn_nargs_sum += self.fn_nargs;
169    }
170    #[inline(always)]
171    pub(crate) fn compute_minmax(&mut self) {
172        self.closure_nargs_min = self.closure_nargs_min.min(self.closure_nargs);
173        self.closure_nargs_max = self.closure_nargs_max.max(self.closure_nargs);
174        self.fn_nargs_min = self.fn_nargs_min.min(self.fn_nargs);
175        self.fn_nargs_max = self.fn_nargs_max.max(self.fn_nargs);
176        self.compute_sum();
177    }
178    pub(crate) fn finalize(&mut self, total_functions: usize, total_closures: usize) {
179        self.total_functions = total_functions;
180        self.total_closures = total_closures;
181    }
182}
183
184#[inline(always)]
185fn compute_args<T: Checker>(node: &Node, nargs: &mut usize) {
186    if let Some(params) = node.child_by_field_name("parameters") {
187        let node_params = params;
188        node_params.act_on_child(&mut |n| {
189            if !T::is_non_arg(n) {
190                *nargs += 1;
191            }
192        });
193    }
194}
195
196pub trait NArgs
197where
198    Self: Checker,
199    Self: std::marker::Sized,
200{
201    fn compute(node: &Node, stats: &mut Stats) {
202        if Self::is_func(node) {
203            compute_args::<Self>(node, &mut stats.fn_nargs);
204            return;
205        }
206
207        if Self::is_closure(node) {
208            compute_args::<Self>(node, &mut stats.closure_nargs);
209        }
210    }
211}
212
213impl NArgs for CppCode {
214    fn compute(node: &Node, stats: &mut Stats) {
215        if Self::is_func(node) {
216            if let Some(declarator) = node.child_by_field_name("declarator") {
217                let new_node = declarator;
218                compute_args::<Self>(&new_node, &mut stats.fn_nargs);
219            }
220            return;
221        }
222
223        if Self::is_closure(node)
224            && let Some(declarator) = node.child_by_field_name("declarator")
225        {
226            let new_node = declarator;
227            compute_args::<Self>(&new_node, &mut stats.closure_nargs);
228        }
229    }
230}
231
232implement_metric_trait!(
233    [NArgs],
234    PythonCode,
235    JavascriptCode,
236    TypescriptCode,
237    TsxCode,
238    RustCode,
239    PreprocCode,
240    CcommentCode,
241    JavaCode,
242    KotlinCode
243);
244
245#[cfg(test)]
246mod tests {
247    use crate::tools::check_metrics;
248
249    use super::*;
250
251    #[test]
252    fn python_no_functions_and_closures() {
253        check_metrics::<PythonParser>("a = 42", "foo.py", |metric| {
254            // 0 functions + 0 closures
255            insta::assert_json_snapshot!(
256                metric.nargs,
257                @r###"
258                    {
259                      "total_functions": 0.0,
260                      "total_closures": 0.0,
261                      "average_functions": 0.0,
262                      "average_closures": 0.0,
263                      "total": 0.0,
264                      "average": 0.0,
265                      "functions_min": 0.0,
266                      "functions_max": 0.0,
267                      "closures_min": 0.0,
268                      "closures_max": 0.0
269                    }"###
270            );
271        });
272    }
273
274    #[test]
275    fn rust_no_functions_and_closures() {
276        check_metrics::<RustParser>("let a = 42;", "foo.rs", |metric| {
277            // 0 functions + 0 closures
278            insta::assert_json_snapshot!(
279                metric.nargs,
280                @r###"
281                    {
282                      "total_functions": 0.0,
283                      "total_closures": 0.0,
284                      "average_functions": 0.0,
285                      "average_closures": 0.0,
286                      "total": 0.0,
287                      "average": 0.0,
288                      "functions_min": 0.0,
289                      "functions_max": 0.0,
290                      "closures_min": 0.0,
291                      "closures_max": 0.0
292                    }"###
293            );
294        });
295    }
296
297    #[test]
298    fn cpp_no_functions_and_closures() {
299        check_metrics::<CppParser>("int a = 42;", "foo.cpp", |metric| {
300            // 0 functions + 0 closures
301            insta::assert_json_snapshot!(
302                metric.nargs,
303                @r###"
304                    {
305                      "total_functions": 0.0,
306                      "total_closures": 0.0,
307                      "average_functions": 0.0,
308                      "average_closures": 0.0,
309                      "total": 0.0,
310                      "average": 0.0,
311                      "functions_min": 0.0,
312                      "functions_max": 0.0,
313                      "closures_min": 0.0,
314                      "closures_max": 0.0
315                    }"###
316            );
317        });
318    }
319
320    #[test]
321    fn javascript_no_functions_and_closures() {
322        check_metrics::<JavascriptParser>("var a = 42;", "foo.js", |metric| {
323            // 0 functions + 0 closures
324            insta::assert_json_snapshot!(
325                metric.nargs,
326                @r###"
327                    {
328                      "total_functions": 0.0,
329                      "total_closures": 0.0,
330                      "average_functions": 0.0,
331                      "average_closures": 0.0,
332                      "total": 0.0,
333                      "average": 0.0,
334                      "functions_min": 0.0,
335                      "functions_max": 0.0,
336                      "closures_min": 0.0,
337                      "closures_max": 0.0
338                    }"###
339            );
340        });
341    }
342
343    #[test]
344    fn python_single_function() {
345        check_metrics::<PythonParser>(
346            "def f(a, b):
347                 if a:
348                     return a",
349            "foo.py",
350            |metric| {
351                // 1 function
352                insta::assert_json_snapshot!(
353                    metric.nargs,
354                    @r###"
355                    {
356                      "total_functions": 2.0,
357                      "total_closures": 0.0,
358                      "average_functions": 2.0,
359                      "average_closures": 0.0,
360                      "total": 2.0,
361                      "average": 2.0,
362                      "functions_min": 0.0,
363                      "functions_max": 2.0,
364                      "closures_min": 0.0,
365                      "closures_max": 0.0
366                    }"###
367                );
368            },
369        );
370    }
371
372    #[test]
373    fn rust_single_function() {
374        check_metrics::<RustParser>(
375            "fn f(a: bool, b: usize) {
376                 if a {
377                     return a;
378                }
379             }",
380            "foo.rs",
381            |metric| {
382                // 1 function
383                insta::assert_json_snapshot!(
384                    metric.nargs,
385                    @r###"
386                    {
387                      "total_functions": 2.0,
388                      "total_closures": 0.0,
389                      "average_functions": 2.0,
390                      "average_closures": 0.0,
391                      "total": 2.0,
392                      "average": 2.0,
393                      "functions_min": 0.0,
394                      "functions_max": 2.0,
395                      "closures_min": 0.0,
396                      "closures_max": 0.0
397                    }"###
398                );
399            },
400        );
401    }
402
403    #[test]
404    fn c_single_function() {
405        check_metrics::<CppParser>(
406            "int f(int a, int b) {
407                 if (a) {
408                     return a;
409                }
410             }",
411            "foo.c",
412            |metric| {
413                // 1 function
414                insta::assert_json_snapshot!(
415                    metric.nargs,
416                    @r###"
417                    {
418                      "total_functions": 2.0,
419                      "total_closures": 0.0,
420                      "average_functions": 2.0,
421                      "average_closures": 0.0,
422                      "total": 2.0,
423                      "average": 2.0,
424                      "functions_min": 0.0,
425                      "functions_max": 2.0,
426                      "closures_min": 0.0,
427                      "closures_max": 0.0
428                    }"###
429                );
430            },
431        );
432    }
433
434    #[test]
435    fn javascript_single_function() {
436        check_metrics::<JavascriptParser>(
437            "function f(a, b) {
438                 return a * b;
439             }",
440            "foo.js",
441            |metric| {
442                // 1 function
443                insta::assert_json_snapshot!(
444                    metric.nargs,
445                    @r###"
446                    {
447                      "total_functions": 2.0,
448                      "total_closures": 0.0,
449                      "average_functions": 2.0,
450                      "average_closures": 0.0,
451                      "total": 2.0,
452                      "average": 2.0,
453                      "functions_min": 0.0,
454                      "functions_max": 2.0,
455                      "closures_min": 0.0,
456                      "closures_max": 0.0
457                    }"###
458                );
459            },
460        );
461    }
462
463    #[test]
464    fn python_single_lambda() {
465        check_metrics::<PythonParser>("bar = lambda a: True", "foo.py", |metric| {
466            // 1 lambda
467            insta::assert_json_snapshot!(
468                metric.nargs,
469                @r###"
470                    {
471                      "total_functions": 0.0,
472                      "total_closures": 1.0,
473                      "average_functions": 0.0,
474                      "average_closures": 1.0,
475                      "total": 1.0,
476                      "average": 1.0,
477                      "functions_min": 0.0,
478                      "functions_max": 0.0,
479                      "closures_min": 1.0,
480                      "closures_max": 1.0
481                    }"###
482            );
483        });
484    }
485
486    #[test]
487    fn rust_single_closure() {
488        check_metrics::<RustParser>("let bar = |i: i32| -> i32 { i + 1 };", "foo.rs", |metric| {
489            // 1 lambda
490            insta::assert_json_snapshot!(
491                metric.nargs,
492                @r###"
493                    {
494                      "total_functions": 0.0,
495                      "total_closures": 1.0,
496                      "average_functions": 0.0,
497                      "average_closures": 1.0,
498                      "total": 1.0,
499                      "average": 1.0,
500                      "functions_min": 0.0,
501                      "functions_max": 0.0,
502                      "closures_min": 0.0,
503                      "closures_max": 1.0
504                    }"###
505            );
506        });
507    }
508
509    #[test]
510    fn cpp_single_lambda() {
511        check_metrics::<CppParser>(
512            "auto bar = [](int x, int y) -> int { return x + y; };",
513            "foo.cpp",
514            |metric| {
515                // 1 lambda
516                insta::assert_json_snapshot!(
517                    metric.nargs,
518                    @r###"
519                    {
520                      "total_functions": 0.0,
521                      "total_closures": 2.0,
522                      "average_functions": 0.0,
523                      "average_closures": 2.0,
524                      "total": 2.0,
525                      "average": 2.0,
526                      "functions_min": 0.0,
527                      "functions_max": 0.0,
528                      "closures_min": 2.0,
529                      "closures_max": 2.0
530                    }"###
531                );
532            },
533        );
534    }
535
536    #[test]
537    fn javascript_single_closure() {
538        check_metrics::<JavascriptParser>("function (a, b) {return a + b};", "foo.js", |metric| {
539            // 1 lambda
540            insta::assert_json_snapshot!(
541                metric.nargs,
542                @r###"
543                    {
544                      "total_functions": 0.0,
545                      "total_closures": 2.0,
546                      "average_functions": 0.0,
547                      "average_closures": 2.0,
548                      "total": 2.0,
549                      "average": 2.0,
550                      "functions_min": 0.0,
551                      "functions_max": 0.0,
552                      "closures_min": 0.0,
553                      "closures_max": 2.0
554                    }"###
555            );
556        });
557    }
558
559    #[test]
560    fn python_functions() {
561        check_metrics::<PythonParser>(
562            "def f(a, b):
563                 if a:
564                     return a
565            def f(a, b):
566                 if b:
567                     return b",
568            "foo.py",
569            |metric| {
570                // 2 functions
571                insta::assert_json_snapshot!(
572                    metric.nargs,
573                    @r###"
574                    {
575                      "total_functions": 4.0,
576                      "total_closures": 0.0,
577                      "average_functions": 2.0,
578                      "average_closures": 0.0,
579                      "total": 4.0,
580                      "average": 2.0,
581                      "functions_min": 0.0,
582                      "functions_max": 2.0,
583                      "closures_min": 0.0,
584                      "closures_max": 0.0
585                    }"###
586                );
587            },
588        );
589
590        check_metrics::<PythonParser>(
591            "def f(a, b):
592                 if a:
593                     return a
594            def f(a, b, c):
595                 if b:
596                     return b",
597            "foo.py",
598            |metric| {
599                // 2 functions
600                insta::assert_json_snapshot!(
601                    metric.nargs,
602                    @r###"
603                    {
604                      "total_functions": 5.0,
605                      "total_closures": 0.0,
606                      "average_functions": 2.5,
607                      "average_closures": 0.0,
608                      "total": 5.0,
609                      "average": 2.5,
610                      "functions_min": 0.0,
611                      "functions_max": 3.0,
612                      "closures_min": 0.0,
613                      "closures_max": 0.0
614                    }"###
615                );
616            },
617        );
618    }
619
620    #[test]
621    fn rust_functions() {
622        check_metrics::<RustParser>(
623            "fn f(a: bool, b: usize) {
624                 if a {
625                     return a;
626                }
627             }
628             fn f1(a: bool, b: usize) {
629                 if a {
630                     return a;
631                }
632             }",
633            "foo.rs",
634            |metric| {
635                // 2 functions
636                insta::assert_json_snapshot!(
637                    metric.nargs,
638                    @r###"
639                    {
640                      "total_functions": 4.0,
641                      "total_closures": 0.0,
642                      "average_functions": 2.0,
643                      "average_closures": 0.0,
644                      "total": 4.0,
645                      "average": 2.0,
646                      "functions_min": 0.0,
647                      "functions_max": 2.0,
648                      "closures_min": 0.0,
649                      "closures_max": 0.0
650                    }"###
651                );
652            },
653        );
654
655        check_metrics::<RustParser>(
656            "fn f(a: bool, b: usize) {
657                 if a {
658                     return a;
659                }
660             }
661             fn f1(a: bool, b: usize, c: usize) {
662                 if a {
663                     return a;
664                }
665             }",
666            "foo.rs",
667            |metric| {
668                // 2 functions
669                insta::assert_json_snapshot!(
670                    metric.nargs,
671                    @r###"
672                    {
673                      "total_functions": 5.0,
674                      "total_closures": 0.0,
675                      "average_functions": 2.5,
676                      "average_closures": 0.0,
677                      "total": 5.0,
678                      "average": 2.5,
679                      "functions_min": 0.0,
680                      "functions_max": 3.0,
681                      "closures_min": 0.0,
682                      "closures_max": 0.0
683                    }"###
684                );
685            },
686        );
687    }
688
689    #[test]
690    fn c_functions() {
691        check_metrics::<CppParser>(
692            "int f(int a, int b) {
693                 if (a) {
694                     return a;
695                }
696             }
697             int f1(int a, int b) {
698                 if (a) {
699                     return a;
700                }
701             }",
702            "foo.c",
703            |metric| {
704                // 2 functions
705                insta::assert_json_snapshot!(
706                    metric.nargs,
707                    @r###"
708                    {
709                      "total_functions": 4.0,
710                      "total_closures": 0.0,
711                      "average_functions": 2.0,
712                      "average_closures": 0.0,
713                      "total": 4.0,
714                      "average": 2.0,
715                      "functions_min": 0.0,
716                      "functions_max": 2.0,
717                      "closures_min": 0.0,
718                      "closures_max": 0.0
719                    }"###
720                );
721            },
722        );
723
724        check_metrics::<CppParser>(
725            "int f(int a, int b) {
726                 if (a) {
727                     return a;
728                }
729             }
730             int f1(int a, int b, int c) {
731                 if (a) {
732                     return a;
733                }
734             }",
735            "foo.c",
736            |metric| {
737                // 2 functions
738                insta::assert_json_snapshot!(
739                    metric.nargs,
740                    @r###"
741                    {
742                      "total_functions": 5.0,
743                      "total_closures": 0.0,
744                      "average_functions": 2.5,
745                      "average_closures": 0.0,
746                      "total": 5.0,
747                      "average": 2.5,
748                      "functions_min": 0.0,
749                      "functions_max": 3.0,
750                      "closures_min": 0.0,
751                      "closures_max": 0.0
752                    }"###
753                );
754            },
755        );
756    }
757
758    #[test]
759    fn javascript_functions() {
760        check_metrics::<JavascriptParser>(
761            "function f(a, b) {
762                 return a * b;
763             }
764             function f1(a, b) {
765                 return a * b;
766             }",
767            "foo.js",
768            |metric| {
769                // 2 functions
770                insta::assert_json_snapshot!(
771                    metric.nargs,
772                    @r###"
773                    {
774                      "total_functions": 4.0,
775                      "total_closures": 0.0,
776                      "average_functions": 2.0,
777                      "average_closures": 0.0,
778                      "total": 4.0,
779                      "average": 2.0,
780                      "functions_min": 0.0,
781                      "functions_max": 2.0,
782                      "closures_min": 0.0,
783                      "closures_max": 0.0
784                    }"###
785                );
786            },
787        );
788
789        check_metrics::<JavascriptParser>(
790            "function f(a, b) {
791                 return a * b;
792             }
793             function f1(a, b, c) {
794                 return a * b;
795             }",
796            "foo.js",
797            |metric| {
798                // 2 functions
799                insta::assert_json_snapshot!(
800                    metric.nargs,
801                    @r###"
802                    {
803                      "total_functions": 5.0,
804                      "total_closures": 0.0,
805                      "average_functions": 2.5,
806                      "average_closures": 0.0,
807                      "total": 5.0,
808                      "average": 2.5,
809                      "functions_min": 0.0,
810                      "functions_max": 3.0,
811                      "closures_min": 0.0,
812                      "closures_max": 0.0
813                    }"###
814                );
815            },
816        );
817    }
818
819    #[test]
820    fn python_nested_functions() {
821        check_metrics::<PythonParser>(
822            "def f(a, b):
823                 def foo(a):
824                     if a:
825                         return 1
826                 bar = lambda a: lambda b: b or True or True
827                 return bar(foo(a))(a)",
828            "foo.py",
829            |metric| {
830                // 2 functions + 2 lambdas = 4
831                insta::assert_json_snapshot!(
832                    metric.nargs,
833                    @r###"
834                    {
835                      "total_functions": 3.0,
836                      "total_closures": 2.0,
837                      "average_functions": 1.5,
838                      "average_closures": 1.0,
839                      "total": 5.0,
840                      "average": 1.25,
841                      "functions_min": 0.0,
842                      "functions_max": 2.0,
843                      "closures_min": 0.0,
844                      "closures_max": 2.0
845                    }"###
846                );
847            },
848        );
849    }
850
851    #[test]
852    fn rust_nested_functions() {
853        check_metrics::<RustParser>(
854            "fn f(a: i32, b: i32) -> i32 {
855                 fn foo(a: i32) -> i32 {
856                     return a;
857                 }
858                 let bar = |a: i32, b: i32| -> i32 { a + 1 };
859                 let bar1 = |b: i32| -> i32 { b + 1 };
860                 return bar(foo(a), a);
861             }",
862            "foo.rs",
863            |metric| {
864                // 2 functions + 2 lambdas = 4
865                insta::assert_json_snapshot!(
866                    metric.nargs,
867                    @r###"
868                    {
869                      "total_functions": 3.0,
870                      "total_closures": 3.0,
871                      "average_functions": 1.5,
872                      "average_closures": 1.5,
873                      "total": 6.0,
874                      "average": 1.5,
875                      "functions_min": 0.0,
876                      "functions_max": 2.0,
877                      "closures_min": 0.0,
878                      "closures_max": 2.0
879                    }"###
880                );
881            },
882        );
883    }
884
885    #[test]
886    fn cpp_nested_functions() {
887        check_metrics::<CppParser>(
888            "int f(int a, int b, int c) {
889                 auto foo = [](int x) -> int { return x; };
890                 auto bar = [](int x, int y) -> int { return x + y; };
891                 return bar(foo(a), a);
892             }",
893            "foo.cpp",
894            |metric| {
895                // 1 functions + 2 lambdas = 3
896                insta::assert_json_snapshot!(
897                    metric.nargs,
898                    @r###"
899                    {
900                      "total_functions": 3.0,
901                      "total_closures": 3.0,
902                      "average_functions": 3.0,
903                      "average_closures": 1.5,
904                      "total": 6.0,
905                      "average": 2.0,
906                      "functions_min": 0.0,
907                      "functions_max": 3.0,
908                      "closures_min": 0.0,
909                      "closures_max": 3.0
910                    }"###
911                );
912            },
913        );
914    }
915
916    #[test]
917    fn javascript_nested_functions() {
918        check_metrics::<JavascriptParser>(
919            "function f(a, b) {
920                 function foo(a, c) {
921                     return a;
922                 }
923                 var bar = function (a, b) {return a + b};
924                 function (a) {return a};
925                 return bar(foo(a), a);
926             }",
927            "foo.js",
928            |metric| {
929                // 3 functions + 1 lambdas = 4
930                insta::assert_json_snapshot!(
931                    metric.nargs,
932                    @r###"
933                    {
934                      "total_functions": 6.0,
935                      "total_closures": 1.0,
936                      "average_functions": 2.0,
937                      "average_closures": 1.0,
938                      "total": 7.0,
939                      "average": 1.75,
940                      "functions_min": 0.0,
941                      "functions_max": 2.0,
942                      "closures_min": 0.0,
943                      "closures_max": 1.0
944                    }"###
945                );
946            },
947        );
948    }
949}