
.write_mdl <- function(body, sketch = "") {
  path <- tempfile(fileext = ".mdl")
  writeLines(c("{UTF-8}", body, if (nzchar(sketch)) sketch else NULL), path)
  path
}

test_that("quoted variable names containing commas stay intact", {
  # "Climate (Temp, rainfall, etc.)" was split into three fake variables
  # because the argument tokenizer matched '[^,]+' before the quoted branch.
  mdl <- .write_mdl(paste(
    'Vegetation growth  = A FUNCTION OF( "Climate (Temp, rainfall, etc.)",Vegetation discrepency\\',
    '\t\t)',
    '\t~\t',
    '\t~\t\t|',
    '',
    '"Climate (Temp, rainfall, etc.)"  = A FUNCTION OF( )',
    '\t~\t',
    '\t~\t\t|',
    '',
    'Vegetation discrepency  = A FUNCTION OF( )',
    '\t~\t',
    '\t~\t\t|',
    sep = "\n"))

  el <- model_to_edgelist(mdl)
  nodes <- unique(c(el$INPUT, el$OUTPUT))

  expect_true("Climate (Temp, rainfall, etc.)" %in% nodes)
  # the three fragments the old tokenizer produced must NOT appear
  expect_false("Climate (Temp" %in% nodes)
  expect_false("rainfall" %in% nodes)
  expect_false("etc.)" %in% nodes)
  expect_equal(nrow(el[el$INPUT == "Climate (Temp, rainfall, etc.)", ]), 1L)
})

test_that("argument splitting handles the awkward cases", {
  split <- CLDedgelister:::.split_arguments
  expect_equal(split(' "A (x, y)",B'), c("A (x, y)", "B"))
  expect_equal(split(' "A, B","C, D",E'), c("A, B", "C, D", "E"))
  expect_equal(split(' A,B,C'), c("A", "B", "C"))
  expect_equal(split(' "Rural-urban migration",Time'),
               c("Rural-urban migration", "Time"))
  # an unterminated quote must degrade gracefully, not swallow the rest
  expect_equal(split(' "unterminated (oops,X'),
               c("unterminated (oops", "X"))
  expect_equal(split(''), character(0))
})

test_that("diagram legend arrows are removed whatever punctuation is used", {
  # Only "." was recognised before, so legends drawn with ",", ",,", "..",
  # "...." leaked into the edge list as real variables.
  anchor <- CLDedgelister:::.is_legend_anchor
  expect_true(anchor("."))
  expect_true(anchor(","))
  expect_true(anchor(",,"))
  expect_true(anchor("...."))
  expect_true(anchor("KEY"))
  expect_false(anchor("Food price"))
  expect_false(anchor("Climate (Temp, rainfall, etc.)"))
  expect_false(anchor("B12"))

  drop <- CLDedgelister:::.drop_legend_edges
  df <- data.frame(
    INPUT  = c("a", ",,", ",,,", "....", "Delay Mark"),
    OUTPUT = c("b", "..", "...", ",,,,", "."),
    stringsAsFactors = FALSE)
  kept <- drop(df)
  expect_equal(nrow(kept), 1L)
  expect_equal(kept$INPUT, "a")
})

test_that("full equations resolve quoted punctuated names", {
  # Models written with real equations rather than "A FUNCTION OF(...)"
  # produced NO edges at all from the equation section before.
  mdl <- .write_mdl(paste(
    '"Climate (Temp, rainfall, etc.)"= 5',
    '\t~\t',
    '\t~\t\t|',
    '',
    'Vegetation growth= "Climate (Temp, rainfall, etc.)" * 2 + "Rural-urban migration"',
    '\t~\t',
    '\t~\t\t|',
    '',
    '"Rural-urban migration"= 1',
    '\t~\t',
    '\t~\t\t|',
    sep = "\n"))

  el <- model_to_edgelist(mdl)
  expect_true(any(el$INPUT == "Climate (Temp, rainfall, etc.)" &
                  el$OUTPUT == "Vegetation growth"))
  expect_true(any(el$INPUT == "Rural-urban migration" &
                  el$OUTPUT == "Vegetation growth"))
})

test_that("control variables are never emitted as nodes", {
  mdl <- .write_mdl(paste(
    'Migration  = A FUNCTION OF( Population,Time)',
    '\t~\t',
    '\t~\t\t|',
    '',
    'Population  = A FUNCTION OF( )',
    '\t~\t',
    '\t~\t\t|',
    sep = "\n"))
  el <- model_to_edgelist(mdl)
  expect_false("Time" %in% c(el$INPUT, el$OUTPUT))
  expect_true(any(el$INPUT == "Population" & el$OUTPUT == "Migration"))
})

test_that("a self-referencing variable does not create a self-loop", {
  mdl <- .write_mdl(paste(
    'Stock  = A FUNCTION OF( Stock,Inflow)',
    '\t~\t',
    '\t~\t\t|',
    '',
    'Inflow  = A FUNCTION OF( )',
    '\t~\t',
    '\t~\t\t|',
    sep = "\n"))
  el <- model_to_edgelist(mdl)
  expect_equal(sum(el$INPUT == el$OUTPUT), 0L)
})

test_that("the edge list has no duplicate rows", {
  mdl <- system.file("extdata", "example_model.mdl",
                     package = "CLDedgelister")
  el <- model_to_edgelist(mdl)
  key <- paste(el$INPUT, el$OUTPUT, sep = "\r")
  expect_equal(anyDuplicated(key), 0L)
})

test_that("the bundled example exercises both regressions", {
  mdl <- system.file("extdata", "example_model.mdl",
                     package = "CLDedgelister")
  el <- model_to_edgelist(mdl)
  nodes <- unique(c(el$INPUT, el$OUTPUT))
  # a quoted, comma-bearing name survives as one variable
  expect_true("Climate (Temp, rainfall, etc.)" %in% nodes)
  expect_false("Climate (Temp" %in% nodes)
  # the legend pair drawn with ",," -> ".." is gone
  expect_false(any(grepl("^[[:punct:]]+$", nodes)))
})
