/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.fibers.instrument;
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.fibers.Suspendable;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.objectweb.asm.Type;
public class SuspendablesScannerTest {
private static SuspendablesScanner scanner;
private static final Set<String> suspendables = new HashSet<>();
private static final Set<String> suspendableSupers = new HashSet<>();
@BeforeClass
public static void buildGraph() throws Exception {
// find test classes directory
final String resource = SuspendablesScannerTest.class.getName().replace('.', '/') + ".class";
final URL url = SuspendablesScannerTest.class.getClassLoader().getResource(resource);
final Path p1 = Paths.get(resource);
final Path p2 = Paths.get(url.toURI()).toAbsolutePath();
final Path p = p2.getRoot().resolve(p2.subpath(0, p2.getNameCount() - p1.getNameCount()));
System.out.println("Test classes: " + p);
scanner = new SuspendablesScanner(p);
// scanner = new AutoSuspendablesScanner(
// Paths.get(AutoSuspendablesScannerTest.class.getClassLoader()
// .getResource(AutoSuspendablesScannerTest.class.getName().replace('.', '/') + ".class").toURI()));
scanner.setAuto(true);
scanner.run();
scanner.putSuspendablesAndSupers(suspendables, suspendableSupers);
System.out.println("SUSPENDABLES: " + suspendables);
System.out.println("SUPERS: " + suspendableSupers);
}
@Test
public void suspendableCallTest() {
final String method = B.class.getName() + ".foo(I)V";
assertTrue(suspendables.contains(method));
}
@Test
public void superSuspendableCallTest() {
final String method = A.class.getName() + ".foo" + Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(IA.class));
assertTrue(suspendables.contains(method));
}
@Test
public void nonSuperSuspendableCallTest() {
final String method = A.class.getName() + ".foo()";
assertTrue(!suspendables.contains(method));
}
@Test
public void superNonSuspendableCallTest() {
final String method = A.class.getName() + ".bar" + Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(IA.class));
assertTrue(!suspendables.contains(method));
}
@Test
public void inheritedSuspendableCallTest() {
final String method = C.class.getName() + ".bax" + Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(IA.class));
assertTrue(suspendables.contains(method));
}
@Test
public void inheritedNonSuspendableCallTest() {
final String method = C.class.getName() + ".fon()";
assertTrue(!suspendables.contains(method));
}
@Test
public void superSuspendableTest() {
final String method = IA.class.getName() + ".foo(I)V";
assertTrue(suspendableSupers.contains(method));
}
@Test
public void bridgeMethodTest() {
assertTrue(suspendableSupers.contains(I2.class.getName() + ".foo(I)Ljava/lang/Number;"));
assertTrue(suspendableSupers.contains(A2.class.getName() + ".bar(I)Ljava/lang/Object;"));
assertTrue(!suspendableSupers.contains(A2.class.getName() + ".baz(I)Ljava/lang/Object;"));
}
static interface IA {
// super suspendable
void foo(int t);
// doesn't have suspandable implementation
void bar(int t);
}
static class A {
// suspendable
void foo(IA a) {
a.foo(0);
}
// not suspendable
void foo() {
bar(null); // test that if foo->bar->foo->... doesn't cause infinite loop
}
// not suspendable
void bar(IA a) {
a.bar(0);
foo();
}
// suspendable
void baz(IA a) {
a.foo(0);
}
}
static class B implements IA {
// suspendable
@Override
public void foo(int t) {
try {
Fiber.park();
} catch (SuspendExecution ex) {
throw new RuntimeException(ex);
}
}
// not suspendable
@Override
public void bar(int t) {
}
}
static class C extends A {
// suspendable
void bax(IA a) {
baz(a);
}
// non suspendable
void fon() {
foo();
}
}
static interface I2 {
Number foo(int x);
}
static class A2 {
protected Object bar(int x) {
return null;
}
protected Object baz(int x) {
return null;
}
}
static class C2 extends A2 implements I2 {
@Override
@Suspendable
protected String bar(int x) {
return "3";
}
@Override
@Suspendable
public Integer foo(int x) {
return 3;
}
public Integer baz(int x) {
return 3;
}
}
}