001: /*
002: * @(#)ClassMarkSet.java
003: *
004: * Copyright (C) 2002,2003 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.codecoverage.v2.report;
028:
029: import java.util.ArrayList;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: import net.sourceforge.groboutils.codecoverage.v2.IAnalysisMetaData;
036: import net.sourceforge.groboutils.codecoverage.v2.IChannelLogRecord;
037: import net.sourceforge.groboutils.codecoverage.v2.datastore.MarkRecord;
038:
039: /**
040: * Contains all the marks (sorted by covered and not covered) per method.
041: *
042: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
043: * @version $Date: 2004/04/15 05:48:26 $
044: * @since December 17, 2002
045: * @see IAnalysisMetaData
046: */
047: public class ClassMarkSet {
048: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
049: .getLogger(ClassMarkSet.class);
050:
051: private String[] methodNames;
052: private Map methodToCoveredMarks;
053: private Map methodToNotCoveredMarks;
054:
055: //------------------------------------------------------------------------
056:
057: /**
058: * Container data for a mark and whether it were covered.
059: * Instances of this class are only used in the ClassMarkSet constructor.
060: */
061: private static class DidCover {
062: public MarkRecord mr;
063: public boolean wasCovered;
064:
065: public DidCover(MarkRecord mr) {
066: if (mr == null) {
067: throw new IllegalArgumentException("no null args.");
068: }
069: this .mr = mr;
070: }
071:
072: public void cover() {
073: this .wasCovered = true;
074: }
075:
076: public String toString() {
077: return this .mr.toString();
078: }
079: }
080:
081: //------------------------------------------------------------------------
082:
083: /**
084: * Convienient way to store marks and their mark index relationship.
085: * Instances of this class are only used in the ClassMarkSet constructor.
086: */
087: private static class MarkSet {
088: private short methodIndex;
089: private String methodName;
090: private Map markSet = new HashMap();
091:
092: public MarkSet(String name, short methIndex) {
093: this .methodName = name;
094: this .methodIndex = methIndex;
095: }
096:
097: public String getMethodName() {
098: return this .methodName;
099: }
100:
101: public short getMethodIndex() {
102: return this .methodIndex;
103: }
104:
105: public void addMark(MarkRecord mr) {
106: if (this .methodIndex != mr.getMethodIndex()) {
107: throw new IllegalStateException(
108: "Put mark in wrong method bucket.");
109: }
110: Short index = new Short(mr.getMarkIndex());
111: if (!this .markSet.containsKey(index)) {
112: this .markSet.put(index, new DidCover(mr));
113: } else {
114: throw new IllegalArgumentException("Mark index "
115: + index
116: + " is in the MarkRecord list mroe than once.");
117: }
118: }
119:
120: public void coverMark(short index) {
121: DidCover dc = getMark(index);
122: if (dc != null) {
123: dc.cover();
124: } else {
125: // the marks and the logs are out-of-sync
126: /*
127: LOG.fatal( "Channel log record "+
128: "has mark "+index+" in method "+getMethodName()+
129: " [index "+getMethodIndex()+
130: "] which is not known by the class records." );
131: */
132: throw new IllegalArgumentException(
133: "Channel log record "
134: + "has mark "
135: + index
136: + " in method "
137: + getMethodName()
138: + " [index "
139: + getMethodIndex()
140: + "] which is not known by the class records.");
141: }
142: }
143:
144: public DidCover getMark(short index) {
145: return (DidCover) this .markSet.get(new Short(index));
146: }
147:
148: public MarkRecord[] getMarksOfType(boolean type) {
149: List out = new ArrayList();
150: Iterator iter = this .markSet.values().iterator();
151: while (iter.hasNext()) {
152: DidCover dc = (DidCover) iter.next();
153: if (dc.wasCovered == type) {
154: out.add(dc.mr);
155: }
156: }
157: return (MarkRecord[]) out
158: .toArray(new MarkRecord[out.size()]);
159: }
160: }
161:
162: //------------------------------------------------------------------------
163:
164: /**
165: * Convienient way to store the sorted methods and their data.
166: * Instances of this class are only used in the ClassMarkSet constructor.
167: */
168: private static class MethodSet {
169: private String methodNames[];
170: private Map perMethodItems = new HashMap();
171:
172: public MethodSet(String methNames[], MarkRecord mrL[]) {
173: this .methodNames = copyStringArray(methNames);
174: for (int i = 0; i < methNames.length; ++i) {
175: if (methNames[i] == null) {
176: throw new IllegalArgumentException("No null args.");
177: }
178: this .perMethodItems.put(methNames[i], new MarkSet(
179: methNames[i], (short) i));
180: }
181:
182: int len = mrL.length;
183: for (int i = 0; i < len; ++i) {
184: if (mrL[i] == null) {
185: throw new IllegalArgumentException("No null args.");
186: }
187: String sig = mrL[i].getMethodSignature();
188: MarkSet ms = get(sig);
189: if (ms == null) {
190: throw new IllegalArgumentException(
191: "Found mark for method "
192: + sig
193: + " which was not in the method list.");
194: }
195:
196: // assurance
197: if (ms.getMethodIndex() != mrL[i].getMethodIndex()) {
198: throw new IllegalArgumentException(
199: "The signature order from ClassRecord ["
200: + ms.getMethodIndex()
201: + " does not match the method index ["
202: + mrL[i].getMethodIndex()
203: + "] for the mark.");
204: }
205:
206: ms.addMark(mrL[i]);
207: }
208: }
209:
210: public int getMethodCount() {
211: return this .methodNames.length;
212: }
213:
214: public String[] getMethodNames() {
215: return copyStringArray(this .methodNames);
216: }
217:
218: public short getMethodIndex(String methName) {
219: MarkSet ms = get(methName);
220: if (ms == null) {
221: return (short) -1;
222: }
223: return ms.getMethodIndex();
224: }
225:
226: public String getMethodByIndex(short index) {
227: int iindex = (int) index;
228: String names[] = getMethodNames();
229: if (iindex < 0 || iindex >= names.length) {
230: return null;
231: }
232: return names[iindex];
233: }
234:
235: public Iterator nameIterator() {
236: return this .perMethodItems.keySet().iterator();
237: }
238:
239: public MarkSet get(String methName) {
240: return (MarkSet) this .perMethodItems.get(methName);
241: }
242:
243: public MarkSet get(short methodIndex) {
244: return get(getMethodByIndex(methodIndex));
245: }
246: }
247:
248: //------------------------------------------------------------------------
249:
250: /**
251: *
252: */
253: ClassMarkSet(String className, String methodSigs[],
254: MarkRecord[] marks, IChannelLogRecord[] classLogs) {
255: if (marks == null || classLogs == null || methodSigs == null) {
256: throw new IllegalArgumentException("No null args.");
257: }
258:
259: this .methodNames = copyStringArray(methodSigs);
260: MethodSet set = new MethodSet(methodSigs, marks);
261: coverMarks(set, classLogs);
262: this .methodToCoveredMarks = getMarksOfType(set, true);
263: this .methodToNotCoveredMarks = getMarksOfType(set, false);
264: }
265:
266: /**
267: * Return all the methods known by the list of marks and class logs.
268: */
269: public String[] getMethodSignatures() {
270: String s[] = this .methodNames;
271: List list = new ArrayList(s.length);
272: for (int i = 0; i < s.length; ++i) {
273: if (s[i] != null) {
274: list.add(s[i]);
275: }
276: }
277: return (String[]) list.toArray(new String[list.size()]);
278: }
279:
280: /**
281: * Return all the marks that were covered during the execution of the
282: * given method. Guaranteed to never return null.
283: */
284: public MarkRecord[] getCoveredMarksForMethod(String methodSig) {
285: MarkRecord[] mrL = (MarkRecord[]) this .methodToCoveredMarks
286: .get(methodSig);
287: if (mrL == null) {
288: throw new IllegalArgumentException("Unknown method: "
289: + methodSig);
290: }
291: return mrL;
292: }
293:
294: /**
295: * Return all the marks that were not executed during the runtime
296: * of the given method. Guaranteed to never return null.
297: */
298: public MarkRecord[] getNotCoveredMarksForMethod(String methodSig) {
299: MarkRecord[] mrL = (MarkRecord[]) this .methodToNotCoveredMarks
300: .get(methodSig);
301: if (mrL == null) {
302: throw new IllegalArgumentException("Unknown method: "
303: + methodSig);
304: }
305: return mrL;
306: }
307:
308: //------------------------------------------------------------------------
309: // Examine the input data and organize it
310:
311: private void coverMarks(MethodSet methods,
312: IChannelLogRecord[] classLogs) {
313: for (int i = 0; i < classLogs.length; ++i) {
314: IChannelLogRecord clr = classLogs[i];
315: if (clr == null) {
316: throw new IllegalArgumentException("no null args");
317: }
318: short markIndex = clr.getMarkIndex();
319: short methIndex = clr.getMethodIndex();
320: //LOG.debug( "Covering method "+mi+", mark "+markIndex );
321:
322: MarkSet ms = methods.get(methIndex);
323: if (ms != null) {
324: ms.coverMark(markIndex);
325: } else {
326: // the marks and the logs are out-of-sync
327: /*
328: // let's assume that it's ok.
329: LOG.fatal( "Channel log record "+
330: "refers to a method index ("+methIndex+
331: ") that is not known by the class records (mark = "+
332: markIndex+")." );
333: */
334: throw new IllegalArgumentException(
335: "Channel log record "
336: + "refers to a method index ("
337: + methIndex
338: + ") that is not known by the class records (mark = "
339: + markIndex + ").");
340: }
341: }
342: }
343:
344: private Map getMarksOfType(MethodSet methods, boolean covered) {
345: Map map = new HashMap();
346: Iterator iter = methods.nameIterator();
347: while (iter.hasNext()) {
348: String methName = (String) iter.next();
349: MarkSet ms = methods.get(methName);
350: map.put(methName, ms.getMarksOfType(covered));
351: }
352: return map;
353: }
354:
355: private static String[] copyStringArray(String in[]) {
356: int len = in.length;
357: String out[] = new String[len];
358: System.arraycopy(in, 0, out, 0, len);
359: return out;
360: }
361: }
|