test_that("unreferenced observers are garbage collected", {
  vals_removed <- FALSE
  obs_removed  <- FALSE
  vals <- reactiveValues(A=1)
  obs  <- observe({ vals$A })

  # These are called when the objects are garbage-collected
  reg.finalizer(.subset2(vals,'impl'), function(e) vals_removed <<- TRUE)
  reg.finalizer(obs, function(e) obs_removed  <<- TRUE)

  flushReact()

  # Removing this reference to obs doesn't delete it because vals still has a
  # reference to it
  rm(obs)
  invisible(gc())
  expect_equal(c(vals_removed, obs_removed), c(FALSE, FALSE))

  # Updating vals$A and flushing won't make obs go away because it creates a new
  # context, and vals$A's context tracks obs's context as a dependent
  vals$A <- 2
  flushReact()
  invisible(gc())
  expect_equal(c(vals_removed, obs_removed), c(FALSE, FALSE))

  # Removing vals will result in vals and obs being garbage collected since
  # there are no other references to them
  rm(vals)
  invisible(gc())
  expect_equal(c(vals_removed, obs_removed), c(TRUE, TRUE))
})


test_that("suspended observers are garbage collected", {
  vals_removed <- FALSE
  obs_removed  <- FALSE
  vals <- reactiveValues(A=1)
  obs  <- observe({ vals$A })

  # These are called when the objects are garbage-collected
  reg.finalizer(.subset2(vals,'impl'), function(e) vals_removed <<- TRUE)
  reg.finalizer(obs, function(e) obs_removed <<- TRUE)

  flushReact()

  vals$A <- 2
  flushReact()
  invisible(gc())

  # Simply suspending and removing our reference to obs doesn't result in GC,
  # because vals's context still has a reference to obs's context, as a dependent
  obs$suspend()
  rm(obs)
  invisible(gc())
  expect_equal(c(vals_removed, obs_removed), c(FALSE, FALSE))

  # Next time we update vals$A and flush, there's no more reference to obs
  vals$A <- 3
  flushReact()
  invisible(gc())
  expect_equal(c(vals_removed, obs_removed), c(FALSE, TRUE))

  # Deleting vals should work immediately now
  rm(vals)
  invisible(gc())  # Removes vals object
  expect_equal(c(vals_removed, obs_removed), c(TRUE, TRUE))
})
