#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
use serde::Serialize;
use serde::ser::{SerializeStruct, Serializer};
use std::fmt;
use crate::checker::Checker;
use crate::macros::implement_metric_trait;
use crate::*;
#[derive(Debug, Clone, Default)]
pub struct Stats {
cyclomatic: f64,
class_wmc: f64,
interface_wmc: f64,
class_wmc_sum: f64,
interface_wmc_sum: f64,
space_kind: SpaceKind,
}
impl Serialize for Stats {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut st = serializer.serialize_struct("wmc", 3)?;
st.serialize_field("classes", &self.class_wmc_sum())?;
st.serialize_field("interfaces", &self.interface_wmc_sum())?;
st.serialize_field("total", &self.total_wmc())?;
st.end()
}
}
impl fmt::Display for Stats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"classes: {}, interfaces: {}, total: {}",
self.class_wmc_sum(),
self.interface_wmc_sum(),
self.total_wmc()
)
}
}
impl Stats {
pub fn merge(&mut self, other: &Stats) {
use SpaceKind::*;
if let Function = other.space_kind {
match self.space_kind {
Class => self.class_wmc += other.cyclomatic,
Interface => self.interface_wmc += other.cyclomatic,
_ => {}
}
}
self.class_wmc_sum += other.class_wmc_sum;
self.interface_wmc_sum += other.interface_wmc_sum;
}
#[inline]
#[must_use]
pub fn class_wmc(&self) -> f64 {
self.class_wmc
}
#[inline]
#[must_use]
pub fn interface_wmc(&self) -> f64 {
self.interface_wmc
}
#[inline]
#[must_use]
pub fn class_wmc_sum(&self) -> f64 {
self.class_wmc_sum
}
#[inline]
#[must_use]
pub fn interface_wmc_sum(&self) -> f64 {
self.interface_wmc_sum
}
#[inline]
#[must_use]
pub fn total_wmc(&self) -> f64 {
self.class_wmc_sum() + self.interface_wmc_sum()
}
#[inline]
pub(crate) fn compute_sum(&mut self) {
self.class_wmc_sum += self.class_wmc;
self.interface_wmc_sum += self.interface_wmc;
}
#[inline]
pub(crate) fn is_disabled(&self) -> bool {
matches!(self.space_kind, SpaceKind::Function | SpaceKind::Unknown)
}
}
#[doc(hidden)]
pub trait Wmc
where
Self: Checker,
{
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats);
}
fn class_interface_compute(
space_kind: SpaceKind,
cyclomatic: &cyclomatic::Stats,
stats: &mut Stats,
) {
use SpaceKind::*;
if let Unit | Class | Interface | Function = space_kind {
if stats.space_kind == Unknown {
stats.space_kind = space_kind;
}
if space_kind == Function {
stats.cyclomatic = cyclomatic.cyclomatic_sum();
}
}
}
impl Wmc for JavaCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for GroovyCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for CsharpCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for KotlinCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for PhpCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
use SpaceKind::*;
if let Unit | Class | Interface | Function = space_kind {
if stats.space_kind == Unknown {
stats.space_kind = space_kind;
}
if space_kind == Function {
stats.cyclomatic = cyclomatic.cyclomatic_sum();
}
}
}
}
impl Wmc for PythonCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for RustCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
let mapped = match space_kind {
SpaceKind::Impl => SpaceKind::Class,
SpaceKind::Trait => SpaceKind::Interface,
other => other,
};
class_interface_compute(mapped, cyclomatic, stats);
}
}
impl Wmc for CppCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
let mapped = match space_kind {
SpaceKind::Struct => SpaceKind::Class,
other => other,
};
class_interface_compute(mapped, cyclomatic, stats);
}
}
impl Wmc for TypescriptCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for TsxCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for RubyCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for JavascriptCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for MozjsCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
impl Wmc for ElixirCode {
fn compute(space_kind: SpaceKind, cyclomatic: &cyclomatic::Stats, stats: &mut Stats) {
class_interface_compute(space_kind, cyclomatic, stats);
}
}
implement_metric_trait!(
Wmc,
PreprocCode,
CcommentCode,
GoCode,
PerlCode,
BashCode,
LuaCode,
TclCode
);
#[cfg(test)]
#[allow(
clippy::float_cmp,
clippy::cast_precision_loss,
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::similar_names,
clippy::doc_markdown,
clippy::needless_raw_string_hashes,
clippy::too_many_lines
)]
mod tests {
use crate::tools::{assert_child_space_kind, check_func_space, check_metrics};
use super::*;
#[test]
fn java_single_class() {
check_metrics::<JavaParser>(
"public class Example { // wmc = 13
public boolean m1(boolean a, boolean b) { // +1
boolean r = false;
if (a && b == a || b) { // +3
r = true;
}
return r;
}
public boolean m2(int n) { // +1
for (int i = 0; i < n; i++) { // +1
int j = n;
while (j > i) { // +1
j--;
}
}
return (n % 2 == 0) ? true : false; // +1
}
public int m3(int x, int y, int z) { // +1
int ret;
try {
z = x/y + y/x;
} catch (ArithmeticException e) { // +1
z = (x == 0) ? -1 : -2; // +1
}
switch (z) {
case -1: // +1
ret = y * y;
break;
case -2: // +1
ret = x * x;
break;
default:
ret = x + y;
}
return ret;
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 13.0,
"interfaces": 0.0,
"total": 13.0
}"###
);
},
);
}
#[test]
fn groovy_single_class() {
check_metrics::<GroovyParser>(
"class Example {
boolean m1(boolean a, boolean b) {
boolean r = false
if (a && b == a || b) {
r = true
}
return r
}
boolean m2(int n) {
for (int i = 0; i < n; i++) {
int j = n
while (j > i) {
j--
}
}
return (n % 2 == 0) ? true : false
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 8.0);
},
);
}
#[test]
fn groovy_empty_class() {
check_metrics::<GroovyParser>("class Empty {}", "foo.groovy", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
});
}
#[test]
fn groovy_class_with_single_method() {
check_metrics::<GroovyParser>(
"class A {
void foo() {
println 'hi'
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
},
);
}
#[test]
fn groovy_multiple_classes() {
check_metrics::<GroovyParser>(
"class A {
void f() { if (true) {} }
}
class B {
void g() {}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
},
);
}
#[test]
fn groovy_class_with_branching_methods() {
check_metrics::<GroovyParser>(
"class Calc {
int abs(int x) {
if (x < 0) {
return -x
}
return x
}
int sign(int x) {
if (x > 0) return 1
if (x < 0) return -1
return 0
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 5.0);
},
);
}
#[test]
fn groovy_interface_wmc_is_zero() {
check_metrics::<GroovyParser>(
"interface I {
void a()
void b()
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
},
);
}
#[test]
fn groovy_static_nested_class() {
check_metrics::<GroovyParser>(
"class TopLevelClass {
static class StaticNestedClass {
private void m() {
println 'Test'
}
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
},
);
}
#[test]
#[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside class bodies"]
fn groovy_nested_inner_classes_wmc() {
check_metrics::<GroovyParser>(
"class X {
void a() {}
class Y {
void b() {}
class Z {
void c() {}
}
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
},
);
}
#[test]
fn groovy_local_inner_class() {
check_metrics::<GroovyParser>(
"class Outer {
void m() {
class Local {
void l() {
if (true) {}
}
}
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
},
);
}
#[test]
#[ignore = "dekobon Groovy grammar v1 does not yet support anonymous inner classes (`new T() { … }`)"]
fn groovy_anonymous_inner_class_wmc() {
check_metrics::<GroovyParser>(
"abstract class Base {
abstract void m1()
}
class Top {
void m() {
def b = new Base() {
void m1() {
for (int i = 0; i < 5; i++) {
println(i)
}
}
}
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 4.0);
},
);
}
#[test]
fn groovy_lambda_expression_wmc() {
check_metrics::<GroovyParser>(
"class Top {
void m1() {
def list = [1, 2, 3]
list.each { n -> println(n) }
}
void m2() {
if (true) {}
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
},
);
}
#[test]
fn groovy_single_interface_wmc() {
check_metrics::<GroovyParser>(
"interface Example {
default boolean m1(boolean a, boolean b) {
return (a && b == a || b)
}
default int m2(int n) {
return (n != 0) ? 1/n : n
}
void m3()
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.interface_wmc_sum(), 6.0);
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
},
);
}
#[test]
#[ignore = "dekobon Groovy grammar v1 does not yet support inner classes inside interface bodies"]
fn groovy_class_in_interface() {
check_metrics::<GroovyParser>(
"interface Outer {
void api()
class Inner {
void f() {
if (true) {}
}
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn groovy_enum_wmc_aggregates_method_complexity() {
check_metrics::<GroovyParser>(
"enum Status {
ACTIVE, INACTIVE;
public int code(int n) {
if (n > 0) { return n }
return 0
}
}",
"foo.groovy",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
#[ignore = "dekobon Groovy grammar v1 does not support annotation type elements with `default` values"]
fn groovy_annotation_type_opens_interface_space_with_zero_wmc() {
check_func_space::<GroovyParser, _>(
"public @interface Marker {
String value() default \"\";
int priority() default 0;
}",
"foo.groovy",
|func_space| {
assert_eq!(func_space.metrics.wmc.interface_wmc_sum(), 0.0);
assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
},
);
}
#[test]
fn java_multiple_classes() {
check_metrics::<JavaParser>(
"public class MainClass { // wmc = 3
private int a;
public MainClass() { // +1
a = 0;
}
public void setA(int n) { // +1
a = n;
}
public int getA() { // +1
return a;
}
}
class TopLevelClass { // wmc = 2
private int b;
public TopLevelClass() { // +1
b = 0;
}
public int getB() { // +1
return b;
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 5.0,
"interfaces": 0.0,
"total": 5.0
}"###
);
},
);
}
#[test]
fn java_static_nested_class() {
check_metrics::<JavaParser>(
"public class TopLevelClass { // wmc = 0
public static class StaticNestedClass { // wmc = 1
private void m() { // +1
System.out.println(\"Test\");
}
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 1.0,
"interfaces": 0.0,
"total": 1.0
}"###
);
},
);
}
#[test]
fn java_nested_inner_classes() {
check_metrics::<JavaParser>(
"public class TopLevelClass { // wmc = 2
private int a;
class InnerClassBefore { // wmc = 1
private boolean b = (a % 2 == 0) ? true : false;
public boolean getB() { // +1
return b;
}
}
public TopLevelClass(int n) { // +1
if (a != n) { // +1
a = n;
}
}
class InnerClassAfter { // wmc = 2
private int c = a;
public int getC() { // +1
return c;
}
public void setC(int n) { // +1
c = n;
}
class InnerClass1 { // wmc = 1
private int p1;
class InnerClass2 { // wmc = 1
private int p2;
public int getP2() { // +1
return p2;
}
class InnerClass3 { // wmc = 2
private int p3;
public int getP3() { // +1
return p3;
}
public void setP3(int n) { // +1
p3 = n;
}
}
}
public void setP1(int n) { // +1
p1 = n;
}
}
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 9.0,
"interfaces": 0.0,
"total": 9.0
}"###
);
},
);
}
#[test]
fn java_local_inner_class() {
check_metrics::<JavaParser>(
"import java.util.LinkedList;
import java.util.List;
public final class FinalClass { // wmc = 5
private int a = 1;
public void test() { // +1
final List<String> localList = new LinkedList<String>();
class LocalInnerClass { // +1, wmc = 2
private int b = (a == 1) ? 1 : 0; // +1
public void print() { // +1
for ( String s : localList ) { // +1
System.out.println(s);
}
}
}
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 7.0,
"interfaces": 0.0,
"total": 7.0
}"###
);
},
);
}
#[test]
fn java_anonymous_inner_class() {
check_metrics::<JavaParser>(
"abstract class AbstractClass { // wmc = 1
abstract void m1(); // +1
}
public class TopLevelClass{ // wmc = 3
public void m(){ // +1
AbstractClass ac1 = new AbstractClass() {
void m1() { // +1
for (int i = 0; i < 5; i++) { // +1
System.out.println(\"Test 1: \" + i);
}
}
};
ac1.m1();
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 4.0,
"interfaces": 0.0,
"total": 4.0
}"###
);
},
);
}
#[test]
fn java_nested_anonymous_inner_classes() {
check_metrics::<JavaParser>(
"abstract class AbstractClass{ // wmc = 2
abstract void m1(); // +1
abstract void m2(); // +1
}
public class TopLevelClass{ // wmc = 6
public void m(){ // +1
AbstractClass ac1 = new AbstractClass() {
void m1() { // +1
for (int i = 0; i < 5; i++) { // +1
System.out.println(\"Test 1: \" + i);
}
}
void m2() { // +1
AbstractClass ac2 = new AbstractClass() {
void m1() { // +1
System.out.println(\"Test A\");
}
void m2() { // +1
System.out.println(\"Test B\");
}
};
ac2.m2();
System.out.println(\"Test 2\");
}
};
ac1.m1();
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 8.0,
"interfaces": 0.0,
"total": 8.0
}"###
);
},
);
}
#[test]
fn java_lambda_expression() {
check_metrics::<JavaParser>(
"import java.util.ArrayList;
public class TopLevelClass { // wmc = 2
private ArrayList<Integer> numbers;
public void m1() { // +1
numbers = new ArrayList<Integer>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
}
public void m2() { // +1
numbers.forEach( (n) -> { System.out.println(n); } );
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 2.0,
"interfaces": 0.0,
"total": 2.0
}"###
);
},
);
}
#[test]
fn java_single_interface() {
check_metrics::<JavaParser>(
"interface Example { // wmc = 6
default boolean m1(boolean a, boolean b) { // +1
return (a && b == a || b); // +2
}
default int m2(int n) { // +1
return (n != 0) ? 1/n : n; // +1
};
void m3(); // +1
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 0.0,
"interfaces": 6.0,
"total": 6.0
}"###
);
},
);
}
#[test]
fn java_multiple_interfaces() {
check_metrics::<JavaParser>(
"interface FirstInterface { // wmc = 1
int a = 0;
default int getA() { // +1
return a;
}
}
interface SecondInterface { // wmc = 2
void setB(int n); // +1
int getB(); // +1
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 0.0,
"interfaces": 3.0,
"total": 3.0
}"###
);
},
);
}
#[test]
fn java_nested_inner_interfaces() {
check_metrics::<JavaParser>(
"interface TopLevelInterface { // wmc = 1
interface InnerInterfaceBefore { // wmc = 1
void m1(); // +1
}
void m2(); // +1
interface InnerInterfaceAfter { // wmc = 2
void m3(); // +1
interface InnerInterface { // wmc = 1
void m4(); // +1
}
void m5(); // +1
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 0.0,
"interfaces": 5.0,
"total": 5.0
}"###
);
},
);
}
#[test]
fn java_class_in_interface() {
check_metrics::<JavaParser>(
"interface TopLevelInterface { // wmc = 2
int getA(); // +1
boolean getB(); // +1
class InnerClass { // wmc = 2
float c;
double d;
float getC() { // +1
return c;
}
double getD() { // +1
return d;
}
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 2.0,
"interfaces": 2.0,
"total": 4.0
}"###
);
},
);
}
#[test]
fn java_interface_in_class() {
check_metrics::<JavaParser>(
"class TopLevelClass { // wmc = 2
int a;
boolean b;
int getA() { // +1
return a;
}
boolean getB() { // +1
return b;
}
interface InnerInterface { // wmc = 2
float getC(); // +1
double getD(); // +1
}
}",
"foo.java",
|metric| {
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 2.0,
"interfaces": 2.0,
"total": 4.0
}"###
);
},
);
}
#[test]
fn java_enum_wmc_aggregates_method_complexity() {
check_metrics::<JavaParser>(
"enum Status {
ACTIVE, INACTIVE;
public int code(int n) { // entry +1
if (n > 0) { // if +1
return n;
}
return 0;
}
}",
"foo.java",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn java_record_wmc_aggregates_method_complexity() {
check_metrics::<JavaParser>(
"record Point(int x, int y) {
public int describe() { // entry +1
return (x == 0) ? 0 : 1; // ternary +1
}
}",
"foo.java",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn java_annotation_type_opens_interface_space_with_zero_wmc() {
check_func_space::<JavaParser, _>(
"@interface Marker {
String value() default \"\";
int priority() default 0;
}",
"foo.java",
|func_space| {
assert_eq!(func_space.metrics.wmc.interface_wmc_sum(), 0.0);
assert_child_space_kind(&func_space, "Marker", SpaceKind::Interface);
},
);
}
#[test]
fn csharp_single_class() {
check_metrics::<CsharpParser>(
"public class Example {
public bool M1(bool a, bool b) {
bool r = false;
if (a && b == a || b) {
r = true;
}
return r;
}
public int M2(int n) {
for (int i = 0; i < n; i++) {
int j = n;
while (j > i) {
j--;
}
}
return (n % 2 == 0) ? 1 : 0;
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 8.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_multiple_classes() {
check_metrics::<CsharpParser>(
"public class A {
private int a;
public A() { a = 0; }
public void SetA(int n) { a = n; }
public int GetA() { return a; }
}
class B {
private int b;
public B() { b = 0; }
public int GetB() { return b; }
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 5.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_static_nested_class() {
check_metrics::<CsharpParser>(
"public class Outer {
public static class Nested {
private void M() {
System.Console.WriteLine(\"Test\");
}
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_nested_inner_classes() {
check_metrics::<CsharpParser>(
"public class Outer {
private int a;
public class Inner {
public int GetX() { return 0; }
public class Innermost {
public int GetY() { return 1; }
}
}
public int GetA() { return a; }
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_local_inner_class() {
check_metrics::<CsharpParser>(
"public class A {
public int M(int x) {
int Local(int y) {
if (y > 0) return y;
return -y;
}
return Local(x);
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_anonymous_inner_class() {
check_metrics::<CsharpParser>(
"public class A {
public void Run() {
System.Action f = delegate(int x) {
if (x > 0) System.Console.WriteLine(x);
};
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_nested_anonymous_inner_classes() {
check_metrics::<CsharpParser>(
"public class A {
public void Run() {
System.Action f = delegate(int x) {
System.Action g = delegate(int y) {
if (y > 0) System.Console.WriteLine(y);
};
};
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 4.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_lambda_expression() {
check_metrics::<CsharpParser>(
"public class A {
public void Run() {
System.Func<int, int> f = x => x > 0 ? x : -x;
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_single_interface() {
check_metrics::<CsharpParser>(
"public interface I {
int GetA();
int GetB();
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_multiple_interfaces() {
check_metrics::<CsharpParser>(
"public interface I1 { int GetA(); }
public interface I2 { bool GetB(); float GetC(); }",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_nested_inner_interfaces() {
check_metrics::<CsharpParser>(
"public interface I1 {
int GetA();
public interface I2 {
bool GetB();
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_class_in_interface() {
check_metrics::<CsharpParser>(
"public interface I {
int GetA();
public class Helper {
public int M() { return 0; }
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn csharp_interface_in_class() {
check_metrics::<CsharpParser>(
"class Outer {
int a;
bool b;
public int GetA() { return a; }
public bool GetB() { return b; }
public interface InnerI {
float GetC();
double GetD();
}
}",
"foo.cs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn php_no_classes() {
check_metrics::<PhpParser>(
"<?php function f(): int { return 1; }",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_one_class_simple() {
check_metrics::<PhpParser>(
"<?php
class A {
public function a(): int { return 1; }
public function b(): int { return 2; }
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_one_class_with_loops() {
check_metrics::<PhpParser>(
"<?php
class A {
public function f(int $n): int {
$sum = 0;
for ($i = 0; $i < $n; $i++) {
$sum += $i;
}
return $sum;
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_one_class_with_branches() {
check_metrics::<PhpParser>(
"<?php
class A {
public function f(int $x): int {
if ($x > 0) {
return 1;
}
if ($x < 0) {
return -1;
}
return 0;
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_class_with_methods_only() {
check_metrics::<PhpParser>(
"<?php
class A {
public function a(): void {}
public function b(): void {}
public function c(): void {}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_multiple_classes() {
check_metrics::<PhpParser>(
"<?php
class A {
public function f(int $x): int {
if ($x > 0) { return 1; }
return 0;
}
}
class B {
public function g(int $x): int {
return $x;
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_anonymous_class() {
check_metrics::<PhpParser>(
"<?php
$obj = new class {
public function f(int $x): int {
if ($x > 0) { return 1; }
return 0;
}
};",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_class_with_static_methods() {
check_metrics::<PhpParser>(
"<?php
class A {
public static function f(int $x): int {
if ($x > 0) { return 1; }
return 0;
}
public static function g(): int { return 1; }
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_interface_wmc() {
check_metrics::<PhpParser>(
"<?php
interface I {
public function a(): void;
public function b(): int;
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_trait_wmc() {
check_metrics::<PhpParser>(
"<?php
trait T {
public function f(int $x): int {
if ($x > 0) { return 1; }
return 0;
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_enum_with_methods() {
check_metrics::<PhpParser>(
"<?php
enum Color {
case Red;
case Green;
public function label(): string {
return match ($this) {
Color::Red => 'r',
Color::Green => 'g',
};
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_class_inside_namespace() {
check_metrics::<PhpParser>(
"<?php
namespace App;
class A {
public function f(int $x): int {
if ($x > 0) { return 1; }
return 0;
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn php_class_complex() {
check_metrics::<PhpParser>(
"<?php
class Calc {
public function add(int $a, int $b): int {
if ($a > 0 && $b > 0) {
return $a + $b;
}
return 0;
}
public function loop(int $n): int {
$s = 0;
for ($i = 0; $i < $n; $i++) {
if ($i % 2 === 0) { $s += $i; }
}
return $s;
}
}",
"foo.php",
|metric| insta::assert_json_snapshot!(metric.wmc),
);
}
#[test]
fn kotlin_empty_class() {
check_metrics::<KotlinParser>("class Empty {}", "foo.kt", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn kotlin_single_class() {
check_metrics::<KotlinParser>(
"class C {
fun m(x: Int): Int { // +1
if (x > 0) { // +1
return x
}
return when (x) {
0 -> 0 // +1 (WhenEntry)
else -> -x // skipped (else is default)
}
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_multiple_classes() {
check_metrics::<KotlinParser>(
"class A {
private var a: Int = 0
constructor(n: Int) { a = n } // +1
fun setA(n: Int) { a = n } // +1
fun getA(): Int = a // +1
}
class B {
private var b: Int = 0
constructor(n: Int) { b = n } // +1
fun getB(): Int = b // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 5.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_nested_class() {
check_metrics::<KotlinParser>(
"class Outer {
class Nested {
fun m() { println(\"hi\") } // +1
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_inner_class() {
check_metrics::<KotlinParser>(
"class Outer {
fun outerM() {} // +1
inner class Inner {
fun innerM() {} // +1
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_data_class() {
check_metrics::<KotlinParser>(
"data class Point(val x: Int, val y: Int) {
fun manhattan(): Int = kotlin.math.abs(x) + kotlin.math.abs(y) // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_object_singleton() {
check_metrics::<KotlinParser>(
"object Util {
fun add(a: Int, b: Int): Int = a + b // +1
fun gtZero(n: Int): Boolean { // +1
return n > 0
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_companion_object() {
check_metrics::<KotlinParser>(
"class Holder {
val instance: Int = 1
fun get(): Int = instance // +1
companion object {
val SCALE: Int = 10
fun mk(): Holder = Holder() // +1
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_interface_simple() {
check_metrics::<KotlinParser>(
"interface I {
fun work(): Int // +1
fun describe(): String // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_interface_with_default_method() {
check_metrics::<KotlinParser>(
"interface I {
fun abs(n: Int): Int { // +1
return if (n < 0) -n else n // +1 if
}
fun pure(): Int // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_override_function() {
check_metrics::<KotlinParser>(
"open class Base {
open fun greet(): String = \"hi\" // +1
}
class Sub : Base() {
override fun greet(): String = \"yo\" // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_secondary_constructor() {
check_metrics::<KotlinParser>(
"class C {
private var a: Int = 0
constructor(n: Int) { // +1
a = n
}
constructor(n: Int, m: Int) { // +1
a = n + m
}
fun get(): Int = a // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_init_block() {
check_metrics::<KotlinParser>(
"class C(val n: Int) {
init { // not counted
require(n >= 0) { \"n must be non-negative\" }
}
fun get(): Int = n // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_top_level_function_excluded() {
check_metrics::<KotlinParser>(
"fun freeFunction(): Int = 42
val freeVal: Int = 0
class C { fun m(): Int = 1 } // +1
",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_extension_function_excluded() {
check_metrics::<KotlinParser>(
"fun List<Int>.sum2(): Int = this.size // top-level
class C { fun m(): Int = 1 } // +1
",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_generic_class() {
check_metrics::<KotlinParser>(
"class Box<T>(val value: T) {
fun get(): T = value // +1
fun mapTo(f: (T) -> T): T = f(value) // +1
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_class_in_interface() {
check_metrics::<KotlinParser>(
"interface Outer {
fun work(): Int // +1 (interface)
class Helper {
fun help(): Int = 0 // +1 (class)
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn kotlin_interface_in_class() {
check_metrics::<KotlinParser>(
"class Outer {
fun work(): Int = 1 // +1 (class)
interface Sub {
fun help(): Int // +1 (interface)
}
}",
"foo.kt",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_class_wmc_single_method() {
check_metrics::<TypescriptParser>(
"class C {
m(): number { return 1; } // cyclomatic 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_class_wmc_two_methods() {
check_metrics::<TypescriptParser>(
"class C {
a(): number { return 1; } // +1
b(x: number): number { // +2 (if branch)
if (x > 0) return x;
return 0;
}
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_class_wmc_with_branches() {
check_metrics::<TypescriptParser>(
"class C {
m(x: number): number {
if (x > 0) { // +1
return 1;
} else if (x < 0) { // +1
return -1;
}
return 0;
} // base 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_class_wmc_arrow_field() {
check_metrics::<TypescriptParser>(
"class C {
arrow = (x: number) => {
if (x > 0) return x; // +1
return 0;
}; // base 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_class_wmc_with_loops() {
check_metrics::<TypescriptParser>(
"class C {
m(xs: number[]): number {
let total = 0;
for (const x of xs) { // +1
total += x;
}
return total;
} // base 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_abstract_class_wmc() {
check_metrics::<TypescriptParser>(
"abstract class C {
abstract a(): void; // signature only, 0
m(): number { return 1; } // +1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_interface_wmc_zero() {
check_metrics::<TypescriptParser>(
"interface I {
a(): void;
b(): number;
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_constructor_wmc() {
check_metrics::<TypescriptParser>(
"class C {
x: number;
constructor(n: number) {
if (n > 0) { // +1
this.x = n;
} else {
this.x = 0;
}
} // base 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_getter_setter_wmc() {
check_metrics::<TypescriptParser>(
"class C {
_x: number = 0;
get x(): number { return this._x; }
set x(v: number) { this._x = v; }
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_multiple_classes_wmc_independent() {
check_metrics::<TypescriptParser>(
"class A { m(): number { return 1; } }
class B {
m(x: number): number {
if (x > 0) return x; // +1
return 0;
} // base 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_class_wmc_with_ternary_and_logical() {
check_metrics::<TypescriptParser>(
"class C {
m(x: number, y: number): number {
return x > 0 && y > 0 // +1 (ternary) +1 (&&)
? x + y
: 0;
} // base 1
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn typescript_generic_class_wmc() {
check_metrics::<TypescriptParser>(
"class Box<T> {
value: T;
set(v: T): void { this.value = v; }
get(): T { return this.value; }
}",
"foo.ts",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_class_wmc_single_method() {
check_metrics::<TsxParser>(
"class C { m(): number { return 1; } }",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_class_wmc_two_methods() {
check_metrics::<TsxParser>(
"class C {
a(): number { return 1; }
b(x: number): number {
if (x > 0) return x;
return 0;
}
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_class_wmc_with_branches() {
check_metrics::<TsxParser>(
"class C {
m(x: number): number {
if (x > 0) return 1;
else if (x < 0) return -1;
return 0;
}
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_class_wmc_arrow_field() {
check_metrics::<TsxParser>(
"class C {
arrow = (x: number) => {
if (x > 0) return x;
return 0;
};
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_class_wmc_with_loops() {
check_metrics::<TsxParser>(
"class C {
m(xs: number[]): number {
let total = 0;
for (const x of xs) { total += x; }
return total;
}
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_abstract_class_wmc() {
check_metrics::<TsxParser>(
"abstract class C {
abstract a(): void;
m(): number { return 1; }
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_interface_wmc_zero() {
check_metrics::<TsxParser>(
"interface I { a(): void; b(): number; }",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_constructor_wmc() {
check_metrics::<TsxParser>(
"class C {
x: number;
constructor(n: number) {
if (n > 0) this.x = n;
else this.x = 0;
}
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_getter_setter_wmc() {
check_metrics::<TsxParser>(
"class C {
_x: number = 0;
get x(): number { return this._x; }
set x(v: number) { this._x = v; }
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_multiple_classes_wmc_independent() {
check_metrics::<TsxParser>(
"class A { m(): number { return 1; } }
class B {
m(x: number): number {
if (x > 0) return x;
return 0;
}
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_class_wmc_with_ternary_and_logical() {
check_metrics::<TsxParser>(
"class C {
m(x: number, y: number): number {
return x > 0 && y > 0 ? x + y : 0;
}
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn tsx_generic_class_wmc() {
check_metrics::<TsxParser>(
"class Box<T> {
value: T;
set(v: T): void { this.value = v; }
get(): T { return this.value; }
}",
"foo.tsx",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_no_classes() {
check_metrics::<RubyParser>("def foo\n 1\nend\n", "foo.rb", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn ruby_empty_class() {
check_metrics::<RubyParser>("class Foo\nend\n", "foo.rb", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn ruby_one_class_simple() {
check_metrics::<RubyParser>(
"class A\n def a\n 1\n end\n def b\n 2\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_one_class_with_branch() {
check_metrics::<RubyParser>(
"class A\n def f(x)\n if x > 0\n 1\n else\n 0\n end\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_one_class_with_loop() {
check_metrics::<RubyParser>(
"class A\n def f(n)\n while n > 0\n n -= 1\n end\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_singleton_method_included() {
check_metrics::<RubyParser>(
"class A\n def f\n 1\n end\n def self.g\n 2\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_singleton_class_methods_included() {
check_metrics::<RubyParser>(
"class A\n class << self\n def s\n 1\n end\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_multiple_classes() {
check_metrics::<RubyParser>(
"class A\n def f(x)\n if x > 0\n 1\n end\n end\nend\nclass B\n def g\n 1\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_module_only() {
check_metrics::<RubyParser>(
"module M\n def f\n 1\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_class_with_inheritance() {
check_metrics::<RubyParser>(
"class A < B\n def f\n 1\n end\n def g\n 2\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_class_with_visibility_keywords() {
check_metrics::<RubyParser>(
"class A\n def a\n 1\n end\n private\n def b\n 1\n end\n protected\n def c\n 1\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn ruby_class_complex() {
check_metrics::<RubyParser>(
"class Calc\n def add(a, b)\n if a > 0 && b > 0\n a + b\n end\n end\n def loop(n)\n s = 0\n while n > 0\n if n.even?\n s += n\n end\n n -= 1\n end\n s\n end\nend\n",
"foo.rb",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn python_empty_class_zero_wmc() {
check_metrics::<PythonParser>("class C:\n pass\n", "foo.py", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn python_single_method_wmc_one() {
check_metrics::<PythonParser>(
"class C:\n def m(self):\n return 1\n",
"foo.py",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn python_method_with_if_adds_to_wmc() {
check_metrics::<PythonParser>(
"class C:\n def m(self, x):\n if x > 0:\n return 1\n return 0\n",
"foo.py",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn python_multiple_methods_wmc_sums() {
check_metrics::<PythonParser>(
"class C:\n\
\x20 def m1(self):\n\
\x20 return 1\n\
\x20 def m2(self, x):\n\
\x20 if x:\n\
\x20 return 1\n\
\x20 return 0\n\
\x20 def m3(self, xs):\n\
\x20 for x in xs:\n\
\x20 if x:\n\
\x20 return x\n\
\x20 return None\n",
"foo.py",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn python_top_level_function_does_not_contribute_to_class_wmc() {
check_metrics::<PythonParser>(
"def f(x):\n if x:\n return 1\n return 0\n",
"foo.py",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn python_multiple_classes_wmc_independent() {
check_metrics::<PythonParser>(
"class A:\n\
\x20 def m1(self):\n\
\x20 return 1\n\
class B:\n\
\x20 def m2(self, x):\n\
\x20 if x:\n\
\x20 return 1\n\
\x20 return 0\n",
"foo.py",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn rust_empty_unit_zero_wmc() {
check_metrics::<RustParser>("", "empty.rs", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn rust_single_impl_method_wmc_one() {
check_metrics::<RustParser>(
"struct Foo;\nimpl Foo { fn m(&self) -> i32 { 1 } }\n",
"foo.rs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn rust_method_with_if_adds_to_wmc() {
check_metrics::<RustParser>(
"struct Foo;\n\
impl Foo {\n\
\x20 fn m(&self, x: i32) -> i32 {\n\
\x20 if x > 0 { 1 } else { 0 }\n\
\x20 }\n\
}\n",
"foo.rs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn rust_multiple_methods_wmc_sums() {
check_metrics::<RustParser>(
"struct Foo;\n\
impl Foo {\n\
\x20 fn m1(&self) -> i32 { 1 }\n\
\x20 fn m2(&self, x: i32) -> i32 { if x > 0 { 1 } else { 0 } }\n\
\x20 fn m3(&self, xs: &[i32]) -> i32 {\n\
\x20 for x in xs { if *x > 0 { return *x; } }\n\
\x20 0\n\
\x20 }\n\
}\n",
"foo.rs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 6.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn rust_multiple_impls_wmc_aggregate() {
check_metrics::<RustParser>(
"struct Foo;\n\
impl Foo { fn m1(&self) {} }\n\
impl Foo { fn m2(&self) {} }\n",
"foo.rs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn rust_trait_default_method_contributes_to_interface_wmc() {
check_metrics::<RustParser>(
"trait T { fn draw(&self); fn area(&self) -> f64 { 0.0 } }",
"foo.rs",
|metric| {
assert_eq!(metric.wmc.interface_wmc_sum(), 1.0);
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn rust_top_level_function_does_not_contribute_to_class_wmc() {
check_metrics::<RustParser>(
"fn f(x: i32) -> i32 { if x > 0 { 1 } else { 0 } }",
"foo.rs",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn go_wmc_is_zero_documented_limitation() {
check_metrics::<GoParser>(
"package main\n\
type Foo struct{}\n\
func (f Foo) M(x int) int { if x > 0 { return 1 } else { return 0 } }\n\
func (f Foo) N() {}\n",
"foo.go",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn elixir_wmc_aggregates_def_methods() {
check_metrics::<ElixirParser>(
"defmodule Foo do\n def m(x) do\n if x > 0 do\n 1\n else\n 0\n end\n end\n def n, do: :ok\nend\n",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(
metric.wmc,
@r###"
{
"classes": 3.0,
"interfaces": 0.0,
"total": 3.0
}"###
);
},
);
}
#[test]
fn elixir_wmc_def_plus_defp_counts_both() {
check_metrics::<ElixirParser>(
"defmodule Foo do\n def pub_one, do: 1\n defp priv_one, do: 1\nend\n",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn elixir_wmc_defmacro_counts() {
check_metrics::<ElixirParser>(
"defmodule Foo do\n defmacro stuff(x) do\n if x > 0, do: :pos, else: :neg\n end\nend\n",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn elixir_wmc_multiple_clauses_each_a_method() {
check_metrics::<ElixirParser>(
"defmodule Foo do\n def f(0), do: :zero\n def f(_), do: :other\nend\n",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn elixir_wmc_nested_defmodule_isolates() {
check_metrics::<ElixirParser>(
"defmodule Outer do\n def o, do: 1\n defmodule Inner do\n def i, do: 1\n end\nend\n",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
},
);
}
#[test]
fn elixir_wmc_user_macro_not_classified_as_method() {
check_metrics::<ElixirParser>(
"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",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
},
);
}
#[test]
fn elixir_wmc_quoted_defs_do_not_inflate_method_count() {
check_metrics::<ElixirParser>(
"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",
"foo.ex",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
},
);
}
#[test]
fn cpp_empty_unit_zero_wmc() {
check_metrics::<CppParser>("", "empty.cpp", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn cpp_single_method_wmc_one() {
check_metrics::<CppParser>("class Foo { public: void m() {} };", "foo.cpp", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn cpp_method_with_if_adds_to_wmc() {
check_metrics::<CppParser>(
"class Foo {\n\
public:\n\
int m(int x) {\n\
if (x > 0) { return 1; }\n\
return 0;\n\
}\n\
};",
"foo.cpp",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn cpp_struct_wmc_maps_to_class() {
check_metrics::<CppParser>(
"struct Foo {\n\
int m(int x) {\n\
if (x > 0) { return 1; }\n\
return 0;\n\
}\n\
};",
"foo.cpp",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn cpp_free_function_does_not_contribute_to_class_wmc() {
check_metrics::<CppParser>(
"int free_fn(int x) { if (x > 0) { return 1; } return 0; }",
"foo.cpp",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
assert_eq!(metric.wmc.interface_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn cpp_multiple_methods_wmc_sums() {
check_metrics::<CppParser>(
"class Foo {\n\
public:\n\
int a(int x) { if (x > 0) { return 1; } return 0; }\n\
int b() { return 42; }\n\
};",
"foo.cpp",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 3.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn cpp_multiple_classes_wmc_aggregate() {
check_metrics::<CppParser>(
"class Foo { public: void a() {} };\nstruct Bar { void b() {} };",
"foo.cpp",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn javascript_empty_unit_zero_wmc() {
check_metrics::<JavascriptParser>("", "empty.js", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 0.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn javascript_single_method_wmc_one() {
check_metrics::<JavascriptParser>("class Foo { a() { return 1; } }", "foo.js", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
#[test]
fn javascript_method_with_if_adds_to_wmc() {
check_metrics::<JavascriptParser>(
"class Foo { a(x) { if (x > 0) return 1; return 0; } }",
"foo.js",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn javascript_free_function_does_not_contribute_to_class_wmc() {
check_metrics::<JavascriptParser>(
"function f(x) { if (x > 0) return 1; return 0; }\nclass Foo { a() { return 1; } }",
"foo.js",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn javascript_multiple_classes_wmc_aggregate() {
check_metrics::<JavascriptParser>(
"class Foo { a() { return 1; } }\nclass Bar { b() { return 1; } }",
"foo.js",
|metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 2.0);
insta::assert_json_snapshot!(metric.wmc);
},
);
}
#[test]
fn mozjs_single_method_wmc_one() {
check_metrics::<MozjsParser>("class Foo { a() { return 1; } }", "foo.js", |metric| {
assert_eq!(metric.wmc.class_wmc_sum(), 1.0);
insta::assert_json_snapshot!(metric.wmc);
});
}
}