|
1 | | -"""Tests for Haplotype.reference_mapping coordinate translation in remap_divref.""" |
| 1 | +"""Tests for remap_divref models and helper functions.""" |
2 | 2 |
|
3 | 3 | from typing import Any |
4 | 4 |
|
| 5 | +import pytest |
| 6 | + |
5 | 7 | from divref.tools.remap_divref import Haplotype |
6 | 8 | from divref.tools.remap_divref import ReferenceMapping |
| 9 | +from divref.tools.remap_divref import Variant |
| 10 | +from divref.tools.remap_divref import _parse_pop_freqs |
7 | 11 |
|
8 | 12 |
|
9 | 13 | def create_haplotype( |
@@ -156,3 +160,150 @@ def test_large_insertion_with_null_frequencies() -> None: |
156 | 160 | "nfe": [0.0], |
157 | 161 | "sas": [0.0], |
158 | 162 | } |
| 163 | + |
| 164 | + |
| 165 | +# --------------------------------------------------------------------------- |
| 166 | +# Variant.render |
| 167 | +# --------------------------------------------------------------------------- |
| 168 | + |
| 169 | + |
| 170 | +def test_variant_render_snp() -> None: |
| 171 | + assert Variant(chromosome="chr1", position=100, reference="A", alternate="T").render() == ( |
| 172 | + "chr1:100:A:T" |
| 173 | + ) |
| 174 | + |
| 175 | + |
| 176 | +def test_variant_render_insertion() -> None: |
| 177 | + assert Variant(chromosome="chr2", position=200, reference="A", alternate="ATG").render() == ( |
| 178 | + "chr2:200:A:ATG" |
| 179 | + ) |
| 180 | + |
| 181 | + |
| 182 | +def test_variant_render_deletion() -> None: |
| 183 | + assert Variant(chromosome="chrX", position=300, reference="ATG", alternate="A").render() == ( |
| 184 | + "chrX:300:ATG:A" |
| 185 | + ) |
| 186 | + |
| 187 | + |
| 188 | +# --------------------------------------------------------------------------- |
| 189 | +# Haplotype.parsed_variants and .contig |
| 190 | +# --------------------------------------------------------------------------- |
| 191 | + |
| 192 | + |
| 193 | +def test_parsed_variants_single() -> None: |
| 194 | + hap = create_haplotype(variants="chr1:100:A:T", n_variants=1) |
| 195 | + vs = hap.parsed_variants() |
| 196 | + assert len(vs) == 1 |
| 197 | + assert vs[0].chromosome == "chr1" |
| 198 | + assert vs[0].position == 100 |
| 199 | + assert vs[0].reference == "A" |
| 200 | + assert vs[0].alternate == "T" |
| 201 | + |
| 202 | + |
| 203 | +def test_parsed_variants_multiple() -> None: |
| 204 | + hap = create_haplotype(variants="chr1:100:A:T,chr1:200:CC:G", n_variants=2) |
| 205 | + vs = hap.parsed_variants() |
| 206 | + assert len(vs) == 2 |
| 207 | + assert vs[1].position == 200 |
| 208 | + assert vs[1].reference == "CC" |
| 209 | + |
| 210 | + |
| 211 | +def test_parsed_variants_cached() -> None: |
| 212 | + # Second call returns the exact same list object (no re-parsing) |
| 213 | + hap = create_haplotype(variants="chr1:100:A:T,chr1:200:C:G", n_variants=2) |
| 214 | + assert hap.parsed_variants() is hap.parsed_variants() |
| 215 | + |
| 216 | + |
| 217 | +def test_contig_returns_first_variant_chromosome() -> None: |
| 218 | + hap = create_haplotype(variants="chr5:100:A:T,chr5:200:C:G", n_variants=2) |
| 219 | + assert hap.contig() == "chr5" |
| 220 | + |
| 221 | + |
| 222 | +# --------------------------------------------------------------------------- |
| 223 | +# ReferenceMapping.variants_involved_str |
| 224 | +# --------------------------------------------------------------------------- |
| 225 | + |
| 226 | + |
| 227 | +def test_variants_involved_str_empty() -> None: |
| 228 | + rm = ReferenceMapping( |
| 229 | + chromosome="chr1", |
| 230 | + start=100, |
| 231 | + end=200, |
| 232 | + variants_involved=[], |
| 233 | + first_variant_index=None, |
| 234 | + last_variant_index=None, |
| 235 | + population_frequencies={}, |
| 236 | + ) |
| 237 | + assert rm.variants_involved_str() == "" |
| 238 | + |
| 239 | + |
| 240 | +def test_variants_involved_str_single() -> None: |
| 241 | + rm = ReferenceMapping( |
| 242 | + chromosome="chr1", |
| 243 | + start=100, |
| 244 | + end=200, |
| 245 | + variants_involved=[Variant(chromosome="chr1", position=150, reference="A", alternate="T")], |
| 246 | + first_variant_index=0, |
| 247 | + last_variant_index=0, |
| 248 | + population_frequencies={}, |
| 249 | + ) |
| 250 | + assert rm.variants_involved_str() == "chr1:150:A:T" |
| 251 | + |
| 252 | + |
| 253 | +def test_variants_involved_str_multiple() -> None: |
| 254 | + rm = ReferenceMapping( |
| 255 | + chromosome="chr1", |
| 256 | + start=100, |
| 257 | + end=300, |
| 258 | + variants_involved=[ |
| 259 | + Variant(chromosome="chr1", position=150, reference="A", alternate="T"), |
| 260 | + Variant(chromosome="chr1", position=200, reference="CC", alternate="C"), |
| 261 | + ], |
| 262 | + first_variant_index=0, |
| 263 | + last_variant_index=1, |
| 264 | + population_frequencies={}, |
| 265 | + ) |
| 266 | + assert rm.variants_involved_str() == "chr1:150:A:T,chr1:200:CC:C" |
| 267 | + |
| 268 | + |
| 269 | +# --------------------------------------------------------------------------- |
| 270 | +# _parse_pop_freqs |
| 271 | +# --------------------------------------------------------------------------- |
| 272 | + |
| 273 | + |
| 274 | +def test_parse_pop_freqs_all_floats() -> None: |
| 275 | + assert _parse_pop_freqs("0.1,0.2,0.3") == [0.1, 0.2, 0.3] |
| 276 | + |
| 277 | + |
| 278 | +def test_parse_pop_freqs_nulls_become_zero() -> None: |
| 279 | + assert _parse_pop_freqs("0.1,null,0.3") == [0.1, 0.0, 0.3] |
| 280 | + |
| 281 | + |
| 282 | +def test_parse_pop_freqs_single_null() -> None: |
| 283 | + assert _parse_pop_freqs("null") == [0.0] |
| 284 | + |
| 285 | + |
| 286 | +# --------------------------------------------------------------------------- |
| 287 | +# Error paths: malformed variant strings |
| 288 | +# --------------------------------------------------------------------------- |
| 289 | + |
| 290 | + |
| 291 | +def test_parsed_variants_empty_string_raises() -> None: |
| 292 | + # variants="" yields one empty token which cannot be split into 4 fields. |
| 293 | + hap = create_haplotype(variants="", n_variants=0) |
| 294 | + with pytest.raises(ValueError): |
| 295 | + hap.parsed_variants() |
| 296 | + |
| 297 | + |
| 298 | +def test_parsed_variants_too_few_fields_raises() -> None: |
| 299 | + # "chr1:100:A" has only 3 colon-delimited fields; unpacking into 4 raises ValueError. |
| 300 | + hap = create_haplotype(variants="chr1:100:A", n_variants=1) |
| 301 | + with pytest.raises(ValueError): |
| 302 | + hap.parsed_variants() |
| 303 | + |
| 304 | + |
| 305 | +def test_contig_malformed_variants_raises() -> None: |
| 306 | + # contig() delegates to parsed_variants(), so a malformed string propagates the error. |
| 307 | + hap = create_haplotype(variants="", n_variants=0) |
| 308 | + with pytest.raises(ValueError): |
| 309 | + hap.contig() |
0 commit comments