IItemAttribute.java revision f6fe897e173f4e4bda72a7dddb091b667066764a
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 */ 9package com.vladium.emma.report; 10 11import java.text.DecimalFormat; 12import java.text.FieldPosition; 13import java.text.NumberFormat; 14import java.util.Comparator; 15 16import com.vladium.util.asserts.$assert; 17 18// ---------------------------------------------------------------------------- 19/** 20 * @author Vlad Roubtsov, (C) 2003 21 */ 22public 23interface 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 43 Comparator /* IItem */ comparator (); 44 String getName (); 45 void format (IItem item, StringBuffer appendTo); 46 boolean passes (IItem item, int criterion); // ideally, criteria should come from a double-dispatched API 47 48 49 abstract class Factory 50 { 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 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 { 68 public String getName () 69 { 70 return m_name; 71 } 72 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 { 89 public Comparator comparator () 90 { 91 return m_comparator; 92 } 93 94 public void format (final IItem item, final StringBuffer appendTo) 95 { 96 appendTo.append (item.getName ()); 97 } 98 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 { 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 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 { 133 public Comparator comparator () 134 { 135 return m_comparator; 136 } 137 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 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 { 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 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 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// ----------------------------------------------------------------------------