001: package org.hansel.probes;
002:
003: import org.hansel.Probe;
004: import org.hansel.ProbeData;
005: import org.objectweb.asm.Label;
006: import org.objectweb.asm.MethodVisitor;
007: import org.objectweb.asm.Opcodes;
008:
009: public class SelectProbe extends Probe {
010: private boolean[] covered;
011: private int[] keys;
012: private Label[] labels;
013: private boolean[] isDefault;
014: private boolean defaultCovered;
015:
016: private boolean isHit;
017:
018: public SelectProbe(ProbeData pd, int min, int max, Label dflt,
019: Label labels[]) {
020: super (pd);
021:
022: this .labels = labels;
023: this .keys = new int[max - min + 1];
024: for (int i = 0; i < max - min + 1; i++) {
025: keys[i] = min + i;
026: }
027:
028: this .covered = new boolean[labels.length];
029:
030: // Some targets might point to default target.
031: // These targets have to be treated just like the defaultTarget
032: isDefault = new boolean[labels.length];
033: for (int i = 0; i < isDefault.length; i++) {
034: isDefault[i] = (labels[i] == dflt);
035: covered[i] = isDefault[i];
036: }
037: }
038:
039: public SelectProbe(ProbeData pd, Label dflt, int[] keys,
040: Label[] labels) {
041: super (pd);
042:
043: this .labels = labels;
044: this .keys = keys;
045: this .covered = new boolean[labels.length];
046:
047: // Some targets might point to default target.
048: // These targets have to be treated just like the defaultTarget
049: isDefault = new boolean[labels.length];
050: for (int i = 0; i < isDefault.length; i++) {
051: isDefault[i] = (labels[i] == dflt);
052: covered[i] = isDefault[i];
053: }
054: }
055:
056: /**
057: * Return the filure message for this probe.
058: * @return Failure message.
059: */
060: public String getFailureMessage() {
061: int count = 0;
062: String cases = "";
063:
064: for (int i = 0; i < covered.length; i++) {
065: if (!covered[i]) {
066: cases += "'" + keys[i] + "', ";
067: count++;
068: }
069: }
070:
071: if (!defaultCovered) {
072: count++;
073: cases += "'default', ";
074: }
075:
076: cases = cases.substring(0, cases.length() - 2);
077:
078: int index = cases.lastIndexOf(',');
079: if (index > -1) {
080: cases = cases.substring(0, index) + " and "
081: + cases.substring(index + 2);
082: }
083:
084: if (count > 1) {
085: return "Switch-cases " + cases + " have not been covered.";
086: } else {
087: return "Switch-case " + cases + " has not been covered.";
088: }
089: }
090:
091: /**
092: * Return wether this probe failed to be covered.
093: * A probe for a conditional branch fails, if the branch is only taken,
094: * or only omitted. If both cases are encountered, the probe is fully
095: * covered. If the probe is not executed at all, this method still returns
096: * false, because in that case, another probe has to fail (otherwise this
097: * probe had been reached). Because the other failure is more important,
098: * the result of this probe is left out in this case.
099: * @return true If covering this probe failed.
100: */
101: public boolean displayFailure() {
102: if (!isHit) {
103: return false;
104: }
105:
106: return coverageFailure();
107: }
108:
109: public boolean coverageFailure() {
110: if (!defaultCovered) {
111: return true;
112: }
113:
114: for (int i = 0; i < covered.length; i++) {
115: if (!covered[i]) {
116: return true;
117: }
118: }
119:
120: return false;
121: }
122:
123: private final int getIndex(int value) {
124: for (int i = 0; i < keys.length; i++) {
125: if (keys[i] == value) {
126: return i;
127: } else if (keys[i] > value) {
128: return -1;
129: }
130:
131: }
132:
133: return -1;
134: }
135:
136: public void hit(int value) {
137: isHit = true;
138:
139: int index = getIndex(value);
140:
141: if ((index == -1) || isDefault[index]) {
142: defaultCovered = true;
143: } else {
144: // Cover all keys that point to the same label.
145: Label label = labels[index];
146: for (int i = 0; i < labels.length; i++) {
147: if (labels[i] == label) {
148: covered[i] = true;
149: }
150: }
151: }
152: }
153:
154: public void insertProbeCode(MethodVisitor cv) {
155: cv.visitInsn(Opcodes.DUP);
156: cv.visitLdcInsn(new Integer(getID()));
157: cv.visitMethodInsn(Opcodes.INVOKESTATIC, HIT_CLASS,
158: "hitSelect", "(II)V");
159: }
160: }
|