Nothing
test_that("parse_residue works for each monosaccharide without substituents", {
expect_equal(
parse_residue("a2122h-1a_1-5"),
c(mono = "Glc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1122h-1a_1-5"),
c(mono = "Man", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2112h-1a_1-5"),
c(mono = "Gal", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2212h-1a_1-5"),
c(mono = "Gul", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2111h-1a_1-5"),
c(mono = "Alt", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2222h-1a_1-5"),
c(mono = "All", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1112h-1a_1-5"),
c(mono = "Tal", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2121h-1a_1-5"),
c(mono = "Ido", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122h-1a_1-5_2*NCC/3=O"),
c(mono = "GlcNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2112h-1a_1-5_2*NCC/3=O"),
c(mono = "GalNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1122h-1a_1-5_2*NCC/3=O"),
c(mono = "ManNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2212h-1a_1-5_2*NCC/3=O"),
c(mono = "GulNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2111h-1a_1-5_2*NCC/3=O"),
c(mono = "AltNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2222h-1a_1-5_2*NCC/3=O"),
c(mono = "AllNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1112h-1a_1-5_2*NCC/3=O"),
c(mono = "TalNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2121h-1a_1-5_2*NCC/3=O"),
c(mono = "IdoNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122h-1a_1-5_2*N"),
c(mono = "GlcN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1122h-1a_1-5_2*N"),
c(mono = "ManN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2112h-1a_1-5_2*N"),
c(mono = "GalN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2212h-1a_1-5_2*N"),
c(mono = "GulN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2111h-1a_1-5_2*N"),
c(mono = "AltN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2222h-1a_1-5_2*N"),
c(mono = "AllN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1112h-1a_1-5_2*N"),
c(mono = "TalN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2121h-1a_1-5_2*N"),
c(mono = "IdoN", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122A-1a_1-5"),
c(mono = "GlcA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1122A-1a_1-5"),
c(mono = "ManA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2112A-1a_1-5"),
c(mono = "GalA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2212A-1a_1-5"),
c(mono = "GulA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2111A-1a_1-5"),
c(mono = "AltA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2222A-1a_1-5"),
c(mono = "AllA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1112A-1a_1-5"),
c(mono = "TalA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2121A-1a_1-5"),
c(mono = "IdoA", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1221m-1a_1-5"),
c(mono = "Fuc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122m-1a_1-5"),
c(mono = "Qui", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2211m-1a_1-5"),
c(mono = "Rha", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2212m-1a_1-5"),
c(mono = "6dGul", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2111m-1a_1-5"),
c(mono = "6dAlt", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1112m-1a_1-5"),
c(mono = "6dTal", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122m-1a_1-5_2*NCC/3=O"),
c(mono = "QuiNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2211m-1a_1-5_2*NCC/3=O"),
c(mono = "RhaNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2111m-1a_1-5_2*NCC/3=O"),
c(mono = "6dAltNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1112m-1a_1-5_2*NCC/3=O"),
c(mono = "6dTalNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1221m-1a_1-5_2*NCC/3=O"),
c(mono = "FucNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("ad122m-1a_1-5"),
c(mono = "Oli", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1d22m-1a_1-5"),
c(mono = "Tyv", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2d12m-1a_1-5"),
c(mono = "Abe", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2d22m-1a_1-5"),
c(mono = "Par", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("ad222m-1a_1-5"),
c(mono = "Dig", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a1d21m-1a_1-5"),
c(mono = "Col", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a211h-1a_1-5"),
c(mono = "Ara", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a221h-1a_1-5"),
c(mono = "Lyx", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a212h-1a_1-5"),
c(mono = "Xyl", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a212h-1x_1-4"),
c(mono = "Xylf", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("a222h-1a_1-5"),
c(mono = "Rib", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("Aad21122h-2a_2-6_5*NCC/3=O"),
c(mono = "Neu5Ac", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad21122h-2a_2-6_5*NCCO/3=O"),
c(mono = "Neu5Gc", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad21122h-2a_2-6_5*N"),
c(mono = "Neu", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad21122h-2a_2-6"),
c(mono = "Kdn", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("had22111m-2a_2-6_5*N_7*N"),
c(mono = "Pse", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad21122m-2a_2-6_5*N_7*N"),
c(mono = "Leg", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad21111m-2a_2-6_5*N_7*N"),
c(mono = "Aci", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad11122m-2a_2-6_5*N_7*N"),
c(mono = "4eLeg", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("a2122m-1a_1-5_2*N_4*N"),
c(mono = "Bac", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a11221h-1a_1-5"),
c(mono = "LDmanHep", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("Aad1122h-2a_2-6"),
c(mono = "Kdo", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aad112A-2a_2-6"),
c(mono = "Dha", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("a11222h-1a_1-5"),
c(mono = "DDmanHep", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122h-1a_1-5_2*NCC/3=O_3*OC^RCO/4=O/3C"),
c(mono = "MurNAc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122h-1a_1-5_2*NCCO/3=O_3*OC^RCO/4=O/3C"),
c(mono = "MurNGc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OC^RCO/4=O/3C"),
c(mono = "Mur", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("ha122h-2a_2-6"),
c(mono = "Fru", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("ha112h-2a_2-6"),
c(mono = "Tag", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("ha121h-2a_2-6"),
c(mono = "Sor", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("ha222h-2a_2-6"),
c(mono = "Psi", anomer = "a2", sub = "")
)
})
test_that("parse_residue preserves unusual configurations", {
residues <- c(
DFuc = "a2112m-1a_1-5",
DFucf = "a2112m-1a_1-4",
LGul = "a1121h-1b_1-5",
DIdoA = "a1212A-1x_1-5",
LNeu5Ac = "Aad12211h-2a_2-6_5*NCC/3=O",
LGul_unknown_ring = "a1121h-1x_1-?",
DFuc_ambiguous = "u2112m",
DFuc_alditol = "h2112m"
)
parsed <- purrr::map(residues, parse_residue)
expect_identical(
purrr::map_chr(parsed, "mono"),
c(
DFuc = "D-Fuc",
DFucf = "D-Fucf",
LGul = "L-Gul",
DIdoA = "D-IdoA",
LNeu5Ac = "L-Neu5Ac",
LGul_unknown_ring = "L-Gul",
DFuc_ambiguous = "D-Fuc",
DFuc_alditol = "D-Fuc"
)
)
})
test_that("WURCS patterns cover every distinguishable unusual configuration", {
unusual_map <- unusual_configuration_monosaccharide_map()
concrete <- glyrepr::available_monosaccharides("concrete")
pattern_sets <- list(
WURCS_MONO_REGEX,
WURCS_UNKNOWN_RING_MONO_REGEX,
WURCS_AMBIGUOUS_MONO_REGEX,
WURCS_ALDITOL_MONO_REGEX
)
for (patterns in pattern_sets) {
natural_indices <- which(names(patterns) %in% names(unusual_map))
for (index in natural_indices) {
unusual_name <- unname(unusual_map[[names(patterns)[[index]]]])
unusual_pattern <- invert_wurcs_pattern_configuration(patterns[[index]])
matching_names <- names(patterns)[unname(patterns) == unusual_pattern]
expect_true(
unusual_name %in% matching_names || any(matching_names %in% concrete),
info = paste("missing unusual WURCS pattern for", unusual_name)
)
}
}
})
test_that("parse_residue recognizes GlycanFormatConverter alternate codes", {
residues <- c(
LGal_a = "a1221h-1a_1-5",
LGal_b = "a1221h-1b_1-5",
LGal_x = "a1221h-1x_1-5",
LGal_ambiguous = "u1221h",
LGul_a = "a1121h-1a_1-5",
LGul_x = "a1121h-1x_1-5",
LGul_ambiguous = "u1121h",
ManNAc_relative = "a5122h-1b_1-5_2*NCC/3=O"
)
expect_identical(
purrr::map_chr(residues, ~ parse_residue(.x)[["mono"]]),
c(
LGal_a = "L-Gal",
LGal_b = "L-Gal",
LGal_x = "L-Gal",
LGal_ambiguous = "L-Gal",
LGul_a = "L-Gul",
LGul_x = "L-Gul",
LGul_ambiguous = "L-Gul",
ManNAc_relative = "ManNAc"
)
)
})
test_that("parse_residue recognizes the xylHex encoding of Fuc", {
residues <- c(
a = "a12d1m-1a_1-5",
b = "a12d1m-1b_1-5",
unknown = "a12d1m-1x_1-5"
)
expect_identical(
purrr::map_chr(residues, ~ parse_residue(.x)[["mono"]]),
c(a = "Fuc", b = "Fuc", unknown = "Fuc")
)
})
test_that("specific unusual WURCS patterns take priority over generic fallbacks", {
expect_identical(
parse_residue("a2112m-1x_1-5_2*NCC/3=O")[["mono"]],
"D-FucNAc"
)
expect_identical(
parse_residue("a2112m-1x_1-4_2*NCC/3=O")[["mono"]],
"D-FucfNAc"
)
})
test_that("parse_residue raises an error with unkown monosaccharide", {
expect_error(
parse_residue("axxxxxh-1a_1-5"),
'Unable to parse residue: "axxxxxh-1a_1-5"'
)
})
test_that("parse_residue recognizes substituents on Glc", {
expect_equal(
parse_residue("a2122h-1a_1-5_3*OC"),
c(mono = "Glc", anomer = "a1", sub = "3Me")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OCC/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3Ac")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*NCC/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3NAc")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OPO/3O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3P")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*PO/2O/2=O"),
c(mono = "Glc", anomer = "a1", sub = "3P")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OSO/3=O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3S")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OCCC/4=O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3Pyr")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OPOCCNC/7C/7C/3O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3PC")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OPOPOCCN/5O/5=O/3O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3PPEtn")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*OPOCCN/3O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3PEtn")
)
expect_equal(
parse_residue("a2122h-1a_1-5_3*N"),
c(mono = "Glc", anomer = "a1", sub = "3N")
)
})
test_that("parse_residue recognizes multiple substituents", {
expect_equal(
parse_residue("a2122h-1a_1-5_3*OC_6*OSO/3=O/3=O"),
c(mono = "Glc", anomer = "a1", sub = "3Me,6S")
)
expect_equal(
parse_residue("Aad21122h-2a_2-6_4*OCC/3=O_5*NCC/3=O_9*OCC/3=O"),
c(mono = "Neu5Ac", anomer = "a2", sub = "4Ac,9Ac")
)
})
test_that("parse_residue recognizes substituents on complex monosaccharides", {
expect_equal(
parse_residue("a2122h-1a_1-5_2*NCC/3=O_3*N"),
c(mono = "GlcNAc", anomer = "a1", sub = "3N")
)
expect_equal(
parse_residue("a2122h-1a_1-5_2*NCC/3=O_3*NCC/3=O"),
c(mono = "GlcNAc", anomer = "a1", sub = "3NAc")
)
expect_equal(
parse_residue("a1221m-1a_1-5_4*OPO/3O/3=O"),
c(mono = "Fuc", anomer = "a1", sub = "4P")
)
})
test_that("parse_residue recognized substituents with known positions", {
expect_equal(
parse_residue("a2122h-1a_1-5_2*NCC/3=O_?*OC"),
c(mono = "GlcNAc", anomer = "a1", sub = "?Me")
)
expect_equal(
parse_residue("a2112h-1b_1-5_2*NCC/3=O_3|4*OSO/3=O/3=O"),
c(mono = "GalNAc", anomer = "b1", sub = "3/4S")
)
})
test_that("parse_residue raises an error with unkown substituent", {
expect_error(
parse_residue("a2122h-1a_1-5_3*OXXXX"),
'Unable to parse substituent: "_3\\*OXXXX"'
)
})
test_that("parse_residue correctly deals with anomers", {
expect_equal(
parse_residue("a2122h-1a_1-5"),
c(mono = "Glc", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2122h-1b_1-5"),
c(mono = "Glc", anomer = "b1", sub = "")
)
expect_equal(
parse_residue("a2122h-1x_1-5"),
c(mono = "Glc", anomer = "?1", sub = "")
)
})
test_that("parse_residue knows unkown anomers", {
expect_equal(
parse_residue("a2122h-1x_1-5"),
c(mono = "Glc", anomer = "?1", sub = "")
)
})
test_that("parse_residue knows unkown substituent linkages", {
expect_equal(
parse_residue("a2122h-1a_1-5_?*OC"),
c(mono = "Glc", anomer = "a1", sub = "?Me")
)
})
test_that("parse_residue handles ambiguous u residues", {
expect_ambiguous_residue <- function(residue, mono, sub = "") {
expect_equal(
parse_residue(residue),
c(mono = mono, anomer = "??", sub = sub)
)
}
purrr::iwalk(
c(
Glc = "u2122h",
Man = "u1122h",
Gal = "u2112h",
Gul = "u2212h",
Alt = "u2111h",
All = "u2222h",
Tal = "u1112h",
Ido = "u2121h",
GlcA = "u2122A",
ManA = "u1122A",
GalA = "u2112A",
GulA = "u2212A",
AltA = "u2111A",
AllA = "u2222A",
TalA = "u1112A",
IdoA = "u2121A",
Fuc = "u1221m",
Qui = "u2122m",
Rha = "u2211m",
`6dGul` = "u2212m",
`6dAlt` = "u2111m",
`6dTal` = "u1112m",
Oli = "ud122m",
Tyv = "u1d22m",
Abe = "u2d12m",
Par = "u2d22m",
Dig = "ud222m",
Col = "u1d21m",
Ara = "u211h",
Lyx = "u221h",
Xyl = "u212h",
Rib = "u222h"
),
~ expect_ambiguous_residue(.x, .y)
)
purrr::iwalk(
c(
GlcNAc = "u2122h_2*NCC/3=O",
ManNAc = "u1122h_2*NCC/3=O",
GalNAc = "u2112h_2*NCC/3=O",
GulNAc = "u2212h_2*NCC/3=O",
AltNAc = "u2111h_2*NCC/3=O",
AllNAc = "u2222h_2*NCC/3=O",
TalNAc = "u1112h_2*NCC/3=O",
IdoNAc = "u2121h_2*NCC/3=O",
FucNAc = "u1221m_2*NCC/3=O",
QuiNAc = "u2122m_2*NCC/3=O",
RhaNAc = "u2211m_2*NCC/3=O",
`6dAltNAc` = "u2111m_2*NCC/3=O",
`6dTalNAc` = "u1112m_2*NCC/3=O"
),
~ expect_ambiguous_residue(.x, .y)
)
purrr::iwalk(
c(
GlcN = "u2122h_2*N",
ManN = "u1122h_2*N",
GalN = "u2112h_2*N",
GulN = "u2212h_2*N",
AltN = "u2111h_2*N",
AllN = "u2222h_2*N",
TalN = "u1112h_2*N",
IdoN = "u2121h_2*N"
),
~ expect_ambiguous_residue(.x, .y)
)
purrr::pwalk(
list(
c(
"u2122A_2*NCC/3=O",
"u1122A_2*NCC/3=O",
"u2112A_2*NCC/3=O",
"u2212A_2*NCC/3=O",
"u2111A_2*NCC/3=O",
"u2222A_2*NCC/3=O",
"u1112A_2*NCC/3=O",
"u2121A_2*NCC/3=O",
"u2212m_2*NCC/3=O",
"ud122m_2*NCC/3=O",
"u1d22m_2*NCC/3=O",
"u2d12m_2*NCC/3=O",
"u2d22m_2*NCC/3=O",
"ud222m_2*NCC/3=O",
"u1d21m_2*NCC/3=O",
"u211h_2*NCC/3=O",
"u221h_2*NCC/3=O",
"u212h_2*NCC/3=O",
"u222h_2*NCC/3=O"
),
c(
"GlcA",
"ManA",
"GalA",
"GulA",
"AltA",
"AllA",
"TalA",
"IdoA",
"6dGul",
"Oli",
"Tyv",
"Abe",
"Par",
"Dig",
"Col",
"Ara",
"Lyx",
"Xyl",
"Rib"
),
"2NAc"
),
expect_ambiguous_residue
)
purrr::pwalk(
list(
c(
"u2122A_2*N",
"u1122A_2*N",
"u2112A_2*N",
"u2212A_2*N",
"u2111A_2*N",
"u2222A_2*N",
"u1112A_2*N",
"u2121A_2*N",
"u1221m_2*N",
"u2122m_2*N",
"u2211m_2*N",
"u2212m_2*N",
"u2111m_2*N",
"u1112m_2*N",
"ud122m_2*N",
"u1d22m_2*N",
"u2d12m_2*N",
"u2d22m_2*N",
"ud222m_2*N",
"u1d21m_2*N",
"u211h_2*N",
"u221h_2*N",
"u212h_2*N",
"u222h_2*N"
),
c(
"GlcA",
"ManA",
"GalA",
"GulA",
"AltA",
"AllA",
"TalA",
"IdoA",
"Fuc",
"Qui",
"Rha",
"6dGul",
"6dAlt",
"6dTal",
"Oli",
"Tyv",
"Abe",
"Par",
"Dig",
"Col",
"Ara",
"Lyx",
"Xyl",
"Rib"
),
"2N"
),
expect_ambiguous_residue
)
expect_ambiguous_residue(
"u2122h_2*NCC/3=O_?*OSO/3=O/3=O",
"GlcNAc",
"?S"
)
})
test_that("parse_residue maps generic WURCS descriptors to generic monosaccharides", {
expect_equal(
parse_residue("axxxxh-1x_1-5"),
c(mono = "Hex", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("axxxxh-1b_1-5_2*NCC/3=O"),
c(mono = "HexNAc", anomer = "b1", sub = "")
)
expect_equal(
parse_residue("uxxxxm"),
c(mono = "dHex", anomer = "??", sub = "")
)
expect_equal(
parse_residue("uxxxxh"),
c(mono = "Hex", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("uxxxxh_2*N"),
c(mono = "HexN", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("u2112m"),
c(mono = "D-Fuc", anomer = "??", sub = "")
)
expect_equal(
parse_residue("a2112m-1x_1-5_2*NCC/3=O"),
c(mono = "D-FucNAc", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("a4334m-1x_1-?"),
c(mono = "dHex", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("hxxxxh_2*NCC/3=O"),
c(mono = "HexNAc", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("AUd21122h_5*NCC/3=O"),
c(mono = "Neu5Ac", anomer = "??", sub = "")
)
expect_equal(
parse_residue("AUd21122h_4*OCC/3=O_5*NCC/3=O"),
c(mono = "Neu5Ac", anomer = "??", sub = "4Ac")
)
expect_equal(
parse_residue("AUd12211h_4*OCC/3=O_5*NCC/3=O"),
c(mono = "L-Neu5Ac", anomer = "??", sub = "4Ac")
)
})
test_that("parse_residue handles generic nonulosonic acids", {
expect_equal(
parse_residue("Aadxxxxxh-2x_2-6_5*NCC/3=O"),
c(mono = "NeuAc", anomer = "?2", sub = "")
)
expect_equal(
parse_residue("Aadxxxxxh-2a_2-6_5*NCCO/3=O"),
c(mono = "NeuGc", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("Aadxxxxxh-2a_2-6_4*OCC/3=O_5*NCC/3=O"),
c(mono = "NeuAc", anomer = "a2", sub = "4Ac")
)
expect_equal(
parse_residue("Aadxxxxxh-2x_2-?_4*OCC/3=O_5*NCCO/3=O"),
c(mono = "NeuGc", anomer = "?2", sub = "4Ac")
)
expect_equal(
parse_residue("AUdxxxxxh_4*OCC/3=O_5*N"),
c(mono = "gNeu", anomer = "??", sub = "4Ac")
)
expect_equal(
parse_residue("hUdxxxxxh_4*OCC/3=O_5*NCC/3=O"),
c(mono = "NeuAc", anomer = "?2", sub = "4Ac")
)
expect_equal(
parse_residue("AUdxxxxxh_5*N"),
c(mono = "gNeu", anomer = "??", sub = "")
)
expect_equal(
parse_residue("AUdxxxxxh"),
c(mono = "gKdn", anomer = "??", sub = "")
)
expect_equal(
parse_residue("hUdxxxxxh_5*NCC/3=O"),
c(mono = "NeuAc", anomer = "?2", sub = "")
)
result <- parse_wurcs(
"WURCS=2.0/1,1,0/[AUdxxxxxh_5*NCC/3=O]/1/"
)
expect_identical(unname(as.character(result)), "NeuAc(??-")
})
test_that("parse_residue preserves supported furanose ring closures", {
expect_equal(
parse_residue("a2112h-1a_1-4"),
c(mono = "Galf", anomer = "a1", sub = "")
)
expect_equal(
parse_residue("a2112h-1x_1-4_2*NCC/3=O"),
c(mono = "GalfNAc", anomer = "?1", sub = "")
)
expect_equal(
parse_residue("Aad21122h-2a_2-5_5*NCC/3=O"),
c(mono = "Neuf5Ac", anomer = "a2", sub = "")
)
expect_equal(
parse_residue("axxxxh-1x_1-4"),
c(mono = "Hex", anomer = "?1", sub = "")
)
result <- parse_wurcs(paste0(
"WURCS=2.0/2,3,2/",
"[a2112h-1b_1-5][a2112h-1a_1-4]/",
"1-2-2/a4-b1_b2-c1"
))
expect_identical(
unname(as.character(result)),
"Galf(a1-2)Galf(a1-4)Gal(b1-"
)
})
test_that("parse_residue handles unknown ring closure", {
expect_equal(
parse_residue("Aad21122h-2x_2-?_5*NCC/3=O"),
c(mono = "Neu5Ac", anomer = "?2", sub = "")
)
expect_equal(
parse_residue("Aad12211h-2a_2-?_4*OCC/3=O_5*NCC/3=O"),
c(mono = "L-Neu5Ac", anomer = "a2", sub = "4Ac")
)
expect_equal(
parse_residue("Aad12211h-2b_2-?_5*NCCO/3=O"),
c(mono = "L-Neu5Gc", anomer = "b2", sub = "")
)
expect_equal(
parse_residue("Aad21122h-2a_2-?_4*OCC/3=O_5*NCC/3=O"),
c(mono = "Neu5Ac", anomer = "a2", sub = "4Ac")
)
expect_equal(
parse_residue("Aad21122h-2x_2-?_4*OCC/3=O_5*N"),
c(mono = "Neu", anomer = "?2", sub = "4Ac")
)
expect_equal(
parse_residue("Aad21122h-2b_2-6_4*OCC/3=O_5*N"),
c(mono = "Neu", anomer = "b2", sub = "4Ac")
)
expect_unknown_ring_residue <- function(residue, mono, sub = "") {
expect_equal(
parse_residue(residue),
c(mono = mono, anomer = "?1", sub = sub)
)
}
purrr::iwalk(
c(
Glc = "a2122h-1x_1-?",
Man = "a1122h-1x_1-?",
Gal = "a2112h-1x_1-?",
Gul = "a2212h-1x_1-?",
Alt = "a2111h-1x_1-?",
All = "a2222h-1x_1-?",
Tal = "a1112h-1x_1-?",
Ido = "a2121h-1x_1-?",
GlcA = "a2122A-1x_1-?",
ManA = "a1122A-1x_1-?",
GalA = "a2112A-1x_1-?",
GulA = "a2212A-1x_1-?",
AltA = "a2111A-1x_1-?",
AllA = "a2222A-1x_1-?",
TalA = "a1112A-1x_1-?",
IdoA = "a2121A-1x_1-?",
Fuc = "a1221m-1x_1-?",
Qui = "a2122m-1x_1-?",
Rha = "a2211m-1x_1-?",
`6dGul` = "a2212m-1x_1-?",
`6dAlt` = "a2111m-1x_1-?",
`6dTal` = "a1112m-1x_1-?",
Oli = "ad122m-1x_1-?",
Tyv = "a1d22m-1x_1-?",
Abe = "a2d12m-1x_1-?",
Par = "a2d22m-1x_1-?",
Dig = "ad222m-1x_1-?",
Col = "a1d21m-1x_1-?",
Ara = "a211h-1x_1-?",
Lyx = "a221h-1x_1-?",
Xyl = "a212h-1x_1-?",
Rib = "a222h-1x_1-?"
),
~ expect_unknown_ring_residue(.x, .y)
)
purrr::iwalk(
c(
GlcNAc = "a2122h-1x_1-?_2*NCC/3=O",
ManNAc = "a1122h-1x_1-?_2*NCC/3=O",
GalNAc = "a2112h-1x_1-?_2*NCC/3=O",
GulNAc = "a2212h-1x_1-?_2*NCC/3=O",
AltNAc = "a2111h-1x_1-?_2*NCC/3=O",
AllNAc = "a2222h-1x_1-?_2*NCC/3=O",
TalNAc = "a1112h-1x_1-?_2*NCC/3=O",
IdoNAc = "a2121h-1x_1-?_2*NCC/3=O",
FucNAc = "a1221m-1x_1-?_2*NCC/3=O",
QuiNAc = "a2122m-1x_1-?_2*NCC/3=O",
RhaNAc = "a2211m-1x_1-?_2*NCC/3=O",
`6dAltNAc` = "a2111m-1x_1-?_2*NCC/3=O",
`6dTalNAc` = "a1112m-1x_1-?_2*NCC/3=O"
),
~ expect_unknown_ring_residue(.x, .y)
)
purrr::iwalk(
c(
GlcN = "a2122h-1x_1-?_2*N",
ManN = "a1122h-1x_1-?_2*N",
GalN = "a2112h-1x_1-?_2*N",
GulN = "a2212h-1x_1-?_2*N",
AltN = "a2111h-1x_1-?_2*N",
AllN = "a2222h-1x_1-?_2*N",
TalN = "a1112h-1x_1-?_2*N",
IdoN = "a2121h-1x_1-?_2*N"
),
~ expect_unknown_ring_residue(.x, .y)
)
purrr::pwalk(
list(
c(
"a2122A-1x_1-?_2*NCC/3=O",
"a1122A-1x_1-?_2*NCC/3=O",
"a2112A-1x_1-?_2*NCC/3=O",
"a2212A-1x_1-?_2*NCC/3=O",
"a2111A-1x_1-?_2*NCC/3=O",
"a2222A-1x_1-?_2*NCC/3=O",
"a1112A-1x_1-?_2*NCC/3=O",
"a2121A-1x_1-?_2*NCC/3=O",
"a2212m-1x_1-?_2*NCC/3=O",
"ad122m-1x_1-?_2*NCC/3=O",
"a1d22m-1x_1-?_2*NCC/3=O",
"a2d12m-1x_1-?_2*NCC/3=O",
"a2d22m-1x_1-?_2*NCC/3=O",
"ad222m-1x_1-?_2*NCC/3=O",
"a1d21m-1x_1-?_2*NCC/3=O",
"a211h-1x_1-?_2*NCC/3=O",
"a221h-1x_1-?_2*NCC/3=O",
"a212h-1x_1-?_2*NCC/3=O",
"a222h-1x_1-?_2*NCC/3=O"
),
c(
"GlcA",
"ManA",
"GalA",
"GulA",
"AltA",
"AllA",
"TalA",
"IdoA",
"6dGul",
"Oli",
"Tyv",
"Abe",
"Par",
"Dig",
"Col",
"Ara",
"Lyx",
"Xyl",
"Rib"
),
"2NAc"
),
expect_unknown_ring_residue
)
purrr::pwalk(
list(
c(
"a2122A-1x_1-?_2*N",
"a1122A-1x_1-?_2*N",
"a2112A-1x_1-?_2*N",
"a2212A-1x_1-?_2*N",
"a2111A-1x_1-?_2*N",
"a2222A-1x_1-?_2*N",
"a1112A-1x_1-?_2*N",
"a2121A-1x_1-?_2*N",
"a1221m-1x_1-?_2*N",
"a2122m-1x_1-?_2*N",
"a2211m-1x_1-?_2*N",
"a2212m-1x_1-?_2*N",
"a2111m-1x_1-?_2*N",
"a1112m-1x_1-?_2*N",
"ad122m-1x_1-?_2*N",
"a1d22m-1x_1-?_2*N",
"a2d12m-1x_1-?_2*N",
"a2d22m-1x_1-?_2*N",
"ad222m-1x_1-?_2*N",
"a1d21m-1x_1-?_2*N",
"a211h-1x_1-?_2*N",
"a221h-1x_1-?_2*N",
"a212h-1x_1-?_2*N",
"a222h-1x_1-?_2*N"
),
c(
"GlcA",
"ManA",
"GalA",
"GulA",
"AltA",
"AllA",
"TalA",
"IdoA",
"Fuc",
"Qui",
"Rha",
"6dGul",
"6dAlt",
"6dTal",
"Oli",
"Tyv",
"Abe",
"Par",
"Dig",
"Col",
"Ara",
"Lyx",
"Xyl",
"Rib"
),
"2N"
),
expect_unknown_ring_residue
)
})
test_that("letter_to_int handles uppercase WURCS residue IDs", {
expect_equal(letter_to_int("z"), 26)
expect_equal(letter_to_int("A"), 27)
expect_equal(letter_to_int("K"), 37)
expect_equal(
parse_one_linkage("a6-K1"),
list(from = 1, to = 37, linkage = "1-6")
)
})
test_that("parse_residue handles N-sulfate on amino sugars", {
expect_n_sulfate_residue <- function(residue, mono, anomer, sub = "2S") {
expect_equal(
parse_residue(residue),
c(mono = mono, anomer = anomer, sub = sub)
)
}
hexn_codes <- c(
GlcN = "2122h",
ManN = "1122h",
GalN = "2112h",
GulN = "2212h",
AltN = "2111h",
AllN = "2222h",
TalN = "1112h",
IdoN = "2121h"
)
purrr::iwalk(
hexn_codes,
~ expect_n_sulfate_residue(
stringr::str_glue("u{.x}_2*NSO/3=O/3=O"),
.y,
"??"
)
)
purrr::iwalk(
hexn_codes,
~ expect_n_sulfate_residue(
stringr::str_glue("a{.x}-1x_1-5_2*NSO/3=O/3=O"),
.y,
"?1"
)
)
purrr::iwalk(
hexn_codes,
~ expect_n_sulfate_residue(
stringr::str_glue("a{.x}-1x_1-?_2*NSO/3=O/3=O"),
.y,
"?1"
)
)
purrr::iwalk(
hexn_codes,
~ expect_n_sulfate_residue(
stringr::str_glue("u{.x}_2*NSO/3=O/3=O_6*OSO/3=O/3=O"),
.y,
"??",
"2S,6S"
)
)
expect_equal(
parse_residue("a2122h-1x_1-5_2*NSO/3=O/3=O_6*OSO/3=O/3=O"),
c(mono = "GlcN", anomer = "?1", sub = "2S,6S")
)
expect_equal(
parse_residue("a2122h-1x_1-?_2*NSO/3=O/3=O_6*OSO/3=O/3=O"),
c(mono = "GlcN", anomer = "?1", sub = "2S,6S")
)
})
test_that("parse_residue handles alditol residues", {
expect_alditol_residue <- function(residue, mono) {
anomer <- paste0("?", glyrepr::get_anomer_pos(mono))
expect_equal(
parse_residue(residue),
c(mono = mono, anomer = anomer, sub = "")
)
}
alditol_residues <- c(
Glc = "h2122h",
Man = "h1122h",
Gal = "h2112h",
Gul = "h2212h",
Alt = "h2221h",
All = "h2222h",
Tal = "h1222h",
Ido = "h2121h",
GlcNAc = "h2122h_2*NCC/3=O",
GalNAc = "h2112h_2*NCC/3=O",
ManNAc = "h1122h_2*NCC/3=O",
GulNAc = "h2212h_2*NCC/3=O",
AltNAc = "h2221h_5*NCC/3=O",
AllNAc = "h2222h_2*NCC/3=O",
TalNAc = "h1222h_5*NCC/3=O",
IdoNAc = "h2121h_2*NCC/3=O",
GlcN = "h2122h_2*N",
ManN = "h1122h_2*N",
GalN = "h2112h_2*N",
GulN = "h2212h_2*N",
AltN = "h2221h_5*N",
AllN = "h2222h_2*N",
TalN = "h1222h_5*N",
IdoN = "h2121h_2*N",
Fuc = "h1221m",
Qui = "h2122m",
Rha = "h2211m",
`6dGul` = "h2212m",
`6dAlt` = "h2111m",
`6dTal` = "h1112m",
FucNAc = "h1221m_2*NCC/3=O",
QuiNAc = "h2122m_2*NCC/3=O",
RhaNAc = "h2211m_2*NCC/3=O",
`6dAltNAc` = "h2111m_2*NCC/3=O",
`6dTalNAc` = "h1112m_2*NCC/3=O",
Oli = "hd122m",
Tyv = "h1d22m",
Abe = "h2d12m",
Par = "h2d22m",
Dig = "hd222m",
Col = "h1d21m",
Lyx = "h221h",
Xyl = "h212h",
Rib = "h222h",
Neu5Ac = "hUd21122h_5*NCC/3=O",
Neu5Gc = "hUd21122h_5*NCCO/3=O",
Kdn = "hUd21122h",
Neu = "hUd21122h_5*N",
Pse = "hUd22111m_5*N_7*N",
Leg = "hUd21122m_5*N_7*N",
Aci = "hUd21111m_5*N_7*N",
`4eLeg` = "hUd11122m_5*N_7*N",
Bac = "h2122m_2*N_4*N",
LDmanHep = "h21122h",
Kdo = "hUd1122h",
Dha = "A122dUh",
DDmanHep = "h11222h",
MurNAc = "h2122h_2*NCC/3=O_3*OC^RCO/4=O/3C",
MurNGc = "h2122h_2*NCCO/3=O_3*OC^RCO/4=O/3C",
Mur = "h2122h_3*OC^RCO/4=O/3C",
Fru = "hU122h",
Tag = "hU112h",
Sor = "hU121h",
Psi = "hU222h"
)
purrr::iwalk(alditol_residues, ~ expect_alditol_residue(.x, .y))
# GlycanFormatConverter emits h221h for both Ara-ol and Lyx-ol. WURCS
# canonicalizes that alditol descriptor back to Lyx-ol, so parse the distinct
# descriptor deterministically.
expect_alditol_residue("h221h", "Lyx")
})
test_that("parse_wurcs preserves alditols with unknown reducing-end anomers", {
glcnac_alditol <- "WURCS=2.0/1,1,0/[h2122h_2*NCC/3=O]/1/"
glcnac_structure <- parse_wurcs(glcnac_alditol)
expect_equal(as.character(glcnac_structure), "GlcNAc-ol(?1-")
expect_identical(unname(glyrepr::get_alditol(glcnac_structure)), TRUE)
linked_alditol <- "WURCS=2.0/2,2,1/[h2122h_2*NCC/3=O][a2112h-1b_1-5]/1-2/a4-b1"
linked_structure <- parse_wurcs(linked_alditol)
expect_equal(as.character(linked_structure), "Gal(b1-4)GlcNAc-ol(?1-")
expect_identical(unname(glyrepr::get_alditol(linked_structure)), TRUE)
})
test_that("parse_wurcs orients linkages away from reducing-end alditols", {
wurcs <- paste0(
"WURCS=2.0/2,2,1/",
"[a2112h-1b_1-5][h2122h_2*NCC/3=O]/",
"1-2/a1-b6"
)
expect_equal(
as.character(parse_wurcs(wurcs)),
"Gal(b1-6)GlcNAc-ol(?1-"
)
})
test_that("parse_wurcs collapses mixed known and unknown linkage positions", {
expect_equal(
parse_one_linkage(
"b4|b?-c1",
anomers = c("?1", "?1", "b1"),
alditols = rep(FALSE, 3)
),
list(from = 2, to = 3, linkage = "1-?")
)
})
test_that("WURCS corpus substituent encodings remain parseable", {
direct_phosphate <- paste0(
"WURCS=2.0/4,9,8/",
"[a2122h-1b_1-5_2*NCC/3=O][a1122h-1b_1-5]",
"[a1122h-1a_1-5][a1122h-1a_1-5_6*PO/2O/2=O]/",
"1-1-2-3-3-3-3-3-4/",
"a4-b1_b4-c1_c3-d1_c6-f1_d2-e1_f3-g1_f6-h1_h2-i1"
)
alternative_sulfate <- paste0(
"WURCS=2.0/4,9,8/",
"[a2122h-1b_1-5_2*NCC/3=O][a1122h-1b_1-5]",
"[a1122h-1a_1-5]",
"[a2112h-1b_1-5_2*NCC/3=O_3|4*OSO/3=O/3=O]/",
"1-1-2-3-1-4-3-3-3/",
"a4-b1_b4-c1_c3-d1_c6-g1_d2-e1_e4-f1_g3-h1_g6-i1"
)
expect_equal(
as.character(parse_wurcs(direct_phosphate)),
paste0(
"Man6P(a1-2)Man(a1-6)[Man(a1-3)]Man(a1-6)",
"[Man(a1-2)Man(a1-3)]Man(b1-4)GlcNAc(b1-4)GlcNAc(b1-"
)
)
expect_equal(
as.character(parse_wurcs(alternative_sulfate)),
paste0(
"GalNAc3/4S(b1-4)GlcNAc(b1-2)Man(a1-3)",
"[Man(a1-3)[Man(a1-6)]Man(a1-6)]Man(b1-4)",
"GlcNAc(b1-4)GlcNAc(b1-"
)
)
})
test_that("parse_wurcs warns when non-reducing alditols are normalized", {
non_reducing_alditol <- "WURCS=2.0/2,2,1/[a2122h-1a_1-5][h2112h]/1-2/a4-b1"
expect_warning(
structure <- parse_wurcs(non_reducing_alditol),
"Only the main reducing-end WURCS residue"
)
expect_identical(as.character(structure), "Gal(?1-4)Glc(a1-")
expect_identical(unname(glyrepr::get_alditol(structure)), FALSE)
root_and_non_reducing_alditols <-
"WURCS=2.0/2,2,1/[h2122h][h2112h]/1-2/a4-b1"
expect_warning(
structure <- parse_wurcs(root_and_non_reducing_alditols),
"Only the main reducing-end WURCS residue"
)
expect_identical(as.character(structure), "Gal(?1-4)Glc-ol(?1-")
expect_identical(unname(glyrepr::get_alditol(structure)), TRUE)
})
test_that("parse_wurcs correctly handles unknown linkages", {
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[a2112h-1a_1-5_2*NCC/3=O][a2112h-1a_1-5]/1-2/b1-a3|a4"
)),
"Gal(a1-3/4)GalNAc(a1-"
)
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[a2112h-1a_1-5_2*NCC/3=O][a2112h-1a_1-5]/1-2/a?-b1"
)),
"Gal(a1-?)GalNAc(a1-"
)
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[a2112h-1a_1-5_2*NCC/3=O][a2112h-1a_1-5]/1-2/a3-b?"
)),
"Gal(a?-3)GalNAc(a1-"
)
})
test_that("parse_wurcs supports implicit floating parts", {
wurcs <- paste0(
"WURCS=2.0/3,3,2/",
"[a2122h-1x_1-5][a2112h-1b_1-5]",
"[Aad21122h-2a_2-6_5*NCC/3=O]/",
"1-2-3/a4-b1_c2-a6|b6}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"{Neu5Ac(a2-6)}Gal(b1-4)Glc(?1-"
)
expect_equal(
glyrepr::structure_floating_parts(result)$parents,
list(integer())
)
})
test_that("parse_wurcs compares floating acceptor positions as sets", {
wurcs <- paste0(
"WURCS=2.0/3,3,2/",
"[a2122h-1x_1-5][a2112h-1b_1-5]",
"[Aad21122h-2a_2-6_5*NCC/3=O]/",
"1-2-3/a4-b1_c2-a3|a6|b6|b3}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"{Neu5Ac(a2-3/6)}Gal(b1-4)Glc(?1-"
)
})
test_that("parse_wurcs supports floating parts without ordinary linkages", {
wurcs <- paste0(
"WURCS=2.0/2,2,1/",
"[a2122h-1x_1-5][Aad21122h-2a_2-6_5*NCC/3=O]/",
"1-2/b2-a6}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"Neu5Ac(a2-6)Glc(?1-"
)
expect_identical(unname(glyrepr::has_floating_parts(result)), FALSE)
})
test_that("parse_wurcs preserves multiple floating subtrees", {
wurcs <- paste0(
"WURCS=2.0/4,5,4/",
"[a2122h-1x_1-5][a2112h-1b_1-5]",
"[a2122h-1b_1-5_2*NCC/3=O][a1221m-1a_1-5]/",
"1-2-3-2-4/a4-b1_c4-d1_c1-a3|b3}_e1-a6|b6}"
)
result <- parse_wurcs(wurcs)
floating <- glyrepr::structure_floating_parts(result)
expect_identical(
unname(as.character(result)),
paste0(
"{Fuc(a1-6)|4,5}",
"{Gal(b1-4)GlcNAc(b1-3)|4,5}",
"Gal(b1-4)Glc(?1-"
)
)
expect_equal(floating$nodes, list(1L, c(2L, 3L)))
expect_equal(floating$parents, list(c(4L, 5L), c(4L, 5L)))
})
test_that("parse_wurcs preserves cross-component floating parents", {
wurcs <- paste0(
"WURCS=2.0/4,5,4/",
"[a2122h-1x_1-5][a2112h-1b_1-5]",
"[a2122h-1b_1-5_2*NCC/3=O][a1221m-1a_1-5]/",
"1-2-3-2-4/a4-b1_c4-d1_c1-a3|e3}_e1-a6|b6}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
paste0(
"{Fuc(a1-6)|4,5}",
"{Gal(b1-4)GlcNAc(b1-3)|1,5}",
"Gal(b1-4)Glc(?1-"
)
)
expect_equal(
glyrepr::structure_floating_parts(result)$parents,
list(c(4L, 5L), c(1L, 5L))
)
})
test_that("parse_wurcs supports floating substituents", {
restricted <- paste0(
"WURCS=2.0/3,3,3/",
"[a2112h-1a_1-5][a2122h-1a_1-5][a1122h-1a_1-5]/",
"1-2-3/b3|c3}*OSO/3=O/3=O_a3-b1_b4-c1"
)
multiple <- paste0(
"WURCS=2.0/3,3,4/",
"[a2112h-1a_1-5][a2122h-1a_1-5][a1122h-1a_1-5]/",
"1-2-3/a?|b?|c?}*OPO/3O/3=O_",
"a?|b?|c?}*OSO/3=O/3=O_a3-b1_b4-c1"
)
restricted_result <- parse_wurcs(restricted)
multiple_result <- parse_wurcs(multiple)
expect_identical(
unname(as.character(restricted_result)),
"{3S|1,2}Man(a1-4)Glc(a1-3)Gal(a1-"
)
expect_equal(
glyrepr::structure_floating_substituents(
restricted_result
)$parents,
list(c(1L, 2L))
)
expect_identical(
unname(as.character(multiple_result)),
"{?P}{?S}Man(a1-4)Glc(a1-3)Gal(a1-"
)
})
test_that("parse_wurcs supports floating parts and substituents together", {
wurcs <- paste0(
"WURCS=2.0/3,3,3/",
"[a2122h-1x_1-5][a2112h-1b_1-5]",
"[Aad21122h-2a_2-6_5*NCC/3=O]/",
"1-2-3/a4-b1_a?|b?}*OSO/3=O/3=O_c2-a6|b6}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"{?S|2,3}{Neu5Ac(a2-6)}Gal(b1-4)Glc(?1-"
)
expect_identical(
glyrepr::structure_floating_substituents(result)$substituent,
"?S"
)
expect_identical(
glyrepr::structure_floating_parts(result)$linkage,
"a2-6"
)
expect_equal(
glyrepr::structure_floating_substituents(result)$parents,
list(c(2L, 3L))
)
})
test_that("parse_wurcs preserves floating substituent parents across components", {
wurcs <- paste0(
"WURCS=2.0/3,3,3/",
"[a2122h-1x_1-5][a2112h-1b_1-5]",
"[Aad21122h-2a_2-6_5*NCC/3=O]/",
"1-2-3/a4-b1_a?|c?}*OSO/3=O/3=O_c2-a6|b6}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"{?S|1,3}{Neu5Ac(a2-6)}Gal(b1-4)Glc(?1-"
)
expect_equal(
glyrepr::structure_floating_substituents(result)$parents,
list(c(1L, 3L))
)
})
test_that("parse_wurcs maps floating substituent chemistry", {
codes <- c(
Me = "OC",
Ac = "OCC/3=O",
P = "OPO/3O/3=O",
S = "OSO/3=O/3=O",
PEtn = "OP^XOCCN/3O/3=O"
)
parsed <- purrr::map_chr(codes, function(code) {
linkage <- paste0("a?|b?}*", code)
parse_wurcs_floating_linkage(linkage)$metadata$substituent
})
ambiguous <- parse_wurcs_floating_linkage(
"a6|a4|b4|b6}*OSO/3=O/3=O"
)
n_sulfate <- parse_wurcs_floating_linkage(
"a2}*NSO/3=O/3=O"
)
expect_identical(
unname(parsed),
paste0("?", names(codes))
)
expect_identical(ambiguous$metadata$substituent, "4/6S")
expect_identical(n_sulfate$metadata$substituent, "2S")
})
test_that("single-parent WURCS floating substituents become ordinary", {
wurcs <- paste0(
"WURCS=2.0/1,1,1/[a2112h-1a_1-5]/1/",
"a3}*OSO/3=O/3=O"
)
result <- parse_wurcs(wurcs)
expect_identical(unname(as.character(result)), "Gal3S(a1-")
expect_identical(
unname(glyrepr::has_floating_substituents(result)),
FALSE
)
})
test_that("floating WURCS N-sulfates use sulfate chemistry", {
wurcs <- paste0(
"WURCS=2.0/1,1,1/[a2112h-1a_1-5]/1/",
"a2}*NSO/3=O/3=O"
)
result <- parse_wurcs(wurcs)
expect_identical(unname(as.character(result)), "Gal2S(a1-")
})
test_that("all-main WURCS substituent candidates exclude occupied slots", {
wurcs <- paste0(
"WURCS=2.0/2,2,2/",
"[a2112h-1a_1-5][a2122h-1a_1-5]/",
"1-2/a3-b1_a3|b3}*OSO/3=O/3=O"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"Glc3S(a1-3)Gal(a1-"
)
expect_identical(
unname(glyrepr::has_floating_substituents(result)),
FALSE
)
})
test_that("parse_wurcs orients uncertain edges inside floating subtrees", {
wurcs <- paste0(
"WURCS=2.0/4,4,3/",
"[a2122h-1x_1-5][a2112h-1x_1-5]",
"[a2122h-1b_1-5_2*NCC/3=O][a1122h-1a_1-5]/",
"1-2-3-4/a4-d1_b?-c4_c1-a3|b3|c3|d3}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"{Gal(??-4)GlcNAc(b1-3)}Man(a1-4)Glc(?1-"
)
expect_equal(
glyrepr::structure_floating_parts(result)$parents,
list(integer())
)
})
test_that("parse_wurcs removes occupied explicit parents", {
wurcs <- paste0(
"WURCS=2.0/4,4,3/",
"[a2112h-1x_1-5][a2122h-1b_1-5]",
"[a1122h-1a_1-5][a1221m-1a_1-5]/",
"1-2-3-4/a4-b1_a3-c1_d1-a3|b3}"
)
result <- parse_wurcs(wurcs)
expect_identical(
unname(as.character(result)),
"Fuc(a1-3)Glc(b1-4)[Man(a1-3)]Gal(?1-"
)
expect_identical(unname(glyrepr::has_floating_parts(result)), FALSE)
})
test_that("parse_wurcs handles ambiguous u residues", {
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/3,4,3/[u2122h][a2112h-1b_1-5][a2122h-1b_1-5_2*NCC/3=O]/1-2-3-2/a4-b1_b3-c1_c4-d1"
)),
"Gal(b1-4)GlcNAc(b1-3)Gal(b1-4)Glc(??-"
)
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[u2112h_2*NCC/3=O][a2112h-1a_1-5_2*NCC/3=O]/1-2/a6-b1"
)),
"GalNAc(a1-6)GalNAc(??-"
)
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[u2122A][a2122h-1x_1-5_2*NCC/3=O]/1-2/a?-b1"
)),
"GlcNAc(?1-?)GlcA(??-"
)
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[u2112h][a2122h-1x_1-5]/1-2/a2-b3|b4"
)),
"Gal(?2-3/4)Glc(?1-"
)
})
test_that("parse_wurcs handles unknown ring closure", {
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/5,6,5/[a2122h-1x_1-?_2*NCC/3=O][a1221m-1a_1-5][a2122h-1b_1-5_2*NCC/3=O][a1122h-1b_1-5][a1122h-1a_1-5]/1-2-3-4-5-5/a4-c1_c4-d1_d3-e1_d6-f1_a?-b1"
)),
"Man(a1-3)[Man(a1-6)]Man(b1-4)GlcNAc(b1-4)[Fuc(a1-?)]GlcNAc(?1-"
)
})
test_that("parse_wurcs handles N-sulfate on amino sugars", {
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[u2122h_2*NSO/3=O/3=O][a2122A-1x_1-5]/1-2/a?-b1"
)),
"GlcA(?1-?)GlcN2S(??-"
)
expect_equal(
as.character(parse_wurcs(
"WURCS=2.0/2,2,1/[u2122A][a2122h-1x_1-5_2*NSO/3=O/3=O]/1-2/a?-b1"
)),
"GlcN2S(?1-?)GlcA(??-"
)
structure <- parse_wurcs(
"WURCS=2.0/1,1,0/[u2122h_2*NSO/3=O/3=O_6*OSO/3=O/3=O]/1/"
)
graph <- glyrepr::get_structure_graphs(structure)
expect_equal(igraph::vertex_attr(graph, "mono"), "GlcN")
expect_equal(igraph::vertex_attr(graph, "sub"), "2S,6S")
expect_equal(graph$anomer, "??")
})
test_that("anomer is corrected", {
expect_anomer <- function(wurcs, anomer) {
structure <- parse_wurcs(wurcs)
graph <- glyrepr::get_structure_graphs(structure)
expect_equal(graph$anomer, anomer)
}
wurcs_a <- "WURCS=2.0/2,2,1/[a2122h-1a_1-5_2*NCC/3=O][a2122h-1b_1-5_2*NCC/3=O]/1-2/a4-b1"
wurcs_b <- "WURCS=2.0/2,2,1/[a2122h-1b_1-5_2*NCC/3=O][a2122h-1a_1-5_2*NCC/3=O]/1-2/a4-b1"
wurcs_x <- "WURCS=2.0/2,2,1/[a2122h-1x_1-5_2*NCC/3=O][a2122h-1a_1-5_2*NCC/3=O]/1-2/a4-b1"
expect_anomer(wurcs_a, "a1")
expect_anomer(wurcs_b, "b1")
expect_anomer(wurcs_x, "?1")
})
test_that("glycan with only one monosacharide", {
wurcs <- "WURCS=2.0/1,1,0/[a2122h-1b_1-5_2*NCC/3=O]/1/"
expect_snapshot(parse_wurcs(wurcs))
})
test_that("parse_wurcs parses shared residue descriptors once per call", {
input <- c(
"WURCS=2.0/1,1,0/[a2122h-1a_1-5]/1/",
"WURCS=2.0/1,2,1/[a2122h-1a_1-5]/1-1/a1-b1"
)
records <- native_records_cpp(input, "wurcs", native_vocabulary())
expect_identical(attr(records, "residue_parses"), 1L)
expect_false(any(is.na(parse_wurcs(input))))
})
# A basic example
test_that("N-glycan core", {
wurcs <- "WURCS=2.0/4,5,4/[a2122h-1x_1-5_2*NCC/3=O][a2122h-1b_1-5_2*NCC/3=O][a1122h-1b_1-5][a1122h-1a_1-5]/1-2-3-4-4/a4-b1_b4-c1_c3-d1_c6-e1"
expect_snapshot(parse_wurcs(wurcs))
})
# A more complex example
test_that("H5H4F1S2", {
wurcs <- "WURCS=2.0/6,12,11/[a2122h-1b_1-5_2*NCC/3=O][a1122h-1b_1-5][a1122h-1a_1-5][a2112h-1b_1-5][Aad21122h-2a_2-6_5*NCC/3=O][a1221m-1a_1-5]/1-1-2-3-1-4-5-3-1-4-5-6/a4-b1_a6-l1_b4-c1_c3-d1_c6-h1_d2-e1_e4-f1_f3-g2_h2-i1_i4-j1_j3-k2"
expect_snapshot(parse_wurcs(wurcs))
})
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.