/testability-explorer/src/test/java/com/google/test/metric/MetricComputerTest.java
http://testability-explorer.googlecode.com/ · Java · 591 lines · 436 code · 102 blank · 53 comment · 1 complexity · 79a6ab29bcd912049e1e80f794dfc9a7 MD5 · raw file
- /*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.google.test.metric;
- import com.google.test.metric.report.DrillDownReportGenerator;
- import com.google.test.metric.testing.MetricComputerBuilder;
- import com.google.test.metric.testing.MetricComputerJavaDecorator;
- import java.io.ByteArrayOutputStream;
- import java.io.PrintStream;
- import java.util.List;
- import javax.swing.JLabel;
- public class MetricComputerTest extends AutoFieldClearTestCase {
- private MetricComputerJavaDecorator computer;
- private final ClassRepository repo = new JavaClassRepository();
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- RegExpWhiteList regExpWhitelist = new RegExpWhiteList("java.");
- regExpWhitelist.addPackage("javax.");
- MetricComputer toDecorate = new MetricComputerBuilder().withWhitelist(regExpWhitelist)
- .withClassRepository(repo).build();
- computer = new MetricComputerJavaDecorator(toDecorate, repo);
- }
- public static class Medium {
- public Medium() {
- statiCost1();
- cost2();
- }
- /**
- * I cost 1
- */
- public static int statiCost1() {
- int i = 0;
- return i > 0 ? 1 : 2;
- }
- /**
- * I cost 2, but I am instance method so I can be overridden. so my cost may
- * be avoided in most cases.
- */
- public int cost2() {
- int i = 0;
- return i > 0 ? i > 1 ? 1 : 2 : 2;
- }
- /**
- * I cost 2, but I am a <em>final</em> instance method that can not be overridden.
- * My cost is unavoidable.
- */
- public final int finalCost2() {
- int i = 0;
- return i > 0 ? i > 1 ? 1 : 2 : 2;
- }
- /**
- * I am instance method hence you will have to add the cost of constructor
- * to me. (by myself I cost 4)
- */
- public Object testMethod4() {
- int i = 0;
- i = i > 0 ? 1 : 2;
- i = i > 0 ? 1 : 2;
- i = i > 0 ? 1 : 2;
- i = i > 0 ? 1 : 2;
- return new Object();
- }
- }
- public void testMediumCost1() throws Exception {
- MethodInfo method = repo.getClass(Medium.class.getCanonicalName()).getMethod("int statiCost1()");
- assertFalse(method.canOverride());
- MethodCost cost = computer.compute(Medium.class, "int statiCost1()");
- assertEquals(1l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- /**
- * Since cost2 is called twice, once by our test and once by constructor we
- * don't want to add it twice. The constructor adds 1. The direct method call
- * adds 2. So the total cost is 3.
- */
- public void testMediumCost2() throws Exception {
- MethodInfo method = repo.getClass(Medium.class.getCanonicalName()).getMethod("int cost2()");
- assertTrue(method.canOverride());
- MethodCost cost = computer.compute(Medium.class, "int cost2()");
- assertEquals(3l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- public void testMediumFinalCost2() throws Exception {
- MethodInfo method = repo.getClass(Medium.class.getCanonicalName()).getMethod("int finalCost2()");
- assertFalse(method.canOverride());
- }
- /**
- * Cost of the constructor needs to add only the cost of the static method it calls.
- * (The static method can not be overridden). The cost of the instance method can be
- * overridden in a subclass.
- */
- public void testMediumInit() throws Exception {
- MethodInfo method = repo.getClass(Medium.class.getCanonicalName()).getMethod("Medium()");
- assertFalse(method.canOverride());
- MethodCost cost = computer.compute(Medium.class, "Medium()");
- assertEquals(1l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- /**
- * Method4 is cost of 4 by itself, but one has to add the cost of constructor
- * since it is an instance method. The constructor is 0 but calls two methods:
- * cost1 method is static and can not be intercepted hence it has to be added.
- * cost2 method is instance and can be overridden hence we don't add that
- * cost.
- */
- public void testMediumMethod4() throws Exception {
- MethodCost cost = computer.compute(Medium.class,
- "java.lang.Object testMethod4()");
- assertEquals(5l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- public static class Node {
- public String cost1() {
- int a = 0;
- return a == 2 ? "" : null;
- }
- }
- public static class TreeInjection {
- private Node subTitle; // non-injectable
- public Node title = new Node(); // injectable b/c public field (only after constructor)
- private final Node footnote; // injectable via constructor
- public TreeInjection(Node footnote) {
- this.footnote = footnote;
- }
- public String titleTcc0() {
- return title.cost1();
- }
- public String subTitleTcc1() {
- return subTitle.cost1();
- }
- public String footnoteTcc0() {
- return footnote.cost1();
- }
- public String veryExpensive() {
- return "".toLowerCase();
- }
- }
- public void testTreeConstructorHasZeroCost() throws Exception {
- MethodCost cost = computer.compute(TreeInjection.class,
- "TreeInjection(com.google.test.metric.MetricComputerTest.Node)");
- assertEquals(0l, cost.getTotalCost().getCyclomaticComplexityCost());
- assertEquals(0l, cost.getTotalCost().getGlobalCost());
- }
- public void testTreeTitleTcc0CostIsZeroBecauseInjectable() throws Exception {
- MethodCost cost = computer.compute(TreeInjection.class,
- "java.lang.String titleTcc0()");
- assertEquals(0l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- public void testTreeSubTitleTcc1CostIsOneBecauseNonInjectable() throws Exception {
- MethodCost cost = computer.compute(TreeInjection.class,
- "java.lang.String subTitleTcc1()");
- assertEquals(1l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- public void testTreeFootnoteTcc0CostIsZeroBecauseInjectable() throws Exception {
- MethodCost cost = computer.compute(TreeInjection.class,
- "java.lang.String footnoteTcc0()");
- assertEquals(0l, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- static class ChoseConstructor {
- ChoseConstructor() {
- }
- ChoseConstructor(Object a) {
- }
- ChoseConstructor(Object a, int c, int d) {
- }
- ChoseConstructor(Object a, Object b) {
- }
- }
- public void testChooseConstructorWithMostNonPrimitiveParameters() throws Exception {
- ClassInfo classInfo = repo.getClass(ChoseConstructor.class.getCanonicalName());
- MethodInfo constructor = classInfo.getConstructorWithMostNonPrimitiveParameters();
- assertEquals("ChoseConstructor(java.lang.Object, java.lang.Object)", constructor.getName());
- }
- static class Singleton {
- private Singleton() {
- CostUtil.staticCost1();
- }
- public void doWork() {
- CostUtil.staticCost2();
- }
- }
- public void testIgnoreConstructorsIfAllConstructorsArePrivate() throws Exception {
- assertEquals(2L, computer.compute(Singleton.class, "void doWork()").getTotalCost().getCyclomaticComplexityCost());
- ClassInfo classInfo = repo.getClass(Singleton.class.getCanonicalName());
- MethodInfo constructor = classInfo
- .getConstructorWithMostNonPrimitiveParameters();
- assertNull("Constructor should not be found when private", constructor);
- }
- static class StaticInit {
- static {
- CostUtil.staticCost1();
- }
- public void doWork() {
- CostUtil.staticCost2();
- }
- }
- public void testAddStaticInitializationCost() throws Exception {
- assertEquals(3L, computer.compute(StaticInit.class, "void doWork()").getTotalCost().getCyclomaticComplexityCost());
- }
- static class Setters {
- private Object o;
- public void setO(Object o) {
- this.o = o;
- }
- public void doWork() {
- o.toString();
- }
- }
- public void testSetterInjection() throws Exception {
- MethodCost cost = computer.compute(Setters.class, "void doWork()");
- assertEquals(0L, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- static class WholeClassCost {
- void methodA() {
- CostUtil.staticCost1();
- }
- void methodB() {
- CostUtil.staticCost1();
- }
- }
- public void testComputeClassCost() throws Exception {
- ClassCost cost = computer.compute(WholeClassCost.class);
- assertEquals(1L, cost.getMethodCost("void methodA()").getTotalCost().getCyclomaticComplexityCost());
- assertEquals(1L, cost.getMethodCost("void methodB()").getTotalCost().getCyclomaticComplexityCost());
- }
- static class Array {
- String[] strings;
- public void method() {
- strings.clone();
- }
- }
- public void testArray() throws Exception {
- repo.getClass(String[].class.getName());
- computer.compute(repo.getClass(Array.class.getCanonicalName()).getMethod("void method()"));
- }
- static class InjectableClass {
- public void cost4() {
- CostUtil.staticCost4();
- }
- public static void callCost0(InjectableClass ref) {
- indirection(ref);
- }
- private static void indirection(InjectableClass ref) {
- ref.cost4();
- }
- public static void callCost4() {
- InjectableClass x = new InjectableClass();
- indirection(x);
- }
- }
- public void testInjectabilityIsTransitive() throws Exception {
- MethodCost callCost0 = computer.compute(InjectableClass.class, "void callCost0("
- + "com.google.test.metric.MetricComputerTest.InjectableClass)");
- assertEquals(0L, callCost0.getTotalCost().getCyclomaticComplexityCost());
- MethodCost callCost4 = computer.compute(InjectableClass.class, "void callCost4()");
- assertEquals(4L, callCost4.getTotalCost().getCyclomaticComplexityCost());
- }
- static class GlobalState {
- int i;
- static final String X = "X";
- public int inc() {
- return i++;
- }
- public void noop() {
- }
- @Override
- public String toString() {
- return X;
- }
- }
- static final GlobalState ref = new GlobalState();
- static int count;
- static class GlobalStateUser {
- // StateLoad: 0
- public void noLoad() {
- }
- // StateLoad: 1
- public void accessCount() {
- count++;
- }
- // StateLoad: 0
- public void accessFinalState() {
- ref.noop();
- }
- // StateLoad: 0
- public void accessFinalState2() {
- ref.toString();
- }
- // StateLoad: 1
- public void accessMutableState() {
- ref.inc();
- }
- }
- public void testGlobalLoadWhichAccessesFinalShouldBeZero() {
- ClassCost cost = computer.compute(GlobalState.class);
- MethodCost method = cost.getMethodCost("java.lang.String toString()");
- assertEquals(0L, method.getTotalCost().getGlobalCost());
- }
- public void testGlobalLoadMethodDispatchNoStateAccessShouldBeZero() {
- ClassCost cost = computer.compute(GlobalStateUser.class);
- assertEquals(0L, cost.getMethodCost("void noLoad()").getTotalCost().getGlobalCost());
- assertEquals(0L, cost.getMethodCost("void accessFinalState()").getTotalCost().getGlobalCost());
- assertEquals(0L, cost.getMethodCost("void accessFinalState2()").getTotalCost().getGlobalCost());
- }
- public void testGlobalLoadAccessStateShouldBeOne() {
- MethodCost cost = computer.compute(GlobalStateUser.class, "void accessCount()");
- assertEquals(1L, cost.getTotalCost().getGlobalCost());
- }
- public void testGlobalLoadAccessStateThroughFinalShouldBeOne() {
- MethodCost cost =
- computer.compute(GlobalStateUser.class, "void accessMutableState()");
- new DrillDownReportGenerator(new PrintStream(new ByteArrayOutputStream()), new CostModel(),
- null, Integer.MAX_VALUE, 0).print("", cost, 10);
- assertEquals("Expecting one for read and one for write", 2L,
- cost.getTotalCost().getGlobalCost());
- }
- public void testJavaLangObjectParsesCorrectly() throws Exception {
- repo.getClass(Object.class.getCanonicalName());
- }
- public static class CostPerLine {
- static void main(){
- CostUtil.staticCost0(); // line0
- CostUtil.staticCost1(); // line1
- CostUtil.staticCost2(); // line2
- }
- }
- public void testCostPerLine() throws Exception {
- MethodCost cost = computer.compute(CostPerLine.class, "void main()");
- assertEquals(3, cost.getTotalCost().getCyclomaticComplexityCost());
- List<? extends ViolationCost> lineNumberCosts = cost.getViolationCosts();
- assertEquals(3, lineNumberCosts.size());
- MethodInvocationCost line0 = (MethodInvocationCost) lineNumberCosts.get(0);
- MethodInvocationCost line1 = (MethodInvocationCost) lineNumberCosts.get(1);
- MethodInvocationCost line2 = (MethodInvocationCost) lineNumberCosts.get(2);
- int methodStartingLine = cost.getMethodLineNumber();
- assertEquals(0, line0.getMethodCost().getTotalCost().getCyclomaticComplexityCost());
- assertEquals(methodStartingLine + 0, line0.getLocation().getLineNumber());
- assertEquals(1, line1.getMethodCost().getTotalCost().getCyclomaticComplexityCost());
- assertEquals(methodStartingLine + 1, line1.getLocation().getLineNumber());
- assertEquals(2, line2.getMethodCost().getTotalCost().getCyclomaticComplexityCost());
- assertEquals(methodStartingLine + 2, line2.getLocation().getLineNumber());
- }
- public static class WhiteListTest {
- public void testMethod() {
- new String(new byte[0]);
- }
- }
- public void testWhiteList() throws Exception {
- RegExpWhiteList customWhitelist = new RegExpWhiteList("java.lang");
- MetricComputer toDecorate = new MetricComputerBuilder().withClassRepository(repo)
- .withWhitelist(customWhitelist).build();
- computer = new MetricComputerJavaDecorator(toDecorate, repo);
- MethodCost cost = computer.compute(WhiteListTest.class, "void testMethod()");
- assertEquals(0L, cost.getTotalCost().getGlobalCost());
- }
- static class DoubleCountClassConst {
- static int x;
- static {
- x = 1;
- }
- }
- public void testDoubleCountClassConst() throws Exception {
- ClassCost cost = computer.compute(DoubleCountClassConst.class);
- assertEquals(1, cost.getMethodCost("DoubleCountClassConst()").getTotalCost().getGlobalCost());
- }
- static enum TestEnum1{ ONE }
- public void testEnumerationIsZero() throws Exception {
- RegExpWhiteList customWhitelist = new RegExpWhiteList("java.");
- MetricComputer toDecorate = new MetricComputerBuilder().withClassRepository(repo)
- .withWhitelist(customWhitelist).build();
- computer = new MetricComputerJavaDecorator(toDecorate, repo);
- ClassCost cost = computer.compute(TestEnum1.class);
- assertEquals(0, cost.getMethodCost("<static init>()").getTotalCost().getGlobalCost());
- }
- public void testSyntheticEnumValuesAccessorClassIsZero() throws Exception {
- RegExpWhiteList customWhitelist = new RegExpWhiteList("java.");
- MetricComputer toDecorate = new MetricComputerBuilder().withClassRepository(repo)
- .withWhitelist(customWhitelist).build();
- computer = new MetricComputerJavaDecorator(toDecorate, repo);
- ClassCost cost;
- try {
- cost = computer.compute("com.google.test.metric.InnerEnumHolder.1");
- } catch (ClassNotFoundException e) {
- // Eclipse names its enumerations differently
- cost = computer.compute("com.google.test.metric.InnerEnumHolder.NodeType");
- }
- assertEquals(0, cost.getMethodCost("<static init>()").getTotalCost().getGlobalCost());
- }
- private final String testValue = null;
- class InnerClassTest {
- public void test() {
- testValue.indexOf(0);
- }
- }
- public void XtestInnerClassInjectability() throws Exception {
- MethodCost cost = computer.compute(InnerClassTest.class, "void test()");
- assertEquals(0, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- private static class ScoreTooHigh {
- public void doMockery(Builder builder) {
- Product product = builder.build();
- product.execute();
- }
- public static class Product {
- public void execute() {
- CostUtil.staticCost2();
- }
- }
- public static class Builder {
- public Product build() {
- CostUtil.staticCost4();
- return null;
- }
- }
- }
- public void testReturnValueFromInjectableIsInjectable() throws Exception {
- MethodCost cost = computer.compute(ScoreTooHigh.class,
- "void doMockery(com.google.test.metric.MetricComputerTest.ScoreTooHigh.Builder)");
- assertEquals(0, cost.getTotalCost().getCyclomaticComplexityCost());
- }
- public static class NonDeterministicCostUtil {
- public static int global;
- public int notGlobal;
- public int value;
- private int trinary(boolean bool) {
- try {
- return !bool ? notGlobal : global;
- } catch (Exception e) {
- return 1;
- }
- }
- public void test() {
- value = trinary(false);
- }
- }
- public void testWhenLeftAndRightSideOfTrinaryReturnDifferentCostUseHigherOne()
- throws Exception {
- MethodCost cost = computer.compute(NonDeterministicCostUtil.class,
- "void test()");
- assertEquals(1, cost.getTotalCost().getGlobalCost());
- }
- public static class HasIrrelevantImplicitCost {
- public HasIrrelevantImplicitCost() {
- CostUtil.staticCost2();
- }
- public void setNoCost(int i) {
- }
- public void setWithCost(int i) {
- CostUtil.staticCost1();
- }
- public void execute() {
- }
- }
- public void testZeroImplicitCostNotCounted() throws Exception {
- MethodCost cost = computer.compute(HasIrrelevantImplicitCost.class, "void execute()");
- List<? extends ViolationCost> implicitViolationCosts = cost.getImplicitViolationCosts();
- assertEquals(2, implicitViolationCosts.size());
- MethodInvocationCost constructor = (MethodInvocationCost) implicitViolationCosts.get(0);
- assertEquals("implicit cost from construction", constructor.getReason());
- assertEquals(2, constructor.getCost().getCyclomaticComplexityCost());
- assertTrue(constructor.getMethodCost().getImplicitViolationCosts().isEmpty());
- MethodInvocationCost setter = (MethodInvocationCost) implicitViolationCosts.get(1);
- assertEquals("implicit cost calling all setters", setter.getReason());
- assertEquals("void setWithCost(int)", setter.getMethodCost().getMethodName());
- }
- public void testConstructorDoesntCountSetters() throws Exception {
- MethodCost cost = computer.compute(HasIrrelevantImplicitCost.class,
- "HasIrrelevantImplicitCost()");
- assertEquals(0, cost.getImplicitViolationCosts().size());
- }
- static class MyLabel extends JLabel {
- void doThing() {
- }
- }
- public void testJavaXSuperClassSettersArentCountedAgainstMe() throws Exception {
- ClassCost cost = computer.compute(MyLabel.class);
- assertEquals(0, cost.getTotalComplexityCost());
- assertEquals(0, cost.getTotalGlobalCost());
- }
- }