/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package abs.backend.common; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import abs.backend.BackendTestDriver; @RunWith(Parameterized.class) public class ConcurrencyTests extends SemanticTests { public ConcurrencyTests(BackendTestDriver d) { super(d); } static String INTERFACE_I = "interface I { Bool m(); Unit n(); } "; static String CLASS_C = "class C implements I { Unit n() { } Bool m() { return True; } } "; static String CLASS_D = "interface DI { } class D implements DI { { Bool b = False; } }"; static String CALL_M_ASYNC = "{ Bool testresult = True; I i; i = new local C(); i!m(); }"; static String COG_CALL_M_ASYNC = "{ Bool testresult = True; Fut<Bool> f; I i; i = new C(); f = i!m(); testresult = f.get; }"; @Test public void asyncCall() { assertEvalTrue(INTERFACE_I + CLASS_C + CALL_M_ASYNC); } static String CALL_M_ASYNC_GET = "{ Bool testresult = False; I i; i = new C(); Fut<Bool> fut; fut = i!m(); testresult = fut.get; }"; @Test public void futGet() { assertEvalTrue(INTERFACE_I + CLASS_C + CALL_M_ASYNC_GET); } static String CALL_M_ASYNC_AWAIT_GET = "{ Bool testresult = False; I i; i = new local C(); Fut<Bool> fut; fut = i!m(); await fut?; testresult = fut.get; }"; @Test public void futAwaitAndGet() { assertEvalTrue(INTERFACE_I + CLASS_C + CALL_M_ASYNC_AWAIT_GET); } @Test public void twoFutureGuard() { assertEvalTrue(INTERFACE_I + CLASS_C + "{ Bool testresult = True; I i; i = new local C(); " + " Fut<Bool> f1; Fut<Bool> f2;" + " f1 = i!m(); f2 = i!m();" + " await f1? & f2?; }"); } @Test public void booleanGuard() { assertEvalTrue(INTERFACE_I + "class C implements I { Bool b = False; Unit n() { b = True; } Bool m() { await b; return b; } }" + "{ I i; i = new C(); Fut<Bool> f; f = i!m(); i!n(); Bool testresult = False; testresult = f.get; } "); } // Future passing tests static String INTERFACE_IF = "interface I {Fut<Bool> m();}"; static String CLASS_CF = "class C implements I {Bool n() {return True;} Fut<Bool> m() {Fut<Bool> p; p = this!n(); return p;}}"; static String CLASS_CF2 = "class C implements I {Bool n() {return True;} Fut<Bool> m() { return this!n();}}"; static String CLASS_CF3 = "class C implements I {Bool n() {return True;} Fut<Bool> inm(Fut<Bool> p) {suspend; return p;} Fut<Bool> m() {Fut<Fut<Bool>> result; {Fut<Bool> p; p = this!n(); result = this!inm(p);} await result?; return result.get;}}"; static String CALL_M_FUTURE = "{Bool testresult = False; I i; i = new local C(); Fut<Bool> p; p = i.m(); await p?; testresult = p.get;}"; @Test public void futureReturnValue() { // Return a future variable assertEvalTrue(INTERFACE_IF + CLASS_CF + CALL_M_FUTURE); } @Test public void futureReturnCallResult() { // Return the result of an asynchronous call assertEvalTrue(INTERFACE_IF + CLASS_CF2 + CALL_M_FUTURE); } @Test public void futureAsParameter() { // Use a future after variable bindings at the call's location have gone // out of scope assertEvalTrue(INTERFACE_IF + CLASS_CF3 + CALL_M_FUTURE); } @Test public void initBlockCOG() { assertEvalTrue(INTERFACE_I + "class C implements I { Bool b = False; { b = True; } Unit n() { } Bool m() { return b; }} " + COG_CALL_M_ASYNC); } @Test public void initBlockCOG2() { assertEvalTrue(INTERFACE_I+CLASS_D + "class C implements I { Bool b = False; { b = True; DI i = new local D(); } Unit n() { } Bool m() { return b; }} " + COG_CALL_M_ASYNC); } @Test public void runMethodCOG() { assertEvalTrue(INTERFACE_I + "class C implements I { Bool b = False; Unit run() { b = True; } Unit n() { } Bool m() { await b == True; return b; }} " + COG_CALL_M_ASYNC); } @Test public void initBlockCOG3() { assertEvalTrue(INTERFACE_I+CLASS_C +"{ Bool testresult = False; List<Fut<Unit>> fs = Nil; Fut<Unit> f; I a = new C(); f = a!n(); fs = Cons(f,fs); f = a!n(); f = head(fs); f.get; testresult = True;}"); } // ERROR Tests static String CALL_M_ASYNC_GET_DEADLOCK = "{ Bool testresult = False; I i; i = new local C(); Fut<Bool> fut; fut = i!m(); testresult = fut.get; }"; @Test public void futGetDeadlock() throws Exception { // Fails because a deadlock occurs assertEvalFails(INTERFACE_I + CLASS_C + CALL_M_ASYNC_GET_DEADLOCK); } static String CLASS_C_ASSERT_FAILS = "class C implements I { Unit n() { } Bool m() { assert False; return True; } } "; @Test public void assertionFails() throws Exception { assertEvalFails(INTERFACE_I + CLASS_C_ASSERT_FAILS + COG_CALL_M_ASYNC); } // Cross-cog sync calls are allowed until further notice // @Test // public void illegalSyncCall() throws Exception { // // Fails because a synchronous call to an object of a different COG is not // // allowed // assertEvalFails(INTERFACE_I + CLASS_C // + "{ Bool testresult = False; I i; i = new C(); testresult = i.m(); }"); // } @Test public void ticket407_concise_await() { assertEvalTrue(INTERFACE_I+CLASS_C+ "{ I o = new local C(); Bool testresult = await o!m(); }"); } }