1#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
8
9use serde::Serialize;
10use serde::ser::{SerializeStruct, Serializer};
11use std::fmt;
12
13use crate::checker::Checker;
14use crate::macros::implement_metric_trait;
15use crate::*;
16
17#[derive(Debug, Clone, Default)]
25pub struct Stats {
26 cyclomatic: f64,
27 class_wmc: f64,
28 interface_wmc: f64,
29 class_wmc_sum: f64,
30 interface_wmc_sum: f64,
31 space_kind: SpaceKind,
32}
33
34impl Serialize for Stats {
35 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36 where
37 S: Serializer,
38 {
39 let mut st = serializer.serialize_struct("wmc", 3)?;
40 st.serialize_field("classes", &self.class_wmc_sum())?;
41 st.serialize_field("interfaces", &self.interface_wmc_sum())?;
42 st.serialize_field("total", &self.total_wmc())?;
43 st.end()
44 }
45}
46
47impl fmt::Display for Stats {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 write!(
50 f,
51 "classes: {}, interfaces: {}, total: {}",
52 self.class_wmc_sum(),
53 self.interface_wmc_sum(),
54 self.total_wmc()
55 )
56 }
57}
58
59impl Stats {
60 pub fn merge(&mut self, other: &Stats) {
62 use SpaceKind::*;
63
64 if let Function = other.space_kind {
67 match self.space_kind {
68 Class => self.class_wmc += other.cyclomatic,
69 Interface => self.interface_wmc += other.cyclomatic,
70 _ => {}
71 }
72 }
73
74 self.class_wmc_sum += other.class_wmc_sum;
75 self.interface_wmc_sum += other.interface_wmc_sum;
76 }
77
78 #[inline]
80 #[must_use]
81 pub fn class_wmc(&self) -> f64 {
82 self.class_wmc
83 }
84
85 #[inline]
87 #[must_use]
88 pub fn interface_wmc(&self) -> f64 {
89 self.interface_wmc
90 }
91
92 #[inline]
94 #[must_use]
95 pub fn class_wmc_sum(&self) -> f64 {
96 self.class_wmc_sum
97 }
98
99 #[inline]
101 #[must_use]
102 pub fn interface_wmc_sum(&self) -> f64 {
103 self.interface_wmc_sum
104 }
105
106 #[inline]
108 #[must_use]
109 pub fn total_wmc(&self) -> f64 {
110 self.class_wmc_sum() + self.interface_wmc_sum()
111 }
112
113 #[inline]
116 pub(crate) fn compute_sum(&mut self) {
117 self.class_wmc_sum += self.class_wmc;
118 self.interface_wmc_sum += self.interface_wmc;
119 }
120
121 #[inline]
123 pub(crate) fn is_disabled(&self) -> bool {
124 matches!(self.space_kind, SpaceKind::Function | SpaceKind::Unknown)
125 }
126}
127
128#[doc(hidden)]
129pub trait Wmc
131where
132 Self: Checker,
133{
134 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats);
137}
138
139fn class_interface_compute(
144 space_kind: SpaceKind,
145 cyclomatic: &cyclomatic::Stats,
146 stats: &mut Stats,
147) {
148 use SpaceKind::*;
149
150 if let Unit | Class | Interface | Function = space_kind {
151 if stats.space_kind == Unknown {
152 stats.space_kind = space_kind;
153 }
154 if space_kind == Function {
155 stats.cyclomatic = cyclomatic.cyclomatic_sum();
156 }
157 }
158}
159
160impl Wmc for JavaCode {
161 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
162 class_interface_compute(space_kind, cyclomatic, stats);
163 }
164}
165
166impl Wmc for GroovyCode {
167 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
168 class_interface_compute(space_kind, cyclomatic, stats);
169 }
170}
171
172impl Wmc for CsharpCode {
173 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
174 class_interface_compute(space_kind, cyclomatic, stats);
175 }
176}
177
178impl Wmc for KotlinCode {
186 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
187 class_interface_compute(space_kind, cyclomatic, stats);
188 }
189}
190
191impl Wmc for PhpCode {
192 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
193 use SpaceKind::*;
194
195 if let Unit | Class | Interface | Function = space_kind {
198 if stats.space_kind == Unknown {
199 stats.space_kind = space_kind;
200 }
201 if space_kind == Function {
202 stats.cyclomatic = cyclomatic.cyclomatic_sum();
203 }
204 }
205 }
206}
207
208impl Wmc for PythonCode {
222 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
223 class_interface_compute(space_kind, cyclomatic, stats);
224 }
225}
226
227impl Wmc for RustCode {
246 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
247 let mapped = match space_kind {
248 SpaceKind::Impl => SpaceKind::Class,
249 SpaceKind::Trait => SpaceKind::Interface,
250 other => other,
251 };
252 class_interface_compute(mapped, cyclomatic, stats);
253 }
254}
255
256impl Wmc for CppCode {
268 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
269 let mapped = match space_kind {
270 SpaceKind::Struct => SpaceKind::Class,
271 other => other,
272 };
273 class_interface_compute(mapped, cyclomatic, stats);
274 }
275}
276
277impl Wmc for TypescriptCode {
286 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
287 class_interface_compute(space_kind, cyclomatic, stats);
288 }
289}
290
291impl Wmc for TsxCode {
292 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
293 class_interface_compute(space_kind, cyclomatic, stats);
294 }
295}
296
297impl Wmc for RubyCode {
305 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
306 class_interface_compute(space_kind, cyclomatic, stats);
307 }
308}
309
310impl Wmc for JavascriptCode {
316 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
317 class_interface_compute(space_kind, cyclomatic, stats);
318 }
319}
320
321impl Wmc for MozjsCode {
322 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
323 class_interface_compute(space_kind, cyclomatic, stats);
324 }
325}
326
327impl Wmc for ElixirCode {
351 fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
352 class_interface_compute(space_kind, cyclomatic, stats);
353 }
354}
355
356implement_metric_trait!(
362 Wmc,
363 PreprocCode,
364 CcommentCode,
365 GoCode,
366 PerlCode,
367 BashCode,
368 LuaCode,
369 TclCode
370);
371
372#[cfg(test)]
373#[allow(
374 clippy::float_cmp,
375 clippy::cast_precision_loss,
376 clippy::cast_possible_truncation,
377 clippy::cast_sign_loss,
378 clippy::similar_names,
379 clippy::doc_markdown,
380 clippy::needless_raw_string_hashes,
381 clippy::too_many_lines
382)]
383mod tests {
384 use crate::tools::{assert_child_space_kind, check_func_space, check_metrics};
385
386 use super::*;
387
388 #[test]
389 fn java_single_class() {
390 check_metrics::<JavaParser>(
391 "public class Example { // wmc = 13
392
393 public boolean m1(boolean a, boolean b) { // +1
394 boolean r = false;
395 if (a && b == a || b) { // +3
396 r = true;
397 }
398 return r;
399 }
400
401 public boolean m2(int n) { // +1
402 for (int i = 0; i < n; i++) { // +1
403 int j = n;
404 while (j > i) { // +1
405 j--;
406 }
407 }
408 return (n % 2 == 0) ? true : false; // +1
409 }
410
411 public int m3(int x, int y, int z) { // +1
412 int ret;
413 try {
414 z = x/y + y/x;
415 } catch (ArithmeticException e) { // +1
416 z = (x == 0) ? -1 : -2; // +1
417 }
418 switch (z) {
419 case -1: // +1
420 ret = y * y;
421 break;
422 case -2: // +1
423 ret = x * x;
424 break;
425 default:
426 ret = x + y;
427 }
428 return ret;
429 }
430 }",
431 "foo.java",
432 |metric| {
433 insta::assert_json_snapshot!(
435 metric.wmc,
436 @r###"
437 {
438 "classes": 13.0,
439 "interfaces": 0.0,
440 "total": 13.0
441 }"###
442 );
443 },
444 );
445 }
446
447 #[test]
448 fn groovy_single_class() {
449 check_metrics::<GroovyParser>(
451 "class Example {
452 boolean m1(boolean a, boolean b) {
453 boolean r = false
454 if (a && b == a || b) {
455 r = true
456 }
457 return r
458 }
459 boolean m2(int n) {
460 for (int i = 0; i < n; i++) {
461 int j = n
462 while (j > i) {
463 j--
464 }
465 }
466 return (n % 2 == 0) ? true : false
467 }
468 }",
469 "foo.groovy",
470 |metric| {
471 assert_eq!(metric.wmc.class_wmc_sum(), 8.0);
475 },
476 );
477 }
478
479 #[test]
480 fn groovy_empty_class() {
481 check_metrics::<GroovyParser>("class Empty {}", "foo.groovy", |metric| {
482 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
483 });
484 }
485
486 #[test]
487 fn groovy_class_with_single_method() {
488 check_metrics::<GroovyParser>(
489 "class A {
490 void foo() {
491 println 'hi'
492 }
493 }",
494 "foo.groovy",
495 |metric| {
496 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
498 },
499 );
500 }
501
502 #[test]
503 fn groovy_multiple_classes() {
504 check_metrics::<GroovyParser>(
505 "class A {
506 void f() { if (true) {} }
507 }
508 class B {
509 void g() {}
510 }",
511 "foo.groovy",
512 |metric| {
513 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
515 },
516 );
517 }
518
519 #[test]
520 fn groovy_class_with_branching_methods() {
521 check_metrics::<GroovyParser>(
522 "class Calc {
523 int abs(int x) {
524 if (x < 0) {
525 return -x
526 }
527 return x
528 }
529 int sign(int x) {
530 if (x > 0) return 1
531 if (x < 0) return -1
532 return 0
533 }
534 }",
535 "foo.groovy",
536 |metric| {
537 assert_eq!(metric.wmc.class_wmc_sum(), 5.0);
539 },
540 );
541 }
542
543 #[test]
544 fn groovy_interface_wmc_is_zero() {
545 check_metrics::<GroovyParser>(
547 "interface I {
548 void a()
549 void b()
550 }",
551 "foo.groovy",
552 |metric| {
553 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
554 },
555 );
556 }
557
558 #[test]
559 fn groovy_static_nested_class() {
560 check_metrics::<GroovyParser>(
563 "class TopLevelClass {
564 static class StaticNestedClass {
565 private void m() {
566 println 'Test'
567 }
568 }
569 }",
570 "foo.groovy",
571 |metric| {
572 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
574 },
575 );
576 }
577
578 #[test]
579 #[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside class bodies"]
580 fn groovy_nested_inner_classes_wmc() {
581 check_metrics::<GroovyParser>(
584 "class X {
585 void a() {}
586 class Y {
587 void b() {}
588 class Z {
589 void c() {}
590 }
591 }
592 }",
593 "foo.groovy",
594 |metric| {
595 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
597 },
598 );
599 }
600
601 #[test]
602 fn groovy_local_inner_class() {
603 check_metrics::<GroovyParser>(
609 "class Outer {
610 void m() {
611 class Local {
612 void l() {
613 if (true) {}
614 }
615 }
616 }
617 }",
618 "foo.groovy",
619 |metric| {
620 assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
621 },
622 );
623 }
624
625 #[test]
626 #[ignore = "dekobon Groovy grammar v1 does not yet support anonymous inner classes (`new T() { … }`)"]
627 fn groovy_anonymous_inner_class_wmc() {
628 check_metrics::<GroovyParser>(
631 "abstract class Base {
632 abstract void m1()
633 }
634 class Top {
635 void m() {
636 def b = new Base() {
637 void m1() {
638 for (int i = 0; i < 5; i++) {
639 println(i)
640 }
641 }
642 }
643 }
644 }",
645 "foo.groovy",
646 |metric| {
647 assert_eq!(metric.wmc.class_wmc_sum(), 4.0);
649 },
650 );
651 }
652
653 #[test]
654 fn groovy_lambda_expression_wmc() {
655 check_metrics::<GroovyParser>(
658 "class Top {
659 void m1() {
660 def list = [1, 2, 3]
661 list.each { n -> println(n) }
662 }
663 void m2() {
664 if (true) {}
665 }
666 }",
667 "foo.groovy",
668 |metric| {
669 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
671 },
672 );
673 }
674
675 #[test]
676 fn groovy_single_interface_wmc() {
677 check_metrics::<GroovyParser>(
680 "interface Example {
681 default boolean m1(boolean a, boolean b) {
682 return (a && b == a || b)
683 }
684 default int m2(int n) {
685 return (n != 0) ? 1/n : n
686 }
687 void m3()
688 }",
689 "foo.groovy",
690 |metric| {
691 assert_eq!(metric.wmc.interface_wmc_sum(), 6.0);
693 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
694 },
695 );
696 }
697
698 #[test]
699 #[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside interface bodies"]
700 fn groovy_class_in_interface() {
701 check_metrics::<GroovyParser>(
704 "interface Outer {
705 void api()
706 class Inner {
707 void f() {
708 if (true) {}
709 }
710 }
711 }",
712 "foo.groovy",
713 |metric| {
714 assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
716 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
717 },
718 );
719 }
720
721 #[test]
724 fn groovy_enum_wmc_aggregates_method_complexity() {
725 check_metrics::<GroovyParser>(
726 "enum Status {
727 ACTIVE, INACTIVE;
728 public int code(int n) {
729 if (n > 0) { return n }
730 return 0
731 }
732 }",
733 "foo.groovy",
734 |metric| {
735 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
736 },
737 );
738 }
739
740 #[test]
748 #[ignore = "dekobon Groovy grammar v1 does not support annotation type elements with `default` values"]
749 fn groovy_annotation_type_opens_interface_space_with_zero_wmc() {
750 check_func_space::<GroovyParser, _>(
751 "public @interface Marker {
752 String value() default \"\";
753 int priority() default 0;
754 }",
755 "foo.groovy",
756 |func_space| {
757 assert_eq!(func_space.metrics.wmc.interface_wmc_sum(), 0.0);
758 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
759 },
760 );
761 }
762
763 #[test]
766 fn java_multiple_classes() {
767 check_metrics::<JavaParser>(
768 "public class MainClass { // wmc = 3
769 private int a;
770 public MainClass() { // +1
771 a = 0;
772 }
773 public void setA(int n) { // +1
774 a = n;
775 }
776 public int getA() { // +1
777 return a;
778 }
779 }
780
781 class TopLevelClass { // wmc = 2
782 private int b;
783 public TopLevelClass() { // +1
784 b = 0;
785 }
786 public int getB() { // +1
787 return b;
788 }
789 }",
790 "foo.java",
791 |metric| {
792 insta::assert_json_snapshot!(
794 metric.wmc,
795 @r###"
796 {
797 "classes": 5.0,
798 "interfaces": 0.0,
799 "total": 5.0
800 }"###
801 );
802 },
803 );
804 }
805
806 #[test]
807 fn java_static_nested_class() {
808 check_metrics::<JavaParser>(
809 "public class TopLevelClass { // wmc = 0
810 public static class StaticNestedClass { // wmc = 1
811 private void m() { // +1
812 System.out.println(\"Test\");
813 }
814 }
815 }",
816 "foo.java",
817 |metric| {
818 insta::assert_json_snapshot!(
820 metric.wmc,
821 @r###"
822 {
823 "classes": 1.0,
824 "interfaces": 0.0,
825 "total": 1.0
826 }"###
827 );
828 },
829 );
830 }
831
832 #[test]
833 fn java_nested_inner_classes() {
834 check_metrics::<JavaParser>(
835 "public class TopLevelClass { // wmc = 2
836 private int a;
837
838 class InnerClassBefore { // wmc = 1
839 private boolean b = (a % 2 == 0) ? true : false;
840 public boolean getB() { // +1
841 return b;
842 }
843 }
844
845 public TopLevelClass(int n) { // +1
846 if (a != n) { // +1
847 a = n;
848 }
849 }
850
851 class InnerClassAfter { // wmc = 2
852 private int c = a;
853
854 public int getC() { // +1
855 return c;
856 }
857 public void setC(int n) { // +1
858 c = n;
859 }
860
861 class InnerClass1 { // wmc = 1
862 private int p1;
863 class InnerClass2 { // wmc = 1
864 private int p2;
865 public int getP2() { // +1
866 return p2;
867 }
868 class InnerClass3 { // wmc = 2
869 private int p3;
870 public int getP3() { // +1
871 return p3;
872 }
873 public void setP3(int n) { // +1
874 p3 = n;
875 }
876 }
877 }
878 public void setP1(int n) { // +1
879 p1 = n;
880 }
881 }
882 }
883 }",
884 "foo.java",
885 |metric| {
886 insta::assert_json_snapshot!(
888 metric.wmc,
889 @r###"
890 {
891 "classes": 9.0,
892 "interfaces": 0.0,
893 "total": 9.0
894 }"###
895 );
896 },
897 );
898 }
899
900 #[test]
901 fn java_local_inner_class() {
902 check_metrics::<JavaParser>(
903 "import java.util.LinkedList;
904 import java.util.List;
905
906 public final class FinalClass { // wmc = 5
907 private int a = 1;
908 public void test() { // +1
909 final List<String> localList = new LinkedList<String>();
910
911 class LocalInnerClass { // +1, wmc = 2
912 private int b = (a == 1) ? 1 : 0; // +1
913 public void print() { // +1
914 for ( String s : localList ) { // +1
915 System.out.println(s);
916 }
917 }
918 }
919 }
920 }",
921 "foo.java",
922 |metric| {
923 insta::assert_json_snapshot!(
925 metric.wmc,
926 @r###"
927 {
928 "classes": 7.0,
929 "interfaces": 0.0,
930 "total": 7.0
931 }"###
932 );
933 },
934 );
935 }
936
937 #[test]
938 fn java_anonymous_inner_class() {
939 check_metrics::<JavaParser>(
940 "abstract class AbstractClass { // wmc = 1
941 abstract void m1(); // +1
942 }
943 public class TopLevelClass{ // wmc = 3
944 public void m(){ // +1
945 AbstractClass ac1 = new AbstractClass() {
946 void m1() { // +1
947 for (int i = 0; i < 5; i++) { // +1
948 System.out.println(\"Test 1: \" + i);
949 }
950 }
951 };
952 ac1.m1();
953 }
954 }",
955 "foo.java",
956 |metric| {
957 insta::assert_json_snapshot!(
959 metric.wmc,
960 @r###"
961 {
962 "classes": 4.0,
963 "interfaces": 0.0,
964 "total": 4.0
965 }"###
966 );
967 },
968 );
969 }
970
971 #[test]
972 fn java_nested_anonymous_inner_classes() {
973 check_metrics::<JavaParser>(
974 "abstract class AbstractClass{ // wmc = 2
975 abstract void m1(); // +1
976 abstract void m2(); // +1
977 }
978 public class TopLevelClass{ // wmc = 6
979 public void m(){ // +1
980
981 AbstractClass ac1 = new AbstractClass() {
982 void m1() { // +1
983 for (int i = 0; i < 5; i++) { // +1
984 System.out.println(\"Test 1: \" + i);
985 }
986 }
987 void m2() { // +1
988 AbstractClass ac2 = new AbstractClass() {
989 void m1() { // +1
990 System.out.println(\"Test A\");
991 }
992 void m2() { // +1
993 System.out.println(\"Test B\");
994 }
995 };
996 ac2.m2();
997 System.out.println(\"Test 2\");
998 }
999 };
1000 ac1.m1();
1001 }
1002 }",
1003 "foo.java",
1004 |metric| {
1005 insta::assert_json_snapshot!(
1007 metric.wmc,
1008 @r###"
1009 {
1010 "classes": 8.0,
1011 "interfaces": 0.0,
1012 "total": 8.0
1013 }"###
1014 );
1015 },
1016 );
1017 }
1018
1019 #[test]
1020 fn java_lambda_expression() {
1021 check_metrics::<JavaParser>(
1022 "import java.util.ArrayList;
1023
1024 public class TopLevelClass { // wmc = 2
1025 private ArrayList<Integer> numbers;
1026
1027 public void m1() { // +1
1028 numbers = new ArrayList<Integer>();
1029 numbers.add(1);
1030 numbers.add(2);
1031 numbers.add(3);
1032 }
1033
1034 public void m2() { // +1
1035 numbers.forEach( (n) -> { System.out.println(n); } );
1036 }
1037 }",
1038 "foo.java",
1039 |metric| {
1040 insta::assert_json_snapshot!(
1042 metric.wmc,
1043 @r###"
1044 {
1045 "classes": 2.0,
1046 "interfaces": 0.0,
1047 "total": 2.0
1048 }"###
1049 );
1050 },
1051 );
1052 }
1053
1054 #[test]
1055 fn java_single_interface() {
1056 check_metrics::<JavaParser>(
1057 "interface Example { // wmc = 6
1058 default boolean m1(boolean a, boolean b) { // +1
1059 return (a && b == a || b); // +2
1060 }
1061 default int m2(int n) { // +1
1062 return (n != 0) ? 1/n : n; // +1
1063 };
1064 void m3(); // +1
1065 }",
1066 "foo.java",
1067 |metric| {
1068 insta::assert_json_snapshot!(
1070 metric.wmc,
1071 @r###"
1072 {
1073 "classes": 0.0,
1074 "interfaces": 6.0,
1075 "total": 6.0
1076 }"###
1077 );
1078 },
1079 );
1080 }
1081
1082 #[test]
1083 fn java_multiple_interfaces() {
1084 check_metrics::<JavaParser>(
1085 "interface FirstInterface { // wmc = 1
1086 int a = 0;
1087 default int getA() { // +1
1088 return a;
1089 }
1090 }
1091
1092 interface SecondInterface { // wmc = 2
1093 void setB(int n); // +1
1094 int getB(); // +1
1095 }",
1096 "foo.java",
1097 |metric| {
1098 insta::assert_json_snapshot!(
1100 metric.wmc,
1101 @r###"
1102 {
1103 "classes": 0.0,
1104 "interfaces": 3.0,
1105 "total": 3.0
1106 }"###
1107 );
1108 },
1109 );
1110 }
1111
1112 #[test]
1113 fn java_nested_inner_interfaces() {
1114 check_metrics::<JavaParser>(
1115 "interface TopLevelInterface { // wmc = 1
1116 interface InnerInterfaceBefore { // wmc = 1
1117 void m1(); // +1
1118 }
1119
1120 void m2(); // +1
1121
1122 interface InnerInterfaceAfter { // wmc = 2
1123 void m3(); // +1
1124 interface InnerInterface { // wmc = 1
1125 void m4(); // +1
1126 }
1127 void m5(); // +1
1128 }
1129 }",
1130 "foo.java",
1131 |metric| {
1132 insta::assert_json_snapshot!(
1134 metric.wmc,
1135 @r###"
1136 {
1137 "classes": 0.0,
1138 "interfaces": 5.0,
1139 "total": 5.0
1140 }"###
1141 );
1142 },
1143 );
1144 }
1145
1146 #[test]
1147 fn java_class_in_interface() {
1148 check_metrics::<JavaParser>(
1149 "interface TopLevelInterface { // wmc = 2
1150 int getA(); // +1
1151 boolean getB(); // +1
1152
1153 class InnerClass { // wmc = 2
1154 float c;
1155 double d;
1156 float getC() { // +1
1157 return c;
1158 }
1159 double getD() { // +1
1160 return d;
1161 }
1162 }
1163 }",
1164 "foo.java",
1165 |metric| {
1166 insta::assert_json_snapshot!(
1168 metric.wmc,
1169 @r###"
1170 {
1171 "classes": 2.0,
1172 "interfaces": 2.0,
1173 "total": 4.0
1174 }"###
1175 );
1176 },
1177 );
1178 }
1179
1180 #[test]
1181 fn java_interface_in_class() {
1182 check_metrics::<JavaParser>(
1183 "class TopLevelClass { // wmc = 2
1184 int a;
1185 boolean b;
1186 int getA() { // +1
1187 return a;
1188 }
1189 boolean getB() { // +1
1190 return b;
1191 }
1192
1193 interface InnerInterface { // wmc = 2
1194 float getC(); // +1
1195 double getD(); // +1
1196 }
1197 }",
1198 "foo.java",
1199 |metric| {
1200 insta::assert_json_snapshot!(
1202 metric.wmc,
1203 @r###"
1204 {
1205 "classes": 2.0,
1206 "interfaces": 2.0,
1207 "total": 4.0
1208 }"###
1209 );
1210 },
1211 );
1212 }
1213
1214 #[test]
1218 fn java_enum_wmc_aggregates_method_complexity() {
1219 check_metrics::<JavaParser>(
1220 "enum Status {
1221 ACTIVE, INACTIVE;
1222 public int code(int n) { // entry +1
1223 if (n > 0) { // if +1
1224 return n;
1225 }
1226 return 0;
1227 }
1228 }",
1229 "foo.java",
1230 |metric| {
1231 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1233 },
1234 );
1235 }
1236
1237 #[test]
1241 fn java_record_wmc_aggregates_method_complexity() {
1242 check_metrics::<JavaParser>(
1243 "record Point(int x, int y) {
1244 public int describe() { // entry +1
1245 return (x == 0) ? 0 : 1; // ternary +1
1246 }
1247 }",
1248 "foo.java",
1249 |metric| {
1250 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1251 },
1252 );
1253 }
1254
1255 #[test]
1268 fn java_annotation_type_opens_interface_space_with_zero_wmc() {
1269 check_func_space::<JavaParser, _>(
1270 "@interface Marker {
1271 String value() default \"\";
1272 int priority() default 0;
1273 }",
1274 "foo.java",
1275 |func_space| {
1276 assert_eq!(func_space.metrics.wmc.interface_wmc_sum(), 0.0);
1277 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
1280 },
1281 );
1282 }
1283
1284 #[test]
1285 fn csharp_single_class() {
1286 check_metrics::<CsharpParser>(
1287 "public class Example {
1288 public bool M1(bool a, bool b) {
1289 bool r = false;
1290 if (a && b == a || b) {
1291 r = true;
1292 }
1293 return r;
1294 }
1295 public int M2(int n) {
1296 for (int i = 0; i < n; i++) {
1297 int j = n;
1298 while (j > i) {
1299 j--;
1300 }
1301 }
1302 return (n % 2 == 0) ? 1 : 0;
1303 }
1304 }",
1305 "foo.cs",
1306 |metric| {
1307 assert_eq!(metric.wmc.class_wmc_sum(), 8.0);
1308 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1309 insta::assert_json_snapshot!(metric.wmc);
1310 },
1311 );
1312 }
1313
1314 #[test]
1315 fn csharp_multiple_classes() {
1316 check_metrics::<CsharpParser>(
1317 "public class A {
1318 private int a;
1319 public A() { a = 0; }
1320 public void SetA(int n) { a = n; }
1321 public int GetA() { return a; }
1322 }
1323 class B {
1324 private int b;
1325 public B() { b = 0; }
1326 public int GetB() { return b; }
1327 }",
1328 "foo.cs",
1329 |metric| {
1330 assert_eq!(metric.wmc.class_wmc_sum(), 5.0);
1331 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1332 insta::assert_json_snapshot!(metric.wmc);
1333 },
1334 );
1335 }
1336
1337 #[test]
1338 fn csharp_static_nested_class() {
1339 check_metrics::<CsharpParser>(
1340 "public class Outer {
1341 public static class Nested {
1342 private void M() {
1343 System.Console.WriteLine(\"Test\");
1344 }
1345 }
1346 }",
1347 "foo.cs",
1348 |metric| {
1349 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
1350 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1351 insta::assert_json_snapshot!(metric.wmc);
1352 },
1353 );
1354 }
1355
1356 #[test]
1357 fn csharp_nested_inner_classes() {
1358 check_metrics::<CsharpParser>(
1359 "public class Outer {
1360 private int a;
1361 public class Inner {
1362 public int GetX() { return 0; }
1363 public class Innermost {
1364 public int GetY() { return 1; }
1365 }
1366 }
1367 public int GetA() { return a; }
1368 }",
1369 "foo.cs",
1370 |metric| {
1371 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
1372 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1373 insta::assert_json_snapshot!(metric.wmc);
1374 },
1375 );
1376 }
1377
1378 #[test]
1379 fn csharp_local_inner_class() {
1380 check_metrics::<CsharpParser>(
1382 "public class A {
1383 public int M(int x) {
1384 int Local(int y) {
1385 if (y > 0) return y;
1386 return -y;
1387 }
1388 return Local(x);
1389 }
1390 }",
1391 "foo.cs",
1392 |metric| {
1393 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
1394 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1395 insta::assert_json_snapshot!(metric.wmc);
1396 },
1397 );
1398 }
1399
1400 #[test]
1401 fn csharp_anonymous_inner_class() {
1402 check_metrics::<CsharpParser>(
1403 "public class A {
1404 public void Run() {
1405 System.Action f = delegate(int x) {
1406 if (x > 0) System.Console.WriteLine(x);
1407 };
1408 }
1409 }",
1410 "foo.cs",
1411 |metric| {
1412 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
1413 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1414 insta::assert_json_snapshot!(metric.wmc);
1415 },
1416 );
1417 }
1418
1419 #[test]
1420 fn csharp_nested_anonymous_inner_classes() {
1421 check_metrics::<CsharpParser>(
1422 "public class A {
1423 public void Run() {
1424 System.Action f = delegate(int x) {
1425 System.Action g = delegate(int y) {
1426 if (y > 0) System.Console.WriteLine(y);
1427 };
1428 };
1429 }
1430 }",
1431 "foo.cs",
1432 |metric| {
1433 assert_eq!(metric.wmc.class_wmc_sum(), 4.0);
1434 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1435 insta::assert_json_snapshot!(metric.wmc);
1436 },
1437 );
1438 }
1439
1440 #[test]
1441 fn csharp_lambda_expression() {
1442 check_metrics::<CsharpParser>(
1443 "public class A {
1444 public void Run() {
1445 System.Func<int, int> f = x => x > 0 ? x : -x;
1446 }
1447 }",
1448 "foo.cs",
1449 |metric| {
1450 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
1451 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1452 insta::assert_json_snapshot!(metric.wmc);
1453 },
1454 );
1455 }
1456
1457 #[test]
1458 fn csharp_single_interface() {
1459 check_metrics::<CsharpParser>(
1460 "public interface I {
1461 int GetA();
1462 int GetB();
1463 }",
1464 "foo.cs",
1465 |metric| {
1466 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
1467 assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
1468 insta::assert_json_snapshot!(metric.wmc);
1469 },
1470 );
1471 }
1472
1473 #[test]
1474 fn csharp_multiple_interfaces() {
1475 check_metrics::<CsharpParser>(
1476 "public interface I1 { int GetA(); }
1477 public interface I2 { bool GetB(); float GetC(); }",
1478 "foo.cs",
1479 |metric| {
1480 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
1481 assert_eq!(metric.wmc.interface_wmc_sum(), 3.0);
1482 insta::assert_json_snapshot!(metric.wmc);
1483 },
1484 );
1485 }
1486
1487 #[test]
1488 fn csharp_nested_inner_interfaces() {
1489 check_metrics::<CsharpParser>(
1490 "public interface I1 {
1491 int GetA();
1492 public interface I2 {
1493 bool GetB();
1494 }
1495 }",
1496 "foo.cs",
1497 |metric| {
1498 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
1499 assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
1500 insta::assert_json_snapshot!(metric.wmc);
1501 },
1502 );
1503 }
1504
1505 #[test]
1506 fn csharp_class_in_interface() {
1507 check_metrics::<CsharpParser>(
1508 "public interface I {
1509 int GetA();
1510 public class Helper {
1511 public int M() { return 0; }
1512 }
1513 }",
1514 "foo.cs",
1515 |metric| {
1516 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
1517 assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
1518 insta::assert_json_snapshot!(metric.wmc);
1519 },
1520 );
1521 }
1522
1523 #[test]
1524 fn csharp_interface_in_class() {
1525 check_metrics::<CsharpParser>(
1526 "class Outer {
1527 int a;
1528 bool b;
1529 public int GetA() { return a; }
1530 public bool GetB() { return b; }
1531 public interface InnerI {
1532 float GetC();
1533 double GetD();
1534 }
1535 }",
1536 "foo.cs",
1537 |metric| {
1538 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1539 assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
1540 insta::assert_json_snapshot!(metric.wmc);
1541 },
1542 );
1543 }
1544
1545 #[test]
1546 fn php_no_classes() {
1547 check_metrics::<PhpParser>(
1548 "<?php function f(): int { return 1; }",
1549 "foo.php",
1550 |metric| insta::assert_json_snapshot!(metric.wmc),
1551 );
1552 }
1553
1554 #[test]
1555 fn php_one_class_simple() {
1556 check_metrics::<PhpParser>(
1557 "<?php
1558 class A {
1559 public function a(): int { return 1; }
1560 public function b(): int { return 2; }
1561 }",
1562 "foo.php",
1563 |metric| insta::assert_json_snapshot!(metric.wmc),
1564 );
1565 }
1566
1567 #[test]
1568 fn php_one_class_with_loops() {
1569 check_metrics::<PhpParser>(
1570 "<?php
1571 class A {
1572 public function f(int $n): int {
1573 $sum = 0;
1574 for ($i = 0; $i < $n; $i++) {
1575 $sum += $i;
1576 }
1577 return $sum;
1578 }
1579 }",
1580 "foo.php",
1581 |metric| insta::assert_json_snapshot!(metric.wmc),
1582 );
1583 }
1584
1585 #[test]
1586 fn php_one_class_with_branches() {
1587 check_metrics::<PhpParser>(
1588 "<?php
1589 class A {
1590 public function f(int $x): int {
1591 if ($x > 0) {
1592 return 1;
1593 }
1594 if ($x < 0) {
1595 return -1;
1596 }
1597 return 0;
1598 }
1599 }",
1600 "foo.php",
1601 |metric| insta::assert_json_snapshot!(metric.wmc),
1602 );
1603 }
1604
1605 #[test]
1606 fn php_class_with_methods_only() {
1607 check_metrics::<PhpParser>(
1608 "<?php
1609 class A {
1610 public function a(): void {}
1611 public function b(): void {}
1612 public function c(): void {}
1613 }",
1614 "foo.php",
1615 |metric| insta::assert_json_snapshot!(metric.wmc),
1616 );
1617 }
1618
1619 #[test]
1620 fn php_multiple_classes() {
1621 check_metrics::<PhpParser>(
1622 "<?php
1623 class A {
1624 public function f(int $x): int {
1625 if ($x > 0) { return 1; }
1626 return 0;
1627 }
1628 }
1629 class B {
1630 public function g(int $x): int {
1631 return $x;
1632 }
1633 }",
1634 "foo.php",
1635 |metric| insta::assert_json_snapshot!(metric.wmc),
1636 );
1637 }
1638
1639 #[test]
1640 fn php_anonymous_class() {
1641 check_metrics::<PhpParser>(
1642 "<?php
1643 $obj = new class {
1644 public function f(int $x): int {
1645 if ($x > 0) { return 1; }
1646 return 0;
1647 }
1648 };",
1649 "foo.php",
1650 |metric| insta::assert_json_snapshot!(metric.wmc),
1651 );
1652 }
1653
1654 #[test]
1655 fn php_class_with_static_methods() {
1656 check_metrics::<PhpParser>(
1657 "<?php
1658 class A {
1659 public static function f(int $x): int {
1660 if ($x > 0) { return 1; }
1661 return 0;
1662 }
1663 public static function g(): int { return 1; }
1664 }",
1665 "foo.php",
1666 |metric| insta::assert_json_snapshot!(metric.wmc),
1667 );
1668 }
1669
1670 #[test]
1671 fn php_interface_wmc() {
1672 check_metrics::<PhpParser>(
1673 "<?php
1674 interface I {
1675 public function a(): void;
1676 public function b(): int;
1677 }",
1678 "foo.php",
1679 |metric| insta::assert_json_snapshot!(metric.wmc),
1680 );
1681 }
1682
1683 #[test]
1684 fn php_trait_wmc() {
1685 check_metrics::<PhpParser>(
1686 "<?php
1687 trait T {
1688 public function f(int $x): int {
1689 if ($x > 0) { return 1; }
1690 return 0;
1691 }
1692 }",
1693 "foo.php",
1694 |metric| insta::assert_json_snapshot!(metric.wmc),
1695 );
1696 }
1697
1698 #[test]
1699 fn php_enum_with_methods() {
1700 check_metrics::<PhpParser>(
1701 "<?php
1702 enum Color {
1703 case Red;
1704 case Green;
1705 public function label(): string {
1706 return match ($this) {
1707 Color::Red => 'r',
1708 Color::Green => 'g',
1709 };
1710 }
1711 }",
1712 "foo.php",
1713 |metric| insta::assert_json_snapshot!(metric.wmc),
1714 );
1715 }
1716
1717 #[test]
1718 fn php_class_inside_namespace() {
1719 check_metrics::<PhpParser>(
1720 "<?php
1721 namespace App;
1722 class A {
1723 public function f(int $x): int {
1724 if ($x > 0) { return 1; }
1725 return 0;
1726 }
1727 }",
1728 "foo.php",
1729 |metric| insta::assert_json_snapshot!(metric.wmc),
1730 );
1731 }
1732
1733 #[test]
1734 fn php_class_complex() {
1735 check_metrics::<PhpParser>(
1736 "<?php
1737 class Calc {
1738 public function add(int $a, int $b): int {
1739 if ($a > 0 && $b > 0) {
1740 return $a + $b;
1741 }
1742 return 0;
1743 }
1744 public function loop(int $n): int {
1745 $s = 0;
1746 for ($i = 0; $i < $n; $i++) {
1747 if ($i % 2 === 0) { $s += $i; }
1748 }
1749 return $s;
1750 }
1751 }",
1752 "foo.php",
1753 |metric| insta::assert_json_snapshot!(metric.wmc),
1754 );
1755 }
1756
1757 #[test]
1766 fn kotlin_empty_class() {
1767 check_metrics::<KotlinParser>("class Empty {}", "foo.kt", |metric| {
1769 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
1770 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1771 insta::assert_json_snapshot!(metric.wmc);
1772 });
1773 }
1774
1775 #[test]
1776 fn kotlin_single_class() {
1777 check_metrics::<KotlinParser>(
1780 "class C {
1781 fun m(x: Int): Int { // +1
1782 if (x > 0) { // +1
1783 return x
1784 }
1785 return when (x) {
1786 0 -> 0 // +1 (WhenEntry)
1787 else -> -x // skipped (else is default)
1788 }
1789 }
1790 }",
1791 "foo.kt",
1792 |metric| {
1793 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
1794 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1795 insta::assert_json_snapshot!(metric.wmc);
1796 },
1797 );
1798 }
1799
1800 #[test]
1801 fn kotlin_multiple_classes() {
1802 check_metrics::<KotlinParser>(
1805 "class A {
1806 private var a: Int = 0
1807 constructor(n: Int) { a = n } // +1
1808 fun setA(n: Int) { a = n } // +1
1809 fun getA(): Int = a // +1
1810 }
1811 class B {
1812 private var b: Int = 0
1813 constructor(n: Int) { b = n } // +1
1814 fun getB(): Int = b // +1
1815 }",
1816 "foo.kt",
1817 |metric| {
1818 assert_eq!(metric.wmc.class_wmc_sum(), 5.0);
1819 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1820 insta::assert_json_snapshot!(metric.wmc);
1821 },
1822 );
1823 }
1824
1825 #[test]
1826 fn kotlin_nested_class() {
1827 check_metrics::<KotlinParser>(
1829 "class Outer {
1830 class Nested {
1831 fun m() { println(\"hi\") } // +1
1832 }
1833 }",
1834 "foo.kt",
1835 |metric| {
1836 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
1837 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1838 insta::assert_json_snapshot!(metric.wmc);
1839 },
1840 );
1841 }
1842
1843 #[test]
1844 fn kotlin_inner_class() {
1845 check_metrics::<KotlinParser>(
1848 "class Outer {
1849 fun outerM() {} // +1
1850 inner class Inner {
1851 fun innerM() {} // +1
1852 }
1853 }",
1854 "foo.kt",
1855 |metric| {
1856 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1857 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1858 insta::assert_json_snapshot!(metric.wmc);
1859 },
1860 );
1861 }
1862
1863 #[test]
1864 fn kotlin_data_class() {
1865 check_metrics::<KotlinParser>(
1869 "data class Point(val x: Int, val y: Int) {
1870 fun manhattan(): Int = kotlin.math.abs(x) + kotlin.math.abs(y) // +1
1871 }",
1872 "foo.kt",
1873 |metric| {
1874 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
1875 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1876 insta::assert_json_snapshot!(metric.wmc);
1877 },
1878 );
1879 }
1880
1881 #[test]
1882 fn kotlin_object_singleton() {
1883 check_metrics::<KotlinParser>(
1886 "object Util {
1887 fun add(a: Int, b: Int): Int = a + b // +1
1888 fun gtZero(n: Int): Boolean { // +1
1889 return n > 0
1890 }
1891 }",
1892 "foo.kt",
1893 |metric| {
1894 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1895 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1896 insta::assert_json_snapshot!(metric.wmc);
1897 },
1898 );
1899 }
1900
1901 #[test]
1902 fn kotlin_companion_object() {
1903 check_metrics::<KotlinParser>(
1907 "class Holder {
1908 val instance: Int = 1
1909 fun get(): Int = instance // +1
1910 companion object {
1911 val SCALE: Int = 10
1912 fun mk(): Holder = Holder() // +1
1913 }
1914 }",
1915 "foo.kt",
1916 |metric| {
1917 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1918 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1919 insta::assert_json_snapshot!(metric.wmc);
1920 },
1921 );
1922 }
1923
1924 #[test]
1925 fn kotlin_interface_simple() {
1926 check_metrics::<KotlinParser>(
1928 "interface I {
1929 fun work(): Int // +1
1930 fun describe(): String // +1
1931 }",
1932 "foo.kt",
1933 |metric| {
1934 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
1935 assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
1936 insta::assert_json_snapshot!(metric.wmc);
1937 },
1938 );
1939 }
1940
1941 #[test]
1942 fn kotlin_interface_with_default_method() {
1943 check_metrics::<KotlinParser>(
1945 "interface I {
1946 fun abs(n: Int): Int { // +1
1947 return if (n < 0) -n else n // +1 if
1948 }
1949 fun pure(): Int // +1
1950 }",
1951 "foo.kt",
1952 |metric| {
1953 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
1954 assert_eq!(metric.wmc.interface_wmc_sum(), 3.0);
1955 insta::assert_json_snapshot!(metric.wmc);
1956 },
1957 );
1958 }
1959
1960 #[test]
1961 fn kotlin_override_function() {
1962 check_metrics::<KotlinParser>(
1965 "open class Base {
1966 open fun greet(): String = \"hi\" // +1
1967 }
1968 class Sub : Base() {
1969 override fun greet(): String = \"yo\" // +1
1970 }",
1971 "foo.kt",
1972 |metric| {
1973 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
1974 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1975 insta::assert_json_snapshot!(metric.wmc);
1976 },
1977 );
1978 }
1979
1980 #[test]
1981 fn kotlin_secondary_constructor() {
1982 check_metrics::<KotlinParser>(
1985 "class C {
1986 private var a: Int = 0
1987 constructor(n: Int) { // +1
1988 a = n
1989 }
1990 constructor(n: Int, m: Int) { // +1
1991 a = n + m
1992 }
1993 fun get(): Int = a // +1
1994 }",
1995 "foo.kt",
1996 |metric| {
1997 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
1998 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
1999 insta::assert_json_snapshot!(metric.wmc);
2000 },
2001 );
2002 }
2003
2004 #[test]
2005 fn kotlin_init_block() {
2006 check_metrics::<KotlinParser>(
2010 "class C(val n: Int) {
2011 init { // not counted
2012 require(n >= 0) { \"n must be non-negative\" }
2013 }
2014 fun get(): Int = n // +1
2015 }",
2016 "foo.kt",
2017 |metric| {
2018 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2019 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2020 insta::assert_json_snapshot!(metric.wmc);
2021 },
2022 );
2023 }
2024
2025 #[test]
2026 fn kotlin_top_level_function_excluded() {
2027 check_metrics::<KotlinParser>(
2030 "fun freeFunction(): Int = 42
2031 val freeVal: Int = 0
2032 class C { fun m(): Int = 1 } // +1
2033 ",
2034 "foo.kt",
2035 |metric| {
2036 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2037 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2038 insta::assert_json_snapshot!(metric.wmc);
2039 },
2040 );
2041 }
2042
2043 #[test]
2044 fn kotlin_extension_function_excluded() {
2045 check_metrics::<KotlinParser>(
2050 "fun List<Int>.sum2(): Int = this.size // top-level
2051 class C { fun m(): Int = 1 } // +1
2052 ",
2053 "foo.kt",
2054 |metric| {
2055 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2056 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2057 insta::assert_json_snapshot!(metric.wmc);
2058 },
2059 );
2060 }
2061
2062 #[test]
2063 fn kotlin_generic_class() {
2064 check_metrics::<KotlinParser>(
2066 "class Box<T>(val value: T) {
2067 fun get(): T = value // +1
2068 fun mapTo(f: (T) -> T): T = f(value) // +1
2069 }",
2070 "foo.kt",
2071 |metric| {
2072 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2073 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2074 insta::assert_json_snapshot!(metric.wmc);
2075 },
2076 );
2077 }
2078
2079 #[test]
2080 fn kotlin_class_in_interface() {
2081 check_metrics::<KotlinParser>(
2085 "interface Outer {
2086 fun work(): Int // +1 (interface)
2087 class Helper {
2088 fun help(): Int = 0 // +1 (class)
2089 }
2090 }",
2091 "foo.kt",
2092 |metric| {
2093 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2094 assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
2095 insta::assert_json_snapshot!(metric.wmc);
2096 },
2097 );
2098 }
2099
2100 #[test]
2101 fn kotlin_interface_in_class() {
2102 check_metrics::<KotlinParser>(
2104 "class Outer {
2105 fun work(): Int = 1 // +1 (class)
2106 interface Sub {
2107 fun help(): Int // +1 (interface)
2108 }
2109 }",
2110 "foo.kt",
2111 |metric| {
2112 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2113 assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
2114 insta::assert_json_snapshot!(metric.wmc);
2115 },
2116 );
2117 }
2118
2119 #[test]
2127 fn typescript_class_wmc_single_method() {
2128 check_metrics::<TypescriptParser>(
2129 "class C {
2130 m(): number { return 1; } // cyclomatic 1
2131 }",
2132 "foo.ts",
2133 |metric| {
2134 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2135 insta::assert_json_snapshot!(metric.wmc);
2136 },
2137 );
2138 }
2139
2140 #[test]
2141 fn typescript_class_wmc_two_methods() {
2142 check_metrics::<TypescriptParser>(
2143 "class C {
2144 a(): number { return 1; } // +1
2145 b(x: number): number { // +2 (if branch)
2146 if (x > 0) return x;
2147 return 0;
2148 }
2149 }",
2150 "foo.ts",
2151 |metric| {
2152 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2153 insta::assert_json_snapshot!(metric.wmc);
2154 },
2155 );
2156 }
2157
2158 #[test]
2159 fn typescript_class_wmc_with_branches() {
2160 check_metrics::<TypescriptParser>(
2161 "class C {
2162 m(x: number): number {
2163 if (x > 0) { // +1
2164 return 1;
2165 } else if (x < 0) { // +1
2166 return -1;
2167 }
2168 return 0;
2169 } // base 1
2170 }",
2171 "foo.ts",
2172 |metric| {
2173 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2174 insta::assert_json_snapshot!(metric.wmc);
2175 },
2176 );
2177 }
2178
2179 #[test]
2180 fn typescript_class_wmc_arrow_field() {
2181 check_metrics::<TypescriptParser>(
2184 "class C {
2185 arrow = (x: number) => {
2186 if (x > 0) return x; // +1
2187 return 0;
2188 }; // base 1
2189 }",
2190 "foo.ts",
2191 |metric| {
2192 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2193 insta::assert_json_snapshot!(metric.wmc);
2194 },
2195 );
2196 }
2197
2198 #[test]
2199 fn typescript_class_wmc_with_loops() {
2200 check_metrics::<TypescriptParser>(
2201 "class C {
2202 m(xs: number[]): number {
2203 let total = 0;
2204 for (const x of xs) { // +1
2205 total += x;
2206 }
2207 return total;
2208 } // base 1
2209 }",
2210 "foo.ts",
2211 |metric| {
2212 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2213 insta::assert_json_snapshot!(metric.wmc);
2214 },
2215 );
2216 }
2217
2218 #[test]
2219 fn typescript_abstract_class_wmc() {
2220 check_metrics::<TypescriptParser>(
2222 "abstract class C {
2223 abstract a(): void; // signature only, 0
2224 m(): number { return 1; } // +1
2225 }",
2226 "foo.ts",
2227 |metric| {
2228 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2229 insta::assert_json_snapshot!(metric.wmc);
2230 },
2231 );
2232 }
2233
2234 #[test]
2235 fn typescript_interface_wmc_zero() {
2236 check_metrics::<TypescriptParser>(
2238 "interface I {
2239 a(): void;
2240 b(): number;
2241 }",
2242 "foo.ts",
2243 |metric| {
2244 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2245 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2246 insta::assert_json_snapshot!(metric.wmc);
2247 },
2248 );
2249 }
2250
2251 #[test]
2252 fn typescript_constructor_wmc() {
2253 check_metrics::<TypescriptParser>(
2256 "class C {
2257 x: number;
2258 constructor(n: number) {
2259 if (n > 0) { // +1
2260 this.x = n;
2261 } else {
2262 this.x = 0;
2263 }
2264 } // base 1
2265 }",
2266 "foo.ts",
2267 |metric| {
2268 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2269 insta::assert_json_snapshot!(metric.wmc);
2270 },
2271 );
2272 }
2273
2274 #[test]
2275 fn typescript_getter_setter_wmc() {
2276 check_metrics::<TypescriptParser>(
2278 "class C {
2279 _x: number = 0;
2280 get x(): number { return this._x; }
2281 set x(v: number) { this._x = v; }
2282 }",
2283 "foo.ts",
2284 |metric| {
2285 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2286 insta::assert_json_snapshot!(metric.wmc);
2287 },
2288 );
2289 }
2290
2291 #[test]
2292 fn typescript_multiple_classes_wmc_independent() {
2293 check_metrics::<TypescriptParser>(
2294 "class A { m(): number { return 1; } }
2295 class B {
2296 m(x: number): number {
2297 if (x > 0) return x; // +1
2298 return 0;
2299 } // base 1
2300 }",
2301 "foo.ts",
2302 |metric| {
2303 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2305 insta::assert_json_snapshot!(metric.wmc);
2306 },
2307 );
2308 }
2309
2310 #[test]
2311 fn typescript_class_wmc_with_ternary_and_logical() {
2312 check_metrics::<TypescriptParser>(
2313 "class C {
2314 m(x: number, y: number): number {
2315 return x > 0 && y > 0 // +1 (ternary) +1 (&&)
2316 ? x + y
2317 : 0;
2318 } // base 1
2319 }",
2320 "foo.ts",
2321 |metric| {
2322 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2323 insta::assert_json_snapshot!(metric.wmc);
2324 },
2325 );
2326 }
2327
2328 #[test]
2329 fn typescript_generic_class_wmc() {
2330 check_metrics::<TypescriptParser>(
2331 "class Box<T> {
2332 value: T;
2333 set(v: T): void { this.value = v; }
2334 get(): T { return this.value; }
2335 }",
2336 "foo.ts",
2337 |metric| {
2338 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2339 insta::assert_json_snapshot!(metric.wmc);
2340 },
2341 );
2342 }
2343
2344 #[test]
2347 fn tsx_class_wmc_single_method() {
2348 check_metrics::<TsxParser>(
2349 "class C { m(): number { return 1; } }",
2350 "foo.tsx",
2351 |metric| {
2352 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2353 insta::assert_json_snapshot!(metric.wmc);
2354 },
2355 );
2356 }
2357
2358 #[test]
2359 fn tsx_class_wmc_two_methods() {
2360 check_metrics::<TsxParser>(
2361 "class C {
2362 a(): number { return 1; }
2363 b(x: number): number {
2364 if (x > 0) return x;
2365 return 0;
2366 }
2367 }",
2368 "foo.tsx",
2369 |metric| {
2370 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2371 insta::assert_json_snapshot!(metric.wmc);
2372 },
2373 );
2374 }
2375
2376 #[test]
2377 fn tsx_class_wmc_with_branches() {
2378 check_metrics::<TsxParser>(
2379 "class C {
2380 m(x: number): number {
2381 if (x > 0) return 1;
2382 else if (x < 0) return -1;
2383 return 0;
2384 }
2385 }",
2386 "foo.tsx",
2387 |metric| {
2388 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2389 insta::assert_json_snapshot!(metric.wmc);
2390 },
2391 );
2392 }
2393
2394 #[test]
2395 fn tsx_class_wmc_arrow_field() {
2396 check_metrics::<TsxParser>(
2397 "class C {
2398 arrow = (x: number) => {
2399 if (x > 0) return x;
2400 return 0;
2401 };
2402 }",
2403 "foo.tsx",
2404 |metric| {
2405 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2406 insta::assert_json_snapshot!(metric.wmc);
2407 },
2408 );
2409 }
2410
2411 #[test]
2412 fn tsx_class_wmc_with_loops() {
2413 check_metrics::<TsxParser>(
2414 "class C {
2415 m(xs: number[]): number {
2416 let total = 0;
2417 for (const x of xs) { total += x; }
2418 return total;
2419 }
2420 }",
2421 "foo.tsx",
2422 |metric| {
2423 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2424 insta::assert_json_snapshot!(metric.wmc);
2425 },
2426 );
2427 }
2428
2429 #[test]
2430 fn tsx_abstract_class_wmc() {
2431 check_metrics::<TsxParser>(
2432 "abstract class C {
2433 abstract a(): void;
2434 m(): number { return 1; }
2435 }",
2436 "foo.tsx",
2437 |metric| {
2438 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2439 insta::assert_json_snapshot!(metric.wmc);
2440 },
2441 );
2442 }
2443
2444 #[test]
2445 fn tsx_interface_wmc_zero() {
2446 check_metrics::<TsxParser>(
2447 "interface I { a(): void; b(): number; }",
2448 "foo.tsx",
2449 |metric| {
2450 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2451 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2452 insta::assert_json_snapshot!(metric.wmc);
2453 },
2454 );
2455 }
2456
2457 #[test]
2458 fn tsx_constructor_wmc() {
2459 check_metrics::<TsxParser>(
2460 "class C {
2461 x: number;
2462 constructor(n: number) {
2463 if (n > 0) this.x = n;
2464 else this.x = 0;
2465 }
2466 }",
2467 "foo.tsx",
2468 |metric| {
2469 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2470 insta::assert_json_snapshot!(metric.wmc);
2471 },
2472 );
2473 }
2474
2475 #[test]
2476 fn tsx_getter_setter_wmc() {
2477 check_metrics::<TsxParser>(
2478 "class C {
2479 _x: number = 0;
2480 get x(): number { return this._x; }
2481 set x(v: number) { this._x = v; }
2482 }",
2483 "foo.tsx",
2484 |metric| {
2485 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2486 insta::assert_json_snapshot!(metric.wmc);
2487 },
2488 );
2489 }
2490
2491 #[test]
2492 fn tsx_multiple_classes_wmc_independent() {
2493 check_metrics::<TsxParser>(
2494 "class A { m(): number { return 1; } }
2495 class B {
2496 m(x: number): number {
2497 if (x > 0) return x;
2498 return 0;
2499 }
2500 }",
2501 "foo.tsx",
2502 |metric| {
2503 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2504 insta::assert_json_snapshot!(metric.wmc);
2505 },
2506 );
2507 }
2508
2509 #[test]
2510 fn tsx_class_wmc_with_ternary_and_logical() {
2511 check_metrics::<TsxParser>(
2512 "class C {
2513 m(x: number, y: number): number {
2514 return x > 0 && y > 0 ? x + y : 0;
2515 }
2516 }",
2517 "foo.tsx",
2518 |metric| {
2519 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2520 insta::assert_json_snapshot!(metric.wmc);
2521 },
2522 );
2523 }
2524
2525 #[test]
2526 fn tsx_generic_class_wmc() {
2527 check_metrics::<TsxParser>(
2528 "class Box<T> {
2529 value: T;
2530 set(v: T): void { this.value = v; }
2531 get(): T { return this.value; }
2532 }",
2533 "foo.tsx",
2534 |metric| {
2535 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2536 insta::assert_json_snapshot!(metric.wmc);
2537 },
2538 );
2539 }
2540
2541 #[test]
2549 fn ruby_no_classes() {
2550 check_metrics::<RubyParser>("def foo\n 1\nend\n", "foo.rb", |metric| {
2552 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2553 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2554 insta::assert_json_snapshot!(metric.wmc);
2555 });
2556 }
2557
2558 #[test]
2559 fn ruby_empty_class() {
2560 check_metrics::<RubyParser>("class Foo\nend\n", "foo.rb", |metric| {
2562 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2563 insta::assert_json_snapshot!(metric.wmc);
2564 });
2565 }
2566
2567 #[test]
2568 fn ruby_one_class_simple() {
2569 check_metrics::<RubyParser>(
2571 "class A\n def a\n 1\n end\n def b\n 2\n end\nend\n",
2572 "foo.rb",
2573 |metric| {
2574 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2575 insta::assert_json_snapshot!(metric.wmc);
2576 },
2577 );
2578 }
2579
2580 #[test]
2581 fn ruby_one_class_with_branch() {
2582 check_metrics::<RubyParser>(
2584 "class A\n def f(x)\n if x > 0\n 1\n else\n 0\n end\n end\nend\n",
2585 "foo.rb",
2586 |metric| {
2587 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2588 insta::assert_json_snapshot!(metric.wmc);
2589 },
2590 );
2591 }
2592
2593 #[test]
2594 fn ruby_one_class_with_loop() {
2595 check_metrics::<RubyParser>(
2597 "class A\n def f(n)\n while n > 0\n n -= 1\n end\n end\nend\n",
2598 "foo.rb",
2599 |metric| {
2600 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2601 insta::assert_json_snapshot!(metric.wmc);
2602 },
2603 );
2604 }
2605
2606 #[test]
2607 fn ruby_singleton_method_included() {
2608 check_metrics::<RubyParser>(
2611 "class A\n def f\n 1\n end\n def self.g\n 2\n end\nend\n",
2612 "foo.rb",
2613 |metric| {
2614 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2615 insta::assert_json_snapshot!(metric.wmc);
2616 },
2617 );
2618 }
2619
2620 #[test]
2621 fn ruby_singleton_class_methods_included() {
2622 check_metrics::<RubyParser>(
2625 "class A\n class << self\n def s\n 1\n end\n end\nend\n",
2626 "foo.rb",
2627 |metric| {
2628 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2631 insta::assert_json_snapshot!(metric.wmc);
2632 },
2633 );
2634 }
2635
2636 #[test]
2637 fn ruby_multiple_classes() {
2638 check_metrics::<RubyParser>(
2640 "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",
2641 "foo.rb",
2642 |metric| {
2643 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2645 insta::assert_json_snapshot!(metric.wmc);
2646 },
2647 );
2648 }
2649
2650 #[test]
2651 fn ruby_module_only() {
2652 check_metrics::<RubyParser>(
2655 "module M\n def f\n 1\n end\nend\n",
2656 "foo.rb",
2657 |metric| {
2658 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2659 insta::assert_json_snapshot!(metric.wmc);
2660 },
2661 );
2662 }
2663
2664 #[test]
2665 fn ruby_class_with_inheritance() {
2666 check_metrics::<RubyParser>(
2669 "class A < B\n def f\n 1\n end\n def g\n 2\n end\nend\n",
2670 "foo.rb",
2671 |metric| {
2672 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2673 insta::assert_json_snapshot!(metric.wmc);
2674 },
2675 );
2676 }
2677
2678 #[test]
2679 fn ruby_class_with_visibility_keywords() {
2680 check_metrics::<RubyParser>(
2683 "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",
2684 "foo.rb",
2685 |metric| {
2686 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2687 insta::assert_json_snapshot!(metric.wmc);
2688 },
2689 );
2690 }
2691
2692 #[test]
2693 fn ruby_class_complex() {
2694 check_metrics::<RubyParser>(
2699 "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",
2700 "foo.rb",
2701 |metric| {
2702 assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
2703 insta::assert_json_snapshot!(metric.wmc);
2704 },
2705 );
2706 }
2707
2708 #[test]
2720 fn python_empty_class_zero_wmc() {
2721 check_metrics::<PythonParser>("class C:\n pass\n", "foo.py", |metric| {
2722 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2723 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2724 insta::assert_json_snapshot!(metric.wmc);
2725 });
2726 }
2727
2728 #[test]
2729 fn python_single_method_wmc_one() {
2730 check_metrics::<PythonParser>(
2732 "class C:\n def m(self):\n return 1\n",
2733 "foo.py",
2734 |metric| {
2735 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2736 insta::assert_json_snapshot!(metric.wmc);
2737 },
2738 );
2739 }
2740
2741 #[test]
2742 fn python_method_with_if_adds_to_wmc() {
2743 check_metrics::<PythonParser>(
2745 "class C:\n def m(self, x):\n if x > 0:\n return 1\n return 0\n",
2746 "foo.py",
2747 |metric| {
2748 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2749 insta::assert_json_snapshot!(metric.wmc);
2750 },
2751 );
2752 }
2753
2754 #[test]
2755 fn python_multiple_methods_wmc_sums() {
2756 check_metrics::<PythonParser>(
2759 "class C:\n\
2760 \x20 def m1(self):\n\
2761 \x20 return 1\n\
2762 \x20 def m2(self, x):\n\
2763 \x20 if x:\n\
2764 \x20 return 1\n\
2765 \x20 return 0\n\
2766 \x20 def m3(self, xs):\n\
2767 \x20 for x in xs:\n\
2768 \x20 if x:\n\
2769 \x20 return x\n\
2770 \x20 return None\n",
2771 "foo.py",
2772 |metric| {
2773 assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
2774 insta::assert_json_snapshot!(metric.wmc);
2775 },
2776 );
2777 }
2778
2779 #[test]
2780 fn python_top_level_function_does_not_contribute_to_class_wmc() {
2781 check_metrics::<PythonParser>(
2784 "def f(x):\n if x:\n return 1\n return 0\n",
2785 "foo.py",
2786 |metric| {
2787 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2788 insta::assert_json_snapshot!(metric.wmc);
2789 },
2790 );
2791 }
2792
2793 #[test]
2794 fn python_multiple_classes_wmc_independent() {
2795 check_metrics::<PythonParser>(
2799 "class A:\n\
2800 \x20 def m1(self):\n\
2801 \x20 return 1\n\
2802 class B:\n\
2803 \x20 def m2(self, x):\n\
2804 \x20 if x:\n\
2805 \x20 return 1\n\
2806 \x20 return 0\n",
2807 "foo.py",
2808 |metric| {
2809 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2810 insta::assert_json_snapshot!(metric.wmc);
2811 },
2812 );
2813 }
2814
2815 #[test]
2816 fn rust_empty_unit_zero_wmc() {
2817 check_metrics::<RustParser>("", "empty.rs", |metric| {
2818 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2819 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2820 insta::assert_json_snapshot!(metric.wmc);
2821 });
2822 }
2823
2824 #[test]
2825 fn rust_single_impl_method_wmc_one() {
2826 check_metrics::<RustParser>(
2828 "struct Foo;\nimpl Foo { fn m(&self) -> i32 { 1 } }\n",
2829 "foo.rs",
2830 |metric| {
2831 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
2832 insta::assert_json_snapshot!(metric.wmc);
2833 },
2834 );
2835 }
2836
2837 #[test]
2838 fn rust_method_with_if_adds_to_wmc() {
2839 check_metrics::<RustParser>(
2841 "struct Foo;\n\
2842 impl Foo {\n\
2843 \x20 fn m(&self, x: i32) -> i32 {\n\
2844 \x20 if x > 0 { 1 } else { 0 }\n\
2845 \x20 }\n\
2846 }\n",
2847 "foo.rs",
2848 |metric| {
2849 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2850 insta::assert_json_snapshot!(metric.wmc);
2851 },
2852 );
2853 }
2854
2855 #[test]
2856 fn rust_multiple_methods_wmc_sums() {
2857 check_metrics::<RustParser>(
2860 "struct Foo;\n\
2861 impl Foo {\n\
2862 \x20 fn m1(&self) -> i32 { 1 }\n\
2863 \x20 fn m2(&self, x: i32) -> i32 { if x > 0 { 1 } else { 0 } }\n\
2864 \x20 fn m3(&self, xs: &[i32]) -> i32 {\n\
2865 \x20 for x in xs { if *x > 0 { return *x; } }\n\
2866 \x20 0\n\
2867 \x20 }\n\
2868 }\n",
2869 "foo.rs",
2870 |metric| {
2871 assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
2872 insta::assert_json_snapshot!(metric.wmc);
2873 },
2874 );
2875 }
2876
2877 #[test]
2878 fn rust_multiple_impls_wmc_aggregate() {
2879 check_metrics::<RustParser>(
2882 "struct Foo;\n\
2883 impl Foo { fn m1(&self) {} }\n\
2884 impl Foo { fn m2(&self) {} }\n",
2885 "foo.rs",
2886 |metric| {
2887 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2888 insta::assert_json_snapshot!(metric.wmc);
2889 },
2890 );
2891 }
2892
2893 #[test]
2894 fn rust_trait_default_method_contributes_to_interface_wmc() {
2895 check_metrics::<RustParser>(
2900 "trait T { fn draw(&self); fn area(&self) -> f64 { 0.0 } }",
2901 "foo.rs",
2902 |metric| {
2903 assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
2904 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2905 insta::assert_json_snapshot!(metric.wmc);
2906 },
2907 );
2908 }
2909
2910 #[test]
2911 fn rust_top_level_function_does_not_contribute_to_class_wmc() {
2912 check_metrics::<RustParser>(
2916 "fn f(x: i32) -> i32 { if x > 0 { 1 } else { 0 } }",
2917 "foo.rs",
2918 |metric| {
2919 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2920 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2921 insta::assert_json_snapshot!(metric.wmc);
2922 },
2923 );
2924 }
2925
2926 #[test]
2929 fn go_wmc_is_zero_documented_limitation() {
2930 check_metrics::<GoParser>(
2940 "package main\n\
2941 type Foo struct{}\n\
2942 func (f Foo) M(x int) int { if x > 0 { return 1 } else { return 0 } }\n\
2943 func (f Foo) N() {}\n",
2944 "foo.go",
2945 |metric| {
2946 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
2947 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2948 insta::assert_json_snapshot!(metric.wmc);
2949 },
2950 );
2951 }
2952
2953 #[test]
2962 fn elixir_wmc_aggregates_def_methods() {
2963 check_metrics::<ElixirParser>(
2964 "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",
2965 "foo.ex",
2966 |metric| {
2967 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
2969 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
2970 insta::assert_json_snapshot!(
2971 metric.wmc,
2972 @r###"
2973 {
2974 "classes": 3.0,
2975 "interfaces": 0.0,
2976 "total": 3.0
2977 }"###
2978 );
2979 },
2980 );
2981 }
2982
2983 #[test]
2984 fn elixir_wmc_def_plus_defp_counts_both() {
2985 check_metrics::<ElixirParser>(
2986 "defmodule Foo do\n def pub_one, do: 1\n defp priv_one, do: 1\nend\n",
2987 "foo.ex",
2988 |metric| {
2989 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
2992 },
2993 );
2994 }
2995
2996 #[test]
2997 fn elixir_wmc_defmacro_counts() {
2998 check_metrics::<ElixirParser>(
2999 "defmodule Foo do\n defmacro stuff(x) do\n if x > 0, do: :pos, else: :neg\n end\nend\n",
3000 "foo.ex",
3001 |metric| {
3002 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3004 },
3005 );
3006 }
3007
3008 #[test]
3009 fn elixir_wmc_multiple_clauses_each_a_method() {
3010 check_metrics::<ElixirParser>(
3013 "defmodule Foo do\n def f(0), do: :zero\n def f(_), do: :other\nend\n",
3014 "foo.ex",
3015 |metric| {
3016 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3018 },
3019 );
3020 }
3021
3022 #[test]
3023 fn elixir_wmc_nested_defmodule_isolates() {
3024 check_metrics::<ElixirParser>(
3025 "defmodule Outer do\n def o, do: 1\n defmodule Inner do\n def i, do: 1\n end\nend\n",
3026 "foo.ex",
3027 |metric| {
3028 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3030 },
3031 );
3032 }
3033
3034 #[test]
3035 fn elixir_wmc_user_macro_not_classified_as_method() {
3036 check_metrics::<ElixirParser>(
3046 "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",
3047 "foo.ex",
3048 |metric| {
3049 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
3052 },
3053 );
3054 }
3055
3056 #[test]
3057 fn elixir_wmc_quoted_defs_do_not_inflate_method_count() {
3058 check_metrics::<ElixirParser>(
3069 "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",
3070 "foo.ex",
3071 |metric| {
3072 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
3075 },
3076 );
3077 }
3078
3079 #[test]
3082 fn cpp_empty_unit_zero_wmc() {
3083 check_metrics::<CppParser>("", "empty.cpp", |metric| {
3085 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
3086 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
3087 insta::assert_json_snapshot!(metric.wmc);
3088 });
3089 }
3090
3091 #[test]
3092 fn cpp_single_method_wmc_one() {
3093 check_metrics::<CppParser>("class Foo { public: void m() {} };", "foo.cpp", |metric| {
3095 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
3096 insta::assert_json_snapshot!(metric.wmc);
3097 });
3098 }
3099
3100 #[test]
3101 fn cpp_method_with_if_adds_to_wmc() {
3102 check_metrics::<CppParser>(
3104 "class Foo {\n\
3105 public:\n\
3106 int m(int x) {\n\
3107 if (x > 0) { return 1; }\n\
3108 return 0;\n\
3109 }\n\
3110 };",
3111 "foo.cpp",
3112 |metric| {
3113 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3114 insta::assert_json_snapshot!(metric.wmc);
3115 },
3116 );
3117 }
3118
3119 #[test]
3120 fn cpp_struct_wmc_maps_to_class() {
3121 check_metrics::<CppParser>(
3125 "struct Foo {\n\
3126 int m(int x) {\n\
3127 if (x > 0) { return 1; }\n\
3128 return 0;\n\
3129 }\n\
3130 };",
3131 "foo.cpp",
3132 |metric| {
3133 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3134 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
3135 insta::assert_json_snapshot!(metric.wmc);
3136 },
3137 );
3138 }
3139
3140 #[test]
3141 fn cpp_free_function_does_not_contribute_to_class_wmc() {
3142 check_metrics::<CppParser>(
3148 "int free_fn(int x) { if (x > 0) { return 1; } return 0; }",
3149 "foo.cpp",
3150 |metric| {
3151 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
3152 assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
3153 insta::assert_json_snapshot!(metric.wmc);
3154 },
3155 );
3156 }
3157
3158 #[test]
3159 fn cpp_multiple_methods_wmc_sums() {
3160 check_metrics::<CppParser>(
3163 "class Foo {\n\
3164 public:\n\
3165 int a(int x) { if (x > 0) { return 1; } return 0; }\n\
3166 int b() { return 42; }\n\
3167 };",
3168 "foo.cpp",
3169 |metric| {
3170 assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
3171 insta::assert_json_snapshot!(metric.wmc);
3172 },
3173 );
3174 }
3175
3176 #[test]
3177 fn cpp_multiple_classes_wmc_aggregate() {
3178 check_metrics::<CppParser>(
3181 "class Foo { public: void a() {} };\nstruct Bar { void b() {} };",
3182 "foo.cpp",
3183 |metric| {
3184 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3185 insta::assert_json_snapshot!(metric.wmc);
3186 },
3187 );
3188 }
3189
3190 #[test]
3191 fn javascript_empty_unit_zero_wmc() {
3192 check_metrics::<JavascriptParser>("", "empty.js", |metric| {
3193 assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
3194 insta::assert_json_snapshot!(metric.wmc);
3195 });
3196 }
3197
3198 #[test]
3199 fn javascript_single_method_wmc_one() {
3200 check_metrics::<JavascriptParser>("class Foo { a() { return 1; } }", "foo.js", |metric| {
3203 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
3204 insta::assert_json_snapshot!(metric.wmc);
3205 });
3206 }
3207
3208 #[test]
3209 fn javascript_method_with_if_adds_to_wmc() {
3210 check_metrics::<JavascriptParser>(
3212 "class Foo { a(x) { if (x > 0) return 1; return 0; } }",
3213 "foo.js",
3214 |metric| {
3215 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3216 insta::assert_json_snapshot!(metric.wmc);
3217 },
3218 );
3219 }
3220
3221 #[test]
3222 fn javascript_free_function_does_not_contribute_to_class_wmc() {
3223 check_metrics::<JavascriptParser>(
3226 "function f(x) { if (x > 0) return 1; return 0; }\nclass Foo { a() { return 1; } }",
3227 "foo.js",
3228 |metric| {
3229 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
3231 insta::assert_json_snapshot!(metric.wmc);
3232 },
3233 );
3234 }
3235
3236 #[test]
3237 fn javascript_multiple_classes_wmc_aggregate() {
3238 check_metrics::<JavascriptParser>(
3241 "class Foo { a() { return 1; } }\nclass Bar { b() { return 1; } }",
3242 "foo.js",
3243 |metric| {
3244 assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
3245 insta::assert_json_snapshot!(metric.wmc);
3246 },
3247 );
3248 }
3249
3250 #[test]
3251 fn mozjs_single_method_wmc_one() {
3252 check_metrics::<MozjsParser>("class Foo { a() { return 1; } }", "foo.js", |metric| {
3253 assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
3254 insta::assert_json_snapshot!(metric.wmc);
3255 });
3256 }
3257}