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 serde::Serialize;
21use serde::ser::{SerializeStruct, Serializer};
22use std::fmt;
23
24use crate::checker::Checker;
25use crate::langs::*;
26use crate::macros::implement_metric_trait;
27use crate::metrics::npa::ts_member_is_public;
28use crate::node::Node;
29use crate::*;
30
31#[derive(Clone, Debug, Default)]
36pub struct Stats {
37 class_npm: usize,
38 interface_npm: usize,
39 class_nm: usize,
40 interface_nm: usize,
41 class_npm_sum: usize,
42 interface_npm_sum: usize,
43 class_nm_sum: usize,
44 interface_nm_sum: usize,
45 is_class_space: bool,
46}
47
48impl Serialize for Stats {
49 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50 where
51 S: Serializer,
52 {
53 let mut st = serializer.serialize_struct("npm", 9)?;
54 st.serialize_field("classes", &self.class_npm_sum())?;
55 st.serialize_field("interfaces", &self.interface_npm_sum())?;
56 st.serialize_field("class_methods", &self.class_nm_sum())?;
57 st.serialize_field("interface_methods", &self.interface_nm_sum())?;
58 st.serialize_field("classes_average", &self.class_coa())?;
59 st.serialize_field("interfaces_average", &self.interface_coa())?;
60 st.serialize_field("total", &self.total_npm())?;
61 st.serialize_field("total_methods", &self.total_nm())?;
62 st.serialize_field("average", &self.total_coa())?;
63 st.end()
64 }
65}
66
67impl fmt::Display for Stats {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 write!(
70 f,
71 "classes: {}, interfaces: {}, class_methods: {}, interface_methods: {}, classes_average: {}, interfaces_average: {}, total: {}, total_methods: {}, average: {}",
72 self.class_npm_sum(),
73 self.interface_npm_sum(),
74 self.class_nm_sum(),
75 self.interface_nm_sum(),
76 self.class_coa(),
77 self.interface_coa(),
78 self.total_npm(),
79 self.total_nm(),
80 self.total_coa()
81 )
82 }
83}
84
85impl Stats {
86 pub fn merge(&mut self, other: &Stats) {
88 self.class_npm_sum += other.class_npm_sum;
89 self.interface_npm_sum += other.interface_npm_sum;
90 self.class_nm_sum += other.class_nm_sum;
91 self.interface_nm_sum += other.interface_nm_sum;
92 }
93
94 #[inline]
96 #[must_use]
97 pub fn class_npm(&self) -> f64 {
98 self.class_npm as f64
99 }
100
101 #[inline]
103 #[must_use]
104 pub fn interface_npm(&self) -> f64 {
105 self.interface_npm as f64
106 }
107
108 #[inline]
110 #[must_use]
111 pub fn class_nm(&self) -> f64 {
112 self.class_nm as f64
113 }
114
115 #[inline]
117 #[must_use]
118 pub fn interface_nm(&self) -> f64 {
119 self.interface_nm as f64
120 }
121
122 #[inline]
124 #[must_use]
125 pub fn class_npm_sum(&self) -> f64 {
126 self.class_npm_sum as f64
127 }
128
129 #[inline]
131 #[must_use]
132 pub fn interface_npm_sum(&self) -> f64 {
133 self.interface_npm_sum as f64
134 }
135
136 #[inline]
138 #[must_use]
139 pub fn class_nm_sum(&self) -> f64 {
140 self.class_nm_sum as f64
141 }
142
143 #[inline]
145 #[must_use]
146 pub fn interface_nm_sum(&self) -> f64 {
147 self.interface_nm_sum as f64
148 }
149
150 #[inline]
160 #[must_use]
161 pub fn class_coa(&self) -> f64 {
162 self.class_npm_sum() / self.class_nm_sum()
163 }
164
165 #[inline]
175 #[must_use]
176 pub fn interface_coa(&self) -> f64 {
177 if self.interface_npm_sum == self.interface_nm_sum && self.interface_npm_sum != 0 {
180 1.0
181 } else {
182 self.interface_npm_sum() / self.interface_nm_sum()
183 }
184 }
185
186 #[inline]
196 #[must_use]
197 pub fn total_coa(&self) -> f64 {
198 self.total_npm() / self.total_nm()
199 }
200
201 #[inline]
203 #[must_use]
204 pub fn total_npm(&self) -> f64 {
205 self.class_npm_sum() + self.interface_npm_sum()
206 }
207
208 #[inline]
210 #[must_use]
211 pub fn total_nm(&self) -> f64 {
212 self.class_nm_sum() + self.interface_nm_sum()
213 }
214
215 #[inline]
218 pub(crate) fn compute_sum(&mut self) {
219 self.class_npm_sum += self.class_npm;
220 self.interface_npm_sum += self.interface_npm;
221 self.class_nm_sum += self.class_nm;
222 self.interface_nm_sum += self.interface_nm;
223 }
224
225 #[inline]
227 pub(crate) fn is_disabled(&self) -> bool {
228 !self.is_class_space
229 }
230}
231
232#[doc(hidden)]
233pub trait Npm
235where
236 Self: Checker,
237{
238 fn compute<'a>(node: &Node<'a>, code: &'a [u8], stats: &mut Stats);
248}
249
250macro_rules! impl_npm_java_like {
265 ($code:ty, $lang:ident) => {
266 impl Npm for $code {
267 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
268 use $lang::*;
269
270 if Self::is_func_space(node) && stats.is_disabled() {
271 stats.is_class_space = true;
272 }
273
274 match node.kind_id().into() {
275 ClassBody | EnumBodyDeclarations => {
276 for method in node.children().filter(|n| Self::is_func(n)) {
277 stats.class_nm += 1;
278 if let Some(modifiers) = method.child(0)
281 && matches!(modifiers.kind_id().into(), Modifiers)
282 && modifiers.first_child(|id| id == Public).is_some()
283 {
284 stats.class_npm += 1;
285 }
286 }
287 }
288 InterfaceBody => {
289 stats.interface_nm += node.children().filter(|n| Self::is_func(n)).count();
290 stats.interface_npm = stats.interface_nm;
291 }
292 AnnotationTypeBody => {
293 stats.interface_nm += node
294 .children()
295 .filter(|n| {
296 matches!(n.kind_id().into(), AnnotationTypeElementDeclaration)
297 })
298 .count();
299 stats.interface_npm = stats.interface_nm;
300 }
301 _ => {}
302 }
303 }
304 }
305 };
306}
307
308impl_npm_java_like!(JavaCode, Java);
309
310impl Npm for GroovyCode {
318 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
319 use crate::metrics::npa::{groovy_body_is_interface_like, groovy_has_explicit_public};
320 use Groovy::*;
321
322 if Self::is_func_space(node) && stats.is_disabled() {
323 stats.is_class_space = true;
324 }
325
326 match node.kind_id().into() {
327 ClassBody | EnumBody => {
328 let is_interface_like = groovy_body_is_interface_like(node);
329
330 for method in node.children().filter(|n| Self::is_func(n)) {
331 if is_interface_like {
332 stats.interface_nm += 1;
333 stats.interface_npm += 1;
334 } else {
335 stats.class_nm += 1;
336 if groovy_has_explicit_public(&method) {
337 stats.class_npm += 1;
338 }
339 }
340 }
341 }
342 _ => {}
343 }
344 }
345}
346
347fn csharp_count_member(member: &Node) -> usize {
352 use Csharp::*;
353 match member.kind_id().into() {
354 MethodDeclaration
355 | ConstructorDeclaration
356 | DestructorDeclaration
357 | OperatorDeclaration
358 | ConversionOperatorDeclaration => 1,
359 PropertyDeclaration | IndexerDeclaration => member
360 .children()
361 .filter(|c| matches!(c.kind_id().into(), AccessorList))
362 .flat_map(|c| c.children())
363 .filter(|c| matches!(c.kind_id().into(), AccessorDeclaration))
364 .count()
365 .max(1),
366 _ => 0,
367 }
368}
369
370impl Npm for CsharpCode {
371 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
372 use Csharp::*;
373
374 if Self::is_func_space(node) && stats.is_disabled() {
375 stats.is_class_space = true;
376 }
377
378 if !matches!(node.kind_id().into(), DeclarationList) {
379 return;
380 }
381 let Some(parent_kind) = node.parent().map(|p| p.kind_id().into()) else {
382 return;
383 };
384
385 match parent_kind {
386 ClassDeclaration | StructDeclaration | RecordDeclaration => {
387 for member in node.children() {
388 let count = csharp_count_member(&member);
389 stats.class_nm += count;
390 if super::npa::csharp_is_explicit_public(&member) {
391 stats.class_npm += count;
392 }
393 }
394 }
395 InterfaceDeclaration => {
398 for member in node.children() {
399 stats.interface_nm += csharp_count_member(&member);
400 }
401 stats.interface_npm = stats.interface_nm;
402 }
403 _ => {}
404 }
405 }
406}
407
408impl Npm for PhpCode {
409 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
410 use Php::*;
411
412 if Self::is_func_space(node) && stats.is_disabled() {
413 stats.is_class_space = true;
414 }
415
416 match node.kind_id().into() {
417 DeclarationList => {
418 let Some(parent_kind) = node.parent().map(|p| p.kind_id().into()) else {
419 return;
420 };
421 match parent_kind {
422 ClassDeclaration | TraitDeclaration | AnonymousClass => {
423 for method in node.children().filter(|c| Self::is_func(c)) {
424 stats.class_nm += 1;
425 if super::npa::php_is_explicit_public(&method) {
426 stats.class_npm += 1;
427 }
428 }
429 }
430 InterfaceDeclaration => {
432 let count = node.children().filter(|c| Self::is_func(c)).count();
433 stats.interface_nm += count;
434 stats.interface_npm = stats.interface_nm;
435 }
436 _ => {}
437 }
438 }
439 EnumDeclarationList => {
441 for method in node.children().filter(|c| Self::is_func(c)) {
442 stats.class_nm += 1;
443 if super::npa::php_is_explicit_public(&method) {
444 stats.class_npm += 1;
445 }
446 }
447 }
448 _ => {}
449 }
450 }
451}
452
453impl Npm for PythonCode {
474 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
475 use Python::*;
476
477 if !matches!(node.kind_id().into(), ClassDefinition) {
480 return;
481 }
482
483 if stats.is_disabled() {
484 stats.is_class_space = true;
485 }
486
487 let Some(body) = node.children().find(|c| c.kind_id() == Block2) else {
488 return;
489 };
490
491 let count = body
495 .children()
496 .filter(|stmt| match stmt.kind_id().into() {
497 FunctionDefinition => true,
498 DecoratedDefinition => stmt.children().any(|c| c.kind_id() == FunctionDefinition),
499 _ => false,
500 })
501 .count();
502
503 stats.class_nm += count;
504 stats.class_npm += count;
506 }
507}
508
509impl Npm for RustCode {
526 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
527 use Rust::*;
528
529 if matches!(node.kind_id().into(), ImplItem | TraitItem) && stats.is_disabled() {
531 stats.is_class_space = true;
532 }
533
534 if !matches!(node.kind_id().into(), FunctionItem | FunctionSignatureItem) {
540 return;
541 }
542 let Some(parent) = node.parent() else {
543 return;
544 };
545 if !matches!(parent.kind_id().into(), DeclarationList) {
546 return;
547 }
548 let Some(grand) = parent.parent() else {
549 return;
550 };
551 match grand.kind_id().into() {
552 ImplItem => {
553 stats.class_nm += 1;
554 if super::npa::rust_item_is_public(node) {
555 stats.class_npm += 1;
556 }
557 }
558 TraitItem => {
559 stats.interface_nm += 1;
560 stats.interface_npm = stats.interface_nm;
561 }
562 _ => {}
563 }
564 }
565}
566
567impl Npm for GoCode {
571 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
572 use Go as G;
573
574 match node.kind_id().into() {
575 G::SourceFile
580 if stats.is_disabled()
581 && node
582 .children()
583 .any(|c| matches!(c.kind_id().into(), G::MethodDeclaration)) =>
584 {
585 stats.is_class_space = true;
586 }
587 G::MethodDeclaration => {
593 stats.class_nm += 1;
594 stats.class_npm += 1;
597 }
598 G::InterfaceType => {
605 let methods = node
606 .children()
607 .filter(|c| matches!(c.kind_id().into(), G::MethodElem))
608 .count();
609 if methods == 0 {
610 return;
611 }
612 if stats.is_disabled() {
613 stats.is_class_space = true;
614 }
615 stats.interface_nm += methods;
616 stats.interface_npm = stats.interface_nm;
617 }
618 _ => {}
619 }
620 }
621}
622
623impl Npm for CppCode {
624 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
625 use Cpp::*;
626
627 if matches!(node.kind_id().into(), ClassSpecifier | StructSpecifier) && stats.is_disabled()
630 {
631 stats.is_class_space = true;
632 }
633
634 if !matches!(node.kind_id().into(), FieldDeclarationList) {
635 return;
636 }
637 let Some(parent) = node.parent() else {
638 return;
639 };
640 let mut current_is_public = match parent.kind_id().into() {
642 ClassSpecifier => false,
643 StructSpecifier => true,
644 _ => return,
645 };
646
647 for child in node.children() {
648 match child.kind_id().into() {
649 AccessSpecifier => {
650 current_is_public = child
651 .first_child(|id| {
652 id == Cpp::Public || id == Cpp::Protected || id == Cpp::Private
653 })
654 .is_some_and(|tok| tok.kind_id() == Cpp::Public);
655 }
656 FunctionDefinition | FunctionDefinition2 | FunctionDefinition3
661 | FunctionDefinition4 => {
662 stats.class_nm += 1;
663 if current_is_public {
664 stats.class_npm += 1;
665 }
666 }
667 FieldDeclaration | Declaration | Declaration2 | Declaration3 | Declaration4
684 | TemplateDeclaration
685 if super::npa::cpp_has_function_declarator(&child) =>
686 {
687 stats.class_nm += 1;
688 if current_is_public {
689 stats.class_npm += 1;
690 }
691 }
692 _ => {}
693 }
694 }
695 }
696}
697
698impl Npm for KotlinCode {
702 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
703 use Kotlin::*;
704
705 if Self::is_func_space(node) && stats.is_disabled() {
707 stats.is_class_space = true;
708 }
709
710 if !matches!(node.kind_id().into(), ClassBody) {
725 return;
726 }
727 let is_interface = super::npa::kotlin_class_body_is_interface(node);
728 for func in node.children().filter(|c| Self::is_func(c)) {
733 if is_interface {
734 stats.interface_nm += 1;
735 stats.interface_npm += 1;
736 } else {
737 stats.class_nm += 1;
738 if super::npa::kotlin_is_public(&func) {
739 stats.class_npm += 1;
740 }
741 }
742 }
743 }
744}
745
746macro_rules! ts_npm_compute {
774 ($lang:ident) => {
775 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
776 use $lang::*;
777
778 if Self::is_func_space(node) && stats.is_disabled() {
779 stats.is_class_space = true;
780 }
781
782 match node.kind_id().into() {
783 ClassBody => {
784 for member in node.children() {
785 match member.kind_id().into() {
786 MethodDefinition | AbstractMethodSignature => {
787 stats.class_nm += 1;
788 if ts_member_is_public!($lang, member) {
789 stats.class_npm += 1;
790 }
791 }
792 PublicFieldDefinition
795 if member
796 .first_child(|id| {
797 id == $lang::ArrowFunction
798 || id == $lang::FunctionExpression
799 })
800 .is_some() =>
801 {
802 stats.class_nm += 1;
803 if ts_member_is_public!($lang, member) {
804 stats.class_npm += 1;
805 }
806 }
807 _ => {}
808 }
809 }
810 }
811 InterfaceBody => {
812 let count = node
813 .children()
814 .filter(|c| {
815 matches!(
816 c.kind_id().into(),
817 MethodSignature | AbstractMethodSignature | ConstructSignature
818 )
819 })
820 .count();
821 stats.interface_nm += count;
822 stats.interface_npm = stats.interface_nm;
823 }
824 _ => {}
825 }
826 }
827 };
828}
829
830impl Npm for TypescriptCode {
831 ts_npm_compute!(Typescript);
832}
833
834impl Npm for TsxCode {
835 ts_npm_compute!(Tsx);
836}
837
838impl Npm for RubyCode {
850 fn compute<'a>(node: &Node<'a>, code: &'a [u8], stats: &mut Stats) {
851 use Ruby::*;
852
853 if Self::is_func_space(node) && stats.is_disabled() {
854 stats.is_class_space = true;
855 }
856
857 if !matches!(node.kind_id().into(), BodyStatement | BodyStatement2) {
858 return;
859 }
860 let Some(parent_kind) = node.parent().map(|p| p.kind_id().into()) else {
861 return;
862 };
863 if !matches!(parent_kind, Class | SingletonClass) {
864 return;
865 }
866
867 let mut visibility = super::npa::RubyVisibility::Public;
868 for child in node.children() {
869 if let Some(marker) = super::npa::ruby_visibility_marker(&child, code) {
870 visibility = marker;
871 continue;
872 }
873 if matches!(child.kind_id().into(), Method | SingletonMethod) {
874 stats.class_nm += 1;
875 if visibility == super::npa::RubyVisibility::Public {
876 stats.class_npm += 1;
877 }
878 }
879 }
880 }
881}
882
883macro_rules! js_npm_compute {
900 ($lang:ident) => {
901 fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
902 use $lang::*;
903
904 if Self::is_func_space(node) && stats.is_disabled() {
905 stats.is_class_space = true;
906 }
907
908 if !matches!(node.kind_id().into(), ClassBody) {
909 return;
910 }
911
912 for member in node.children() {
913 match member.kind_id().into() {
914 MethodDefinition => {
915 stats.class_nm += 1;
916 stats.class_npm += 1;
917 }
918 FieldDefinition
919 if member
920 .first_child(|id| {
921 id == $lang::ArrowFunction || id == $lang::FunctionExpression
922 })
923 .is_some() =>
924 {
925 stats.class_nm += 1;
926 stats.class_npm += 1;
927 }
928 _ => {}
929 }
930 }
931 }
932 };
933}
934
935impl Npm for JavascriptCode {
936 js_npm_compute!(Javascript);
937}
938
939impl Npm for MozjsCode {
940 js_npm_compute!(Mozjs);
941}
942
943impl Npm for ElixirCode {
952 fn compute<'a>(node: &Node<'a>, code: &'a [u8], stats: &mut Stats) {
953 use crate::metrics::cognitive::{elixir_call_keyword, elixir_do_block_call_children};
954
955 if !stats.is_disabled() || !Self::is_func_space_with_code(node, code) {
956 return;
957 }
958 if !matches!(elixir_call_keyword(node, code), Some("defmodule")) {
961 return;
962 }
963
964 stats.is_class_space = true;
965
966 for stmt in elixir_do_block_call_children(node) {
971 match elixir_call_keyword(&stmt, code) {
972 Some("def" | "defmacro") => {
973 stats.class_nm += 1;
974 stats.class_npm += 1;
975 }
976 Some("defp" | "defmacrop") => {
979 stats.class_nm += 1;
980 }
981 _ => {}
982 }
983 }
984 }
985}
986
987implement_metric_trait!(
993 Npm,
994 PreprocCode,
995 CcommentCode,
996 PerlCode,
997 BashCode,
998 LuaCode,
999 TclCode
1000);
1001
1002#[cfg(test)]
1003#[allow(
1004 clippy::float_cmp,
1005 clippy::cast_precision_loss,
1006 clippy::cast_possible_truncation,
1007 clippy::cast_sign_loss,
1008 clippy::similar_names,
1009 clippy::doc_markdown,
1010 clippy::needless_raw_string_hashes,
1011 clippy::too_many_lines
1012)]
1013mod tests {
1014 use crate::tools::{assert_child_space_kind, check_func_space, check_metrics};
1015
1016 use super::*;
1017
1018 #[test]
1019 fn java_constructors() {
1020 check_metrics::<JavaParser>(
1021 "class X {
1022 X() {}
1023 private X(int a) {}
1024 protected X(int a, int b) {}
1025 public X(int a, int b, int c) {} // +1
1026 }",
1027 "foo.java",
1028 |metric| {
1029 insta::assert_json_snapshot!(
1030 metric.npm,
1031 @r###"
1032 {
1033 "classes": 1.0,
1034 "interfaces": 0.0,
1035 "class_methods": 4.0,
1036 "interface_methods": 0.0,
1037 "classes_average": 0.25,
1038 "interfaces_average": null,
1039 "total": 1.0,
1040 "total_methods": 4.0,
1041 "average": 0.25
1042 }"###
1043 );
1044 },
1045 );
1046 }
1047
1048 #[test]
1049 fn groovy_no_methods() {
1050 check_metrics::<GroovyParser>("class A { int x = 1 }", "foo.groovy", |metric| {
1051 assert_eq!(metric.npm.total_nm(), 0.0);
1052 });
1053 }
1054
1055 #[test]
1056 fn groovy_public_methods() {
1057 check_metrics::<GroovyParser>(
1058 "class A {
1059 public void m1() {}
1060 public int m2() { return 0 }
1061 private void m3() {}
1062 }",
1063 "foo.groovy",
1064 |metric| {
1065 assert_eq!(metric.npm.class_nm_sum(), 3.0);
1066 assert_eq!(metric.npm.class_npm_sum(), 2.0);
1067 },
1068 );
1069 }
1070
1071 #[test]
1072 fn groovy_interface_methods_implicitly_public() {
1073 check_func_space::<GroovyParser, _>(
1080 "interface I {
1081 void a()
1082 int b()
1083 }",
1084 "foo.groovy",
1085 |func_space| {
1086 let metric = &func_space.metrics;
1087 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
1089 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
1090 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
1091 },
1092 );
1093 }
1094
1095 #[test]
1098 fn groovy_enum_counts_methods() {
1099 check_metrics::<GroovyParser>(
1100 "enum Status {
1101 ACTIVE, INACTIVE;
1102 public int code() { return 0 }
1103 private void reset() {}
1104 }",
1105 "foo.groovy",
1106 |metric| {
1107 assert_eq!(metric.npm.class_nm_sum(), 2.0);
1108 assert_eq!(metric.npm.class_npm_sum(), 1.0);
1109 },
1110 );
1111 }
1112
1113 #[test]
1114 #[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"]
1115 fn groovy_annotation_type_counts_elements() {
1116 check_func_space::<GroovyParser, _>(
1127 "public @interface Marker {
1128 String value() default \"\";
1129 int priority() default 0;
1130 }",
1131 "foo.groovy",
1132 |func_space| {
1133 assert_eq!(func_space.metrics.npm.interface_nm_sum(), 2.0);
1134 assert_eq!(func_space.metrics.npm.interface_npm_sum(), 2.0);
1135 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
1136 },
1137 );
1138 }
1139
1140 #[test]
1141 fn groovy_constructors() {
1142 check_metrics::<GroovyParser>(
1143 "class X {
1144 X() {}
1145 private X(int a) {}
1146 protected X(int a, int b) {}
1147 public X(int a, int b, int c) {}
1148 }",
1149 "foo.groovy",
1150 |metric| {
1151 assert_eq!(metric.npm.class_nm_sum(), 4.0);
1153 assert_eq!(metric.npm.class_npm_sum(), 1.0);
1154 },
1155 );
1156 }
1157
1158 #[test]
1159 fn groovy_no_methods_in_unit_scope() {
1160 check_metrics::<GroovyParser>("int x = 1", "foo.groovy", |metric| {
1161 assert_eq!(metric.npm.total_nm(), 0.0);
1162 });
1163 }
1164
1165 #[test]
1166 fn groovy_multiple_classes_methods() {
1167 check_metrics::<GroovyParser>(
1168 "class A { public void a() {} }
1169 class B { public void b() {} }",
1170 "foo.groovy",
1171 |metric| {
1172 assert_eq!(metric.npm.class_nm_sum(), 2.0);
1173 assert_eq!(metric.npm.class_npm_sum(), 2.0);
1174 },
1175 );
1176 }
1177
1178 #[test]
1179 fn groovy_methods_returning_primitive_types() {
1180 check_metrics::<GroovyParser>(
1184 "class X {
1185 public byte a() {}
1186 public int b() {}
1187 public double c() {}
1188 public boolean d() {}
1189 byte e() {}
1190 int f() {}
1191 }",
1192 "foo.groovy",
1193 |metric| {
1194 assert_eq!(metric.npm.class_nm_sum(), 6.0);
1196 assert_eq!(metric.npm.class_npm_sum(), 4.0);
1197 },
1198 );
1199 }
1200
1201 #[test]
1202 fn groovy_methods_with_generic_types() {
1203 check_metrics::<GroovyParser>(
1205 "class X {
1206 public List<String> a() {}
1207 public Map<String, Integer> b() {}
1208 List<Integer> c() {}
1209 }",
1210 "foo.groovy",
1211 |metric| {
1212 assert_eq!(metric.npm.class_nm_sum(), 3.0);
1213 assert_eq!(metric.npm.class_npm_sum(), 2.0);
1214 },
1215 );
1216 }
1217
1218 #[test]
1219 fn groovy_method_modifiers() {
1220 check_metrics::<GroovyParser>(
1224 "abstract class X {
1225 public static void a() {}
1226 static public void b() {}
1227 public final void c() {}
1228 final public void d() {}
1229 protected static void e() {}
1230 static protected void f() {}
1231 abstract public void g()
1232 abstract void h()
1233 }",
1234 "foo.groovy",
1235 |metric| {
1236 assert_eq!(metric.npm.class_nm_sum(), 8.0);
1238 assert_eq!(metric.npm.class_npm_sum(), 5.0);
1239 },
1240 );
1241 }
1242
1243 #[test]
1244 #[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside class bodies"]
1245 fn groovy_nested_inner_classes() {
1246 check_metrics::<GroovyParser>(
1249 "class X {
1250 public void a() {}
1251 class Y {
1252 public void b() {}
1253 class Z {
1254 public void c() {}
1255 }
1256 }
1257 }",
1258 "foo.groovy",
1259 |metric| {
1260 assert_eq!(metric.npm.class_nm_sum(), 3.0);
1262 assert_eq!(metric.npm.class_npm_sum(), 3.0);
1263 },
1264 );
1265 }
1266
1267 #[test]
1268 #[ignore = "dekobon Groovy grammar v1 does not yet support anonymous inner classes (`new T() { … }`)"]
1269 fn groovy_anonymous_inner_class() {
1270 check_metrics::<GroovyParser>(
1273 "class X {
1274 public Runnable r = new Runnable() {
1275 public void run() {}
1276 void helper() {}
1277 }
1278 }",
1279 "foo.groovy",
1280 |metric| {
1281 assert_eq!(metric.npm.class_nm_sum(), 2.0);
1284 assert_eq!(metric.npm.class_npm_sum(), 1.0);
1285 },
1286 );
1287 }
1288
1289 #[test]
1290 fn groovy_interfaces_and_class() {
1291 check_func_space::<GroovyParser, _>(
1297 "interface X {
1298 void a()
1299 }
1300 interface Y extends X {
1301 void b()
1302 void c()
1303 }
1304 class Z implements Y {
1305 public void a() {}
1306 public void b() {}
1307 public void c() {}
1308 void d() {}
1309 void e() {}
1310 }",
1311 "foo.groovy",
1312 |func_space| {
1313 let metric = &func_space.metrics;
1314 assert_eq!(metric.npm.interface_nm_sum(), 3.0);
1316 assert_eq!(metric.npm.interface_npm_sum(), 3.0);
1317 assert_eq!(metric.npm.class_nm_sum(), 5.0);
1320 assert_eq!(metric.npm.class_npm_sum(), 3.0);
1321 assert_child_space_kind(&func_space, "X", SpaceKind::Interface);
1322 assert_child_space_kind(&func_space, "Y", SpaceKind::Interface);
1323 assert_child_space_kind(&func_space, "Z", SpaceKind::Class);
1324 },
1325 );
1326 }
1327
1328 #[test]
1329 fn java_methods_returning_primitive_types() {
1330 check_metrics::<JavaParser>(
1331 "class X {
1332 public byte a() {} // +1
1333 public short b() {} // +1
1334 public int c() {} // +1
1335 public long d() {} // +1
1336 public float e() {} // +1
1337 public double f() {} // +1
1338 public boolean g() {} // +1
1339 public char h() {} // +1
1340 byte i() {}
1341 short j() {}
1342 int k() {}
1343 long l() {}
1344 float m() {}
1345 double n() {}
1346 boolean o() {}
1347 char p() {}
1348 }",
1349 "foo.java",
1350 |metric| {
1351 insta::assert_json_snapshot!(
1352 metric.npm,
1353 @r###"
1354 {
1355 "classes": 8.0,
1356 "interfaces": 0.0,
1357 "class_methods": 16.0,
1358 "interface_methods": 0.0,
1359 "classes_average": 0.5,
1360 "interfaces_average": null,
1361 "total": 8.0,
1362 "total_methods": 16.0,
1363 "average": 0.5
1364 }"###
1365 );
1366 },
1367 );
1368 }
1369
1370 #[test]
1371 fn java_methods_returning_arrays() {
1372 check_metrics::<JavaParser>(
1373 "class X {
1374 public byte[] a() {} // +1
1375 public short[] b() {} // +1
1376 public int[] c() {} // +1
1377 public long[] d() {} // +1
1378 public float[] e() {} // +1
1379 public double[] f() {} // +1
1380 public boolean[] g() {} // +1
1381 public char[] h() {} // +1
1382 byte[] i() {}
1383 short[] j() {}
1384 int[] k() {}
1385 long[] l() {}
1386 float[] m() {}
1387 double[] n() {}
1388 boolean[] o() {}
1389 char[] p() {}
1390 }",
1391 "foo.java",
1392 |metric| {
1393 insta::assert_json_snapshot!(
1394 metric.npm,
1395 @r###"
1396 {
1397 "classes": 8.0,
1398 "interfaces": 0.0,
1399 "class_methods": 16.0,
1400 "interface_methods": 0.0,
1401 "classes_average": 0.5,
1402 "interfaces_average": null,
1403 "total": 8.0,
1404 "total_methods": 16.0,
1405 "average": 0.5
1406 }"###
1407 );
1408 },
1409 );
1410 }
1411
1412 #[test]
1413 fn java_methods_returning_objects() {
1414 check_metrics::<JavaParser>(
1415 "class X {
1416 public Integer[] a() {} // +1
1417 public Integer b() {} // +1
1418 public String[] c() {} // +1
1419 public String d() {} // +1
1420 public Y[] e() {} // +1
1421 public Y f() {} // +1
1422 Integer[] g() {}
1423 Integer h() {}
1424 String[] i() {}
1425 String j() {}
1426 Y[] k() {}
1427 Y l() {}
1428 }",
1429 "foo.java",
1430 |metric| {
1431 insta::assert_json_snapshot!(
1432 metric.npm,
1433 @r###"
1434 {
1435 "classes": 6.0,
1436 "interfaces": 0.0,
1437 "class_methods": 12.0,
1438 "interface_methods": 0.0,
1439 "classes_average": 0.5,
1440 "interfaces_average": null,
1441 "total": 6.0,
1442 "total_methods": 12.0,
1443 "average": 0.5
1444 }"###
1445 );
1446 },
1447 );
1448 }
1449
1450 #[test]
1451 fn java_methods_with_generic_types() {
1452 check_metrics::<JavaParser>(
1453 "class X {
1454 public <T, S extends T> void a(T x, S y) {} // +1
1455 public <T, S> int b(T x, S y) {} // +1
1456 public <T> boolean c(T x) {} // +1
1457 public <T> ArrayList<T> d() {} // +1
1458 public Y<String> e() {} // +1
1459 <T, S extends T> void f(T x, S y) {}
1460 <T, S> int g(T x, S y) {}
1461 <T> boolean h(T x) {}
1462 <T> ArrayList<T> i() {}
1463 Y<String> j() {}
1464 }",
1465 "foo.java",
1466 |metric| {
1467 insta::assert_json_snapshot!(
1468 metric.npm,
1469 @r###"
1470 {
1471 "classes": 5.0,
1472 "interfaces": 0.0,
1473 "class_methods": 10.0,
1474 "interface_methods": 0.0,
1475 "classes_average": 0.5,
1476 "interfaces_average": null,
1477 "total": 5.0,
1478 "total_methods": 10.0,
1479 "average": 0.5
1480 }"###
1481 );
1482 },
1483 );
1484 }
1485
1486 #[test]
1487 fn java_method_modifiers() {
1488 check_metrics::<JavaParser>(
1489 "abstract class X {
1490 public static final synchronized strictfp void a() {} // +1
1491 static public final synchronized strictfp void b() {} // +1
1492 static final public synchronized strictfp void c() {} // +1
1493 static final synchronized public strictfp void d() {} // +1
1494 static final synchronized strictfp public void e() {} // +1
1495 protected static final synchronized native void f();
1496 static protected final synchronized native void g();
1497 static final protected synchronized native void h();
1498 static final synchronized protected native void i();
1499 static final synchronized native protected void j();
1500 abstract public void k(); // +1
1501 abstract void l();
1502 }",
1503 "foo.java",
1504 |metric| {
1505 insta::assert_json_snapshot!(
1506 metric.npm,
1507 @r###"
1508 {
1509 "classes": 6.0,
1510 "interfaces": 0.0,
1511 "class_methods": 12.0,
1512 "interface_methods": 0.0,
1513 "classes_average": 0.5,
1514 "interfaces_average": null,
1515 "total": 6.0,
1516 "total_methods": 12.0,
1517 "average": 0.5
1518 }"###
1519 );
1520 },
1521 );
1522 }
1523
1524 #[test]
1525 fn java_classes() {
1526 check_metrics::<JavaParser>(
1527 "class X {
1528 public void a() {} // +1
1529 public void b() {} // +1
1530 private void c() {}
1531 }
1532 class Y {
1533 private void d() {}
1534 private void e() {}
1535 public void f() {} // +1
1536 }",
1537 "foo.java",
1538 |metric| {
1539 insta::assert_json_snapshot!(
1540 metric.npm,
1541 @r###"
1542 {
1543 "classes": 3.0,
1544 "interfaces": 0.0,
1545 "class_methods": 6.0,
1546 "interface_methods": 0.0,
1547 "classes_average": 0.5,
1548 "interfaces_average": null,
1549 "total": 3.0,
1550 "total_methods": 6.0,
1551 "average": 0.5
1552 }"###
1553 );
1554 },
1555 );
1556 }
1557
1558 #[test]
1559 fn java_nested_inner_classes() {
1560 check_metrics::<JavaParser>(
1561 "class X {
1562 public void a() {} // +1
1563 class Y {
1564 public void b() {} // +1
1565 class Z {
1566 public void c() {} // +1
1567 }
1568 }
1569 }",
1570 "foo.java",
1571 |metric| {
1572 insta::assert_json_snapshot!(
1573 metric.npm,
1574 @r###"
1575 {
1576 "classes": 3.0,
1577 "interfaces": 0.0,
1578 "class_methods": 3.0,
1579 "interface_methods": 0.0,
1580 "classes_average": 1.0,
1581 "interfaces_average": null,
1582 "total": 3.0,
1583 "total_methods": 3.0,
1584 "average": 1.0
1585 }"###
1586 );
1587 },
1588 );
1589 }
1590
1591 #[test]
1592 fn java_local_inner_classes() {
1593 check_metrics::<JavaParser>(
1594 "class X {
1595 public void a() { // +1
1596 class Y {
1597 public void b() { // +1
1598 class Z {
1599 public void c() {} // +1
1600 }
1601 }
1602 }
1603 }
1604 }",
1605 "foo.java",
1606 |metric| {
1607 insta::assert_json_snapshot!(
1608 metric.npm,
1609 @r###"
1610 {
1611 "classes": 3.0,
1612 "interfaces": 0.0,
1613 "class_methods": 3.0,
1614 "interface_methods": 0.0,
1615 "classes_average": 1.0,
1616 "interfaces_average": null,
1617 "total": 3.0,
1618 "total_methods": 3.0,
1619 "average": 1.0
1620 }"###
1621 );
1622 },
1623 );
1624 }
1625
1626 #[test]
1627 fn java_anonymous_inner_classes() {
1628 check_metrics::<JavaParser>(
1629 "abstract class X {
1630 public abstract void a(); // +1
1631 }
1632 abstract class Y {
1633 abstract void b();
1634 }
1635 class Z {
1636 public void c(){ // +1
1637 X x = new X() {
1638 @Override
1639 public void a() {} // +1
1640 };
1641 Y y = new Y() {
1642 @Override
1643 void b() {}
1644 };
1645 }
1646 }",
1647 "foo.java",
1648 |metric| {
1649 insta::assert_json_snapshot!(
1650 metric.npm,
1651 @r###"
1652 {
1653 "classes": 3.0,
1654 "interfaces": 0.0,
1655 "class_methods": 5.0,
1656 "interface_methods": 0.0,
1657 "classes_average": 0.6,
1658 "interfaces_average": null,
1659 "total": 3.0,
1660 "total_methods": 5.0,
1661 "average": 0.6
1662 }"###
1663 );
1664 },
1665 );
1666 }
1667
1668 #[test]
1669 fn java_interface() {
1670 check_metrics::<JavaParser>(
1671 "interface X {
1672 public int a(); // +1
1673 boolean b(); // +1
1674 void c(); // +1
1675 }",
1676 "foo.java",
1677 |metric| {
1678 insta::assert_json_snapshot!(
1679 metric.npm,
1680 @r###"
1681 {
1682 "classes": 0.0,
1683 "interfaces": 3.0,
1684 "class_methods": 0.0,
1685 "interface_methods": 3.0,
1686 "classes_average": null,
1687 "interfaces_average": 1.0,
1688 "total": 3.0,
1689 "total_methods": 3.0,
1690 "average": 1.0
1691 }"###
1692 );
1693 },
1694 );
1695 }
1696
1697 #[test]
1701 fn java_enum_counts_methods() {
1702 check_metrics::<JavaParser>(
1703 "enum Status {
1704 ACTIVE, INACTIVE;
1705 public int code() { return 0; } // +1 public
1706 private void reset() {} // not public
1707 }",
1708 "foo.java",
1709 |metric| {
1710 assert_eq!(metric.npm.class_nm_sum(), 2.0);
1711 assert_eq!(metric.npm.class_npm_sum(), 1.0);
1712 },
1713 );
1714 }
1715
1716 #[test]
1719 fn java_record_counts_methods() {
1720 check_metrics::<JavaParser>(
1721 "record Point(int x, int y) {
1722 public int sum() { return x + y; }
1723 public Point() { this(0, 0); }
1724 }",
1725 "foo.java",
1726 |metric| {
1727 assert_eq!(metric.npm.class_nm_sum(), 2.0);
1732 assert_eq!(metric.npm.class_npm_sum(), 2.0);
1733 },
1734 );
1735 }
1736
1737 #[test]
1738 fn java_annotation_type_counts_elements() {
1739 check_func_space::<JavaParser, _>(
1749 "@interface Marker {
1750 String value() default \"\";
1751 int priority() default 0;
1752 }",
1753 "foo.java",
1754 |func_space| {
1755 assert_eq!(func_space.metrics.npm.interface_nm_sum(), 2.0);
1756 assert_eq!(func_space.metrics.npm.interface_npm_sum(), 2.0);
1757 assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
1758 },
1759 );
1760 }
1761
1762 #[test]
1763 fn java_interfaces_and_class() {
1764 check_metrics::<JavaParser>(
1765 "interface X {
1766 void a(); // +1
1767 }
1768 interface Y extends X {
1769 void b(); // +1
1770 void c(); // +1
1771 }
1772 class Z implements Y {
1773 @Override
1774 public void a() {} // +1
1775 @Override
1776 public void b() {} // +1
1777 @Override
1778 public void c() {} // +1
1779 void d() {}
1780 void e() {}
1781 }",
1782 "foo.java",
1783 |metric| {
1784 insta::assert_json_snapshot!(
1785 metric.npm,
1786 @r###"
1787 {
1788 "classes": 3.0,
1789 "interfaces": 3.0,
1790 "class_methods": 5.0,
1791 "interface_methods": 3.0,
1792 "classes_average": 0.6,
1793 "interfaces_average": 1.0,
1794 "total": 6.0,
1795 "total_methods": 8.0,
1796 "average": 0.75
1797 }"###
1798 );
1799 },
1800 );
1801 }
1802
1803 #[test]
1804 fn csharp_constructors() {
1805 check_metrics::<CsharpParser>(
1806 "class A {
1807 public A() {}
1808 public A(int x) {}
1809 A(int x, int y) {}
1810 }",
1811 "foo.cs",
1812 |metric| insta::assert_json_snapshot!(metric.npm),
1813 );
1814 }
1815
1816 #[test]
1817 fn csharp_methods_returning_primitive_types() {
1818 check_metrics::<CsharpParser>(
1819 "class A {
1820 public int M1() { return 1; }
1821 public bool M2() { return true; }
1822 public double M3() { return 0.0; }
1823 int M4() { return 0; }
1824 }",
1825 "foo.cs",
1826 |metric| insta::assert_json_snapshot!(metric.npm),
1827 );
1828 }
1829
1830 #[test]
1831 fn csharp_methods_returning_arrays() {
1832 check_metrics::<CsharpParser>(
1833 "class A {
1834 public int[] M1() { return new int[0]; }
1835 public string[] M2() { return new string[0]; }
1836 int[] M3() { return new int[0]; }
1837 }",
1838 "foo.cs",
1839 |metric| insta::assert_json_snapshot!(metric.npm),
1840 );
1841 }
1842
1843 #[test]
1844 fn csharp_methods_returning_objects() {
1845 check_metrics::<CsharpParser>(
1846 "class Point { }
1847 class A {
1848 public Point M1() { return new Point(); }
1849 public string M2() { return \"\"; }
1850 Point M3() { return new Point(); }
1851 }",
1852 "foo.cs",
1853 |metric| insta::assert_json_snapshot!(metric.npm),
1854 );
1855 }
1856
1857 #[test]
1858 fn csharp_methods_with_generic_types() {
1859 check_metrics::<CsharpParser>(
1860 "class A {
1861 public System.Collections.Generic.List<int> M1() { return null; }
1862 public System.Collections.Generic.Dictionary<string, int> M2() { return null; }
1863 System.Collections.Generic.List<string> M3() { return null; }
1864 }",
1865 "foo.cs",
1866 |metric| insta::assert_json_snapshot!(metric.npm),
1867 );
1868 }
1869
1870 #[test]
1871 fn csharp_method_modifiers() {
1872 check_metrics::<CsharpParser>(
1873 "class A {
1874 public void M1() {}
1875 private void M2() {}
1876 protected void M3() {}
1877 internal void M4() {}
1878 public static void M5() {}
1879 public virtual void M6() {}
1880 }",
1881 "foo.cs",
1882 |metric| insta::assert_json_snapshot!(metric.npm),
1883 );
1884 }
1885
1886 #[test]
1887 fn csharp_classes() {
1888 check_metrics::<CsharpParser>(
1889 "class A {
1890 public void M1() {}
1891 public void M2() {}
1892 void M3() {}
1893 }
1894 class B {
1895 public int N() { return 0; }
1896 int Hidden() { return 0; }
1897 }",
1898 "foo.cs",
1899 |metric| insta::assert_json_snapshot!(metric.npm),
1900 );
1901 }
1902
1903 #[test]
1904 fn csharp_nested_inner_classes() {
1905 check_metrics::<CsharpParser>(
1906 "class Outer {
1907 public void M() {}
1908 void Hidden() {}
1909 public class Inner {
1910 public void N() {}
1911 void HiddenN() {}
1912 }
1913 }",
1914 "foo.cs",
1915 |metric| insta::assert_json_snapshot!(metric.npm),
1916 );
1917 }
1918
1919 #[test]
1920 fn csharp_property_accessors() {
1921 check_metrics::<CsharpParser>(
1926 "class A {
1927 int _w;
1928 public int X { get; set; }
1929 public int Y { get; }
1930 public int Z { get; init; }
1931 public int W => _w;
1932 int Hidden { get; set; }
1933 }",
1934 "foo.cs",
1935 |metric| insta::assert_json_snapshot!(metric.npm),
1936 );
1937 }
1938
1939 #[test]
1940 fn csharp_local_functions() {
1941 check_metrics::<CsharpParser>(
1948 "class A {
1949 public void Outer() {
1950 void Local() {}
1951 Local();
1952 }
1953 private void Hidden() {}
1954 }",
1955 "foo.cs",
1956 |metric| {
1957 assert_eq!(metric.npm.class_nm_sum(), 2.0, "Local must not leak");
1958 assert_eq!(metric.npm.class_npm_sum(), 1.0, "only Outer is public");
1959 insta::assert_json_snapshot!(metric.npm);
1960 },
1961 );
1962 }
1963
1964 #[test]
1965 fn csharp_interface() {
1966 check_metrics::<CsharpParser>(
1968 "interface I {
1969 int M1();
1970 bool M2();
1971 int X { get; set; }
1972 }",
1973 "foo.cs",
1974 |metric| insta::assert_json_snapshot!(metric.npm),
1975 );
1976 }
1977
1978 #[test]
1979 fn csharp_interfaces_and_class() {
1980 check_metrics::<CsharpParser>(
1981 "interface I1 { int M1(); }
1982 interface I2 { bool M2(); float M3(); }
1983 class A {
1984 public void M() {}
1985 void Hidden() {}
1986 }",
1987 "foo.cs",
1988 |metric| insta::assert_json_snapshot!(metric.npm),
1989 );
1990 }
1991
1992 #[test]
1993 fn php_no_class_methods() {
1994 check_metrics::<PhpParser>(
1995 "<?php class A { public int $x = 0; }",
1996 "foo.php",
1997 |metric| insta::assert_json_snapshot!(metric.npm),
1998 );
1999 }
2000
2001 #[test]
2002 fn php_one_public_method() {
2003 check_metrics::<PhpParser>(
2004 "<?php class A { public function f(): void {} }",
2005 "foo.php",
2006 |metric| insta::assert_json_snapshot!(metric.npm),
2007 );
2008 }
2009
2010 #[test]
2011 fn php_one_private_method() {
2012 check_metrics::<PhpParser>(
2013 "<?php class A { private function f(): void {} }",
2014 "foo.php",
2015 |metric| insta::assert_json_snapshot!(metric.npm),
2016 );
2017 }
2018
2019 #[test]
2020 fn php_one_protected_method() {
2021 check_metrics::<PhpParser>(
2022 "<?php class A { protected function f(): void {} }",
2023 "foo.php",
2024 |metric| insta::assert_json_snapshot!(metric.npm),
2025 );
2026 }
2027
2028 #[test]
2029 fn php_mixed_visibility_methods() {
2030 check_metrics::<PhpParser>(
2031 "<?php
2032 class A {
2033 public function a(): void {}
2034 public function b(): void {}
2035 private function c(): void {}
2036 protected function d(): void {}
2037 }",
2038 "foo.php",
2039 |metric| insta::assert_json_snapshot!(metric.npm),
2040 );
2041 }
2042
2043 #[test]
2044 fn php_static_public_method() {
2045 check_metrics::<PhpParser>(
2046 "<?php class A { public static function f(): void {} }",
2047 "foo.php",
2048 |metric| insta::assert_json_snapshot!(metric.npm),
2049 );
2050 }
2051
2052 #[test]
2053 fn php_abstract_method() {
2054 check_metrics::<PhpParser>(
2055 "<?php abstract class A { abstract public function f(): void; }",
2056 "foo.php",
2057 |metric| insta::assert_json_snapshot!(metric.npm),
2058 );
2059 }
2060
2061 #[test]
2062 fn php_final_public_method() {
2063 check_metrics::<PhpParser>(
2064 "<?php class A { final public function f(): void {} }",
2065 "foo.php",
2066 |metric| insta::assert_json_snapshot!(metric.npm),
2067 );
2068 }
2069
2070 #[test]
2071 fn php_interface_methods() {
2072 check_metrics::<PhpParser>(
2074 "<?php
2075 interface I {
2076 public function a(): void;
2077 public function b(): int;
2078 }",
2079 "foo.php",
2080 |metric| insta::assert_json_snapshot!(metric.npm),
2081 );
2082 }
2083
2084 #[test]
2085 fn php_enum_methods() {
2086 check_metrics::<PhpParser>(
2088 "<?php
2089 enum Color {
2090 case Red;
2091 case Green;
2092 public function label(): string {
2093 return match ($this) {
2094 Color::Red => 'r',
2095 Color::Green => 'g',
2096 };
2097 }
2098 }",
2099 "foo.php",
2100 |metric| insta::assert_json_snapshot!(metric.npm),
2101 );
2102 }
2103
2104 #[test]
2105 fn php_trait_methods() {
2106 check_metrics::<PhpParser>(
2107 "<?php
2108 trait T {
2109 public function a(): void {}
2110 private function b(): void {}
2111 }",
2112 "foo.php",
2113 |metric| insta::assert_json_snapshot!(metric.npm),
2114 );
2115 }
2116
2117 #[test]
2118 fn php_no_explicit_visibility_method_excluded() {
2119 check_metrics::<PhpParser>(
2122 "<?php class A { function f(): void {} }",
2123 "foo.php",
2124 |metric| insta::assert_json_snapshot!(metric.npm),
2125 );
2126 }
2127
2128 #[test]
2131 fn kotlin_empty_class_no_methods() {
2132 check_metrics::<KotlinParser>("class C {}", "foo.kt", |metric| {
2133 assert_eq!(metric.npm.class_npm_sum(), 0.0);
2134 assert_eq!(metric.npm.class_nm_sum(), 0.0);
2135 assert_eq!(metric.npm.interface_nm_sum(), 0.0);
2136 insta::assert_json_snapshot!(metric.npm);
2137 });
2138 }
2139
2140 #[test]
2141 fn kotlin_public_methods_default() {
2142 check_metrics::<KotlinParser>(
2144 "class C {
2145 fun a() {}
2146 fun b(): Int = 0
2147 fun c(x: Int): Int = x
2148 }",
2149 "foo.kt",
2150 |metric| {
2151 assert_eq!(metric.npm.class_npm_sum(), 3.0);
2152 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2153 insta::assert_json_snapshot!(metric.npm);
2154 },
2155 );
2156 }
2157
2158 #[test]
2159 fn kotlin_private_method() {
2160 check_metrics::<KotlinParser>(
2161 "class C {
2162 fun a() {} // public
2163 private fun b() {} // private
2164 fun c() {} // public
2165 }",
2166 "foo.kt",
2167 |metric| {
2168 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2169 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2170 insta::assert_json_snapshot!(metric.npm);
2171 },
2172 );
2173 }
2174
2175 #[test]
2176 fn kotlin_protected_internal_methods() {
2177 check_metrics::<KotlinParser>(
2178 "open class C {
2179 protected fun a() {}
2180 internal fun b() {}
2181 public fun c() {}
2182 }",
2183 "foo.kt",
2184 |metric| {
2185 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2186 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2187 insta::assert_json_snapshot!(metric.npm);
2188 },
2189 );
2190 }
2191
2192 #[test]
2193 fn kotlin_secondary_constructor_counts() {
2194 check_metrics::<KotlinParser>(
2197 "class C {
2198 private var a: Int = 0
2199 constructor(n: Int) { a = n }
2200 constructor(n: Int, m: Int) { a = n + m }
2201 fun get(): Int = a
2202 }",
2203 "foo.kt",
2204 |metric| {
2205 assert_eq!(metric.npm.class_npm_sum(), 3.0);
2206 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2207 insta::assert_json_snapshot!(metric.npm);
2208 },
2209 );
2210 }
2211
2212 #[test]
2213 fn kotlin_companion_object_methods() {
2214 check_metrics::<KotlinParser>(
2217 "class Holder {
2218 fun memberFn() {}
2219 companion object {
2220 fun staticFn() {}
2221 private fun secret() {}
2222 }
2223 }",
2224 "foo.kt",
2225 |metric| {
2226 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2227 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2228 insta::assert_json_snapshot!(metric.npm);
2229 },
2230 );
2231 }
2232
2233 #[test]
2234 fn kotlin_data_class_methods() {
2235 check_metrics::<KotlinParser>(
2238 "data class Point(val x: Int, val y: Int) {
2239 fun manhattan(): Int = x + y
2240 private fun internal_(): Int = 0
2241 }",
2242 "foo.kt",
2243 |metric| {
2244 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2245 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2246 insta::assert_json_snapshot!(metric.npm);
2247 },
2248 );
2249 }
2250
2251 #[test]
2252 fn kotlin_object_singleton_methods() {
2253 check_metrics::<KotlinParser>(
2254 "object Util {
2255 fun add(a: Int, b: Int): Int = a + b
2256 private fun helper(): Int = 0
2257 }",
2258 "foo.kt",
2259 |metric| {
2260 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2261 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2262 insta::assert_json_snapshot!(metric.npm);
2263 },
2264 );
2265 }
2266
2267 #[test]
2268 fn kotlin_interface_methods() {
2269 check_func_space::<KotlinParser, _>(
2270 "interface I {
2271 fun work(): Int
2272 fun describe(): String
2273 }",
2274 "foo.kt",
2275 |func_space| {
2276 let metric = &func_space.metrics;
2277 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
2278 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
2279 assert_eq!(metric.npm.class_nm_sum(), 0.0);
2280 insta::assert_json_snapshot!(metric.npm);
2281 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2282 },
2283 );
2284 }
2285
2286 #[test]
2287 fn kotlin_interface_with_default_method() {
2288 check_func_space::<KotlinParser, _>(
2289 "interface I {
2290 fun abs(n: Int): Int {
2291 return if (n < 0) -n else n
2292 }
2293 fun pure(): Int
2294 }",
2295 "foo.kt",
2296 |func_space| {
2297 let metric = &func_space.metrics;
2298 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
2299 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
2300 insta::assert_json_snapshot!(metric.npm);
2301 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2302 },
2303 );
2304 }
2305
2306 #[test]
2307 fn kotlin_override_fun_counts() {
2308 check_metrics::<KotlinParser>(
2309 "open class Base {
2310 open fun greet(): String = \"hi\"
2311 }
2312 class Sub : Base() {
2313 override fun greet(): String = \"yo\"
2314 private fun secret() {}
2315 }",
2316 "foo.kt",
2317 |metric| {
2318 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2322 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2323 insta::assert_json_snapshot!(metric.npm);
2324 },
2325 );
2326 }
2327
2328 #[test]
2329 fn kotlin_nested_class_methods() {
2330 check_metrics::<KotlinParser>(
2331 "class Outer {
2332 fun outerM() {}
2333 class Nested {
2334 fun nestedM() {}
2335 private fun nestedSecret() {}
2336 }
2337 }",
2338 "foo.kt",
2339 |metric| {
2340 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2341 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2342 insta::assert_json_snapshot!(metric.npm);
2343 },
2344 );
2345 }
2346
2347 #[test]
2348 fn kotlin_inner_class_methods() {
2349 check_metrics::<KotlinParser>(
2350 "class Outer {
2351 fun outerM() {}
2352 inner class Inner {
2353 fun innerM() {}
2354 }
2355 }",
2356 "foo.kt",
2357 |metric| {
2358 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2359 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2360 insta::assert_json_snapshot!(metric.npm);
2361 },
2362 );
2363 }
2364
2365 #[test]
2366 fn kotlin_top_level_function_excluded() {
2367 check_metrics::<KotlinParser>(
2369 "fun freeFn() {}
2370class C {
2371 fun m() {}
2372}",
2373 "foo.kt",
2374 |metric| {
2375 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2376 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2377 insta::assert_json_snapshot!(metric.npm);
2378 },
2379 );
2380 }
2381
2382 #[test]
2383 fn kotlin_extension_function_excluded() {
2384 check_metrics::<KotlinParser>(
2387 "fun List<Int>.sum2(): Int = this.size
2388class C {
2389 fun m() {}
2390}",
2391 "foo.kt",
2392 |metric| {
2393 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2394 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2395 insta::assert_json_snapshot!(metric.npm);
2396 },
2397 );
2398 }
2399
2400 #[test]
2401 fn kotlin_class_in_interface() {
2402 check_func_space::<KotlinParser, _>(
2407 "interface Outer {
2408 fun work(): Int
2409 class Helper {
2410 fun help() {}
2411 }
2412 }",
2413 "foo.kt",
2414 |func_space| {
2415 let metric = &func_space.metrics;
2416 assert_eq!(metric.npm.interface_npm_sum(), 1.0);
2417 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2418 insta::assert_json_snapshot!(metric.npm);
2419 assert_child_space_kind(&func_space, "Outer", SpaceKind::Interface);
2420 let outer = func_space
2421 .spaces
2422 .iter()
2423 .find(|s| s.name.as_deref() == Some("Outer"))
2424 .expect("Outer FuncSpace");
2425 assert_child_space_kind(outer, "Helper", SpaceKind::Class);
2426 },
2427 );
2428 }
2429
2430 #[test]
2431 fn kotlin_interface_in_class() {
2432 check_func_space::<KotlinParser, _>(
2437 "class Outer {
2438 fun work() {}
2439 interface Sub {
2440 fun help(): Int
2441 }
2442 }",
2443 "foo.kt",
2444 |func_space| {
2445 let metric = &func_space.metrics;
2446 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2447 assert_eq!(metric.npm.interface_npm_sum(), 1.0);
2448 insta::assert_json_snapshot!(metric.npm);
2449 assert_child_space_kind(&func_space, "Outer", SpaceKind::Class);
2450 let outer = func_space
2451 .spaces
2452 .iter()
2453 .find(|s| s.name.as_deref() == Some("Outer"))
2454 .expect("Outer FuncSpace");
2455 assert_child_space_kind(outer, "Sub", SpaceKind::Interface);
2456 },
2457 );
2458 }
2459
2460 #[test]
2461 fn kotlin_init_block_not_a_method() {
2462 check_metrics::<KotlinParser>(
2465 "class C(val n: Int) {
2466 init { require(n >= 0) }
2467 fun get(): Int = n
2468 }",
2469 "foo.kt",
2470 |metric| {
2471 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2472 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2473 insta::assert_json_snapshot!(metric.npm);
2474 },
2475 );
2476 }
2477
2478 #[test]
2494 fn typescript_empty_class_no_methods() {
2495 check_metrics::<TypescriptParser>("class C {}", "foo.ts", |metric| {
2496 assert_eq!(metric.npm.class_npm_sum(), 0.0);
2497 assert_eq!(metric.npm.class_nm_sum(), 0.0);
2498 insta::assert_json_snapshot!(metric.npm);
2499 });
2500 }
2501
2502 #[test]
2503 fn typescript_default_public_methods() {
2504 check_metrics::<TypescriptParser>(
2505 "class C {
2506 a(): void {}
2507 b(): number { return 0; }
2508 c(x: number): number { return x; }
2509 }",
2510 "foo.ts",
2511 |metric| {
2512 assert_eq!(metric.npm.class_npm_sum(), 3.0);
2513 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2514 insta::assert_json_snapshot!(metric.npm);
2515 },
2516 );
2517 }
2518
2519 #[test]
2520 fn typescript_method_visibility() {
2521 check_metrics::<TypescriptParser>(
2522 "class C {
2523 public a(): void {}
2524 private b(): void {}
2525 protected c(): void {}
2526 d(): void {}
2527 }",
2528 "foo.ts",
2529 |metric| {
2530 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2532 assert_eq!(metric.npm.class_nm_sum(), 4.0);
2533 insta::assert_json_snapshot!(metric.npm);
2534 },
2535 );
2536 }
2537
2538 #[test]
2539 fn typescript_static_methods() {
2540 check_metrics::<TypescriptParser>(
2541 "class C {
2542 static a(): void {}
2543 public static b(): void {}
2544 private static c(): void {}
2545 }",
2546 "foo.ts",
2547 |metric| {
2548 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2550 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2551 insta::assert_json_snapshot!(metric.npm);
2552 },
2553 );
2554 }
2555
2556 #[test]
2557 fn typescript_constructor_counts_as_method() {
2558 check_metrics::<TypescriptParser>(
2560 "class C {
2561 constructor(public x: number) {}
2562 m(): void {}
2563 }",
2564 "foo.ts",
2565 |metric| {
2566 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2567 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2568 insta::assert_json_snapshot!(metric.npm);
2569 },
2570 );
2571 }
2572
2573 #[test]
2574 fn typescript_getter_setter_each_count_once() {
2575 check_metrics::<TypescriptParser>(
2578 "class C {
2579 private _x: number = 0;
2580 get x(): number { return this._x; }
2581 set x(v: number) { this._x = v; }
2582 }",
2583 "foo.ts",
2584 |metric| {
2585 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2586 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2587 insta::assert_json_snapshot!(metric.npm);
2588 },
2589 );
2590 }
2591
2592 #[test]
2593 fn typescript_arrow_field_counts_as_method() {
2594 check_metrics::<TypescriptParser>(
2596 "class C {
2597 a: number = 0;
2598 arrow = () => this.a;
2599 private secret = () => this.a;
2600 }",
2601 "foo.ts",
2602 |metric| {
2603 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2605 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2606 insta::assert_json_snapshot!(metric.npm);
2607 },
2608 );
2609 }
2610
2611 #[test]
2612 fn typescript_method_overload_counts_once() {
2613 check_metrics::<TypescriptParser>(
2616 "class C {
2617 m(x: number): void;
2618 m(x: string): void;
2619 m(x: any): void {}
2620 }",
2621 "foo.ts",
2622 |metric| {
2623 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2624 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2625 insta::assert_json_snapshot!(metric.npm);
2626 },
2627 );
2628 }
2629
2630 #[test]
2631 fn typescript_abstract_class_methods() {
2632 check_metrics::<TypescriptParser>(
2635 "abstract class C {
2636 abstract a(): void;
2637 public abstract b(): number;
2638 protected abstract c(): void;
2639 public m(): void {}
2640 private n(): void {}
2641 }",
2642 "foo.ts",
2643 |metric| {
2644 assert_eq!(metric.npm.class_npm_sum(), 3.0);
2647 assert_eq!(metric.npm.class_nm_sum(), 5.0);
2648 insta::assert_json_snapshot!(metric.npm);
2649 },
2650 );
2651 }
2652
2653 #[test]
2654 fn typescript_interface_methods() {
2655 check_func_space::<TypescriptParser, _>(
2657 "interface I {
2658 a(): void;
2659 b(x: number): number;
2660 c: string;
2661 }",
2662 "foo.ts",
2663 |func_space| {
2664 let metric = &func_space.metrics;
2665 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
2666 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
2667 assert_eq!(metric.npm.class_nm_sum(), 0.0);
2668 insta::assert_json_snapshot!(metric.npm);
2669 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2670 },
2671 );
2672 }
2673
2674 #[test]
2675 fn typescript_generic_class_methods() {
2676 check_metrics::<TypescriptParser>(
2677 "class Box<T> {
2678 value: T;
2679 set(v: T): void { this.value = v; }
2680 get(): T { return this.value; }
2681 }",
2682 "foo.ts",
2683 |metric| {
2684 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2685 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2686 insta::assert_json_snapshot!(metric.npm);
2687 },
2688 );
2689 }
2690
2691 #[test]
2692 fn typescript_multiple_classes_and_interface() {
2693 check_func_space::<TypescriptParser, _>(
2694 "class A { m(): void {} }
2695 class B { private h(): void {} }
2696 interface I { p(): number; }",
2697 "foo.ts",
2698 |func_space| {
2699 let metric = &func_space.metrics;
2700 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2701 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2702 assert_eq!(metric.npm.interface_npm_sum(), 1.0);
2703 assert_eq!(metric.npm.interface_nm_sum(), 1.0);
2704 insta::assert_json_snapshot!(metric.npm);
2705 assert_child_space_kind(&func_space, "A", SpaceKind::Class);
2706 assert_child_space_kind(&func_space, "B", SpaceKind::Class);
2707 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2708 },
2709 );
2710 }
2711
2712 #[test]
2715 fn tsx_empty_class_no_methods() {
2716 check_metrics::<TsxParser>("class C {}", "foo.tsx", |metric| {
2717 assert_eq!(metric.npm.class_npm_sum(), 0.0);
2718 assert_eq!(metric.npm.class_nm_sum(), 0.0);
2719 insta::assert_json_snapshot!(metric.npm);
2720 });
2721 }
2722
2723 #[test]
2724 fn tsx_default_public_methods() {
2725 check_metrics::<TsxParser>(
2726 "class C {
2727 a(): void {}
2728 b(): number { return 0; }
2729 }",
2730 "foo.tsx",
2731 |metric| {
2732 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2733 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2734 insta::assert_json_snapshot!(metric.npm);
2735 },
2736 );
2737 }
2738
2739 #[test]
2740 fn tsx_method_visibility() {
2741 check_metrics::<TsxParser>(
2742 "class C {
2743 public a(): void {}
2744 private b(): void {}
2745 protected c(): void {}
2746 }",
2747 "foo.tsx",
2748 |metric| {
2749 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2750 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2751 insta::assert_json_snapshot!(metric.npm);
2752 },
2753 );
2754 }
2755
2756 #[test]
2757 fn tsx_static_methods() {
2758 check_metrics::<TsxParser>(
2759 "class C {
2760 static a(): void {}
2761 private static b(): void {}
2762 }",
2763 "foo.tsx",
2764 |metric| {
2765 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2766 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2767 insta::assert_json_snapshot!(metric.npm);
2768 },
2769 );
2770 }
2771
2772 #[test]
2773 fn tsx_constructor_counts_as_method() {
2774 check_metrics::<TsxParser>(
2775 "class C {
2776 constructor() {}
2777 m(): void {}
2778 }",
2779 "foo.tsx",
2780 |metric| {
2781 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2782 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2783 insta::assert_json_snapshot!(metric.npm);
2784 },
2785 );
2786 }
2787
2788 #[test]
2789 fn tsx_getter_setter_each_count_once() {
2790 check_metrics::<TsxParser>(
2791 "class C {
2792 private _x: number = 0;
2793 get x(): number { return this._x; }
2794 set x(v: number) { this._x = v; }
2795 }",
2796 "foo.tsx",
2797 |metric| {
2798 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2799 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2800 insta::assert_json_snapshot!(metric.npm);
2801 },
2802 );
2803 }
2804
2805 #[test]
2806 fn tsx_arrow_field_counts_as_method() {
2807 check_metrics::<TsxParser>(
2808 "class C {
2809 arrow = () => 1;
2810 private secret = () => 2;
2811 }",
2812 "foo.tsx",
2813 |metric| {
2814 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2815 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2816 insta::assert_json_snapshot!(metric.npm);
2817 },
2818 );
2819 }
2820
2821 #[test]
2822 fn tsx_method_overload_counts_once() {
2823 check_metrics::<TsxParser>(
2824 "class C {
2825 m(x: number): void;
2826 m(x: string): void;
2827 m(x: any): void {}
2828 }",
2829 "foo.tsx",
2830 |metric| {
2831 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2832 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2833 insta::assert_json_snapshot!(metric.npm);
2834 },
2835 );
2836 }
2837
2838 #[test]
2839 fn tsx_abstract_class_methods() {
2840 check_metrics::<TsxParser>(
2841 "abstract class C {
2842 abstract a(): void;
2843 public m(): void {}
2844 private n(): void {}
2845 }",
2846 "foo.tsx",
2847 |metric| {
2848 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2850 assert_eq!(metric.npm.class_nm_sum(), 3.0);
2851 insta::assert_json_snapshot!(metric.npm);
2852 },
2853 );
2854 }
2855
2856 #[test]
2857 fn tsx_interface_methods() {
2858 check_func_space::<TsxParser, _>(
2859 "interface I {
2860 a(): void;
2861 b(): number;
2862 }",
2863 "foo.tsx",
2864 |func_space| {
2865 let metric = &func_space.metrics;
2866 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
2867 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
2868 insta::assert_json_snapshot!(metric.npm);
2869 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2870 },
2871 );
2872 }
2873
2874 #[test]
2875 fn tsx_generic_class_methods() {
2876 check_metrics::<TsxParser>(
2877 "class Box<T> { value: T; set(v: T): void { this.value = v; } }",
2878 "foo.tsx",
2879 |metric| {
2880 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2881 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2882 insta::assert_json_snapshot!(metric.npm);
2883 },
2884 );
2885 }
2886
2887 #[test]
2888 fn tsx_multiple_classes_and_interface() {
2889 check_func_space::<TsxParser, _>(
2890 "class A { m(): void {} }
2891 class B { private h(): void {} }
2892 interface I { p(): number; }",
2893 "foo.tsx",
2894 |func_space| {
2895 let metric = &func_space.metrics;
2896 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2897 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2898 assert_eq!(metric.npm.interface_npm_sum(), 1.0);
2899 assert_eq!(metric.npm.interface_nm_sum(), 1.0);
2900 insta::assert_json_snapshot!(metric.npm);
2901 assert_child_space_kind(&func_space, "A", SpaceKind::Class);
2902 assert_child_space_kind(&func_space, "B", SpaceKind::Class);
2903 assert_child_space_kind(&func_space, "I", SpaceKind::Interface);
2904 },
2905 );
2906 }
2907
2908 #[test]
2917 fn ruby_no_class_methods() {
2918 check_metrics::<RubyParser>("def foo\n 1\nend\n", "foo.rb", |metric| {
2919 assert_eq!(metric.npm.class_npm_sum(), 0.0);
2920 assert_eq!(metric.npm.class_nm_sum(), 0.0);
2921 insta::assert_json_snapshot!(metric.npm);
2922 });
2923 }
2924
2925 #[test]
2926 fn ruby_one_public_method() {
2927 check_metrics::<RubyParser>(
2929 "class A\n def f\n 1\n end\nend\n",
2930 "foo.rb",
2931 |metric| {
2932 assert_eq!(metric.npm.class_npm_sum(), 1.0);
2933 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2934 insta::assert_json_snapshot!(metric.npm);
2935 },
2936 );
2937 }
2938
2939 #[test]
2940 fn ruby_one_private_method() {
2941 check_metrics::<RubyParser>(
2943 "class A\n private\n def f\n 1\n end\nend\n",
2944 "foo.rb",
2945 |metric| {
2946 assert_eq!(metric.npm.class_npm_sum(), 0.0);
2947 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2948 insta::assert_json_snapshot!(metric.npm);
2949 },
2950 );
2951 }
2952
2953 #[test]
2954 fn ruby_one_protected_method() {
2955 check_metrics::<RubyParser>(
2956 "class A\n protected\n def f\n 1\n end\nend\n",
2957 "foo.rb",
2958 |metric| {
2959 assert_eq!(metric.npm.class_npm_sum(), 0.0);
2960 assert_eq!(metric.npm.class_nm_sum(), 1.0);
2961 insta::assert_json_snapshot!(metric.npm);
2962 },
2963 );
2964 }
2965
2966 #[test]
2967 fn ruby_mixed_visibility_methods() {
2968 check_metrics::<RubyParser>(
2972 "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",
2973 "foo.rb",
2974 |metric| {
2975 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2976 assert_eq!(metric.npm.class_nm_sum(), 4.0);
2977 insta::assert_json_snapshot!(metric.npm);
2978 },
2979 );
2980 }
2981
2982 #[test]
2983 fn ruby_singleton_method_is_counted() {
2984 check_metrics::<RubyParser>(
2986 "class A\n def self.f\n 1\n end\n def g\n 1\n end\nend\n",
2987 "foo.rb",
2988 |metric| {
2989 assert_eq!(metric.npm.class_npm_sum(), 2.0);
2990 assert_eq!(metric.npm.class_nm_sum(), 2.0);
2991 insta::assert_json_snapshot!(metric.npm);
2992 },
2993 );
2994 }
2995
2996 #[test]
2997 fn ruby_singleton_class_methods() {
2998 check_metrics::<RubyParser>(
3001 "class A\n class << self\n def s\n 1\n end\n def t\n 2\n end\n end\nend\n",
3002 "foo.rb",
3003 |metric| {
3004 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3005 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3006 insta::assert_json_snapshot!(metric.npm);
3007 },
3008 );
3009 }
3010
3011 #[test]
3012 fn ruby_argument_form_visibility_does_not_flip() {
3013 check_metrics::<RubyParser>(
3017 "class A\n def y\n 1\n end\n private :y\n def z\n 1\n end\nend\n",
3018 "foo.rb",
3019 |metric| {
3020 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3021 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3022 insta::assert_json_snapshot!(metric.npm);
3023 },
3024 );
3025 }
3026
3027 #[test]
3028 fn ruby_multiple_classes() {
3029 check_metrics::<RubyParser>(
3030 "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",
3031 "foo.rb",
3032 |metric| {
3033 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3035 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3036 insta::assert_json_snapshot!(metric.npm);
3037 },
3038 );
3039 }
3040
3041 #[test]
3042 fn ruby_module_methods_not_counted() {
3043 check_metrics::<RubyParser>(
3046 "module M\n def f\n 1\n end\n def g\n 1\n end\nend\n",
3047 "foo.rb",
3048 |metric| {
3049 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3050 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3051 insta::assert_json_snapshot!(metric.npm);
3052 },
3053 );
3054 }
3055
3056 #[test]
3057 fn ruby_class_with_inheritance() {
3058 check_metrics::<RubyParser>(
3060 "class A < B\n def f\n 1\n end\n def g\n 1\n end\nend\n",
3061 "foo.rb",
3062 |metric| {
3063 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3064 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3065 insta::assert_json_snapshot!(metric.npm);
3066 },
3067 );
3068 }
3069
3070 #[test]
3071 fn ruby_visibility_resets_between_classes() {
3072 check_metrics::<RubyParser>(
3075 "class A\n private\n def a\n 1\n end\nend\nclass B\n def b\n 1\n end\nend\n",
3076 "foo.rb",
3077 |metric| {
3078 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3080 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3081 insta::assert_json_snapshot!(metric.npm);
3082 },
3083 );
3084 }
3085
3086 #[test]
3087 fn ruby_empty_class_no_methods() {
3088 check_metrics::<RubyParser>("class Empty\nend\n", "foo.rb", |metric| {
3089 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3090 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3091 insta::assert_json_snapshot!(metric.npm);
3092 });
3093 }
3094
3095 #[test]
3108 fn python_empty_class_no_methods() {
3109 check_metrics::<PythonParser>("class C:\n pass\n", "foo.py", |metric| {
3110 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3111 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3112 insta::assert_json_snapshot!(metric.npm);
3113 });
3114 }
3115
3116 #[test]
3117 fn python_class_methods_count() {
3118 check_metrics::<PythonParser>(
3120 "class C:\n\
3121 \x20 def __init__(self):\n\
3122 \x20 pass\n\
3123 \x20 def m(self):\n\
3124 \x20 pass\n\
3125 \x20 def n(self):\n\
3126 \x20 pass\n",
3127 "foo.py",
3128 |metric| {
3129 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3130 assert_eq!(metric.npm.class_npm_sum(), 3.0);
3131 insta::assert_json_snapshot!(metric.npm);
3132 },
3133 );
3134 }
3135
3136 #[test]
3137 fn python_decorated_methods_count() {
3138 check_metrics::<PythonParser>(
3142 "class C:\n\
3143 \x20 @property\n\
3144 \x20 def p(self):\n\
3145 \x20 return 1\n\
3146 \x20 @staticmethod\n\
3147 \x20 def s():\n\
3148 \x20 return 2\n\
3149 \x20 @classmethod\n\
3150 \x20 def c(cls):\n\
3151 \x20 return 3\n",
3152 "foo.py",
3153 |metric| {
3154 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3155 insta::assert_json_snapshot!(metric.npm);
3156 },
3157 );
3158 }
3159
3160 #[test]
3161 fn python_async_method_counts() {
3162 check_metrics::<PythonParser>(
3165 "class C:\n async def m(self):\n return 1\n",
3166 "foo.py",
3167 |metric| {
3168 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3169 insta::assert_json_snapshot!(metric.npm);
3170 },
3171 );
3172 }
3173
3174 #[test]
3175 fn python_nested_class_methods_independent() {
3176 check_metrics::<PythonParser>(
3179 "class Outer:\n\
3180 \x20 def method(self):\n\
3181 \x20 pass\n\
3182 \x20 class Inner:\n\
3183 \x20 def inner_method(self):\n\
3184 \x20 pass\n",
3185 "foo.py",
3186 |metric| {
3187 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3188 insta::assert_json_snapshot!(metric.npm);
3189 },
3190 );
3191 }
3192
3193 #[test]
3194 fn python_module_level_function_is_not_method() {
3195 check_metrics::<PythonParser>(
3198 "def f():\n pass\nclass C:\n def m(self):\n pass\n",
3199 "foo.py",
3200 |metric| {
3201 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3203 insta::assert_json_snapshot!(metric.npm);
3204 },
3205 );
3206 }
3207
3208 #[test]
3209 fn python_dunder_methods_count() {
3210 check_metrics::<PythonParser>(
3213 "class C:\n\
3214 \x20 def __init__(self):\n\
3215 \x20 pass\n\
3216 \x20 def __repr__(self):\n\
3217 \x20 return 'C'\n\
3218 \x20 def __eq__(self, other):\n\
3219 \x20 return True\n",
3220 "foo.py",
3221 |metric| {
3222 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3223 assert_eq!(metric.npm.class_npm_sum(), 3.0);
3224 insta::assert_json_snapshot!(metric.npm);
3225 },
3226 );
3227 }
3228
3229 #[test]
3230 fn rust_empty_unit_no_methods() {
3231 check_metrics::<RustParser>("", "empty.rs", |metric| {
3232 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3233 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3234 assert_eq!(metric.npm.interface_nm_sum(), 0.0);
3235 assert_eq!(metric.npm.interface_npm_sum(), 0.0);
3236 insta::assert_json_snapshot!(metric.npm);
3237 });
3238 }
3239
3240 #[test]
3241 fn rust_impl_methods_count() {
3242 check_metrics::<RustParser>(
3245 "struct Foo;\n\
3246 impl Foo {\n\
3247 \x20 pub fn new() -> Self { Foo }\n\
3248 \x20 fn helper(&self) -> i32 { 0 }\n\
3249 \x20 pub fn process(&self) -> i32 { 0 }\n\
3250 }\n",
3251 "foo.rs",
3252 |metric| {
3253 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3254 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3255 insta::assert_json_snapshot!(metric.npm);
3256 },
3257 );
3258 }
3259
3260 #[test]
3261 fn rust_trait_methods_count() {
3262 check_func_space::<RustParser, _>(
3269 "trait Drawable {\n\
3270 \x20 fn draw(&self);\n\
3271 \x20 fn area(&self) -> f64 { 0.0 }\n\
3272 }\n",
3273 "foo.rs",
3274 |func_space| {
3275 let metric = &func_space.metrics;
3276 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
3277 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
3278 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3279 insta::assert_json_snapshot!(metric.npm);
3280 assert_child_space_kind(&func_space, "Drawable", SpaceKind::Trait);
3281 },
3282 );
3283 }
3284
3285 #[test]
3286 fn rust_module_level_function_not_method() {
3287 check_metrics::<RustParser>("fn f() {}\nfn g() {}\n", "foo.rs", |metric| {
3291 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3292 assert_eq!(metric.npm.interface_nm_sum(), 0.0);
3293 insta::assert_json_snapshot!(metric.npm);
3294 });
3295 }
3296
3297 #[test]
3298 fn rust_multiple_impls_methods_aggregate() {
3299 check_metrics::<RustParser>(
3301 "struct Foo;\n\
3302 impl Foo { pub fn m1(&self) {} }\n\
3303 impl Foo { fn m2(&self) {} }\n",
3304 "foo.rs",
3305 |metric| {
3306 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3307 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3308 insta::assert_json_snapshot!(metric.npm);
3309 },
3310 );
3311 }
3312
3313 #[test]
3314 fn rust_trait_impl_block_counts_methods() {
3315 check_func_space::<RustParser, _>(
3322 "struct Foo;\n\
3323 trait Drawable { fn draw(&self); }\n\
3324 impl Drawable for Foo { fn draw(&self) {} }\n",
3325 "foo.rs",
3326 |func_space| {
3327 let metric = &func_space.metrics;
3328 assert_eq!(metric.npm.interface_nm_sum(), 1.0);
3331 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3332 insta::assert_json_snapshot!(metric.npm);
3333 assert_child_space_kind(&func_space, "Drawable", SpaceKind::Trait);
3334 },
3335 );
3336 }
3337
3338 #[test]
3341 fn go_empty_unit_no_methods() {
3342 check_metrics::<GoParser>("package main\n", "empty.go", |metric| {
3344 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3345 insta::assert_json_snapshot!(metric.npm);
3346 });
3347 }
3348
3349 #[test]
3350 fn go_method_declarations_count() {
3351 check_metrics::<GoParser>(
3355 "package main\n\
3356 type Foo struct{}\n\
3357 func (f Foo) DoX() {}\n\
3358 func (f Foo) doY() {}\n",
3359 "foo.go",
3360 |metric| {
3361 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3362 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3363 insta::assert_json_snapshot!(metric.npm);
3364 },
3365 );
3366 }
3367
3368 #[test]
3369 fn go_free_function_is_not_method() {
3370 check_metrics::<GoParser>(
3374 "package main\nfunc g() {}\nfunc h(x int) int { return x }\n",
3375 "foo.go",
3376 |metric| {
3377 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3378 insta::assert_json_snapshot!(metric.npm);
3379 },
3380 );
3381 }
3382
3383 #[test]
3384 fn go_methods_on_different_receivers_aggregate_at_unit() {
3385 check_metrics::<GoParser>(
3389 "package main\n\
3390 type Foo struct{}\n\
3391 type Bar struct{}\n\
3392 func (f Foo) M1() {}\n\
3393 func (b Bar) M2() {}\n\
3394 func (b *Bar) M3() {}\n",
3395 "foo.go",
3396 |metric| {
3397 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3398 insta::assert_json_snapshot!(metric.npm);
3399 },
3400 );
3401 }
3402
3403 #[test]
3404 fn go_interface_methods_count_as_interface_nm() {
3405 check_metrics::<GoParser>(
3419 "package main\ntype RC interface { Read() error; Close() error }\n",
3420 "foo.go",
3421 |metric| {
3422 assert_eq!(metric.npm.interface_nm_sum(), 2.0);
3423 assert_eq!(metric.npm.interface_npm_sum(), 2.0);
3424 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3425 insta::assert_json_snapshot!(metric.npm);
3426 },
3427 );
3428 }
3429
3430 #[test]
3431 fn go_pointer_receiver_methods_count() {
3432 check_metrics::<GoParser>(
3436 "package main\n\
3437 type Foo struct{}\n\
3438 func (f *Foo) Set() {}\n\
3439 func (f *Foo) Get() int { return 0 }\n",
3440 "foo.go",
3441 |metric| {
3442 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3443 insta::assert_json_snapshot!(metric.npm);
3444 },
3445 );
3446 }
3447
3448 #[test]
3453 fn elixir_npm_def_is_public_defp_is_private() {
3454 check_metrics::<ElixirParser>(
3455 "defmodule Foo do\n def pub_one, do: 1\n defp priv_one, do: 1\n def pub_two(x), do: x\nend\n",
3456 "foo.ex",
3457 |metric| {
3458 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3460 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3461 },
3462 );
3463 }
3464
3465 #[test]
3466 fn elixir_npm_defmacro_counts_as_public() {
3467 check_metrics::<ElixirParser>(
3468 "defmodule Foo do\n defmacro pub_macro(x), do: x\n defmacrop priv_macro(x), do: x\nend\n",
3469 "foo.ex",
3470 |metric| {
3471 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3473 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3474 },
3475 );
3476 }
3477
3478 #[test]
3479 fn elixir_npm_multiple_def_clauses_each_count() {
3480 check_metrics::<ElixirParser>(
3482 "defmodule Foo do\n def f(0), do: :zero\n def f(_), do: :other\nend\n",
3483 "foo.ex",
3484 |metric| {
3485 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3486 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3487 },
3488 );
3489 }
3490
3491 #[test]
3492 fn elixir_npm_nested_defmodule_each_class() {
3493 check_metrics::<ElixirParser>(
3494 "defmodule Outer do\n def o, do: 1\n defmodule Inner do\n def i, do: 1\n end\nend\n",
3495 "foo.ex",
3496 |metric| {
3497 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3499 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3500 },
3501 );
3502 }
3503
3504 #[test]
3505 fn elixir_npm_user_macro_not_classified_as_method() {
3506 check_metrics::<ElixirParser>(
3510 "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",
3511 "foo.ex",
3512 |metric| {
3513 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3518 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3519 },
3520 );
3521 }
3522
3523 #[test]
3524 fn elixir_npm_quoted_defs_do_not_inflate_method_count() {
3525 check_metrics::<ElixirParser>(
3533 "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",
3534 "foo.ex",
3535 |metric| {
3536 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3538 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3539 },
3540 );
3541 }
3542
3543 #[test]
3546 fn cpp_empty_unit_no_methods() {
3547 check_metrics::<CppParser>("", "empty.cpp", |metric| {
3549 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3550 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3551 insta::assert_json_snapshot!(metric.npm);
3552 });
3553 }
3554
3555 #[test]
3556 fn cpp_class_methods_count() {
3557 check_metrics::<CppParser>(
3560 "class Foo {\n\
3561 void method1() {}\n\
3562 void method2();\n\
3563 };",
3564 "foo.cpp",
3565 |metric| {
3566 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3567 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3568 insta::assert_json_snapshot!(metric.npm);
3569 },
3570 );
3571 }
3572
3573 #[test]
3574 fn cpp_constructors_and_destructors_count() {
3575 check_metrics::<CppParser>(
3579 "class Foo {\n\
3580 public:\n\
3581 Foo();\n\
3582 ~Foo();\n\
3583 void method();\n\
3584 };",
3585 "foo.cpp",
3586 |metric| {
3587 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3588 assert_eq!(metric.npm.class_npm_sum(), 3.0);
3589 insta::assert_json_snapshot!(metric.npm);
3590 },
3591 );
3592 }
3593
3594 #[test]
3595 fn cpp_template_methods_count() {
3596 check_metrics::<CppParser>(
3600 "class Foo {\n\
3601 public:\n\
3602 template<typename T> T fn(T x);\n\
3603 };",
3604 "foo.cpp",
3605 |metric| {
3606 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3607 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3608 insta::assert_json_snapshot!(metric.npm);
3609 },
3610 );
3611 }
3612
3613 #[test]
3614 fn cpp_struct_methods_default_public() {
3615 check_metrics::<CppParser>(
3618 "struct Foo {\n\
3619 void a();\n\
3620 void b() {}\n\
3621 Foo() {}\n\
3622 };",
3623 "foo.cpp",
3624 |metric| {
3625 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3626 assert_eq!(metric.npm.class_npm_sum(), 3.0);
3627 insta::assert_json_snapshot!(metric.npm);
3628 },
3629 );
3630 }
3631
3632 #[test]
3633 fn cpp_free_function_is_not_method() {
3634 check_metrics::<CppParser>("void free_fn() {}\n", "foo.cpp", |metric| {
3638 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3639 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3640 insta::assert_json_snapshot!(metric.npm);
3641 });
3642 }
3643
3644 #[test]
3645 fn cpp_mixed_visibility_methods() {
3646 check_metrics::<CppParser>(
3650 "class Foo {\n\
3651 public: void a();\n\
3652 protected: void b();\n\
3653 private: void c();\n\
3654 };",
3655 "foo.cpp",
3656 |metric| {
3657 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3658 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3659 insta::assert_json_snapshot!(metric.npm);
3660 },
3661 );
3662 }
3663
3664 #[test]
3665 fn cpp_multiple_classes_aggregate_at_unit() {
3666 check_metrics::<CppParser>(
3669 "class Foo { public: void a(); void b() {} };\n\
3670 struct Bar { void c(); };",
3671 "foo.cpp",
3672 |metric| {
3673 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3674 assert_eq!(metric.npm.class_npm_sum(), 3.0);
3675 insta::assert_json_snapshot!(metric.npm);
3676 },
3677 );
3678 }
3679
3680 #[test]
3681 fn javascript_empty_unit_no_methods() {
3682 check_metrics::<JavascriptParser>("", "empty.js", |metric| {
3683 assert_eq!(metric.npm.class_nm_sum(), 0.0);
3684 assert_eq!(metric.npm.class_npm_sum(), 0.0);
3685 insta::assert_json_snapshot!(metric.npm);
3686 });
3687 }
3688
3689 #[test]
3690 fn javascript_class_methods_count() {
3691 check_metrics::<JavascriptParser>(
3695 "class Foo {\n\
3696 constructor() {}\n\
3697 bar() {}\n\
3698 get baz() { return 1; }\n\
3699 set baz(v) {}\n\
3700 }",
3701 "foo.js",
3702 |metric| {
3703 assert_eq!(metric.npm.class_nm_sum(), 4.0);
3704 assert_eq!(metric.npm.class_npm_sum(), 4.0);
3705 insta::assert_json_snapshot!(metric.npm);
3706 },
3707 );
3708 }
3709
3710 #[test]
3711 fn javascript_arrow_field_is_method() {
3712 check_metrics::<JavascriptParser>(
3716 "class Foo { x = () => {}; y = function() {}; z = 1; }",
3717 "foo.js",
3718 |metric| {
3719 assert_eq!(metric.npm.class_nm_sum(), 2.0);
3721 assert_eq!(metric.npm.class_npm_sum(), 2.0);
3722 insta::assert_json_snapshot!(metric.npm);
3723 },
3724 );
3725 }
3726
3727 #[test]
3728 fn javascript_free_function_is_not_method() {
3729 check_metrics::<JavascriptParser>(
3732 "function f() {}\nconst g = () => {};\nclass Foo { h() {} }",
3733 "foo.js",
3734 |metric| {
3735 assert_eq!(metric.npm.class_nm_sum(), 1.0);
3737 assert_eq!(metric.npm.class_npm_sum(), 1.0);
3738 insta::assert_json_snapshot!(metric.npm);
3739 },
3740 );
3741 }
3742
3743 #[test]
3744 fn javascript_multiple_classes_aggregate_at_unit() {
3745 check_metrics::<JavascriptParser>(
3748 "class Foo { a() {} b() {} }\nclass Bar { c() {} }",
3749 "foo.js",
3750 |metric| {
3751 assert_eq!(metric.npm.class_nm_sum(), 3.0);
3752 assert_eq!(metric.npm.class_npm_sum(), 3.0);
3753 insta::assert_json_snapshot!(metric.npm);
3754 },
3755 );
3756 }
3757
3758 #[test]
3759 fn mozjs_class_methods_count() {
3760 check_metrics::<MozjsParser>(
3762 "class Foo {\n\
3763 constructor() {}\n\
3764 bar() {}\n\
3765 get baz() { return 1; }\n\
3766 set baz(v) {}\n\
3767 }",
3768 "foo.js",
3769 |metric| {
3770 assert_eq!(metric.npm.class_nm_sum(), 4.0);
3771 assert_eq!(metric.npm.class_npm_sum(), 4.0);
3772 insta::assert_json_snapshot!(metric.npm);
3773 },
3774 );
3775 }
3776}