source(file.path("_helper", "init.R"))
source(file.path("aammrtf", "ref.R")); make_ref_obj_funs("refobjs")

txt <- "# This is an early comment\n\n  hello <- 25\n\n  # multi\n  # line\n  # comment\n\n  matrix(1:9, 3)  # and another!\n\n  unitizer_sect(\"here is a section\", {\n    # test that were not crazy\n\n    1 + 1 == 2   # TRUE hopefully\n\n    # Still not crazy\n\n    2 * 2 == 2 ^ 2\n    # Tada\n  } )\n  sample(1:10)\n\n  # and this comment belongs to whom?\n\n  runif(20)\n  print(\"woo\")  # and I?\n  "
all <- unitizer:::parse_dat_get(text = txt)
prs <- all$expr
dat <- all$dat
dat$parent <- pmax(0L, dat$parent)
# With R4.0 some of the ids started changing
normalize_id <- function(dat) {
    idu <- sort(unique(dat[["id"]]))
    id <- with(dat, match(id, idu))
    parent <- with(dat, ifelse(parent == 0L, 0L, match(parent, 
        idu)))
    dat[["id"]] <- id
    dat[["parent"]] <- parent
    dat
}
dat <- normalize_id(dat)
dat.split <- dat.split.2 <- par.ids.3 <- NULL
if.text <- "if # IFFY\n(x > 3 # ifcond\n){ hello\n #whome to attach?\n} else #final\ngoodbye"

# - "Top Level Parents Identified Correctly" -----------------------------------

# "Identified top level parents?"
par.ids <- with(dat, unitizer:::top_level_parse_parents(id, parent))
par.ids
dat.split <- split(dat, par.ids)

# "Identified sub-level top level parents correctly"
par.ids.2 <- with(dat.split$`64`, unitizer:::top_level_parse_parents(id, 
    parent, 64L))
par.ids.2
dat.split.2 <- split(dat.split$`64`, par.ids.2)

# "Parent relationships in `unitizer_sect` piece."

par.ids.3 <- with(dat.split.2$`62`, unitizer:::top_level_parse_parents(id, 
    parent, 62L))
par.ids.3

# - "Comments Are Assigned" ----------------------------------------------------

# "Did we assign comments correctly to topmost level?"
lapply(unitizer:::comments_assign(prs, dat.split$`0`), attr, "comment")

# "No comments here so no changes should occur"
all.equal(unitizer:::comments_assign(prs[[3]], dat.split.2$`64`), prs[[3]])

# "Comments in `unitizer_sect` body assigned correctly"
lapply(unitizer:::comments_assign(prs[[3]][[3]], split(dat.split.2$`62`, 
    par.ids.3)$`62`), attr, "comment")

# - "Ancestry Descend" ---------------------------------------------------------

x <- unitizer:::parse_dat_get(text = "1 + 1; fun(x, fun(y + z))")$dat
x <- normalize_id(x)

unitizer:::ancestry_descend(x$id, x$parent, 0)

# - "Clean up Parse Data" ------------------------------------------------------

dat <- unitizer:::parse_dat_get(text = "{function(x) NULL;; #comment\n}")$dat
# set negative ids to be top level parents
dat <- transform(dat, parent = ifelse(parent < 0, 0L, parent))
dat <- normalize_id(dat)

# "Ancestry Descend"
dat.anc <- unitizer:::ancestry_descend(dat$id, dat$parent, 0L)
dat.anc

# "Excise `exprlist`"
unitizer:::prsdat_fix_exprlist(dat, dat.anc)$token

dat.1 <- unitizer:::parse_dat_get(text = "{1 ; ; ;2;}")$dat
# set negative ids to be top level parents
dat.1 <- transform(dat.1, parent = ifelse(parent < 0, 0L, parent))
dat.1 <- normalize_id(dat.1)

# "Another `exprlist` test"
unname(
  as.list(
    unitizer:::prsdat_fix_exprlist(
      dat.1, 
      unitizer:::ancestry_descend(dat.1$id, dat.1$parent, 0L)
    )[c("parent", "token")]
) )
dat.2 <- unitizer:::parse_dat_get(text = "{NULL; yowza; #comment\nhello\n}")$dat
# set negative ids to be top level parents
dat.2 <- transform(dat.2, parent = ifelse(parent < 0, 0L, parent))
dat.2 <- normalize_id(dat.2)

# "Yet another `exprlist`"
unname(
  as.list(
    unitizer:::prsdat_fix_exprlist(
      dat.2, unitizer:::ancestry_descend(dat.2$id, dat.2$parent, 0L)
    )[c("parent", "token")]
) )

dat.2a <- normalize_id(
  unitizer:::parse_dat_get(text = "for(i in x) {if(x) break else next}")$dat
)
# "`for` cleanup"

as.list(unitizer:::prsdat_fix_for(dat.2a[-1L, ]))

dat.3 <- normalize_id(unitizer:::parse_dat_get(text = if.text)$dat)

# "`if` cleanup"

unname(as.list(unitizer:::prsdat_fix_if(dat.3[-1, ])[c("id", "token")]))

# - "Full Parse Works Properly" ------------------------------------------------

# "Full Comment Parse"
unitizer:::comm_extract(unitizer:::parse_with_comments(text = txt))

# "EQ_SUB and SYMBOL_SUB test"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "structure(1:3, # the data\nclass # the label\n=#the equal sign\n'hello' # the class\n)"
) )

# "Function with `exprlist`"

unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "function(x #first arg\n, y=25 #second arg with default\n) {x + y; # first comment\n; yo #second comment\n x / y; #lastcomment \n;}"
) )

# "`for` loop"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "for(i #in counter\nin 1:10#incounter again\n) {x + y; # first comment\n; next; yo #second comment\n x / y; break; #lastcomment \n;}"
) )

# "`if` statement"
unitizer:::comm_extract(unitizer:::parse_with_comments(text = if.text))

# "formula"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = ". + x # hello\n#yowza\n~#bust a move\ny"
) )

# "`repeat`"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "repeat #first\n{runif(10); #comm\nbreak;}"
) )

# "S4 slot"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(text = "test@#comment\nhello <- 3")
)

#  "`while`"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "while(x > 5 # a comment\n) { hello; goodbye } #yay"
) )

txt2 <- "library(functools)\n    fun <- function(a=1, bravo, card=25, ..., xar=list(\"aurochs\", 1), z) {}\n\n    # Need to add tests:\n    # - with complex objects? (did I mean in the definition? Or the call??)\n    (NULL)\n    # These should be identical to match.call()\n\n    body(fun) <- parse(text=\"{print(match_call()); print(match.call())}\")\n\n    calls <- c(\n      'fun(54, \"hello\", \"wowo\", \"blergh\", 8, 9)',\n      'fun(54, \"hello\", \"wowo\", \"blergh\", a=8, z=9)',\n      'fun(54, \"hello\", z=\"wowo\", \"blergh\", 8, 9)',\n      'fun(54, \"hello\", z=\"wowo\", x=\"blergh\", 8, 9)',\n      'fun(54, c=\"hello\", z=\"wowo\", xar=3, 8, 9)'\n    )\n    invisible(lapply(calls, function(x){cat(\"-- New Call --\", x, sep=\"\n\"); eval(parse(text=x))}))\n  "
test.comp <- unitizer:::comm_extract(unitizer:::parse_with_comments(text = txt2))

# "A more complex test"
lapply(test.comp[4:5], `[[`, 1)

# "Added SYMBOL_PACKAGE token"
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "# a comment before\nunitizer:::browse()  #a comment after"
) )
# "Added SYMBOL_PACKAGE token v2" 
unitizer:::comm_extract(
  unitizer:::parse_with_comments(
    text = "# a comment before\nunitizer::browse()  #a comment after"
) )
# LBB used to break stuff
txt3 <- "# This is an early comment\n    hello <- 25\n    # multi\n    hello[[1]]  # and another!"
# "LBB test"
unitizer:::comm_extract(unitizer:::parse_with_comments(text = txt3))

# - "Weird missing comment on `res` works" -------------------------------------

txt3 <- "# Calls to `library` and assignments are not normally considered tests, so\n# you will not be prompted to review them\n\nlibrary(utzflm)\nx <- 1:100\ny <- x ^ 2\nres <- fastlm(x, y)\n\nres                     # first reviewable expression\nget_slope(res)\nget_rsq(res)\n\nfastlm(x, head(y))      # This should cause an error; press Y to add to store"
expr <- unitizer:::parse_with_comments(text = txt3)
my.unitizer <- new("unitizer", id = 1, zero.env = new.env())
capture.output(my.unitizer <- my.unitizer + expr)

lapply(unitizer:::as.list(my.unitizer@items.new), slot, "comment")

# - "exprlist excission with negative par ids" ---------------------------------

txt <- "# For random tests\n\nunitizer_sect(\"blah\", {\n  identity(1);\n})\n"
prs.dat <- unitizer:::parse_dat_get(text = txt)$dat
# set negative ids to be top level parents
prs.dat <- transform(prs.dat, parent = ifelse(parent < 0, 0L, 
    parent))
prs.dat <- normalize_id(prs.dat)
ancestry <- with(prs.dat, unitizer:::ancestry_descend(id, parent, 
    0L))
x <- unitizer:::prsdat_fix_exprlist(prs.dat, ancestry)
unname(as.matrix(x[, 5:6]))

# - "empty symbols handled okay" -----------------------------------------------

# the empty second argument to `[` caused problems before
txt <- "mtcars[1:10,]\n"
# shouldn't cause error
unitizer:::parse_with_comments(text = txt)

# - "uncommenting works" -------------------------------------------------------

unitizer:::uncomment(expr[[1]])

# "don't blow away function arg names"
unitizer:::uncomment(quote(function(a, b) NULL))
#
# Recover comments and uncomment
txt <- ".alike(  # FALSE, match.call disabled\n  quote(fun(b=fun2(x, y), 1, 3)),  # first sub.call\n  quote(fun(NULL, fun2(a, b), 1)), # second sub.call\n  alike_settings(lang.mode=1))"
exp <- unitizer:::parse_with_comments(text = txt)
candc <- unitizer:::comm_and_call_extract(exp)

candc$call[[1L]]

candc$comments

# - "failing parses produce proper errors" -------------------------------------

txt <- "this is a + syntax error that cannot be parsed"
try(capture.output(unitizer:::parse_tests(text = txt), type = "message"))
f <- tempfile()
on.exit(unlink(f))
cat(txt, "\n", sep = "", file = f)
try(capture.output(unitizer:::parse_tests(f), type = "message"))
# try in normal mode (just fall back to normal parse)
try(unitizer:::parse_tests(text = txt, comments = FALSE))

any(
  grepl(
    "unexpected symbol",
    capture.output(try(unitizer:::parse_tests(f, comments = FALSE)), type='message'),
) )

# - "NULL, constants, and new tokens" ------------------------------------------

# These were added with 3.6.3?  Previously, it seems that the equal assign did
# not generate a master expression to wrap all the pieces, which means these
# tests just don't work because all the eq_assign at the top level end up with
# the same parent and the parser gets confused.

txt <- c("a = 2", "# ho how", "b = 3", "", "b + a  # oh here", 
    "", "b + # oh there", "a   # bear", "", "NULL")
if(getRversion() >= "3.6.3") {
  identical(
    unitizer:::comm_extract(unitizer:::parse_with_comments(text = txt)),
    rds('parse-eq')
  )
} else TRUE

with.const <- unitizer:::parse_with_comments(text = "3 # comment on const")
unitizer:::symb_mark_rem(with.const[[1]])

