package com.sora.util.akatsuki;
import static org.mockito.Mockito.mock;
import javax.lang.model.element.Modifier;
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import android.app.Fragment;
import android.os.Bundle;
@RunWith(Theories.class)
public class InternalClassDiscoveryIntegrationTest extends IntegrationTestBase {
// we just need something that @Arg supports natively
public static class MockedFragment extends Fragment {
public MockedFragment() {
// super();
}
}
private static class APITestBase extends BaseTestEnvironment {
private Object instance;
private Bundle mockedBundle;
public APITestBase(IntegrationTestBase base, TestSource source, TestSource... required) {
super(base, source, required);
instantaiteInstance(null);
}
public APITestBase(IntegrationTestBase base, TestSource instanceSource, TestSource source,
TestSource... required) {
super(base, source, required);
instantaiteInstance(instanceSource.fqcn());
}
private void instantaiteInstance(String instanceName) {
String instanceFqcn = instanceName != null ? instanceName : sources.get(0).fqcn();
try {
instance = findClass(instanceFqcn).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
throw new AssertionError("Unable to instantiate " + instanceFqcn, e);
}
}
@Override
protected void setupTestEnvironment() throws Exception {
mockedBundle = mock(Bundle.class);
}
public Object instance() {
return instance;
}
public Bundle mockedBundle() {
return mockedBundle;
}
}
interface APITestScenario {
APITestBase create(IntegrationTestBase base);
}
@DataPoint
public static APITestScenario createSimpleSource() {
TestSource source = new TestSource("test", generateClassName(), Modifier.PUBLIC);
source.appendFields(new RetainedTestField(String.class).createFieldSpec(),
new ArgTestField(Integer.class).createFieldSpec())
.appendTransformation((b, s) -> b.superclass(MockedFragment.class));
return base -> new APITestBase(base, source);
}
@DataPoint
public static APITestScenario createSourceWithInnerClass() {
TestSource enclosingClass = new TestSource("test", generateClassName(), Modifier.PUBLIC);
TestSource source = new TestSource(null, generateClassName(), Modifier.PUBLIC);
source.appendFields(new RetainedTestField(String.class).createFieldSpec(),
new ArgTestField(Integer.class).createFieldSpec())
.appendTransformation((b, s) -> b.superclass(MockedFragment.class));
enclosingClass.innerClasses(true, source);
return base -> new APITestBase(base, source, enclosingClass, new TestSource[] {});
}
// @DataPoint
// public static APITestScenario createSourceWithMultipleInnerClass() {
// throw new RuntimeException();
// }
//
// @DataPoint
// public static APITestScenario createSourceWithMultipleSameNameInnerClass() {
// throw new RuntimeException();
// }
//
// @DataPoint
// public static APITestScenario createSourceWithInnerClassAndInheritance() {
// throw new RuntimeException();
// }
@Theory
public void testSaveWithInstanceState(APITestScenario scenario)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
APITestBase base = scenario.create(this);
ClassLoader loader = base.classLoader();
Akatsuki.save(loader, base.instance(), base.mockedBundle());
BundleRetainer<Object> retainer = Akatsuki.findRetainerInstance(loader, base.instance(),
Retained.class);
retainer.restore(base.instance(), base.mockedBundle());
}
@Theory
public void testSaveWithArg(APITestScenario scenario)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
APITestBase base = scenario.create(this);
ClassLoader loader = base.classLoader();
BundleRetainer<Object> retainer = Akatsuki.findRetainerInstance(loader, base.instance(),
Arg.class);
retainer.restore(base.instance(), base.mockedBundle());
}
@Theory
public void testSaveWithInstanceStateAndArg(APITestScenario scenario)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
APITestBase base = scenario.create(this);
ClassLoader loader = base.classLoader();
Akatsuki.save(loader, base.instance(), base.mockedBundle());
BundleRetainer<Object> argRetainer = Akatsuki.findRetainerInstance(loader, base.instance(),
Arg.class);
BundleRetainer<Object> bundleRetainer = Akatsuki.findRetainerInstance(loader,
base.instance(), Retained.class);
argRetainer.restore(base.instance(), base.mockedBundle());
bundleRetainer.restore(base.instance(), base.mockedBundle());
}
}