diff --git a/R/versions.R b/R/versions.R index 17090ae02ec..87779d45fa0 100644 --- a/R/versions.R +++ b/R/versions.R @@ -22,7 +22,7 @@ ## ## ---------------------------------------------------------------------- -pkg_graph_version <- "0.8.0" +pkg_graph_version <- "1.5.0" pkg_graph_version_obj <- as.package_version(pkg_graph_version) @@ -96,7 +96,20 @@ upgrade_graph <- function(graph) { if (g_ver == "0.4.0") { .Call(R_igraph_add_env, graph) } else if (g_ver == "0.7.999") { + # Not observed in the wild + .Call(R_igraph_add_myid_to_env, graph) .Call(R_igraph_add_version_to_env, graph) + } else if (g_ver == "0.8.0") { + .Call(R_igraph_add_version_to_env, graph) + graph <- unclass(graph) + graph[igraph_t_idx_oi:igraph_t_idx_is] <- list(NULL) + class(graph) <- "igraph" + + # Calling for side effect: error if R_SEXP_to_igraph() fails, create native igraph, + # update "me" element of environment + V(graph) + + graph } else { stop("Don't know how to upgrade graph from ", g_ver, " to ", p_ver) } @@ -122,6 +135,17 @@ warn_version <- function(graph) { " Call upgrade_graph() on it to use with the current igraph version\n", " For now we convert it on the fly..." ) + + # In-place upgrade: + # - The igraph element in the igraph_t_idx_env component will be added + # transparently because it's missing. + # - The components igraph_t_idx_oi, igraph_t_idx_ii, igraph_t_idx_os, + # igraph_t_idx_is are ignored, but we can't do much about the contents. + # Users will have to call upgrade_graph(), but this is what the message + # is about. + if (pkg_graph_version <= "1.5.0") { + .Call(R_igraph_add_version_to_env, graph) + } return(TRUE) } @@ -149,3 +173,9 @@ oldsamples <- function() { "0.1.1" = oldsample_0_1_1() ) } + +clear_native_ptr <- function(g) { + gx <- unclass(g) + gx[[igraph_t_idx_env]]$igraph <- NULL + g +} diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 4878ba5e4e9..f7a41348fa0 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -17,6 +17,7 @@ extern "C" { /* .Call calls */ extern SEXP R_igraph_add_edges(SEXP, SEXP); extern SEXP R_igraph_add_env(SEXP); +extern SEXP R_igraph_add_myid_to_env(SEXP); extern SEXP R_igraph_add_version_to_env(SEXP); extern SEXP R_igraph_add_vertices(SEXP, SEXP); extern SEXP R_igraph_address(SEXP); @@ -398,6 +399,7 @@ extern SEXP promise_expr_(SEXP); static const R_CallMethodDef CallEntries[] = { {"R_igraph_add_edges", (DL_FUNC) &R_igraph_add_edges, 2}, {"R_igraph_add_env", (DL_FUNC) &R_igraph_add_env, 1}, + {"R_igraph_add_myid_to_env", (DL_FUNC) &R_igraph_add_myid_to_env, 1}, {"R_igraph_add_version_to_env", (DL_FUNC) &R_igraph_add_version_to_env, 1}, {"R_igraph_add_vertices", (DL_FUNC) &R_igraph_add_vertices, 2}, {"R_igraph_address", (DL_FUNC) &R_igraph_address, 1}, diff --git a/src/rinterface.h b/src/rinterface.h index 8117872f9ef..08547677dea 100644 --- a/src/rinterface.h +++ b/src/rinterface.h @@ -25,7 +25,7 @@ #include "uuid/uuid.h" -#define R_IGRAPH_TYPE_VERSION "0.8.0" +#define R_IGRAPH_TYPE_VERSION "1.5.0" #define R_IGRAPH_VERSION_VAR ".__igraph_version__." SEXP R_igraph_add_env(SEXP graph); diff --git a/src/rinterface_extra.c b/src/rinterface_extra.c index 84d943a791f..2f91a6b73c9 100644 --- a/src/rinterface_extra.c +++ b/src/rinterface_extra.c @@ -2986,6 +2986,9 @@ void R_igraph_restore_pointer(SEXP graph) { igraph_t *R_igraph_get_pointer(SEXP graph) { if (GET_LENGTH(graph) != igraph_t_idx_max || !Rf_isEnvironment(R_igraph_graph_env(graph))) { + if (GET_LENGTH(graph) == 11) { + Rf_error("This graph was created by igraph < 0.2.\n Upgrading this format is not supported, sorry."); + } Rf_error("This graph was created by a now unsupported old igraph version.\n Call upgrade_version() before using igraph functions on that object."); } @@ -9945,7 +9948,9 @@ SEXP R_igraph_identical_graphs(SEXP g1, SEXP g2, SEXP attrs) { } SEXP R_igraph_graph_version(SEXP graph) { - if (GET_LENGTH(graph) == igraph_t_idx_max && Rf_isEnvironment(R_igraph_graph_env(graph))) { + if (GET_LENGTH(graph) == 11) { + return Rf_mkString("0.1.1"); + } else if (GET_LENGTH(graph) == igraph_t_idx_max && Rf_isEnvironment(R_igraph_graph_env(graph))) { SEXP ver = Rf_findVar(Rf_install(R_IGRAPH_VERSION_VAR), R_igraph_graph_env(graph)); if (ver != R_UnboundValue) { return ver; @@ -9957,24 +9962,26 @@ SEXP R_igraph_graph_version(SEXP graph) { } } -SEXP R_igraph_add_version_to_env(SEXP graph) { +SEXP R_igraph_add_myid_to_env(SEXP graph) { uuid_t my_id; char my_id_chr[40]; - PROTECT(graph = Rf_duplicate(graph)); - uuid_generate(my_id); uuid_unparse_lower(my_id, my_id_chr); SEXP l1 = PROTECT(Rf_install("myid")); SEXP l2 = PROTECT(Rf_mkString(my_id_chr)); Rf_defineVar(l1, l2, R_igraph_graph_env(graph)); UNPROTECT(2); - l1 = PROTECT(Rf_install(R_IGRAPH_VERSION_VAR)); - l2 = PROTECT(Rf_mkString(R_IGRAPH_TYPE_VERSION)); + + return graph; +} + +SEXP R_igraph_add_version_to_env(SEXP graph) { + SEXP l1 = PROTECT(Rf_install(R_IGRAPH_VERSION_VAR)); + SEXP l2 = PROTECT(Rf_mkString(R_IGRAPH_TYPE_VERSION)); Rf_defineVar(l1, l2, R_igraph_graph_env(graph)); UNPROTECT(2); - UNPROTECT(1); return graph; } diff --git a/tests/testthat/_snaps/versions.md b/tests/testthat/_snaps/versions.md index 09044316cbd..223c08c52e7 100644 --- a/tests/testthat/_snaps/versions.md +++ b/tests/testthat/_snaps/versions.md @@ -1,11 +1,73 @@ -# reading of old igraph formats +# we can't upgrade from 0.1.1 to 1.5.0, on the fly Code - s[["0.1.1"]] + oldsample_0_1_1() + Error + This graph was created by igraph < 0.2. + Upgrading this format is not supported, sorry. + +# we can't upgrade from 0.1.1 to 1.5.0, explicitly + + Code + upgrade_graph(g) + Error + Don't know how to upgrade graph from 0.1.1 to 1.5.0 + +# we can't upgrade from 0.2 to 1.5.0, on the fly + + Code + oldsample_0_2() Error This graph was created by a now unsupported old igraph version. Call upgrade_version() before using igraph functions on that object. +# we can't upgrade from 0.5 to 1.5.0, on the fly + + Code + oldsample_0_5() + Error + This graph was created by a now unsupported old igraph version. + Call upgrade_version() before using igraph functions on that object. + +# we can't upgrade from 0.6 to 1.5.0, on the fly + + Code + oldsample_0_6() + Error + This graph was created by a now unsupported old igraph version. + Call upgrade_version() before using igraph functions on that object. + +# we can upgrade from 1.0.0 to 1.5.0, on the fly + + Code + g <- oldsample_1_0_0() + graph_version(g) + Output + [1] '0.8.0' + Code + g + Message + This graph was created by an old(er) igraph version. + Call upgrade_graph() on it to use with the current igraph version + For now we convert it on the fly... + Output + IGRAPH D--- 3 3 -- Ring graph + + attr: name (g/c), mutual (g/l), circular (g/l), bar (v/c), foo (e/c) + + edges: + [1] 1->2 2->3 3->1 + Code + graph_version(g) + Output + [1] '1.5.0' + +# reading of old igraph formats + + Code + s[["0.1.1"]] + Error + This graph was created by igraph < 0.2. + Upgrading this format is not supported, sorry. + --- Code @@ -34,6 +96,10 @@ Code s[["1.0.0"]] + Message + This graph was created by an old(er) igraph version. + Call upgrade_graph() on it to use with the current igraph version + For now we convert it on the fly... Output IGRAPH D--- 3 3 -- Ring graph + attr: name (g/c), mutual (g/l), circular (g/l), bar (v/c), foo (e/c) @@ -44,6 +110,9 @@ Code s[["1.5.0"]] - Error - This graph was created by a new(er) igraph version. Please install the latest version of igraph and try again. + Output + IGRAPH D--- 3 3 -- Ring graph + + attr: name (g/c), mutual (g/l), circular (g/l), bar (v/c), foo (e/c) + + edges: + [1] 1->2 2->3 3->1 diff --git a/tests/testthat/test-versions.R b/tests/testthat/test-versions.R index 97b93212587..b9d038f0f26 100644 --- a/tests/testthat/test-versions.R +++ b/tests/testthat/test-versions.R @@ -5,16 +5,90 @@ test_that("we create graphs of the current version", { expect_equal(v1, v2) }) -test_that("we can upgrade from 0.4.0 to 0.8.0", { - g <- make_ring(10) - g <- unclass(g) - g[[10]] <- NULL - class(g) <- "igraph" +test_that("we can't upgrade from 0.1.1 to 1.5.0, on the fly", { + expect_snapshot(error = TRUE, { + oldsample_0_1_1() + }) +}) + +test_that("we can't upgrade from 0.1.1 to 1.5.0, explicitly", { + g <- oldsample_0_1_1() + + expect_equal(graph_version(g), as.package_version("0.1.1")) + + expect_snapshot(error = TRUE, { + upgrade_graph(g) + }) +}) + +test_that("we can't upgrade from 0.2 to 1.5.0, on the fly", { + expect_snapshot(error = TRUE, { + oldsample_0_2() + }) +}) + +test_that("we can upgrade from 0.2 to 1.5.0, explicitly", { + g <- oldsample_0_2() + + expect_equal(graph_version(g), as.package_version("0.4.0")) + + g2 <- upgrade_graph(g) + expect_equal(graph_version(g2), as.package_version("1.5.0")) +}) + +test_that("we can't upgrade from 0.5 to 1.5.0, on the fly", { + expect_snapshot(error = TRUE, { + oldsample_0_5() + }) +}) + +test_that("we can upgrade from 0.5 to 1.5.0, explicitly", { + g <- oldsample_0_5() + + expect_equal(graph_version(g), as.package_version("0.4.0")) + + g2 <- upgrade_graph(g) + expect_equal(graph_version(g2), as.package_version("1.5.0")) +}) + +test_that("we can't upgrade from 0.6 to 1.5.0, on the fly", { + expect_snapshot(error = TRUE, { + oldsample_0_6() + }) +}) + +test_that("we can upgrade from 0.6 to 1.5.0, explicitly", { + g <- oldsample_0_6() expect_equal(graph_version(g), as.package_version("0.4.0")) g2 <- upgrade_graph(g) - expect_equal(graph_version(g2), as.package_version("0.8.0")) + expect_equal(graph_version(g2), as.package_version("1.5.0")) +}) + +test_that("we can upgrade from 1.0.0 to 1.5.0, on the fly", { + local_igraph_options(print.id = FALSE) + + expect_snapshot({ + g <- oldsample_1_0_0() + graph_version(g) + g + graph_version(g) + }) +}) + +test_that("we can upgrade from 1.0.0 to 1.5.0, explicitly", { + g <- oldsample_1_0_0() + graph_version(g) + g2 <- upgrade_graph(g) + graph_version(g2) + + g3 <- oldsample_1_5_0() + + expect_identical( + unclass(clear_native_ptr(g2)), + unclass(clear_native_ptr(g3)) + ) }) test_that("reading of old igraph formats", { @@ -36,7 +110,7 @@ test_that("reading of old igraph formats", { expect_snapshot({ s[["1.0.0"]] }) - expect_snapshot(error = TRUE, { + expect_snapshot({ s[["1.5.0"]] }) })