1#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
8#![allow(
15 clippy::cast_precision_loss,
16 clippy::cast_possible_truncation,
17 clippy::cast_sign_loss
18)]
19
20use std::fmt;
21
22use crate::checker::{Checker, csharp_accessor_count};
23use crate::langs::*;
24use crate::macros::implement_metric_trait;
25use crate::metrics::npa::{accessibility_ratio, python_is_block, ts_member_is_public};
26use crate::node::Node;
27use crate::*;
28
29#[derive(Clone, Debug, Default, PartialEq)]
53#[non_exhaustive]
54pub struct Stats {
55 class_npm: usize,
56 interface_npm: usize,
57 class_nm: usize,
58 interface_nm: usize,
59 class_npm_sum: usize,
60 interface_npm_sum: usize,
61 class_nm_sum: usize,
62 interface_nm_sum: usize,
63 space_kind: SpaceKind,
64}
65
66impl fmt::Display for Stats {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 write!(
69 f,
70 "classes: {}, interfaces: {}, class_methods: {}, interface_methods: {}, class_coa: {}, interface_coa: {}, total: {}, total_methods: {}, coa: {}",
71 self.class_npm_sum(),
72 self.interface_npm_sum(),
73 self.class_nm_sum(),
74 self.interface_nm_sum(),
75 self.class_coa(),
76 self.interface_coa(),
77 self.total_npm(),
78 self.total_nm(),
79 self.total_coa()
80 )
81 }
82}
83
84impl Stats {
85 pub fn merge(&mut self, other: &Stats) {
87 self.class_npm_sum += other.class_npm_sum;
88 self.interface_npm_sum += other.interface_npm_sum;
89 self.class_nm_sum += other.class_nm_sum;
90 self.interface_nm_sum += other.interface_nm_sum;
91 }
92
93 #[inline]
95 #[must_use]
96 pub fn class_npm(&self) -> u64 {
97 self.class_npm as u64
98 }
99
100 #[inline]
102 #[must_use]
103 pub fn interface_npm(&self) -> u64 {
104 self.interface_npm as u64
105 }
106
107 #[inline]
109 #[must_use]
110 pub fn class_nm(&self) -> u64 {
111 self.class_nm as u64
112 }
113
114 #[inline]
116 #[must_use]
117 pub fn interface_nm(&self) -> u64 {
118 self.interface_nm as u64
119 }
120
121 #[inline]
123 #[must_use]
124 pub fn class_npm_sum(&self) -> u64 {
125 self.class_npm_sum as u64
126 }
127
128 #[inline]
130 #[must_use]
131 pub fn interface_npm_sum(&self) -> u64 {
132 self.interface_npm_sum as u64
133 }
134
135 #[inline]
137 #[must_use]
138 pub fn class_nm_sum(&self) -> u64 {
139 self.class_nm_sum as u64
140 }
141
142 #[inline]
144 #[must_use]
145 pub fn interface_nm_sum(&self) -> u64 {
146 self.interface_nm_sum as u64
147 }
148
149 #[inline]
159 #[must_use]
160 pub fn class_coa(&self) -> f64 {
161 accessibility_ratio(self.class_npm_sum() as f64, self.class_nm_sum() as f64)
162 }
163
164 #[inline]
174 #[must_use]
175 pub fn interface_coa(&self) -> f64 {
176 if self.interface_npm_sum == self.interface_nm_sum && self.interface_npm_sum != 0 {
182 1.0
183 } else {
184 accessibility_ratio(
185 self.interface_npm_sum() as f64,
186 self.interface_nm_sum() as f64,
187 )
188 }
189 }
190
191 #[inline]
201 #[must_use]
202 pub fn total_coa(&self) -> f64 {
203 accessibility_ratio(self.total_npm() as f64, self.total_nm() as f64)
204 }
205
206 #[inline]
208 #[must_use]
209 pub fn total_npm(&self) -> u64 {
210 self.class_npm_sum() + self.interface_npm_sum()
211 }
212
213 #[inline]
215 #[must_use]
216 pub fn total_nm(&self) -> u64 {
217 self.class_nm_sum() + self.interface_nm_sum()
218 }
219
220 #[inline]
223 pub(crate) fn compute_sum(&mut self) {
224 self.class_npm_sum += self.class_npm;
225 self.interface_npm_sum += self.interface_npm;
226 self.class_nm_sum += self.class_nm;
227 self.interface_nm_sum += self.interface_nm;
228 }
229
230 #[inline]
237 pub(crate) fn set_space_kind(&mut self, kind: SpaceKind) {
238 self.space_kind = kind;
239 }
240
241 #[inline]
243 pub(crate) fn is_disabled(&self) -> bool {
244 !self.space_kind.is_member_scope()
245 }
246}
247
248fn direct_child_funcs<'a, C: Checker>(node: &Node<'a>) -> impl Iterator<Item = Node<'a>> {
258 node.children()
259 .filter(|child| C::is_func(child, Ancestors::unknown()))
260}
261
262#[doc(hidden)]
263pub(crate) trait Npm
265where
266 Self: Checker,
267{
268 const HAS_MEMBERS: bool = true;
278
279 fn compute<'a>(
297 node: &Node<'a>,
298 code: &'a [u8],
299 ancestors: Ancestors<'a, '_>,
300 stats: &mut Stats,
301 );
302}
303
304macro_rules! impl_npm_java_like {
322 ($code:ty, $lang:ident) => {
323 impl Npm for $code {
324 fn compute<'a>(
325 node: &Node<'a>,
326 _code: &'a [u8],
327 _ancestors: Ancestors<'a, '_>,
328 stats: &mut Stats,
329 ) {
330 use $lang::*;
331
332 match node.kind_id().into() {
333 ClassBody | EnumBodyDeclarations => {
334 for method in direct_child_funcs::<Self>(node) {
335 stats.class_nm += 1;
336 if let Some(modifiers) = method.child(0)
339 && matches!(modifiers.kind_id().into(), Modifiers)
340 && modifiers.first_child(|id| id == Public).is_some()
341 {
342 stats.class_npm += 1;
343 }
344 }
345 }
346 InterfaceBody => {
347 stats.interface_nm += direct_child_funcs::<Self>(node).count();
348 stats.interface_npm = stats.interface_nm;
349 }
350 AnnotationTypeBody => {
351 stats.interface_nm += node
352 .children()
353 .filter(|n| {
354 matches!(n.kind_id().into(), AnnotationTypeElementDeclaration)
355 })
356 .count();
357 stats.interface_npm = stats.interface_nm;
358 }
359 _ => {}
360 }
361 }
362 }
363 };
364}
365
366macro_rules! ts_npm_compute {
394 ($lang:ident) => {
395 fn compute<'a>(
396 node: &Node<'a>,
397 _code: &'a [u8],
398 _ancestors: Ancestors<'a, '_>,
399 stats: &mut Stats,
400 ) {
401 use $lang::*;
402
403 match node.kind_id().into() {
404 ClassBody => {
405 for member in node.children() {
406 match member.kind_id().into() {
407 MethodDefinition | AbstractMethodSignature => {
408 stats.class_nm += 1;
409 if ts_member_is_public!($lang, member) {
410 stats.class_npm += 1;
411 }
412 }
413 PublicFieldDefinition
416 if member
417 .first_child(|id| {
418 id == $lang::ArrowFunction
419 || id == $lang::FunctionExpression
420 })
421 .is_some() =>
422 {
423 stats.class_nm += 1;
424 if ts_member_is_public!($lang, member) {
425 stats.class_npm += 1;
426 }
427 }
428 _ => {}
429 }
430 }
431 }
432 InterfaceBody => {
433 let count = node
434 .children()
435 .filter(|c| {
436 matches!(
437 c.kind_id().into(),
438 MethodSignature | AbstractMethodSignature | ConstructSignature
439 )
440 })
441 .count();
442 stats.interface_nm += count;
443 stats.interface_npm = stats.interface_nm;
444 }
445 _ => {}
446 }
447 }
448 };
449}
450
451macro_rules! js_npm_compute {
468 ($lang:ident) => {
469 fn compute<'a>(
470 node: &Node<'a>,
471 _code: &'a [u8],
472 _ancestors: Ancestors<'a, '_>,
473 stats: &mut Stats,
474 ) {
475 use $lang::*;
476
477 if !matches!(node.kind_id().into(), ClassBody) {
478 return;
479 }
480
481 for member in node.children() {
482 match member.kind_id().into() {
483 MethodDefinition => {
484 stats.class_nm += 1;
485 stats.class_npm += 1;
486 }
487 FieldDefinition
488 if member
489 .first_child(|id| {
490 id == $lang::ArrowFunction || id == $lang::FunctionExpression
491 })
492 .is_some() =>
493 {
494 stats.class_nm += 1;
495 stats.class_npm += 1;
496 }
497 _ => {}
498 }
499 }
500 }
501 };
502}
503
504mod cpp;
509mod csharp;
510mod elixir;
511mod go;
512mod groovy;
513mod java;
514mod javascript;
515mod kotlin;
516mod mozcpp;
517mod mozjs;
518mod objc;
519mod php;
520mod python;
521mod ruby;
522mod rust;
523mod tsx;
524mod typescript;
525
526implement_metric_trait!(
532 Npm,
533 CCode,
534 PreprocCode,
535 CcommentCode,
536 PerlCode,
537 BashCode,
538 LuaCode,
539 TclCode,
540 IrulesCode
541);
542
543#[cfg(test)]
544#[allow(
545 clippy::float_cmp,
546 clippy::cast_precision_loss,
547 clippy::cast_possible_truncation,
548 clippy::cast_sign_loss,
549 clippy::similar_names,
550 clippy::doc_markdown,
551 clippy::needless_raw_string_hashes,
552 clippy::too_many_lines
553)]
554mod tests {
555 use crate::test_support::{
556 assert_child_space_kind, check_func_space_only_shim, check_metrics_only_shim, child_space,
557 };
558
559 use super::*;
560
561 check_metrics_only_shim!(check_metrics, Npm);
562 check_func_space_only_shim!(check_func_space, Npm);
563 check_metrics_only_shim!(check_metrics_with_nom_wmc, Npm, Nom, Wmc);
569 check_metrics_only_shim!(check_metrics_with_npa, Npm, Npa);
574
575 #[test]
576 fn java_constructors() {
577 check_metrics::<JavaParser>(
578 "class X {
579 X() {}
580 private X(int a) {}
581 protected X(int a, int b) {}
582 public X(int a, int b, int c) {} // +1
583 }",
584 "foo.java",
585 |metric| {
586 insta::assert_json_snapshot!(
587 metric.npm,
588 @r#"
589 {
590 "class_npm_sum": 1,
591 "interface_npm_sum": 0,
592 "class_methods": 4,
593 "interface_methods": 0,
594 "class_coa": 0.25,
595 "interface_coa": 0.0,
596 "total": 1,
597 "total_methods": 4,
598 "coa": 0.25
599 }
600 "#
601 );
602 },
603 );
604 }
605
606 #[test]
607 fn groovy_no_methods() {
608 check_metrics::<GroovyParser>("class A { int x = 1 }", "foo.groovy", |metric| {
609 assert_eq!(metric.npm.total_nm(), 0);
610 });
611 }
612
613 #[test]
614 fn groovy_public_methods() {
615 check_metrics::<GroovyParser>(
616 "class A {
617 public void m1() {}
618 public int m2() { return 0 }
619 private void m3() {}
620 }",
621 "foo.groovy",
622 |metric| {
623 assert_eq!(metric.npm.class_nm_sum(), 3);
624 assert_eq!(metric.npm.class_npm_sum(), 2);
625 },
626 );
627 }
628
629 #[test]
630 fn groovy_interface_methods_implicitly_public() {
631 check_func_space::<GroovyParser, _>(
638 "interface I {
639 void a()
640 int b()
641 }",
642 "foo.groovy",
643 |func_space| {
644 let metric = &func_space.metrics;
645 assert_eq!(metric.npm.interface_nm_sum(), 2);
647 assert_eq!(metric.npm.interface_npm_sum(), 2);
648 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
649 },
650 );
651 }
652
653 #[test]
656 fn groovy_enum_counts_methods() {
657 check_metrics::<GroovyParser>(
658 "enum Status {
659 ACTIVE, INACTIVE;
660 public int code() { return 0 }
661 private void reset() {}
662 }",
663 "foo.groovy",
664 |metric| {
665 assert_eq!(metric.npm.class_nm_sum(), 2);
666 assert_eq!(metric.npm.class_npm_sum(), 1);
667 },
668 );
669 }
670
671 #[test]
672 #[ignore = "dekobon Groovy grammar v1 does not support annotation type elements with `default` values; the trailing `default \"\"`/`default 0` make the body fail to parse"]
673 fn groovy_annotation_type_counts_elements() {
674 check_func_space::<GroovyParser, _>(
685 "public @interface Marker {
686 String value() default \"\";
687 int priority() default 0;
688 }",
689 "foo.groovy",
690 |func_space| {
691 assert_eq!(func_space.metrics.npm.interface_nm_sum(), 2);
692 assert_eq!(func_space.metrics.npm.interface_npm_sum(), 2);
693 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
694 },
695 );
696 }
697
698 #[test]
699 fn groovy_constructors() {
700 check_metrics::<GroovyParser>(
701 "class X {
702 X() {}
703 private X(int a) {}
704 protected X(int a, int b) {}
705 public X(int a, int b, int c) {}
706 }",
707 "foo.groovy",
708 |metric| {
709 assert_eq!(metric.npm.class_nm_sum(), 4);
711 assert_eq!(metric.npm.class_npm_sum(), 1);
712 },
713 );
714 }
715
716 #[test]
717 fn groovy_no_methods_in_unit_scope() {
718 check_metrics::<GroovyParser>("int x = 1", "foo.groovy", |metric| {
719 assert_eq!(metric.npm.total_nm(), 0);
720 });
721 }
722
723 #[test]
724 fn groovy_multiple_classes_methods() {
725 check_metrics::<GroovyParser>(
726 "class A { public void a() {} }
727 class B { public void b() {} }",
728 "foo.groovy",
729 |metric| {
730 assert_eq!(metric.npm.class_nm_sum(), 2);
731 assert_eq!(metric.npm.class_npm_sum(), 2);
732 },
733 );
734 }
735
736 #[test]
737 fn groovy_methods_returning_primitive_types() {
738 check_metrics::<GroovyParser>(
742 "class X {
743 public byte a() {}
744 public int b() {}
745 public double c() {}
746 public boolean d() {}
747 byte e() {}
748 int f() {}
749 }",
750 "foo.groovy",
751 |metric| {
752 assert_eq!(metric.npm.class_nm_sum(), 6);
754 assert_eq!(metric.npm.class_npm_sum(), 4);
755 },
756 );
757 }
758
759 #[test]
760 fn groovy_methods_with_generic_types() {
761 check_metrics::<GroovyParser>(
763 "class X {
764 public List<String> a() {}
765 public Map<String, Integer> b() {}
766 List<Integer> c() {}
767 }",
768 "foo.groovy",
769 |metric| {
770 assert_eq!(metric.npm.class_nm_sum(), 3);
771 assert_eq!(metric.npm.class_npm_sum(), 2);
772 },
773 );
774 }
775
776 #[test]
777 fn groovy_method_modifiers() {
778 check_metrics::<GroovyParser>(
782 "abstract class X {
783 public static void a() {}
784 static public void b() {}
785 public final void c() {}
786 final public void d() {}
787 protected static void e() {}
788 static protected void f() {}
789 abstract public void g()
790 abstract void h()
791 }",
792 "foo.groovy",
793 |metric| {
794 assert_eq!(metric.npm.class_nm_sum(), 8);
796 assert_eq!(metric.npm.class_npm_sum(), 5);
797 },
798 );
799 }
800
801 #[test]
802 #[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside class bodies"]
803 fn groovy_nested_inner_classes() {
804 check_metrics::<GroovyParser>(
807 "class X {
808 public void a() {}
809 class Y {
810 public void b() {}
811 class Z {
812 public void c() {}
813 }
814 }
815 }",
816 "foo.groovy",
817 |metric| {
818 assert_eq!(metric.npm.class_nm_sum(), 3);
820 assert_eq!(metric.npm.class_npm_sum(), 3);
821 },
822 );
823 }
824
825 #[test]
826 #[ignore = "dekobon Groovy grammar v1 does not yet support anonymous inner classes (`new T() { … }`)"]
827 fn groovy_anonymous_inner_class() {
828 check_metrics::<GroovyParser>(
831 "class X {
832 public Runnable r = new Runnable() {
833 public void run() {}
834 void helper() {}
835 }
836 }",
837 "foo.groovy",
838 |metric| {
839 assert_eq!(metric.npm.class_nm_sum(), 2);
842 assert_eq!(metric.npm.class_npm_sum(), 1);
843 },
844 );
845 }
846
847 #[test]
848 fn groovy_interfaces_and_class() {
849 check_func_space::<GroovyParser, _>(
855 "interface X {
856 void a()
857 }
858 interface Y extends X {
859 void b()
860 void c()
861 }
862 class Z implements Y {
863 public void a() {}
864 public void b() {}
865 public void c() {}
866 void d() {}
867 void e() {}
868 }",
869 "foo.groovy",
870 |func_space| {
871 let metric = &func_space.metrics;
872 assert_eq!(metric.npm.interface_nm_sum(), 3);
874 assert_eq!(metric.npm.interface_npm_sum(), 3);
875 assert_eq!(metric.npm.class_nm_sum(), 5);
878 assert_eq!(metric.npm.class_npm_sum(), 3);
879 assert_child_space_kind(&func_space, "X", SpaceKind::Interface);
880 assert_child_space_kind(&func_space, "Y", SpaceKind::Interface);
881 assert_child_space_kind(&func_space, "Z", SpaceKind::Class);
882 },
883 );
884 }
885
886 #[test]
887 fn java_methods_returning_primitive_types() {
888 check_metrics::<JavaParser>(
889 "class X {
890 public byte a() {} // +1
891 public short b() {} // +1
892 public int c() {} // +1
893 public long d() {} // +1
894 public float e() {} // +1
895 public double f() {} // +1
896 public boolean g() {} // +1
897 public char h() {} // +1
898 byte i() {}
899 short j() {}
900 int k() {}
901 long l() {}
902 float m() {}
903 double n() {}
904 boolean o() {}
905 char p() {}
906 }",
907 "foo.java",
908 |metric| {
909 insta::assert_json_snapshot!(
910 metric.npm,
911 @r#"
912 {
913 "class_npm_sum": 8,
914 "interface_npm_sum": 0,
915 "class_methods": 16,
916 "interface_methods": 0,
917 "class_coa": 0.5,
918 "interface_coa": 0.0,
919 "total": 8,
920 "total_methods": 16,
921 "coa": 0.5
922 }
923 "#
924 );
925 },
926 );
927 }
928
929 #[test]
930 fn java_methods_returning_arrays() {
931 check_metrics::<JavaParser>(
932 "class X {
933 public byte[] a() {} // +1
934 public short[] b() {} // +1
935 public int[] c() {} // +1
936 public long[] d() {} // +1
937 public float[] e() {} // +1
938 public double[] f() {} // +1
939 public boolean[] g() {} // +1
940 public char[] h() {} // +1
941 byte[] i() {}
942 short[] j() {}
943 int[] k() {}
944 long[] l() {}
945 float[] m() {}
946 double[] n() {}
947 boolean[] o() {}
948 char[] p() {}
949 }",
950 "foo.java",
951 |metric| {
952 insta::assert_json_snapshot!(
953 metric.npm,
954 @r#"
955 {
956 "class_npm_sum": 8,
957 "interface_npm_sum": 0,
958 "class_methods": 16,
959 "interface_methods": 0,
960 "class_coa": 0.5,
961 "interface_coa": 0.0,
962 "total": 8,
963 "total_methods": 16,
964 "coa": 0.5
965 }
966 "#
967 );
968 },
969 );
970 }
971
972 #[test]
973 fn java_methods_returning_objects() {
974 check_metrics::<JavaParser>(
975 "class X {
976 public Integer[] a() {} // +1
977 public Integer b() {} // +1
978 public String[] c() {} // +1
979 public String d() {} // +1
980 public Y[] e() {} // +1
981 public Y f() {} // +1
982 Integer[] g() {}
983 Integer h() {}
984 String[] i() {}
985 String j() {}
986 Y[] k() {}
987 Y l() {}
988 }",
989 "foo.java",
990 |metric| {
991 insta::assert_json_snapshot!(
992 metric.npm,
993 @r#"
994 {
995 "class_npm_sum": 6,
996 "interface_npm_sum": 0,
997 "class_methods": 12,
998 "interface_methods": 0,
999 "class_coa": 0.5,
1000 "interface_coa": 0.0,
1001 "total": 6,
1002 "total_methods": 12,
1003 "coa": 0.5
1004 }
1005 "#
1006 );
1007 },
1008 );
1009 }
1010
1011 #[test]
1012 fn java_methods_with_generic_types() {
1013 check_metrics::<JavaParser>(
1014 "class X {
1015 public <T, S extends T> void a(T x, S y) {} // +1
1016 public <T, S> int b(T x, S y) {} // +1
1017 public <T> boolean c(T x) {} // +1
1018 public <T> ArrayList<T> d() {} // +1
1019 public Y<String> e() {} // +1
1020 <T, S extends T> void f(T x, S y) {}
1021 <T, S> int g(T x, S y) {}
1022 <T> boolean h(T x) {}
1023 <T> ArrayList<T> i() {}
1024 Y<String> j() {}
1025 }",
1026 "foo.java",
1027 |metric| {
1028 insta::assert_json_snapshot!(
1029 metric.npm,
1030 @r#"
1031 {
1032 "class_npm_sum": 5,
1033 "interface_npm_sum": 0,
1034 "class_methods": 10,
1035 "interface_methods": 0,
1036 "class_coa": 0.5,
1037 "interface_coa": 0.0,
1038 "total": 5,
1039 "total_methods": 10,
1040 "coa": 0.5
1041 }
1042 "#
1043 );
1044 },
1045 );
1046 }
1047
1048 #[test]
1049 fn java_method_modifiers() {
1050 check_metrics::<JavaParser>(
1051 "abstract class X {
1052 public static final synchronized strictfp void a() {} // +1
1053 static public final synchronized strictfp void b() {} // +1
1054 static final public synchronized strictfp void c() {} // +1
1055 static final synchronized public strictfp void d() {} // +1
1056 static final synchronized strictfp public void e() {} // +1
1057 protected static final synchronized native void f();
1058 static protected final synchronized native void g();
1059 static final protected synchronized native void h();
1060 static final synchronized protected native void i();
1061 static final synchronized native protected void j();
1062 abstract public void k(); // +1
1063 abstract void l();
1064 }",
1065 "foo.java",
1066 |metric| {
1067 insta::assert_json_snapshot!(
1068 metric.npm,
1069 @r#"
1070 {
1071 "class_npm_sum": 6,
1072 "interface_npm_sum": 0,
1073 "class_methods": 12,
1074 "interface_methods": 0,
1075 "class_coa": 0.5,
1076 "interface_coa": 0.0,
1077 "total": 6,
1078 "total_methods": 12,
1079 "coa": 0.5
1080 }
1081 "#
1082 );
1083 },
1084 );
1085 }
1086
1087 #[test]
1088 fn java_classes() {
1089 check_metrics::<JavaParser>(
1090 "class X {
1091 public void a() {} // +1
1092 public void b() {} // +1
1093 private void c() {}
1094 }
1095 class Y {
1096 private void d() {}
1097 private void e() {}
1098 public void f() {} // +1
1099 }",
1100 "foo.java",
1101 |metric| {
1102 insta::assert_json_snapshot!(
1103 metric.npm,
1104 @r#"
1105 {
1106 "class_npm_sum": 3,
1107 "interface_npm_sum": 0,
1108 "class_methods": 6,
1109 "interface_methods": 0,
1110 "class_coa": 0.5,
1111 "interface_coa": 0.0,
1112 "total": 3,
1113 "total_methods": 6,
1114 "coa": 0.5
1115 }
1116 "#
1117 );
1118 },
1119 );
1120 }
1121
1122 #[test]
1123 fn java_nested_inner_classes() {
1124 check_metrics::<JavaParser>(
1125 "class X {
1126 public void a() {} // +1
1127 class Y {
1128 public void b() {} // +1
1129 class Z {
1130 public void c() {} // +1
1131 }
1132 }
1133 }",
1134 "foo.java",
1135 |metric| {
1136 insta::assert_json_snapshot!(
1137 metric.npm,
1138 @r#"
1139 {
1140 "class_npm_sum": 3,
1141 "interface_npm_sum": 0,
1142 "class_methods": 3,
1143 "interface_methods": 0,
1144 "class_coa": 1.0,
1145 "interface_coa": 0.0,
1146 "total": 3,
1147 "total_methods": 3,
1148 "coa": 1.0
1149 }
1150 "#
1151 );
1152 },
1153 );
1154 }
1155
1156 #[test]
1157 fn java_local_inner_classes() {
1158 check_metrics::<JavaParser>(
1159 "class X {
1160 public void a() { // +1
1161 class Y {
1162 public void b() { // +1
1163 class Z {
1164 public void c() {} // +1
1165 }
1166 }
1167 }
1168 }
1169 }",
1170 "foo.java",
1171 |metric| {
1172 insta::assert_json_snapshot!(
1173 metric.npm,
1174 @r#"
1175 {
1176 "class_npm_sum": 3,
1177 "interface_npm_sum": 0,
1178 "class_methods": 3,
1179 "interface_methods": 0,
1180 "class_coa": 1.0,
1181 "interface_coa": 0.0,
1182 "total": 3,
1183 "total_methods": 3,
1184 "coa": 1.0
1185 }
1186 "#
1187 );
1188 },
1189 );
1190 }
1191
1192 #[test]
1193 fn java_anonymous_inner_classes() {
1194 check_metrics::<JavaParser>(
1195 "abstract class X {
1196 public abstract void a(); // +1
1197 }
1198 abstract class Y {
1199 abstract void b();
1200 }
1201 class Z {
1202 public void c(){ // +1
1203 X x = new X() {
1204 @Override
1205 public void a() {} // +1
1206 };
1207 Y y = new Y() {
1208 @Override
1209 void b() {}
1210 };
1211 }
1212 }",
1213 "foo.java",
1214 |metric| {
1215 insta::assert_json_snapshot!(
1216 metric.npm,
1217 @r#"
1218 {
1219 "class_npm_sum": 3,
1220 "interface_npm_sum": 0,
1221 "class_methods": 5,
1222 "interface_methods": 0,
1223 "class_coa": 0.6,
1224 "interface_coa": 0.0,
1225 "total": 3,
1226 "total_methods": 5,
1227 "coa": 0.6
1228 }
1229 "#
1230 );
1231 },
1232 );
1233 }
1234
1235 #[test]
1236 fn java_interface() {
1237 check_metrics::<JavaParser>(
1238 "interface X {
1239 public int a(); // +1
1240 boolean b(); // +1
1241 void c(); // +1
1242 }",
1243 "foo.java",
1244 |metric| {
1245 insta::assert_json_snapshot!(
1246 metric.npm,
1247 @r#"
1248 {
1249 "class_npm_sum": 0,
1250 "interface_npm_sum": 3,
1251 "class_methods": 0,
1252 "interface_methods": 3,
1253 "class_coa": 0.0,
1254 "interface_coa": 1.0,
1255 "total": 3,
1256 "total_methods": 3,
1257 "coa": 1.0
1258 }
1259 "#
1260 );
1261 },
1262 );
1263 }
1264
1265 #[test]
1269 fn java_enum_counts_methods() {
1270 check_metrics::<JavaParser>(
1271 "enum Status {
1272 ACTIVE, INACTIVE;
1273 public int code() { return 0; } // +1 public
1274 private void reset() {} // not public
1275 }",
1276 "foo.java",
1277 |metric| {
1278 assert_eq!(metric.npm.class_nm_sum(), 2);
1279 assert_eq!(metric.npm.class_npm_sum(), 1);
1280 },
1281 );
1282 }
1283
1284 #[test]
1287 fn java_record_counts_methods() {
1288 check_metrics::<JavaParser>(
1289 "record Point(int x, int y) {
1290 public int sum() { return x + y; }
1291 public Point() { this(0, 0); }
1292 }",
1293 "foo.java",
1294 |metric| {
1295 assert_eq!(metric.npm.class_nm_sum(), 2);
1300 assert_eq!(metric.npm.class_npm_sum(), 2);
1301 },
1302 );
1303 }
1304
1305 #[test]
1316 fn java_record_counts_a_compact_constructor_as_a_method() {
1317 check_metrics::<JavaParser>(
1318 "record R(int a, int b) {
1319 public R { }
1320 private int half() { return a / 2; }
1321 public int sum() { return a + b; }
1322 }",
1323 "foo.java",
1324 |metric| {
1325 assert_eq!(metric.npm.class_nm_sum(), 3);
1330 assert_eq!(metric.npm.class_npm_sum(), 2);
1331 },
1332 );
1333 }
1334
1335 #[test]
1336 fn java_annotation_type_counts_elements() {
1337 check_func_space::<JavaParser, _>(
1347 "@interface Marker {
1348 String value() default \"\";
1349 int priority() default 0;
1350 }",
1351 "foo.java",
1352 |func_space| {
1353 assert_eq!(func_space.metrics.npm.interface_nm_sum(), 2);
1354 assert_eq!(func_space.metrics.npm.interface_npm_sum(), 2);
1355 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
1356 },
1357 );
1358 }
1359
1360 #[test]
1361 fn java_interfaces_and_class() {
1362 check_metrics::<JavaParser>(
1363 "interface X {
1364 void a(); // +1
1365 }
1366 interface Y extends X {
1367 void b(); // +1
1368 void c(); // +1
1369 }
1370 class Z implements Y {
1371 @Override
1372 public void a() {} // +1
1373 @Override
1374 public void b() {} // +1
1375 @Override
1376 public void c() {} // +1
1377 void d() {}
1378 void e() {}
1379 }",
1380 "foo.java",
1381 |metric| {
1382 insta::assert_json_snapshot!(
1383 metric.npm,
1384 @r#"
1385 {
1386 "class_npm_sum": 3,
1387 "interface_npm_sum": 3,
1388 "class_methods": 5,
1389 "interface_methods": 3,
1390 "class_coa": 0.6,
1391 "interface_coa": 1.0,
1392 "total": 6,
1393 "total_methods": 8,
1394 "coa": 0.75
1395 }
1396 "#
1397 );
1398 },
1399 );
1400 }
1401
1402 #[test]
1403 fn csharp_constructors() {
1404 check_metrics::<CsharpParser>(
1405 "class A {
1406 public A() {}
1407 public A(int x) {}
1408 A(int x, int y) {}
1409 }",
1410 "foo.cs",
1411 |metric| insta::assert_json_snapshot!(metric.npm),
1412 );
1413 }
1414
1415 #[test]
1416 fn csharp_methods_returning_primitive_types() {
1417 check_metrics::<CsharpParser>(
1418 "class A {
1419 public int M1() { return 1; }
1420 public bool M2() { return true; }
1421 public double M3() { return 0.0; }
1422 int M4() { return 0; }
1423 }",
1424 "foo.cs",
1425 |metric| insta::assert_json_snapshot!(metric.npm),
1426 );
1427 }
1428
1429 #[test]
1430 fn csharp_methods_returning_arrays() {
1431 check_metrics::<CsharpParser>(
1432 "class A {
1433 public int[] M1() { return new int[0]; }
1434 public string[] M2() { return new string[0]; }
1435 int[] M3() { return new int[0]; }
1436 }",
1437 "foo.cs",
1438 |metric| insta::assert_json_snapshot!(metric.npm),
1439 );
1440 }
1441
1442 #[test]
1443 fn csharp_methods_returning_objects() {
1444 check_metrics::<CsharpParser>(
1445 "class Point { }
1446 class A {
1447 public Point M1() { return new Point(); }
1448 public string M2() { return \"\"; }
1449 Point M3() { return new Point(); }
1450 }",
1451 "foo.cs",
1452 |metric| insta::assert_json_snapshot!(metric.npm),
1453 );
1454 }
1455
1456 #[test]
1457 fn csharp_methods_with_generic_types() {
1458 check_metrics::<CsharpParser>(
1459 "class A {
1460 public System.Collections.Generic.List<int> M1() { return null; }
1461 public System.Collections.Generic.Dictionary<string, int> M2() { return null; }
1462 System.Collections.Generic.List<string> M3() { return null; }
1463 }",
1464 "foo.cs",
1465 |metric| insta::assert_json_snapshot!(metric.npm),
1466 );
1467 }
1468
1469 #[test]
1470 fn csharp_method_modifiers() {
1471 check_metrics::<CsharpParser>(
1472 "class A {
1473 public void M1() {}
1474 private void M2() {}
1475 protected void M3() {}
1476 internal void M4() {}
1477 public static void M5() {}
1478 public virtual void M6() {}
1479 }",
1480 "foo.cs",
1481 |metric| insta::assert_json_snapshot!(metric.npm),
1482 );
1483 }
1484
1485 #[test]
1486 fn csharp_classes() {
1487 check_metrics::<CsharpParser>(
1488 "class A {
1489 public void M1() {}
1490 public void M2() {}
1491 void M3() {}
1492 }
1493 class B {
1494 public int N() { return 0; }
1495 int Hidden() { return 0; }
1496 }",
1497 "foo.cs",
1498 |metric| insta::assert_json_snapshot!(metric.npm),
1499 );
1500 }
1501
1502 #[test]
1503 fn csharp_nested_inner_classes() {
1504 check_metrics::<CsharpParser>(
1505 "class Outer {
1506 public void M() {}
1507 void Hidden() {}
1508 public class Inner {
1509 public void N() {}
1510 void HiddenN() {}
1511 }
1512 }",
1513 "foo.cs",
1514 |metric| insta::assert_json_snapshot!(metric.npm),
1515 );
1516 }
1517
1518 #[test]
1519 fn csharp_property_accessors() {
1520 check_metrics::<CsharpParser>(
1525 "class A {
1526 int _w;
1527 public int X { get; set; }
1528 public int Y { get; }
1529 public int Z { get; init; }
1530 public int W => _w;
1531 int Hidden { get; set; }
1532 }",
1533 "foo.cs",
1534 |metric| insta::assert_json_snapshot!(metric.npm),
1535 );
1536 }
1537
1538 #[test]
1539 fn csharp_narrowed_accessor_visibility() {
1540 check_metrics::<CsharpParser>(
1553 "class A {
1554 public int X { get; private set; }
1555 public int this[int i] { get; protected set; }
1556 public int Y { get; set; }
1557 public int W { get; }
1558 public int Z => 0;
1559 int P { get; set; }
1560 }",
1561 "foo.cs",
1562 |metric| {
1563 assert_eq!(metric.npm.class_nm_sum(), 10, "all accessors count as nm");
1564 assert_eq!(
1565 metric.npm.class_npm_sum(),
1566 6,
1567 "narrowed private/protected accessors are not public methods"
1568 );
1569 insta::assert_json_snapshot!(metric.npm);
1570 },
1571 );
1572 }
1573
1574 #[test]
1575 fn csharp_local_functions() {
1576 check_metrics::<CsharpParser>(
1583 "class A {
1584 public void Outer() {
1585 void Local() {}
1586 Local();
1587 }
1588 private void Hidden() {}
1589 }",
1590 "foo.cs",
1591 |metric| {
1592 assert_eq!(metric.npm.class_nm_sum(), 2, "Local must not leak");
1593 assert_eq!(metric.npm.class_npm_sum(), 1, "only Outer is public");
1594 insta::assert_json_snapshot!(metric.npm);
1595 },
1596 );
1597 }
1598
1599 #[test]
1600 fn csharp_interface() {
1601 check_metrics::<CsharpParser>(
1603 "interface I {
1604 int M1();
1605 bool M2();
1606 int X { get; set; }
1607 }",
1608 "foo.cs",
1609 |metric| insta::assert_json_snapshot!(metric.npm),
1610 );
1611 }
1612
1613 #[test]
1614 fn csharp_interfaces_and_class() {
1615 check_metrics::<CsharpParser>(
1616 "interface I1 { int M1(); }
1617 interface I2 { bool M2(); float M3(); }
1618 class A {
1619 public void M() {}
1620 void Hidden() {}
1621 }",
1622 "foo.cs",
1623 |metric| insta::assert_json_snapshot!(metric.npm),
1624 );
1625 }
1626
1627 #[test]
1628 fn php_no_class_methods() {
1629 check_metrics::<PhpParser>(
1630 "<?php class A { public int $x = 0; }",
1631 "foo.php",
1632 |metric| insta::assert_json_snapshot!(metric.npm),
1633 );
1634 }
1635
1636 #[test]
1637 fn php_one_public_method() {
1638 check_metrics::<PhpParser>(
1639 "<?php class A { public function f(): void {} }",
1640 "foo.php",
1641 |metric| insta::assert_json_snapshot!(metric.npm),
1642 );
1643 }
1644
1645 #[test]
1646 fn php_one_private_method() {
1647 check_metrics::<PhpParser>(
1648 "<?php class A { private function f(): void {} }",
1649 "foo.php",
1650 |metric| insta::assert_json_snapshot!(metric.npm),
1651 );
1652 }
1653
1654 #[test]
1655 fn php_one_protected_method() {
1656 check_metrics::<PhpParser>(
1657 "<?php class A { protected function f(): void {} }",
1658 "foo.php",
1659 |metric| insta::assert_json_snapshot!(metric.npm),
1660 );
1661 }
1662
1663 #[test]
1664 fn php_mixed_visibility_methods() {
1665 check_metrics::<PhpParser>(
1666 "<?php
1667 class A {
1668 public function a(): void {}
1669 public function b(): void {}
1670 private function c(): void {}
1671 protected function d(): void {}
1672 }",
1673 "foo.php",
1674 |metric| insta::assert_json_snapshot!(metric.npm),
1675 );
1676 }
1677
1678 #[test]
1679 fn php_static_public_method() {
1680 check_metrics::<PhpParser>(
1681 "<?php class A { public static function f(): void {} }",
1682 "foo.php",
1683 |metric| insta::assert_json_snapshot!(metric.npm),
1684 );
1685 }
1686
1687 #[test]
1688 fn php_abstract_method() {
1689 check_metrics::<PhpParser>(
1690 "<?php abstract class A { abstract public function f(): void; }",
1691 "foo.php",
1692 |metric| insta::assert_json_snapshot!(metric.npm),
1693 );
1694 }
1695
1696 #[test]
1697 fn php_final_public_method() {
1698 check_metrics::<PhpParser>(
1699 "<?php class A { final public function f(): void {} }",
1700 "foo.php",
1701 |metric| insta::assert_json_snapshot!(metric.npm),
1702 );
1703 }
1704
1705 #[test]
1706 fn php_interface_methods() {
1707 check_metrics::<PhpParser>(
1709 "<?php
1710 interface I {
1711 public function a(): void;
1712 public function b(): int;
1713 }",
1714 "foo.php",
1715 |metric| insta::assert_json_snapshot!(metric.npm),
1716 );
1717 }
1718
1719 #[test]
1720 fn php_enum_methods() {
1721 check_metrics::<PhpParser>(
1723 "<?php
1724 enum Color {
1725 case Red;
1726 case Green;
1727 public function label(): string {
1728 return match ($this) {
1729 Color::Red => 'r',
1730 Color::Green => 'g',
1731 };
1732 }
1733 }",
1734 "foo.php",
1735 |metric| insta::assert_json_snapshot!(metric.npm),
1736 );
1737 }
1738
1739 #[test]
1740 fn php_trait_methods() {
1741 check_metrics::<PhpParser>(
1742 "<?php
1743 trait T {
1744 public function a(): void {}
1745 private function b(): void {}
1746 }",
1747 "foo.php",
1748 |metric| insta::assert_json_snapshot!(metric.npm),
1749 );
1750 }
1751
1752 #[test]
1753 fn php_no_explicit_visibility_method_excluded() {
1754 check_metrics::<PhpParser>(
1757 "<?php class A { function f(): void {} }",
1758 "foo.php",
1759 |metric| insta::assert_json_snapshot!(metric.npm),
1760 );
1761 }
1762
1763 #[test]
1766 fn kotlin_empty_class_no_methods() {
1767 check_metrics::<KotlinParser>("class C {}", "foo.kt", |metric| {
1768 assert_eq!(metric.npm.class_npm_sum(), 0);
1769 assert_eq!(metric.npm.class_nm_sum(), 0);
1770 assert_eq!(metric.npm.interface_nm_sum(), 0);
1771 insta::assert_json_snapshot!(metric.npm);
1772 });
1773 }
1774
1775 #[test]
1776 fn kotlin_public_methods_default() {
1777 check_metrics::<KotlinParser>(
1779 "class C {
1780 fun a() {}
1781 fun b(): Int = 0
1782 fun c(x: Int): Int = x
1783 }",
1784 "foo.kt",
1785 |metric| {
1786 assert_eq!(metric.npm.class_npm_sum(), 3);
1787 assert_eq!(metric.npm.class_nm_sum(), 3);
1788 insta::assert_json_snapshot!(metric.npm);
1789 },
1790 );
1791 }
1792
1793 #[test]
1794 fn kotlin_private_method() {
1795 check_metrics::<KotlinParser>(
1796 "class C {
1797 fun a() {} // public
1798 private fun b() {} // private
1799 fun c() {} // public
1800 }",
1801 "foo.kt",
1802 |metric| {
1803 assert_eq!(metric.npm.class_npm_sum(), 2);
1804 assert_eq!(metric.npm.class_nm_sum(), 3);
1805 insta::assert_json_snapshot!(metric.npm);
1806 },
1807 );
1808 }
1809
1810 #[test]
1811 fn kotlin_protected_internal_methods() {
1812 check_metrics::<KotlinParser>(
1813 "open class C {
1814 protected fun a() {}
1815 internal fun b() {}
1816 public fun c() {}
1817 }",
1818 "foo.kt",
1819 |metric| {
1820 assert_eq!(metric.npm.class_npm_sum(), 1);
1821 assert_eq!(metric.npm.class_nm_sum(), 3);
1822 insta::assert_json_snapshot!(metric.npm);
1823 },
1824 );
1825 }
1826
1827 #[test]
1828 fn kotlin_secondary_constructor_counts() {
1829 check_metrics::<KotlinParser>(
1832 "class C {
1833 private var a: Int = 0
1834 constructor(n: Int) { a = n }
1835 constructor(n: Int, m: Int) { a = n + m }
1836 fun get(): Int = a
1837 }",
1838 "foo.kt",
1839 |metric| {
1840 assert_eq!(metric.npm.class_npm_sum(), 3);
1841 assert_eq!(metric.npm.class_nm_sum(), 3);
1842 insta::assert_json_snapshot!(metric.npm);
1843 },
1844 );
1845 }
1846
1847 #[test]
1848 fn kotlin_companion_object_methods() {
1849 check_metrics::<KotlinParser>(
1852 "class Holder {
1853 fun memberFn() {}
1854 companion object {
1855 fun staticFn() {}
1856 private fun secret() {}
1857 }
1858 }",
1859 "foo.kt",
1860 |metric| {
1861 assert_eq!(metric.npm.class_npm_sum(), 2);
1862 assert_eq!(metric.npm.class_nm_sum(), 3);
1863 insta::assert_json_snapshot!(metric.npm);
1864 },
1865 );
1866 }
1867
1868 #[test]
1869 fn kotlin_data_class_methods() {
1870 check_metrics::<KotlinParser>(
1873 "data class Point(val x: Int, val y: Int) {
1874 fun manhattan(): Int = x + y
1875 private fun internal_(): Int = 0
1876 }",
1877 "foo.kt",
1878 |metric| {
1879 assert_eq!(metric.npm.class_npm_sum(), 1);
1880 assert_eq!(metric.npm.class_nm_sum(), 2);
1881 insta::assert_json_snapshot!(metric.npm);
1882 },
1883 );
1884 }
1885
1886 #[test]
1887 fn kotlin_object_singleton_methods() {
1888 check_metrics::<KotlinParser>(
1889 "object Util {
1890 fun add(a: Int, b: Int): Int = a + b
1891 private fun helper(): Int = 0
1892 }",
1893 "foo.kt",
1894 |metric| {
1895 assert_eq!(metric.npm.class_npm_sum(), 1);
1896 assert_eq!(metric.npm.class_nm_sum(), 2);
1897 insta::assert_json_snapshot!(metric.npm);
1898 },
1899 );
1900 }
1901
1902 #[test]
1903 fn kotlin_interface_methods() {
1904 check_func_space::<KotlinParser, _>(
1905 "interface I {
1906 fun work(): Int
1907 fun describe(): String
1908 }",
1909 "foo.kt",
1910 |func_space| {
1911 let metric = &func_space.metrics;
1912 assert_eq!(metric.npm.interface_npm_sum(), 2);
1913 assert_eq!(metric.npm.interface_nm_sum(), 2);
1914 assert_eq!(metric.npm.class_nm_sum(), 0);
1915 insta::assert_json_snapshot!(metric.npm);
1916 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
1917 },
1918 );
1919 }
1920
1921 #[test]
1922 fn kotlin_interface_with_default_method() {
1923 check_func_space::<KotlinParser, _>(
1924 "interface I {
1925 fun abs(n: Int): Int {
1926 return if (n < 0) -n else n
1927 }
1928 fun pure(): Int
1929 }",
1930 "foo.kt",
1931 |func_space| {
1932 let metric = &func_space.metrics;
1933 assert_eq!(metric.npm.interface_npm_sum(), 2);
1934 assert_eq!(metric.npm.interface_nm_sum(), 2);
1935 insta::assert_json_snapshot!(metric.npm);
1936 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
1937 },
1938 );
1939 }
1940
1941 #[test]
1942 fn kotlin_override_fun_counts() {
1943 check_metrics::<KotlinParser>(
1944 "open class Base {
1945 open fun greet(): String = \"hi\"
1946 }
1947 class Sub : Base() {
1948 override fun greet(): String = \"yo\"
1949 private fun secret() {}
1950 }",
1951 "foo.kt",
1952 |metric| {
1953 assert_eq!(metric.npm.class_npm_sum(), 2);
1957 assert_eq!(metric.npm.class_nm_sum(), 3);
1958 insta::assert_json_snapshot!(metric.npm);
1959 },
1960 );
1961 }
1962
1963 #[test]
1964 fn kotlin_nested_class_methods() {
1965 check_metrics::<KotlinParser>(
1966 "class Outer {
1967 fun outerM() {}
1968 class Nested {
1969 fun nestedM() {}
1970 private fun nestedSecret() {}
1971 }
1972 }",
1973 "foo.kt",
1974 |metric| {
1975 assert_eq!(metric.npm.class_npm_sum(), 2);
1976 assert_eq!(metric.npm.class_nm_sum(), 3);
1977 insta::assert_json_snapshot!(metric.npm);
1978 },
1979 );
1980 }
1981
1982 #[test]
1983 fn kotlin_inner_class_methods() {
1984 check_metrics::<KotlinParser>(
1985 "class Outer {
1986 fun outerM() {}
1987 inner class Inner {
1988 fun innerM() {}
1989 }
1990 }",
1991 "foo.kt",
1992 |metric| {
1993 assert_eq!(metric.npm.class_npm_sum(), 2);
1994 assert_eq!(metric.npm.class_nm_sum(), 2);
1995 insta::assert_json_snapshot!(metric.npm);
1996 },
1997 );
1998 }
1999
2000 #[test]
2001 fn kotlin_top_level_function_excluded() {
2002 check_metrics::<KotlinParser>(
2004 "fun freeFn() {}
2005class C {
2006 fun m() {}
2007}",
2008 "foo.kt",
2009 |metric| {
2010 assert_eq!(metric.npm.class_npm_sum(), 1);
2011 assert_eq!(metric.npm.class_nm_sum(), 1);
2012 insta::assert_json_snapshot!(metric.npm);
2013 },
2014 );
2015 }
2016
2017 #[test]
2018 fn kotlin_extension_function_excluded() {
2019 check_metrics::<KotlinParser>(
2022 "fun List<Int>.sum2(): Int = this.size
2023class C {
2024 fun m() {}
2025}",
2026 "foo.kt",
2027 |metric| {
2028 assert_eq!(metric.npm.class_npm_sum(), 1);
2029 assert_eq!(metric.npm.class_nm_sum(), 1);
2030 insta::assert_json_snapshot!(metric.npm);
2031 },
2032 );
2033 }
2034
2035 #[test]
2036 fn kotlin_class_in_interface() {
2037 check_func_space::<KotlinParser, _>(
2042 "interface Outer {
2043 fun work(): Int
2044 class Helper {
2045 fun help() {}
2046 }
2047 }",
2048 "foo.kt",
2049 |func_space| {
2050 let metric = &func_space.metrics;
2051 assert_eq!(metric.npm.interface_npm_sum(), 1);
2052 assert_eq!(metric.npm.class_npm_sum(), 1);
2053 insta::assert_json_snapshot!(metric.npm);
2054 assert_child_space_kind(&func_space, "Outer", SpaceKind::Interface);
2055 let outer = func_space
2056 .spaces
2057 .iter()
2058 .find(|s| s.name.as_deref() == Some("Outer"))
2059 .expect("Outer FuncSpace");
2060 assert_child_space_kind(outer, "Helper", SpaceKind::Class);
2061 },
2062 );
2063 }
2064
2065 #[test]
2066 fn kotlin_interface_in_class() {
2067 check_func_space::<KotlinParser, _>(
2072 "class Outer {
2073 fun work() {}
2074 interface Sub {
2075 fun help(): Int
2076 }
2077 }",
2078 "foo.kt",
2079 |func_space| {
2080 let metric = &func_space.metrics;
2081 assert_eq!(metric.npm.class_npm_sum(), 1);
2082 assert_eq!(metric.npm.interface_npm_sum(), 1);
2083 insta::assert_json_snapshot!(metric.npm);
2084 assert_child_space_kind(&func_space, "Outer", SpaceKind::Class);
2085 let outer = func_space
2086 .spaces
2087 .iter()
2088 .find(|s| s.name.as_deref() == Some("Outer"))
2089 .expect("Outer FuncSpace");
2090 assert_child_space_kind(outer, "Sub", SpaceKind::Interface);
2091 },
2092 );
2093 }
2094
2095 #[test]
2096 fn kotlin_init_block_not_a_method() {
2097 check_metrics::<KotlinParser>(
2100 "class C(val n: Int) {
2101 init { require(n >= 0) }
2102 fun get(): Int = n
2103 }",
2104 "foo.kt",
2105 |metric| {
2106 assert_eq!(metric.npm.class_npm_sum(), 1);
2107 assert_eq!(metric.npm.class_nm_sum(), 1);
2108 insta::assert_json_snapshot!(metric.npm);
2109 },
2110 );
2111 }
2112
2113 #[test]
2129 fn typescript_empty_class_no_methods() {
2130 check_metrics::<TypescriptParser>("class C {}", "foo.ts", |metric| {
2131 assert_eq!(metric.npm.class_npm_sum(), 0);
2132 assert_eq!(metric.npm.class_nm_sum(), 0);
2133 insta::assert_json_snapshot!(metric.npm);
2134 });
2135 }
2136
2137 #[test]
2138 fn typescript_default_public_methods() {
2139 check_metrics::<TypescriptParser>(
2140 "class C {
2141 a(): void {}
2142 b(): number { return 0; }
2143 c(x: number): number { return x; }
2144 }",
2145 "foo.ts",
2146 |metric| {
2147 assert_eq!(metric.npm.class_npm_sum(), 3);
2148 assert_eq!(metric.npm.class_nm_sum(), 3);
2149 insta::assert_json_snapshot!(metric.npm);
2150 },
2151 );
2152 }
2153
2154 #[test]
2155 fn typescript_method_visibility() {
2156 check_metrics::<TypescriptParser>(
2157 "class C {
2158 public a(): void {}
2159 private b(): void {}
2160 protected c(): void {}
2161 d(): void {}
2162 }",
2163 "foo.ts",
2164 |metric| {
2165 assert_eq!(metric.npm.class_npm_sum(), 2);
2167 assert_eq!(metric.npm.class_nm_sum(), 4);
2168 insta::assert_json_snapshot!(metric.npm);
2169 },
2170 );
2171 }
2172
2173 #[test]
2174 fn typescript_static_methods() {
2175 check_metrics::<TypescriptParser>(
2176 "class C {
2177 static a(): void {}
2178 public static b(): void {}
2179 private static c(): void {}
2180 }",
2181 "foo.ts",
2182 |metric| {
2183 assert_eq!(metric.npm.class_npm_sum(), 2);
2185 assert_eq!(metric.npm.class_nm_sum(), 3);
2186 insta::assert_json_snapshot!(metric.npm);
2187 },
2188 );
2189 }
2190
2191 #[test]
2192 fn typescript_constructor_counts_as_method() {
2193 check_metrics::<TypescriptParser>(
2195 "class C {
2196 constructor(public x: number) {}
2197 m(): void {}
2198 }",
2199 "foo.ts",
2200 |metric| {
2201 assert_eq!(metric.npm.class_npm_sum(), 2);
2202 assert_eq!(metric.npm.class_nm_sum(), 2);
2203 insta::assert_json_snapshot!(metric.npm);
2204 },
2205 );
2206 }
2207
2208 #[test]
2209 fn typescript_getter_setter_each_count_once() {
2210 check_metrics::<TypescriptParser>(
2213 "class C {
2214 private _x: number = 0;
2215 get x(): number { return this._x; }
2216 set x(v: number) { this._x = v; }
2217 }",
2218 "foo.ts",
2219 |metric| {
2220 assert_eq!(metric.npm.class_npm_sum(), 2);
2221 assert_eq!(metric.npm.class_nm_sum(), 2);
2222 insta::assert_json_snapshot!(metric.npm);
2223 },
2224 );
2225 }
2226
2227 #[test]
2228 fn typescript_arrow_field_counts_as_method() {
2229 check_metrics::<TypescriptParser>(
2231 "class C {
2232 a: number = 0;
2233 arrow = () => this.a;
2234 private secret = () => this.a;
2235 }",
2236 "foo.ts",
2237 |metric| {
2238 assert_eq!(metric.npm.class_npm_sum(), 1);
2240 assert_eq!(metric.npm.class_nm_sum(), 2);
2241 insta::assert_json_snapshot!(metric.npm);
2242 },
2243 );
2244 }
2245
2246 #[test]
2247 fn typescript_method_overload_counts_once() {
2248 check_metrics::<TypescriptParser>(
2251 "class C {
2252 m(x: number): void;
2253 m(x: string): void;
2254 m(x: any): void {}
2255 }",
2256 "foo.ts",
2257 |metric| {
2258 assert_eq!(metric.npm.class_npm_sum(), 1);
2259 assert_eq!(metric.npm.class_nm_sum(), 1);
2260 insta::assert_json_snapshot!(metric.npm);
2261 },
2262 );
2263 }
2264
2265 #[test]
2266 fn typescript_abstract_class_methods() {
2267 check_metrics::<TypescriptParser>(
2270 "abstract class C {
2271 abstract a(): void;
2272 public abstract b(): number;
2273 protected abstract c(): void;
2274 public m(): void {}
2275 private n(): void {}
2276 }",
2277 "foo.ts",
2278 |metric| {
2279 assert_eq!(metric.npm.class_npm_sum(), 3);
2282 assert_eq!(metric.npm.class_nm_sum(), 5);
2283 insta::assert_json_snapshot!(metric.npm);
2284 },
2285 );
2286 }
2287
2288 #[test]
2289 fn typescript_interface_methods() {
2290 check_func_space::<TypescriptParser, _>(
2292 "interface I {
2293 a(): void;
2294 b(x: number): number;
2295 c: string;
2296 }",
2297 "foo.ts",
2298 |func_space| {
2299 let metric = &func_space.metrics;
2300 assert_eq!(metric.npm.interface_npm_sum(), 2);
2301 assert_eq!(metric.npm.interface_nm_sum(), 2);
2302 assert_eq!(metric.npm.class_nm_sum(), 0);
2303 insta::assert_json_snapshot!(metric.npm);
2304 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2305 },
2306 );
2307 }
2308
2309 #[test]
2310 fn typescript_generic_class_methods() {
2311 check_metrics::<TypescriptParser>(
2312 "class Box<T> {
2313 value: T;
2314 set(v: T): void { this.value = v; }
2315 get(): T { return this.value; }
2316 }",
2317 "foo.ts",
2318 |metric| {
2319 assert_eq!(metric.npm.class_npm_sum(), 2);
2320 assert_eq!(metric.npm.class_nm_sum(), 2);
2321 insta::assert_json_snapshot!(metric.npm);
2322 },
2323 );
2324 }
2325
2326 #[test]
2327 fn typescript_multiple_classes_and_interface() {
2328 check_func_space::<TypescriptParser, _>(
2329 "class A { m(): void {} }
2330 class B { private h(): void {} }
2331 interface I { p(): number; }",
2332 "foo.ts",
2333 |func_space| {
2334 let metric = &func_space.metrics;
2335 assert_eq!(metric.npm.class_npm_sum(), 1);
2336 assert_eq!(metric.npm.class_nm_sum(), 2);
2337 assert_eq!(metric.npm.interface_npm_sum(), 1);
2338 assert_eq!(metric.npm.interface_nm_sum(), 1);
2339 insta::assert_json_snapshot!(metric.npm);
2340 assert_child_space_kind(&func_space, "A", SpaceKind::Class);
2341 assert_child_space_kind(&func_space, "B", SpaceKind::Class);
2342 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2343 },
2344 );
2345 }
2346
2347 #[test]
2350 fn tsx_empty_class_no_methods() {
2351 check_metrics::<TsxParser>("class C {}", "foo.tsx", |metric| {
2352 assert_eq!(metric.npm.class_npm_sum(), 0);
2353 assert_eq!(metric.npm.class_nm_sum(), 0);
2354 insta::assert_json_snapshot!(metric.npm);
2355 });
2356 }
2357
2358 #[test]
2359 fn tsx_default_public_methods() {
2360 check_metrics::<TsxParser>(
2361 "class C {
2362 a(): void {}
2363 b(): number { return 0; }
2364 }",
2365 "foo.tsx",
2366 |metric| {
2367 assert_eq!(metric.npm.class_npm_sum(), 2);
2368 assert_eq!(metric.npm.class_nm_sum(), 2);
2369 insta::assert_json_snapshot!(metric.npm);
2370 },
2371 );
2372 }
2373
2374 #[test]
2375 fn tsx_method_visibility() {
2376 check_metrics::<TsxParser>(
2377 "class C {
2378 public a(): void {}
2379 private b(): void {}
2380 protected c(): void {}
2381 }",
2382 "foo.tsx",
2383 |metric| {
2384 assert_eq!(metric.npm.class_npm_sum(), 1);
2385 assert_eq!(metric.npm.class_nm_sum(), 3);
2386 insta::assert_json_snapshot!(metric.npm);
2387 },
2388 );
2389 }
2390
2391 #[test]
2392 fn tsx_static_methods() {
2393 check_metrics::<TsxParser>(
2394 "class C {
2395 static a(): void {}
2396 private static b(): void {}
2397 }",
2398 "foo.tsx",
2399 |metric| {
2400 assert_eq!(metric.npm.class_npm_sum(), 1);
2401 assert_eq!(metric.npm.class_nm_sum(), 2);
2402 insta::assert_json_snapshot!(metric.npm);
2403 },
2404 );
2405 }
2406
2407 #[test]
2408 fn tsx_constructor_counts_as_method() {
2409 check_metrics::<TsxParser>(
2410 "class C {
2411 constructor() {}
2412 m(): void {}
2413 }",
2414 "foo.tsx",
2415 |metric| {
2416 assert_eq!(metric.npm.class_npm_sum(), 2);
2417 assert_eq!(metric.npm.class_nm_sum(), 2);
2418 insta::assert_json_snapshot!(metric.npm);
2419 },
2420 );
2421 }
2422
2423 #[test]
2424 fn tsx_getter_setter_each_count_once() {
2425 check_metrics::<TsxParser>(
2426 "class C {
2427 private _x: number = 0;
2428 get x(): number { return this._x; }
2429 set x(v: number) { this._x = v; }
2430 }",
2431 "foo.tsx",
2432 |metric| {
2433 assert_eq!(metric.npm.class_npm_sum(), 2);
2434 assert_eq!(metric.npm.class_nm_sum(), 2);
2435 insta::assert_json_snapshot!(metric.npm);
2436 },
2437 );
2438 }
2439
2440 #[test]
2441 fn tsx_arrow_field_counts_as_method() {
2442 check_metrics::<TsxParser>(
2443 "class C {
2444 arrow = () => 1;
2445 private secret = () => 2;
2446 }",
2447 "foo.tsx",
2448 |metric| {
2449 assert_eq!(metric.npm.class_npm_sum(), 1);
2450 assert_eq!(metric.npm.class_nm_sum(), 2);
2451 insta::assert_json_snapshot!(metric.npm);
2452 },
2453 );
2454 }
2455
2456 #[test]
2457 fn tsx_method_overload_counts_once() {
2458 check_metrics::<TsxParser>(
2459 "class C {
2460 m(x: number): void;
2461 m(x: string): void;
2462 m(x: any): void {}
2463 }",
2464 "foo.tsx",
2465 |metric| {
2466 assert_eq!(metric.npm.class_npm_sum(), 1);
2467 assert_eq!(metric.npm.class_nm_sum(), 1);
2468 insta::assert_json_snapshot!(metric.npm);
2469 },
2470 );
2471 }
2472
2473 #[test]
2474 fn tsx_abstract_class_methods() {
2475 check_metrics::<TsxParser>(
2476 "abstract class C {
2477 abstract a(): void;
2478 public m(): void {}
2479 private n(): void {}
2480 }",
2481 "foo.tsx",
2482 |metric| {
2483 assert_eq!(metric.npm.class_npm_sum(), 2);
2485 assert_eq!(metric.npm.class_nm_sum(), 3);
2486 insta::assert_json_snapshot!(metric.npm);
2487 },
2488 );
2489 }
2490
2491 #[test]
2492 fn tsx_interface_methods() {
2493 check_func_space::<TsxParser, _>(
2494 "interface I {
2495 a(): void;
2496 b(): number;
2497 }",
2498 "foo.tsx",
2499 |func_space| {
2500 let metric = &func_space.metrics;
2501 assert_eq!(metric.npm.interface_npm_sum(), 2);
2502 assert_eq!(metric.npm.interface_nm_sum(), 2);
2503 insta::assert_json_snapshot!(metric.npm);
2504 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2505 },
2506 );
2507 }
2508
2509 #[test]
2510 fn tsx_generic_class_methods() {
2511 check_metrics::<TsxParser>(
2512 "class Box<T> { value: T; set(v: T): void { this.value = v; } }",
2513 "foo.tsx",
2514 |metric| {
2515 assert_eq!(metric.npm.class_npm_sum(), 1);
2516 assert_eq!(metric.npm.class_nm_sum(), 1);
2517 insta::assert_json_snapshot!(metric.npm);
2518 },
2519 );
2520 }
2521
2522 #[test]
2523 fn tsx_multiple_classes_and_interface() {
2524 check_func_space::<TsxParser, _>(
2525 "class A { m(): void {} }
2526 class B { private h(): void {} }
2527 interface I { p(): number; }",
2528 "foo.tsx",
2529 |func_space| {
2530 let metric = &func_space.metrics;
2531 assert_eq!(metric.npm.class_npm_sum(), 1);
2532 assert_eq!(metric.npm.class_nm_sum(), 2);
2533 assert_eq!(metric.npm.interface_npm_sum(), 1);
2534 assert_eq!(metric.npm.interface_nm_sum(), 1);
2535 insta::assert_json_snapshot!(metric.npm);
2536 assert_child_space_kind(&func_space, "A", SpaceKind::Class);
2537 assert_child_space_kind(&func_space, "B", SpaceKind::Class);
2538 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2539 },
2540 );
2541 }
2542
2543 #[test]
2552 fn ruby_no_class_methods() {
2553 check_metrics::<RubyParser>("def foo\n 1\nend\n", "foo.rb", |metric| {
2554 assert_eq!(metric.npm.class_npm_sum(), 0);
2555 assert_eq!(metric.npm.class_nm_sum(), 0);
2556 insta::assert_json_snapshot!(metric.npm);
2557 });
2558 }
2559
2560 #[test]
2561 fn ruby_one_public_method() {
2562 check_metrics::<RubyParser>(
2564 "class A\n def f\n 1\n end\nend\n",
2565 "foo.rb",
2566 |metric| {
2567 assert_eq!(metric.npm.class_npm_sum(), 1);
2568 assert_eq!(metric.npm.class_nm_sum(), 1);
2569 insta::assert_json_snapshot!(metric.npm);
2570 },
2571 );
2572 }
2573
2574 #[test]
2575 fn ruby_one_private_method() {
2576 check_metrics::<RubyParser>(
2578 "class A\n private\n def f\n 1\n end\nend\n",
2579 "foo.rb",
2580 |metric| {
2581 assert_eq!(metric.npm.class_npm_sum(), 0);
2582 assert_eq!(metric.npm.class_nm_sum(), 1);
2583 insta::assert_json_snapshot!(metric.npm);
2584 },
2585 );
2586 }
2587
2588 #[test]
2589 fn ruby_one_protected_method() {
2590 check_metrics::<RubyParser>(
2591 "class A\n protected\n def f\n 1\n end\nend\n",
2592 "foo.rb",
2593 |metric| {
2594 assert_eq!(metric.npm.class_npm_sum(), 0);
2595 assert_eq!(metric.npm.class_nm_sum(), 1);
2596 insta::assert_json_snapshot!(metric.npm);
2597 },
2598 );
2599 }
2600
2601 #[test]
2602 fn ruby_mixed_visibility_methods() {
2603 check_metrics::<RubyParser>(
2607 "class A\n def a\n 1\n end\n private\n def b\n 1\n end\n public\n def c\n 1\n end\n protected\n def d\n 1\n end\nend\n",
2608 "foo.rb",
2609 |metric| {
2610 assert_eq!(metric.npm.class_npm_sum(), 2);
2611 assert_eq!(metric.npm.class_nm_sum(), 4);
2612 insta::assert_json_snapshot!(metric.npm);
2613 },
2614 );
2615 }
2616
2617 #[test]
2618 fn ruby_singleton_method_is_counted() {
2619 check_metrics::<RubyParser>(
2621 "class A\n def self.f\n 1\n end\n def g\n 1\n end\nend\n",
2622 "foo.rb",
2623 |metric| {
2624 assert_eq!(metric.npm.class_npm_sum(), 2);
2625 assert_eq!(metric.npm.class_nm_sum(), 2);
2626 insta::assert_json_snapshot!(metric.npm);
2627 },
2628 );
2629 }
2630
2631 #[test]
2632 fn ruby_singleton_class_methods() {
2633 check_metrics::<RubyParser>(
2636 "class A\n class << self\n def s\n 1\n end\n def t\n 2\n end\n end\nend\n",
2637 "foo.rb",
2638 |metric| {
2639 assert_eq!(metric.npm.class_npm_sum(), 2);
2640 assert_eq!(metric.npm.class_nm_sum(), 2);
2641 insta::assert_json_snapshot!(metric.npm);
2642 },
2643 );
2644 }
2645
2646 #[test]
2647 fn ruby_argument_form_visibility_does_not_flip() {
2648 check_metrics::<RubyParser>(
2652 "class A\n def y\n 1\n end\n private :y\n def z\n 1\n end\nend\n",
2653 "foo.rb",
2654 |metric| {
2655 assert_eq!(metric.npm.class_npm_sum(), 2);
2656 assert_eq!(metric.npm.class_nm_sum(), 2);
2657 insta::assert_json_snapshot!(metric.npm);
2658 },
2659 );
2660 }
2661
2662 #[test]
2663 fn ruby_multiple_classes() {
2664 check_metrics::<RubyParser>(
2665 "class A\n def a\n 1\n end\nend\nclass B\n private\n def b\n 1\n end\n def c\n 1\n end\nend\n",
2666 "foo.rb",
2667 |metric| {
2668 assert_eq!(metric.npm.class_npm_sum(), 1);
2670 assert_eq!(metric.npm.class_nm_sum(), 3);
2671 insta::assert_json_snapshot!(metric.npm);
2672 },
2673 );
2674 }
2675
2676 #[test]
2677 fn ruby_module_methods_not_counted() {
2678 check_metrics::<RubyParser>(
2681 "module M\n def f\n 1\n end\n def g\n 1\n end\nend\n",
2682 "foo.rb",
2683 |metric| {
2684 assert_eq!(metric.npm.class_npm_sum(), 0);
2685 assert_eq!(metric.npm.class_nm_sum(), 0);
2686 insta::assert_json_snapshot!(metric.npm);
2687 },
2688 );
2689 }
2690
2691 #[test]
2692 fn ruby_class_with_inheritance() {
2693 check_metrics::<RubyParser>(
2695 "class A < B\n def f\n 1\n end\n def g\n 1\n end\nend\n",
2696 "foo.rb",
2697 |metric| {
2698 assert_eq!(metric.npm.class_npm_sum(), 2);
2699 assert_eq!(metric.npm.class_nm_sum(), 2);
2700 insta::assert_json_snapshot!(metric.npm);
2701 },
2702 );
2703 }
2704
2705 #[test]
2706 fn ruby_visibility_resets_between_classes() {
2707 check_metrics::<RubyParser>(
2710 "class A\n private\n def a\n 1\n end\nend\nclass B\n def b\n 1\n end\nend\n",
2711 "foo.rb",
2712 |metric| {
2713 assert_eq!(metric.npm.class_npm_sum(), 1);
2715 assert_eq!(metric.npm.class_nm_sum(), 2);
2716 insta::assert_json_snapshot!(metric.npm);
2717 },
2718 );
2719 }
2720
2721 #[test]
2722 fn ruby_empty_class_no_methods() {
2723 check_metrics::<RubyParser>("class Empty\nend\n", "foo.rb", |metric| {
2724 assert_eq!(metric.npm.class_npm_sum(), 0);
2725 assert_eq!(metric.npm.class_nm_sum(), 0);
2726 insta::assert_json_snapshot!(metric.npm);
2727 });
2728 }
2729
2730 #[test]
2743 fn python_empty_class_no_methods() {
2744 check_metrics::<PythonParser>("class C:\n pass\n", "foo.py", |metric| {
2745 assert_eq!(metric.npm.class_nm_sum(), 0);
2746 assert_eq!(metric.npm.class_npm_sum(), 0);
2747 insta::assert_json_snapshot!(metric.npm);
2748 });
2749 }
2750
2751 #[test]
2752 fn python_class_methods_count() {
2753 check_metrics::<PythonParser>(
2755 "class C:\n\
2756 \x20 def __init__(self):\n\
2757 \x20 pass\n\
2758 \x20 def m(self):\n\
2759 \x20 pass\n\
2760 \x20 def n(self):\n\
2761 \x20 pass\n",
2762 "foo.py",
2763 |metric| {
2764 assert_eq!(metric.npm.class_nm_sum(), 3);
2765 assert_eq!(metric.npm.class_npm_sum(), 3);
2766 insta::assert_json_snapshot!(metric.npm);
2767 },
2768 );
2769 }
2770
2771 #[test]
2772 fn python_decorated_methods_count() {
2773 check_metrics::<PythonParser>(
2777 "class C:\n\
2778 \x20 @property\n\
2779 \x20 def p(self):\n\
2780 \x20 return 1\n\
2781 \x20 @staticmethod\n\
2782 \x20 def s():\n\
2783 \x20 return 2\n\
2784 \x20 @classmethod\n\
2785 \x20 def c(cls):\n\
2786 \x20 return 3\n",
2787 "foo.py",
2788 |metric| {
2789 assert_eq!(metric.npm.class_nm_sum(), 3);
2790 insta::assert_json_snapshot!(metric.npm);
2791 },
2792 );
2793 }
2794
2795 #[test]
2796 fn python_async_method_counts() {
2797 check_metrics::<PythonParser>(
2800 "class C:\n async def m(self):\n return 1\n",
2801 "foo.py",
2802 |metric| {
2803 assert_eq!(metric.npm.class_nm_sum(), 1);
2804 insta::assert_json_snapshot!(metric.npm);
2805 },
2806 );
2807 }
2808
2809 #[test]
2810 fn python_nested_class_methods_independent() {
2811 check_metrics::<PythonParser>(
2814 "class Outer:\n\
2815 \x20 def method(self):\n\
2816 \x20 pass\n\
2817 \x20 class Inner:\n\
2818 \x20 def inner_method(self):\n\
2819 \x20 pass\n",
2820 "foo.py",
2821 |metric| {
2822 assert_eq!(metric.npm.class_nm_sum(), 2);
2823 insta::assert_json_snapshot!(metric.npm);
2824 },
2825 );
2826 }
2827
2828 #[test]
2829 fn python_module_level_function_is_not_method() {
2830 check_metrics::<PythonParser>(
2833 "def f():\n pass\nclass C:\n def m(self):\n pass\n",
2834 "foo.py",
2835 |metric| {
2836 assert_eq!(metric.npm.class_nm_sum(), 1);
2838 insta::assert_json_snapshot!(metric.npm);
2839 },
2840 );
2841 }
2842
2843 #[test]
2844 fn python_dunder_methods_count() {
2845 check_metrics::<PythonParser>(
2848 "class C:\n\
2849 \x20 def __init__(self):\n\
2850 \x20 pass\n\
2851 \x20 def __repr__(self):\n\
2852 \x20 return 'C'\n\
2853 \x20 def __eq__(self, other):\n\
2854 \x20 return True\n",
2855 "foo.py",
2856 |metric| {
2857 assert_eq!(metric.npm.class_nm_sum(), 3);
2858 assert_eq!(metric.npm.class_npm_sum(), 3);
2859 insta::assert_json_snapshot!(metric.npm);
2860 },
2861 );
2862 }
2863
2864 #[test]
2865 fn rust_empty_unit_no_methods() {
2866 check_metrics::<RustParser>("", "empty.rs", |metric| {
2867 assert_eq!(metric.npm.class_nm_sum(), 0);
2868 assert_eq!(metric.npm.class_npm_sum(), 0);
2869 assert_eq!(metric.npm.interface_nm_sum(), 0);
2870 assert_eq!(metric.npm.interface_npm_sum(), 0);
2871 insta::assert_json_snapshot!(metric.npm);
2872 });
2873 }
2874
2875 #[test]
2876 fn rust_impl_methods_count() {
2877 check_metrics::<RustParser>(
2880 "struct Foo;\n\
2881 impl Foo {\n\
2882 \x20 pub fn new() -> Self { Foo }\n\
2883 \x20 fn helper(&self) -> i32 { 0 }\n\
2884 \x20 pub fn process(&self) -> i32 { 0 }\n\
2885 }\n",
2886 "foo.rs",
2887 |metric| {
2888 assert_eq!(metric.npm.class_nm_sum(), 3);
2889 assert_eq!(metric.npm.class_npm_sum(), 2);
2890 insta::assert_json_snapshot!(metric.npm);
2891 },
2892 );
2893 }
2894
2895 #[test]
2896 fn rust_pub_self_is_private() {
2897 check_metrics::<RustParser>(
2905 "struct S;\n\
2906 impl S {\n\
2907 \x20 pub(self) fn a(&self) {}\n\
2908 \x20 pub(in self) fn a2(&self) {}\n\
2909 \x20 pub(crate) fn b(&self) {}\n\
2910 \x20 pub(super) fn d(&self) {}\n\
2911 \x20 pub(in crate::x) fn e(&self) {}\n\
2912 \x20 pub fn f(&self) {}\n\
2913 \x20 fn c(&self) {}\n\
2914 }\n",
2915 "foo.rs",
2916 |metric| {
2917 assert_eq!(metric.npm.class_nm_sum(), 7);
2918 assert_eq!(metric.npm.class_npm_sum(), 4);
2919 },
2920 );
2921 }
2922
2923 #[test]
2924 fn rust_trait_methods_count() {
2925 check_func_space::<RustParser, _>(
2932 "trait Drawable {\n\
2933 \x20 fn draw(&self);\n\
2934 \x20 fn area(&self) -> f64 { 0.0 }\n\
2935 }\n",
2936 "foo.rs",
2937 |func_space| {
2938 let metric = &func_space.metrics;
2939 assert_eq!(metric.npm.interface_nm_sum(), 2);
2940 assert_eq!(metric.npm.interface_npm_sum(), 2);
2941 assert_eq!(metric.npm.class_nm_sum(), 0);
2942 insta::assert_json_snapshot!(metric.npm);
2943 assert_child_space_kind(&func_space, "Drawable", SpaceKind::Trait);
2944 },
2945 );
2946 }
2947
2948 #[test]
2949 fn rust_module_level_function_not_method() {
2950 check_metrics::<RustParser>("fn f() {}\nfn g() {}\n", "foo.rs", |metric| {
2954 assert_eq!(metric.npm.class_nm_sum(), 0);
2955 assert_eq!(metric.npm.interface_nm_sum(), 0);
2956 insta::assert_json_snapshot!(metric.npm);
2957 });
2958 }
2959
2960 #[test]
2961 fn rust_multiple_impls_methods_aggregate() {
2962 check_metrics::<RustParser>(
2964 "struct Foo;\n\
2965 impl Foo { pub fn m1(&self) {} }\n\
2966 impl Foo { fn m2(&self) {} }\n",
2967 "foo.rs",
2968 |metric| {
2969 assert_eq!(metric.npm.class_nm_sum(), 2);
2970 assert_eq!(metric.npm.class_npm_sum(), 1);
2971 insta::assert_json_snapshot!(metric.npm);
2972 },
2973 );
2974 }
2975
2976 #[test]
2977 fn rust_trait_impl_block_counts_methods() {
2978 check_func_space::<RustParser, _>(
2985 "struct Foo;\n\
2986 trait Drawable { fn draw(&self); }\n\
2987 impl Drawable for Foo { fn draw(&self) {} }\n",
2988 "foo.rs",
2989 |func_space| {
2990 let metric = &func_space.metrics;
2991 assert_eq!(metric.npm.interface_nm_sum(), 1);
2994 assert_eq!(metric.npm.class_nm_sum(), 1);
2995 insta::assert_json_snapshot!(metric.npm);
2996 assert_child_space_kind(&func_space, "Drawable", SpaceKind::Trait);
2997 },
2998 );
2999 }
3000
3001 #[test]
3004 fn go_empty_unit_no_methods() {
3005 check_metrics::<GoParser>("package main\n", "empty.go", |metric| {
3007 assert_eq!(metric.npm.class_nm_sum(), 0);
3008 insta::assert_json_snapshot!(metric.npm);
3009 });
3010 }
3011
3012 #[test]
3013 fn go_method_declarations_count() {
3014 check_metrics::<GoParser>(
3018 "package main\n\
3019 type Foo struct{}\n\
3020 func (f Foo) DoX() {}\n\
3021 func (f Foo) doY() {}\n",
3022 "foo.go",
3023 |metric| {
3024 assert_eq!(metric.npm.class_nm_sum(), 2);
3025 assert_eq!(metric.npm.class_npm_sum(), 1);
3026 insta::assert_json_snapshot!(metric.npm);
3027 },
3028 );
3029 }
3030
3031 #[test]
3032 fn go_free_function_is_not_method() {
3033 check_metrics::<GoParser>(
3037 "package main\nfunc g() {}\nfunc h(x int) int { return x }\n",
3038 "foo.go",
3039 |metric| {
3040 assert_eq!(metric.npm.class_nm_sum(), 0);
3041 insta::assert_json_snapshot!(metric.npm);
3042 },
3043 );
3044 }
3045
3046 #[test]
3047 fn go_methods_on_different_receivers_aggregate_at_unit() {
3048 check_metrics::<GoParser>(
3052 "package main\n\
3053 type Foo struct{}\n\
3054 type Bar struct{}\n\
3055 func (f Foo) M1() {}\n\
3056 func (b Bar) M2() {}\n\
3057 func (b *Bar) M3() {}\n",
3058 "foo.go",
3059 |metric| {
3060 assert_eq!(metric.npm.class_nm_sum(), 3);
3061 insta::assert_json_snapshot!(metric.npm);
3062 },
3063 );
3064 }
3065
3066 #[test]
3067 fn go_interface_methods_count_as_interface_nm() {
3068 check_metrics::<GoParser>(
3083 "package main\ntype RC interface { Read() error; Close() error }\n",
3084 "foo.go",
3085 |metric| {
3086 assert_eq!(metric.npm.interface_nm_sum(), 2);
3087 assert_eq!(metric.npm.interface_npm_sum(), 2);
3088 assert_eq!(metric.npm.class_nm_sum(), 0);
3089 insta::assert_json_snapshot!(metric.npm);
3090 },
3091 );
3092 }
3093
3094 #[test]
3095 fn go_interface_methods_respect_export() {
3096 check_metrics::<GoParser>(
3102 "package main\ntype I interface { Foo(); bar(); Ünic() }\n",
3103 "foo.go",
3104 |metric| {
3105 assert_eq!(metric.npm.interface_nm_sum(), 3);
3106 assert_eq!(metric.npm.interface_npm_sum(), 2);
3107 assert_eq!(metric.npm.class_nm_sum(), 0);
3108 insta::assert_json_snapshot!(metric.npm);
3109 },
3110 );
3111 }
3112
3113 #[test]
3114 fn go_pointer_receiver_methods_count() {
3115 check_metrics::<GoParser>(
3119 "package main\n\
3120 type Foo struct{}\n\
3121 func (f *Foo) Set() {}\n\
3122 func (f *Foo) Get() int { return 0 }\n",
3123 "foo.go",
3124 |metric| {
3125 assert_eq!(metric.npm.class_nm_sum(), 2);
3126 insta::assert_json_snapshot!(metric.npm);
3127 },
3128 );
3129 }
3130
3131 #[test]
3132 fn go_npm_excludes_unexported() {
3133 check_metrics::<GoParser>(
3139 "package main\n\
3140 type T struct{}\n\
3141 func (t *T) Greet() {}\n\
3142 func (t *T) helper() {}\n\
3143 func (t *T) Ärger() {}\n",
3144 "foo.go",
3145 |metric| {
3146 assert_eq!(metric.npm.class_nm_sum(), 3);
3147 assert_eq!(metric.npm.class_npm_sum(), 2);
3148 insta::assert_json_snapshot!(metric.npm);
3149 },
3150 );
3151 }
3152
3153 #[test]
3158 fn elixir_npm_def_is_public_defp_is_private() {
3159 check_metrics::<ElixirParser>(
3160 "defmodule Foo do\n def pub_one, do: 1\n defp priv_one, do: 1\n def pub_two(x), do: x\nend\n",
3161 "foo.ex",
3162 |metric| {
3163 assert_eq!(metric.npm.class_nm_sum(), 3);
3165 assert_eq!(metric.npm.class_npm_sum(), 2);
3166 },
3167 );
3168 }
3169
3170 #[test]
3171 fn elixir_npm_defmacro_counts_as_public() {
3172 check_metrics::<ElixirParser>(
3173 "defmodule Foo do\n defmacro pub_macro(x), do: x\n defmacrop priv_macro(x), do: x\nend\n",
3174 "foo.ex",
3175 |metric| {
3176 assert_eq!(metric.npm.class_nm_sum(), 2);
3178 assert_eq!(metric.npm.class_npm_sum(), 1);
3179 },
3180 );
3181 }
3182
3183 #[test]
3184 fn elixir_npm_multiple_def_clauses_each_count() {
3185 check_metrics::<ElixirParser>(
3187 "defmodule Foo do\n def f(0), do: :zero\n def f(_), do: :other\nend\n",
3188 "foo.ex",
3189 |metric| {
3190 assert_eq!(metric.npm.class_nm_sum(), 2);
3191 assert_eq!(metric.npm.class_npm_sum(), 2);
3192 },
3193 );
3194 }
3195
3196 #[test]
3197 fn elixir_npm_nested_defmodule_each_class() {
3198 check_metrics::<ElixirParser>(
3199 "defmodule Outer do\n def o, do: 1\n defmodule Inner do\n def i, do: 1\n end\nend\n",
3200 "foo.ex",
3201 |metric| {
3202 assert_eq!(metric.npm.class_nm_sum(), 2);
3204 assert_eq!(metric.npm.class_npm_sum(), 2);
3205 },
3206 );
3207 }
3208
3209 #[test]
3210 fn elixir_npm_user_macro_not_classified_as_method() {
3211 check_metrics::<ElixirParser>(
3215 "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",
3216 "foo.ex",
3217 |metric| {
3218 assert_eq!(metric.npm.class_nm_sum(), 1);
3223 assert_eq!(metric.npm.class_npm_sum(), 1);
3224 },
3225 );
3226 }
3227
3228 #[test]
3229 fn elixir_npm_quoted_defs_do_not_inflate_method_count() {
3230 check_metrics::<ElixirParser>(
3238 "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",
3239 "foo.ex",
3240 |metric| {
3241 assert_eq!(metric.npm.class_nm_sum(), 1);
3243 assert_eq!(metric.npm.class_npm_sum(), 1);
3244 },
3245 );
3246 }
3247
3248 #[test]
3266 fn elixir_npm_counts_a_quoted_defmodule_as_a_class() {
3267 check_metrics::<ElixirParser>(
3268 "defmodule Outer do\n defmacro gen do\n quote do\n defmodule Inner do\n def a, do: 1\n defp b, do: 2\n end\n end\n end\nend\n",
3269 "outer.ex",
3270 |metric| {
3271 assert_eq!(metric.npm.class_nm_sum(), 3);
3274 assert_eq!(metric.npm.class_npm_sum(), 2);
3275 },
3276 );
3277 }
3278
3279 #[test]
3282 fn objc_npm() {
3283 check_metrics::<ObjcParser>(
3290 "@interface Foo : NSObject\n\
3291 - (void)pub1;\n\
3292 - (void)pub2;\n\
3293 @end\n\
3294 @implementation Foo\n\
3295 - (void)pub1 { }\n\
3296 - (void)pub2 { }\n\
3297 - (void)privHelper { }\n\
3298 void cFunc(void) { }\n\
3299 @end\n",
3300 "foo.m",
3301 |metric| {
3302 assert_eq!(metric.npm.interface_nm_sum(), 2);
3303 assert_eq!(metric.npm.interface_npm_sum(), 2);
3304 assert_eq!(metric.npm.class_nm_sum(), 3);
3305 assert_eq!(metric.npm.class_npm_sum(), 3);
3306 },
3307 );
3308 }
3309
3310 #[test]
3311 fn objc_npm_protocol() {
3312 check_metrics::<ObjcParser>(
3317 "@protocol Drawable <NSObject>\n\
3318 - (void)draw;\n\
3319 @optional\n\
3320 - (void)optDraw;\n\
3321 @end\n",
3322 "foo.m",
3323 |metric| {
3324 assert_eq!(metric.npm.interface_nm_sum(), 2);
3325 assert_eq!(metric.npm.interface_npm_sum(), 2);
3326 },
3327 );
3328 }
3329
3330 #[test]
3333 fn cpp_empty_unit_no_methods() {
3334 check_metrics::<CppParser>("", "empty.cpp", |metric| {
3336 assert_eq!(metric.npm.class_nm_sum(), 0);
3337 assert_eq!(metric.npm.class_npm_sum(), 0);
3338 insta::assert_json_snapshot!(metric.npm);
3339 });
3340 }
3341
3342 #[test]
3343 fn cpp_class_methods_count() {
3344 check_metrics::<CppParser>(
3347 "class Foo {\n\
3348 void method1() {}\n\
3349 void method2();\n\
3350 };",
3351 "foo.cpp",
3352 |metric| {
3353 assert_eq!(metric.npm.class_nm_sum(), 2);
3354 assert_eq!(metric.npm.class_npm_sum(), 0);
3355 insta::assert_json_snapshot!(metric.npm);
3356 },
3357 );
3358 }
3359
3360 #[test]
3361 fn cpp_constructors_and_destructors_count() {
3362 check_metrics::<CppParser>(
3366 "class Foo {\n\
3367 public:\n\
3368 Foo();\n\
3369 ~Foo();\n\
3370 void method();\n\
3371 };",
3372 "foo.cpp",
3373 |metric| {
3374 assert_eq!(metric.npm.class_nm_sum(), 3);
3375 assert_eq!(metric.npm.class_npm_sum(), 3);
3376 insta::assert_json_snapshot!(metric.npm);
3377 },
3378 );
3379 }
3380
3381 #[test]
3382 fn cpp_template_methods_count() {
3383 check_metrics::<CppParser>(
3387 "class Foo {\n\
3388 public:\n\
3389 template<typename T> T fn(T x);\n\
3390 };",
3391 "foo.cpp",
3392 |metric| {
3393 assert_eq!(metric.npm.class_nm_sum(), 1);
3394 assert_eq!(metric.npm.class_npm_sum(), 1);
3395 insta::assert_json_snapshot!(metric.npm);
3396 },
3397 );
3398 }
3399
3400 #[test]
3401 fn cpp_struct_methods_default_public() {
3402 check_metrics::<CppParser>(
3405 "struct Foo {\n\
3406 void a();\n\
3407 void b() {}\n\
3408 Foo() {}\n\
3409 };",
3410 "foo.cpp",
3411 |metric| {
3412 assert_eq!(metric.npm.class_nm_sum(), 3);
3413 assert_eq!(metric.npm.class_npm_sum(), 3);
3414 insta::assert_json_snapshot!(metric.npm);
3415 },
3416 );
3417 }
3418
3419 #[test]
3420 fn cpp_free_function_is_not_method() {
3421 check_metrics::<CppParser>("void free_fn() {}\n", "foo.cpp", |metric| {
3425 assert_eq!(metric.npm.class_nm_sum(), 0);
3426 assert_eq!(metric.npm.class_npm_sum(), 0);
3427 insta::assert_json_snapshot!(metric.npm);
3428 });
3429 }
3430
3431 #[test]
3432 fn cpp_mixed_visibility_methods() {
3433 check_metrics::<CppParser>(
3437 "class Foo {\n\
3438 public: void a();\n\
3439 protected: void b();\n\
3440 private: void c();\n\
3441 };",
3442 "foo.cpp",
3443 |metric| {
3444 assert_eq!(metric.npm.class_nm_sum(), 3);
3445 assert_eq!(metric.npm.class_npm_sum(), 1);
3446 insta::assert_json_snapshot!(metric.npm);
3447 },
3448 );
3449 }
3450
3451 #[test]
3452 fn cpp_multiple_classes_aggregate_at_unit() {
3453 check_metrics::<CppParser>(
3456 "class Foo { public: void a(); void b() {} };\n\
3457 struct Bar { void c(); };",
3458 "foo.cpp",
3459 |metric| {
3460 assert_eq!(metric.npm.class_nm_sum(), 3);
3461 assert_eq!(metric.npm.class_npm_sum(), 3);
3462 insta::assert_json_snapshot!(metric.npm);
3463 },
3464 );
3465 }
3466
3467 const TEMPLATE_METHOD_WITH_BODY: &str = "class C {\n\
3473 public:\n\
3474 template<typename T> T get() { return T{}; }\n\
3475 int plain() { return 1; }\n\
3476 };";
3477
3478 const CONVERSION_OPERATORS_WITHOUT_BODIES: &str = "class C {\n\
3495 public:\n\
3496 operator float();\n\
3497 template<typename T> operator T();\n\
3498 int width;\n\
3499 private:\n\
3500 operator double();\n\
3501 };";
3502
3503 const NON_METHOD_TEMPLATE_PAYLOADS: &str = "class C {\n\
3528 public:\n\
3529 template<typename T> class Nested { void hidden() {} };\n\
3530 template<typename T> using Alias = T;\n\
3531 template<typename T> static T value;\n\
3532 template<typename T> friend void amigo() {}\n\
3533 template<typename T> T real() { return T{}; }\n\
3534 };";
3535
3536 #[test]
3537 fn cpp_template_method_with_inline_body_counts() {
3538 check_metrics_with_nom_wmc::<CppParser>(TEMPLATE_METHOD_WITH_BODY, "foo.cpp", |metric| {
3546 assert_eq!(metric.npm.class_nm_sum(), 2);
3547 assert_eq!(metric.npm.class_npm_sum(), 2);
3548 assert_eq!(metric.nom.functions_sum(), 2);
3551 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3552 });
3553 }
3554
3555 #[test]
3556 fn cpp_template_method_with_inline_body_respects_visibility() {
3557 check_metrics_with_nom_wmc::<CppParser>(
3562 "class C {\n\
3563 public:\n\
3564 template<typename T> T a() { return T{}; }\n\
3565 template<typename T> T b() { return T{}; }\n\
3566 private:\n\
3567 template<typename T> T c() { return T{}; }\n\
3568 };",
3569 "foo.cpp",
3570 |metric| {
3571 assert_eq!(metric.npm.class_nm_sum(), 3);
3572 assert_eq!(metric.npm.class_npm_sum(), 2);
3573 assert_eq!(metric.nom.functions_sum(), 3);
3574 },
3575 );
3576 }
3577
3578 #[test]
3579 fn cpp_template_conversion_operator_with_body_counts() {
3580 check_metrics_with_nom_wmc::<CppParser>(
3589 "class C {\n\
3590 public:\n\
3591 template<typename T> operator T() { return T{}; }\n\
3592 };",
3593 "foo.cpp",
3594 |metric| {
3595 assert_eq!(metric.npm.class_nm_sum(), 1);
3596 assert_eq!(metric.npm.class_npm_sum(), 1);
3597 assert_eq!(metric.nom.functions_sum(), 1);
3598 },
3599 );
3600 }
3601
3602 #[test]
3603 fn cpp_conversion_operators_without_bodies_count_as_methods() {
3604 check_metrics_with_npa::<CppParser>(
3605 CONVERSION_OPERATORS_WITHOUT_BODIES,
3606 "foo.cpp",
3607 |metric| {
3608 assert_eq!(metric.npm.class_nm_sum(), 3);
3609 assert_eq!(metric.npm.class_npm_sum(), 2);
3610 assert_eq!(metric.npa.class_na_sum(), 1);
3614 assert_eq!(metric.npa.class_npa_sum(), 1);
3615 },
3616 );
3617 }
3618
3619 #[test]
3620 fn mozcpp_conversion_operators_without_bodies_count_as_methods() {
3621 check_metrics_with_npa::<MozcppParser>(
3622 CONVERSION_OPERATORS_WITHOUT_BODIES,
3623 "foo.cpp",
3624 |metric| {
3625 assert_eq!(metric.npm.class_nm_sum(), 3);
3626 assert_eq!(metric.npm.class_npm_sum(), 2);
3627 assert_eq!(metric.npa.class_na_sum(), 1);
3628 assert_eq!(metric.npa.class_npa_sum(), 1);
3629 },
3630 );
3631 }
3632
3633 const FUNCTION_POINTER_MEMBERS: &str = "class F {\n\
3673 public:\n\
3674 int (*fp)(int);\n\
3675 int plainData;\n\
3676 int (*fps[4])(int);\n\
3677 void realMethod();\n\
3678 Foo* operator->();\n\
3679 operator float();\n\
3680 template<typename T> operator T();\n\
3681 void (parenMethod)();\n\
3682 int (operator+)(int);\n\
3683 void ((doubleParenMethod))();\n\
3684 int ((*doubleParenFp))(int);\n\
3685 private:\n\
3686 int (*privFp)(int);\n\
3687 void privMethod();\n\
3688 };";
3689
3690 const METHOD_RETURNING_FUNCTION_POINTER: &str = "class F {\n\
3705 public:\n\
3706 int (*getFp(int))(int);\n\
3707 int (*fp)(int);\n\
3708 private:\n\
3709 int (*privGetFp(int))(int);\n\
3710 int (*privFp)(int);\n\
3711 };";
3712
3713 #[test]
3714 fn cpp_function_pointer_members_are_attributes_not_methods() {
3715 check_metrics_with_npa::<CppParser>(FUNCTION_POINTER_MEMBERS, "foo.cpp", |metric| {
3716 assert_eq!(metric.npm.class_nm_sum(), 8);
3722 assert_eq!(metric.npm.class_npm_sum(), 7);
3723 assert_eq!(metric.npa.class_na_sum(), 5);
3730 assert_eq!(metric.npa.class_npa_sum(), 4);
3731 });
3732 }
3733
3734 #[test]
3735 fn mozcpp_function_pointer_members_are_attributes_not_methods() {
3736 check_metrics_with_npa::<MozcppParser>(FUNCTION_POINTER_MEMBERS, "foo.cpp", |metric| {
3737 assert_eq!(metric.npm.class_nm_sum(), 8);
3738 assert_eq!(metric.npm.class_npm_sum(), 7);
3739 assert_eq!(metric.npa.class_na_sum(), 5);
3740 assert_eq!(metric.npa.class_npa_sum(), 4);
3741 });
3742 }
3743
3744 #[test]
3745 fn cpp_method_returning_a_function_pointer_stays_a_method() {
3746 check_metrics_with_npa::<CppParser>(
3747 METHOD_RETURNING_FUNCTION_POINTER,
3748 "foo.cpp",
3749 |metric| {
3750 assert_eq!(metric.npm.class_nm_sum(), 2);
3751 assert_eq!(metric.npm.class_npm_sum(), 1);
3752 assert_eq!(metric.npa.class_na_sum(), 2);
3753 assert_eq!(metric.npa.class_npa_sum(), 1);
3754 },
3755 );
3756 }
3757
3758 #[test]
3759 fn mozcpp_method_returning_a_function_pointer_stays_a_method() {
3760 check_metrics_with_npa::<MozcppParser>(
3761 METHOD_RETURNING_FUNCTION_POINTER,
3762 "foo.cpp",
3763 |metric| {
3764 assert_eq!(metric.npm.class_nm_sum(), 2);
3765 assert_eq!(metric.npm.class_npm_sum(), 1);
3766 assert_eq!(metric.npa.class_na_sum(), 2);
3767 assert_eq!(metric.npa.class_npa_sum(), 1);
3768 },
3769 );
3770 }
3771
3772 #[test]
3773 fn cpp_non_method_template_payloads_are_not_counted() {
3774 check_metrics_with_nom_wmc::<CppParser>(
3775 NON_METHOD_TEMPLATE_PAYLOADS,
3776 "foo.cpp",
3777 |metric| {
3778 assert_eq!(metric.npm.class_nm_sum(), 2);
3781 assert_eq!(metric.npm.class_npm_sum(), 1);
3782 assert_eq!(metric.nom.functions_sum(), 3);
3787 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3795 },
3796 );
3797 }
3798
3799 #[test]
3800 fn mozcpp_template_method_with_inline_body_counts() {
3801 check_metrics_with_nom_wmc::<MozcppParser>(
3802 TEMPLATE_METHOD_WITH_BODY,
3803 "foo.cpp",
3804 |metric| {
3805 assert_eq!(metric.npm.class_nm_sum(), 2);
3806 assert_eq!(metric.npm.class_npm_sum(), 2);
3807 assert_eq!(metric.nom.functions_sum(), 2);
3808 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3809 },
3810 );
3811 }
3812
3813 #[test]
3814 fn mozcpp_non_method_template_payloads_are_not_counted() {
3815 check_metrics_with_nom_wmc::<MozcppParser>(
3816 NON_METHOD_TEMPLATE_PAYLOADS,
3817 "foo.cpp",
3818 |metric| {
3819 assert_eq!(metric.npm.class_nm_sum(), 2);
3820 assert_eq!(metric.npm.class_npm_sum(), 1);
3821 assert_eq!(metric.nom.functions_sum(), 3);
3822 assert_eq!(metric.wmc.class_wmc_sum(), 2);
3824 },
3825 );
3826 }
3827
3828 #[test]
3829 fn javascript_empty_unit_no_methods() {
3830 check_metrics::<JavascriptParser>("", "empty.js", |metric| {
3831 assert_eq!(metric.npm.class_nm_sum(), 0);
3832 assert_eq!(metric.npm.class_npm_sum(), 0);
3833 insta::assert_json_snapshot!(metric.npm);
3834 });
3835 }
3836
3837 #[test]
3838 fn javascript_class_methods_count() {
3839 check_metrics::<JavascriptParser>(
3843 "class Foo {\n\
3844 constructor() {}\n\
3845 bar() {}\n\
3846 get baz() { return 1; }\n\
3847 set baz(v) {}\n\
3848 }",
3849 "foo.js",
3850 |metric| {
3851 assert_eq!(metric.npm.class_nm_sum(), 4);
3852 assert_eq!(metric.npm.class_npm_sum(), 4);
3853 insta::assert_json_snapshot!(metric.npm);
3854 },
3855 );
3856 }
3857
3858 #[test]
3859 fn javascript_arrow_field_is_method() {
3860 check_metrics::<JavascriptParser>(
3864 "class Foo { x = () => {}; y = function() {}; z = 1; }",
3865 "foo.js",
3866 |metric| {
3867 assert_eq!(metric.npm.class_nm_sum(), 2);
3869 assert_eq!(metric.npm.class_npm_sum(), 2);
3870 insta::assert_json_snapshot!(metric.npm);
3871 },
3872 );
3873 }
3874
3875 #[test]
3876 fn javascript_free_function_is_not_method() {
3877 check_metrics::<JavascriptParser>(
3880 "function f() {}\nconst g = () => {};\nclass Foo { h() {} }",
3881 "foo.js",
3882 |metric| {
3883 assert_eq!(metric.npm.class_nm_sum(), 1);
3885 assert_eq!(metric.npm.class_npm_sum(), 1);
3886 insta::assert_json_snapshot!(metric.npm);
3887 },
3888 );
3889 }
3890
3891 #[test]
3892 fn javascript_multiple_classes_aggregate_at_unit() {
3893 check_metrics::<JavascriptParser>(
3896 "class Foo { a() {} b() {} }\nclass Bar { c() {} }",
3897 "foo.js",
3898 |metric| {
3899 assert_eq!(metric.npm.class_nm_sum(), 3);
3900 assert_eq!(metric.npm.class_npm_sum(), 3);
3901 insta::assert_json_snapshot!(metric.npm);
3902 },
3903 );
3904 }
3905
3906 #[test]
3907 fn mozjs_class_methods_count() {
3908 check_metrics::<MozjsParser>(
3910 "class Foo {\n\
3911 constructor() {}\n\
3912 bar() {}\n\
3913 get baz() { return 1; }\n\
3914 set baz(v) {}\n\
3915 }",
3916 "foo.js",
3917 |metric| {
3918 assert_eq!(metric.npm.class_nm_sum(), 4);
3919 assert_eq!(metric.npm.class_npm_sum(), 4);
3920 insta::assert_json_snapshot!(metric.npm);
3921 },
3922 );
3923 }
3924
3925 #[test]
3933 fn empty_class_coa_is_zero_not_nan() {
3934 let assert_zero = |metric: crate::CodeMetrics| {
3935 assert_eq!(metric.npm.class_nm_sum(), 0);
3936 assert!(!metric.npm.class_coa().is_nan());
3937 assert!(!metric.npm.total_coa().is_nan());
3938 assert_eq!(metric.npm.class_coa(), 0.0);
3939 assert_eq!(metric.npm.total_coa(), 0.0);
3940 };
3941 check_metrics::<JavaParser>("class Foo {}", "foo.java", assert_zero);
3942 check_metrics::<CsharpParser>("class Foo {}", "foo.cs", assert_zero);
3943 check_metrics::<KotlinParser>("class Foo {}", "foo.kt", assert_zero);
3944 check_metrics::<PhpParser>("<?php class Foo {}", "foo.php", assert_zero);
3945 }
3946
3947 #[test]
3952 fn empty_interface_coa_is_zero_not_nan() {
3953 let assert_zero = |metric: crate::CodeMetrics| {
3954 assert_eq!(metric.npm.interface_nm_sum(), 0);
3955 assert!(!metric.npm.interface_coa().is_nan());
3956 assert_eq!(metric.npm.interface_coa(), 0.0);
3957 };
3958 check_metrics::<JavaParser>("interface Foo {}", "foo.java", assert_zero);
3959 check_metrics::<CsharpParser>("interface Foo {}", "foo.cs", assert_zero);
3960 }
3961
3962 #[test]
3966 fn stats_display_and_per_space_accessors() {
3967 check_func_space::<JavaParser, _>(
3968 "public interface I {\n void p();\n}\n\
3969 public class C {\n public void m() {}\n private void n() {}\n}\n",
3970 "X.java",
3971 |unit| {
3972 assert_eq!(unit.metrics.npm.class_npm_sum(), 1);
3975 assert_eq!(unit.metrics.npm.class_nm_sum(), 2);
3976 let rendered = unit.metrics.npm.to_string();
3977 for fragment in [
3978 "classes: 1, interfaces: 1",
3979 "class_methods: 2",
3980 "interface_methods: 1",
3981 "total: 2, total_methods: 3",
3982 ] {
3983 assert!(
3984 rendered.contains(fragment),
3985 "missing {fragment:?} in {rendered}"
3986 );
3987 }
3988 let class = child_space(&unit, "C");
3993 assert_eq!(class.kind, SpaceKind::Class);
3994 assert_eq!(class.metrics.npm.class_npm(), 1);
3995 assert_eq!(class.metrics.npm.class_nm(), 2);
3996 let iface = child_space(&unit, "I");
3997 assert_eq!(iface.kind, SpaceKind::Interface);
3998 assert_eq!(iface.metrics.npm.interface_npm(), 1);
3999 assert_eq!(iface.metrics.npm.interface_nm(), 1);
4000 },
4001 );
4002 }
4003}