#include #include "cpp11/sexp.hpp" #include "cpp11/strings.hpp" #include context("strings-C++") { test_that("strings.push_back()") { cpp11::writable::strings x; x.push_back("a"); x.push_back("b"); expect_true(x.size() == 2); expect_true(x[0] == "a"); expect_true(x[1] == "b"); } test_that("strings.resize()") { cpp11::writable::strings x; x.resize(2); x[0] = "a"; x[1] = "b"; expect_true(x.size() == 2); expect_true(x[0] == "a"); expect_true(x[1] == "b"); } test_that("strings.at()") { cpp11::writable::strings x; expect_error(x.at(-1)); expect_error(x.at(0)); x.push_back("a"); auto test = x.at(0); expect_true(test == "a"); expect_error(x.at(1)); } test_that("strings.pop_back()") { cpp11::writable::strings x; x.push_back("a"); x.push_back("b"); x.pop_back(); expect_true(x.size() == 1); expect_true(x[0] == "a"); expect_error(x.at(1)); } test_that("strings.insert()") { cpp11::writable::strings x; x.insert(0, "a"); x.insert(0, "b"); x.insert(1, "c"); expect_true(x.size() == 3); expect_true(x[0] == "b"); expect_true(x[1] == "c"); expect_true(x[2] == "a"); } test_that("strings.erase()") { cpp11::writable::strings x; x.push_back("a"); x.push_back("b"); x.push_back("c"); x.push_back("d"); x.push_back("e"); expect_true(x.size() == 5); x.erase(0); expect_true(x.size() == 4); expect_true(x[0] == "b"); expect_true(x[1] == "c"); expect_true(x[2] == "d"); expect_true(x[3] == "e"); x.erase(2); expect_true(x.size() == 3); expect_true(x[0] == "b"); expect_true(x[1] == "c"); expect_true(x[2] == "e"); } test_that("strings.iterator* = ") { cpp11::writable::strings x; x.push_back("a"); x.push_back("b"); x.push_back("c"); auto it = x.begin() + 1; *it = "d"; ++it; *it = "e"; expect_true(x.size() == 3); expect_true(x[0] == "a"); expect_true(x[1] == "d"); expect_true(x[2] == "e"); } test_that("writable::strings(SEXP)") { SEXP x = PROTECT(Rf_allocVector(STRSXP, 5)); SET_STRING_ELT(x, 0, Rf_mkCharCE("a", CE_UTF8)); SET_STRING_ELT(x, 1, Rf_mkCharCE("b", CE_UTF8)); SET_STRING_ELT(x, 2, Rf_mkCharCE("c", CE_UTF8)); SET_STRING_ELT(x, 3, Rf_mkCharCE("d", CE_UTF8)); SET_STRING_ELT(x, 4, Rf_mkCharCE("e", CE_UTF8)); cpp11::writable::strings y(x); y[0] = "foo"; expect_true(x != y.data()); expect_true(std::string(CHAR(STRING_ELT(x, 0))) == "a"); expect_true(y[0] == "foo"); cpp11::writable::strings z(y); z[0] = "bar"; expect_true(z.data() != y.data()); expect_true(std::string(CHAR(STRING_ELT(x, 0))) == "a"); expect_true(y[0] == "foo"); expect_true(z[0] == "bar"); UNPROTECT(1); } test_that("writable::strings(initializer_list)") { using namespace cpp11::literals; SEXP x1 = PROTECT(Rf_allocVector(STRSXP, 1)); SEXP x2 = PROTECT(Rf_allocVector(STRSXP, 1)); SEXP x3 = PROTECT(Rf_allocVector(STRSXP, 1)); SEXP one = PROTECT(Rf_mkCharCE("one", CE_UTF8)); SEXP two = PROTECT(Rf_mkCharCE("two", CE_UTF8)); SEXP three = PROTECT(Rf_mkCharCE("three", CE_UTF8)); SET_STRING_ELT(x1, 0, one); SET_STRING_ELT(x2, 0, two); SET_STRING_ELT(x3, 0, three); // From scalar string vectors cpp11::writable::strings x({"one"_nm = x1, "two"_nm = x2, "three"_nm = x3}); expect_true(x.named()); expect_true(x["one"] == cpp11::r_string("one")); expect_true(x["two"] == cpp11::r_string("two")); expect_true(x["three"] == cpp11::r_string("three")); // From strings cpp11::writable::strings y( {"one"_nm = "one", "two"_nm = "two", "three"_nm = "three"}); expect_true(y.named()); expect_true(y["one"] == cpp11::r_string("one")); expect_true(y["two"] == cpp11::r_string("two")); expect_true(y["three"] == cpp11::r_string("three")); UNPROTECT(6); } test_that("writable::strings(initializer_list) type check") { using namespace cpp11::literals; expect_error_as(cpp11::writable::strings({"one"_nm = true}), cpp11::type_error); expect_error_as(cpp11::writable::strings({"one"_nm = R_NilValue}), cpp11::type_error); } test_that("writable::strings(initializer_list) length check") { using namespace cpp11::literals; SEXP x = PROTECT(Rf_allocVector(STRSXP, 2)); expect_error_as(cpp11::writable::strings({"x"_nm = x}), std::length_error); UNPROTECT(1); } test_that("writable::strings(initializer_list)") { cpp11::r_string abc = cpp11::r_string("abc"); cpp11::r_string na = cpp11::r_string(NA_STRING); cpp11::writable::strings x({abc, na, abc}); expect_true(x[0] == abc); expect_true(x[1] == na); expect_true(x[2] == abc); // This works due to implicit conversion of `SEXP` to `r_string` SEXP a = PROTECT(Rf_mkCharCE("a", CE_UTF8)); SEXP b = PROTECT(Rf_mkCharCE("b", CE_UTF8)); cpp11::writable::strings y({a, b}); expect_true(y[0] == cpp11::r_string("a")); expect_true(y[1] == cpp11::r_string("b")); // This works due to implicit conversion of `const char*` to `r_string` cpp11::writable::strings z({"neat", "stuff"}); expect_true(z[0] == cpp11::r_string("neat")); expect_true(z[1] == cpp11::r_string("stuff")); cpp11::writable::strings w({std::string("neat"), std::string("stuff")}); expect_true(w[0] == cpp11::r_string("neat")); expect_true(w[1] == cpp11::r_string("stuff")); UNPROTECT(2); } test_that("std::initializer_list") { cpp11::writable::strings x{"foo"}; expect_true(x.size() == 1); expect_true(x[0] == "foo"); } test_that("std::initializer_list") { std::string str("foo"); cpp11::writable::strings x{str}; expect_true(x.size() == 1); expect_true(x[0] == "foo"); } test_that("NA_STRING constructor") { cpp11::writable::strings x({NA_STRING}); expect_true(x.size() == 1); expect_true(x[0] == NA_STRING); cpp11::writable::strings y({NA_STRING, "foo"}); expect_true(y.size() == 2); expect_true(y[0] == NA_STRING); expect_true(y[1] == "foo"); } test_that("CHARSXP move constructor") { SEXP x = PROTECT(Rf_mkChar("foo")); cpp11::writable::strings y(std::move(x)); expect_true(y.size() == 1); expect_true(y[0] == "foo"); UNPROTECT(1); } // test_that("strings::operator=() and strings::at() do not compile") { // cpp11::strings x(Rf_mkChar("foo")); // x[0] = "bar"; // x.at(0) = "bar"; //} test_that("strings::operator=() and strings::at() do compile") { cpp11::writable::strings x(Rf_mkChar("foo")); x[0] = "bar"; x.at(0) = "bar"; } test_that("strings::operator=() works with std:strings") { cpp11::writable::strings x(Rf_mkChar("foo")); std::string y("bar"); x[0] = y; expect_true(x[0] == y); } test_that("conversion to SEXP with missing values") { cpp11::sexp x1 = cpp11::r_string(NA_STRING); expect_true(static_cast(x1) == NA_STRING); cpp11::sexp x2 = cpp11::writable::strings(NA_STRING); expect_true(Rf_xlength(x2) == 1); expect_true(STRING_ELT(x2, 0) == NA_STRING); cpp11::sexp x3 = cpp11::writable::strings({NA_STRING}); expect_true(Rf_xlength(x3) == 1); expect_true(STRING_ELT(x3, 0) == NA_STRING); cpp11::sexp x4 = cpp11::writable::strings({NA_STRING, "text"}); expect_true(Rf_xlength(x4) == 2); expect_true(STRING_ELT(x4, 0) == NA_STRING); expect_true(strcmp(CHAR(STRING_ELT(x4, 1)), "text") == 0); } }