1#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
8#![allow(
12 clippy::cast_precision_loss,
13 clippy::cast_possible_truncation,
14 clippy::cast_sign_loss
15)]
16
17use std::fmt;
18
19use crate::checker::Checker;
20use crate::macros::implement_metric_trait;
21use crate::*;
22
23#[derive(Debug, Clone, Default, PartialEq)]
31#[non_exhaustive]
32pub struct Stats {
33 cyclomatic: f64,
34 nested_class_cyclomatic: f64,
42 class_wmc: f64,
43 interface_wmc: f64,
44 class_wmc_sum: f64,
45 interface_wmc_sum: f64,
46 space_kind: SpaceKind,
47}
48
49impl fmt::Display for Stats {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 write!(
52 f,
53 "classes: {}, interfaces: {}, total: {}",
54 self.class_wmc_sum(),
55 self.interface_wmc_sum(),
56 self.total_wmc()
57 )
58 }
59}
60
61impl Stats {
62 pub fn merge(&mut self, other: &Stats) {
64 use SpaceKind::*;
65
66 match other.space_kind {
70 Function => {
78 let own_cyclomatic = other.cyclomatic - other.nested_class_cyclomatic;
79 match self.space_kind {
80 Class => self.class_wmc += own_cyclomatic,
81 Interface => self.interface_wmc += own_cyclomatic,
82 _ => {}
83 }
84 self.nested_class_cyclomatic += other.nested_class_cyclomatic;
85 }
86 Class | Interface => self.nested_class_cyclomatic += other.cyclomatic,
93 _ => {}
94 }
95
96 self.class_wmc_sum += other.class_wmc_sum;
97 self.interface_wmc_sum += other.interface_wmc_sum;
98 }
99
100 #[inline]
102 #[must_use]
103 pub fn class_wmc(&self) -> u64 {
104 self.class_wmc as u64
105 }
106
107 #[inline]
109 #[must_use]
110 pub fn interface_wmc(&self) -> u64 {
111 self.interface_wmc as u64
112 }
113
114 #[inline]
116 #[must_use]
117 pub fn class_wmc_sum(&self) -> u64 {
118 self.class_wmc_sum as u64
119 }
120
121 #[inline]
123 #[must_use]
124 pub fn interface_wmc_sum(&self) -> u64 {
125 self.interface_wmc_sum as u64
126 }
127
128 #[inline]
130 #[must_use]
131 pub fn total_wmc(&self) -> u64 {
132 self.class_wmc_sum() + self.interface_wmc_sum()
133 }
134
135 #[inline]
138 pub(crate) fn compute_sum(&mut self) {
139 self.class_wmc_sum += self.class_wmc;
140 self.interface_wmc_sum += self.interface_wmc;
141 }
142
143 #[inline]
145 pub(crate) fn is_disabled(&self) -> bool {
146 !self.space_kind.is_member_scope()
147 }
148}
149
150#[doc(hidden)]
151pub(crate) trait Wmc
153where
154 Self: Checker,
155{
156 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats);
159}
160
161fn class_interface_compute(
166 space_kind: SpaceKind,
167 cyclomatic: &cyclomatic::Stats,
168 stats: &mut Stats,
169) {
170 use SpaceKind::*;
171
172 if let Unit | Class | Interface | Function = space_kind {
173 if stats.space_kind == Unknown {
174 stats.space_kind = space_kind;
175 }
176 if let Function | Class | Interface = space_kind {
181 stats.cyclomatic = cyclomatic.cyclomatic_sum() as f64;
182 }
183 }
184}
185
186impl Wmc for JavaCode {
187 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
188 class_interface_compute(space_kind, cyclomatic, stats);
189 }
190}
191
192impl Wmc for GroovyCode {
193 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
194 class_interface_compute(space_kind, cyclomatic, stats);
195 }
196}
197
198impl Wmc for CsharpCode {
199 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
200 class_interface_compute(space_kind, cyclomatic, stats);
201 }
202}
203
204impl Wmc for KotlinCode {
215 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
216 class_interface_compute(space_kind, cyclomatic, stats);
217 }
218}
219
220impl Wmc for PhpCode {
221 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
222 use SpaceKind::*;
223
224 if let Unit | Class | Interface | Function = space_kind {
227 if stats.space_kind == Unknown {
228 stats.space_kind = space_kind;
229 }
230 if let Function | Class | Interface = space_kind {
236 stats.cyclomatic = cyclomatic.cyclomatic_sum() as f64;
237 }
238 }
239 }
240}
241
242impl Wmc for PythonCode {
256 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
257 class_interface_compute(space_kind, cyclomatic, stats);
258 }
259}
260
261impl Wmc for RustCode {
280 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
281 let mapped = match space_kind {
282 SpaceKind::Impl => SpaceKind::Class,
283 SpaceKind::Trait => SpaceKind::Interface,
284 other => other,
285 };
286 class_interface_compute(mapped, cyclomatic, stats);
287 }
288}
289
290impl Wmc for CppCode {
302 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
303 let mapped = match space_kind {
304 SpaceKind::Struct => SpaceKind::Class,
305 other => other,
306 };
307 class_interface_compute(mapped, cyclomatic, stats);
308 }
309}
310
311impl Wmc for MozcppCode {
312 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
313 let mapped = match space_kind {
314 SpaceKind::Struct => SpaceKind::Class,
315 other => other,
316 };
317 class_interface_compute(mapped, cyclomatic, stats);
318 }
319}
320
321impl Wmc for ObjcCode {
328 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
329 class_interface_compute(space_kind, cyclomatic, stats);
330 }
331}
332
333impl Wmc for TypescriptCode {
342 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
343 class_interface_compute(space_kind, cyclomatic, stats);
344 }
345}
346
347impl Wmc for TsxCode {
348 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
349 class_interface_compute(space_kind, cyclomatic, stats);
350 }
351}
352
353impl Wmc for RubyCode {
361 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
362 class_interface_compute(space_kind, cyclomatic, stats);
363 }
364}
365
366impl Wmc for JavascriptCode {
372 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
373 class_interface_compute(space_kind, cyclomatic, stats);
374 }
375}
376
377impl Wmc for MozjsCode {
378 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
379 class_interface_compute(space_kind, cyclomatic, stats);
380 }
381}
382
383impl Wmc for ElixirCode {
407 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
408 class_interface_compute(space_kind, cyclomatic, stats);
409 }
410}
411
412implement_metric_trait!(
419 Wmc,
420 CCode,
421 PreprocCode,
422 CcommentCode,
423 GoCode,
424 PerlCode,
425 BashCode,
426 LuaCode,
427 TclCode,
428 IrulesCode
429);
430
431#[cfg(test)]
432#[allow(
433 clippy::float_cmp,
434 clippy::cast_precision_loss,
435 clippy::cast_possible_truncation,
436 clippy::cast_sign_loss,
437 clippy::similar_names,
438 clippy::doc_markdown,
439 clippy::needless_raw_string_hashes,
440 clippy::too_many_lines
441)]
442mod tests {
443 use crate::test_support::{
444 assert_child_space_kind, check_func_space_only_shim, check_metrics_only_shim, child_space,
445 };
446
447 use super::*;
448
449 check_metrics_only_shim!(check_metrics, Wmc);
452 check_func_space_only_shim!(check_func_space, Wmc);
453 check_metrics_only_shim!(check_wmc_and_npm, Wmc, Npm);
457
458 #[test]
459 fn java_single_class() {
460 check_metrics::<JavaParser>(
461 "public class Example { // wmc = 13
462
463 public boolean m1(boolean a, boolean b) { // +1
464 boolean r = false;
465 if (a && b == a || b) { // +3
466 r = true;
467 }
468 return r;
469 }
470
471 public boolean m2(int n) { // +1
472 for (int i = 0; i < n; i++) { // +1
473 int j = n;
474 while (j > i) { // +1
475 j--;
476 }
477 }
478 return (n % 2 == 0) ? true : false; // +1
479 }
480
481 public int m3(int x, int y, int z) { // +1
482 int ret;
483 try {
484 z = x/y + y/x;
485 } catch (ArithmeticException e) { // +1
486 z = (x == 0) ? -1 : -2; // +1
487 }
488 switch (z) {
489 case -1: // +1
490 ret = y * y;
491 break;
492 case -2: // +1
493 ret = x * x;
494 break;
495 default:
496 ret = x + y;
497 }
498 return ret;
499 }
500 }",
501 "foo.java",
502 |metric| {
503 insta::assert_json_snapshot!(
505 metric.wmc,
506 @r#"
507 {
508 "class_wmc_sum": 13,
509 "interface_wmc_sum": 0,
510 "total": 13
511 }
512 "#
513 );
514 },
515 );
516 }
517
518 #[test]
519 fn groovy_single_class() {
520 check_metrics::<GroovyParser>(
522 "class Example {
523 boolean m1(boolean a, boolean b) {
524 boolean r = false
525 if (a && b == a || b) {
526 r = true
527 }
528 return r
529 }
530 boolean m2(int n) {
531 for (int i = 0; i < n; i++) {
532 int j = n
533 while (j > i) {
534 j--
535 }
536 }
537 return (n % 2 == 0) ? true : false
538 }
539 }",
540 "foo.groovy",
541 |metric| {
542 assert_eq!(metric.wmc.class_wmc_sum(), 8);
546 },
547 );
548 }
549
550 #[test]
551 fn groovy_empty_class() {
552 check_metrics::<GroovyParser>("class Empty {}", "foo.groovy", |metric| {
553 assert_eq!(metric.wmc.class_wmc_sum(), 0);
554 });
555 }
556
557 #[test]
558 fn groovy_class_with_single_method() {
559 check_metrics::<GroovyParser>(
560 "class A {
561 void foo() {
562 println 'hi'
563 }
564 }",
565 "foo.groovy",
566 |metric| {
567 assert_eq!(metric.wmc.class_wmc_sum(), 1);
569 },
570 );
571 }
572
573 #[test]
574 fn groovy_multiple_classes() {
575 check_metrics::<GroovyParser>(
576 "class A {
577 void f() { if (true) {} }
578 }
579 class B {
580 void g() {}
581 }",
582 "foo.groovy",
583 |metric| {
584 assert_eq!(metric.wmc.class_wmc_sum(), 3);
586 },
587 );
588 }
589
590 #[test]
591 fn groovy_class_with_branching_methods() {
592 check_metrics::<GroovyParser>(
593 "class Calc {
594 int abs(int x) {
595 if (x < 0) {
596 return -x
597 }
598 return x
599 }
600 int sign(int x) {
601 if (x > 0) return 1
602 if (x < 0) return -1
603 return 0
604 }
605 }",
606 "foo.groovy",
607 |metric| {
608 assert_eq!(metric.wmc.class_wmc_sum(), 5);
610 },
611 );
612 }
613
614 #[test]
615 fn groovy_interface_wmc_is_zero() {
616 check_metrics::<GroovyParser>(
618 "interface I {
619 void a()
620 void b()
621 }",
622 "foo.groovy",
623 |metric| {
624 assert_eq!(metric.wmc.class_wmc_sum(), 0);
625 },
626 );
627 }
628
629 #[test]
630 fn groovy_static_nested_class() {
631 check_metrics::<GroovyParser>(
634 "class TopLevelClass {
635 static class StaticNestedClass {
636 private void m() {
637 println 'Test'
638 }
639 }
640 }",
641 "foo.groovy",
642 |metric| {
643 assert_eq!(metric.wmc.class_wmc_sum(), 1);
645 },
646 );
647 }
648
649 #[test]
650 #[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside class bodies"]
651 fn groovy_nested_inner_classes_wmc() {
652 check_metrics::<GroovyParser>(
655 "class X {
656 void a() {}
657 class Y {
658 void b() {}
659 class Z {
660 void c() {}
661 }
662 }
663 }",
664 "foo.groovy",
665 |metric| {
666 assert_eq!(metric.wmc.class_wmc_sum(), 3);
668 },
669 );
670 }
671
672 #[test]
673 fn groovy_local_inner_class() {
674 check_metrics::<GroovyParser>(
683 "class Outer {
684 void m() {
685 class Local {
686 void l() {
687 if (true) {}
688 }
689 }
690 }
691 }",
692 "foo.groovy",
693 |metric| {
694 assert_eq!(metric.wmc.class_wmc_sum(), 3);
695 },
696 );
697 }
698
699 #[test]
700 #[ignore = "dekobon Groovy grammar v1 does not yet support anonymous inner classes (`new T() { … }`)"]
701 fn groovy_anonymous_inner_class_wmc() {
702 check_metrics::<GroovyParser>(
705 "abstract class Base {
706 abstract void m1()
707 }
708 class Top {
709 void m() {
710 def b = new Base() {
711 void m1() {
712 for (int i = 0; i < 5; i++) {
713 println(i)
714 }
715 }
716 }
717 }
718 }",
719 "foo.groovy",
720 |metric| {
721 assert_eq!(metric.wmc.class_wmc_sum(), 4);
723 },
724 );
725 }
726
727 #[test]
728 fn groovy_lambda_expression_wmc() {
729 check_metrics::<GroovyParser>(
732 "class Top {
733 void m1() {
734 def list = [1, 2, 3]
735 list.each { n -> println(n) }
736 }
737 void m2() {
738 if (true) {}
739 }
740 }",
741 "foo.groovy",
742 |metric| {
743 assert_eq!(metric.wmc.class_wmc_sum(), 3);
745 },
746 );
747 }
748
749 #[test]
750 fn groovy_single_interface_wmc() {
751 check_metrics::<GroovyParser>(
754 "interface Example {
755 default boolean m1(boolean a, boolean b) {
756 return (a && b == a || b)
757 }
758 default int m2(int n) {
759 return (n != 0) ? 1/n : n
760 }
761 void m3()
762 }",
763 "foo.groovy",
764 |metric| {
765 assert_eq!(metric.wmc.interface_wmc_sum(), 6);
767 assert_eq!(metric.wmc.class_wmc_sum(), 0);
768 },
769 );
770 }
771
772 #[test]
773 #[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside interface bodies"]
774 fn groovy_class_in_interface() {
775 check_metrics::<GroovyParser>(
778 "interface Outer {
779 void api()
780 class Inner {
781 void f() {
782 if (true) {}
783 }
784 }
785 }",
786 "foo.groovy",
787 |metric| {
788 assert_eq!(metric.wmc.interface_wmc_sum(), 1);
790 assert_eq!(metric.wmc.class_wmc_sum(), 2);
791 },
792 );
793 }
794
795 #[test]
798 fn groovy_enum_wmc_aggregates_method_complexity() {
799 check_metrics::<GroovyParser>(
800 "enum Status {
801 ACTIVE, INACTIVE;
802 public int code(int n) {
803 if (n > 0) { return n }
804 return 0
805 }
806 }",
807 "foo.groovy",
808 |metric| {
809 assert_eq!(metric.wmc.class_wmc_sum(), 2);
810 },
811 );
812 }
813
814 #[test]
822 #[ignore = "dekobon Groovy grammar v1 does not support annotation type elements with `default` values"]
823 fn groovy_annotation_type_opens_interface_space_with_zero_wmc() {
824 check_func_space::<GroovyParser, _>(
825 "public @interface Marker {
826 String value() default \"\";
827 int priority() default 0;
828 }",
829 "foo.groovy",
830 |func_space| {
831 assert_eq!(func_space.metrics.wmc.interface_wmc_sum(), 0);
832 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
833 },
834 );
835 }
836
837 #[test]
840 fn java_multiple_classes() {
841 check_metrics::<JavaParser>(
842 "public class MainClass { // wmc = 3
843 private int a;
844 public MainClass() { // +1
845 a = 0;
846 }
847 public void setA(int n) { // +1
848 a = n;
849 }
850 public int getA() { // +1
851 return a;
852 }
853 }
854
855 class TopLevelClass { // wmc = 2
856 private int b;
857 public TopLevelClass() { // +1
858 b = 0;
859 }
860 public int getB() { // +1
861 return b;
862 }
863 }",
864 "foo.java",
865 |metric| {
866 insta::assert_json_snapshot!(
868 metric.wmc,
869 @r#"
870 {
871 "class_wmc_sum": 5,
872 "interface_wmc_sum": 0,
873 "total": 5
874 }
875 "#
876 );
877 },
878 );
879 }
880
881 #[test]
882 fn java_static_nested_class() {
883 check_metrics::<JavaParser>(
884 "public class TopLevelClass { // wmc = 0
885 public static class StaticNestedClass { // wmc = 1
886 private void m() { // +1
887 System.out.println(\"Test\");
888 }
889 }
890 }",
891 "foo.java",
892 |metric| {
893 insta::assert_json_snapshot!(
895 metric.wmc,
896 @r#"
897 {
898 "class_wmc_sum": 1,
899 "interface_wmc_sum": 0,
900 "total": 1
901 }
902 "#
903 );
904 },
905 );
906 }
907
908 #[test]
909 fn java_nested_inner_classes() {
910 check_metrics::<JavaParser>(
911 "public class TopLevelClass { // wmc = 2
912 private int a;
913
914 class InnerClassBefore { // wmc = 1
915 private boolean b = (a % 2 == 0) ? true : false;
916 public boolean getB() { // +1
917 return b;
918 }
919 }
920
921 public TopLevelClass(int n) { // +1
922 if (a != n) { // +1
923 a = n;
924 }
925 }
926
927 class InnerClassAfter { // wmc = 2
928 private int c = a;
929
930 public int getC() { // +1
931 return c;
932 }
933 public void setC(int n) { // +1
934 c = n;
935 }
936
937 class InnerClass1 { // wmc = 1
938 private int p1;
939 class InnerClass2 { // wmc = 1
940 private int p2;
941 public int getP2() { // +1
942 return p2;
943 }
944 class InnerClass3 { // wmc = 2
945 private int p3;
946 public int getP3() { // +1
947 return p3;
948 }
949 public void setP3(int n) { // +1
950 p3 = n;
951 }
952 }
953 }
954 public void setP1(int n) { // +1
955 p1 = n;
956 }
957 }
958 }
959 }",
960 "foo.java",
961 |metric| {
962 insta::assert_json_snapshot!(
964 metric.wmc,
965 @r#"
966 {
967 "class_wmc_sum": 9,
968 "interface_wmc_sum": 0,
969 "total": 9
970 }
971 "#
972 );
973 },
974 );
975 }
976
977 #[test]
978 fn java_local_inner_class() {
979 check_metrics::<JavaParser>(
980 "import java.util.LinkedList;
981 import java.util.List;
982
983 public final class FinalClass { // wmc = 1 (test only)
984 private int a = 1;
985 public void test() { // +1
986 final List<String> localList = new LinkedList<String>();
987
988 class LocalInnerClass { // wmc = 2 (print only)
989 private int b = (a == 1) ? 1 : 0; // field init, not a method
990 public void print() { // +1
991 for ( String s : localList ) { // +1
992 System.out.println(s);
993 }
994 }
995 }
996 }
997 }",
998 "foo.java",
999 |metric| {
1000 assert_eq!(metric.wmc.class_wmc_sum(), 3);
1011 insta::assert_json_snapshot!(
1012 metric.wmc,
1013 @r#"
1014 {
1015 "class_wmc_sum": 3,
1016 "interface_wmc_sum": 0,
1017 "total": 3
1018 }
1019 "#
1020 );
1021 },
1022 );
1023 }
1024
1025 #[test]
1026 fn java_anonymous_inner_class() {
1027 check_metrics::<JavaParser>(
1028 "abstract class AbstractClass { // wmc = 1
1029 abstract void m1(); // +1
1030 }
1031 public class TopLevelClass{ // wmc = 3
1032 public void m(){ // +1
1033 AbstractClass ac1 = new AbstractClass() {
1034 void m1() { // +1
1035 for (int i = 0; i < 5; i++) { // +1
1036 System.out.println(\"Test 1: \" + i);
1037 }
1038 }
1039 };
1040 ac1.m1();
1041 }
1042 }",
1043 "foo.java",
1044 |metric| {
1045 insta::assert_json_snapshot!(
1047 metric.wmc,
1048 @r#"
1049 {
1050 "class_wmc_sum": 4,
1051 "interface_wmc_sum": 0,
1052 "total": 4
1053 }
1054 "#
1055 );
1056 },
1057 );
1058 }
1059
1060 #[test]
1061 fn java_nested_anonymous_inner_classes() {
1062 check_metrics::<JavaParser>(
1063 "abstract class AbstractClass{ // wmc = 2
1064 abstract void m1(); // +1
1065 abstract void m2(); // +1
1066 }
1067 public class TopLevelClass{ // wmc = 6
1068 public void m(){ // +1
1069
1070 AbstractClass ac1 = new AbstractClass() {
1071 void m1() { // +1
1072 for (int i = 0; i < 5; i++) { // +1
1073 System.out.println(\"Test 1: \" + i);
1074 }
1075 }
1076 void m2() { // +1
1077 AbstractClass ac2 = new AbstractClass() {
1078 void m1() { // +1
1079 System.out.println(\"Test A\");
1080 }
1081 void m2() { // +1
1082 System.out.println(\"Test B\");
1083 }
1084 };
1085 ac2.m2();
1086 System.out.println(\"Test 2\");
1087 }
1088 };
1089 ac1.m1();
1090 }
1091 }",
1092 "foo.java",
1093 |metric| {
1094 insta::assert_json_snapshot!(
1096 metric.wmc,
1097 @r#"
1098 {
1099 "class_wmc_sum": 8,
1100 "interface_wmc_sum": 0,
1101 "total": 8
1102 }
1103 "#
1104 );
1105 },
1106 );
1107 }
1108
1109 #[test]
1110 fn java_lambda_expression() {
1111 check_metrics::<JavaParser>(
1112 "import java.util.ArrayList;
1113
1114 public class TopLevelClass { // wmc = 2
1115 private ArrayList<Integer> numbers;
1116
1117 public void m1() { // +1
1118 numbers = new ArrayList<Integer>();
1119 numbers.add(1);
1120 numbers.add(2);
1121 numbers.add(3);
1122 }
1123
1124 public void m2() { // +1
1125 numbers.forEach( (n) -> { System.out.println(n); } );
1126 }
1127 }",
1128 "foo.java",
1129 |metric| {
1130 insta::assert_json_snapshot!(
1132 metric.wmc,
1133 @r#"
1134 {
1135 "class_wmc_sum": 2,
1136 "interface_wmc_sum": 0,
1137 "total": 2
1138 }
1139 "#
1140 );
1141 },
1142 );
1143 }
1144
1145 #[test]
1146 fn java_single_interface() {
1147 check_metrics::<JavaParser>(
1148 "interface Example { // wmc = 6
1149 default boolean m1(boolean a, boolean b) { // +1
1150 return (a && b == a || b); // +2
1151 }
1152 default int m2(int n) { // +1
1153 return (n != 0) ? 1/n : n; // +1
1154 };
1155 void m3(); // +1
1156 }",
1157 "foo.java",
1158 |metric| {
1159 insta::assert_json_snapshot!(
1161 metric.wmc,
1162 @r#"
1163 {
1164 "class_wmc_sum": 0,
1165 "interface_wmc_sum": 6,
1166 "total": 6
1167 }
1168 "#
1169 );
1170 },
1171 );
1172 }
1173
1174 #[test]
1175 fn java_multiple_interfaces() {
1176 check_metrics::<JavaParser>(
1177 "interface FirstInterface { // wmc = 1
1178 int a = 0;
1179 default int getA() { // +1
1180 return a;
1181 }
1182 }
1183
1184 interface SecondInterface { // wmc = 2
1185 void setB(int n); // +1
1186 int getB(); // +1
1187 }",
1188 "foo.java",
1189 |metric| {
1190 insta::assert_json_snapshot!(
1192 metric.wmc,
1193 @r#"
1194 {
1195 "class_wmc_sum": 0,
1196 "interface_wmc_sum": 3,
1197 "total": 3
1198 }
1199 "#
1200 );
1201 },
1202 );
1203 }
1204
1205 #[test]
1206 fn java_nested_inner_interfaces() {
1207 check_metrics::<JavaParser>(
1208 "interface TopLevelInterface { // wmc = 1
1209 interface InnerInterfaceBefore { // wmc = 1
1210 void m1(); // +1
1211 }
1212
1213 void m2(); // +1
1214
1215 interface InnerInterfaceAfter { // wmc = 2
1216 void m3(); // +1
1217 interface InnerInterface { // wmc = 1
1218 void m4(); // +1
1219 }
1220 void m5(); // +1
1221 }
1222 }",
1223 "foo.java",
1224 |metric| {
1225 insta::assert_json_snapshot!(
1227 metric.wmc,
1228 @r#"
1229 {
1230 "class_wmc_sum": 0,
1231 "interface_wmc_sum": 5,
1232 "total": 5
1233 }
1234 "#
1235 );
1236 },
1237 );
1238 }
1239
1240 #[test]
1241 fn java_class_in_interface() {
1242 check_metrics::<JavaParser>(
1243 "interface TopLevelInterface { // wmc = 2
1244 int getA(); // +1
1245 boolean getB(); // +1
1246
1247 class InnerClass { // wmc = 2
1248 float c;
1249 double d;
1250 float getC() { // +1
1251 return c;
1252 }
1253 double getD() { // +1
1254 return d;
1255 }
1256 }
1257 }",
1258 "foo.java",
1259 |metric| {
1260 insta::assert_json_snapshot!(
1262 metric.wmc,
1263 @r#"
1264 {
1265 "class_wmc_sum": 2,
1266 "interface_wmc_sum": 2,
1267 "total": 4
1268 }
1269 "#
1270 );
1271 },
1272 );
1273 }
1274
1275 #[test]
1276 fn java_interface_in_class() {
1277 check_metrics::<JavaParser>(
1278 "class TopLevelClass { // wmc = 2
1279 int a;
1280 boolean b;
1281 int getA() { // +1
1282 return a;
1283 }
1284 boolean getB() { // +1
1285 return b;
1286 }
1287
1288 interface InnerInterface { // wmc = 2
1289 float getC(); // +1
1290 double getD(); // +1
1291 }
1292 }",
1293 "foo.java",
1294 |metric| {
1295 insta::assert_json_snapshot!(
1297 metric.wmc,
1298 @r#"
1299 {
1300 "class_wmc_sum": 2,
1301 "interface_wmc_sum": 2,
1302 "total": 4
1303 }
1304 "#
1305 );
1306 },
1307 );
1308 }
1309
1310 #[test]
1314 fn java_enum_wmc_aggregates_method_complexity() {
1315 check_metrics::<JavaParser>(
1316 "enum Status {
1317 ACTIVE, INACTIVE;
1318 public int code(int n) { // entry +1
1319 if (n > 0) { // if +1
1320 return n;
1321 }
1322 return 0;
1323 }
1324 }",
1325 "foo.java",
1326 |metric| {
1327 assert_eq!(metric.wmc.class_wmc_sum(), 2);
1329 },
1330 );
1331 }
1332
1333 #[test]
1337 fn java_record_wmc_aggregates_method_complexity() {
1338 check_metrics::<JavaParser>(
1339 "record Point(int x, int y) {
1340 public int describe() { // entry +1
1341 return (x == 0) ? 0 : 1; // ternary +1
1342 }
1343 }",
1344 "foo.java",
1345 |metric| {
1346 assert_eq!(metric.wmc.class_wmc_sum(), 2);
1347 },
1348 );
1349 }
1350
1351 #[test]
1362 fn java_record_compact_and_alternative_constructors_open_two_spaces() {
1363 check_func_space::<JavaParser, _>(
1364 "record R(int a, int b) {
1365 R { // entry +1, if +1
1366 if (a < 0) { throw new IllegalArgumentException(); }
1367 }
1368 R(int a) { this(a, 0); } // entry +1
1369 }",
1370 "R.java",
1371 |space| {
1372 assert_child_space_kind(&space, "R", SpaceKind::Class);
1373 let record = child_space(&space, "R");
1374 let constructors = record
1375 .spaces
1376 .iter()
1377 .filter(|child| child.kind == SpaceKind::Function)
1378 .count();
1379 assert_eq!(constructors, 2, "compact + delegating constructor spaces");
1380 assert_eq!(record.metrics.wmc.class_wmc(), 3);
1384 },
1385 );
1386 }
1387
1388 #[test]
1400 fn java_record_without_constructor_opens_only_its_methods() {
1401 check_func_space::<JavaParser, _>(
1402 "record R(int a, int b) {
1403 int sum() { return a + b; } // entry +1
1404 }",
1405 "R.java",
1406 |space| {
1407 assert_child_space_kind(&space, "R", SpaceKind::Class);
1408 let record = child_space(&space, "R");
1409 let functions: Vec<_> = record
1410 .spaces
1411 .iter()
1412 .filter(|child| child.kind == SpaceKind::Function)
1413 .map(|child| child.name.as_deref())
1414 .collect();
1415 assert_eq!(functions, vec![Some("sum")]);
1416 assert_eq!(record.metrics.wmc.class_wmc(), 1);
1417 },
1418 );
1419 }
1420
1421 #[test]
1434 fn java_annotation_type_opens_interface_space_with_zero_wmc() {
1435 check_func_space::<JavaParser, _>(
1436 "@interface Marker {
1437 String value() default \"\";
1438 int priority() default 0;
1439 }",
1440 "foo.java",
1441 |func_space| {
1442 assert_eq!(func_space.metrics.wmc.interface_wmc_sum(), 0);
1443 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
1446 },
1447 );
1448 }
1449
1450 #[test]
1451 fn csharp_single_class() {
1452 check_metrics::<CsharpParser>(
1453 "public class Example {
1454 public bool M1(bool a, bool b) {
1455 bool r = false;
1456 if (a && b == a || b) {
1457 r = true;
1458 }
1459 return r;
1460 }
1461 public int M2(int n) {
1462 for (int i = 0; i < n; i++) {
1463 int j = n;
1464 while (j > i) {
1465 j--;
1466 }
1467 }
1468 return (n % 2 == 0) ? 1 : 0;
1469 }
1470 }",
1471 "foo.cs",
1472 |metric| {
1473 assert_eq!(metric.wmc.class_wmc_sum(), 8);
1474 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1475 insta::assert_json_snapshot!(metric.wmc);
1476 },
1477 );
1478 }
1479
1480 #[test]
1481 fn csharp_multiple_classes() {
1482 check_metrics::<CsharpParser>(
1483 "public class A {
1484 private int a;
1485 public A() { a = 0; }
1486 public void SetA(int n) { a = n; }
1487 public int GetA() { return a; }
1488 }
1489 class B {
1490 private int b;
1491 public B() { b = 0; }
1492 public int GetB() { return b; }
1493 }",
1494 "foo.cs",
1495 |metric| {
1496 assert_eq!(metric.wmc.class_wmc_sum(), 5);
1497 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1498 insta::assert_json_snapshot!(metric.wmc);
1499 },
1500 );
1501 }
1502
1503 #[test]
1504 fn csharp_static_nested_class() {
1505 check_metrics::<CsharpParser>(
1506 "public class Outer {
1507 public static class Nested {
1508 private void M() {
1509 System.Console.WriteLine(\"Test\");
1510 }
1511 }
1512 }",
1513 "foo.cs",
1514 |metric| {
1515 assert_eq!(metric.wmc.class_wmc_sum(), 1);
1516 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1517 insta::assert_json_snapshot!(metric.wmc);
1518 },
1519 );
1520 }
1521
1522 #[test]
1523 fn csharp_nested_inner_classes() {
1524 check_metrics::<CsharpParser>(
1525 "public class Outer {
1526 private int a;
1527 public class Inner {
1528 public int GetX() { return 0; }
1529 public class Innermost {
1530 public int GetY() { return 1; }
1531 }
1532 }
1533 public int GetA() { return a; }
1534 }",
1535 "foo.cs",
1536 |metric| {
1537 assert_eq!(metric.wmc.class_wmc_sum(), 3);
1538 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1539 insta::assert_json_snapshot!(metric.wmc);
1540 },
1541 );
1542 }
1543
1544 #[test]
1545 fn csharp_local_inner_class() {
1546 check_metrics::<CsharpParser>(
1548 "public class A {
1549 public int M(int x) {
1550 int Local(int y) {
1551 if (y > 0) return y;
1552 return -y;
1553 }
1554 return Local(x);
1555 }
1556 }",
1557 "foo.cs",
1558 |metric| {
1559 assert_eq!(metric.wmc.class_wmc_sum(), 3);
1560 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1561 insta::assert_json_snapshot!(metric.wmc);
1562 },
1563 );
1564 }
1565
1566 #[test]
1567 fn csharp_anonymous_inner_class() {
1568 check_metrics::<CsharpParser>(
1569 "public class A {
1570 public void Run() {
1571 System.Action f = delegate(int x) {
1572 if (x > 0) System.Console.WriteLine(x);
1573 };
1574 }
1575 }",
1576 "foo.cs",
1577 |metric| {
1578 assert_eq!(metric.wmc.class_wmc_sum(), 3);
1579 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1580 insta::assert_json_snapshot!(metric.wmc);
1581 },
1582 );
1583 }
1584
1585 #[test]
1586 fn csharp_nested_anonymous_inner_classes() {
1587 check_metrics::<CsharpParser>(
1588 "public class A {
1589 public void Run() {
1590 System.Action f = delegate(int x) {
1591 System.Action g = delegate(int y) {
1592 if (y > 0) System.Console.WriteLine(y);
1593 };
1594 };
1595 }
1596 }",
1597 "foo.cs",
1598 |metric| {
1599 assert_eq!(metric.wmc.class_wmc_sum(), 4);
1600 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1601 insta::assert_json_snapshot!(metric.wmc);
1602 },
1603 );
1604 }
1605
1606 #[test]
1607 fn csharp_lambda_expression() {
1608 check_metrics::<CsharpParser>(
1609 "public class A {
1610 public void Run() {
1611 System.Func<int, int> f = x => x > 0 ? x : -x;
1612 }
1613 }",
1614 "foo.cs",
1615 |metric| {
1616 assert_eq!(metric.wmc.class_wmc_sum(), 3);
1617 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1618 insta::assert_json_snapshot!(metric.wmc);
1619 },
1620 );
1621 }
1622
1623 #[test]
1624 fn csharp_indexer_wmc() {
1625 check_wmc_and_npm::<CsharpParser>(
1631 "class A {
1632 private int[] _d;
1633 public int this[int i] { get => _d[i]; set => _d[i] = value; }
1634 }",
1635 "foo.cs",
1636 |metric| {
1637 assert_eq!(metric.wmc.class_wmc_sum(), 2);
1640 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1641 assert_eq!(metric.npm.class_nm_sum(), 2);
1642 insta::assert_json_snapshot!(metric.wmc);
1643 },
1644 );
1645 }
1646
1647 #[test]
1648 fn csharp_expression_bodied_indexer_wmc() {
1649 check_wmc_and_npm::<CsharpParser>(
1654 "class A {
1655 private int[] _d;
1656 public int this[int i] => _d[i];
1657 }",
1658 "foo.cs",
1659 |metric| {
1660 assert_eq!(metric.wmc.class_wmc_sum(), 1);
1662 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1663 assert_eq!(metric.npm.class_nm_sum(), 1);
1664 insta::assert_json_snapshot!(metric.wmc);
1665 },
1666 );
1667 }
1668
1669 #[test]
1670 fn csharp_property_wmc() {
1671 check_wmc_and_npm::<CsharpParser>(
1676 "class A {
1677 private int _w;
1678 public int W { get => _w; set => _w = value; }
1679 }",
1680 "foo.cs",
1681 |metric| {
1682 assert_eq!(metric.wmc.class_wmc_sum(), 2);
1685 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1686 assert_eq!(metric.npm.class_nm_sum(), 2);
1687 },
1688 );
1689 }
1690
1691 #[test]
1692 fn csharp_expression_bodied_property_wmc() {
1693 check_wmc_and_npm::<CsharpParser>(
1698 "class A {
1699 private int _w;
1700 public int W => _w;
1701 }",
1702 "foo.cs",
1703 |metric| {
1704 assert_eq!(metric.wmc.class_wmc_sum(), 1);
1706 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
1707 assert_eq!(metric.npm.class_nm_sum(), 1);
1708 },
1709 );
1710 }
1711
1712 #[test]
1713 fn csharp_single_interface() {
1714 check_metrics::<CsharpParser>(
1715 "public interface I {
1716 int GetA();
1717 int GetB();
1718 }",
1719 "foo.cs",
1720 |metric| {
1721 assert_eq!(metric.wmc.class_wmc_sum(), 0);
1722 assert_eq!(metric.wmc.interface_wmc_sum(), 2);
1723 insta::assert_json_snapshot!(metric.wmc);
1724 },
1725 );
1726 }
1727
1728 #[test]
1729 fn csharp_multiple_interfaces() {
1730 check_metrics::<CsharpParser>(
1731 "public interface I1 { int GetA(); }
1732 public interface I2 { bool GetB(); float GetC(); }",
1733 "foo.cs",
1734 |metric| {
1735 assert_eq!(metric.wmc.class_wmc_sum(), 0);
1736 assert_eq!(metric.wmc.interface_wmc_sum(), 3);
1737 insta::assert_json_snapshot!(metric.wmc);
1738 },
1739 );
1740 }
1741
1742 #[test]
1743 fn csharp_nested_inner_interfaces() {
1744 check_metrics::<CsharpParser>(
1745 "public interface I1 {
1746 int GetA();
1747 public interface I2 {
1748 bool GetB();
1749 }
1750 }",
1751 "foo.cs",
1752 |metric| {
1753 assert_eq!(metric.wmc.class_wmc_sum(), 0);
1754 assert_eq!(metric.wmc.interface_wmc_sum(), 2);
1755 insta::assert_json_snapshot!(metric.wmc);
1756 },
1757 );
1758 }
1759
1760 #[test]
1761 fn csharp_class_in_interface() {
1762 check_metrics::<CsharpParser>(
1763 "public interface I {
1764 int GetA();
1765 public class Helper {
1766 public int M() { return 0; }
1767 }
1768 }",
1769 "foo.cs",
1770 |metric| {
1771 assert_eq!(metric.wmc.class_wmc_sum(), 1);
1772 assert_eq!(metric.wmc.interface_wmc_sum(), 1);
1773 insta::assert_json_snapshot!(metric.wmc);
1774 },
1775 );
1776 }
1777
1778 #[test]
1779 fn csharp_interface_in_class() {
1780 check_metrics::<CsharpParser>(
1781 "class Outer {
1782 int a;
1783 bool b;
1784 public int GetA() { return a; }
1785 public bool GetB() { return b; }
1786 public interface InnerI {
1787 float GetC();
1788 double GetD();
1789 }
1790 }",
1791 "foo.cs",
1792 |metric| {
1793 assert_eq!(metric.wmc.class_wmc_sum(), 2);
1794 assert_eq!(metric.wmc.interface_wmc_sum(), 2);
1795 insta::assert_json_snapshot!(metric.wmc);
1796 },
1797 );
1798 }
1799
1800 #[test]
1801 fn php_no_classes() {
1802 check_metrics::<PhpParser>(
1803 "<?php function f(): int { return 1; }",
1804 "foo.php",
1805 |metric| insta::assert_json_snapshot!(metric.wmc),
1806 );
1807 }
1808
1809 #[test]
1810 fn php_one_class_simple() {
1811 check_metrics::<PhpParser>(
1812 "<?php
1813 class A {
1814 public function a(): int { return 1; }
1815 public function b(): int { return 2; }
1816 }",
1817 "foo.php",
1818 |metric| insta::assert_json_snapshot!(metric.wmc),
1819 );
1820 }
1821
1822 #[test]
1823 fn php_one_class_with_loops() {
1824 check_metrics::<PhpParser>(
1825 "<?php
1826 class A {
1827 public function f(int $n): int {
1828 $sum = 0;
1829 for ($i = 0; $i < $n; $i++) {
1830 $sum += $i;
1831 }
1832 return $sum;
1833 }
1834 }",
1835 "foo.php",
1836 |metric| insta::assert_json_snapshot!(metric.wmc),
1837 );
1838 }
1839
1840 #[test]
1841 fn php_one_class_with_branches() {
1842 check_metrics::<PhpParser>(
1843 "<?php
1844 class A {
1845 public function f(int $x): int {
1846 if ($x > 0) {
1847 return 1;
1848 }
1849 if ($x < 0) {
1850 return -1;
1851 }
1852 return 0;
1853 }
1854 }",
1855 "foo.php",
1856 |metric| insta::assert_json_snapshot!(metric.wmc),
1857 );
1858 }
1859
1860 #[test]
1861 fn php_class_with_methods_only() {
1862 check_metrics::<PhpParser>(
1863 "<?php
1864 class A {
1865 public function a(): void {}
1866 public function b(): void {}
1867 public function c(): void {}
1868 }",
1869 "foo.php",
1870 |metric| insta::assert_json_snapshot!(metric.wmc),
1871 );
1872 }
1873
1874 #[test]
1875 fn php_multiple_classes() {
1876 check_metrics::<PhpParser>(
1877 "<?php
1878 class A {
1879 public function f(int $x): int {
1880 if ($x > 0) { return 1; }
1881 return 0;
1882 }
1883 }
1884 class B {
1885 public function g(int $x): int {
1886 return $x;
1887 }
1888 }",
1889 "foo.php",
1890 |metric| insta::assert_json_snapshot!(metric.wmc),
1891 );
1892 }
1893
1894 #[test]
1895 fn php_anonymous_class() {
1896 check_metrics::<PhpParser>(
1897 "<?php
1898 $obj = new class {
1899 public function f(int $x): int {
1900 if ($x > 0) { return 1; }
1901 return 0;
1902 }
1903 };",
1904 "foo.php",
1905 |metric| insta::assert_json_snapshot!(metric.wmc),
1906 );
1907 }
1908
1909 #[test]
1910 fn php_class_with_static_methods() {
1911 check_metrics::<PhpParser>(
1912 "<?php
1913 class A {
1914 public static function f(int $x): int {
1915 if ($x > 0) { return 1; }
1916 return 0;
1917 }
1918 public static function g(): int { return 1; }
1919 }",
1920 "foo.php",
1921 |metric| insta::assert_json_snapshot!(metric.wmc),
1922 );
1923 }
1924
1925 #[test]
1926 fn php_interface_wmc() {
1927 check_metrics::<PhpParser>(
1928 "<?php
1929 interface I {
1930 public function a(): void;
1931 public function b(): int;
1932 }",
1933 "foo.php",
1934 |metric| insta::assert_json_snapshot!(metric.wmc),
1935 );
1936 }
1937
1938 #[test]
1939 fn php_trait_wmc() {
1940 check_metrics::<PhpParser>(
1941 "<?php
1942 trait T {
1943 public function f(int $x): int {
1944 if ($x > 0) { return 1; }
1945 return 0;
1946 }
1947 }",
1948 "foo.php",
1949 |metric| insta::assert_json_snapshot!(metric.wmc),
1950 );
1951 }
1952
1953 #[test]
1954 fn php_enum_with_methods() {
1955 check_metrics::<PhpParser>(
1956 "<?php
1957 enum Color {
1958 case Red;
1959 case Green;
1960 public function label(): string {
1961 return match ($this) {
1962 Color::Red => 'r',
1963 Color::Green => 'g',
1964 };
1965 }
1966 }",
1967 "foo.php",
1968 |metric| insta::assert_json_snapshot!(metric.wmc),
1969 );
1970 }
1971
1972 #[test]
1973 fn php_class_inside_namespace() {
1974 check_metrics::<PhpParser>(
1975 "<?php
1976 namespace App;
1977 class A {
1978 public function f(int $x): int {
1979 if ($x > 0) { return 1; }
1980 return 0;
1981 }
1982 }",
1983 "foo.php",
1984 |metric| insta::assert_json_snapshot!(metric.wmc),
1985 );
1986 }
1987
1988 #[test]
1989 fn php_class_complex() {
1990 check_metrics::<PhpParser>(
1991 "<?php
1992 class Calc {
1993 public function add(int $a, int $b): int {
1994 if ($a > 0 && $b > 0) {
1995 return $a + $b;
1996 }
1997 return 0;
1998 }
1999 public function loop(int $n): int {
2000 $s = 0;
2001 for ($i = 0; $i < $n; $i++) {
2002 if ($i % 2 === 0) { $s += $i; }
2003 }
2004 return $s;
2005 }
2006 }",
2007 "foo.php",
2008 |metric| insta::assert_json_snapshot!(metric.wmc),
2009 );
2010 }
2011
2012 #[test]
2021 fn kotlin_empty_class() {
2022 check_metrics::<KotlinParser>("class Empty {}", "foo.kt", |metric| {
2024 assert_eq!(metric.wmc.class_wmc_sum(), 0);
2025 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2026 insta::assert_json_snapshot!(metric.wmc);
2027 });
2028 }
2029
2030 #[test]
2031 fn kotlin_single_class() {
2032 check_metrics::<KotlinParser>(
2035 "class C {
2036 fun m(x: Int): Int { // +1
2037 if (x > 0) { // +1
2038 return x
2039 }
2040 return when (x) {
2041 0 -> 0 // +1 (WhenEntry)
2042 else -> -x // skipped (else is default)
2043 }
2044 }
2045 }",
2046 "foo.kt",
2047 |metric| {
2048 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2049 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2050 insta::assert_json_snapshot!(metric.wmc);
2051 },
2052 );
2053 }
2054
2055 #[test]
2056 fn kotlin_multiple_classes() {
2057 check_metrics::<KotlinParser>(
2060 "class A {
2061 private var a: Int = 0
2062 constructor(n: Int) { a = n } // +1
2063 fun setA(n: Int) { a = n } // +1
2064 fun getA(): Int = a // +1
2065 }
2066 class B {
2067 private var b: Int = 0
2068 constructor(n: Int) { b = n } // +1
2069 fun getB(): Int = b // +1
2070 }",
2071 "foo.kt",
2072 |metric| {
2073 assert_eq!(metric.wmc.class_wmc_sum(), 5);
2074 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2075 insta::assert_json_snapshot!(metric.wmc);
2076 },
2077 );
2078 }
2079
2080 #[test]
2081 fn kotlin_nested_class() {
2082 check_metrics::<KotlinParser>(
2084 "class Outer {
2085 class Nested {
2086 fun m() { println(\"hi\") } // +1
2087 }
2088 }",
2089 "foo.kt",
2090 |metric| {
2091 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2092 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2093 insta::assert_json_snapshot!(metric.wmc);
2094 },
2095 );
2096 }
2097
2098 #[test]
2099 fn kotlin_inner_class() {
2100 check_metrics::<KotlinParser>(
2103 "class Outer {
2104 fun outerM() {} // +1
2105 inner class Inner {
2106 fun innerM() {} // +1
2107 }
2108 }",
2109 "foo.kt",
2110 |metric| {
2111 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2112 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2113 insta::assert_json_snapshot!(metric.wmc);
2114 },
2115 );
2116 }
2117
2118 #[test]
2119 fn kotlin_data_class() {
2120 check_metrics::<KotlinParser>(
2124 "data class Point(val x: Int, val y: Int) {
2125 fun manhattan(): Int = kotlin.math.abs(x) + kotlin.math.abs(y) // +1
2126 }",
2127 "foo.kt",
2128 |metric| {
2129 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2130 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2131 insta::assert_json_snapshot!(metric.wmc);
2132 },
2133 );
2134 }
2135
2136 #[test]
2137 fn kotlin_object_singleton() {
2138 check_metrics::<KotlinParser>(
2141 "object Util {
2142 fun add(a: Int, b: Int): Int = a + b // +1
2143 fun gtZero(n: Int): Boolean { // +1
2144 return n > 0
2145 }
2146 }",
2147 "foo.kt",
2148 |metric| {
2149 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2150 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2151 insta::assert_json_snapshot!(metric.wmc);
2152 },
2153 );
2154 }
2155
2156 #[test]
2157 fn kotlin_companion_object() {
2158 check_metrics::<KotlinParser>(
2164 "class Holder {
2165 val instance: Int = 1
2166 fun get(): Int = instance // +1
2167 companion object {
2168 val SCALE: Int = 10
2169 fun mk(): Holder = Holder() // +1
2170 }
2171 }",
2172 "foo.kt",
2173 |metric| {
2174 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2175 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2176 insta::assert_json_snapshot!(metric.wmc);
2177 },
2178 );
2179 }
2180
2181 #[test]
2182 fn kotlin_companion_object_opens_class_space() {
2183 check_func_space::<KotlinParser, _>(
2189 "class Holder {
2190 fun get(): Int = 1
2191 companion object Companion {
2192 fun mk(): Holder = Holder()
2193 }
2194 }",
2195 "foo.kt",
2196 |func_space| {
2197 let holder = func_space
2198 .spaces
2199 .iter()
2200 .find(|s| s.name.as_deref() == Some("Holder"))
2201 .expect("expected a child FuncSpace named \"Holder\"");
2202 assert_child_space_kind(holder, "Companion", crate::SpaceKind::Class);
2205 let companion = holder
2206 .spaces
2207 .iter()
2208 .find(|s| s.name.as_deref() == Some("Companion"))
2209 .expect("expected a child FuncSpace named \"Companion\"");
2210 assert_eq!(companion.metrics.wmc.class_wmc_sum(), 1);
2214 assert_eq!(holder.metrics.wmc.class_wmc_sum(), 2);
2215 },
2216 );
2217 }
2218
2219 #[test]
2220 fn kotlin_object_literal_opens_class_space() {
2221 check_func_space::<KotlinParser, _>(
2229 "class Holder {
2230 fun get(): Int {
2231 val r = object : Runnable {
2232 override fun run() {}
2233 fun helper(): Int = 42
2234 }
2235 return 1
2236 }
2237 }",
2238 "foo.kt",
2239 |func_space| {
2240 let holder = func_space
2241 .spaces
2242 .iter()
2243 .find(|s| s.name.as_deref() == Some("Holder"))
2244 .expect("expected a child FuncSpace named \"Holder\"");
2245 let get = holder
2246 .spaces
2247 .iter()
2248 .find(|s| s.name.as_deref() == Some("get"))
2249 .expect("expected a child FuncSpace named \"get\"");
2250 assert_child_space_kind(get, "<anonymous>", crate::SpaceKind::Class);
2253 let anon = get
2254 .spaces
2255 .iter()
2256 .find(|s| s.name.as_deref() == Some("<anonymous>"))
2257 .expect("expected a child FuncSpace named \"<anonymous>\"");
2258 assert_eq!(
2263 get.spaces.len(),
2264 1,
2265 "get's only child is the anonymous class"
2266 );
2267 let anon_methods = anon
2268 .spaces
2269 .iter()
2270 .filter(|s| s.kind == crate::SpaceKind::Function)
2271 .count();
2272 assert_eq!(
2273 anon_methods, 2,
2274 "run + helper attributed to the anonymous class"
2275 );
2276 assert_eq!(
2281 get.metrics.nom.functions(),
2282 1,
2283 "get owns only itself; run/helper are not folded in"
2284 );
2285 assert_eq!(anon.metrics.wmc.class_wmc_sum(), 2);
2289 },
2290 );
2291 }
2292
2293 #[test]
2294 fn java_anonymous_class_opens_space() {
2295 check_func_space::<JavaParser, _>(
2303 "class C {
2304 void m() {
2305 Runnable r = new Runnable() {
2306 public void run() {}
2307 };
2308 Object o = new Object();
2309 Runnable l = () -> {};
2310 }
2311 }",
2312 "C.java",
2313 |func_space| {
2314 let c = func_space
2315 .spaces
2316 .iter()
2317 .find(|s| s.name.as_deref() == Some("C"))
2318 .expect("expected a child FuncSpace named \"C\"");
2319 let m = c
2320 .spaces
2321 .iter()
2322 .find(|s| s.name.as_deref() == Some("m"))
2323 .expect("expected a child FuncSpace named \"m\"");
2324 let anon_classes: Vec<_> = m
2329 .spaces
2330 .iter()
2331 .filter(|s| s.kind == crate::SpaceKind::Class)
2332 .collect();
2333 assert_eq!(anon_classes.len(), 1, "exactly one anonymous Class space");
2334 assert_eq!(anon_classes[0].name.as_deref(), Some("<anonymous>"));
2335 let anon_methods = anon_classes[0]
2338 .spaces
2339 .iter()
2340 .filter(|s| s.kind == crate::SpaceKind::Function)
2341 .count();
2342 assert_eq!(anon_methods, 1, "run attributed to the anonymous class");
2343 assert_eq!(anon_classes[0].metrics.wmc.class_wmc_sum(), 1);
2344 },
2345 );
2346 }
2347
2348 #[test]
2349 fn java_lambda_opens_no_class_space() {
2350 check_func_space::<JavaParser, _>(
2355 "class C {
2356 void m() {
2357 Runnable l = () -> { int x = 1; };
2358 }
2359 }",
2360 "C.java",
2361 |func_space| {
2362 let c = func_space
2363 .spaces
2364 .iter()
2365 .find(|s| s.name.as_deref() == Some("C"))
2366 .expect("expected a child FuncSpace named \"C\"");
2367 let m = c
2368 .spaces
2369 .iter()
2370 .find(|s| s.name.as_deref() == Some("m"))
2371 .expect("expected a child FuncSpace named \"m\"");
2372 let class_children = m
2373 .spaces
2374 .iter()
2375 .filter(|s| s.kind == crate::SpaceKind::Class)
2376 .count();
2377 assert_eq!(class_children, 0, "a lambda must not open a Class space");
2378 },
2379 );
2380 }
2381
2382 #[test]
2383 fn groovy_anonymous_class_models_body_as_closure() {
2384 check_func_space::<GroovyParser, _>(
2396 "class C {
2397 void m() {
2398 def r = new Runnable() {
2399 void run() {}
2400 }
2401 }
2402 }",
2403 "C.groovy",
2404 |func_space| {
2405 let c = func_space
2406 .spaces
2407 .iter()
2408 .find(|s| s.name.as_deref() == Some("C"))
2409 .expect("expected a child FuncSpace named \"C\"");
2410 let m = c
2411 .spaces
2412 .iter()
2413 .find(|s| s.name.as_deref() == Some("m"))
2414 .expect("expected a child FuncSpace named \"m\"");
2415 let class_children = m
2418 .spaces
2419 .iter()
2420 .filter(|s| s.kind == crate::SpaceKind::Class)
2421 .count();
2422 assert_eq!(
2423 class_children, 0,
2424 "Groovy grammar models the body as a closure, not a class"
2425 );
2426 assert_eq!(m.metrics.nom.functions(), 1, "`m` itself, not `run`");
2427 let nested_funcs: u64 = m.spaces.iter().map(|s| s.metrics.nom.functions()).sum();
2428 assert_eq!(
2429 nested_funcs, 1,
2430 "`run` is attributed to the nested closure space"
2431 );
2432 },
2433 );
2434 }
2435
2436 #[test]
2437 fn kotlin_interface_simple() {
2438 check_metrics::<KotlinParser>(
2440 "interface I {
2441 fun work(): Int // +1
2442 fun describe(): String // +1
2443 }",
2444 "foo.kt",
2445 |metric| {
2446 assert_eq!(metric.wmc.class_wmc_sum(), 0);
2447 assert_eq!(metric.wmc.interface_wmc_sum(), 2);
2448 insta::assert_json_snapshot!(metric.wmc);
2449 },
2450 );
2451 }
2452
2453 #[test]
2454 fn kotlin_interface_with_default_method() {
2455 check_metrics::<KotlinParser>(
2457 "interface I {
2458 fun abs(n: Int): Int { // +1
2459 return if (n < 0) -n else n // +1 if
2460 }
2461 fun pure(): Int // +1
2462 }",
2463 "foo.kt",
2464 |metric| {
2465 assert_eq!(metric.wmc.class_wmc_sum(), 0);
2466 assert_eq!(metric.wmc.interface_wmc_sum(), 3);
2467 insta::assert_json_snapshot!(metric.wmc);
2468 },
2469 );
2470 }
2471
2472 #[test]
2473 fn kotlin_override_function() {
2474 check_metrics::<KotlinParser>(
2477 "open class Base {
2478 open fun greet(): String = \"hi\" // +1
2479 }
2480 class Sub : Base() {
2481 override fun greet(): String = \"yo\" // +1
2482 }",
2483 "foo.kt",
2484 |metric| {
2485 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2486 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2487 insta::assert_json_snapshot!(metric.wmc);
2488 },
2489 );
2490 }
2491
2492 #[test]
2493 fn kotlin_secondary_constructor() {
2494 check_metrics::<KotlinParser>(
2497 "class C {
2498 private var a: Int = 0
2499 constructor(n: Int) { // +1
2500 a = n
2501 }
2502 constructor(n: Int, m: Int) { // +1
2503 a = n + m
2504 }
2505 fun get(): Int = a // +1
2506 }",
2507 "foo.kt",
2508 |metric| {
2509 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2510 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2511 insta::assert_json_snapshot!(metric.wmc);
2512 },
2513 );
2514 }
2515
2516 #[test]
2517 fn kotlin_init_block() {
2518 check_metrics::<KotlinParser>(
2530 "class C(val n: Int) {
2531 init { // +1 since #1184
2532 require(n >= 0) { \"n must be non-negative\" }
2533 }
2534 fun get(): Int = n // +1
2535 }",
2536 "foo.kt",
2537 |metric| {
2538 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2539 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2540 insta::assert_json_snapshot!(metric.wmc);
2541 },
2542 );
2543 }
2544
2545 #[test]
2546 fn kotlin_top_level_function_excluded() {
2547 check_metrics::<KotlinParser>(
2550 "fun freeFunction(): Int = 42
2551 val freeVal: Int = 0
2552 class C { fun m(): Int = 1 } // +1
2553 ",
2554 "foo.kt",
2555 |metric| {
2556 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2557 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2558 insta::assert_json_snapshot!(metric.wmc);
2559 },
2560 );
2561 }
2562
2563 #[test]
2564 fn kotlin_extension_function_excluded() {
2565 check_metrics::<KotlinParser>(
2570 "fun List<Int>.sum2(): Int = this.size // top-level
2571 class C { fun m(): Int = 1 } // +1
2572 ",
2573 "foo.kt",
2574 |metric| {
2575 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2576 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2577 insta::assert_json_snapshot!(metric.wmc);
2578 },
2579 );
2580 }
2581
2582 #[test]
2583 fn kotlin_generic_class() {
2584 check_metrics::<KotlinParser>(
2586 "class Box<T>(val value: T) {
2587 fun get(): T = value // +1
2588 fun mapTo(f: (T) -> T): T = f(value) // +1
2589 }",
2590 "foo.kt",
2591 |metric| {
2592 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2593 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2594 insta::assert_json_snapshot!(metric.wmc);
2595 },
2596 );
2597 }
2598
2599 #[test]
2600 fn kotlin_class_in_interface() {
2601 check_metrics::<KotlinParser>(
2605 "interface Outer {
2606 fun work(): Int // +1 (interface)
2607 class Helper {
2608 fun help(): Int = 0 // +1 (class)
2609 }
2610 }",
2611 "foo.kt",
2612 |metric| {
2613 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2614 assert_eq!(metric.wmc.interface_wmc_sum(), 1);
2615 insta::assert_json_snapshot!(metric.wmc);
2616 },
2617 );
2618 }
2619
2620 #[test]
2621 fn kotlin_interface_in_class() {
2622 check_metrics::<KotlinParser>(
2624 "class Outer {
2625 fun work(): Int = 1 // +1 (class)
2626 interface Sub {
2627 fun help(): Int // +1 (interface)
2628 }
2629 }",
2630 "foo.kt",
2631 |metric| {
2632 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2633 assert_eq!(metric.wmc.interface_wmc_sum(), 1);
2634 insta::assert_json_snapshot!(metric.wmc);
2635 },
2636 );
2637 }
2638
2639 #[test]
2647 fn typescript_class_wmc_single_method() {
2648 check_metrics::<TypescriptParser>(
2649 "class C {
2650 m(): number { return 1; } // cyclomatic 1
2651 }",
2652 "foo.ts",
2653 |metric| {
2654 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2655 insta::assert_json_snapshot!(metric.wmc);
2656 },
2657 );
2658 }
2659
2660 #[test]
2661 fn typescript_class_wmc_two_methods() {
2662 check_metrics::<TypescriptParser>(
2663 "class C {
2664 a(): number { return 1; } // +1
2665 b(x: number): number { // +2 (if branch)
2666 if (x > 0) return x;
2667 return 0;
2668 }
2669 }",
2670 "foo.ts",
2671 |metric| {
2672 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2673 insta::assert_json_snapshot!(metric.wmc);
2674 },
2675 );
2676 }
2677
2678 #[test]
2679 fn typescript_class_wmc_with_branches() {
2680 check_metrics::<TypescriptParser>(
2681 "class C {
2682 m(x: number): number {
2683 if (x > 0) { // +1
2684 return 1;
2685 } else if (x < 0) { // +1
2686 return -1;
2687 }
2688 return 0;
2689 } // base 1
2690 }",
2691 "foo.ts",
2692 |metric| {
2693 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2694 insta::assert_json_snapshot!(metric.wmc);
2695 },
2696 );
2697 }
2698
2699 #[test]
2700 fn typescript_class_wmc_arrow_field() {
2701 check_metrics::<TypescriptParser>(
2704 "class C {
2705 arrow = (x: number) => {
2706 if (x > 0) return x; // +1
2707 return 0;
2708 }; // base 1
2709 }",
2710 "foo.ts",
2711 |metric| {
2712 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2713 insta::assert_json_snapshot!(metric.wmc);
2714 },
2715 );
2716 }
2717
2718 #[test]
2719 fn typescript_class_wmc_with_loops() {
2720 check_metrics::<TypescriptParser>(
2721 "class C {
2722 m(xs: number[]): number {
2723 let total = 0;
2724 for (const x of xs) { // +1
2725 total += x;
2726 }
2727 return total;
2728 } // base 1
2729 }",
2730 "foo.ts",
2731 |metric| {
2732 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2733 insta::assert_json_snapshot!(metric.wmc);
2734 },
2735 );
2736 }
2737
2738 #[test]
2739 fn typescript_abstract_class_wmc() {
2740 check_metrics::<TypescriptParser>(
2742 "abstract class C {
2743 abstract a(): void; // signature only, 0
2744 m(): number { return 1; } // +1
2745 }",
2746 "foo.ts",
2747 |metric| {
2748 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2749 insta::assert_json_snapshot!(metric.wmc);
2750 },
2751 );
2752 }
2753
2754 #[test]
2755 fn typescript_interface_wmc_zero() {
2756 check_metrics::<TypescriptParser>(
2758 "interface I {
2759 a(): void;
2760 b(): number;
2761 }",
2762 "foo.ts",
2763 |metric| {
2764 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2765 assert_eq!(metric.wmc.class_wmc_sum(), 0);
2766 insta::assert_json_snapshot!(metric.wmc);
2767 },
2768 );
2769 }
2770
2771 #[test]
2772 fn typescript_constructor_wmc() {
2773 check_metrics::<TypescriptParser>(
2776 "class C {
2777 x: number;
2778 constructor(n: number) {
2779 if (n > 0) { // +1
2780 this.x = n;
2781 } else {
2782 this.x = 0;
2783 }
2784 } // base 1
2785 }",
2786 "foo.ts",
2787 |metric| {
2788 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2789 insta::assert_json_snapshot!(metric.wmc);
2790 },
2791 );
2792 }
2793
2794 #[test]
2795 fn typescript_getter_setter_wmc() {
2796 check_metrics::<TypescriptParser>(
2798 "class C {
2799 _x: number = 0;
2800 get x(): number { return this._x; }
2801 set x(v: number) { this._x = v; }
2802 }",
2803 "foo.ts",
2804 |metric| {
2805 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2806 insta::assert_json_snapshot!(metric.wmc);
2807 },
2808 );
2809 }
2810
2811 #[test]
2812 fn typescript_multiple_classes_wmc_independent() {
2813 check_metrics::<TypescriptParser>(
2814 "class A { m(): number { return 1; } }
2815 class B {
2816 m(x: number): number {
2817 if (x > 0) return x; // +1
2818 return 0;
2819 } // base 1
2820 }",
2821 "foo.ts",
2822 |metric| {
2823 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2825 insta::assert_json_snapshot!(metric.wmc);
2826 },
2827 );
2828 }
2829
2830 #[test]
2831 fn typescript_class_wmc_with_ternary_and_logical() {
2832 check_metrics::<TypescriptParser>(
2833 "class C {
2834 m(x: number, y: number): number {
2835 return x > 0 && y > 0 // +1 (ternary) +1 (&&)
2836 ? x + y
2837 : 0;
2838 } // base 1
2839 }",
2840 "foo.ts",
2841 |metric| {
2842 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2843 insta::assert_json_snapshot!(metric.wmc);
2844 },
2845 );
2846 }
2847
2848 #[test]
2849 fn typescript_generic_class_wmc() {
2850 check_metrics::<TypescriptParser>(
2851 "class Box<T> {
2852 value: T;
2853 set(v: T): void { this.value = v; }
2854 get(): T { return this.value; }
2855 }",
2856 "foo.ts",
2857 |metric| {
2858 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2859 insta::assert_json_snapshot!(metric.wmc);
2860 },
2861 );
2862 }
2863
2864 #[test]
2867 fn tsx_class_wmc_single_method() {
2868 check_metrics::<TsxParser>(
2869 "class C { m(): number { return 1; } }",
2870 "foo.tsx",
2871 |metric| {
2872 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2873 insta::assert_json_snapshot!(metric.wmc);
2874 },
2875 );
2876 }
2877
2878 #[test]
2879 fn tsx_class_wmc_two_methods() {
2880 check_metrics::<TsxParser>(
2881 "class C {
2882 a(): number { return 1; }
2883 b(x: number): number {
2884 if (x > 0) return x;
2885 return 0;
2886 }
2887 }",
2888 "foo.tsx",
2889 |metric| {
2890 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2891 insta::assert_json_snapshot!(metric.wmc);
2892 },
2893 );
2894 }
2895
2896 #[test]
2897 fn tsx_class_wmc_with_branches() {
2898 check_metrics::<TsxParser>(
2899 "class C {
2900 m(x: number): number {
2901 if (x > 0) return 1;
2902 else if (x < 0) return -1;
2903 return 0;
2904 }
2905 }",
2906 "foo.tsx",
2907 |metric| {
2908 assert_eq!(metric.wmc.class_wmc_sum(), 3);
2909 insta::assert_json_snapshot!(metric.wmc);
2910 },
2911 );
2912 }
2913
2914 #[test]
2915 fn tsx_class_wmc_arrow_field() {
2916 check_metrics::<TsxParser>(
2917 "class C {
2918 arrow = (x: number) => {
2919 if (x > 0) return x;
2920 return 0;
2921 };
2922 }",
2923 "foo.tsx",
2924 |metric| {
2925 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2926 insta::assert_json_snapshot!(metric.wmc);
2927 },
2928 );
2929 }
2930
2931 #[test]
2932 fn tsx_class_wmc_with_loops() {
2933 check_metrics::<TsxParser>(
2934 "class C {
2935 m(xs: number[]): number {
2936 let total = 0;
2937 for (const x of xs) { total += x; }
2938 return total;
2939 }
2940 }",
2941 "foo.tsx",
2942 |metric| {
2943 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2944 insta::assert_json_snapshot!(metric.wmc);
2945 },
2946 );
2947 }
2948
2949 #[test]
2950 fn tsx_abstract_class_wmc() {
2951 check_metrics::<TsxParser>(
2952 "abstract class C {
2953 abstract a(): void;
2954 m(): number { return 1; }
2955 }",
2956 "foo.tsx",
2957 |metric| {
2958 assert_eq!(metric.wmc.class_wmc_sum(), 1);
2959 insta::assert_json_snapshot!(metric.wmc);
2960 },
2961 );
2962 }
2963
2964 #[test]
2965 fn tsx_interface_wmc_zero() {
2966 check_metrics::<TsxParser>(
2967 "interface I { a(): void; b(): number; }",
2968 "foo.tsx",
2969 |metric| {
2970 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
2971 assert_eq!(metric.wmc.class_wmc_sum(), 0);
2972 insta::assert_json_snapshot!(metric.wmc);
2973 },
2974 );
2975 }
2976
2977 #[test]
2978 fn tsx_constructor_wmc() {
2979 check_metrics::<TsxParser>(
2980 "class C {
2981 x: number;
2982 constructor(n: number) {
2983 if (n > 0) this.x = n;
2984 else this.x = 0;
2985 }
2986 }",
2987 "foo.tsx",
2988 |metric| {
2989 assert_eq!(metric.wmc.class_wmc_sum(), 2);
2990 insta::assert_json_snapshot!(metric.wmc);
2991 },
2992 );
2993 }
2994
2995 #[test]
2996 fn tsx_getter_setter_wmc() {
2997 check_metrics::<TsxParser>(
2998 "class C {
2999 _x: number = 0;
3000 get x(): number { return this._x; }
3001 set x(v: number) { this._x = v; }
3002 }",
3003 "foo.tsx",
3004 |metric| {
3005 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3006 insta::assert_json_snapshot!(metric.wmc);
3007 },
3008 );
3009 }
3010
3011 #[test]
3012 fn tsx_multiple_classes_wmc_independent() {
3013 check_metrics::<TsxParser>(
3014 "class A { m(): number { return 1; } }
3015 class B {
3016 m(x: number): number {
3017 if (x > 0) return x;
3018 return 0;
3019 }
3020 }",
3021 "foo.tsx",
3022 |metric| {
3023 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3024 insta::assert_json_snapshot!(metric.wmc);
3025 },
3026 );
3027 }
3028
3029 #[test]
3030 fn tsx_class_wmc_with_ternary_and_logical() {
3031 check_metrics::<TsxParser>(
3032 "class C {
3033 m(x: number, y: number): number {
3034 return x > 0 && y > 0 ? x + y : 0;
3035 }
3036 }",
3037 "foo.tsx",
3038 |metric| {
3039 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3040 insta::assert_json_snapshot!(metric.wmc);
3041 },
3042 );
3043 }
3044
3045 #[test]
3046 fn tsx_generic_class_wmc() {
3047 check_metrics::<TsxParser>(
3048 "class Box<T> {
3049 value: T;
3050 set(v: T): void { this.value = v; }
3051 get(): T { return this.value; }
3052 }",
3053 "foo.tsx",
3054 |metric| {
3055 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3056 insta::assert_json_snapshot!(metric.wmc);
3057 },
3058 );
3059 }
3060
3061 #[test]
3069 fn ruby_no_classes() {
3070 check_metrics::<RubyParser>("def foo\n 1\nend\n", "foo.rb", |metric| {
3072 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3073 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3074 insta::assert_json_snapshot!(metric.wmc);
3075 });
3076 }
3077
3078 #[test]
3079 fn ruby_empty_class() {
3080 check_metrics::<RubyParser>("class Foo\nend\n", "foo.rb", |metric| {
3082 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3083 insta::assert_json_snapshot!(metric.wmc);
3084 });
3085 }
3086
3087 #[test]
3088 fn ruby_one_class_simple() {
3089 check_metrics::<RubyParser>(
3091 "class A\n def a\n 1\n end\n def b\n 2\n end\nend\n",
3092 "foo.rb",
3093 |metric| {
3094 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3095 insta::assert_json_snapshot!(metric.wmc);
3096 },
3097 );
3098 }
3099
3100 #[test]
3101 fn ruby_one_class_with_branch() {
3102 check_metrics::<RubyParser>(
3104 "class A\n def f(x)\n if x > 0\n 1\n else\n 0\n end\n end\nend\n",
3105 "foo.rb",
3106 |metric| {
3107 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3108 insta::assert_json_snapshot!(metric.wmc);
3109 },
3110 );
3111 }
3112
3113 #[test]
3114 fn ruby_one_class_with_loop() {
3115 check_metrics::<RubyParser>(
3117 "class A\n def f(n)\n while n > 0\n n -= 1\n end\n end\nend\n",
3118 "foo.rb",
3119 |metric| {
3120 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3121 insta::assert_json_snapshot!(metric.wmc);
3122 },
3123 );
3124 }
3125
3126 #[test]
3127 fn ruby_singleton_method_included() {
3128 check_metrics::<RubyParser>(
3131 "class A\n def f\n 1\n end\n def self.g\n 2\n end\nend\n",
3132 "foo.rb",
3133 |metric| {
3134 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3135 insta::assert_json_snapshot!(metric.wmc);
3136 },
3137 );
3138 }
3139
3140 #[test]
3141 fn ruby_singleton_class_methods_included() {
3142 check_metrics::<RubyParser>(
3145 "class A\n class << self\n def s\n 1\n end\n end\nend\n",
3146 "foo.rb",
3147 |metric| {
3148 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3151 insta::assert_json_snapshot!(metric.wmc);
3152 },
3153 );
3154 }
3155
3156 #[test]
3157 fn ruby_multiple_classes() {
3158 check_metrics::<RubyParser>(
3160 "class A\n def f(x)\n if x > 0\n 1\n end\n end\nend\nclass B\n def g\n 1\n end\nend\n",
3161 "foo.rb",
3162 |metric| {
3163 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3165 insta::assert_json_snapshot!(metric.wmc);
3166 },
3167 );
3168 }
3169
3170 #[test]
3171 fn ruby_module_only() {
3172 check_metrics::<RubyParser>(
3175 "module M\n def f\n 1\n end\nend\n",
3176 "foo.rb",
3177 |metric| {
3178 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3179 insta::assert_json_snapshot!(metric.wmc);
3180 },
3181 );
3182 }
3183
3184 #[test]
3185 fn ruby_class_with_inheritance() {
3186 check_metrics::<RubyParser>(
3189 "class A < B\n def f\n 1\n end\n def g\n 2\n end\nend\n",
3190 "foo.rb",
3191 |metric| {
3192 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3193 insta::assert_json_snapshot!(metric.wmc);
3194 },
3195 );
3196 }
3197
3198 #[test]
3199 fn ruby_class_with_visibility_keywords() {
3200 check_metrics::<RubyParser>(
3203 "class A\n def a\n 1\n end\n private\n def b\n 1\n end\n protected\n def c\n 1\n end\nend\n",
3204 "foo.rb",
3205 |metric| {
3206 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3207 insta::assert_json_snapshot!(metric.wmc);
3208 },
3209 );
3210 }
3211
3212 #[test]
3213 fn ruby_class_complex() {
3214 check_metrics::<RubyParser>(
3219 "class Calc\n def add(a, b)\n if a > 0 && b > 0\n a + b\n end\n end\n def loop(n)\n s = 0\n while n > 0\n if n.even?\n s += n\n end\n n -= 1\n end\n s\n end\nend\n",
3220 "foo.rb",
3221 |metric| {
3222 assert_eq!(metric.wmc.class_wmc_sum(), 6);
3223 insta::assert_json_snapshot!(metric.wmc);
3224 },
3225 );
3226 }
3227
3228 #[test]
3240 fn python_empty_class_zero_wmc() {
3241 check_metrics::<PythonParser>("class C:\n pass\n", "foo.py", |metric| {
3242 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3243 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3244 insta::assert_json_snapshot!(metric.wmc);
3245 });
3246 }
3247
3248 #[test]
3249 fn python_single_method_wmc_one() {
3250 check_metrics::<PythonParser>(
3252 "class C:\n def m(self):\n return 1\n",
3253 "foo.py",
3254 |metric| {
3255 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3256 insta::assert_json_snapshot!(metric.wmc);
3257 },
3258 );
3259 }
3260
3261 #[test]
3262 fn python_method_with_if_adds_to_wmc() {
3263 check_metrics::<PythonParser>(
3265 "class C:\n def m(self, x):\n if x > 0:\n return 1\n return 0\n",
3266 "foo.py",
3267 |metric| {
3268 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3269 insta::assert_json_snapshot!(metric.wmc);
3270 },
3271 );
3272 }
3273
3274 #[test]
3275 fn python_multiple_methods_wmc_sums() {
3276 check_metrics::<PythonParser>(
3279 "class C:\n\
3280 \x20 def m1(self):\n\
3281 \x20 return 1\n\
3282 \x20 def m2(self, x):\n\
3283 \x20 if x:\n\
3284 \x20 return 1\n\
3285 \x20 return 0\n\
3286 \x20 def m3(self, xs):\n\
3287 \x20 for x in xs:\n\
3288 \x20 if x:\n\
3289 \x20 return x\n\
3290 \x20 return None\n",
3291 "foo.py",
3292 |metric| {
3293 assert_eq!(metric.wmc.class_wmc_sum(), 6);
3294 insta::assert_json_snapshot!(metric.wmc);
3295 },
3296 );
3297 }
3298
3299 #[test]
3300 fn python_top_level_function_does_not_contribute_to_class_wmc() {
3301 check_metrics::<PythonParser>(
3304 "def f(x):\n if x:\n return 1\n return 0\n",
3305 "foo.py",
3306 |metric| {
3307 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3308 insta::assert_json_snapshot!(metric.wmc);
3309 },
3310 );
3311 }
3312
3313 #[test]
3314 fn python_multiple_classes_wmc_independent() {
3315 check_metrics::<PythonParser>(
3319 "class A:\n\
3320 \x20 def m1(self):\n\
3321 \x20 return 1\n\
3322 class B:\n\
3323 \x20 def m2(self, x):\n\
3324 \x20 if x:\n\
3325 \x20 return 1\n\
3326 \x20 return 0\n",
3327 "foo.py",
3328 |metric| {
3329 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3330 insta::assert_json_snapshot!(metric.wmc);
3331 },
3332 );
3333 }
3334
3335 #[test]
3336 fn rust_empty_unit_zero_wmc() {
3337 check_metrics::<RustParser>("", "empty.rs", |metric| {
3338 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3339 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3340 insta::assert_json_snapshot!(metric.wmc);
3341 });
3342 }
3343
3344 #[test]
3345 fn rust_single_impl_method_wmc_one() {
3346 check_metrics::<RustParser>(
3348 "struct Foo;\nimpl Foo { fn m(&self) -> i32 { 1 } }\n",
3349 "foo.rs",
3350 |metric| {
3351 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3352 insta::assert_json_snapshot!(metric.wmc);
3353 },
3354 );
3355 }
3356
3357 #[test]
3358 fn rust_method_with_if_adds_to_wmc() {
3359 check_metrics::<RustParser>(
3361 "struct Foo;\n\
3362 impl Foo {\n\
3363 \x20 fn m(&self, x: i32) -> i32 {\n\
3364 \x20 if x > 0 { 1 } else { 0 }\n\
3365 \x20 }\n\
3366 }\n",
3367 "foo.rs",
3368 |metric| {
3369 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3370 insta::assert_json_snapshot!(metric.wmc);
3371 },
3372 );
3373 }
3374
3375 #[test]
3376 fn rust_multiple_methods_wmc_sums() {
3377 check_metrics::<RustParser>(
3380 "struct Foo;\n\
3381 impl Foo {\n\
3382 \x20 fn m1(&self) -> i32 { 1 }\n\
3383 \x20 fn m2(&self, x: i32) -> i32 { if x > 0 { 1 } else { 0 } }\n\
3384 \x20 fn m3(&self, xs: &[i32]) -> i32 {\n\
3385 \x20 for x in xs { if *x > 0 { return *x; } }\n\
3386 \x20 0\n\
3387 \x20 }\n\
3388 }\n",
3389 "foo.rs",
3390 |metric| {
3391 assert_eq!(metric.wmc.class_wmc_sum(), 6);
3392 insta::assert_json_snapshot!(metric.wmc);
3393 },
3394 );
3395 }
3396
3397 #[test]
3398 fn rust_multiple_impls_wmc_aggregate() {
3399 check_metrics::<RustParser>(
3402 "struct Foo;\n\
3403 impl Foo { fn m1(&self) {} }\n\
3404 impl Foo { fn m2(&self) {} }\n",
3405 "foo.rs",
3406 |metric| {
3407 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3408 insta::assert_json_snapshot!(metric.wmc);
3409 },
3410 );
3411 }
3412
3413 #[test]
3414 fn rust_trait_default_method_contributes_to_interface_wmc() {
3415 check_metrics::<RustParser>(
3420 "trait T { fn draw(&self); fn area(&self) -> f64 { 0.0 } }",
3421 "foo.rs",
3422 |metric| {
3423 assert_eq!(metric.wmc.interface_wmc_sum(), 1);
3424 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3425 insta::assert_json_snapshot!(metric.wmc);
3426 },
3427 );
3428 }
3429
3430 #[test]
3431 fn rust_top_level_function_does_not_contribute_to_class_wmc() {
3432 check_metrics::<RustParser>(
3436 "fn f(x: i32) -> i32 { if x > 0 { 1 } else { 0 } }",
3437 "foo.rs",
3438 |metric| {
3439 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3440 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3441 insta::assert_json_snapshot!(metric.wmc);
3442 },
3443 );
3444 }
3445
3446 #[test]
3449 fn go_wmc_is_zero_documented_limitation() {
3450 check_metrics::<GoParser>(
3460 "package main\n\
3461 type Foo struct{}\n\
3462 func (f Foo) M(x int) int { if x > 0 { return 1 } else { return 0 } }\n\
3463 func (f Foo) N() {}\n",
3464 "foo.go",
3465 |metric| {
3466 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3467 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3468 insta::assert_json_snapshot!(metric.wmc);
3469 },
3470 );
3471 }
3472
3473 #[test]
3482 fn elixir_wmc_aggregates_def_methods() {
3483 check_metrics::<ElixirParser>(
3484 "defmodule Foo do\n def m(x) do\n if x > 0 do\n 1\n else\n 0\n end\n end\n def n, do: :ok\nend\n",
3485 "foo.ex",
3486 |metric| {
3487 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3489 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3490 insta::assert_json_snapshot!(
3491 metric.wmc,
3492 @r#"
3493 {
3494 "class_wmc_sum": 3,
3495 "interface_wmc_sum": 0,
3496 "total": 3
3497 }
3498 "#
3499 );
3500 },
3501 );
3502 }
3503
3504 #[test]
3505 fn elixir_wmc_def_plus_defp_counts_both() {
3506 check_metrics::<ElixirParser>(
3507 "defmodule Foo do\n def pub_one, do: 1\n defp priv_one, do: 1\nend\n",
3508 "foo.ex",
3509 |metric| {
3510 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3513 },
3514 );
3515 }
3516
3517 #[test]
3518 fn elixir_wmc_defmacro_counts() {
3519 check_metrics::<ElixirParser>(
3520 "defmodule Foo do\n defmacro stuff(x) do\n if x > 0, do: :pos, else: :neg\n end\nend\n",
3521 "foo.ex",
3522 |metric| {
3523 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3525 },
3526 );
3527 }
3528
3529 #[test]
3530 fn elixir_wmc_multiple_clauses_each_a_method() {
3531 check_metrics::<ElixirParser>(
3534 "defmodule Foo do\n def f(0), do: :zero\n def f(_), do: :other\nend\n",
3535 "foo.ex",
3536 |metric| {
3537 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3539 },
3540 );
3541 }
3542
3543 #[test]
3544 fn elixir_wmc_nested_defmodule_isolates() {
3545 check_metrics::<ElixirParser>(
3546 "defmodule Outer do\n def o, do: 1\n defmodule Inner do\n def i, do: 1\n end\nend\n",
3547 "foo.ex",
3548 |metric| {
3549 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3551 },
3552 );
3553 }
3554
3555 #[test]
3556 fn elixir_wmc_user_macro_not_classified_as_method() {
3557 check_metrics::<ElixirParser>(
3567 "defmodule Foo do\n defmacro custom_def(name, body) do\n quote do\n def unquote(name), do: unquote(body)\n end\n end\n custom_def foo, do: 1\nend\n",
3568 "foo.ex",
3569 |metric| {
3570 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3573 },
3574 );
3575 }
3576
3577 #[test]
3578 fn elixir_wmc_quoted_defs_do_not_inflate_method_count() {
3579 check_metrics::<ElixirParser>(
3590 "defmodule Foo do\n defmacro multi do\n quote do\n def a, do: 1\n def b, do: 2\n defp c, do: 3\n end\n end\nend\n",
3591 "foo.ex",
3592 |metric| {
3593 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3596 },
3597 );
3598 }
3599
3600 #[test]
3603 fn objc_wmc() {
3604 check_metrics::<ObjcParser>(
3611 "@interface Foo : NSObject\n\
3612 - (int)a:(int)x;\n\
3613 @end\n\
3614 @implementation Foo\n\
3615 - (int)a:(int)x { if (x > 0) { return 1; } return 0; }\n\
3616 - (void)b { }\n\
3617 @end\n",
3618 "foo.m",
3619 |metric| {
3620 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3621 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3622 },
3623 );
3624 }
3625
3626 #[test]
3629 fn cpp_empty_unit_zero_wmc() {
3630 check_metrics::<CppParser>("", "empty.cpp", |metric| {
3632 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3633 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3634 insta::assert_json_snapshot!(metric.wmc);
3635 });
3636 }
3637
3638 #[test]
3639 fn cpp_single_method_wmc_one() {
3640 check_metrics::<CppParser>("class Foo { public: void m() {} };", "foo.cpp", |metric| {
3642 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3643 insta::assert_json_snapshot!(metric.wmc);
3644 });
3645 }
3646
3647 #[test]
3648 fn cpp_method_with_if_adds_to_wmc() {
3649 check_metrics::<CppParser>(
3651 "class Foo {\n\
3652 public:\n\
3653 int m(int x) {\n\
3654 if (x > 0) { return 1; }\n\
3655 return 0;\n\
3656 }\n\
3657 };",
3658 "foo.cpp",
3659 |metric| {
3660 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3661 insta::assert_json_snapshot!(metric.wmc);
3662 },
3663 );
3664 }
3665
3666 #[test]
3667 fn cpp_struct_wmc_maps_to_class() {
3668 check_metrics::<CppParser>(
3672 "struct Foo {\n\
3673 int m(int x) {\n\
3674 if (x > 0) { return 1; }\n\
3675 return 0;\n\
3676 }\n\
3677 };",
3678 "foo.cpp",
3679 |metric| {
3680 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3681 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3682 insta::assert_json_snapshot!(metric.wmc);
3683 },
3684 );
3685 }
3686
3687 #[test]
3688 fn cpp_free_function_does_not_contribute_to_class_wmc() {
3689 check_metrics::<CppParser>(
3695 "int free_fn(int x) { if (x > 0) { return 1; } return 0; }",
3696 "foo.cpp",
3697 |metric| {
3698 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3699 assert_eq!(metric.wmc.interface_wmc_sum(), 0);
3700 insta::assert_json_snapshot!(metric.wmc);
3701 },
3702 );
3703 }
3704
3705 #[test]
3706 fn cpp_multiple_methods_wmc_sums() {
3707 check_metrics::<CppParser>(
3710 "class Foo {\n\
3711 public:\n\
3712 int a(int x) { if (x > 0) { return 1; } return 0; }\n\
3713 int b() { return 42; }\n\
3714 };",
3715 "foo.cpp",
3716 |metric| {
3717 assert_eq!(metric.wmc.class_wmc_sum(), 3);
3718 insta::assert_json_snapshot!(metric.wmc);
3719 },
3720 );
3721 }
3722
3723 #[test]
3724 fn cpp_multiple_classes_wmc_aggregate() {
3725 check_metrics::<CppParser>(
3728 "class Foo { public: void a() {} };\nstruct Bar { void b() {} };",
3729 "foo.cpp",
3730 |metric| {
3731 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3732 insta::assert_json_snapshot!(metric.wmc);
3733 },
3734 );
3735 }
3736
3737 #[test]
3738 fn javascript_empty_unit_zero_wmc() {
3739 check_metrics::<JavascriptParser>("", "empty.js", |metric| {
3740 assert_eq!(metric.wmc.class_wmc_sum(), 0);
3741 insta::assert_json_snapshot!(metric.wmc);
3742 });
3743 }
3744
3745 #[test]
3746 fn javascript_single_method_wmc_one() {
3747 check_metrics::<JavascriptParser>("class Foo { a() { return 1; } }", "foo.js", |metric| {
3750 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3751 insta::assert_json_snapshot!(metric.wmc);
3752 });
3753 }
3754
3755 #[test]
3756 fn javascript_method_with_if_adds_to_wmc() {
3757 check_metrics::<JavascriptParser>(
3759 "class Foo { a(x) { if (x > 0) return 1; return 0; } }",
3760 "foo.js",
3761 |metric| {
3762 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3763 insta::assert_json_snapshot!(metric.wmc);
3764 },
3765 );
3766 }
3767
3768 #[test]
3769 fn javascript_free_function_does_not_contribute_to_class_wmc() {
3770 check_metrics::<JavascriptParser>(
3773 "function f(x) { if (x > 0) return 1; return 0; }\nclass Foo { a() { return 1; } }",
3774 "foo.js",
3775 |metric| {
3776 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3778 insta::assert_json_snapshot!(metric.wmc);
3779 },
3780 );
3781 }
3782
3783 #[test]
3784 fn javascript_multiple_classes_wmc_aggregate() {
3785 check_metrics::<JavascriptParser>(
3788 "class Foo { a() { return 1; } }\nclass Bar { b() { return 1; } }",
3789 "foo.js",
3790 |metric| {
3791 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3792 insta::assert_json_snapshot!(metric.wmc);
3793 },
3794 );
3795 }
3796
3797 #[test]
3798 fn mozjs_single_method_wmc_one() {
3799 check_metrics::<MozjsParser>("class Foo { a() { return 1; } }", "foo.js", |metric| {
3800 assert_eq!(metric.wmc.class_wmc_sum(), 1);
3801 insta::assert_json_snapshot!(metric.wmc);
3802 });
3803 }
3804
3805 #[test]
3812 fn java_method_with_nested_class_wmc_is_non_negative_integer() {
3813 check_metrics::<JavaParser>(
3814 "public class Outer {
3815 public void m() {
3816 class Inner {
3817 public void n() {}
3818 }
3819 }
3820 }",
3821 "Outer.java",
3822 |metric| {
3823 let total = metric.wmc.class_wmc_sum();
3824 assert_eq!(total, 2, "Outer.m (1) + Inner.n (1) with no double-count");
3825 },
3826 );
3827 }
3828
3829 #[test]
3833 fn stats_display_and_per_space_accessors() {
3834 check_func_space::<JavaParser, _>(
3835 "public interface I {\n void p();\n}\n\
3836 public class C {\n public void m() {}\n private void n() {}\n}\n",
3837 "X.java",
3838 |unit| {
3839 assert_eq!(unit.metrics.wmc.class_wmc_sum(), 2);
3841 assert_eq!(unit.metrics.wmc.interface_wmc_sum(), 1);
3842 assert_eq!(
3843 unit.metrics.wmc.to_string(),
3844 "classes: 2, interfaces: 1, total: 3"
3845 );
3846 let class = child_space(&unit, "C");
3851 assert_eq!(class.kind, SpaceKind::Class);
3852 assert_eq!(class.metrics.wmc.class_wmc(), 2);
3853 let iface = child_space(&unit, "I");
3854 assert_eq!(iface.kind, SpaceKind::Interface);
3855 assert_eq!(iface.metrics.wmc.interface_wmc(), 1);
3856 },
3857 );
3858 }
3859}