From 59ee683e544b573101bcdac213cd7a494d67b86a Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Fri, 17 Mar 2023 08:22:53 -0400 Subject: [PATCH] Adapt u_memstream code from mesa `u_memstream` is an `open_memstream`-like API that is designed to work universally across multiple operating systems, including Windows. These changes finally allow using the various `*_to_string` functions on Windows without segfaulting, thereby fixing #65. I have added some basic `polyxx` test cases involving the `<<` operator, which is defined in terms of the `*_to_string` functions, to ensure that the bug that this patch fixes remains fixed. --- src/CMakeLists.txt | 11 +-- src/interval/interval.c | 6 +- src/number/algebraic_number.c | 10 ++- src/number/dyadic_rational.h | 6 +- src/number/integer.c | 6 +- src/number/integer.h | 8 +- src/number/rational.h | 8 +- src/number/value.c | 6 +- src/polynomial/feasibility_set.c | 6 +- src/polynomial/output.c | 6 +- src/upolynomial/output.c | 6 +- src/utils/assignment.c | 12 ++- src/utils/u_memstream.c | 100 +++++++++++++++++++++++ src/utils/u_memstream.h | 83 +++++++++++++++++++ src/variable/variable_order.c | 8 +- test/polyxx/test_algebraic_number.cpp | 7 ++ test/polyxx/test_assignment.cpp | 6 +- test/polyxx/test_dyadic_interval.cpp | 7 ++ test/polyxx/test_dyadic_rational.cpp | 7 ++ test/polyxx/test_integer.cpp | 7 ++ test/polyxx/test_interval.cpp | 7 ++ test/polyxx/test_interval_assignment.cpp | 6 +- test/polyxx/test_polynomial.cpp | 11 ++- test/polyxx/test_rational.cpp | 7 ++ test/polyxx/test_rational_interval.cpp | 7 ++ test/polyxx/test_upolynomial.cpp | 7 ++ test/polyxx/test_value.cpp | 17 ++-- test/polyxx/test_variable.cpp | 6 +- 28 files changed, 339 insertions(+), 45 deletions(-) create mode 100644 src/utils/u_memstream.c create mode 100644 src/utils/u_memstream.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a33e112..ac20a969 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,10 @@ -set(poly_SOURCES +set(poly_SOURCES utils/debug_trace.c utils/assignment.c utils/statistics.c utils/output.c utils/sign_condition.c + utils/u_memstream.c number/integer.c number/rational.c number/dyadic_rational.c @@ -37,7 +38,7 @@ set(poly_SOURCES poly.c ) -if (NOT HAVE_OPEN_MEMSTREAM) +if (NOT HAVE_OPEN_MEMSTREAM) set(poly_SOURCES utils/open_memstream.c ${poly_SOURCES}) endif() @@ -81,9 +82,9 @@ target_link_libraries(poly ${GMP_LIBRARY}) add_library(polyxx SHARED ${polyxx_SOURCES}) set_target_properties(polyxx PROPERTIES - VERSION ${LIBPOLY_VERSION} + VERSION ${LIBPOLY_VERSION} SOVERSION ${LIBPOLY_VERSION_MAJOR} -) +) target_link_libraries(polyxx poly ${GMP_LIBRARY}) @@ -121,7 +122,7 @@ endif() # # Linux, FreeBSD, and old versions of Darwin (and probably other systems) don't use fPIC by default. # We just check for Linux and FreeBSD here. -# +# if(LIBPOLY_BUILD_STATIC_PIC) add_library(static_pic_poly STATIC ${poly_SOURCES}) set_target_properties(static_pic_poly PROPERTIES OUTPUT_NAME picpoly POSITION_INDEPENDENT_CODE true) diff --git a/src/interval/interval.c b/src/interval/interval.c index d246cb1a..85594f71 100644 --- a/src/interval/interval.c +++ b/src/interval/interval.c @@ -1072,11 +1072,13 @@ int lp_interval_size_approx(const lp_interval_t* I) { } char* lp_interval_to_string(const lp_interval_t* I) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_interval_print(I, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/number/algebraic_number.c b/src/number/algebraic_number.c index 0c9733ef..6b340a62 100644 --- a/src/number/algebraic_number.c +++ b/src/number/algebraic_number.c @@ -503,11 +503,13 @@ int lp_algebraic_number_print(const lp_algebraic_number_t* a, FILE* out) { } char* lp_algebraic_number_to_string(const lp_algebraic_number_t* a) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_algebraic_number_print(a, f); - fclose(f); + u_memstream_close(&mem); return str; } @@ -865,10 +867,10 @@ lp_upolynomial_t* lp_upolynomial_shift(const lp_upolynomial_t* poly, const lp_in lp_upolynomial_unpack(poly, coeffs); lp_upolynomial_t* out = lp_upolynomial_construct(lp_Z, 0, coeffs); - + for (size_t i = 1; i <= lp_upolynomial_degree(poly); ++i) { lp_upolynomial_t* cur = lp_upolynomial_mul_c(curmult, &coeffs[i]); - + lp_upolynomial_t* tout = lp_upolynomial_add(out, cur); lp_upolynomial_t* tcurmult = lp_upolynomial_mul(curmult, basemult); lp_upolynomial_delete(cur); diff --git a/src/number/dyadic_rational.h b/src/number/dyadic_rational.h index 86055295..f42b8dfe 100644 --- a/src/number/dyadic_rational.h +++ b/src/number/dyadic_rational.h @@ -113,11 +113,13 @@ int dyadic_rational_print(const lp_dyadic_rational_t* dq, FILE* out) { static inline char* dyadic_rational_to_string(const lp_dyadic_rational_t* q) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); dyadic_rational_print(q, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/number/integer.c b/src/number/integer.c index 2ec2b458..f0f87881 100644 --- a/src/number/integer.c +++ b/src/number/integer.c @@ -93,11 +93,13 @@ int lp_int_ring_print(const lp_int_ring_t* K, FILE* out) { } char* lp_int_ring_to_string(const lp_int_ring_t* K) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_int_ring_print(K, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/number/integer.h b/src/number/integer.h index 2f3bd3fe..ab0efbfe 100644 --- a/src/number/integer.h +++ b/src/number/integer.h @@ -26,7 +26,7 @@ #include #include -#include "utils/open_memstream.h" +#include "utils/u_memstream.h" #include "utils/hash.h" #define __var_unused(x) ((void)x) @@ -141,11 +141,13 @@ int integer_print_matrix(const lp_integer_t* c, size_t m, size_t n, FILE* out) { static inline char* integer_to_string(const lp_integer_t* c) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); integer_print(c, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/number/rational.h b/src/number/rational.h index f690d841..cf0cd5d1 100644 --- a/src/number/rational.h +++ b/src/number/rational.h @@ -22,7 +22,7 @@ #include #include -#include "utils/open_memstream.h" +#include "utils/u_memstream.h" static inline void rational_construct(lp_rational_t* q) { @@ -94,11 +94,13 @@ int rational_print(const lp_rational_t* c, FILE* out) { static inline char* rational_to_string(const lp_rational_t* q) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); rational_print(q, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/number/value.c b/src/number/value.c index b3091b81..a964edc7 100644 --- a/src/number/value.c +++ b/src/number/value.c @@ -599,11 +599,13 @@ void lp_value_get_den(const lp_value_t* v, lp_integer_t* den) { } char* lp_value_to_string(const lp_value_t* v) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_value_print(v, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/polynomial/feasibility_set.c b/src/polynomial/feasibility_set.c index c54ab2fc..af7bea5c 100644 --- a/src/polynomial/feasibility_set.c +++ b/src/polynomial/feasibility_set.c @@ -157,11 +157,13 @@ int lp_feasibility_set_print(const lp_feasibility_set_t* set, FILE* out) { } char* lp_feasibility_set_to_string(const lp_feasibility_set_t* set) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_feasibility_set_print(set, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/polynomial/output.c b/src/polynomial/output.c index 03c720bf..3fec4e55 100644 --- a/src/polynomial/output.c +++ b/src/polynomial/output.c @@ -102,10 +102,12 @@ int coefficient_print(const lp_polynomial_context_t* ctx, const coefficient_t* C } char* coefficient_to_string(const lp_polynomial_context_t* ctx, const coefficient_t* C) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); coefficient_print(ctx, C, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/upolynomial/output.c b/src/upolynomial/output.c index f77bbeb1..4972ca6f 100644 --- a/src/upolynomial/output.c +++ b/src/upolynomial/output.c @@ -77,11 +77,13 @@ int lp_upolynomial_print(const lp_upolynomial_t* p, FILE* out) { } char* lp_upolynomial_to_string(const lp_upolynomial_t* p) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_upolynomial_print(p, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/utils/assignment.c b/src/utils/assignment.c index fc46fbcc..5a04aff6 100644 --- a/src/utils/assignment.c +++ b/src/utils/assignment.c @@ -88,11 +88,13 @@ int lp_assignment_print(const lp_assignment_t* m, FILE* out) { } char* lp_assignment_to_string(const lp_assignment_t* m) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_assignment_print(m, f); - fclose(f); + u_memstream_close(&mem); return str; } @@ -195,11 +197,13 @@ int lp_interval_assignment_print(const lp_interval_assignment_t* m, FILE* out) { } char* lp_interval_assignment_to_string(const lp_interval_assignment_t* m) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_interval_assignment_print(m, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/src/utils/u_memstream.c b/src/utils/u_memstream.c new file mode 100644 index 00000000..680ead75 --- /dev/null +++ b/src/utils/u_memstream.c @@ -0,0 +1,100 @@ +/** + * A variation of open_memstream that works universally across multiple + * operating systems, including Windows. This implementation was adapted from + * the mesa source code at: + * + * https://gitlab.freedesktop.org/mesa/mesa/-/blob/14f9f98dcb4b6034c331120acf405e9a3c64edc6/src/util/memstream.c + * + * This mesa code is licensed under the MIT license. The copyright notice is + * reproduced below: + */ + +/* + * Copyright 2020 Lag Free Games, LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "utils/u_memstream.h" +#include "utils/open_memstream.h" + +#include + +#ifdef _WIN32 +#include +#endif + +bool +u_memstream_open(struct u_memstream *mem, char **bufp, size_t *sizep) +{ +#if defined(_WIN32) + bool success = false; + + char path[MAX_PATH]; + DWORD dwResult = GetTempPath(MAX_PATH, path); + if ((dwResult > 0) && (dwResult < MAX_PATH)) { + char *temp = mem->temp; + UINT uResult = GetTempFileName(path, "MEMSTREAM", 0, temp); + if (uResult != 0) { + FILE *f = fopen(temp, "w+b"); + success = f != NULL; + if (success) + { + mem->f = f; + mem->bufp = bufp; + mem->sizep = sizep; + } + } + } + + return success; +#else + FILE *const f = open_memstream(bufp, sizep); + mem->f = f; + return f != NULL; +#endif +} + +void +u_memstream_close(struct u_memstream *mem) +{ + FILE *const f = mem->f; + +#ifdef _WIN32 + long size = ftell(f); + if (size > 0) { + /* reserve space for the null terminator */ + char *buf = malloc(size + 1); + fseek(f, 0, SEEK_SET); + fread(buf, 1, size, f); + /* insert null terminator */ + buf[size] = '\0'; + + *mem->bufp = buf; + *mem->sizep = size; + } + + remove(mem->temp); +#endif + + fclose(f); +} diff --git a/src/utils/u_memstream.h b/src/utils/u_memstream.h new file mode 100644 index 00000000..77a3c6b6 --- /dev/null +++ b/src/utils/u_memstream.h @@ -0,0 +1,83 @@ +/** + * A variation of open_memstream that works universally across multiple + * operating systems, including Windows. This implementation was adapted from + * the mesa source code at: + * + * https://gitlab.freedesktop.org/mesa/mesa/-/blob/14f9f98dcb4b6034c331120acf405e9a3c64edc6/src/util/memstream.h + * + * This mesa code is licensed under the MIT license. The copyright notice is + * reproduced below: + */ + +/************************************************************************** + * + * Copyright 2020 Lag Free Games, LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef MEMSTREAM_H +#define MEMSTREAM_H + +#include +#include +#include /* PATH_MAX */ + +#ifdef _MSC_VER +#include +#ifndef PATH_MAX +#define PATH_MAX _MAX_PATH /* Equivalent to MAX_PATH from minwindef.h */ +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct u_memstream +{ + FILE *f; +#ifdef _WIN32 + char **bufp; + size_t *sizep; + char temp[PATH_MAX]; +#endif +}; + +extern bool +u_memstream_open(struct u_memstream *mem, char **bufp, size_t *sizep); + +extern void +u_memstream_close(struct u_memstream *mem); + +static inline FILE * +u_memstream_get(const struct u_memstream *mem) +{ + return mem->f; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/variable/variable_order.c b/src/variable/variable_order.c index c06303dd..dff35f7a 100644 --- a/src/variable/variable_order.c +++ b/src/variable/variable_order.c @@ -26,7 +26,7 @@ #include #include -#include "utils/open_memstream.h" +#include "utils/u_memstream.h" /** * A simple variable order that orders variable based on a given list, and @@ -163,11 +163,13 @@ int lp_variable_order_print(const lp_variable_order_t* var_order, const lp_varia } char* lp_variable_order_to_string(const lp_variable_order_t* var_order, const lp_variable_db_t* var_db) { + struct u_memstream mem; char* str = 0; size_t size = 0; - FILE* f = open_memstream(&str, &size); + u_memstream_open(&mem, &str, &size); + FILE* f = u_memstream_get(&mem); lp_variable_order_print(var_order, var_db, f); - fclose(f); + u_memstream_close(&mem); return str; } diff --git a/test/polyxx/test_algebraic_number.cpp b/test/polyxx/test_algebraic_number.cpp index 4978afec..e4e9d2d5 100644 --- a/test/polyxx/test_algebraic_number.cpp +++ b/test/polyxx/test_algebraic_number.cpp @@ -105,3 +105,10 @@ TEST_CASE("algebraic_number::operator/") { CHECK(sqrt2 / -sqrt2 == Rational(-1)); CHECK(-(sqrt2 / -sqrt2) == Rational(1)); } + +TEST_CASE("algebraic_number::operator<<") { + AlgebraicNumber a(UPolynomial({-2, 0, 1}), DyadicInterval(-2, -1)); + std::stringstream out; + out << a; + CHECK(out.str() == "<1*x^2 + (-2), (-3/2, -5/4)>"); +} diff --git a/test/polyxx/test_assignment.cpp b/test/polyxx/test_assignment.cpp index 5e329ef7..64b478d0 100644 --- a/test/polyxx/test_assignment.cpp +++ b/test/polyxx/test_assignment.cpp @@ -59,4 +59,8 @@ TEST_CASE("assignment") { CHECK(a.has(z)); CHECK(a.get(x) == Value(4)); CHECK(a.get(z) == Value(5)); -} \ No newline at end of file + + std::stringstream out; + out << a; + CHECK(out.str() == "[x -> 4, z -> 5]"); +} diff --git a/test/polyxx/test_dyadic_interval.cpp b/test/polyxx/test_dyadic_interval.cpp index 244b7260..52cec803 100644 --- a/test/polyxx/test_dyadic_interval.cpp +++ b/test/polyxx/test_dyadic_interval.cpp @@ -161,3 +161,10 @@ TEST_CASE("dyadic_interval::sgn") { CHECK(sgn(DyadicInterval(4, 5)) == 1); CHECK(sgn(DyadicInterval(5)) == 1); } + +TEST_CASE("dyadic_interval::operator<<") { + DyadicInterval di(1, 2); + std::stringstream out; + out << di; + CHECK(out.str() == "( 1 ; 2 )"); +} diff --git a/test/polyxx/test_dyadic_rational.cpp b/test/polyxx/test_dyadic_rational.cpp index 45308ae3..c408ea93 100644 --- a/test/polyxx/test_dyadic_rational.cpp +++ b/test/polyxx/test_dyadic_rational.cpp @@ -200,3 +200,10 @@ TEST_CASE("dyadic_rational::floor") { CHECK(floor(DyadicRational(1, 3)) == Integer(0)); CHECK(floor(DyadicRational(7, 2)) == Integer(1)); } + +TEST_CASE("dyadic_rational::operator<<") { + DyadicRational dr(1, 3); + std::stringstream out; + out << dr; + CHECK(out.str() == "1/8"); +} diff --git a/test/polyxx/test_integer.cpp b/test/polyxx/test_integer.cpp index 173289dc..dfc92a14 100644 --- a/test/polyxx/test_integer.cpp +++ b/test/polyxx/test_integer.cpp @@ -238,3 +238,10 @@ TEST_CASE("integer::gcd") { TEST_CASE("integer::lcm") { CHECK(lcm(Integer(15), Integer(35)) == Integer(105)); } + +TEST_CASE("integer::operator<<") { + Integer i(5); + std::stringstream out; + out << i; + CHECK(out.str() == "5"); +} diff --git a/test/polyxx/test_interval.cpp b/test/polyxx/test_interval.cpp index 5cb6dc75..8fbdc542 100644 --- a/test/polyxx/test_interval.cpp +++ b/test/polyxx/test_interval.cpp @@ -182,3 +182,10 @@ TEST_CASE("interval::operator*") { CHECK(Interval(-1,1) * Interval(1,2) == Interval(-2,2)); CHECK(Interval(-1,1) * Interval(-1,2) == Interval(-2,2)); } + +TEST_CASE("interval::operator<<") { + Interval i(1, 3); + std::stringstream out; + out << i; + CHECK(out.str() == "(1, 3)"); +} diff --git a/test/polyxx/test_interval_assignment.cpp b/test/polyxx/test_interval_assignment.cpp index d3bfe480..85c8152e 100644 --- a/test/polyxx/test_interval_assignment.cpp +++ b/test/polyxx/test_interval_assignment.cpp @@ -59,4 +59,8 @@ TEST_CASE("interval_assignment") { CHECK(a.has(z)); CHECK(a.get(x) == Interval(4, 5)); CHECK(a.get(z) == Interval(5, 6)); -} \ No newline at end of file + + std::stringstream out; + out << a; + CHECK(out.str() == "[x -> (4, 5), z -> (5, 6)]"); +} diff --git a/test/polyxx/test_polynomial.cpp b/test/polyxx/test_polynomial.cpp index aefb46fb..7360d42f 100644 --- a/test/polyxx/test_polynomial.cpp +++ b/test/polyxx/test_polynomial.cpp @@ -71,4 +71,13 @@ TEST_CASE("polynomial::psc") { CHECK(tmp[3] == Integer(0)); CHECK(tmp[4] == Integer(-45)); CHECK(tmp[5] == Integer(7)); -} \ No newline at end of file +} + +TEST_CASE("polynomial::operator<<") { + Variable y("y"); + Variable x("x"); + Polynomial p = 1 * pow(x, 6) + 2 * pow(x, 5) + 3 * y - 1; + std::stringstream out; + out << p; + CHECK(out.str() == "1*x^6 + 2*x^5 + (3*y - 1)"); +} diff --git a/test/polyxx/test_rational.cpp b/test/polyxx/test_rational.cpp index 1e9dbc0c..f4be79a0 100644 --- a/test/polyxx/test_rational.cpp +++ b/test/polyxx/test_rational.cpp @@ -163,3 +163,10 @@ TEST_CASE("rational::floor") { CHECK(floor(Rational(1)) == Rational(1)); CHECK(floor(Rational(Integer(1), Integer(2))) == Rational()); } + +TEST_CASE("rational::operator<<") { + Rational r(1); + std::stringstream out; + out << r; + CHECK(out.str() == "1"); +} diff --git a/test/polyxx/test_rational_interval.cpp b/test/polyxx/test_rational_interval.cpp index ec09770e..7c629325 100644 --- a/test/polyxx/test_rational_interval.cpp +++ b/test/polyxx/test_rational_interval.cpp @@ -47,3 +47,10 @@ TEST_CASE("rational_interval::sgn") { CHECK(sgn(RationalInterval(0, 2)) == 1); CHECK(sgn(RationalInterval(1, 2)) == 1); } + +TEST_CASE("rational_interval::operator<<") { + RationalInterval ri(-3, 2); + std::stringstream out; + out << ri; + CHECK(out.str() == "( -3 ; 2 )"); +} diff --git a/test/polyxx/test_upolynomial.cpp b/test/polyxx/test_upolynomial.cpp index 005430d9..5b6d7c52 100644 --- a/test/polyxx/test_upolynomial.cpp +++ b/test/polyxx/test_upolynomial.cpp @@ -267,3 +267,10 @@ TEST_CASE("upolynomial::isolate_real_roots") { CHECK(roots[3] == AlgebraicNumber(UPolynomial({-3, 0, 1}), DyadicInterval(1, 2))); } } + +TEST_CASE("upolynomial::operator<<") { + UPolynomial p({1, 2, 3, 4, 5}); + std::stringstream out; + out << p; + CHECK(out.str() == "5*x^4 + 4*x^3 + 3*x^2 + 2*x + 1"); +} diff --git a/test/polyxx/test_value.cpp b/test/polyxx/test_value.cpp index 37b70268..9452fdbe 100644 --- a/test/polyxx/test_value.cpp +++ b/test/polyxx/test_value.cpp @@ -57,7 +57,7 @@ TEST_CASE("value::operator==") { TEST_CASE("value::operator!=") { CHECK_FALSE(Value() != Value()); - + CHECK_FALSE(Value::minus_infty() != Value::minus_infty()); CHECK(Value::minus_infty() != Value(-20)); CHECK(Value::minus_infty() != Value(Integer(-15))); @@ -96,7 +96,7 @@ TEST_CASE("value::operator!=") { TEST_CASE("value::operator<") { CHECK_FALSE(Value() < Value()); - + CHECK_FALSE(Value::minus_infty() < Value::minus_infty()); CHECK(Value::minus_infty() < Value(-20)); CHECK(Value::minus_infty() < Value(Integer(-15))); @@ -135,7 +135,7 @@ TEST_CASE("value::operator<") { TEST_CASE("value::operator<=") { CHECK(Value() <= Value()); - + CHECK(Value::minus_infty() <= Value::minus_infty()); CHECK(Value::minus_infty() <= Value(-20)); CHECK(Value::minus_infty() <= Value(Integer(-15))); @@ -174,7 +174,7 @@ TEST_CASE("value::operator<=") { TEST_CASE("value::operator>") { CHECK_FALSE(Value() > Value()); - + CHECK_FALSE(Value::minus_infty() > Value::minus_infty()); CHECK_FALSE(Value::minus_infty() > Value(-20)); CHECK_FALSE(Value::minus_infty() > Value(Integer(-15))); @@ -213,7 +213,7 @@ TEST_CASE("value::operator>") { TEST_CASE("value::operator>=") { CHECK(Value() >= Value()); - + CHECK(Value::minus_infty() >= Value::minus_infty()); CHECK_FALSE(Value::minus_infty() >= Value(-20)); CHECK_FALSE(Value::minus_infty() >= Value(Integer(-15))); @@ -268,3 +268,10 @@ TEST_CASE("value::value_between") { CHECK(a < s); CHECK(s < b); } + +TEST_CASE("value::operator<<") { + Value v(-20); + std::stringstream out; + out << v; + CHECK(out.str() == "-20"); +} diff --git a/test/polyxx/test_variable.cpp b/test/polyxx/test_variable.cpp index 4c9a5bb4..82ffa9d8 100644 --- a/test/polyxx/test_variable.cpp +++ b/test/polyxx/test_variable.cpp @@ -15,4 +15,8 @@ TEST_CASE("variable") { CHECK_FALSE(v1 != v1); CHECK(v1 != v2); CHECK_FALSE(v2 != v2); -} \ No newline at end of file + + std::stringstream out; + out << v2; + CHECK(out.str() == "foo"); +}