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;
24
25use crate::*;
26
27#[derive(Clone, Debug, PartialEq)]
29#[non_exhaustive]
30pub struct Stats {
31 functions: usize,
32 closures: usize,
33 functions_sum: usize,
34 closures_sum: usize,
35 functions_min: usize,
36 functions_max: usize,
37 closures_min: usize,
38 closures_max: usize,
39 space_count: usize,
40}
41
42impl Default for Stats {
43 fn default() -> Self {
44 Self {
45 functions: 0,
46 closures: 0,
47 functions_sum: 0,
48 closures_sum: 0,
49 functions_min: usize::MAX,
50 functions_max: 0,
51 closures_min: usize::MAX,
52 closures_max: 0,
53 space_count: 1,
54 }
55 }
56}
57
58impl fmt::Display for Stats {
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 write!(
61 f,
62 "functions: {}, \
63 closures: {}, \
64 functions_average: {}, \
65 closures_average: {}, \
66 total: {}, \
67 average: {}, \
68 functions_min: {}, \
69 functions_max: {}, \
70 closures_min: {}, \
71 closures_max: {}",
72 self.functions_sum(),
73 self.closures_sum(),
74 self.functions_average(),
75 self.closures_average(),
76 self.total(),
77 self.average(),
78 self.functions_min(),
79 self.functions_max(),
80 self.closures_min(),
81 self.closures_max(),
82 )
83 }
84}
85
86impl Stats {
87 pub fn merge(&mut self, other: &Stats) {
89 self.functions_min = self.functions_min.min(other.functions_min);
90 self.functions_max = self.functions_max.max(other.functions_max);
91 self.closures_min = self.closures_min.min(other.closures_min);
92 self.closures_max = self.closures_max.max(other.closures_max);
93 self.functions_sum += other.functions_sum;
94 self.closures_sum += other.closures_sum;
95 self.space_count += other.space_count;
96 }
97
98 #[inline]
100 #[must_use]
101 pub fn functions(&self) -> u64 {
102 self.functions as u64
104 }
105
106 #[inline]
108 #[must_use]
109 pub fn closures(&self) -> u64 {
110 self.closures as u64
111 }
112
113 #[inline]
115 #[must_use]
116 pub fn functions_sum(&self) -> u64 {
117 self.functions_sum as u64
119 }
120
121 #[inline]
123 #[must_use]
124 pub fn closures_sum(&self) -> u64 {
125 self.closures_sum as u64
126 }
127
128 #[inline]
136 #[must_use]
137 pub fn functions_average(&self) -> f64 {
138 crate::metrics::average(self.functions_sum() as f64, self.space_count)
139 }
140
141 #[inline]
143 #[must_use]
144 pub fn closures_average(&self) -> f64 {
145 crate::metrics::average(self.closures_sum() as f64, self.space_count)
146 }
147
148 #[inline]
150 #[must_use]
151 pub fn average(&self) -> f64 {
152 crate::metrics::average(self.total() as f64, self.space_count)
153 }
154
155 #[inline]
161 #[must_use]
162 pub fn functions_min(&self) -> u64 {
163 if self.functions_min == usize::MAX {
165 0
166 } else {
167 self.functions_min as u64
168 }
169 }
170
171 #[inline]
175 #[must_use]
176 pub fn closures_min(&self) -> u64 {
177 if self.closures_min == usize::MAX {
178 0
179 } else {
180 self.closures_min as u64
181 }
182 }
183 #[inline]
185 #[must_use]
186 pub fn functions_max(&self) -> u64 {
187 self.functions_max as u64
189 }
190
191 #[inline]
193 #[must_use]
194 pub fn closures_max(&self) -> u64 {
195 self.closures_max as u64
196 }
197 #[inline]
200 #[must_use]
201 pub fn total(&self) -> u64 {
202 self.functions_sum() + self.closures_sum()
203 }
204 #[inline]
205 pub(crate) fn compute_sum(&mut self) {
206 self.functions_sum += self.functions;
207 self.closures_sum += self.closures;
208 }
209 #[inline]
210 pub(crate) fn compute_minmax(&mut self) {
211 self.functions_min = self.functions_min.min(self.functions);
212 self.functions_max = self.functions_max.max(self.functions);
213 self.closures_min = self.closures_min.min(self.closures);
214 self.closures_max = self.closures_max.max(self.closures);
215 self.compute_sum();
216 }
217}
218
219#[doc(hidden)]
220pub(crate) trait Nom
222where
223 Self: Checker,
224{
225 fn compute(node: &Node, code: &[u8], stats: &mut Stats) {
237 if Self::is_func_with_code(node, code) {
238 stats.functions += 1;
239 return;
240 }
241 if Self::is_closure(node) {
242 stats.closures += 1;
243 }
244 }
245}
246
247implement_metric_trait!(
248 [Nom],
249 PythonCode,
250 MozjsCode,
251 JavascriptCode,
252 TypescriptCode,
253 TsxCode,
254 CppCode,
255 MozcppCode,
256 CCode,
257 ObjcCode,
258 RustCode,
259 PreprocCode,
260 CcommentCode,
261 JavaCode,
262 KotlinCode,
263 GoCode,
264 PerlCode,
265 BashCode,
266 LuaCode,
267 TclCode,
268 PhpCode,
269 CsharpCode,
270 ElixirCode,
271 RubyCode,
272 GroovyCode,
273 IrulesCode
274);
275
276#[cfg(test)]
277#[allow(
278 clippy::float_cmp,
279 clippy::cast_precision_loss,
280 clippy::cast_possible_truncation,
281 clippy::cast_sign_loss,
282 clippy::similar_names,
283 clippy::doc_markdown,
284 clippy::needless_raw_string_hashes,
285 clippy::too_many_lines
286)]
287mod tests {
288 use crate::tools::check_metrics;
289
290 use super::*;
291
292 #[test]
297 fn nom_empty_file_min_is_zero() {
298 let stats = Stats::default();
299 assert_eq!(stats.functions_min(), 0);
300 assert_eq!(stats.closures_min(), 0);
301 }
302
303 #[test]
304 fn python_nom() {
305 check_metrics::<PythonParser>(
306 "def a():
307 pass
308 def b():
309 pass
310 def c():
311 pass
312 x = lambda a : a + 42",
313 "foo.py",
314 |metric| {
315 assert_eq!(metric.nom.closures_sum(), 1);
321 insta::assert_json_snapshot!(
322 metric.nom,
323 @r#"
324 {
325 "functions": 3,
326 "closures": 1,
327 "functions_average": 0.75,
328 "closures_average": 0.25,
329 "total": 4,
330 "average": 1.0,
331 "functions_min": 0,
332 "functions_max": 1,
333 "closures_min": 0,
334 "closures_max": 1
335 }
336 "#
337 );
338 },
339 );
340 }
341
342 #[test]
343 fn rust_nom() {
344 check_metrics::<RustParser>(
345 "mod A { fn foo() {}}
346 mod B { fn foo() {}}
347 let closure = |i: i32| -> i32 { i + 42 };",
348 "foo.rs",
349 |metric| {
350 insta::assert_json_snapshot!(
352 metric.nom,
353 @r#"
354 {
355 "functions": 2,
356 "closures": 1,
357 "functions_average": 0.5,
358 "closures_average": 0.25,
359 "total": 3,
360 "average": 0.75,
361 "functions_min": 0,
362 "functions_max": 1,
363 "closures_min": 0,
364 "closures_max": 1
365 }
366 "#
367 );
368 },
369 );
370 }
371
372 #[test]
373 fn c_nom() {
374 check_metrics::<CParser>(
375 "int foo();
376
377 int foo() {
378 return 0;
379 }",
380 "foo.c",
381 |metric| {
382 insta::assert_json_snapshot!(
384 metric.nom,
385 @r#"
386 {
387 "functions": 1,
388 "closures": 0,
389 "functions_average": 0.5,
390 "closures_average": 0.0,
391 "total": 1,
392 "average": 0.5,
393 "functions_min": 0,
394 "functions_max": 1,
395 "closures_min": 0,
396 "closures_max": 0
397 }
398 "#
399 );
400 },
401 );
402 }
403
404 #[test]
405 fn cpp_nom() {
406 check_metrics::<CppParser>(
407 "struct A {
408 void foo(int) {}
409 void foo(double) {}
410 };
411 int b = [](int x) -> int { return x + 42; };",
412 "foo.cpp",
413 |metric| {
414 insta::assert_json_snapshot!(
416 metric.nom,
417 @r#"
418 {
419 "functions": 2,
420 "closures": 1,
421 "functions_average": 0.5,
422 "closures_average": 0.25,
423 "total": 3,
424 "average": 0.75,
425 "functions_min": 0,
426 "functions_max": 1,
427 "closures_min": 0,
428 "closures_max": 1
429 }
430 "#
431 );
432 },
433 );
434 }
435
436 #[test]
441 fn cpp_free_and_member_functions() {
442 check_metrics::<CppParser>(
443 "int free_fn(int x) { return x; }
444 struct S {
445 int member_fn(int x) { return x + 1; }
446 };",
447 "foo.cpp",
448 |metric| {
449 let s = &metric.nom;
451 assert_eq!(s.functions_sum(), 2);
452 assert_eq!(s.closures_sum(), 0);
453 assert_eq!(s.total(), 2);
454 insta::assert_json_snapshot!(metric.nom);
455 },
456 );
457 }
458
459 #[test]
463 fn cpp_static_member_function() {
464 check_metrics::<CppParser>(
465 "struct S {
466 static int factory(int x) { return x; }
467 int method(int x) { return x + 1; }
468 };",
469 "foo.cpp",
470 |metric| {
471 let s = &metric.nom;
472 assert_eq!(s.functions_sum(), 2);
473 assert_eq!(s.closures_sum(), 0);
474 insta::assert_json_snapshot!(metric.nom);
475 },
476 );
477 }
478
479 #[test]
484 fn cpp_constructor_and_destructor() {
485 check_metrics::<CppParser>(
486 "struct S {
487 S() {}
488 ~S() {}
489 int method() { return 0; }
490 };",
491 "foo.cpp",
492 |metric| {
493 let s = &metric.nom;
494 assert_eq!(s.functions_sum(), 3);
496 assert_eq!(s.closures_sum(), 0);
497 insta::assert_json_snapshot!(metric.nom);
498 },
499 );
500 }
501
502 #[test]
506 fn cpp_operator_overloads() {
507 check_metrics::<CppParser>(
508 "struct V {
509 int x;
510 V operator+(const V& o) const { return V{x + o.x}; }
511 bool operator==(const V& o) const { return x == o.x; }
512 };",
513 "foo.cpp",
514 |metric| {
515 let s = &metric.nom;
516 assert_eq!(s.functions_sum(), 2);
517 assert_eq!(s.closures_sum(), 0);
518 insta::assert_json_snapshot!(metric.nom);
519 },
520 );
521 }
522
523 #[test]
527 fn cpp_function_template() {
528 check_metrics::<CppParser>(
529 "template<typename T>
530 T identity(T x) { return x; }",
531 "foo.cpp",
532 |metric| {
533 let s = &metric.nom;
534 assert_eq!(s.functions_sum(), 1);
535 assert_eq!(s.closures_sum(), 0);
536 insta::assert_json_snapshot!(metric.nom);
537 },
538 );
539 }
540
541 #[test]
545 fn cpp_class_template_members() {
546 check_metrics::<CppParser>(
547 "template<typename T>
548 struct Box {
549 T value;
550 T get() const { return value; }
551 void set(T v) { value = v; }
552 };",
553 "foo.cpp",
554 |metric| {
555 let s = &metric.nom;
556 assert_eq!(s.functions_sum(), 2);
557 assert_eq!(s.closures_sum(), 0);
558 insta::assert_json_snapshot!(metric.nom);
559 },
560 );
561 }
562
563 #[test]
568 fn cpp_lambdas_inside_function() {
569 check_metrics::<CppParser>(
570 "int run() {
571 auto add = [](int a, int b) { return a + b; };
572 auto mul = [](int a, int b) { return a * b; };
573 return add(1, 2) + mul(3, 4);
574 }",
575 "foo.cpp",
576 |metric| {
577 let s = &metric.nom;
578 assert_eq!(s.functions_sum(), 1);
580 assert_eq!(s.closures_sum(), 2);
581 assert_eq!(s.total(), 3);
582 insta::assert_json_snapshot!(metric.nom);
583 },
584 );
585 }
586
587 #[test]
588 fn javascript_nom() {
589 check_metrics::<JavascriptParser>(
590 "function f(a, b) {
591 function foo(a) {
592 return a;
593 }
594 var bar = (function () {
595 var counter = 0;
596 return function () {
597 counter += 1;
598 return counter
599 }
600 })();
601 return bar(foo(a), a);
602 }",
603 "foo.js",
604 |metric| {
605 insta::assert_json_snapshot!(
609 metric.nom,
610 @r#"
611 {
612 "functions": 3,
613 "closures": 1,
614 "functions_average": 0.6,
615 "closures_average": 0.2,
616 "total": 4,
617 "average": 0.8,
618 "functions_min": 0,
619 "functions_max": 1,
620 "closures_min": 0,
621 "closures_max": 1
622 }
623 "#
624 );
625 },
626 );
627 }
628
629 #[test]
630 fn javascript_call_nom() {
631 check_metrics::<JavascriptParser>(
632 "add_task(async function test_safe_mode() {
633 gAppInfo.inSafeMode = true;
634 });",
635 "foo.js",
636 |metric| {
637 insta::assert_json_snapshot!(
640 metric.nom,
641 @r#"
642 {
643 "functions": 1,
644 "closures": 0,
645 "functions_average": 0.5,
646 "closures_average": 0.0,
647 "total": 1,
648 "average": 0.5,
649 "functions_min": 0,
650 "functions_max": 1,
651 "closures_min": 0,
652 "closures_max": 0
653 }
654 "#
655 );
656 },
657 );
658 }
659
660 #[test]
661 fn javascript_assignment_nom() {
662 check_metrics::<JavascriptParser>(
663 "AnimationTest.prototype.enableDisplay = function(element) {};",
664 "foo.js",
665 |metric| {
666 insta::assert_json_snapshot!(
668 metric.nom,
669 @r#"
670 {
671 "functions": 1,
672 "closures": 0,
673 "functions_average": 0.5,
674 "closures_average": 0.0,
675 "total": 1,
676 "average": 0.5,
677 "functions_min": 0,
678 "functions_max": 1,
679 "closures_min": 0,
680 "closures_max": 0
681 }
682 "#
683 );
684 },
685 );
686 }
687
688 #[test]
689 fn javascript_labeled_nom() {
690 check_metrics::<JavascriptParser>(
691 "toJSON: function() {
692 return this.inspect(true);
693 }",
694 "foo.js",
695 |metric| {
696 insta::assert_json_snapshot!(
698 metric.nom,
699 @r#"
700 {
701 "functions": 1,
702 "closures": 0,
703 "functions_average": 0.5,
704 "closures_average": 0.0,
705 "total": 1,
706 "average": 0.5,
707 "functions_min": 0,
708 "functions_max": 1,
709 "closures_min": 0,
710 "closures_max": 0
711 }
712 "#
713 );
714 },
715 );
716 }
717
718 #[test]
719 fn javascript_labeled_arrow_nom() {
720 check_metrics::<JavascriptParser>(
721 "const dimConverters = {
722 pt: x => x,
723 };",
724 "foo.js",
725 |metric| {
726 insta::assert_json_snapshot!(
728 metric.nom,
729 @r#"
730 {
731 "functions": 1,
732 "closures": 0,
733 "functions_average": 0.5,
734 "closures_average": 0.0,
735 "total": 1,
736 "average": 0.5,
737 "functions_min": 0,
738 "functions_max": 1,
739 "closures_min": 0,
740 "closures_max": 0
741 }
742 "#
743 );
744 },
745 );
746 }
747
748 #[test]
749 fn javascript_pair_nom() {
750 check_metrics::<JavascriptParser>(
751 "return {
752 initialize: function(object) {
753 this._object = object.toObject();
754 },
755 }",
756 "foo.js",
757 |metric| {
758 insta::assert_json_snapshot!(
760 metric.nom,
761 @r#"
762 {
763 "functions": 1,
764 "closures": 0,
765 "functions_average": 0.5,
766 "closures_average": 0.0,
767 "total": 1,
768 "average": 0.5,
769 "functions_min": 0,
770 "functions_max": 1,
771 "closures_min": 0,
772 "closures_max": 0
773 }
774 "#
775 );
776 },
777 );
778 }
779
780 fn check_returned_object_arrow_nom<T: ParserTrait>(file_name: &str) {
781 check_metrics::<T>(
782 "function f() { return { foo: x => x }; }",
783 file_name,
784 |metric| {
785 insta::allow_duplicates! {
786 insta::assert_json_snapshot!(
787 metric.nom,
788 @r#"
789 {
790 "functions": 2,
791 "closures": 0,
792 "functions_average": 0.6666666666666666,
793 "closures_average": 0.0,
794 "total": 2,
795 "average": 0.6666666666666666,
796 "functions_min": 0,
797 "functions_max": 1,
798 "closures_min": 0,
799 "closures_max": 0
800 }
801 "#
802 );
803 }
804 },
805 );
806 }
807
808 #[test]
809 fn javascript_returned_object_arrow_nom() {
810 check_returned_object_arrow_nom::<JavascriptParser>("foo.js");
811 }
812
813 #[test]
814 fn mozjs_returned_object_arrow_nom() {
815 check_returned_object_arrow_nom::<MozjsParser>("foo.js");
816 }
817
818 #[test]
819 fn typescript_returned_object_arrow_nom() {
820 check_returned_object_arrow_nom::<TypescriptParser>("foo.ts");
821 }
822
823 #[test]
824 fn tsx_returned_object_arrow_nom() {
825 check_returned_object_arrow_nom::<TsxParser>("foo.tsx");
826 }
827
828 #[test]
829 fn javascript_unnamed_nom() {
830 check_metrics::<JavascriptParser>(
831 "Ajax.getTransport = Try.these(
832 function() {
833 return function(){ return new XMLHttpRequest()}
834 }
835 );",
836 "foo.js",
837 |metric| {
838 insta::assert_json_snapshot!(
840 metric.nom,
841 @r#"
842 {
843 "functions": 0,
844 "closures": 2,
845 "functions_average": 0.0,
846 "closures_average": 0.6666666666666666,
847 "total": 2,
848 "average": 0.6666666666666666,
849 "functions_min": 0,
850 "functions_max": 0,
851 "closures_min": 0,
852 "closures_max": 1
853 }
854 "#
855 );
856 },
857 );
858 }
859
860 #[test]
861 fn javascript_arrow_nom() {
862 check_metrics::<JavascriptParser>(
863 "var materials = [\"Hydrogen\"];
864 materials.map(material => material.length);
865 let add = (a, b) => a + b;",
866 "foo.js",
867 |metric| {
868 insta::assert_json_snapshot!(
872 metric.nom,
873 @r#"
874 {
875 "functions": 1,
876 "closures": 1,
877 "functions_average": 0.3333333333333333,
878 "closures_average": 0.3333333333333333,
879 "total": 2,
880 "average": 0.6666666666666666,
881 "functions_min": 0,
882 "functions_max": 1,
883 "closures_min": 0,
884 "closures_max": 1
885 }
886 "#
887 );
888 },
889 );
890 }
891
892 #[test]
893 fn javascript_arrow_assignment_nom() {
894 check_metrics::<JavascriptParser>("sink.onPull = () => { };", "foo.js", |metric| {
895 insta::assert_json_snapshot!(
897 metric.nom,
898 @r#"
899 {
900 "functions": 1,
901 "closures": 0,
902 "functions_average": 0.5,
903 "closures_average": 0.0,
904 "total": 1,
905 "average": 0.5,
906 "functions_min": 0,
907 "functions_max": 1,
908 "closures_min": 0,
909 "closures_max": 0
910 }
911 "#
912 );
913 });
914 }
915
916 #[test]
917 fn javascript_arrow_new_nom() {
918 check_metrics::<JavascriptParser>(
919 "const response = new Promise(resolve => channel.port1.onmessage = resolve);",
920 "foo.js",
921 |metric| {
922 insta::assert_json_snapshot!(
924 metric.nom,
925 @r#"
926 {
927 "functions": 0,
928 "closures": 1,
929 "functions_average": 0.0,
930 "closures_average": 0.5,
931 "total": 1,
932 "average": 0.5,
933 "functions_min": 0,
934 "functions_max": 0,
935 "closures_min": 0,
936 "closures_max": 1
937 }
938 "#
939 );
940 },
941 );
942 }
943
944 #[test]
945 fn javascript_arrow_call_nom() {
946 check_metrics::<JavascriptParser>(
947 "let notDisabled = TestUtils.waitForCondition(
948 () => !backbutton.hasAttribute(\"disabled\")
949 );",
950 "foo.js",
951 |metric| {
952 insta::assert_json_snapshot!(
954 metric.nom,
955 @r#"
956 {
957 "functions": 0,
958 "closures": 1,
959 "functions_average": 0.0,
960 "closures_average": 0.5,
961 "total": 1,
962 "average": 0.5,
963 "functions_min": 0,
964 "functions_max": 0,
965 "closures_min": 0,
966 "closures_max": 1
967 }
968 "#
969 );
970 },
971 );
972 }
973
974 #[test]
975 fn java_nom() {
976 check_metrics::<JavaParser>(
977 "class A {
978 public void foo(){
979 return;
980 }
981 public void bar(){
982 return;
983 }
984 }",
985 "foo.java",
986 |metric| {
987 insta::assert_json_snapshot!(
989 metric.nom,
990 @r#"
991 {
992 "functions": 2,
993 "closures": 0,
994 "functions_average": 0.5,
995 "closures_average": 0.0,
996 "total": 2,
997 "average": 0.5,
998 "functions_min": 0,
999 "functions_max": 1,
1000 "closures_min": 0,
1001 "closures_max": 0
1002 }
1003 "#
1004 );
1005 },
1006 );
1007 }
1008
1009 #[test]
1010 fn csharp_nom() {
1011 check_metrics::<CsharpParser>(
1012 "class A {
1013 public void Foo() {
1014 return;
1015 }
1016 public void Bar() {
1017 return;
1018 }
1019 public int X { get; set; }
1020 public void Outer() {
1021 void Local() { return; }
1022 Local();
1023 }
1024 }",
1025 "foo.cs",
1026 |metric| {
1027 insta::assert_json_snapshot!(
1032 metric.nom,
1033 @r#"
1034 {
1035 "functions": 6,
1036 "closures": 0,
1037 "functions_average": 0.75,
1038 "closures_average": 0.0,
1039 "total": 6,
1040 "average": 0.75,
1041 "functions_min": 0,
1042 "functions_max": 1,
1043 "closures_min": 0,
1044 "closures_max": 0
1045 }
1046 "#
1047 );
1048 },
1049 );
1050 }
1051
1052 #[test]
1053 fn csharp_closure_nom() {
1054 check_metrics::<CsharpParser>(
1055 "class A {
1056 public void Run() {
1057 System.Func<int, int> f = x => x + 1;
1058 System.Action g = delegate(int y) { System.Console.WriteLine(y); };
1059 }
1060 }",
1061 "foo.cs",
1062 |metric| {
1063 insta::assert_json_snapshot!(
1065 metric.nom,
1066 @r#"
1067 {
1068 "functions": 1,
1069 "closures": 2,
1070 "functions_average": 0.2,
1071 "closures_average": 0.4,
1072 "total": 3,
1073 "average": 0.6,
1074 "functions_min": 0,
1075 "functions_max": 1,
1076 "closures_min": 0,
1077 "closures_max": 1
1078 }
1079 "#
1080 );
1081 },
1082 );
1083 }
1084
1085 #[test]
1086 fn csharp_indexer_nom() {
1087 check_metrics::<CsharpParser>(
1093 "class A {
1094 private int[] _d;
1095 public int this[int i] { get => _d[i]; set => _d[i] = value; }
1096 }",
1097 "foo.cs",
1098 |metric| {
1099 assert_eq!(metric.nom.functions_sum(), 2);
1102 assert_eq!(metric.npm.class_nm_sum(), 2);
1103 insta::assert_json_snapshot!(
1104 metric.nom,
1105 @r#"
1106 {
1107 "functions": 2,
1108 "closures": 0,
1109 "functions_average": 0.5,
1110 "closures_average": 0.0,
1111 "total": 2,
1112 "average": 0.5,
1113 "functions_min": 0,
1114 "functions_max": 1,
1115 "closures_min": 0,
1116 "closures_max": 0
1117 }
1118 "#
1119 );
1120 },
1121 );
1122 }
1123
1124 #[test]
1125 fn csharp_expression_bodied_indexer_nom() {
1126 check_metrics::<CsharpParser>(
1133 "class A {
1134 private int[] _d;
1135 public int this[int i] => _d[i];
1136 }",
1137 "foo.cs",
1138 |metric| {
1139 assert_eq!(metric.nom.functions_sum(), 1);
1141 assert_eq!(metric.npm.class_nm_sum(), 1);
1142 insta::assert_json_snapshot!(
1143 metric.nom,
1144 @r#"
1145 {
1146 "functions": 1,
1147 "closures": 0,
1148 "functions_average": 0.3333333333333333,
1149 "closures_average": 0.0,
1150 "total": 1,
1151 "average": 0.3333333333333333,
1152 "functions_min": 0,
1153 "functions_max": 1,
1154 "closures_min": 0,
1155 "closures_max": 0
1156 }
1157 "#
1158 );
1159 },
1160 );
1161 }
1162
1163 #[test]
1164 fn csharp_property_nom() {
1165 check_metrics::<CsharpParser>(
1171 "class A {
1172 private int _w;
1173 public int W { get => _w; set => _w = value; }
1174 }",
1175 "foo.cs",
1176 |metric| {
1177 assert_eq!(metric.nom.functions_sum(), 2);
1180 assert_eq!(metric.npm.class_nm_sum(), 2);
1181 },
1182 );
1183 }
1184
1185 #[test]
1186 fn csharp_auto_property_nom() {
1187 check_metrics::<CsharpParser>(
1191 "class A {
1192 public int Y { get; set; }
1193 }",
1194 "foo.cs",
1195 |metric| {
1196 assert_eq!(metric.nom.functions_sum(), 2);
1198 assert_eq!(metric.npm.class_nm_sum(), 2);
1199 },
1200 );
1201 }
1202
1203 #[test]
1204 fn csharp_expression_bodied_property_nom() {
1205 check_metrics::<CsharpParser>(
1213 "class A {
1214 private int _w;
1215 public int W => _w;
1216 }",
1217 "foo.cs",
1218 |metric| {
1219 assert_eq!(metric.nom.functions_sum(), 1);
1221 assert_eq!(metric.npm.class_nm_sum(), 1);
1222 },
1223 );
1224 }
1225
1226 #[test]
1227 fn go_top_level_funcs() {
1228 check_metrics::<GoParser>(
1229 "package main
1230 func a() {}
1231 func b() {}
1232 func c() {}",
1233 "foo.go",
1234 |metric| {
1235 insta::assert_json_snapshot!(
1237 metric.nom,
1238 @r#"
1239 {
1240 "functions": 3,
1241 "closures": 0,
1242 "functions_average": 0.75,
1243 "closures_average": 0.0,
1244 "total": 3,
1245 "average": 0.75,
1246 "functions_min": 0,
1247 "functions_max": 1,
1248 "closures_min": 0,
1249 "closures_max": 0
1250 }
1251 "#
1252 );
1253 },
1254 );
1255 }
1256
1257 #[test]
1258 fn go_method_declaration() {
1259 check_metrics::<GoParser>(
1260 "package main
1261 type T struct{}
1262 func (r *T) M() {}",
1263 "foo.go",
1264 |metric| {
1265 insta::assert_json_snapshot!(
1267 metric.nom,
1268 @r#"
1269 {
1270 "functions": 1,
1271 "closures": 0,
1272 "functions_average": 0.5,
1273 "closures_average": 0.0,
1274 "total": 1,
1275 "average": 0.5,
1276 "functions_min": 0,
1277 "functions_max": 1,
1278 "closures_min": 0,
1279 "closures_max": 0
1280 }
1281 "#
1282 );
1283 },
1284 );
1285 }
1286
1287 #[test]
1288 fn go_func_literal_is_closure() {
1289 check_metrics::<GoParser>(
1290 "package main
1291 var f = func() {}",
1292 "foo.go",
1293 |metric| {
1294 insta::assert_json_snapshot!(
1296 metric.nom,
1297 @r#"
1298 {
1299 "functions": 0,
1300 "closures": 1,
1301 "functions_average": 0.0,
1302 "closures_average": 0.5,
1303 "total": 1,
1304 "average": 0.5,
1305 "functions_min": 0,
1306 "functions_max": 0,
1307 "closures_min": 0,
1308 "closures_max": 1
1309 }
1310 "#
1311 );
1312 },
1313 );
1314 }
1315
1316 #[test]
1317 fn go_nested_closures() {
1318 check_metrics::<GoParser>(
1319 "package main
1320 func f() {
1321 inner := func() {
1322 deeper := func() {}
1323 _ = deeper
1324 }
1325 _ = inner
1326 }",
1327 "foo.go",
1328 |metric| {
1329 insta::assert_json_snapshot!(
1331 metric.nom,
1332 @r#"
1333 {
1334 "functions": 1,
1335 "closures": 2,
1336 "functions_average": 0.25,
1337 "closures_average": 0.5,
1338 "total": 3,
1339 "average": 0.75,
1340 "functions_min": 0,
1341 "functions_max": 1,
1342 "closures_min": 0,
1343 "closures_max": 1
1344 }
1345 "#
1346 );
1347 },
1348 );
1349 }
1350
1351 #[test]
1352 fn java_closure_nom() {
1353 check_metrics::<JavaParser>(
1354 "interface printable{
1355 void print();
1356 }
1357
1358 interface IntFunc {
1359 int func(int n);
1360 }
1361
1362 class Printer implements printable{
1363 public void print(){System.out.println(\"Hello\");}
1364
1365 public static void main(String args[]){
1366 Printer obj = new Printer();
1367 obj.print();
1368 IntFunc meaning = (i) -> i + 42;
1369 int i = meaning.func(1);
1370 }
1371 }",
1372 "foo.java",
1373 |metric| {
1374 insta::assert_json_snapshot!(
1376 metric.nom,
1377 @r#"
1378 {
1379 "functions": 4,
1380 "closures": 1,
1381 "functions_average": 0.5,
1382 "closures_average": 0.125,
1383 "total": 5,
1384 "average": 0.625,
1385 "functions_min": 0,
1386 "functions_max": 1,
1387 "closures_min": 0,
1388 "closures_max": 1
1389 }
1390 "#
1391 );
1392 },
1393 );
1394 }
1395
1396 #[test]
1397 fn groovy_nom() {
1398 check_metrics::<GroovyParser>(
1399 "class Printer {
1400 void print() {
1401 println 'hello'
1402 }
1403 static void main(String[] args) {
1404 def p = new Printer()
1405 p.print()
1406 def doubler = { x -> x * 2 }
1407 int r = doubler(21)
1408 }
1409 }",
1410 "foo.groovy",
1411 |metric| {
1412 assert_eq!(metric.nom.functions_sum(), 2);
1419 assert_eq!(metric.nom.closures_sum(), 1);
1420 },
1421 );
1422 }
1423
1424 #[test]
1425 fn groovy_nom_function_definition() {
1426 check_metrics::<GroovyParser>(
1429 "def greet(name) {
1430 println(name)
1431 }
1432 greet('world')",
1433 "foo.groovy",
1434 |metric| {
1435 assert_eq!(metric.nom.functions_sum(), 1);
1436 },
1437 );
1438 }
1439
1440 #[test]
1441 fn perl_nom() {
1442 check_metrics::<PerlParser>(
1443 "sub a { 1 }
1444 sub b { 2 }
1445 my $c = sub { 3 };
1446 sub outer {
1447 my $inner = sub { 4 };
1448 return $inner;
1449 }",
1450 "foo.pl",
1451 |metric| {
1452 insta::assert_json_snapshot!(
1453 metric.nom,
1454 @r#"
1455 {
1456 "functions": 3,
1457 "closures": 2,
1458 "functions_average": 0.5,
1459 "closures_average": 0.3333333333333333,
1460 "total": 5,
1461 "average": 0.8333333333333334,
1462 "functions_min": 0,
1463 "functions_max": 1,
1464 "closures_min": 0,
1465 "closures_max": 1
1466 }
1467 "#
1468 );
1469 },
1470 );
1471 }
1472
1473 #[test]
1474 fn tsx_named_and_arrow_functions() {
1475 check_metrics::<TsxParser>(
1476 "function greet(name: string): string {
1477 return `Hello, ${name}`;
1478 }
1479 const add = (a: number, b: number) => a + b;
1480 const log = () => { console.log('done'); };",
1481 "foo.tsx",
1482 |metric| {
1483 insta::assert_json_snapshot!(
1484 metric.nom,
1485 @r#"
1486 {
1487 "functions": 3,
1488 "closures": 0,
1489 "functions_average": 0.75,
1490 "closures_average": 0.0,
1491 "total": 3,
1492 "average": 0.75,
1493 "functions_min": 0,
1494 "functions_max": 1,
1495 "closures_min": 0,
1496 "closures_max": 0
1497 }
1498 "#
1499 );
1500 },
1501 );
1502 }
1503
1504 #[test]
1505 fn typescript_named_arrow_and_class_methods() {
1506 check_metrics::<TypescriptParser>(
1507 "function compute(x: number): number {
1508 return x * 2;
1509 }
1510 const double = (n: number): number => n * 2;
1511 class Calculator {
1512 add(a: number, b: number): number {
1513 return a + b;
1514 }
1515 }",
1516 "foo.ts",
1517 |metric| {
1518 insta::assert_json_snapshot!(
1519 metric.nom,
1520 @r#"
1521 {
1522 "functions": 3,
1523 "closures": 0,
1524 "functions_average": 0.6,
1525 "closures_average": 0.0,
1526 "total": 3,
1527 "average": 0.6,
1528 "functions_min": 0,
1529 "functions_max": 1,
1530 "closures_min": 0,
1531 "closures_max": 0
1532 }
1533 "#
1534 );
1535 },
1536 );
1537 }
1538
1539 #[test]
1540 fn mozjs_nom() {
1541 check_metrics::<MozjsParser>(
1542 "function f(a, b) {
1543 function foo(a) {
1544 return a;
1545 }
1546 var bar = (function () {
1547 var counter = 0;
1548 return function () {
1549 counter += 1;
1550 return counter
1551 }
1552 })();
1553 return bar(foo(a), a);
1554 }",
1555 "foo.js",
1556 |metric| {
1557 insta::assert_json_snapshot!(
1558 metric.nom,
1559 @r#"
1560 {
1561 "functions": 3,
1562 "closures": 1,
1563 "functions_average": 0.6,
1564 "closures_average": 0.2,
1565 "total": 4,
1566 "average": 0.8,
1567 "functions_min": 0,
1568 "functions_max": 1,
1569 "closures_min": 0,
1570 "closures_max": 1
1571 }
1572 "#
1573 );
1574 },
1575 );
1576 }
1577
1578 #[test]
1579 fn mozjs_arrow_and_method() {
1580 check_metrics::<MozjsParser>(
1581 "let add = (a, b) => a + b;
1582 class Counter {
1583 increment() {
1584 this.count++;
1585 }
1586 }",
1587 "foo.js",
1588 |metric| {
1589 insta::assert_json_snapshot!(
1590 metric.nom,
1591 @r#"
1592 {
1593 "functions": 2,
1594 "closures": 0,
1595 "functions_average": 0.5,
1596 "closures_average": 0.0,
1597 "total": 2,
1598 "average": 0.5,
1599 "functions_min": 0,
1600 "functions_max": 1,
1601 "closures_min": 0,
1602 "closures_max": 0
1603 }
1604 "#
1605 );
1606 },
1607 );
1608 }
1609
1610 #[test]
1611 fn kotlin_nom_class_with_methods() {
1612 check_metrics::<KotlinParser>(
1613 "class Calculator {
1614 fun add(a: Int, b: Int): Int {
1615 return a + b
1616 }
1617 fun subtract(a: Int, b: Int): Int {
1618 return a - b
1619 }
1620 }",
1621 "foo.kt",
1622 |metric| {
1623 insta::assert_json_snapshot!(
1624 metric.nom,
1625 @r#"
1626 {
1627 "functions": 2,
1628 "closures": 0,
1629 "functions_average": 0.5,
1630 "closures_average": 0.0,
1631 "total": 2,
1632 "average": 0.5,
1633 "functions_min": 0,
1634 "functions_max": 1,
1635 "closures_min": 0,
1636 "closures_max": 0
1637 }
1638 "#
1639 );
1640 },
1641 );
1642 }
1643
1644 #[test]
1645 fn lua_nom() {
1646 check_metrics::<LuaParser>(
1647 "function greet(name)
1648 return \"hello \" .. name
1649end
1650
1651local add = function(a, b)
1652 return a + b
1653end
1654
1655local function outer()
1656 local inner = function()
1657 return 42
1658 end
1659 return inner()
1660end",
1661 "foo.lua",
1662 |metric| {
1663 insta::assert_json_snapshot!(metric.nom, @r#"
1665 {
1666 "functions": 2,
1667 "closures": 2,
1668 "functions_average": 0.4,
1669 "closures_average": 0.4,
1670 "total": 4,
1671 "average": 0.8,
1672 "functions_min": 0,
1673 "functions_max": 1,
1674 "closures_min": 0,
1675 "closures_max": 1
1676 }
1677 "#);
1678 },
1679 );
1680 }
1681
1682 #[test]
1683 fn bash_nom() {
1684 check_metrics::<BashParser>(
1685 "#!/bin/bash
1686foo() {
1687 echo 'hello'
1688}
1689bar() {
1690 echo 'world'
1691}
1692foo
1693bar",
1694 "foo.sh",
1695 |metric| {
1696 insta::assert_json_snapshot!(
1697 metric.nom,
1698 @r#"
1699 {
1700 "functions": 2,
1701 "closures": 0,
1702 "functions_average": 0.6666666666666666,
1703 "closures_average": 0.0,
1704 "total": 2,
1705 "average": 0.6666666666666666,
1706 "functions_min": 0,
1707 "functions_max": 1,
1708 "closures_min": 0,
1709 "closures_max": 0
1710 }
1711 "#
1712 );
1713 },
1714 );
1715 }
1716
1717 #[test]
1718 fn tcl_nom() {
1719 check_metrics::<TclParser>(
1720 "proc foo {a} { puts $a }
1721proc bar {x y} { puts $x }
1722foo 1
1723bar 2 3",
1724 "foo.tcl",
1725 |metric| {
1726 assert_eq!(metric.nom.functions_sum(), 2);
1727 assert_eq!(metric.nom.closures_sum(), 0);
1728 insta::assert_json_snapshot!(metric.nom);
1729 },
1730 );
1731 }
1732
1733 #[test]
1734 fn tcl_nested_nom() {
1735 check_metrics::<TclParser>(
1736 "proc outer {a} {
1737 proc inner {x} { puts $x }
1738 inner $a
1739}",
1740 "foo.tcl",
1741 |metric| {
1742 assert_eq!(metric.nom.functions_sum(), 2);
1743 assert_eq!(metric.nom.closures_sum(), 0);
1744 insta::assert_json_snapshot!(metric.nom);
1745 },
1746 );
1747 }
1748
1749 #[test]
1750 fn typescript_class_methods() {
1751 check_metrics::<TypescriptParser>(
1752 "class Calc {
1753 add(a: number, b: number): number { return a + b; }
1754 sub(a: number, b: number): number { return a - b; }
1755 }",
1756 "foo.ts",
1757 |metric| {
1758 assert_eq!(metric.nom.functions_sum(), 2);
1759 assert_eq!(metric.nom.closures_sum(), 0);
1760 insta::assert_json_snapshot!(metric.nom);
1761 },
1762 );
1763 }
1764
1765 #[test]
1766 fn typescript_arrow_and_function() {
1767 check_metrics::<TypescriptParser>(
1768 "function f(): number { return 1; }
1769 const g = (): number => 2;
1770 const h = (x: number): number => x * 2;",
1771 "foo.ts",
1772 |metric| {
1773 assert_eq!(metric.nom.functions_sum(), 3);
1774 assert_eq!(metric.nom.closures_sum(), 0);
1775 insta::assert_json_snapshot!(metric.nom);
1776 },
1777 );
1778 }
1779
1780 #[test]
1781 fn tsx_class_methods() {
1782 check_metrics::<TsxParser>(
1783 "class Calc {
1784 add(a: number, b: number): number { return a + b; }
1785 sub(a: number, b: number): number { return a - b; }
1786 }",
1787 "foo.tsx",
1788 |metric| {
1789 assert_eq!(metric.nom.functions_sum(), 2);
1790 assert_eq!(metric.nom.closures_sum(), 0);
1791 insta::assert_json_snapshot!(metric.nom);
1792 },
1793 );
1794 }
1795
1796 #[test]
1797 fn tsx_arrow_and_function() {
1798 check_metrics::<TsxParser>(
1799 "function f(): number { return 1; }
1800 const g = (): number => 2;
1801 const h = (x: number): number => x * 2;",
1802 "foo.tsx",
1803 |metric| {
1804 assert_eq!(metric.nom.functions_sum(), 3);
1805 assert_eq!(metric.nom.closures_sum(), 0);
1806 insta::assert_json_snapshot!(metric.nom);
1807 },
1808 );
1809 }
1810
1811 #[test]
1812 fn bash_multiple_functions_nom() {
1813 check_metrics::<BashParser>(
1814 "#!/bin/bash
1815f() {
1816 echo hello
1817}
1818g() {
1819 echo world
1820}",
1821 "foo.sh",
1822 |metric| {
1823 assert_eq!(metric.nom.functions_sum(), 2);
1824 assert_eq!(metric.nom.closures_sum(), 0);
1825 insta::assert_json_snapshot!(metric.nom);
1826 },
1827 );
1828 }
1829
1830 #[test]
1831 fn bash_nested_functions_nom() {
1832 check_metrics::<BashParser>(
1833 "#!/bin/bash
1834outer() {
1835 inner() {
1836 echo inner
1837 }
1838 inner
1839}",
1840 "foo.sh",
1841 |metric| {
1842 assert_eq!(metric.nom.functions_sum(), 2);
1843 assert_eq!(metric.nom.closures_sum(), 0);
1844 insta::assert_json_snapshot!(metric.nom);
1845 },
1846 );
1847 }
1848
1849 #[test]
1850 fn mozjs_nested_function_nom() {
1851 check_metrics::<MozjsParser>(
1852 "function outer() {
1853 function inner() {
1854 return 1;
1855 }
1856 return inner();
1857 }",
1858 "foo.js",
1859 |metric| {
1860 assert_eq!(metric.nom.functions_sum(), 2);
1861 assert_eq!(metric.nom.closures_sum(), 0);
1862 insta::assert_json_snapshot!(metric.nom);
1863 },
1864 );
1865 }
1866
1867 #[test]
1868 fn mozjs_class_methods_nom() {
1869 check_metrics::<MozjsParser>(
1870 "class Calc {
1871 add(a, b) { return a + b; }
1872 sub(a, b) { return a - b; }
1873 }",
1874 "foo.js",
1875 |metric| {
1876 assert_eq!(metric.nom.functions_sum(), 2);
1877 assert_eq!(metric.nom.closures_sum(), 0);
1878 insta::assert_json_snapshot!(metric.nom);
1879 },
1880 );
1881 }
1882
1883 #[test]
1884 fn mozjs_iife_nom() {
1885 check_metrics::<MozjsParser>(
1886 "(function() {
1887 var x = 1;
1888 return x;
1889 })();",
1890 "foo.js",
1891 |metric| {
1892 assert_eq!(metric.nom.functions_sum(), 0);
1893 assert_eq!(metric.nom.closures_sum(), 1);
1894 insta::assert_json_snapshot!(metric.nom);
1895 },
1896 );
1897 }
1898
1899 #[test]
1900 fn kotlin_class_methods_nom() {
1901 check_metrics::<KotlinParser>(
1902 "class Calc {
1903 fun add(a: Int, b: Int): Int = a + b
1904 fun sub(a: Int, b: Int): Int = a - b
1905 }",
1906 "foo.kt",
1907 |metric| {
1908 assert_eq!(metric.nom.functions_sum(), 2);
1909 assert_eq!(metric.nom.closures_sum(), 0);
1910 insta::assert_json_snapshot!(metric.nom);
1911 },
1912 );
1913 }
1914
1915 #[test]
1916 fn kotlin_lambda_nom() {
1917 check_metrics::<KotlinParser>(
1918 "fun f(list: List<Int>): Int {
1919 val double = { x: Int -> x * 2 }
1920 return list.sumOf(double)
1921 }",
1922 "foo.kt",
1923 |metric| {
1924 assert_eq!(metric.nom.functions_sum(), 1);
1925 assert_eq!(metric.nom.closures_sum(), 1);
1926 insta::assert_json_snapshot!(metric.nom);
1927 },
1928 );
1929 }
1930
1931 #[test]
1932 fn php_nom() {
1933 check_metrics::<PhpParser>(
1936 "<?php
1937 function top(): void {}
1938 class A {
1939 public function m1(): void {}
1940 public function m2(): int {
1941 $f = function () { return 1; };
1942 $g = fn () => 2;
1943 return $f() + $g();
1944 }
1945 }",
1946 "foo.php",
1947 |metric| {
1948 insta::assert_json_snapshot!(
1949 metric.nom,
1950 @r#"
1951 {
1952 "functions": 3,
1953 "closures": 2,
1954 "functions_average": 0.42857142857142855,
1955 "closures_average": 0.2857142857142857,
1956 "total": 5,
1957 "average": 0.7142857142857143,
1958 "functions_min": 0,
1959 "functions_max": 1,
1960 "closures_min": 0,
1961 "closures_max": 1
1962 }
1963 "#
1964 );
1965 },
1966 );
1967 }
1968
1969 #[test]
1970 fn php_nom_anonymous_class() {
1971 check_metrics::<PhpParser>(
1975 "<?php
1976 function f(): object {
1977 return new class {
1978 public function inner(): int { return 1; }
1979 };
1980 }",
1981 "foo.php",
1982 |metric| {
1983 insta::assert_json_snapshot!(
1984 metric.nom,
1985 @r#"
1986 {
1987 "functions": 2,
1988 "closures": 0,
1989 "functions_average": 0.5,
1990 "closures_average": 0.0,
1991 "total": 2,
1992 "average": 0.5,
1993 "functions_min": 0,
1994 "functions_max": 1,
1995 "closures_min": 0,
1996 "closures_max": 0
1997 }
1998 "#
1999 );
2000 },
2001 );
2002 }
2003
2004 #[test]
2013 fn elixir_nom_counts_def_as_functions_and_fn_as_closures() {
2014 check_metrics::<ElixirParser>(
2015 "defmodule Foo do\n def public_fn(x), do: x + 1\n defp private_fn(x), do: x - 1\n def with_anon do\n inc = fn x -> x + 1 end\n dec = fn x -> x - 1 end\n {inc, dec}\n end\nend\n",
2016 "foo.ex",
2017 |metric| {
2018 assert_eq!(metric.nom.functions_sum(), 3);
2019 assert_eq!(metric.nom.closures_sum(), 2);
2020 assert_eq!(metric.nom.total(), 5);
2021 },
2022 );
2023 }
2024
2025 #[test]
2026 fn stats_display_commas_between_all_fields() {
2027 let stats = Stats {
2028 functions: 0,
2029 closures: 0,
2030 functions_sum: 3,
2031 closures_sum: 1,
2032 functions_min: 0,
2033 functions_max: 2,
2034 closures_min: 0,
2035 closures_max: 1,
2036 space_count: 2,
2037 };
2038 let formatted = format!("{stats}");
2039
2040 let expected_fragments = [
2043 "functions: 3, closures: 1",
2044 "closures: 1, functions_average:",
2045 "functions_average: 1.5, closures_average:",
2046 "closures_average: 0.5, total:",
2047 "total: 4, average:",
2048 "average: 2, functions_min:",
2049 "functions_min: 0, functions_max:",
2050 "functions_max: 2, closures_min:",
2051 "closures_min: 0, closures_max:",
2052 ];
2053
2054 for fragment in expected_fragments {
2055 assert!(
2056 formatted.contains(fragment),
2057 "missing fragment {fragment:?} in: {formatted}"
2058 );
2059 }
2060 }
2061
2062 #[test]
2063 fn ruby_nom() {
2064 check_metrics::<RubyParser>(
2070 "class C\n def add(a, b)\n a + b\n end\n def mul(a, b)\n a * b\n end\n def self.factory\n new\n end\nend\n\n[1, 2, 3].each { |x| puts x }\n",
2071 "foo.rb",
2072 |metric| {
2073 assert_eq!(metric.nom.functions_sum(), 3);
2074 assert_eq!(metric.nom.closures_sum(), 1);
2075 assert_eq!(metric.nom.total(), 4);
2076 },
2077 );
2078 }
2079
2080 #[test]
2081 fn ruby_stabby_lambda_single_closure() {
2082 check_metrics::<RubyParser>("f = ->(z) { z + 1 }\n", "stabby.rb", |metric| {
2087 assert_eq!(metric.nom.functions_sum(), 0);
2088 assert_eq!(metric.nom.closures_sum(), 1);
2089 });
2090 }
2091
2092 #[test]
2093 fn ruby_stabby_lambda_multi_statement_single_closure() {
2094 check_metrics::<RubyParser>(
2097 "f = ->(z) {\n y = z + 1\n y * 2\n}\n",
2098 "stabby_multi.rb",
2099 |metric| {
2100 assert_eq!(metric.nom.closures_sum(), 1);
2101 },
2102 );
2103 }
2104
2105 #[test]
2106 fn ruby_stabby_lambda_do_block_single_closure() {
2107 check_metrics::<RubyParser>("f = ->(z) do\n z + 1\nend\n", "stabby_do.rb", |metric| {
2110 assert_eq!(metric.nom.closures_sum(), 1);
2111 });
2112 }
2113
2114 #[test]
2115 fn ruby_keyword_lambda_single_closure() {
2116 check_metrics::<RubyParser>(
2121 "g = lambda { |z| z + 1 }\nh = proc { |z| z + 1 }\n",
2122 "keyword.rb",
2123 |metric| {
2124 assert_eq!(metric.nom.closures_sum(), 2);
2125 },
2126 );
2127 }
2128
2129 #[test]
2134 fn irules_nom_handlers_and_procs() {
2135 check_metrics::<IrulesParser>(
2136 "when CLIENT_ACCEPTED {
2137 log local0. \"connected\"
2138}
2139when HTTP_REQUEST {
2140 log local0. [HTTP::uri]
2141}
2142proc helper { x } {
2143 return $x
2144}
2145",
2146 "foo.irule",
2147 |metric| {
2148 assert_eq!(metric.nom.functions_sum(), 3);
2149 assert_eq!(metric.nom.closures_sum(), 0);
2150 assert_eq!(metric.nom.total(), 3);
2151 },
2152 );
2153 }
2154
2155 #[test]
2160 fn objc_nom() {
2161 check_metrics::<ObjcParser>(
2162 "@implementation Foo
2163- (void)one {
2164 void (^blk)(void) = ^{
2165 [self two];
2166 };
2167 blk();
2168}
2169- (void)two {
2170 [self one];
2171}
2172@end
2173",
2174 "foo.m",
2175 |metric| {
2176 assert_eq!(metric.nom.functions_sum(), 2);
2177 assert_eq!(metric.nom.closures_sum(), 1);
2178 assert_eq!(metric.nom.total(), 3);
2179 insta::assert_json_snapshot!(metric.nom, @r#"
2180 {
2181 "functions": 2,
2182 "closures": 1,
2183 "functions_average": 0.5,
2184 "closures_average": 0.25,
2185 "total": 3,
2186 "average": 0.75,
2187 "functions_min": 0,
2188 "functions_max": 1,
2189 "closures_min": 0,
2190 "closures_max": 1
2191 }
2192 "#);
2193 },
2194 );
2195 }
2196}