package japicmp.test;
import com.google.common.base.Optional;
import japicmp.cmp.JApiCmpArchive;
import japicmp.cmp.JarArchiveComparator;
import japicmp.cmp.JarArchiveComparatorOptions;
import japicmp.model.JApiChangeStatus;
import japicmp.model.JApiClass;
import japicmp.model.SyntheticAttribute;
import javassist.*;
import javassist.Modifier;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import static japicmp.test.util.Helper.*;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class SyntheticAttributeTest {
@Test
public void test() throws IOException, CannotCompileException, NotFoundException {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
JarArchiveComparator jarArchiveComparator = new JarArchiveComparator(options);
JApiCmpArchive archiveV1 = getArchive("japicmp-test-v1.jar");
JApiCmpArchive archiveV2 = getArchive("japicmp-test-v2.jar");
JApiCmpArchive instrumentedArchiveV2 = instrumentClass(archiveV2);
List<JApiClass> jApiClasses = jarArchiveComparator.compare(archiveV1, instrumentedArchiveV2);
JApiClass syntheticClass = getJApiClass(jApiClasses, Synthetic.class.getName());
assertThat(syntheticClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(syntheticClass.getSyntheticAttribute().getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(syntheticClass.getSyntheticAttribute().getOldAttribute(), is(Optional.of(SyntheticAttribute.NON_SYNTHETIC)));
assertThat(syntheticClass.getSyntheticAttribute().getNewAttribute(), is(Optional.of(SyntheticAttribute.SYNTHETIC)));
assertThat(getJApiMethod(syntheticClass.getMethods(), "newMethod").getChangeStatus(), is(JApiChangeStatus.NEW));
assertThat(getJApiMethod(syntheticClass.getMethods(), "newMethod").getSyntheticAttribute().getChangeStatus(), is(JApiChangeStatus.NEW));
assertThat(getJApiMethod(syntheticClass.getMethods(), "newMethod").getSyntheticAttribute().getOldAttribute(), is(Optional.<SyntheticAttribute>absent()));
assertThat(getJApiMethod(syntheticClass.getMethods(), "newMethod").getSyntheticAttribute().getNewAttribute(), is(Optional.of(SyntheticAttribute.SYNTHETIC)));
assertThat(getJApiField(syntheticClass.getFields(), "newField").getSyntheticAttribute().getChangeStatus(), is(JApiChangeStatus.NEW));
assertThat(getJApiField(syntheticClass.getFields(), "newField").getSyntheticAttribute().getOldAttribute(), is(Optional.<SyntheticAttribute>absent()));
assertThat(getJApiField(syntheticClass.getFields(), "newField").getSyntheticAttribute().getNewAttribute(), is(Optional.of(SyntheticAttribute.SYNTHETIC)));
}
private JApiCmpArchive instrumentClass(JApiCmpArchive archive) throws IOException, CannotCompileException, NotFoundException {
ClassPool classPool = ClassPool.getDefault();
String path = Paths.get(System.getProperty("user.dir"), "target", "japicmp-test-v2-instrumented.jar").toString();
try (ZipFile zipFile = new ZipFile(archive.getFile()); ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(path))) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
String name = zipEntry.getName();
if (name.contains(Synthetic.class.getSimpleName() + ".class")) {
try (InputStream inputStream = zipFile.getInputStream(zipEntry)) {
CtClass ctClass = classPool.makeClass(inputStream);
CtMethod method = CtNewMethod.make("public int newMethod(int x) { return x; }", ctClass);
javassist.bytecode.SyntheticAttribute syntheticAttribute = new javassist.bytecode.SyntheticAttribute(ctClass.getClassFile().getConstPool());
method.setAttribute(syntheticAttribute.getName(), syntheticAttribute.get());
ctClass.setAttribute(syntheticAttribute.getName(), syntheticAttribute.get());
ctClass.addMethod(method);
CtField newField = new CtField(classPool.get(String.class.getCanonicalName()), "newField", ctClass);
newField.setAttribute(syntheticAttribute.getName(), syntheticAttribute.get());
newField.setModifiers(Modifier.PUBLIC);
ctClass.addField(newField);
byte[] bytecode = ctClass.toBytecode();
ZipEntry newEntry = new ZipEntry(zipEntry.getName());
zos.putNextEntry(newEntry);
zos.write(bytecode);
}
} else {
zos.putNextEntry(zipEntry);
InputStream is = zipFile.getInputStream(zipEntry);
byte[] buf = new byte[1024];
int len;
while ((len = (is.read(buf))) != -1) {
zos.write(buf, 0, len);
}
}
}
}
return new JApiCmpArchive(new File(path), "n.a.");
}
}