From 4268750c0469479ae9d8fea971a243927fd3b130 Mon Sep 17 00:00:00 2001 From: Mitchell O'Hara-Wild Date: Thu, 16 Jan 2025 19:11:29 +1100 Subject: [PATCH] Add unit tests for cloze functions and fix bugs --- R/cloze.R | 20 +++--- tests/testthat/test-cloze.R | 133 ++++++++++++++++++++++++++++++++++++ tests/testthat/test-quiz.R | 5 -- 3 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 tests/testthat/test-cloze.R delete mode 100644 tests/testthat/test-quiz.R diff --git a/R/cloze.R b/R/cloze.R index 57b7383..4da01bd 100644 --- a/R/cloze.R +++ b/R/cloze.R @@ -73,7 +73,7 @@ cloze_shortanswer <- function( case_sensitive = FALSE) { force(feedback) # Validate an answer is provided - options <- options/weight*100 + options <- options/pmax(weight, 0.01)*100 if(!any(options == 100)) stop("At least one correct answer with mark value 1 (or more) must be specified for a short answer question.") sprintf( "`{%i:SHORTANSWER%s:%s}`{=html}", @@ -92,7 +92,7 @@ cloze_multichoice <- function( shuffle = FALSE) { force(feedback) # Validate an answer is provided - options <- options/weight*100 + options <- options/pmax(weight, 0.01)*100 if(!any(options == 100)) stop("At least one correct answer with mark value 1 (or more) must be specified for a multiple choice question.") type <- match.arg(type) @@ -115,15 +115,15 @@ cloze_singlechoice <- function( shuffle = FALSE) { force(feedback) # Validate an answer is provided - options <- options/weight*100 + options <- options/pmax(weight, 0.01)*100 if(!any(options == 100)) stop("At least one correct answer with mark value 1 (or more) must be specified for a single choice question.") type <- match.arg(type) sprintf( - "`{%i:MULTICHOICE%s%s:%s}`{=html}", + "`{%i:MULTICHOICE%s%s%s:%s}`{=html}", weight, - switch(type, dropdown = "", vertical = "_V", horizontal = "_H"), - #if(shuffle || type != "dropdown") "_" else "", + if(shuffle || type != "dropdown") "_" else "", + switch(type, dropdown = "", vertical = "V", horizontal = "H"), if(shuffle) "S" else "", paste0("%", options, "%", names(options), "#", feedback, collapse = "~") ) @@ -165,11 +165,11 @@ cloze.numeric <- function(x, ...) { } #' @export -cloze.character <- function(x, choices = NULL, ...) { +cloze.character <- function(x, choices = NULL, weight = 1L, ...) { if(is.null(choices)) - cloze_shortanswer(`names<-`(1L, x), ...) + cloze_shortanswer(`names<-`(weight, x), weight = weight, ...) else if(length(x) > 1) - cloze_multichoice(choices(choices, x)) + cloze_multichoice(choices(choices, x)*weight, weight = weight, ...) else - cloze_singlechoice(choices(choices, x)) + cloze_singlechoice(choices(choices, x)*weight, weight = weight, ...) } diff --git a/tests/testthat/test-cloze.R b/tests/testthat/test-cloze.R new file mode 100644 index 0000000..58702e1 --- /dev/null +++ b/tests/testthat/test-cloze.R @@ -0,0 +1,133 @@ +library(testthat) + +test_that("cloze_shortanswer generates correct output", { + # Test with a single correct answer, case insensitive + expect_equal( + cloze_shortanswer(c("Canberra" = 100), case_sensitive = FALSE), + "`{100:SHORTANSWER:%100%Canberra#}`{=html}" + ) + + # Test with multiple correct answers, case insensitive + expect_equal( + cloze_shortanswer(c("Canberra" = 100, "canberra" = 100), case_sensitive = FALSE), + "`{100:SHORTANSWER:%100%Canberra#~%100%canberra#}`{=html}" + ) + + # Test with case sensitivity enabled + expect_equal( + cloze_shortanswer(c("Canberra" = 100), case_sensitive = TRUE), + "`{100:SHORTANSWER_C:%100%Canberra#}`{=html}" + ) + + # Test with missing correct answer + expect_error( + cloze_shortanswer(c("Sydney" = 0)), + "At least one correct answer with mark value 1.*must be specified" + ) +}) + +test_that("cloze_multichoice generates correct output", { + # Test with vertical layout + expect_equal( + cloze_multichoice(c("4" = 100, "3" = 0, "5" = 0), type = "vertical"), + "`{100:MULTIRESPONSE:%100%4#~%0%3#~%0%5#}`{=html}" + ) + + # Test with horizontal layout + expect_equal( + cloze_multichoice(c("4" = 100, "3" = 0, "5" = 0), type = "horizontal"), + "`{100:MULTIRESPONSE_H:%100%4#~%0%3#~%0%5#}`{=html}" + ) + + # Test with shuffling enabled + expect_equal( + cloze_multichoice(c("4" = 100, "3" = 0, "5" = 0), shuffle = TRUE), + "`{100:MULTIRESPONSE_S:%100%4#~%0%3#~%0%5#}`{=html}" + ) + + # Test with no correct answer + expect_error( + cloze_multichoice(c("3" = 0, "5" = 0)), + "At least one correct answer with mark value 1.*must be specified" + ) +}) + +test_that("cloze_singlechoice generates correct output", { + # Test with dropdown layout + expect_equal( + cloze_singlechoice(c("2" = 100, "1" = 0, "3" = 0), type = "dropdown"), + "`{100:MULTICHOICE:%100%2#~%0%1#~%0%3#}`{=html}" + ) + + # Test with vertical layout + expect_equal( + cloze_singlechoice(c("2" = 100, "1" = 0, "3" = 0), type = "vertical"), + "`{100:MULTICHOICE_V:%100%2#~%0%1#~%0%3#}`{=html}" + ) + + # Test with shuffling enabled + expect_equal( + cloze_singlechoice(c("2" = 100, "1" = 0, "3" = 0), shuffle = TRUE), + "`{100:MULTICHOICE_S:%100%2#~%0%1#~%0%3#}`{=html}" + ) + + # Test with no correct answer + expect_error( + cloze_singlechoice(c("1" = 0, "3" = 0)), + "At least one correct answer with mark value 1.*must be specified" + ) +}) + +test_that("cloze_numerical generates correct output", { + # Test with exact match + expect_equal( + cloze_numerical(5, weight = 1, tolerance = 0), + "`{1:NUMERICAL:=5.000000:0.000000#}`{=html}" + ) + + # Test with tolerance + expect_equal( + cloze_numerical(5, weight = 2, tolerance = 0.1), + "`{2:NUMERICAL:=5.000000:0.100000#}`{=html}" + ) +}) + +test_that("choices function works as expected", { + # Test valid choices + expect_equal( + choices(c("A", "B", "C"), c("A", "C")), + c(A = 1, B = 0, C = 1) + ) + + # Test with no correct answer + expect_error( + choices(c("A", "B", "C"), "D"), + "The correct answer does not exist in the provided options" + ) +}) + +test_that("cloze dispatch works correctly", { + # Test numeric dispatch + expect_equal( + cloze(5, tolerance = 0.1), + "`{1:NUMERICAL:=5.000000:0.100000#}`{=html}" + ) + + # Test character dispatch (short answer) + expect_equal( + cloze("Canberra"), + "`{1:SHORTANSWER:%100%Canberra#}`{=html}" + ) + + # Test character dispatch (multiple choice) + expect_equal( + cloze(c("4", "5"), choices = c("4", "5", "6")), + "`{1:MULTIRESPONSE:%100%4#~%100%5#~%0%6#}`{=html}" + ) + + # Test character dispatch (single choice) + expect_equal( + cloze("4", choices = c("4", "5", "6"), weight = 3), + "`{3:MULTICHOICE:%100%4#~%0%5#~%0%6#}`{=html}" + ) +}) diff --git a/tests/testthat/test-quiz.R b/tests/testthat/test-quiz.R deleted file mode 100644 index 66d7396..0000000 --- a/tests/testthat/test-quiz.R +++ /dev/null @@ -1,5 +0,0 @@ -test_that("run examples", { - ex_scatter <- "../../inst/examples/draw-scatterplots.Rmd" - rmarkdown::render(ex_scatter) - -})