1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: IItemAttribute.java,v 1.1.1.1.2.1 2004/07/10 19:08:50 vlad_r Exp $ 8 */ 9 package com.vladium.emma.report; 10 11 import java.text.DecimalFormat; 12 import java.text.FieldPosition; 13 import java.text.NumberFormat; 14 import java.util.Comparator; 15 16 import com.vladium.util.asserts.$assert; 17 18 // ---------------------------------------------------------------------------- 19 /** 20 * @author Vlad Roubtsov, (C) 2003 21 */ 22 public 23 interface IItemAttribute 24 { 25 // public: ................................................................ 26 27 // TODO: this modeling (units is an independent axis) is not ideal, because 28 // not all of the attributes have meaningful separation by unit type 29 30 // note: the ordering is consistent with code in Factory: 31 32 int ATTRIBUTE_NAME_ID = 0; 33 int ATTRIBUTE_CLASS_COVERAGE_ID = 1; 34 int ATTRIBUTE_METHOD_COVERAGE_ID = 2; 35 int ATTRIBUTE_BLOCK_COVERAGE_ID = 3; 36 int ATTRIBUTE_LINE_COVERAGE_ID = 4; 37 38 // note: the ordering is consistent with code in Factory and SrcFileItem: 39 40 int UNITS_COUNT = 0; 41 int UNITS_INSTR = 1; 42 comparator()43 Comparator /* IItem */ comparator (); getName()44 String getName (); format(IItem item, StringBuffer appendTo)45 void format (IItem item, StringBuffer appendTo); passes(IItem item, int criterion)46 boolean passes (IItem item, int criterion); // ideally, criteria should come from a double-dispatched API 47 48 49 abstract class Factory 50 { getAttribute(final int attributeID, final int unitsID)51 public static IItemAttribute getAttribute (final int attributeID, final int unitsID) 52 { 53 if ($assert.ENABLED) $assert.ASSERT (attributeID >= ATTRIBUTE_NAME_ID && attributeID <= ATTRIBUTE_LINE_COVERAGE_ID, "invalid attribute ID: " + attributeID); 54 if ($assert.ENABLED) $assert.ASSERT (unitsID >= UNITS_COUNT && unitsID <= UNITS_INSTR, "invalid units ID: " + unitsID); 55 56 return ATTRIBUTES [unitsID][attributeID]; 57 } 58 getAttributes(final int unitsID)59 public static IItemAttribute [] getAttributes (final int unitsID) 60 { 61 if ($assert.ENABLED) $assert.ASSERT (unitsID >= UNITS_COUNT && unitsID <= UNITS_INSTR, "invalid units ID: " + unitsID); 62 63 return (IItemAttribute []) ATTRIBUTES [unitsID].clone (); 64 } 65 66 private static abstract class Attribute implements IItemAttribute 67 { getName()68 public String getName () 69 { 70 return m_name; 71 } 72 Attribute(final String name)73 protected Attribute (final String name) 74 { 75 if (name == null) throw new IllegalArgumentException ("null input: name"); 76 77 m_name = name; 78 } 79 80 81 private final String m_name; 82 83 } // end of nested class 84 85 86 private static final class NameAttribute extends Attribute 87 implements IItemAttribute 88 { comparator()89 public Comparator comparator () 90 { 91 return m_comparator; 92 } 93 format(final IItem item, final StringBuffer appendTo)94 public void format (final IItem item, final StringBuffer appendTo) 95 { 96 appendTo.append (item.getName ()); 97 } 98 passes(final IItem item, final int criterion)99 public boolean passes (final IItem item, final int criterion) 100 { 101 return true; // names always pass [for now] 102 } 103 104 105 private static final class NameComparator implements Comparator 106 { compare(final Object l, final Object g)107 public int compare (final Object l, final Object g) 108 { 109 final IItem il = (IItem) l; 110 final IItem ig = (IItem) g; 111 112 return il.getName ().compareTo (ig.getName ()); 113 } 114 115 } // end of nested class 116 NameAttribute(final String name)117 NameAttribute (final String name) 118 { 119 super (name); 120 121 m_comparator = new NameComparator (); 122 } 123 124 125 private final Comparator m_comparator; 126 127 } // end of nested class 128 129 130 private static final class FractionAttribute extends Attribute 131 implements IItemAttribute 132 { comparator()133 public Comparator comparator () 134 { 135 return m_comparator; 136 } 137 format(final IItem item, final StringBuffer appendTo)138 public void format (final IItem item, final StringBuffer appendTo) 139 { 140 final int n = item.getAggregate (m_numeratorAggregateID); 141 final double n_scaled = (double) n / m_scale; 142 final int d = item.getAggregate (m_denominatorAggregateID); 143 144 // d can be 0 legally: the compiler can generate classes with no methods in them [happens with synthetic classes, for example] 145 //if ($assert.ENABLED) $assert.ASSERT (d > 0, "[attr ID = " + m_denominatorAggregateID + "] invalid denominator: " + d); 146 147 final int appendToStart = appendTo.length (); 148 149 if (d == 0) 150 m_format.format (1.0F, appendTo, m_fieldPosition); 151 else 152 m_format.format (n_scaled / d, appendTo, m_fieldPosition); 153 154 final int iLimit = Math.max (1, 5 - appendTo.length () + appendToStart); 155 for (int i = 0; i < iLimit; ++ i) appendTo.append (' '); 156 157 appendTo.append ('('); 158 m_nFormat.format (n_scaled, appendTo, m_fieldPosition); 159 appendTo.append ('/'); 160 appendTo.append (d); 161 appendTo.append (')'); 162 } 163 passes(final IItem item, final int criterion)164 public boolean passes (final IItem item, final int criterion) 165 { 166 final int n = item.getAggregate (m_numeratorAggregateID); 167 final int d = item.getAggregate (m_denominatorAggregateID); 168 169 return ((double) n) * IItem.PRECISION >= ((double) d) * m_scale * criterion; 170 } 171 172 173 private final class FractionComparator implements Comparator 174 { compare(final Object l, final Object g)175 public int compare (final Object l, final Object g) 176 { 177 final IItem il = (IItem) l; 178 final IItem ig = (IItem) g; 179 180 final double nil = il.getAggregate (m_numeratorAggregateID); 181 final double dil = il.getAggregate (m_denominatorAggregateID); 182 183 final double nig = ig.getAggregate (m_numeratorAggregateID); 184 final double dig = ig.getAggregate (m_denominatorAggregateID); 185 186 final double diff = nil * dig - nig * dil; 187 188 return diff > 0.0 ? +1 : (diff < 0.0 ? -1 : 0); 189 } 190 191 } // end of inner class 192 193 FractionAttribute(final String name, final int numeratorAggregateID, final int denominatorAggregateID, final int scale, final int nFractionDigits)194 FractionAttribute (final String name, final int numeratorAggregateID, final int denominatorAggregateID, final int scale, final int nFractionDigits) 195 { 196 super (name); 197 198 if ($assert.ENABLED) $assert.ASSERT (scale != 0, "scale: " + scale); 199 200 m_numeratorAggregateID = numeratorAggregateID; 201 m_denominatorAggregateID = denominatorAggregateID; // ok to be zero 202 m_scale = scale; 203 204 m_format = (DecimalFormat) NumberFormat.getPercentInstance (); // TODO: locale 205 m_fieldPosition = new FieldPosition (DecimalFormat.INTEGER_FIELD); 206 207 // TODO: set this from a pattern property 208 //m_format.setMinimumFractionDigits (1); 209 m_format.setMaximumFractionDigits (0); 210 //m_format.setDecimalSeparatorAlwaysShown (false); 211 212 m_nFormat = (DecimalFormat) NumberFormat.getInstance (); // TODO: locale 213 m_nFormat.setGroupingUsed (false); 214 m_nFormat.setMaximumFractionDigits (nFractionDigits); 215 216 m_comparator = new FractionComparator (); 217 } 218 219 220 final int m_numeratorAggregateID, m_denominatorAggregateID; 221 222 private final int m_scale; 223 private final DecimalFormat m_format, m_nFormat; 224 private final FieldPosition m_fieldPosition; 225 private final Comparator m_comparator; 226 227 } // end of nested class 228 229 230 Factory()231 private Factory () {} 232 233 private static final IItemAttribute [/* unit */][/* attributes */] ATTRIBUTES; // set in <clinit> 234 235 static 236 { 237 final IItemAttribute nameAttribute = new NameAttribute ("name"); 238 239 final IItemAttribute classCoverageAttribute = new FractionAttribute ("class, %", IItem.COVERAGE_CLASS_COUNT, IItem.TOTAL_CLASS_COUNT, 1, 0); 240 final IItemAttribute methodCoverageAttribute = new FractionAttribute ("method, %", IItem.COVERAGE_METHOD_COUNT, IItem.TOTAL_METHOD_COUNT, 1, 0); 241 242 ATTRIBUTES = new IItemAttribute [][] 243 { 244 /* count: */ 245 { 246 nameAttribute, 247 classCoverageAttribute, 248 methodCoverageAttribute, 249 new FractionAttribute ("block, %", IItem.COVERAGE_BLOCK_COUNT, IItem.TOTAL_BLOCK_COUNT, 1, 0), 250 new FractionAttribute ("line, %", IItem.COVERAGE_LINE_COUNT, IItem.TOTAL_LINE_COUNT, IItem.PRECISION, 1), 251 }, 252 /* instr: */ 253 { 254 nameAttribute, 255 classCoverageAttribute, 256 methodCoverageAttribute, 257 new FractionAttribute ("block, %", IItem.COVERAGE_BLOCK_INSTR, IItem.TOTAL_BLOCK_INSTR, 1, 0), 258 new FractionAttribute ("line, %", IItem.COVERAGE_LINE_INSTR, IItem.TOTAL_LINE_COUNT, IItem.PRECISION, 1), 259 }, 260 }; 261 } 262 263 } // end of nested class 264 265 } // end of interface 266 // ----------------------------------------------------------------------------