Skip to content

Commit

Permalink
Add tests for recover semantics.
Browse files Browse the repository at this point in the history
  • Loading branch information
jemc committed Apr 11, 2016
1 parent b41a1da commit 8dc856a
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/libponyc/expr/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,11 @@ bool expr_recover(ast_t* ast)

if(r_type == NULL)
{
ast_error(ast, "can't recover to this capability");
ast_error(expr, "expression type is %s", ast_print_type(type));
errorframe_t frame = NULL;
ast_error_frame(&frame, ast, "can't recover to this capability");
ast_error_frame(&frame, expr, "expression type is %s",
ast_print_type(type));
errorframe_report(&frame);
return false;
}

Expand Down
257 changes: 257 additions & 0 deletions test/libponyc/recover.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#include <gtest/gtest.h>
#include <platform.h>

#include "util.h"


#define TEST_COMPILE(src) DO(test_compile(src, "expr"))
#define TEST_ERRORS_1(src, err1) DO(test_errors_1(src, "expr", err1));


class RecoverTest : public PassTest
{};


TEST_F(RecoverTest, CanRecover_NewRefToIso)
{
const char* src =
"class Class\n"
" new ref create() => None\n"

"primitive Prim\n"
" fun apply(): Class iso =>\n"
" recover iso Class end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CanRecover_NewRefToVal)
{
const char* src =
"class Class\n"
" new ref create() => None\n"

"primitive Prim\n"
" fun apply(): Class val =>\n"
" recover val Class end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CantRecover_NewValToIso)
{
const char* src =
"class Class\n"
" new val create() => None\n"

"primitive Prim\n"
" fun apply(): Class iso =>\n"
" recover iso Class end";

TEST_ERRORS_1(src, "can't recover to this capability");
}

TEST_F(RecoverTest, CantRecover_NewTagToVal)
{
const char* src =
"class Class\n"
" new tag create() => None\n"

"primitive Prim\n"
" fun apply(): Class val =>\n"
" recover val Class end";

TEST_ERRORS_1(src, "can't recover to this capability");
}

TEST_F(RecoverTest, CantAccess_LetLocalRef)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(): Wrap iso =>\n"
" let inner: Inner ref = Inner\n"
" recover Wrap(inner) end";

TEST_ERRORS_1(src, "can't access a non-sendable local defined outside");
}

TEST_F(RecoverTest, CanAccess_LetLocalVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(): Wrap iso =>\n"
" let inner: Inner val = Inner\n"
" recover Wrap(inner) end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CanAccess_LetLocalConsumedIso)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(): Wrap iso =>\n"
" let inner: Inner iso = Inner\n"
" recover Wrap(consume inner) end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CantAccess_VarLocalRef)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(): Wrap iso =>\n"
" var inner: Inner ref = Inner\n"
" recover Wrap(inner) end";

TEST_ERRORS_1(src, "can't access a non-sendable local defined outside");
}

TEST_F(RecoverTest, CanAccess_VarLocalVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(): Wrap iso =>\n"
" var inner: Inner val = Inner\n"
" recover Wrap(inner) end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CanAccess_VarLocalConsumedIso)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(): Wrap iso =>\n"
" var inner: Inner iso = Inner\n"
" recover Wrap(consume inner) end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CantAccess_ParamRef)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(inner: Inner ref): Wrap iso =>\n"
" recover Wrap(inner) end";

TEST_ERRORS_1(src, "can't access a non-sendable parameter");
}

TEST_F(RecoverTest, CanAccess_ParamVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(inner: Inner val): Wrap iso =>\n"
" recover Wrap(inner) end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CanAccess_ParamConsumedIso)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"primitive Prim\n"
" fun apply(inner: Inner iso): Wrap iso =>\n"
" recover Wrap(consume inner) end";

TEST_COMPILE(src);
}

TEST_F(RecoverTest, CantAccess_LetFieldVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"class Class\n"
" let inner: Inner val = Inner\n"
" fun apply(): Wrap iso =>\n"
" recover Wrap(inner) end";

TEST_ERRORS_1(src, "can't read a field through Class tag");
}

TEST_F(RecoverTest, CantAccess_VarFieldVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"class Class\n"
" var inner: Inner val = Inner\n"
" fun apply(): Wrap iso =>\n"
" recover Wrap(inner) end";

TEST_ERRORS_1(src, "can't read a field through Class tag");
}

TEST_F(RecoverTest, CantAccess_EmbedFieldVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"class Class\n"
" embed inner: Inner val = Inner\n"
" fun apply(): Wrap iso =>\n"
" recover Wrap(inner) end";

TEST_ERRORS_1(src, "can't read a field through Class tag");
}

TEST_F(RecoverTest, CantAccess_FunReturnVal)
{
const char* src =
"class Inner\n"
"class Wrap\n"
" new create(s: Inner box) => None\n"

"class Class\n"
" fun inner(): Inner val => Inner\n"
" fun apply(): Wrap iso =>\n"
" recover Wrap(inner()) end";

TEST_ERRORS_1(src, "receiver type is not a subtype of target type");
}
12 changes: 12 additions & 0 deletions test/libponyc/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,18 @@ void PassTest::test_error(const char* src, const char* pass)
}


void PassTest::test_errors_1(const char* src, const char* pass,
const char* err1)
{
DO(test_error(src, pass));

ASSERT_EQ(1, get_error_count());
errormsg_t* errors = get_errors();
EXPECT_TRUE(strstr(errors->msg, err1) != NULL)
<< "Actual error: " << errors->msg;
}


void PassTest::test_equiv(const char* actual_src, const char* actual_pass,
const char* expect_src, const char* expect_pass)
{
Expand Down
4 changes: 4 additions & 0 deletions test/libponyc/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class PassTest : public testing::Test
// Check that the given source fails when compiled to the specified pass
void test_error(const char* src, const char* pass);

// Check that the given source fails when compiled to the specified pass,
// exactly N errors are produced, and the errors match expected text.
void test_errors_1(const char* src, const char* pass, const char* err1);

// Check that the 2 given sources compile to give the same AST for the first
// package
void test_equiv(const char* actual_src, const char* actual_pass,
Expand Down

0 comments on commit 8dc856a

Please sign in to comment.