Skip to main content

rust_code_analysis_code_split/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    MozjsCode,
236    JavascriptCode,
237    TypescriptCode,
238    TsxCode,
239    RustCode,
240    PreprocCode,
241    CcommentCode,
242    JavaCode,
243    KotlinCode
244);
245
246#[cfg(test)]
247mod tests {
248    use crate::tools::check_metrics;
249
250    use super::*;
251
252    #[test]
253    fn python_no_functions_and_closures() {
254        check_metrics::<PythonParser>("a = 42", "foo.py", |metric| {
255            // 0 functions + 0 closures
256            insta::assert_json_snapshot!(
257                metric.nargs,
258                @r###"
259                    {
260                      "total_functions": 0.0,
261                      "total_closures": 0.0,
262                      "average_functions": 0.0,
263                      "average_closures": 0.0,
264                      "total": 0.0,
265                      "average": 0.0,
266                      "functions_min": 0.0,
267                      "functions_max": 0.0,
268                      "closures_min": 0.0,
269                      "closures_max": 0.0
270                    }"###
271            );
272        });
273    }
274
275    #[test]
276    fn rust_no_functions_and_closures() {
277        check_metrics::<RustParser>("let a = 42;", "foo.rs", |metric| {
278            // 0 functions + 0 closures
279            insta::assert_json_snapshot!(
280                metric.nargs,
281                @r###"
282                    {
283                      "total_functions": 0.0,
284                      "total_closures": 0.0,
285                      "average_functions": 0.0,
286                      "average_closures": 0.0,
287                      "total": 0.0,
288                      "average": 0.0,
289                      "functions_min": 0.0,
290                      "functions_max": 0.0,
291                      "closures_min": 0.0,
292                      "closures_max": 0.0
293                    }"###
294            );
295        });
296    }
297
298    #[test]
299    fn cpp_no_functions_and_closures() {
300        check_metrics::<CppParser>("int a = 42;", "foo.cpp", |metric| {
301            // 0 functions + 0 closures
302            insta::assert_json_snapshot!(
303                metric.nargs,
304                @r###"
305                    {
306                      "total_functions": 0.0,
307                      "total_closures": 0.0,
308                      "average_functions": 0.0,
309                      "average_closures": 0.0,
310                      "total": 0.0,
311                      "average": 0.0,
312                      "functions_min": 0.0,
313                      "functions_max": 0.0,
314                      "closures_min": 0.0,
315                      "closures_max": 0.0
316                    }"###
317            );
318        });
319    }
320
321    #[test]
322    fn javascript_no_functions_and_closures() {
323        check_metrics::<JavascriptParser>("var a = 42;", "foo.js", |metric| {
324            // 0 functions + 0 closures
325            insta::assert_json_snapshot!(
326                metric.nargs,
327                @r###"
328                    {
329                      "total_functions": 0.0,
330                      "total_closures": 0.0,
331                      "average_functions": 0.0,
332                      "average_closures": 0.0,
333                      "total": 0.0,
334                      "average": 0.0,
335                      "functions_min": 0.0,
336                      "functions_max": 0.0,
337                      "closures_min": 0.0,
338                      "closures_max": 0.0
339                    }"###
340            );
341        });
342    }
343
344    #[test]
345    fn python_single_function() {
346        check_metrics::<PythonParser>(
347            "def f(a, b):
348                 if a:
349                     return a",
350            "foo.py",
351            |metric| {
352                // 1 function
353                insta::assert_json_snapshot!(
354                    metric.nargs,
355                    @r#"
356                {
357                  "total_functions": 0.0,
358                  "total_closures": 0.0,
359                  "average_functions": 0.0,
360                  "average_closures": 0.0,
361                  "total": 0.0,
362                  "average": 0.0,
363                  "functions_min": 0.0,
364                  "functions_max": 0.0,
365                  "closures_min": 0.0,
366                  "closures_max": 0.0
367                }
368                "#
369                );
370            },
371        );
372    }
373
374    #[test]
375    fn rust_single_function() {
376        check_metrics::<RustParser>(
377            "fn f(a: bool, b: usize) {
378                 if a {
379                     return a;
380                }
381             }",
382            "foo.rs",
383            |metric| {
384                // 1 function
385                insta::assert_json_snapshot!(
386                    metric.nargs,
387                    @r###"
388                    {
389                      "total_functions": 2.0,
390                      "total_closures": 0.0,
391                      "average_functions": 2.0,
392                      "average_closures": 0.0,
393                      "total": 2.0,
394                      "average": 2.0,
395                      "functions_min": 0.0,
396                      "functions_max": 2.0,
397                      "closures_min": 0.0,
398                      "closures_max": 0.0
399                    }"###
400                );
401            },
402        );
403    }
404
405    #[test]
406    fn c_single_function() {
407        check_metrics::<CppParser>(
408            "int f(int a, int b) {
409                 if (a) {
410                     return a;
411                }
412             }",
413            "foo.c",
414            |metric| {
415                // 1 function
416                insta::assert_json_snapshot!(
417                    metric.nargs,
418                    @r###"
419                    {
420                      "total_functions": 2.0,
421                      "total_closures": 0.0,
422                      "average_functions": 2.0,
423                      "average_closures": 0.0,
424                      "total": 2.0,
425                      "average": 2.0,
426                      "functions_min": 0.0,
427                      "functions_max": 2.0,
428                      "closures_min": 0.0,
429                      "closures_max": 0.0
430                    }"###
431                );
432            },
433        );
434    }
435
436    #[test]
437    fn javascript_single_function() {
438        check_metrics::<JavascriptParser>(
439            "function f(a, b) {
440                 return a * b;
441             }",
442            "foo.js",
443            |metric| {
444                // 1 function
445                insta::assert_json_snapshot!(
446                    metric.nargs,
447                    @r#"
448                {
449                  "total_functions": 0.0,
450                  "total_closures": 4.0,
451                  "average_functions": 0.0,
452                  "average_closures": 4.0,
453                  "total": 4.0,
454                  "average": 4.0,
455                  "functions_min": 0.0,
456                  "functions_max": 0.0,
457                  "closures_min": 4.0,
458                  "closures_max": 4.0
459                }
460                "#
461                );
462            },
463        );
464    }
465
466    #[test]
467    fn python_single_lambda() {
468        check_metrics::<PythonParser>("bar = lambda a: True", "foo.py", |metric| {
469            // 1 lambda
470            insta::assert_json_snapshot!(
471                metric.nargs,
472                @r#"
473            {
474              "total_functions": 0.0,
475              "total_closures": 0.0,
476              "average_functions": 0.0,
477              "average_closures": 0.0,
478              "total": 0.0,
479              "average": 0.0,
480              "functions_min": 0.0,
481              "functions_max": 0.0,
482              "closures_min": 0.0,
483              "closures_max": 0.0
484            }
485            "#
486            );
487        });
488    }
489
490    #[test]
491    fn rust_single_closure() {
492        check_metrics::<RustParser>("let bar = |i: i32| -> i32 { i + 1 };", "foo.rs", |metric| {
493            // 1 lambda
494            insta::assert_json_snapshot!(
495                metric.nargs,
496                @r###"
497                    {
498                      "total_functions": 0.0,
499                      "total_closures": 1.0,
500                      "average_functions": 0.0,
501                      "average_closures": 1.0,
502                      "total": 1.0,
503                      "average": 1.0,
504                      "functions_min": 0.0,
505                      "functions_max": 0.0,
506                      "closures_min": 0.0,
507                      "closures_max": 1.0
508                    }"###
509            );
510        });
511    }
512
513    #[test]
514    fn cpp_single_lambda() {
515        check_metrics::<CppParser>(
516            "auto bar = [](int x, int y) -> int { return x + y; };",
517            "foo.cpp",
518            |metric| {
519                // 1 lambda
520                insta::assert_json_snapshot!(
521                    metric.nargs,
522                    @r###"
523                    {
524                      "total_functions": 0.0,
525                      "total_closures": 2.0,
526                      "average_functions": 0.0,
527                      "average_closures": 2.0,
528                      "total": 2.0,
529                      "average": 2.0,
530                      "functions_min": 0.0,
531                      "functions_max": 0.0,
532                      "closures_min": 2.0,
533                      "closures_max": 2.0
534                    }"###
535                );
536            },
537        );
538    }
539
540    #[test]
541    fn javascript_single_closure() {
542        check_metrics::<JavascriptParser>("function (a, b) {return a + b};", "foo.js", |metric| {
543            // 1 lambda
544            insta::assert_json_snapshot!(
545                metric.nargs,
546                @r#"
547            {
548              "total_functions": 0.0,
549              "total_closures": 8.0,
550              "average_functions": 0.0,
551              "average_closures": 4.0,
552              "total": 8.0,
553              "average": 4.0,
554              "functions_min": 0.0,
555              "functions_max": 0.0,
556              "closures_min": 4.0,
557              "closures_max": 4.0
558            }
559            "#
560            );
561        });
562    }
563
564    #[test]
565    fn python_functions() {
566        check_metrics::<PythonParser>(
567            "def f(a, b):
568                 if a:
569                     return a
570            def f(a, b):
571                 if b:
572                     return b",
573            "foo.py",
574            |metric| {
575                // 2 functions
576                insta::assert_json_snapshot!(
577                    metric.nargs,
578                    @r#"
579                {
580                  "total_functions": 0.0,
581                  "total_closures": 0.0,
582                  "average_functions": 0.0,
583                  "average_closures": 0.0,
584                  "total": 0.0,
585                  "average": 0.0,
586                  "functions_min": 0.0,
587                  "functions_max": 0.0,
588                  "closures_min": 0.0,
589                  "closures_max": 0.0
590                }
591                "#
592                );
593            },
594        );
595
596        check_metrics::<PythonParser>(
597            "def f(a, b):
598                 if a:
599                     return a
600            def f(a, b, c):
601                 if b:
602                     return b",
603            "foo.py",
604            |metric| {
605                // 2 functions
606                insta::assert_json_snapshot!(
607                    metric.nargs,
608                    @r#"
609                {
610                  "total_functions": 0.0,
611                  "total_closures": 0.0,
612                  "average_functions": 0.0,
613                  "average_closures": 0.0,
614                  "total": 0.0,
615                  "average": 0.0,
616                  "functions_min": 0.0,
617                  "functions_max": 0.0,
618                  "closures_min": 0.0,
619                  "closures_max": 0.0
620                }
621                "#
622                );
623            },
624        );
625    }
626
627    #[test]
628    fn rust_functions() {
629        check_metrics::<RustParser>(
630            "fn f(a: bool, b: usize) {
631                 if a {
632                     return a;
633                }
634             }
635             fn f1(a: bool, b: usize) {
636                 if a {
637                     return a;
638                }
639             }",
640            "foo.rs",
641            |metric| {
642                // 2 functions
643                insta::assert_json_snapshot!(
644                    metric.nargs,
645                    @r###"
646                    {
647                      "total_functions": 4.0,
648                      "total_closures": 0.0,
649                      "average_functions": 2.0,
650                      "average_closures": 0.0,
651                      "total": 4.0,
652                      "average": 2.0,
653                      "functions_min": 0.0,
654                      "functions_max": 2.0,
655                      "closures_min": 0.0,
656                      "closures_max": 0.0
657                    }"###
658                );
659            },
660        );
661
662        check_metrics::<RustParser>(
663            "fn f(a: bool, b: usize) {
664                 if a {
665                     return a;
666                }
667             }
668             fn f1(a: bool, b: usize, c: usize) {
669                 if a {
670                     return a;
671                }
672             }",
673            "foo.rs",
674            |metric| {
675                // 2 functions
676                insta::assert_json_snapshot!(
677                    metric.nargs,
678                    @r###"
679                    {
680                      "total_functions": 5.0,
681                      "total_closures": 0.0,
682                      "average_functions": 2.5,
683                      "average_closures": 0.0,
684                      "total": 5.0,
685                      "average": 2.5,
686                      "functions_min": 0.0,
687                      "functions_max": 3.0,
688                      "closures_min": 0.0,
689                      "closures_max": 0.0
690                    }"###
691                );
692            },
693        );
694    }
695
696    #[test]
697    fn c_functions() {
698        check_metrics::<CppParser>(
699            "int f(int a, int b) {
700                 if (a) {
701                     return a;
702                }
703             }
704             int f1(int a, int b) {
705                 if (a) {
706                     return a;
707                }
708             }",
709            "foo.c",
710            |metric| {
711                // 2 functions
712                insta::assert_json_snapshot!(
713                    metric.nargs,
714                    @r###"
715                    {
716                      "total_functions": 4.0,
717                      "total_closures": 0.0,
718                      "average_functions": 2.0,
719                      "average_closures": 0.0,
720                      "total": 4.0,
721                      "average": 2.0,
722                      "functions_min": 0.0,
723                      "functions_max": 2.0,
724                      "closures_min": 0.0,
725                      "closures_max": 0.0
726                    }"###
727                );
728            },
729        );
730
731        check_metrics::<CppParser>(
732            "int f(int a, int b) {
733                 if (a) {
734                     return a;
735                }
736             }
737             int f1(int a, int b, int c) {
738                 if (a) {
739                     return a;
740                }
741             }",
742            "foo.c",
743            |metric| {
744                // 2 functions
745                insta::assert_json_snapshot!(
746                    metric.nargs,
747                    @r###"
748                    {
749                      "total_functions": 5.0,
750                      "total_closures": 0.0,
751                      "average_functions": 2.5,
752                      "average_closures": 0.0,
753                      "total": 5.0,
754                      "average": 2.5,
755                      "functions_min": 0.0,
756                      "functions_max": 3.0,
757                      "closures_min": 0.0,
758                      "closures_max": 0.0
759                    }"###
760                );
761            },
762        );
763    }
764
765    #[test]
766    fn javascript_functions() {
767        check_metrics::<JavascriptParser>(
768            "function f(a, b) {
769                 return a * b;
770             }
771             function f1(a, b) {
772                 return a * b;
773             }",
774            "foo.js",
775            |metric| {
776                // 2 functions
777                insta::assert_json_snapshot!(
778                    metric.nargs,
779                    @r#"
780                {
781                  "total_functions": 0.0,
782                  "total_closures": 12.0,
783                  "average_functions": 0.0,
784                  "average_closures": 4.0,
785                  "total": 12.0,
786                  "average": 4.0,
787                  "functions_min": 0.0,
788                  "functions_max": 0.0,
789                  "closures_min": 4.0,
790                  "closures_max": 4.0
791                }
792                "#
793                );
794            },
795        );
796
797        check_metrics::<JavascriptParser>(
798            "function f(a, b) {
799                 return a * b;
800             }
801             function f1(a, b, c) {
802                 return a * b;
803             }",
804            "foo.js",
805            |metric| {
806                // 2 functions
807                insta::assert_json_snapshot!(
808                    metric.nargs,
809                    @r#"
810                {
811                  "total_functions": 0.0,
812                  "total_closures": 13.0,
813                  "average_functions": 0.0,
814                  "average_closures": 4.333333333333333,
815                  "total": 13.0,
816                  "average": 4.333333333333333,
817                  "functions_min": 0.0,
818                  "functions_max": 0.0,
819                  "closures_min": 4.0,
820                  "closures_max": 5.0
821                }
822                "#
823                );
824            },
825        );
826    }
827
828    #[test]
829    fn python_nested_functions() {
830        check_metrics::<PythonParser>(
831            "def f(a, b):
832                 def foo(a):
833                     if a:
834                         return 1
835                 bar = lambda a: lambda b: b or True or True
836                 return bar(foo(a))(a)",
837            "foo.py",
838            |metric| {
839                // 2 functions + 2 lambdas = 4
840                insta::assert_json_snapshot!(
841                    metric.nargs,
842                    @r#"
843                {
844                  "total_functions": 0.0,
845                  "total_closures": 0.0,
846                  "average_functions": 0.0,
847                  "average_closures": 0.0,
848                  "total": 0.0,
849                  "average": 0.0,
850                  "functions_min": 0.0,
851                  "functions_max": 0.0,
852                  "closures_min": 0.0,
853                  "closures_max": 0.0
854                }
855                "#
856                );
857            },
858        );
859    }
860
861    #[test]
862    fn rust_nested_functions() {
863        check_metrics::<RustParser>(
864            "fn f(a: i32, b: i32) -> i32 {
865                 fn foo(a: i32) -> i32 {
866                     return a;
867                 }
868                 let bar = |a: i32, b: i32| -> i32 { a + 1 };
869                 let bar1 = |b: i32| -> i32 { b + 1 };
870                 return bar(foo(a), a);
871             }",
872            "foo.rs",
873            |metric| {
874                // 2 functions + 2 lambdas = 4
875                insta::assert_json_snapshot!(
876                    metric.nargs,
877                    @r###"
878                    {
879                      "total_functions": 3.0,
880                      "total_closures": 3.0,
881                      "average_functions": 1.5,
882                      "average_closures": 1.5,
883                      "total": 6.0,
884                      "average": 1.5,
885                      "functions_min": 0.0,
886                      "functions_max": 2.0,
887                      "closures_min": 0.0,
888                      "closures_max": 2.0
889                    }"###
890                );
891            },
892        );
893    }
894
895    #[test]
896    fn cpp_nested_functions() {
897        check_metrics::<CppParser>(
898            "int f(int a, int b, int c) {
899                 auto foo = [](int x) -> int { return x; };
900                 auto bar = [](int x, int y) -> int { return x + y; };
901                 return bar(foo(a), a);
902             }",
903            "foo.cpp",
904            |metric| {
905                // 1 functions + 2 lambdas = 3
906                insta::assert_json_snapshot!(
907                    metric.nargs,
908                    @r###"
909                    {
910                      "total_functions": 3.0,
911                      "total_closures": 3.0,
912                      "average_functions": 3.0,
913                      "average_closures": 1.5,
914                      "total": 6.0,
915                      "average": 2.0,
916                      "functions_min": 0.0,
917                      "functions_max": 3.0,
918                      "closures_min": 0.0,
919                      "closures_max": 3.0
920                    }"###
921                );
922            },
923        );
924    }
925
926    #[test]
927    fn javascript_nested_functions() {
928        check_metrics::<JavascriptParser>(
929            "function f(a, b) {
930                 function foo(a, c) {
931                     return a;
932                 }
933                 var bar = function (a, b) {return a + b};
934                 function (a) {return a};
935                 return bar(foo(a), a);
936             }",
937            "foo.js",
938            |metric| {
939                // 3 functions + 1 lambdas = 4
940                insta::assert_json_snapshot!(
941                    metric.nargs,
942                    @r#"
943                {
944                  "total_functions": 0.0,
945                  "total_closures": 15.0,
946                  "average_functions": 0.0,
947                  "average_closures": 3.75,
948                  "total": 15.0,
949                  "average": 3.75,
950                  "functions_min": 0.0,
951                  "functions_max": 0.0,
952                  "closures_min": 3.0,
953                  "closures_max": 4.0
954                }
955                "#
956                );
957            },
958        );
959    }
960}