Package com.google.test.metric

Source Code of com.google.test.metric.MetricComputerTest

/*
* 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());
  }
}
TOP

Related Classes of com.google.test.metric.MetricComputerTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.