Nothing
# Demonstration of Expected Element Error Reporting
# This file demonstrates the new functionality for showing expected elements
# in parser error messages, making debugging much easier.
test_that("Demo: Basic literal parser shows what was expected", {
reset_LNR()
# When a literal parser fails, it now tells you what it expected
err <- tryCatch(
reporter(literal("start") %then% eof())(c("wrong")),
error = function(e) e
)
expect_match(err$message, "Expected: literal 'start'")
expect_match(err$message, "line 1")
})
test_that("Demo: Multiple alternatives show all options", {
reset_LNR()
# When using %or%, the error shows all alternatives that could have worked
command_parser <- literal("GET") %or%
literal("POST") %or%
literal("PUT") %or%
literal("DELETE")
err <- tryCatch(
reporter(command_parser %then% eof())("PATCH"),
error = function(e) e
)
expect_match(err$message, "Expected one of:")
expect_match(err$message, "literal 'GET'")
expect_match(err$message, "literal 'POST'")
expect_match(err$message, "literal 'PUT'")
expect_match(err$message, "literal 'DELETE'")
})
test_that("Demo: Named parsers provide semantic error messages", {
reset_LNR()
# Use named() to give semantic meaning to parsers
DNA_base <- named(
satisfy(function(x) x %in% c("A", "T", "G", "C")),
"DNA base (A, T, G, or C)"
)
# Don't use eof() here - we want to see the DNA_base error, not eof error
err <- tryCatch(
reporter(DNA_base %then% eof())(c("X")),
error = function(e) e
)
expect_match(err$message, "line 1")
expect_match(err$message, "Expected: DNA base")
})
test_that("Demo: Complex parser with meaningful names", {
reset_LNR()
# Build a simple parser for structured data with meaningful names
header <- named(
satisfy(function(x) grepl("^#", x)),
"header (line starting with #)"
)
number <- named(
satisfy(function(x) grepl("^\\d+$", x)),
"number"
)
text <- named(
satisfy(function(x) grepl("^[a-zA-Z ]+$", x)),
"text"
)
data_line <- number %or% text
simple_file <- header %then% one_or_more(data_line) %then% eof()
# Test the data_line parser directly to see its error message
err <- tryCatch(
reporter(data_line %then% eof())("!!!"),
error = function(e) e
)
expect_match(err$message, "line 1")
expect_match(err$message, "Expected one of:")
expect_match(err$message, "number")
expect_match(err$message, "text")
})
test_that("Demo: Fasta-like parser with clear error messages", {
reset_LNR()
# Realistic example: parsing sequence data
fasta_header <- named(
satisfy(function(x) grepl("^>\\w+", x)),
"FASTA header (>sequence_name)"
)
nucleotide_line <- named(
satisfy(function(x) grepl("^[GATC]+$", x)),
"nucleotide sequence (only G, A, T, C)"
)
protein_line <- named(
satisfy(function(x) grepl("^[ARNDCQEGHILKMFPSTWYV]+$", x)),
"protein sequence"
)
sequence_line <- nucleotide_line %or% protein_line
fasta_entry <- fasta_header %then% one_or_more(sequence_line)
# Valid input works fine
valid <- c(">seq1", "GATCGATC", "AAATTTGGG")
result <- reporter(fasta_entry %then% eof())(valid)
expect_true(is.list(result))
# Invalid sequence gives clear error - test sequence_line directly
err <- tryCatch(
reporter(sequence_line %then% eof())("12345"),
error = function(e) e
)
expect_match(err$message, "line 1")
expect_match(err$message, "Expected one of:")
expect_match(err$message, "nucleotide sequence")
expect_match(err$message, "protein sequence")
# Missing header gives clear error
err2 <- tryCatch(
reporter(fasta_entry %then% eof())(c("GATC", "AAATTT")),
error = function(e) e
)
expect_match(err2$message, "line 1")
expect_match(err2$message, "Expected: FASTA header")
})
test_that("Demo: Sequential parser errors point to exact failure", {
reset_LNR()
# Build a parser for a simple protocol
version <- named(literal("v1.0"), "version 'v1.0'")
separator <- literal("---")
status_ok <- named(literal("OK"), "status 'OK'")
status_err <- named(literal("ERROR"), "status 'ERROR'")
status <- status_ok %or% status_err
protocol <- version %then% separator %then% status %then% eof()
# Error in first element
err1 <- tryCatch(
reporter(protocol)(c("v2.0", "---", "OK")),
error = function(e) e
)
expect_match(err1$message, "line 1")
expect_match(err1$message, "Expected: version 'v1.0'")
# Error in middle element
err2 <- tryCatch(
reporter(protocol)(c("v1.0", "+++", "OK")),
error = function(e) e
)
expect_match(err2$message, "line 2")
expect_match(err2$message, "Expected: literal '---'")
# Error in last element
err3 <- tryCatch(
reporter(protocol)(c("v1.0", "---", "PENDING")),
error = function(e) e
)
expect_match(err3$message, "line 3")
expect_match(err3$message, "Expected one of:")
expect_match(err3$message, "status 'OK'")
expect_match(err3$message, "status 'ERROR'")
})
test_that("Demo: Error messages help understand complex parser structure", {
reset_LNR()
# A parser for key-value configuration files
comment <- named(
satisfy(function(x) grepl("^#", x)),
"comment line"
)
key_value <- named(
satisfy(function(x) grepl("^\\w+\\s*=\\s*.+$", x)),
"key=value pair"
)
config_line <- comment %or% EmptyLine() %or% key_value
# This helps users understand what constitutes a valid line
# Test config_line directly with invalid input
err <- tryCatch(
reporter(config_line %then% eof())("invalid line here"),
error = function(e) e
)
expect_match(err$message, "line 1")
# The error should mention what kinds of lines are acceptable
expect_match(err$message, "Expected one of:")
})
test_that("Demo: Named wrappers replace underlying expectations", {
reset_LNR()
# Sometimes you want to hide implementation details
# and show user-friendly names
# Without named: shows technical details
ip_octet_raw <- satisfy(function(x) {
num <- suppressWarnings(as.numeric(x))
!is.na(num) && num >= 0 && num <= 255
})
err_raw <- tryCatch(
reporter(ip_octet_raw %then% eof())("999"),
error = function(e) e
)
expect_match(err_raw$message, "matching input") # Generic message
# With named: shows semantic meaning
ip_octet <- named(
satisfy(function(x) {
num <- suppressWarnings(as.numeric(x))
!is.na(num) && num >= 0 && num <= 255
}),
"IP octet (0-255)"
)
err_named <- tryCatch(
reporter(ip_octet %then% eof())("999"),
error = function(e) e
)
expect_match(err_named$message, "IP octet") # Clear message
})
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.