Skip to content

Commit 855326a

Browse files
Merge pull request #16 from ncborcherding/main
expand unit testing
2 parents 29ceb2e + ac5f90e commit 855326a

3 files changed

Lines changed: 646 additions & 2 deletions

File tree

tests/testthat/test-calculatePeptideBindingLoad.R

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,219 @@ test_that("calculatePeptideBindingLoad accepts character vector of alleles", {
160160
expect_type(result, "double")
161161
expect_true(result >= 0)
162162
})
163+
164+
# --- Identical Genotype Tests ---
165+
166+
test_that("calculatePeptideBindingLoad returns 0 for identical genotypes with no mismatched peptides", {
167+
# When donor and recipient have identical alleles, no mismatched peptides should be derived
168+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", A_2 = "A*03:01", stringsAsFactors = FALSE))
169+
donor <- hlaGeno(data.frame(A_1 = "A*02:01", A_2 = "A*03:01", stringsAsFactors = FALSE))
170+
171+
# With empty peptides (when peptides cannot be derived), should return 0
172+
result <- calculatePeptideBindingLoad(recipient, character(0), return = "total")
173+
expect_equal(result, 0)
174+
})
175+
176+
# --- PWM Backend Detailed Tests ---
177+
178+
test_that("PWM backend produces consistent scores for known binders", {
179+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
180+
# GILGFVFTL is a well-known A*02:01 binder (influenza M1 peptide)
181+
peptides <- c("GILGFVFTL")
182+
183+
result <- calculatePeptideBindingLoad(recipient, peptides, backend = "pwm", return = "detail")
184+
185+
expect_equal(nrow(result), 1)
186+
expect_equal(result$peptide, "GILGFVFTL")
187+
expect_equal(result$hla_allele, "A*02:01")
188+
expect_true(result$predicted_ic50 > 0)
189+
})
190+
191+
test_that("PWM backend handles unknown supertypes gracefully", {
192+
# Use an allele that might not be in the supertype mapping
193+
recipient <- hlaGeno(data.frame(A_1 = "A*99:01", stringsAsFactors = FALSE))
194+
peptides <- c("GILGFVFTL")
195+
196+
# Should not error, falls back to A02-like
197+
result <- calculatePeptideBindingLoad(recipient, peptides, backend = "pwm", return = "detail")
198+
expect_equal(nrow(result), 1)
199+
})
200+
201+
# --- Summary Return Tests ---
202+
203+
test_that("summary return correctly aggregates across alleles", {
204+
recipient <- hlaGeno(data.frame(
205+
A_1 = "A*02:01", A_2 = "A*03:01",
206+
stringsAsFactors = FALSE
207+
))
208+
peptides <- c("GILGFVFTL", "NLVPMVATV", "FLKEKGGL")
209+
210+
result <- calculatePeptideBindingLoad(recipient, peptides, return = "summary")
211+
212+
expect_equal(nrow(result), 2) # Two alleles
213+
expect_true(all(result$n_strong >= 0))
214+
expect_true(all(result$n_weak >= 0))
215+
expect_true(all(result$n_strong + result$n_weak <= result$n_peptides))
216+
})
217+
218+
test_that("summary totals match detail breakdown", {
219+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
220+
peptides <- c("GILGFVFTL", "NLVPMVATV", "FLKEKGGL")
221+
222+
detail <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
223+
summary <- calculatePeptideBindingLoad(recipient, peptides, return = "summary")
224+
225+
expect_equal(summary$n_peptides[1], nrow(detail))
226+
expect_equal(summary$n_strong[1], sum(detail$binding_level == "strong"))
227+
expect_equal(summary$n_weak[1], sum(detail$binding_level == "weak"))
228+
})
229+
230+
# --- Contribution Calculation Tests ---
231+
232+
test_that("contribution scores are non-negative", {
233+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
234+
peptides <- c("GILGFVFTL", "NLVPMVATV")
235+
236+
result <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
237+
238+
expect_true(all(result$contribution >= 0))
239+
})
240+
241+
test_that("strong binders have higher contribution than weak binders", {
242+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
243+
peptides <- c("GILGFVFTL", "NLVPMVATV", "FLKEKGGL", "AAAAAAAAL")
244+
245+
result <- calculatePeptideBindingLoad(
246+
recipient, peptides,
247+
binding_threshold = 500,
248+
weak_threshold = 5000,
249+
return = "detail"
250+
)
251+
252+
# Check that multiplier difference is reflected
253+
strong <- result[result$binding_level == "strong", ]
254+
weak <- result[result$binding_level == "weak", ]
255+
256+
# This tests the formula: strong gets 2x multiplier, weak gets 1x
257+
# For same IC50, strong contribution should be ~2x weak
258+
if (nrow(strong) > 0 && nrow(weak) > 0) {
259+
# At least verify strong binders have non-zero contribution
260+
expect_true(all(strong$contribution > 0))
261+
}
262+
})
263+
264+
# --- Edge Case Tests ---
265+
266+
test_that("calculatePeptideBindingLoad handles single character peptide input", {
267+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
268+
269+
# Single short peptide (will be filtered out for 9-mer requirement)
270+
result <- calculatePeptideBindingLoad(recipient, "ABC", peptide_length = 9L)
271+
expect_equal(result, 0)
272+
})
273+
274+
test_that("calculatePeptideBindingLoad handles peptides with non-standard characters", {
275+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
276+
# Peptide with X (unknown)
277+
peptides <- c("GILGFVFTX")
278+
279+
result <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
280+
expect_equal(nrow(result), 1) # Should still process
281+
})
282+
283+
test_that("calculatePeptideBindingLoad handles duplicate peptides", {
284+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
285+
peptides <- c("GILGFVFTL", "GILGFVFTL", "GILGFVFTL")
286+
287+
result <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
288+
289+
# Duplicates should be deduplicated internally by .getPeptides
290+
expect_equal(nrow(result), 1)
291+
})
292+
293+
# --- Different Peptide Lengths ---
294+
295+
test_that("calculatePeptideBindingLoad works with different peptide lengths", {
296+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
297+
298+
# 8-mers
299+
peptides_8 <- c("GILGFVFT", "NLVPMVAT")
300+
result_8 <- calculatePeptideBindingLoad(recipient, peptides_8, peptide_length = 8L, return = "detail")
301+
expect_equal(nrow(result_8), 2)
302+
expect_true(all(nchar(result_8$peptide) == 8))
303+
304+
# 10-mers
305+
peptides_10 <- c("GILGFVFTLA", "NLVPMVATVA")
306+
result_10 <- calculatePeptideBindingLoad(recipient, peptides_10, peptide_length = 10L, return = "detail")
307+
expect_equal(nrow(result_10), 2)
308+
expect_true(all(nchar(result_10$peptide) == 10))
309+
})
310+
311+
# --- Aggregate Method Tests ---
312+
313+
test_that("aggregate_method sum gives total of all contributions", {
314+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
315+
peptides <- c("GILGFVFTL", "NLVPMVATV")
316+
317+
detail <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
318+
total_sum <- calculatePeptideBindingLoad(recipient, peptides, aggregate_method = "sum")
319+
320+
expect_equal(total_sum, sum(detail$contribution))
321+
})
322+
323+
test_that("aggregate_method max gives maximum contribution", {
324+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
325+
peptides <- c("GILGFVFTL", "NLVPMVATV")
326+
327+
detail <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
328+
total_max <- calculatePeptideBindingLoad(recipient, peptides, aggregate_method = "max")
329+
330+
expect_equal(total_max, max(detail$contribution))
331+
})
332+
333+
test_that("aggregate_method mean gives average contribution", {
334+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
335+
peptides <- c("GILGFVFTL", "NLVPMVATV")
336+
337+
detail <- calculatePeptideBindingLoad(recipient, peptides, return = "detail")
338+
total_mean <- calculatePeptideBindingLoad(recipient, peptides, aggregate_method = "mean")
339+
340+
expect_equal(total_mean, mean(detail$contribution))
341+
})
342+
343+
# --- Class I vs Class II Alleles ---
344+
345+
test_that("calculatePeptideBindingLoad handles Class I B locus alleles", {
346+
recipient <- hlaGeno(data.frame(B_1 = "B*07:02", B_2 = "B*08:01", stringsAsFactors = FALSE))
347+
peptides <- c("TPRVTGGGAM") # Known B*07:02 binder motif (Pro at P2)
348+
349+
result <- calculatePeptideBindingLoad(recipient, peptides, peptide_length = 10L, return = "detail")
350+
351+
expect_true(nrow(result) >= 1)
352+
expect_true(all(grepl("B\\*", result$hla_allele)))
353+
})
354+
355+
# --- Empty and Edge Cases for Summary ---
356+
357+
test_that("summary return handles empty peptides correctly", {
358+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", A_2 = "A*03:01", stringsAsFactors = FALSE))
359+
360+
result <- calculatePeptideBindingLoad(recipient, character(0), return = "summary")
361+
362+
expect_s3_class(result, "data.frame")
363+
expect_equal(nrow(result), 2)
364+
expect_true(all(result$n_peptides == 0))
365+
expect_true(all(result$n_strong == 0))
366+
expect_true(all(result$n_weak == 0))
367+
expect_true(all(result$risk_contribution == 0))
368+
})
369+
370+
test_that("detail return handles empty peptides correctly", {
371+
recipient <- hlaGeno(data.frame(A_1 = "A*02:01", stringsAsFactors = FALSE))
372+
373+
result <- calculatePeptideBindingLoad(recipient, character(0), return = "detail")
374+
375+
expect_s3_class(result, "data.frame")
376+
expect_equal(nrow(result), 0)
377+
expect_true(all(c("peptide", "hla_allele", "predicted_ic50", "binding_level", "contribution") %in% names(result)))
378+
})

tests/testthat/test-deepmatchrEnv.R

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,97 @@ sysname <- tryCatch({
2121
test_that("explicit platform selection returns expected BasiliskEnvironment S4 objects", {
2222
out_lin <- deepmatchrEnv("linux")
2323
out_mac <- deepmatchrEnv("macos")
24-
24+
2525
# S4 class checks
2626
expect_s4_class(out_lin, "BasiliskEnvironment")
2727
expect_s4_class(out_mac, "BasiliskEnvironment")
28-
28+
2929
# envname slot is the one you defined in your code ("deepmatchrEnv")
30+
3031
expect_identical(out_lin@envname, "deepmatchrEnv_v2")
3132
expect_identical(out_mac@envname, "deepmatchrEnv_v2")
3233
})
3334

3435
test_that("match.arg validates unsupported platform", {
3536
expect_error(deepmatchrEnv("windows"), "arg")
3637
})
38+
39+
# --- Auto Platform Detection Tests ---
40+
41+
test_that("auto platform detection returns valid BasiliskEnvironment", {
42+
out_auto <- deepmatchrEnv("auto")
43+
expect_s4_class(out_auto, "BasiliskEnvironment")
44+
expect_identical(out_auto@envname, "deepmatchrEnv_v2")
45+
})
46+
47+
test_that("auto platform matches explicit selection for current OS", {
48+
out_auto <- deepmatchrEnv("auto")
49+
50+
if (grepl("darwin|mac", sysname)) {
51+
out_explicit <- deepmatchrEnv("macos")
52+
} else {
53+
out_explicit <- deepmatchrEnv("linux")
54+
}
55+
56+
expect_identical(out_auto@envname, out_explicit@envname)
57+
expect_identical(out_auto@pkgname, out_explicit@pkgname)
58+
})
59+
60+
# --- Environment Configuration Tests ---
61+
62+
test_that("linux environment has correct package configuration", {
63+
out_lin <- deepmatchrEnv("linux")
64+
65+
expect_identical(out_lin@pkgname, "deepMatchR")
66+
# Check pip packages are specified (the slots vary by basilisk version)
67+
# At minimum, envname and pkgname should be correct
68+
})
69+
70+
test_that("macos environment has correct package configuration", {
71+
out_mac <- deepmatchrEnv("macos")
72+
73+
expect_identical(out_mac@pkgname, "deepMatchR")
74+
})
75+
76+
# --- Default Argument Tests ---
77+
78+
test_that("deepmatchrEnv with no arguments uses auto", {
79+
out_default <- deepmatchrEnv()
80+
out_auto <- deepmatchrEnv("auto")
81+
82+
expect_identical(out_default@envname, out_auto@envname)
83+
})
84+
85+
# --- Internal Environment Object Tests ---
86+
87+
test_that("internal linux environment object exists and is valid", {
88+
env_lin <- get_linux_env()
89+
expect_s4_class(env_lin, "BasiliskEnvironment")
90+
expect_identical(env_lin@envname, "deepmatchrEnv_v2")
91+
expect_identical(env_lin@pkgname, "deepMatchR")
92+
})
93+
94+
test_that("internal macos environment object exists and is valid", {
95+
env_mac <- get_macos_env()
96+
expect_s4_class(env_mac, "BasiliskEnvironment")
97+
expect_identical(env_mac@envname, "deepmatchrEnv_v2")
98+
expect_identical(env_mac@pkgname, "deepMatchR")
99+
})
100+
101+
# --- Idempotency Tests ---
102+
103+
test_that("repeated calls return identical environments", {
104+
out1 <- deepmatchrEnv("linux")
105+
out2 <- deepmatchrEnv("linux")
106+
107+
expect_identical(out1@envname, out2@envname)
108+
expect_identical(out1@pkgname, out2@pkgname)
109+
})
110+
111+
test_that("environment names are consistent across platforms", {
112+
out_lin <- deepmatchrEnv("linux")
113+
out_mac <- deepmatchrEnv("macos")
114+
115+
# Both should have the same environment name for consistency
116+
expect_identical(out_lin@envname, out_mac@envname)
117+
})

0 commit comments

Comments
 (0)