/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2013 Tom Bachmann ******************************************************************************/ #include #include "flintxx/expression.h" #include "flintxx/tuple.h" #include "flintxx/test/helpers.h" #include "flintxx/test/myint.h" using namespace flint; using namespace mp; using namespace traits; void test_initialization() { myint a; tassert(a._data().payload == -1 && a._data().extra == 42); a._data().payload = 17; myint b = a; tassert(b._data().payload == 17); myint c(8); tassert(c._data().payload == 8 && c._data().extra == 2); myint d('a'); tassert(d._data().payload == 'a' && d._data().extra == 3); myint e(c + c); tassert(e._data().payload == 16); } void test_destruction() { bool destroyed = false; { myint a; a._data().destroyed = &destroyed; } tassert(destroyed); } void test_printing() { std::ostringstream o; myint a(4); o << a; tassert(o.str() == "4"); } void test_assignment() { myint a; myint b(43); a = b; tassert(a._data().payload == 43); tassert(a._data().extra == 4); a = WORD(44); tassert(a._data().payload == 44 && a._data().extra == 5); mylong c(0); c = a + b; tassert(c == WORD(87)); } void test_swap() { myint a(2), b(3); swap(a, b); tassert(a == 3 && b == 2 && a._data().extra == 1234); } void test_traits() { typedef myint immediate_expression; typedef int immediate_nonexpression; typedef my_expression< operations::plus, make_tuple::type > lazy_expression; tassert(is_expression::val == true); tassert(is_expression::val == false); tassert(is_expression::val == true); tassert(is_immediate_expr::val == true); tassert(is_immediate_expr::val == false); tassert(is_immediate_expr::val == false); tassert(is_immediate::val == true); tassert(is_immediate::val == true); tassert(is_immediate::val == false); tassert(is_lazy_expr::val == false); tassert(is_lazy_expr::val == false); tassert(is_lazy_expr::val == true); tassert(is_lazy_expr::val == false); } void test_equals() { myint a(3); myint b(4); myint c(3); tassert(a != b); tassert(a == c); tassert(a == 3); tassert(3 == a); tassert(a != 4); tassert(4 != a); tassert((a + b) == (a + 4)); } void test_arithmetic() { myint a(3); myint b(4); myint c(7); myint d(1); myint e(2); tassert((a + b).evaluate() == 7); tassert(a + b == c); tassert(a + b == 7); tassert(a - b == -1); tassert(a * b == 12); tassert(c / e == 3); tassert(c % e == 1); tassert(-a == -3); // Test arithmetic with immediates tassert(a + 4 == 7); tassert(4 + a == 7); tassert(a + WORD(4) == 7); tassert(4u + a == 7); // Test composite arithmetic tassert((a + 1) + (b + 2) == 10); tassert((a + d) + (b + 2) == 10); tassert((a + d) + (b + e) == 10); tassert((3 + d) + (b + e) == 10); tassert((3 + d) + (4 + e) == 10); tassert(a + (b + c) == 14); tassert(3 + (b + c) == 14); tassert(3 + (4 + c) == 14); tassert(3 + (b + 7) == 14); tassert(a + (b + 7) == 14); tassert((b + c) + a == 14); tassert((b + c) + 3 == 14); tassert((4 + c) + 3== 14); tassert((b + 7) + 3== 14); tassert((b + 7) + a== 14); // test combining unary and binary arithmetic tassert(-(-a) == 3); tassert(-(a - b) == b - a); tassert(-((-a) + (-b)) == a + b); // Test mixed arithmetic mylong al(WORD(3)); mylong bl(WORD(4)); mylong cl(WORD(7)); tassert(al + bl == cl); tassert(al + bl == WORD(7)); tassert(al + b == WORD(7)); tassert(a + bl == WORD(7)); tassert((a + bl) + cl == WORD(14)); tassert((a + b) + cl == WORD(14)); tassert((al + b) + c == WORD(14)); tassert(cl + (a + bl) == WORD(14)); tassert(cl + (a + b) == WORD(14)); tassert(c + (al + b) == WORD(14)); tassert((a + bl) + (cl + d) == WORD(15)); tassert((a + bl) + (c + d) == WORD(15)); tassert((a << 2) == 12); tassert(((a << 2) >> 2) == a); } void test_conversion() { myint a(4); mylong b(WORD(4)); tassert(typed_equals(a.to(), 4)); tassert(typed_equals(a.to(), b)); tassert(typed_equals((a + a).to(), 8)); } void test_assignment_arith() { myint a(1); myint b(2); a += b; tassert(a == 3 && b == 2); a += a*b; tassert(a == 9); a += 1; tassert(a == 10); } template bool is_subexpr(const Expr& e) { return tools::has_subexpr, Expr>::val; } void test_tools() { typedef tools::equal_types_pred intpred; myint a(1); mylong b(WORD(2)); tassert(tools::find_subexpr(a) == 1); tassert(tools::find_subexpr(a + b) == 1); tassert(tools::find_subexpr_T(a + b) == WORD(2)); tassert(tools::find_subexpr(b + (a + 2) + b) == 1); tassert(is_subexpr(a+b)); tassert(!is_subexpr(a+a)); } void test_temporaries() { myint a(1); #define T2 ((a + a) + (a + a)) #define T3 (T2 + T2) tassert(count_temporaries(T2) == 2); tassert(count_temporaries(T3) == 3); tassert(count_temporaries(T3 + T2) == 3); tassert(count_temporaries(T2 + T3) == 3); } void test_references() { mylong a(4); mylong_ref ar(a); mylong_cref acr(a); tassert(a == ar); tassert(a == acr); tassert(ar == acr); tassert(ar == WORD(4) && acr == WORD(4)); ar = WORD(5); tassert(a == WORD(5) && acr == WORD(5) && ar == WORD(5)); mylong b(6); ar = b; tassert(a == b); mylong_cref bcr(b); b = WORD(7); ar = bcr; tassert(a == b); a = WORD(4); b = WORD(5); tassert(a + bcr == WORD(9)); tassert(ar + bcr == WORD(9)); a = acr + b; tassert(a == WORD(9)); ar = acr + bcr; tassert(a == WORD(14)); a = WORD(4); tassert((a + a) + bcr == WORD(13)); tassert((acr + acr) + b == WORD(13)); tassert(((a + bcr) + acr + (ar + bcr)) + ((a + a) + (bcr + bcr)) == WORD(40)); a = ((a + bcr) + acr + (ar + bcr)) + ((a + a) + (bcr + bcr)); tassert(a == WORD(40)); a = WORD(4); ar = ((a + bcr) + acr + (ar + bcr)) + ((a + a) + (bcr + bcr)); tassert(a == WORD(40)); } struct S { }; S operator+(const S& s, const S&) {return s;} S operator-(const S&s) {return s;} template S operator*(const S& s, const T&) {return s;} void test_unrelated_overload() { // Test a bug in our operator overloading logic which used to not allow // this to compile. S s; s = s + s; s = -s; s = s * (myint(5) + myint(5)); } void test_multiary() { tassert(fourary_test(1, 2, 3, 4) == myint(1 + 2 + 3 + 4)); tassert(fiveary_test(1, 2, 3, 4, 5u) == 1 + 2 + 3 + 4 + 5); tassert(sixary_test(1, 2, 3, 4, 5, 6) == 1 + 2 + 3 + 4 + 5 + 6); tassert(sevenary_test(1, 2, 3, 4, 5, 6, 7) == 1 + 2 + 3 + 4 + 5 + 6 + 7); } void test_cstyle_io() { #if !defined (__WIN32) && !defined (__CYGWIN__) mylong c(17), d(0); FILE * f = std::fopen("expression_test", "w+"); tassert(f); print(f, c); std::fprintf(f, "\n"); print_pretty(f, c); std::fflush(f); std::fclose(f); f = std::fopen("expression_test", "r"); tassert(read(f, d) > 0); tassert(d == c); d = WORD(0); tassert(std::fscanf(f, "\n") == 0); fclose(f); tassert(std::remove("expression_test") == 0); #endif } int main() { std::cout << "expression...."; test_traits(); test_initialization(); test_destruction(); test_printing(); test_assignment(); test_swap(); test_equals(); test_arithmetic(); test_conversion(); test_assignment_arith(); test_tools(); test_temporaries(); test_references(); test_multiary(); test_cstyle_io(); test_unrelated_overload(); std::cout << "PASS" << std::endl; // TODO test that certain things *don't* compile? return 0; }