Nothing
test_that("GlycoCT: Gal(b1-3)GalNAc(a1-", {
glycoct <- paste0(
"RES\n",
"1b:a-dgal-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:b-dgal-HEX-1:5\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(3+1)3d"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "Gal(b1-3)GalNAc(a1-"
expect_equal(result, expected)
})
test_that("GlycoCT preserves furanose ring bounds", {
glcfnac <- paste0(
"RES\n",
"1b:b-dglc-HEX-1:4\n",
"2s:n-acetyl\n",
"LIN\n",
"1:1d(2+1)2n"
)
neuf5ac <- paste0(
"RES\n",
"1b:a-dgro-dgal-NON-2:5|1:a|2:keto|3:d\n",
"2s:n-acetyl\n",
"LIN\n",
"1:1d(5+1)2n"
)
fruf <- "RES\n1b:b-dara-HEX-2:5|2:keto"
parsed <- parse_glycoct(c(glcfnac, neuf5ac, fruf))
expect_identical(
as.character(parsed),
c("GlcfNAc(b1-", "Neuf5Ac(a2-", "Fruf(b2-")
)
})
test_that("GlycoCT preserves unusual configurations", {
parsed <- parse_glycoct(c(
"RES\n1b:a-dgal-HEX-1:5|6:d",
"RES\n1b:b-lgul-HEX-1:5",
"RES\n1b:x-dido-HEX-1:5|6:a",
"RES\n1b:a-dgal-HEX-1:4|6:d",
"RES\n1b:o-dgal-HEX-0:0|1:aldi|6:d"
))
expect_identical(
as.character(parsed),
c(
"D-Fuc(a1-",
"L-Gul(b1-",
"D-IdoA(?1-",
"D-Fucf(a1-",
"D-Fuc-ol(?1-"
)
)
})
test_that("GlycoCT recognizes the xylHex encoding of Fuc", {
glycoct <- c(
"RES\n1b:a-lxyl-HEX-1:5|4:d|6:d",
"RES\n1b:b-lxyl-HEX-1:5|4:d|6:d",
"RES\n1b:x-lxyl-HEX-1:5|4:d|6:d"
)
expect_identical(
unname(as.character(parse_glycoct(glycoct))),
c("Fuc(a1-", "Fuc(b1-", "Fuc(?1-")
)
})
test_that("GlycoCT accepts space-separated records", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2s:n-acetyl",
"3b:b-dgal-HEX-1:5",
"LIN",
"1:1d(2+1)2n",
"2:1o(3+1)3d"
)
result <- as.character(parse_glycoct(glycoct))
expect_equal(result, "Gal(b1-3)GalNAc(a1-")
})
test_that("GlycoCT maps generic HEX descriptors", {
expect_equal(as.character(parse_glycoct("RES\n1b:x-HEX-x:x")), "Hex(?1-")
expect_equal(as.character(parse_glycoct("RES\n1b:x-HEX-1:x|6:d")), "dHex(?1-")
expect_equal(
as.character(parse_glycoct("RES\n1b:x-HEX-1:5|6:a")),
"HexA(?1-"
)
hexnac <- paste0(
"RES\n",
"1b:x-HEX-1:x\n",
"2s:n-acetyl\n",
"LIN\n",
"1:1d(2+1)2n"
)
hexnac_6s <- paste0(
"RES\n",
"1b:x-HEX-1:x\n",
"2s:n-acetyl\n",
"3s:sulfate\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(6+1)3n"
)
hexn <- paste0(
"RES\n",
"1b:x-HEX-1:x\n",
"2s:amino\n",
"LIN\n",
"1:1d(2+1)2n"
)
hexn_4n <- paste0(
"RES\n",
"1b:x-HEX-1:x\n",
"2s:amino\n",
"3s:amino\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1d(4+1)3n"
)
hexn_4n_reversed <- paste0(
"RES\n",
"1b:x-HEX-1:x\n",
"2s:amino\n",
"3s:amino\n",
"LIN\n",
"1:1d(4+1)2n\n",
"2:1d(2+1)3n"
)
expect_equal(as.character(parse_glycoct(hexn)), "HexN(?1-")
expect_equal(as.character(parse_glycoct(hexn_4n)), "HexN4N(?1-")
expect_equal(as.character(parse_glycoct(hexn_4n_reversed)), "HexN4N(?1-")
expect_equal(as.character(parse_glycoct(hexnac)), "HexNAc(?1-")
expect_equal(as.character(parse_glycoct(hexnac_6s)), "HexNAc6S(?1-")
})
test_that("GlycoCT maps generic PEN descriptors", {
expect_equal(as.character(parse_glycoct("RES\n1b:x-PEN-x:x")), "Pen(?1-")
expect_equal(as.character(parse_glycoct("RES\n1b:x-PEN-1:4")), "Pen(?1-")
})
test_that("GlycoCT maps generic Neu5Ac descriptors", {
neu5ac <- paste0(
"RES\n",
"1b:x-NON-2:6|1:a|2:keto|3:d\n",
"2s:n-acetyl\n",
"LIN\n",
"1:1d(5+1)2n"
)
neu5gc <- paste0(
"RES\n",
"1b:x-NON-2:6|1:a|2:keto|3:d\n",
"2s:n-glycolyl\n",
"LIN\n",
"1:1d(5+1)2n"
)
neu5ac_9ac <- paste0(
"RES\n",
"1b:x-NON-2:6|1:a|2:keto|3:d\n",
"2s:n-acetyl\n",
"3s:acetyl\n",
"LIN\n",
"1:1d(5+1)2n\n",
"2:1o(9+1)3n"
)
neu5gc_9s <- paste0(
"RES\n",
"1b:x-NON-2:6|1:a|2:keto|3:d\n",
"2s:n-glycolyl\n",
"3s:sulfate\n",
"LIN\n",
"1:1d(5+1)2n\n",
"2:1o(9+1)3n"
)
expect_equal(as.character(parse_glycoct(neu5ac)), "Neu5Ac(?2-")
expect_equal(as.character(parse_glycoct(neu5gc)), "Neu5Gc(?2-")
expect_equal(as.character(parse_glycoct(neu5ac_9ac)), "Neu5Ac9Ac(?2-")
expect_equal(as.character(parse_glycoct(neu5gc_9s)), "Neu5Gc9S(?2-")
})
test_that("GlycoCT maps direct n-sulfate substituents", {
glcns <- paste0(
"RES\n",
"1b:x-dglc-HEX-1:5\n",
"2s:n-sulfate\n",
"LIN\n",
"1:1d(2+1)2n"
)
hexns <- paste0(
"RES\n",
"1b:x-HEX-1:x\n",
"2s:n-sulfate\n",
"LIN\n",
"1:1d(2+1)2n"
)
expect_equal(as.character(parse_glycoct(glcns)), "GlcN2S(?1-")
expect_equal(as.character(parse_glycoct(hexns)), "HexN2S(?1-")
})
test_that("GlycoCT: Neu5Ac(a2-3)Gal(b1-3)[Neu5Ac(a2-6)]GalNAc(a1-", {
glycoct <- paste0(
"RES\n",
"1b:a-dgal-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:b-dgal-HEX-1:5\n",
"4b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d\n",
"5s:n-acetyl\n",
"6b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d\n",
"7s:n-acetyl\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(3+1)3d\n",
"3:3o(3+2)4d\n",
"4:4d(5+1)5n\n",
"5:1o(6+2)6d\n",
"6:6d(5+1)7n"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "Neu5Ac(a2-3)Gal(b1-3)[Neu5Ac(a2-6)]GalNAc(a1-"
expect_equal(result, expected)
})
test_that("GlycoCT: Man6", {
glycoct <- paste0(
"RES\n",
"1b:b-dglc-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:b-dglc-HEX-1:5\n",
"4s:n-acetyl\n",
"5b:b-dman-HEX-1:5\n",
"6b:a-dman-HEX-1:5\n",
"7b:a-dman-HEX-1:5\n",
"8b:a-dman-HEX-1:5\n",
"9b:a-dman-HEX-1:5\n",
"10b:a-dman-HEX-1:5\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(4+1)3d\n",
"3:3d(2+1)4n\n",
"4:3o(4+1)5d\n",
"5:5o(3+1)6d\n",
"6:6o(2+1)7d\n",
"7:5o(6+1)8d\n",
"8:8o(3+1)9d\n",
"9:8o(6+1)10d"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "Man(a1-2)Man(a1-3)[Man(a1-3)[Man(a1-6)]Man(a1-6)]Man(b1-4)GlcNAc(b1-4)GlcNAc(b1-"
expect_equal(result, expected)
})
test_that("GlycoCT: GlcA3S(b1-3)Gal(b1-4)GlcNAc(b1- (GlcA and sulfate)", {
glycoct <- paste0(
"RES\n",
"1b:b-dglc-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:b-dgal-HEX-1:5\n",
"4b:b-dglc-HEX-1:5|6:a\n",
"5s:sulfate\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(4+1)3d\n",
"3:3o(3+1)4d\n",
"4:4o(3+1)5n"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "GlcA3S(b1-3)Gal(b1-4)GlcNAc(b1-"
expect_equal(result, expected)
})
test_that("GlycoCT: GlcA?S(b1-3)Gal(b1-4)GlcNAc(b1- (Unknown sulfate position)", {
glycoct <- paste0(
"RES\n",
"1b:b-dglc-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:b-dgal-HEX-1:5\n",
"4b:b-dglc-HEX-1:5|6:a\n",
"5s:sulfate\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(4+1)3d\n",
"3:3o(3+1)4d\n",
"4:4o(-1+1)5n"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "GlcA?S(b1-3)Gal(b1-4)GlcNAc(b1-"
expect_equal(result, expected)
})
test_that("GlycoCT: Neu4Ac5Ac(a2-", {
glycoct <- paste0(
"RES\n",
"1b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d\n",
"2s:acetyl\n",
"3s:n-acetyl\n",
"LIN\n",
"1:1o(4+1)2n\n",
"2:1d(5+1)3n\n"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "Neu5Ac4Ac(a2-"
expect_equal(result, expected)
})
test_that("GlycoCT substituents", {
expect_sub_equal <- function(glycoct_string, expected) {
result <- parse_glycoct(glycoct_string)
graph <- glyrepr::get_structure_graphs(result, return_list = FALSE)
sub <- igraph::V(graph)$sub
expect_equal(sub, expected)
}
sub_N <- "RES\n1b:a-dglc-HEX-1:5\n2s:amino\nLIN\n1:1d(3+1)2n\n"
expect_sub_equal(sub_N, "3N")
sub_Me <- "RES\n1b:a-dglc-HEX-1:5\n2s:acetyl\nLIN\n1:1o(3+1)2n\n"
expect_sub_equal(sub_Me, "3Ac")
sub_NAc <- "RES\n1b:a-dglc-HEX-1:5\n2s:n-acetyl\nLIN\n1:1d(3+1)2n\n"
expect_sub_equal(sub_NAc, "3NAc")
sub_P <- "RES\n1b:a-dglc-HEX-1:5\n2s:phosphate\nLIN\n1:1o(3+1)2n\n"
expect_sub_equal(sub_P, "3P")
sub_S <- "RES\n1b:a-dglc-HEX-1:5\n2s:sulfate\nLIN\n1:1o(3+1)2n\n"
expect_sub_equal(sub_S, "3S")
sub_PPEtn <- "RES\n1b:a-dglc-HEX-1:5\n2s:diphospho-ethanolamine\nLIN\n1:1o(3+1)2n\n"
expect_sub_equal(sub_PPEtn, "3PPEtn")
sub_PEtn <- "RES\n1b:a-dglc-HEX-1:5\n2s:phospho-ethanolamine\nLIN\n1:1o(3+1)2n\n"
expect_sub_equal(sub_PEtn, "3PEtn")
})
test_that("GlycoCT keeps repeated and alternative substituent positions", {
repeated_sulfate <- paste0(
"RES\n",
"1b:x-dglc-HEX-1:5\n",
"2s:sulfate\n",
"3s:sulfate\n",
"LIN\n",
"1:1o(3+1)2n\n",
"2:1o(6+1)3n"
)
alternative_sulfate <- paste0(
"RES\n",
"1b:x-dglc-HEX-1:5\n",
"2s:sulfate\n",
"LIN\n",
"1:1o(3|4+1)2n"
)
neu5ac_1n <- paste0(
"RES\n",
"1b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d\n",
"2s:amino\n",
"3s:n-acetyl\n",
"LIN\n",
"1:1d(1+1)2n\n",
"2:1d(5+1)3n"
)
neu5ac_9nac <- paste0(
"RES\n",
"1b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d\n",
"2s:n-acetyl\n",
"3s:n-acetyl\n",
"LIN\n",
"1:1d(5+1)2n\n",
"2:1d(9+1)3n"
)
expect_equal(as.character(parse_glycoct(repeated_sulfate)), "Glc3S6S(?1-")
expect_equal(
as.character(parse_glycoct(alternative_sulfate)),
"Glc3/4S(?1-"
)
expect_equal(as.character(parse_glycoct(neu5ac_1n)), "Neu5Ac1N(a2-")
expect_equal(as.character(parse_glycoct(neu5ac_9nac)), "Neu5Ac9NAc(a2-")
})
test_that("GlycoCT rejects unrepresentable open-chain residues explicitly", {
expect_error(
map_single_mono_ringless("dglc-HEX-0:0"),
"Open-chain GlycoCT residues without an alditol modification"
)
})
test_that("GlycoCT: GlcA3S(?1-?)Gal(?1-?)GlcNAc(?1-, (Unknown linkages and anomers)", {
glycoct <- paste0(
"RES\n",
"1b:x-dglc-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:x-dgal-HEX-1:5\n",
"4b:x-dglc-HEX-1:5|6:a\n",
"5s:sulfate\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(-1+1)3d\n",
"3:3o(3|6+1)4d\n",
"4:4o(3+1)5n"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "GlcA3S(?1-3/6)Gal(?1-?)GlcNAc(?1-"
expect_equal(result, expected)
})
test_that("GlycoCT handles unknown reducing-end ring bounds", {
glycoct <- "RES\n1b:x-dglc-HEX-x:x"
result <- parse_glycoct(glycoct)
graph <- glyrepr::get_structure_graphs(result)
expect_equal(as.character(result), "Glc(??-")
expect_equal(graph$anomer, "??")
})
test_that("GlycoCT matches amino sugars with unknown ring bounds", {
glycoct <- paste0(
"RES\n",
"1b:x-dglc-HEX-x:x\n",
"2s:amino\n",
"LIN\n",
"1:1d(2+1)2n"
)
expect_equal(as.character(parse_glycoct(glycoct)), "GlcN(??-")
})
test_that("GlycoCT mapping signatures index exact composite candidates", {
signature <- c(
glycoct_mono_signature("dglc-HEX-x:x"),
list(subs = "n-acetyl", linkages = "2+1")
)
expect_identical(
match_composite_structure(signature),
"GlcNAc"
)
signature$linkages <- "5+1"
expect_null(match_composite_structure(signature))
})
test_that("GlycoCT handles N-sulfated amino sugars with unknown ring bounds", {
glycoct <- paste0(
"RES\n",
"1b:x-dglc-HEX-x:x\n",
"2s:amino\n",
"3s:sulfate\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1d(2+1)3n"
)
result <- parse_glycoct(glycoct)
graph <- glyrepr::get_structure_graphs(result)
expect_equal(as.character(result), "GlcN2S(??-")
expect_equal(igraph::vertex_attr(graph, "mono"), "GlcN")
expect_equal(igraph::vertex_attr(graph, "sub"), "2S")
})
test_that("GlycoCT preserves alditols with unknown reducing-end anomers", {
glcnac_alditol <- paste0(
"RES\n",
"1b:o-dglc-HEX-0:0|1:aldi\n",
"2s:n-acetyl\n",
"LIN\n",
"1:1d(2+1)2n"
)
glcnac_structure <- parse_glycoct(glcnac_alditol)
expect_equal(as.character(glcnac_structure), "GlcNAc-ol(?1-")
expect_identical(unname(glyrepr::get_alditol(glcnac_structure)), TRUE)
unknown_ring_alditol <- paste0(
"RES\n",
"1b:x-dgal-HEX-x:x|1:aldi\n",
"2s:n-acetyl\n",
"LIN\n",
"1:1d(2+1)2n"
)
unknown_ring_structure <- parse_glycoct(unknown_ring_alditol)
expect_equal(as.character(unknown_ring_structure), "GalNAc-ol(?1-")
expect_identical(
unname(glyrepr::get_alditol(unknown_ring_structure)),
TRUE
)
linked_alditol <- paste0(
"RES\n",
"1b:o-dglc-HEX-0:0|1:aldi\n",
"2s:n-acetyl\n",
"3b:b-dgal-HEX-1:5\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(4+1)3d"
)
linked_structure <- parse_glycoct(linked_alditol)
expect_equal(as.character(linked_structure), "Gal(b1-4)GlcNAc-ol(?1-")
expect_identical(unname(glyrepr::get_alditol(linked_structure)), TRUE)
symmetric_man_alditol <- paste0(
"RES\n",
"1b:o-dman-HEX-0:0|1:aldi\n",
"2b:a-lgal-HEX-1:5|6:d\n",
"LIN\n",
"1:1o(2+1)2d"
)
symmetric_man_structure <- parse_glycoct(symmetric_man_alditol)
expect_equal(
as.character(symmetric_man_structure),
"Fuc(a1-5)Man-ol(?1-"
)
expect_identical(
unname(glyrepr::get_alditol(symmetric_man_structure)),
TRUE
)
})
test_that("GlycoCT warns when non-reducing alditols are normalized", {
non_reducing_alditol <- paste0(
"RES\n",
"1b:a-dgal-HEX-1:5\n",
"2b:o-dglc-HEX-0:0|1:aldi\n",
"LIN\n",
"1:1o(3+1)2d"
)
expect_warning(
structure <- parse_glycoct(non_reducing_alditol),
"Only the main reducing-end GlycoCT residue"
)
expect_identical(as.character(structure), "Glc(?1-3)Gal(a1-")
expect_identical(unname(glyrepr::get_alditol(structure)), FALSE)
root_and_non_reducing_alditols <- paste0(
"RES\n",
"1b:o-dglc-HEX-0:0|1:aldi\n",
"2b:o-dgal-HEX-0:0|1:aldi\n",
"LIN\n",
"1:1o(4+1)2d"
)
expect_warning(
structure <- parse_glycoct(root_and_non_reducing_alditols),
"Only the main reducing-end GlycoCT residue"
)
expect_identical(as.character(structure), "Gal(?1-4)Glc-ol(?1-")
expect_identical(unname(glyrepr::get_alditol(structure)), TRUE)
})
test_that("GlycoCT parses all distinct converter alditol descriptors", {
alditol_mapping <- function(res, lin = NULL) {
list(res = res, lin = lin)
}
create_glycoct_from_mapping <- function(mapping) {
res_section <- paste(mapping$res, collapse = "\n")
if (!is.null(mapping$lin) && length(mapping$lin) > 0) {
lin_section <- paste(mapping$lin, collapse = "\n")
paste0("RES\n", res_section, "\nLIN\n", lin_section)
} else {
paste0("RES\n", res_section)
}
}
alditol_mappings <- list(
Glc = alditol_mapping(c("1b:o-dglc-HEX-0:0|1:aldi"), NULL),
Man = alditol_mapping(c("1b:o-dman-HEX-0:0|1:aldi"), NULL),
Gal = alditol_mapping(c("1b:o-dgal-HEX-0:0|1:aldi"), NULL),
Gul = alditol_mapping(c("1b:o-dgul-HEX-0:0|1:aldi"), NULL),
Alt = alditol_mapping(c("1b:o-ltal-HEX-0:0|1:aldi"), NULL),
All = alditol_mapping(c("1b:o-dall-HEX-0:0|1:aldi"), NULL),
Tal = alditol_mapping(c("1b:o-dalt-HEX-0:0|1:aldi"), NULL),
Ido = alditol_mapping(c("1b:o-lido-HEX-0:0|1:aldi"), NULL),
GlcNAc = alditol_mapping(
c("1b:o-dglc-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
GalNAc = alditol_mapping(
c("1b:o-dgal-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
ManNAc = alditol_mapping(
c("1b:o-dman-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
GulNAc = alditol_mapping(
c("1b:o-dgul-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
AltNAc = alditol_mapping(
c("1b:o-ltal-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(5+1)2n")
),
AllNAc = alditol_mapping(
c("1b:o-dall-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
TalNAc = alditol_mapping(
c("1b:o-dalt-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(5+1)2n")
),
IdoNAc = alditol_mapping(
c("1b:o-lido-HEX-0:0|1:aldi", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
GlcN = alditol_mapping(
c("1b:o-dglc-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(2+1)2n")
),
ManN = alditol_mapping(
c("1b:o-dman-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(2+1)2n")
),
GalN = alditol_mapping(
c("1b:o-dgal-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(2+1)2n")
),
GulN = alditol_mapping(
c("1b:o-dgul-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(2+1)2n")
),
AltN = alditol_mapping(
c("1b:o-ltal-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(5+1)2n")
),
AllN = alditol_mapping(
c("1b:o-dall-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(2+1)2n")
),
TalN = alditol_mapping(
c("1b:o-dalt-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(5+1)2n")
),
IdoN = alditol_mapping(
c("1b:o-lido-HEX-0:0|1:aldi", "2s:amino"),
c("1:1d(2+1)2n")
),
Fuc = alditol_mapping(c("1b:o-lgal-HEX-0:0|1:aldi|6:d"), NULL),
Qui = alditol_mapping(c("1b:o-dglc-HEX-0:0|1:aldi|6:d"), NULL),
Rha = alditol_mapping(c("1b:o-lman-HEX-0:0|1:aldi|6:d"), NULL),
`6dGul` = alditol_mapping(c("1b:o-dgul-HEX-0:0|1:aldi|6:d"), NULL),
`6dAlt` = alditol_mapping(c("1b:o-lalt-HEX-0:0|1:aldi|6:d"), NULL),
`6dTal` = alditol_mapping(c("1b:o-dtal-HEX-0:0|1:aldi|6:d"), NULL),
FucNAc = alditol_mapping(
c("1b:o-lgal-HEX-0:0|1:aldi|6:d", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
QuiNAc = alditol_mapping(
c("1b:o-dglc-HEX-0:0|1:aldi|6:d", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
RhaNAc = alditol_mapping(
c("1b:o-lman-HEX-0:0|1:aldi|6:d", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
`6dAltNAc` = alditol_mapping(
c("1b:o-lalt-HEX-0:0|1:aldi|6:d", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
`6dTalNAc` = alditol_mapping(
c("1b:o-dtal-HEX-0:0|1:aldi|6:d", "2s:n-acetyl"),
c("1:1d(2+1)2n")
),
Oli = alditol_mapping(c("1b:o-dara-HEX-0:0|1:aldi|2:d|6:d"), NULL),
Tyv = alditol_mapping(c("1b:o-dara-HEX-0:0|1:aldi|3:d|6:d"), NULL),
Abe = alditol_mapping(c("1b:o-dxyl-HEX-0:0|1:aldi|3:d|6:d"), NULL),
Par = alditol_mapping(c("1b:o-drib-HEX-0:0|1:aldi|3:d|6:d"), NULL),
Dig = alditol_mapping(c("1b:o-drib-HEX-0:0|1:aldi|2:d|6:d"), NULL),
Col = alditol_mapping(c("1b:o-lxyl-HEX-0:0|1:aldi|3:d|6:d"), NULL),
Lyx = alditol_mapping(c("1b:o-llyx-PEN-0:0|1:aldi"), NULL),
Xyl = alditol_mapping(c("1b:o-dxyl-PEN-0:0|1:aldi"), NULL),
Rib = alditol_mapping(c("1b:o-drib-PEN-0:0|1:aldi"), NULL),
Bac = alditol_mapping(
c("1b:o-dglc-HEX-0:0|1:aldi|6:d", "2s:amino", "3s:amino"),
c("1:1d(2+1)2n", "2:1d(4+1)3n")
),
LDmanHep = alditol_mapping(c("1b:o-dgro-dgal-HEP-0:0|1:aldi"), NULL),
DDmanHep = alditol_mapping(c("1b:o-dgro-dman-HEP-0:0|1:aldi"), NULL),
MurNAc = alditol_mapping(
c(
"1b:o-dglc-HEX-0:0|1:aldi",
"2s:n-acetyl",
"3s:(r)-carboxyethyl"
),
c("1:1d(2+1)2n", "2:1o(3+1)3n")
),
MurNGc = alditol_mapping(
c(
"1b:o-dglc-HEX-0:0|1:aldi",
"2s:n-glycolyl",
"3s:(r)-carboxyethyl"
),
c("1:1d(2+1)2n", "2:1o(3+1)3n")
),
Mur = alditol_mapping(
c("1b:o-dglc-HEX-0:0|1:aldi", "2s:(r)-carboxyethyl"),
c("1:1o(3+1)2n")
)
)
purrr::iwalk(alditol_mappings, function(mapping, mono_name) {
glycoct <- create_glycoct_from_mapping(mapping)
result <- parse_glycoct(glycoct)
graph <- glyrepr::get_structure_graphs(result, return_list = FALSE)
expect_equal(igraph::vertex_attr(graph, "mono"), mono_name)
expect_equal(graph$anomer, paste0("?", glyrepr::get_anomer_pos(mono_name)))
expect_identical(graph$alditol, TRUE)
})
# GlycanFormatConverter emits the same GlycoCT alditol descriptor for Ara-ol
# and Lyx-ol, so the distinct descriptor is tested once as Lyx.
})
test_that("all monosaccharides can be parsed", {
expect_mono_equal <- function(x, expected) {
graph <- glyrepr::get_structure_graphs(x, return_list = FALSE)
mono <- igraph::V(graph)$mono
expect_equal(mono, expected)
}
# Helper function to create GlycoCT from mapping
create_glycoct_from_mapping <- function(mapping) {
res_section <- paste(mapping$res, collapse = "\n")
if (!is.null(mapping$lin) && length(mapping$lin) > 0) {
lin_section <- paste(mapping$lin, collapse = "\n")
paste0("RES\n", res_section, "\nLIN\n", lin_section)
} else {
paste0("RES\n", res_section)
}
}
# Get all mappings
mappings <- load_mono_mappings()
# Test each monosaccharide
for (mono_name in names(mappings)) {
mapping <- mappings[[mono_name]]
glycoct <- create_glycoct_from_mapping(mapping)
expect_mono_equal(parse_glycoct(glycoct), mono_name)
}
})
test_that("GlycoCT mappings cover every distinguishable unusual configuration", {
unusual_map <- unusual_configuration_monosaccharide_map()
concrete <- glyrepr::available_monosaccharides("concrete")
mappings <- load_mono_mappings()
natural <- intersect(names(mappings), names(unusual_map))
for (mono in natural) {
unusual_name <- unname(unusual_map[[mono]])
unusual_mapping <- mappings[[mono]]
unusual_mapping$res <- stringr::str_replace_all(
unusual_mapping$res,
"(?<=-)[dl](?=[a-z])",
\(configuration) invert_configuration(configuration)
)
matching_names <- names(mappings)[purrr::map_lgl(
mappings,
identical,
unusual_mapping
)]
expect_true(
unusual_name %in% matching_names || any(matching_names %in% concrete),
info = paste("missing unusual GlycoCT mapping for", unusual_name)
)
}
})
test_that("GlycoCT parses every representable unusual furanose", {
unusual <- unname(unusual_configuration_monosaccharide_map())
furanose_map <- furanose_monosaccharide_map()
furanose <- intersect(unusual, unname(furanose_map))
ringless <- names(furanose_map)[match(furanose, unname(furanose_map))]
mappings <- load_mono_mappings()
represented <- ringless %in% names(mappings)
furanose <- furanose[represented]
ringless <- ringless[represented]
for (index in seq_along(furanose)) {
mapping <- mappings[[ringless[[index]]]]
mapping$res <- stringr::str_replace_all(
mapping$res,
c("-1:5" = "-1:4", "-2:6" = "-2:5")
)
glycoct <- paste(
c(
"RES",
mapping$res,
if (length(mapping$lin)) c("LIN", mapping$lin)
),
collapse = "\n"
)
graph <- glyrepr::get_structure_graphs(
parse_glycoct(glycoct),
return_list = FALSE
)
expect_identical(
igraph::V(graph)$mono,
furanose[[index]],
info = paste("failed to preserve unusual furanose", furanose[[index]])
)
}
})
test_that("GlycoCT: a complex N-glycan example", {
glycoct <- paste0(
"RES\n",
"1b:b-dglc-HEX-1:5\n",
"2s:n-acetyl\n",
"3b:b-dglc-HEX-1:5\n",
"4s:n-acetyl\n",
"5b:b-dman-HEX-1:5\n",
"6b:a-dman-HEX-1:5\n",
"7b:b-dglc-HEX-1:5\n",
"8s:n-acetyl\n",
"9b:b-dgal-HEX-1:5\n",
"10b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d\n",
"11s:n-acetyl\n",
"12b:a-dman-HEX-1:5\n",
"13b:b-dglc-HEX-1:5\n",
"14s:n-acetyl\n",
"15b:b-dgal-HEX-1:5\n",
"LIN\n",
"1:1d(2+1)2n\n",
"2:1o(4+1)3d\n",
"3:3d(2+1)4n\n",
"4:3o(4+1)5d\n",
"5:5o(3+1)6d\n",
"6:6o(2+1)7d\n",
"7:7d(2+1)8n\n",
"8:7o(4+1)9d\n",
"9:9o(3|6+2)10d\n",
"10:10d(5+1)11n\n",
"11:5o(6+1)12d\n",
"12:12o(2+1)13d\n",
"13:13d(2+1)14n\n",
"14:13o(4+1)15d"
)
result <- as.character(parse_glycoct(glycoct))
expected <- "Neu5Ac(a2-3/6)Gal(b1-4)GlcNAc(b1-2)Man(a1-3)[Gal(b1-4)GlcNAc(b1-2)Man(a1-6)]Man(b1-4)GlcNAc(b1-4)GlcNAc(b1-"
expect_equal(result, expected)
})
test_that("GlycoCT UND sections become floating glycan parts", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2b:b-dglc-HEX-1:5",
"LIN",
"1:1o(3+1)2d",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(6+1)d",
"RES",
"3b:b-dglc-HEX-1:5",
"4s:n-acetyl",
"5b:b-dgal-HEX-1:5",
"LIN",
"2:3d(2+1)4n",
"3:3o(4+1)5d",
"UND2:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(2+1)d",
"RES",
"6b:a-lgal-HEX-1:5|6:d"
)
result <- parse_glycoct(glycoct)
floating <- glyrepr::structure_floating_parts(result)
expect_identical(
unname(as.character(result)),
paste0(
"{Fuc(a1-2)|4,5}",
"{Gal(b1-4)GlcNAc(b1-6)|4,5}",
"Glc(b1-3)Gal(a1-"
)
)
expect_identical(floating$linkage, c("a1-2", "b1-6"))
expect_equal(floating$nodes, list(1L, c(2L, 3L)))
expect_equal(floating$parents, list(c(4L, 5L), c(4L, 5L)))
})
test_that("substituent-only GlycoCT UND sections become floating", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2b:b-dglc-HEX-1:5",
"LIN",
"1:1o(3+1)2d",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(-1+1)n",
"RES",
"3s:sulfate"
)
result <- parse_glycoct(glycoct)
floating <- glyrepr::structure_floating_substituents(result)
expect_identical(
unname(as.character(result)),
"{?S}Glc(b1-3)Gal(a1-"
)
expect_identical(floating$substituent, "?S")
expect_equal(floating$parents, list(integer()))
})
test_that("single-parent GlycoCT UND substituents become ordinary", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1",
"SubtreeLinkageID1:o(3+1)n",
"RES",
"2s:sulfate"
)
result <- parse_glycoct(glycoct)
expect_identical(unname(as.character(result)), "Gal3S(a1-")
expect_identical(
unname(glyrepr::has_floating_substituents(result)),
FALSE
)
})
test_that("all-main GlycoCT substituent candidates exclude occupied slots", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2b:b-dglc-HEX-1:5",
"LIN",
"1:1o(3+1)2d",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(3+1)n",
"RES",
"3s:sulfate"
)
result <- parse_glycoct(glycoct)
expect_identical(
unname(as.character(result)),
"Glc3S(b1-3)Gal(a1-"
)
expect_identical(
unname(glyrepr::has_floating_substituents(result)),
FALSE
)
})
test_that("floating substituent positions preserve representable domains", {
normalized <- normalize_floating_substituent_parents(
c(1L, 2L),
c(1L, 2L),
"3/6S",
c("1\r3", "2\r3"),
context = "test substituent"
)
expect_identical(
normalized,
list(substituent = "6S", parents = integer())
)
expect_snapshot(
error = TRUE,
normalize_floating_substituent_parents(
c(1L, 2L),
c(1L, 2L),
"3/6S",
c("1\r3", "2\r6"),
context = "test substituent"
)
)
})
test_that("GlycoCT supports floating parts and substituents together", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2b:b-dglc-HEX-1:5",
"LIN",
"1:1o(3+1)2d",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(6+1)d",
"RES",
"3b:a-lgal-HEX-1:5|6:d",
"UND2:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(-1+1)n",
"RES",
"4s:sulfate"
)
result <- parse_glycoct(glycoct)
expect_identical(
unname(as.character(result)),
"{?S|2,3}{Fuc(a1-6)}Glc(b1-3)Gal(a1-"
)
expect_identical(
glyrepr::structure_floating_substituents(result)$substituent,
"?S"
)
expect_identical(
glyrepr::structure_floating_parts(result)$linkage,
"a1-6"
)
expect_equal(
glyrepr::structure_floating_substituents(result)$parents,
list(c(2L, 3L))
)
})
test_that("GlycoCT warns for alditols inside UND sections", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1",
"SubtreeLinkageID1:o(3+1)d",
"RES",
"2b:o-dglc-HEX-0:0|1:aldi"
)
expect_warning(
result <- parse_glycoct(glycoct),
"Only the main reducing-end GlycoCT residue"
)
expect_identical(unname(as.character(result)), "Glc(?1-3)Gal(a1-")
})
test_that("single-parent GlycoCT UND sections become ordinary edges", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1",
"SubtreeLinkageID1:o(3+2)d",
"RES",
"2b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d",
"3s:n-acetyl",
"LIN",
"7:2d(5+1)3n"
)
result <- parse_glycoct(glycoct)
expect_identical(unname(as.character(result)), "Neu5Ac(a2-3)Gal(a1-")
expect_identical(unname(glyrepr::has_floating_parts(result)), FALSE)
})
test_that("GlycoCT UND donor alternatives fail explicitly", {
und <- c(
"UND1:100.0:100.0",
"ParentIDs:1",
"SubtreeLinkageID1:o(3+1|2)d",
"RES",
"2b:a-lgal-HEX-1:5|6:d"
)
expect_snapshot(
error = TRUE,
parse_glycoct_und_block(und)
)
})
test_that("GlycoCT UND candidate parents exclude occupied acceptor slots", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2b:b-dglc-HEX-1:5",
"3b:a-dman-HEX-1:5",
"LIN",
"1:1o(3+1)2d",
"2:1o(4+1)3d",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(3+1)d",
"RES",
"4b:a-lgal-HEX-1:5|6:d"
)
result <- parse_glycoct(glycoct)
expect_identical(
unname(as.character(result)),
"Fuc(a1-3)Glc(b1-3)[Man(a1-4)]Gal(a1-"
)
expect_identical(unname(glyrepr::has_floating_parts(result)), FALSE)
})
test_that("all-main GlycoCT UND candidates become implicit", {
glycoct <- paste(
"RES",
"1b:a-dgal-HEX-1:5",
"2b:b-dglc-HEX-1:5",
"LIN",
"1:1o(3+1)2d",
"UND",
"UND1:100.0:100.0",
"ParentIDs:1|2",
"SubtreeLinkageID1:o(3+2)d",
"RES",
"3b:a-dgro-dgal-NON-2:6|1:a|2:keto|3:d",
"4s:n-acetyl",
"LIN",
"2:3d(5+1)4n"
)
result <- parse_glycoct(glycoct)
expect_identical(
unname(as.character(result)),
"{Neu5Ac(a2-3)}Glc(b1-3)Gal(a1-"
)
expect_equal(
glyrepr::structure_floating_parts(result)$parents,
list(integer())
)
})
test_that("GlycoCT UND parts require a feasible candidate parent", {
expect_snapshot(
error = TRUE,
filter_glycoct_und_parents(1L, "b1-3", "1\r3")
)
})
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.