TEST(IfTest, ThenWithExtraVar) { bool ok; Int i = any_int("I"); Int j = any_int("J"); If branch(i < 5); branch.track(i); branch.track(j); ok = branch.begin_then(); EXPECT_TRUE(ok); i = i + 1; std::stringstream out_then_i; out_then_i << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_then_i.str()); std::stringstream out_then_j; out_then_j << j.get_value().get_expr(); EXPECT_EQ("[J]", out_then_j.str()); branch.end(); std::stringstream out_end_i; out_end_i << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([I]+1):[I])", out_end_i.str()); std::stringstream out_end_j; out_end_j << j.get_value().get_expr(); EXPECT_EQ("[J]", out_end_j.str()); }
TEST(IfTest, ThenElseWithSingleVar) { bool ok; Int i = any_int("I"); If branch(i < 5); branch.track(i); ok = branch.begin_then(); EXPECT_TRUE(ok); i = i + 1; std::stringstream out_then; out_then << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_then.str()); ok = branch.begin_else(); EXPECT_TRUE(ok); i = i + 2; std::stringstream out_else; out_else << i.get_value().get_expr(); EXPECT_EQ("([I]+2)", out_else.str()); branch.end(); std::stringstream out_end; out_end << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([I]+1):([I]+2))", out_end.str()); }
// k is less than the number of loop iterations induced by concrete values. TEST(LoopTest, UnwindWithConcreteConditionLessThanK) { bool ok; Int i = 1; Loop loop(1u); loop.track(i); // 1x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 2; std::stringstream out_1x; out_1x << i.get_value().get_expr(); EXPECT_EQ("3", out_1x.str()); // 2x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 4; std::stringstream out_2x; out_2x << i.get_value().get_expr(); EXPECT_EQ("7", out_2x.str()); // 3x ok = loop.unwind(i < 7); EXPECT_FALSE(ok); std::stringstream out; out << i.get_value().get_expr(); EXPECT_EQ("7", out.str()); }
TEST(IfTest, ThenWithMultipleAnyVars) { bool ok; Int i = any_int("I"); Int j = any_int("J"); If branch(i < 5); branch.track(i); branch.track(j); ok = branch.begin_then(); EXPECT_TRUE(ok); i = i + any_int("A"); j = j + any_int("A"); std::stringstream out_then_i; out_then_i << i.get_value().get_expr(); EXPECT_EQ("([I]+[A])", out_then_i.str()); std::stringstream out_then_j; out_then_j << j.get_value().get_expr(); EXPECT_EQ("([J]+[A])", out_then_j.str()); branch.end(); std::stringstream out_end_i; out_end_i << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([I]+[A]):[I])", out_end_i.str()); std::stringstream out_end_j; out_end_j << j.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([J]+[A]):[J])", out_end_j.str()); }
// k is equal to the number of loop iterations induced by concrete values. TEST(LoopTest, UnwindWithConcreteConditionEqualK) { bool ok; Int i = 1; Loop loop(1u); loop.track(i); // 1x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 2; std::stringstream out_1x; out_1x << i.get_value().get_expr(); EXPECT_EQ("3", out_1x.str()); // 2x ok = loop.unwind(i < 3); EXPECT_FALSE(ok); // unwind(const Value<bool>&) call for 3x is undefined because ok == false. std::stringstream out; out << i.get_value().get_expr(); EXPECT_EQ("3", out.str()); }
TEST(LoopTest, Unwind2xWithSingleVarWithAny) { bool ok; Int i = any_int("I"); Loop loop(2u); loop.track(i); // 1x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + any_int("A"); std::stringstream out_1x; out_1x << i.get_value().get_expr(); EXPECT_EQ("([I]+[A])", out_1x.str()); // 2x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + any_int("B"); std::stringstream out_2x; out_2x << i.get_value().get_expr(); EXPECT_EQ("(([I]+[A])+[B])", out_2x.str()); // 3x ok = loop.unwind(any_bool("ANY")); EXPECT_FALSE(ok); std::stringstream join_out; join_out << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?((([I]+[A])<7)?(([I]+[A])+[B]):([I]+[A])):[I])", join_out.str()); }
TEST(LoopTest, Unwind4xWithSingleVar) { bool ok; Int i = any_int("I"); Loop loop(4u); loop.track(i); // 1x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + 1; std::stringstream out_1x; out_1x << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_1x.str()); // 2x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + 2; std::stringstream out_2x; out_2x << i.get_value().get_expr(); EXPECT_EQ("([I]+3)", out_2x.str()); // 3x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + 3; std::stringstream out_3x; out_3x << i.get_value().get_expr(); EXPECT_EQ("([I]+6)", out_3x.str()); // 4x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + 4; std::stringstream out_4x; out_4x << i.get_value().get_expr(); EXPECT_EQ("([I]+10)", out_4x.str()); // 5x ok = loop.unwind(any_bool("ANY")); EXPECT_FALSE(ok); std::stringstream join_out; join_out << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?((([I]+1)<5)?((([I]+3)<5)?((([I]+6)<5)?([I]+10):([I]+6)):([I]+3)):([I]+1)):[I])", join_out.str()); }
// A concrete loop condition becomes symbolic. TEST(LoopTest, UnwindWithConcreteAndSymbolicCondition) { bool ok; Int i = 1; Loop loop(1u); loop.track(i); // 1x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 2; std::stringstream out_1x; out_1x << i.get_value().get_expr(); EXPECT_EQ("3", out_1x.str()); // 2x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + any_int("A"); std::stringstream out_2x; out_2x << i.get_value().get_expr(); EXPECT_EQ("(3+[A])", out_2x.str()); // 3x ok = loop.unwind(i < 8); EXPECT_TRUE(ok); i = i + any_int("B"); std::stringstream out_3x; out_3x << i.get_value().get_expr(); EXPECT_EQ("((3+[A])+[B])", out_3x.str()); // 4x ok = loop.unwind(i < 9); EXPECT_FALSE(ok); std::stringstream out; out << i.get_value().get_expr(); EXPECT_EQ("(((3+[A])<8)?((3+[A])+[B]):(3+[A]))", out.str()); }
TEST(settings_types, Int) { Int i; ASSERT_TRUE(i.set_default("1")); ASSERT_STREQ("1", i.get_default().c_str()); ASSERT_STREQ("1", i.get_value().c_str()); ASSERT_TRUE(i.is_default()); ASSERT_TRUE(i.set_value("9")); ASSERT_FALSE(i.is_default()); ASSERT_EQ(9, i.value()); ASSERT_EQ(1, i.default_value()); }
TEST(IfTest, ThenWithSingleAnyVar) { bool ok; Int i = any_int("I"); If branch(i < 5); branch.track(i); ok = branch.begin_then(); EXPECT_TRUE(ok); i = i + any_int("A"); branch.end(); std::stringstream out_end; out_end << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([I]+[A]):[I])", out_end.str()); }
TEST(LoopTest, Unwind2xWithMultipleVarsWithAny) { bool ok; Int i = any_int("I"); Int j = any_int("J"); Loop loop(2u); loop.track(i); loop.track(j); // 1x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + any_int("A"); j = j + any_int("A"); std::stringstream out_i_1x; out_i_1x << i.get_value().get_expr(); EXPECT_EQ("([I]+[A])", out_i_1x.str()); std::stringstream out_j_1x; out_j_1x << j.get_value().get_expr(); EXPECT_EQ("([J]+[A])", out_j_1x.str()); // 2x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + any_int("B"); j = j + any_int("B"); std::stringstream out_i_2x; out_i_2x << i.get_value().get_expr(); EXPECT_EQ("(([I]+[A])+[B])", out_i_2x.str()); std::stringstream out_j_2x; out_j_2x << j.get_value().get_expr(); EXPECT_EQ("(([J]+[A])+[B])", out_j_2x.str()); // 3x ok = loop.unwind(any_bool("ANY")); EXPECT_FALSE(ok); std::stringstream out_i_join; out_i_join << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?((([I]+[A])<7)?(([I]+[A])+[B]):([I]+[A])):[I])", out_i_join.str()); std::stringstream out_j_join; out_j_join << j.get_value().get_expr(); EXPECT_EQ("(([I]<5)?((([I]+[A])<7)?(([J]+[A])+[B]):([J]+[A])):[J])", out_j_join.str()); }
TEST(IfTest, ThenElseWithConcreteTrueCondition) { bool ok; Int i = 2; If branch(i < 5); branch.track(i); ok = branch.begin_then(); EXPECT_TRUE(ok); i = i + any_int("A"); ok = branch.begin_else(); EXPECT_FALSE(ok); branch.end(); std::stringstream out_end; out_end << i.get_value().get_expr(); EXPECT_EQ("(2+[A])", out_end.str()); }
TEST(LoopTest, Unwind1xWithSingleVarWithAny) { bool ok; Int i = any_int("I"); Loop loop(1u); loop.track(i); // 1x ok = loop.unwind(i < 5); EXPECT_TRUE(ok); i = i + any_int("A"); // 2x ok = loop.unwind(any_bool("ANY")); EXPECT_FALSE(ok); std::stringstream out; out << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([I]+[A]):[I])", out.str()); }
TEST(IfTest, ThenElseWithMultipleVars) { bool ok; Int i = any_int("I"); Int j = any_int("J"); If branch(i < 5); branch.track(i); branch.track(j); ok = branch.begin_then(); EXPECT_TRUE(ok); i = i + 1; j = j + 2; std::stringstream out_then_i; out_then_i << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_then_i.str()); std::stringstream out_then_j; out_then_j << j.get_value().get_expr(); EXPECT_EQ("([J]+2)", out_then_j.str()); ok = branch.begin_else(); EXPECT_TRUE(ok); i = i + 3; j = j + 4; std::stringstream out_else_i; out_else_i << i.get_value().get_expr(); EXPECT_EQ("([I]+3)", out_else_i.str()); std::stringstream out_else_j; out_else_j << j.get_value().get_expr(); EXPECT_EQ("([J]+4)", out_else_j.str()); branch.end(); std::stringstream out_end_i; out_end_i << i.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([I]+1):([I]+3))", out_end_i.str()); std::stringstream out_end_j; out_end_j << j.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([J]+2):([J]+4))", out_end_j.str()); }
TEST(IfTest, ThenElseNestedThenWithExtraAndAnyVars) { bool ok; // only modified in outer scope Int i = any_int("I"); Int j = any_int("J"); // only modified in inner scope Int k = any_int("K"); // modified in both outer and inner scope Int x = any_int("X"); // never modified in either outer or inner scope Int c = any_int("C"); If outer_if(i < 5); outer_if.track(i); outer_if.track(j); outer_if.track(k); outer_if.track(x); outer_if.track(c); ok = outer_if.begin_then(); EXPECT_TRUE(ok); i = i + 1; j = j + any_int("A"); x = x + any_int("B"); std::stringstream out_outer_then_i; out_outer_then_i << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_outer_then_i.str()); std::stringstream out_outer_then_j; out_outer_then_j << j.get_value().get_expr(); EXPECT_EQ("([J]+[A])", out_outer_then_j.str()); std::stringstream out_outer_then_k; out_outer_then_k << k.get_value().get_expr(); EXPECT_EQ("[K]", out_outer_then_k.str()); std::stringstream out_outer_then_x; out_outer_then_x << x.get_value().get_expr(); EXPECT_EQ("([X]+[B])", out_outer_then_x.str()); std::stringstream out_outer_then_c; out_outer_then_c << c.get_value().get_expr(); EXPECT_EQ("[C]", out_outer_then_c.str()); If inner_if(i < 7); inner_if.track(i); inner_if.track(j); inner_if.track(k); inner_if.track(x); inner_if.track(c); ok = inner_if.begin_then(); EXPECT_TRUE(ok); x = x + 2; k = k + 3; std::stringstream out_inner_then_i; out_inner_then_i << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_inner_then_i.str()); std::stringstream out_inner_then_j; out_inner_then_j << j.get_value().get_expr(); EXPECT_EQ("([J]+[A])", out_inner_then_j.str()); std::stringstream out_inner_then_k; out_inner_then_k << k.get_value().get_expr(); EXPECT_EQ("([K]+3)", out_inner_then_k.str()); std::stringstream out_inner_then_x; out_inner_then_x << x.get_value().get_expr(); // TODO: Support associative operations over symbolic variables. EXPECT_EQ("(([X]+[B])+2)", out_inner_then_x.str()); std::stringstream out_inner_then_c; out_inner_then_c << c.get_value().get_expr(); EXPECT_EQ("[C]", out_inner_then_c.str()); inner_if.end(); std::stringstream out_inner_end_i; out_inner_end_i << i.get_value().get_expr(); // TODO: Optimize NaryExpr partial expressions. EXPECT_EQ("((([I]+1)<7)?([I]+1):([I]+1))", out_inner_end_i.str()); std::stringstream out_inner_end_j; out_inner_end_j << j.get_value().get_expr(); EXPECT_EQ("([J]+[A])", out_inner_end_j.str()); std::stringstream out_inner_end_k; out_inner_end_k << k.get_value().get_expr(); EXPECT_EQ("((([I]+1)<7)?([K]+3):[K])", out_inner_end_k.str()); std::stringstream out_inner_end_x; out_inner_end_x << x.get_value().get_expr(); // TODO: Support associative operations over symbolic variables. EXPECT_EQ("((([I]+1)<7)?(([X]+[B])+2):([X]+[B]))", out_inner_end_x.str()); std::stringstream out_inner_end_c; out_inner_end_c << c.get_value().get_expr(); EXPECT_EQ("[C]", out_inner_end_c.str()); ok = outer_if.begin_else(); EXPECT_TRUE(ok); i = i + 7; j = j + any_int("P"); x = x + any_int("Q"); std::stringstream out_outer_else_i; out_outer_else_i << i.get_value().get_expr(); EXPECT_EQ("([I]+7)", out_outer_else_i.str()); std::stringstream out_outer_else_j; out_outer_else_j << j.get_value().get_expr(); EXPECT_EQ("([J]+[P])", out_outer_else_j.str()); std::stringstream out_outer_else_k; out_outer_else_k << k.get_value().get_expr(); EXPECT_EQ("[K]", out_outer_else_k.str()); std::stringstream out_outer_else_x; out_outer_else_x << x.get_value().get_expr(); EXPECT_EQ("([X]+[Q])", out_outer_else_x.str()); std::stringstream out_outer_else_c; out_outer_else_c << c.get_value().get_expr(); EXPECT_EQ("[C]", out_outer_else_c.str()); outer_if.end(); std::stringstream out_outer_end_i; out_outer_end_i << i.get_value().get_expr(); // TODO: Optimize NaryExpr partial expressions. EXPECT_EQ("(([I]<5)?((([I]+1)<7)?([I]+1):([I]+1)):([I]+7))", out_outer_end_i.str()); std::stringstream out_outer_end_j; out_outer_end_j << j.get_value().get_expr(); EXPECT_EQ("(([I]<5)?([J]+[A]):([J]+[P]))", out_outer_end_j.str()); std::stringstream out_outer_end_k; out_outer_end_k << k.get_value().get_expr(); EXPECT_EQ("(([I]<5)?((([I]+1)<7)?([K]+3):[K]):[K])", out_outer_end_k.str()); std::stringstream out_outer_end_x; out_outer_end_x << x.get_value().get_expr(); // TODO: Support associative operations over symbolic variables. EXPECT_EQ("(([I]<5)?((([I]+1)<7)?(([X]+[B])+2):([X]+[B])):([X]+[Q]))", out_outer_end_x.str()); std::stringstream out_outer_end_c; out_outer_end_c << c.get_value().get_expr(); EXPECT_EQ("[C]", out_outer_end_c.str()); }
TEST(LoopTest, Unwind3xWithMultipleVars) { bool ok; Int i = any_int("I"); Int j = any_int("J"); Loop loop(3u); loop.track(i); loop.track(j); // 1x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 1; j = j + 2; std::stringstream out_i_1x; out_i_1x << i.get_value().get_expr(); EXPECT_EQ("([I]+1)", out_i_1x.str()); std::stringstream out_j_1x; out_j_1x << j.get_value().get_expr(); EXPECT_EQ("([J]+2)", out_j_1x.str()); // 2x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 3; j = j + 4; std::stringstream out_i_2x; out_i_2x << i.get_value().get_expr(); EXPECT_EQ("([I]+4)", out_i_2x.str()); std::stringstream out_j_2x; out_j_2x << j.get_value().get_expr(); EXPECT_EQ("([J]+6)", out_j_2x.str()); // 3x ok = loop.unwind(i < 7); EXPECT_TRUE(ok); i = i + 5; j = j + 6; std::stringstream out_i_3x; out_i_3x << i.get_value().get_expr(); EXPECT_EQ("([I]+9)", out_i_3x.str()); std::stringstream out_j_3x; out_j_3x << j.get_value().get_expr(); EXPECT_EQ("([J]+12)", out_j_3x.str()); // 4x ok = loop.unwind(any_bool("ANY")); EXPECT_FALSE(ok); std::stringstream out_i_join; out_i_join << i.get_value().get_expr(); EXPECT_EQ("(([I]<7)?((([I]+1)<7)?((([I]+4)<7)?([I]+9):([I]+4)):([I]+1)):[I])", out_i_join.str()); std::stringstream out_j_join; out_j_join << j.get_value().get_expr(); EXPECT_EQ("(([I]<7)?((([I]+1)<7)?((([I]+4)<7)?([J]+12):([J]+6)):([J]+2)):[J])", out_j_join.str()); }