001 /*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2003 jcoverage ltd.
005 * Copyright (C) 2005 Mark Doliner
006 * Copyright (C) 2005 Jeremy Thomerson
007 * Copyright (C) 2006 Jiri Mares
008 *
009 * Cobertura is free software; you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as published
011 * by the Free Software Foundation; either version 2 of the License,
012 * or (at your option) any later version.
013 *
014 * Cobertura is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * along with Cobertura; if not, write to the Free Software
021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
022 * USA
023 */
024
025 package net.sourceforge.cobertura.coveragedata;
026
027 import java.util.Iterator;
028 import java.util.SortedSet;
029 import java.util.TreeSet;
030
031 import net.sourceforge.cobertura.util.StringUtil;
032
033 public class SourceFileData extends CoverageDataContainer
034 implements Comparable, HasBeenInstrumented
035 {
036
037 private static final long serialVersionUID = 3;
038
039 private String name;
040
041 /**
042 * @param name In the format, "net/sourceforge/cobertura/coveragedata/SourceFileData.java"
043 */
044 public SourceFileData(String name)
045 {
046 if (name == null)
047 throw new IllegalArgumentException(
048 "Source file name must be specified.");
049 this.name = name;
050 }
051
052 public synchronized void addClassData(ClassData classData)
053 {
054 if (children.containsKey(classData.getBaseName()))
055 throw new IllegalArgumentException("Source file " + this.name
056 + " already contains a class with the name "
057 + classData.getBaseName());
058
059 // Each key is a class basename, stored as an String object.
060 // Each value is information about the class, stored as a ClassData object.
061 children.put(classData.getBaseName(), classData);
062 }
063
064 /**
065 * This is required because we implement Comparable.
066 */
067 public int compareTo(Object o)
068 {
069 if (!o.getClass().equals(SourceFileData.class))
070 return Integer.MAX_VALUE;
071 return this.name.compareTo(((SourceFileData)o).name);
072 }
073
074 public boolean contains(String name)
075 {
076 return this.children.containsKey(name);
077 }
078
079 public boolean containsInstrumentationInfo()
080 {
081 // Return false if any of our child ClassData's does not
082 // contain instrumentation info
083 Iterator iter = this.children.values().iterator();
084 while (iter.hasNext())
085 {
086 ClassData classData = (ClassData)iter.next();
087 if (!classData.containsInstrumentationInfo())
088 return false;
089 }
090 return true;
091 }
092
093 /**
094 * Returns true if the given object is an instance of the
095 * SourceFileData class, and it contains the same data as this
096 * class.
097 */
098 public boolean equals(Object obj)
099 {
100 if (this == obj)
101 return true;
102 if ((obj == null) || !(obj.getClass().equals(this.getClass())))
103 return false;
104
105 SourceFileData sourceFileData = (SourceFileData)obj;
106 return super.equals(obj)
107 && this.name.equals(sourceFileData.name);
108 }
109
110 public String getBaseName()
111 {
112 String fullNameWithoutExtension;
113 int lastDot = this.name.lastIndexOf('.');
114 if (lastDot == -1)
115 {
116 fullNameWithoutExtension = this.name;
117 }
118 else
119 {
120 fullNameWithoutExtension = this.name.substring(0, lastDot);
121 }
122
123 int lastSlash = fullNameWithoutExtension.lastIndexOf('/');
124 if (lastSlash == -1)
125 {
126 return fullNameWithoutExtension;
127 }
128 return fullNameWithoutExtension.substring(lastSlash + 1);
129 }
130
131 public SortedSet getClasses()
132 {
133 return new TreeSet(this.children.values());
134 }
135
136 public LineData getLineCoverage(int lineNumber)
137 {
138 Iterator iter = this.children.values().iterator();
139 while (iter.hasNext())
140 {
141 ClassData classData = (ClassData)iter.next();
142 if (classData.isValidSourceLineNumber(lineNumber))
143 return classData.getLineCoverage(lineNumber);
144 }
145 return null;
146 }
147
148 public String getName()
149 {
150 return this.name;
151 }
152
153 /**
154 * @return The name of this source file without the file extension
155 * in the format
156 * "net.sourceforge.cobertura.coveragedata.SourceFileData"
157 */
158 public String getNormalizedName()
159 {
160 String fullNameWithoutExtension;
161 int lastDot = this.name.lastIndexOf('.');
162 if (lastDot == -1)
163 {
164 fullNameWithoutExtension = this.name;
165 }
166 else
167 {
168 fullNameWithoutExtension = this.name.substring(0, lastDot);
169 }
170
171 return StringUtil.replaceAll(fullNameWithoutExtension, "/", ".");
172 }
173
174 /**
175 * @return The name of the package that this source file is in.
176 * In the format "net.sourceforge.cobertura.coveragedata"
177 */
178 public String getPackageName()
179 {
180 int lastSlash = this.name.lastIndexOf('/');
181 if (lastSlash == -1)
182 {
183 return null;
184 }
185 return StringUtil.replaceAll(this.name.substring(0, lastSlash), "/",
186 ".");
187 }
188
189 public int hashCode()
190 {
191 return this.name.hashCode();
192 }
193
194 public boolean isValidSourceLineNumber(int lineNumber)
195 {
196 Iterator iter = this.children.values().iterator();
197 while (iter.hasNext())
198 {
199 ClassData classData = (ClassData)iter.next();
200 if (classData.isValidSourceLineNumber(lineNumber))
201 return true;
202 }
203 return false;
204 }
205
206 }