Nothing
# Tests for reader/tokenizer edge cases
# Covers unicode, partial input, numeric edge cases, escape sequences
thin <- make_cran_thinner()
test_that("unicode characters in symbols", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Should handle unicode in symbols
result <- engine$eval_text("(define café 42)")
expect_no_error(result)
result <- engine$eval_text("café")
expect_equal(result, 42)
})
test_that("unicode in strings", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text('"Hello 世界"')
expect_equal(result, "Hello 世界")
result <- engine$eval_text('"Emoji: 🎉"')
expect_equal(result, "Emoji: 🎉")
})
test_that("escape sequences in strings", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text('"Hello\\nWorld"')
expect_equal(result, "Hello\nWorld")
result <- engine$eval_text('"Tab\\there"')
expect_equal(result, "Tab\there")
result <- engine$eval_text('"Quote: \\"test\\""')
expect_equal(result, 'Quote: "test"')
result <- engine$eval_text('"Backslash: \\\\"')
expect_equal(result, "Backslash: \\")
})
test_that("numeric literals - integers", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text("42")
expect_equal(result, 42)
result <- engine$eval_text("-17")
expect_equal(result, -17)
result <- engine$eval_text("0")
expect_equal(result, 0)
})
test_that("numeric literals - floats", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text("3.14")
expect_equal(result, 3.14)
result <- engine$eval_text("-2.5")
expect_equal(result, -2.5)
result <- engine$eval_text("0.0")
expect_equal(result, 0.0)
})
test_that("numeric literals - scientific notation", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Basic scientific notation
result <- engine$eval_text("1e5")
expect_equal(result, 1e5)
result <- engine$eval_text("2.5e3")
expect_equal(result, 2.5e3)
# Uppercase E
result <- engine$eval_text("1E5")
expect_equal(result, 1E5)
# Negative exponents
result <- engine$eval_text("1e-5")
expect_equal(result, 1e-5)
result <- engine$eval_text("3.14e-2")
expect_equal(result, 3.14e-2)
# Positive exponents with explicit sign
result <- engine$eval_text("1e+5")
expect_equal(result, 1e+5)
# Negative numbers with scientific notation
result <- engine$eval_text("-2.5e3")
expect_equal(result, -2.5e3)
result <- engine$eval_text("-1e-5")
expect_equal(result, -1e-5)
result <- engine$eval_text("-3.14e+10")
expect_equal(result, -3.14e+10)
# Zero with exponents
result <- engine$eval_text("0e0")
expect_equal(result, 0)
result <- engine$eval_text("0.0e10")
expect_equal(result, 0)
result <- engine$eval_text("0e-5")
expect_equal(result, 0)
# Integer part with exponent (no decimal)
result <- engine$eval_text("123e2")
expect_equal(result, 123e2)
# Decimal without integer part is not valid in standard notation,
# but our regex requires at least one digit before optional decimal
result <- engine$eval_text("5.0e0")
expect_equal(result, 5.0)
# Works in expressions
result <- engine$eval_text("(+ 1e2 2e2)")
expect_equal(result, 300)
result <- engine$eval_text("(* 2e3 3e2)")
expect_equal(result, 2e3 * 3e2)
})
test_that("scientific notation - more edge cases", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Multiple digit exponents
result <- engine$eval_text("1e10")
expect_equal(result, 1e10)
result <- engine$eval_text("1e100")
expect_equal(result, 1e100)
result <- engine$eval_text("1e-10")
expect_equal(result, 1e-10)
# Negative base with various exponents
result <- engine$eval_text("-1e0")
expect_equal(result, -1)
result <- engine$eval_text("-9.99e99")
expect_equal(result, -9.99e99)
result <- engine$eval_text("-1.23e-45")
expect_equal(result, -1.23e-45)
# Positive sign on base
result <- engine$eval_text("+1e5")
expect_equal(result, 1e5)
result <- engine$eval_text("+2.5e-3")
expect_equal(result, 2.5e-3)
})
test_that("scientific notation - invalid formats treated as symbols", {
thin()
engine <- make_engine(load_prelude = FALSE)
# These should be parsed as symbols, not numbers
# Missing exponent digits (e with no digits after)
# This will be tokenized as two separate tokens or fail
expect_error(engine$eval_text("1e"))
# Double e
expect_error(engine$eval_text("1ee5"))
# Decimal in exponent
expect_error(engine$eval_text("1e5.5"))
# Space in scientific notation
expect_error(engine$eval_text("1e 5"))
# Multiple signs
expect_error(engine$eval_text("1e+-5"))
expect_error(engine$eval_text("1e++5"))
})
test_that("numeric edge cases - very large numbers", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Very large numbers using scientific notation
result <- engine$eval_text("1e100")
expect_equal(result, 1e100)
result <- engine$eval_text("9.99e307")
expect_equal(result, 9.99e307)
# Avogadro's number
result <- engine$eval_text("6.022e23")
expect_equal(result, 6.022e23)
# Should work in arithmetic
result <- engine$eval_text("(+ 1e10 1e10)")
expect_equal(result, 2e10)
# Comparisons
result <- engine$eval_text("(> 1e100 1e99)")
expect_equal(result, TRUE)
result <- engine$eval_text("(< 1e100 1e101)")
expect_equal(result, TRUE)
})
test_that("numeric edge cases - very small numbers", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Very small numbers using scientific notation
result <- engine$eval_text("1e-100")
expect_equal(result, 1e-100)
result <- engine$eval_text("2.5e-308")
expect_equal(result, 2.5e-308)
# Planck's constant (approximately)
result <- engine$eval_text("6.626e-34")
expect_equal(result, 6.626e-34)
# Should work in arithmetic
result <- engine$eval_text("(+ 1e-10 1e-10)")
expect_equal(result, 2e-10)
# Multiplication with very small numbers
result <- engine$eval_text("(* 2e-5 3e-5)")
expect_equal(result, 2e-5 * 3e-5)
# Division creating small numbers
result <- engine$eval_text("(/ 1 1e10)")
expect_equal(result, 1e-10)
})
test_that("special numeric values", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Inf
result <- engine$eval_text("(/ 1 0)")
expect_equal(result, Inf)
# -Inf
result <- engine$eval_text("(/ -1 0)")
expect_equal(result, -Inf)
# NaN (0/0)
result <- engine$eval_text("(/ 0 0)")
expect_true(is.nan(result))
})
test_that("empty list", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text("'()")
expect_equal(length(result), 0)
})
test_that("whitespace handling", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Multiple spaces
result <- engine$eval_text("(+ 1 2)")
expect_equal(result, 3)
# Tabs
result <- engine$eval_text("(+\t1\t2)")
expect_equal(result, 3)
# Mixed whitespace
result <- engine$eval_text("(+ \t\n 1 \n\t 2)")
expect_equal(result, 3)
})
test_that("comment handling", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Line comment
result <- engine$eval_text("; comment\n(+ 1 2)")
expect_equal(result, 3)
# Inline comment
result <- engine$eval_text("(+ 1 2) ; result is 3")
expect_equal(result, 3)
# Multiple comments
code <- "; first comment\n; second comment\n(+ 1 2) ; inline\n; trailing"
result <- engine$eval_text(code)
expect_equal(result, 3)
})
test_that("partial input errors", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Unclosed paren - should error
expect_error(engine$eval_text("(+ 1 2"))
# Unclosed string - should error
expect_error(engine$eval_text('"unclosed string'))
# Unclosed list - should error
expect_error(engine$eval_text("'(1 2 3"))
})
test_that("symbols with special characters", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Symbols can have hyphens
engine$eval_text("(define test-var 42)")
result <- engine$eval_text("test-var")
expect_equal(result, 42)
# Symbols can have question marks
engine$eval_text("(import math :refer (%))
(define even? (lambda (x) (= (% x 2) 0)))")
result <- engine$eval_text("(even? 4)")
expect_equal(result, TRUE)
# Symbols can have exclamation marks
engine$eval_text("(define important! 100)")
result <- engine$eval_text("important!")
expect_equal(result, 100)
})
test_that("keywords", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Keywords start with colon and are self-evaluating
result <- engine$eval_text(":keyword")
expect_true(!is.null(result))
# Quoted keywords can be compared as values
result <- engine$eval_text("(= ':foo ':foo)")
expect_equal(result, TRUE)
result <- engine$eval_text("(= ':foo ':bar)")
expect_equal(result, FALSE)
# Bare keywords in argument position are treated as named argument syntax
# :foo :foo becomes a named arg foo=(symbol foo), so = sees 1 arg (vacuously true)
result <- engine$eval_text("(= :foo :foo)")
expect_true(result)
})
test_that("dotted pairs / improper lists", {
thin()
engine <- make_engine(load_prelude = FALSE)
# This may not be supported, but test that it doesn't crash
expect_error(
engine$eval_text("'(1 . 2)"),
NA # Just ensure it doesn't crash silently
)
})
test_that("nested quotes", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text("''x")
# Should be (quote x) - the outer quote is evaluated, returning the inner quote form
expect_true(is.call(result))
})
test_that("empty string", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text('""')
expect_equal(result, "")
})
test_that("string with only whitespace", {
thin()
engine <- make_engine(load_prelude = FALSE)
result <- engine$eval_text('" "')
expect_equal(result, " ")
result <- engine$eval_text('"\n\t"')
expect_equal(result, "\n\t")
})
test_that("very long symbol names", {
thin()
engine <- make_engine(load_prelude = FALSE)
long_name <- paste(rep("a", 1000), collapse = "")
code <- sprintf("(define %s 42)", long_name)
engine$eval_text(code)
result <- engine$eval_text(long_name)
expect_equal(result, 42)
})
test_that("very long strings", {
thin()
engine <- make_engine(load_prelude = FALSE)
long_string <- paste(rep("a", 10000), collapse = "")
code <- sprintf('"%s"', long_string)
result <- engine$eval_text(code)
expect_equal(nchar(result), 10000)
})
test_that("deeply nested lists", {
thin()
engine <- make_engine(load_prelude = FALSE)
# Create deeply nested list
nested <- "'("
for (i in 1:100) {
nested <- paste0(nested, "(")
}
nested <- paste0(nested, "x")
for (i in 1:100) {
nested <- paste0(nested, ")")
}
nested <- paste0(nested, ")")
expect_no_error({
result <- engine$eval_text(nested)
})
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.