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// ----------------------------------------------------------------------------