/** {@inheritDoc} */ @Override public void afterStatement(Statement statement, Scope scope, Throwable exception) { try { for (VariableReference var : statement.getVariableReferences()) { if (var.equals(statement.getReturnValue()) || var.equals(statement.getReturnValue().getAdditionalVariableReference())) continue; Object object = var.getObject(scope); if (var.isPrimitive()) { ConstantValue value = new ConstantValue(test, var.getGenericClass()); value.setValue(object); // logger.info("Statement before inlining: " + statement.getCode()); statement.replace(var, value); // logger.info("Statement after inlining: " + statement.getCode()); } else if (var.isString() && object != null) { ConstantValue value = new ConstantValue(test, var.getGenericClass()); try { String val = StringEscapeUtils.unescapeJava(object.toString()); value.setValue(val); statement.replace(var, value); } catch (IllegalArgumentException e) { // Exceptions may happen if strings are not valid unicode logger.info("Cannot escape invalid string: " + object); } // logger.info("Statement after inlining: " + statement.getCode()); } else if (var.isArrayIndex()) { // If this is an array index and there is an object outside the array // then replace the array index with that object for (VariableReference otherVar : scope.getElements(var.getType())) { Object otherObject = otherVar.getObject(scope); if (otherObject == object && !otherVar.isArrayIndex() && otherVar.getStPosition() < statement.getPosition()) { statement.replace(var, otherVar); break; } } } else { // TODO: Ignoring exceptions during getObject, but keeping the assertion for now if (object == null) { ConstantValue value = new ConstantValue(test, var.getGenericClass()); value.setValue(null); // logger.info("Statement before inlining: " + statement.getCode()); statement.replace(var, value); // logger.info("Statement after inlining: " + statement.getCode()); } } } } catch (CodeUnderTestException e) { logger.warn("Not inlining test: " + e.getCause()); // throw new AssertionError("This case isn't handled yet: " + e.getCause() // + ", " + Arrays.asList(e.getStackTrace())); } }
/** * Set variable to new value * * @param reference VariableReference * @param o Value */ public synchronized void setObject(VariableReference reference, Object o) { // Learn some dynamic information about this object if (reference instanceof ArrayReference) { ArrayReference arrayRef = (ArrayReference) reference; if (o != null && !o.getClass().isArray()) System.out.println("Trying to access object of class " + o.getClass() + " as array: " + o); else if (o != null) { Object value = o; List<Integer> lengths = new ArrayList<Integer>(); int idx = 0; while ((value != null) && value.getClass().isArray()) { if (idx == lengths.size()) { lengths.add(Array.getLength(value)); } else { lengths.set(idx, Array.getLength(value)); } if (Array.getLength(value) == 0) break; value = Array.get(value, 0); idx++; } arrayRef.setLengths(lengths); } else arrayRef.setArrayLength(0); } // TODO: Changing array types might invalidate array assignments - how to treat this properly? if (o != null && !o.getClass().equals(reference.getVariableClass()) && reference.getGenericClass().getNumParameters() == 0 && !reference.isPrimitive() // && !reference.getGenericClass().isClass() && !o.getClass().isArray()) { // && !(reference instanceof ArrayReference)) { if (TestUsageChecker.canUse(o.getClass())) { if (Proxy.isProxyClass(o.getClass())) { reference.setType(o.getClass().getSuperclass()); } else if (o.getClass().getName().contains("EnhancerByMockito")) { /* tricky: this is a functional mock for a class X. We do not want to set scopes on mock objects, as their class definitions are created on the fly and will be missing on different processes (eg communications between Master and Client). If X is a class, then the mock will extend it. However, if it was an interface, then we need to look at all of its interface to find the correct one */ String mockName = o.getClass().getName(); Class<?> target = o.getClass().getSuperclass(); if (!mockName.startsWith(target.getName() + "$")) { for (Class<?> inter : o.getClass().getInterfaces()) { if (mockName.startsWith(inter.getName() + "$")) { target = inter; break; } } } reference.setType(target); } else { reference.setType(o.getClass()); } } } pool.put(reference, o); }