Skip to content

Commit 31c34d2

Browse files
Improved test coverage of Python C code.
1 parent e135059 commit 31c34d2

File tree

3 files changed

+151
-10
lines changed

3 files changed

+151
-10
lines changed

c/tsk_genotypes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ tsk_hapgen_get_haplotype(tsk_hapgen_t *self, tsk_id_t sample_index, char **haplo
180180
{
181181
int ret = 0;
182182

183-
if (sample_index >= (tsk_id_t) self->num_samples) {
183+
if (sample_index < 0 || sample_index >= (tsk_id_t) self->num_samples) {
184184
ret = TSK_ERR_OUT_OF_BOUNDS;
185185
goto out;
186186
}

python/_tskitmodule.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,6 @@ handle_library_error(int err)
195195
case TSK_ERR_FILE_FORMAT:
196196
PyErr_SetString(TskitFileFormatError, tsk_strerror(err));
197197
break;
198-
case TSK_ERR_OUT_OF_BOUNDS:
199-
PyErr_SetString(PyExc_IndexError, tsk_strerror(err));
200-
break;
201198
default:
202199
PyErr_SetString(TskitLibraryError, tsk_strerror(err));
203200
}
@@ -6167,6 +6164,7 @@ TreeSequence_get_pairwise_diversity(TreeSequence *self, PyObject *args, PyObject
61676164
&PyList_Type, &py_samples)) {
61686165
goto out;
61696166
}
6167+
/* TODO Change this to reading numpy array */
61706168
if (parse_sample_ids(py_samples, self->tree_sequence, &num_samples, &samples) != 0) {
61716169
goto out;
61726170
}
@@ -7893,16 +7891,16 @@ HaplotypeGenerator_get_haplotype(HaplotypeGenerator *self, PyObject *args)
78937891
int err;
78947892
PyObject *ret = NULL;
78957893
char *haplotype;
7896-
unsigned int sample_id;
7894+
int sample_id;
78977895

78987896
if (HaplotypeGenerator_check_state(self) != 0) {
78997897
goto out;
79007898
}
7901-
if (!PyArg_ParseTuple(args, "I", &sample_id)) {
7899+
if (!PyArg_ParseTuple(args, "i", &sample_id)) {
79027900
goto out;
79037901
}
79047902
err = tsk_hapgen_get_haplotype(self->haplotype_generator,
7905-
(uint32_t) sample_id, &haplotype);
7903+
(tsk_id_t) sample_id, &haplotype);
79067904
if (err != 0) {
79077905
handle_library_error(err);
79087906
goto out;
@@ -8203,6 +8201,9 @@ LdCalculator_get_r2(LdCalculator *self, PyObject *args)
82038201
return ret;
82048202
}
82058203

8204+
/* TODO this implementation is brittle and cumbersome. Replace with something that
8205+
* returns a numpy array directly. Passing in the memory is a premature optimisation.
8206+
*/
82068207
static PyObject *
82078208
LdCalculator_get_r2_array(LdCalculator *self, PyObject *args, PyObject *kwds)
82088209
{

python/tests/test_lowlevel.py

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def verify_tree_dict(self, n, pi):
8888
self.assertGreaterEqual(num_children[j], 2)
8989

9090
def get_example_tree_sequence(self):
91-
ts = msprime.simulate(10, recombination_rate=0.1, random_seed=1)
91+
ts = msprime.simulate(10, recombination_rate=0.1, mutation_rate=1, random_seed=1)
9292
return ts.ll_tree_sequence
9393

9494
def get_example_tree_sequences(self):
@@ -288,8 +288,8 @@ def test_get_samples(self):
288288
def test_pairwise_diversity(self):
289289
for ts in self.get_example_tree_sequences():
290290
for bad_type in ["", None, {}]:
291-
self.assertRaises(
292-
TypeError, ts.get_pairwise_diversity, bad_type)
291+
self.assertRaises(TypeError, ts.get_pairwise_diversity, bad_type)
292+
self.assertRaises(TypeError, ts.get_pairwise_diversity, [0, bad_type])
293293
self.assertRaises(
294294
ValueError, ts.get_pairwise_diversity, [])
295295
self.assertRaises(
@@ -419,6 +419,121 @@ def test_iterator(self):
419419
self.verify_iterator(_tskit.TreeIterator(tree))
420420

421421

422+
class TestVcfConverter(LowLevelTestCase):
423+
"""
424+
Tests for the VcfConverter class.
425+
"""
426+
def test_uninitialised_tree_sequence(self):
427+
ts = _tskit.TreeSequence()
428+
self.assertRaises(ValueError, _tskit.VcfConverter, ts)
429+
430+
def test_constructor(self):
431+
self.assertRaises(TypeError, _tskit.VcfConverter)
432+
self.assertRaises(TypeError, _tskit.VcfConverter, None)
433+
ts = self.get_example_tree_sequence()
434+
self.assertRaises(TypeError, _tskit.VcfConverter, ts, ploidy="xyt")
435+
self.assertRaises(ValueError, _tskit.VcfConverter, ts, ploidy=0)
436+
self.assertRaises(TypeError, _tskit.VcfConverter, ts, contig_id=None)
437+
self.assertRaises(ValueError, _tskit.VcfConverter, ts, contig_id="")
438+
439+
def test_iterator(self):
440+
ts = self.get_example_tree_sequence()
441+
self.verify_iterator(_tskit.VcfConverter(ts))
442+
443+
444+
class TestVariantGenerator(LowLevelTestCase):
445+
"""
446+
Tests for the VariantGenerator class.
447+
"""
448+
def test_uninitialised_tree_sequence(self):
449+
ts = _tskit.TreeSequence()
450+
self.assertRaises(ValueError, _tskit.VariantGenerator, ts)
451+
452+
def test_constructor(self):
453+
self.assertRaises(TypeError, _tskit.VariantGenerator)
454+
self.assertRaises(TypeError, _tskit.VariantGenerator, None)
455+
ts = self.get_example_tree_sequence()
456+
self.assertRaises(ValueError, _tskit.VariantGenerator, ts, samples={})
457+
self.assertRaises(
458+
_tskit.LibraryError, _tskit.VariantGenerator, ts, samples=[-1, 2])
459+
460+
def test_iterator(self):
461+
ts = self.get_example_tree_sequence()
462+
self.verify_iterator(_tskit.VariantGenerator(ts))
463+
464+
465+
class TestHaplotypeGenerator(LowLevelTestCase):
466+
"""
467+
Tests for the HaplotypeGenerator class.
468+
"""
469+
def test_uninitialised_tree_sequence(self):
470+
ts = _tskit.TreeSequence()
471+
self.assertRaises(ValueError, _tskit.HaplotypeGenerator, ts)
472+
473+
def test_constructor(self):
474+
self.assertRaises(TypeError, _tskit.HaplotypeGenerator)
475+
self.assertRaises(TypeError, _tskit.HaplotypeGenerator, None)
476+
477+
def test_bad_id(self):
478+
ts = self.get_example_tree_sequence()
479+
hg = _tskit.HaplotypeGenerator(ts)
480+
n = ts.get_num_samples()
481+
for bad_id in [-1, n, n + 1]:
482+
with self.assertRaises(_tskit.LibraryError):
483+
hg.get_haplotype(bad_id)
484+
485+
486+
class TestLdCalculator(LowLevelTestCase):
487+
"""
488+
Tests for the LdCalculator class.
489+
"""
490+
def test_uninitialised_tree_sequence(self):
491+
ts = _tskit.TreeSequence()
492+
self.assertRaises(ValueError, _tskit.LdCalculator, ts)
493+
494+
def test_constructor(self):
495+
self.assertRaises(TypeError, _tskit.LdCalculator)
496+
self.assertRaises(TypeError, _tskit.LdCalculator, None)
497+
498+
def test_get_r2(self):
499+
ts = self.get_example_tree_sequence()
500+
calc = _tskit.LdCalculator(ts)
501+
n = ts.get_num_sites()
502+
for bad_id in [-1, n, n + 1]:
503+
with self.assertRaises(_tskit.LibraryError):
504+
calc.get_r2(0, bad_id)
505+
with self.assertRaises(_tskit.LibraryError):
506+
calc.get_r2(bad_id, 0)
507+
508+
def test_get_r2_array(self):
509+
ts = self.get_example_tree_sequence()
510+
calc = _tskit.LdCalculator(ts)
511+
512+
self.assertRaises(TypeError, calc.get_r2_array)
513+
self.assertRaises(TypeError, calc.get_r2_array, None)
514+
# Doesn't support buffer protocol, so raises typeerror
515+
self.assertRaises(TypeError, calc.get_r2_array, None, 0)
516+
517+
n = ts.get_num_sites()
518+
self.assertGreater(n, 2)
519+
with self.assertRaises(BufferError):
520+
calc.get_r2_array(bytes(100), 0)
521+
522+
buff = bytearray(1024)
523+
with self.assertRaises(ValueError):
524+
calc.get_r2_array(buff, 0, max_distance=-1)
525+
with self.assertRaises(ValueError):
526+
calc.get_r2_array(buff, 0, direction=1000)
527+
# TODO this API is poor, we should explicitly catch these negative
528+
# size errors.
529+
for bad_max_mutations in [-2, -3, -2**32]:
530+
with self.assertRaises(BufferError):
531+
calc.get_r2_array(buff, 0, max_mutations=bad_max_mutations)
532+
for bad_start_pos in [-1, n, n + 1]:
533+
with self.assertRaises(_tskit.LibraryError):
534+
calc.get_r2_array(buff, bad_start_pos)
535+
536+
422537
class TestTree(LowLevelTestCase):
423538
"""
424539
Tests on the low-level sparse tree interface.
@@ -450,6 +565,31 @@ def test_flags(self):
450565
self.assertRaises(ValueError, st.get_right_sample, 0)
451566
self.assertRaises(ValueError, st.get_next_sample, 0)
452567

568+
def test_site_errors(self):
569+
ts = self.get_example_tree_sequence()
570+
for bad_index in [-1, ts.get_num_sites(), ts.get_num_sites() + 1]:
571+
self.assertRaises(IndexError, ts.get_site, bad_index)
572+
573+
def test_mutation_errors(self):
574+
ts = self.get_example_tree_sequence()
575+
for bad_index in [-1, ts.get_num_mutations(), ts.get_num_mutations() + 1]:
576+
self.assertRaises(IndexError, ts.get_mutation, bad_index)
577+
578+
def test_individual_errors(self):
579+
ts = self.get_example_tree_sequence()
580+
for bad_index in [-1, ts.get_num_individuals(), ts.get_num_individuals() + 1]:
581+
self.assertRaises(IndexError, ts.get_individual, bad_index)
582+
583+
def test_population_errors(self):
584+
ts = self.get_example_tree_sequence()
585+
for bad_index in [-1, ts.get_num_populations(), ts.get_num_populations() + 1]:
586+
self.assertRaises(IndexError, ts.get_population, bad_index)
587+
588+
def test_provenance_errors(self):
589+
ts = self.get_example_tree_sequence()
590+
for bad_index in [-1, ts.get_num_provenances(), ts.get_num_provenances() + 1]:
591+
self.assertRaises(IndexError, ts.get_provenance, bad_index)
592+
453593
def test_sites(self):
454594
for ts in self.get_example_tree_sequences():
455595
st = _tskit.Tree(ts)

0 commit comments

Comments
 (0)