diff --git a/tests/test_volumelabels.py b/tests/test_volumelabels.py new file mode 100644 index 0000000000000000000000000000000000000000..5265e3fe90768191d7a2532b3d2660d0e09e3695 --- /dev/null +++ b/tests/test_volumelabels.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python +# +# test_volumelabels.py - +# +# Author: Paul McCarthy <pauldmccarthy@gmail.com> +# + +import os.path as op +import itertools as it +import textwrap + +import pytest + +import tests +import fsl.data.fixlabels as fixlbls +import fsl.data.volumelabels as vollbls + + +def test_add_get_hasLabel(): + + ncomps = 5 + labels = ['Label {}'.format(i) for i in range(ncomps)] + lowers = [lbl.lower() for lbl in labels] + lblobj = vollbls.VolumeLabels(ncomps) + + called = [False] + + def labelAdded(lo, topic, value): + called[0] = True + + lblobj.register('callback', labelAdded, topic='added') + + for i in range(ncomps): + + called[0] = False + + assert lblobj.addLabel(i, labels[i]) + assert called[0] + assert lblobj.getLabels(i) == [lowers[i]] + assert lblobj.getDisplayLabel(lowers[i]) == labels[i] + + assert lblobj.hasLabel(i, labels[i]) + assert lblobj.hasLabel(i, lowers[i]) + + # Attempt to add the same label should + # return False + called[0] = False + assert not lblobj.addLabel(i, labels[i]) + assert not called[0] + + # Labels are case insensitive + assert not lblobj.addLabel(i, lowers[i]) + assert not called[0] + + assert sorted(lblobj.getAllLabels()) == lowers + + +def test_removeLabel(): + + ncomps = 5 + labels = ['Label {}'.format(i) for i in range(ncomps)] + lowers = [lbl.lower() for lbl in labels] + lblobj = vollbls.VolumeLabels(ncomps) + + for i in range(ncomps): + lblobj.addLabel(i, labels[i]) + + called = [False] + + def removed(*a): + called[0] = True + + lblobj.register('callback', removed, topic='removed') + + + assert not lblobj.removeLabel(0, 'notalabel') + assert not called[0] + + for i in range(ncomps): + + called[0] = False + assert lblobj.removeLabel(i, labels[i]) + assert called[0] + + assert lblobj.getLabels(i) == [] + assert sorted(lblobj.getAllLabels()) == lowers[i + 1:] + + +def test_clearLabels(): + + ncomps = 5 + labels = [('Label {}'.format(i), 'Label b') + for i in range(ncomps)] + lowers = [[l.lower() for l in ll] for ll in labels] + lblobj = vollbls.VolumeLabels(ncomps) + + for i in range(ncomps): + for l in labels[i]: + lblobj.addLabel(i, l) + + calledValue = [] + + def removed(lo, topic, value): + calledValue.append(value) + + lblobj.register('callback', removed, topic='removed') + + expectedAllLabels = list(it.chain(*[list(l) for l in lowers])) + + for i in range(ncomps): + + calledValue = [] + lblobj.clearLabels(i) + assert calledValue[0] == list(zip([i, i], lowers[i])) + assert lblobj.getLabels(i) == [] + + [expectedAllLabels.remove(l) for l in lowers[i]] + assert sorted(lblobj.getAllLabels()) == sorted(set(expectedAllLabels)) + + +def test_add_get_hasComponents(): + + ncomps = 5 + labels = ['label a', 'label b', 'label c', 'label d', 'label e'] + lblobj = vollbls.VolumeLabels(ncomps) + + called = [False] + + def labelAdded(lo, topic, value): + called[0] = True + + lblobj.register('callback', labelAdded, topic='added') + + for i in range(ncomps): + + called[0] = False + assert lblobj.addComponent(labels[i], i) + assert called[0] + assert lblobj.hasComponent(labels[i], i) + assert lblobj.hasLabel( i, labels[i]) + assert lblobj.getComponents(labels[i]) == [i] + + called[0] = False + assert not lblobj.addComponent(labels[i], i) + assert not called[0] + + +def test_removeComponent(): + ncomps = 5 + labels = ['label a', 'label b', 'label c', 'label d', 'label e'] + lblobj = vollbls.VolumeLabels(ncomps) + + called = [False] + + for i in range(ncomps): + lblobj.addLabel(i, labels[i]) + + def removed(*a): + called[0] = True + + lblobj.register('callback', removed, topic='removed') + + assert not lblobj.removeComponent('notalabel', 0) + assert not called[0] + + for i in range(ncomps): + + called[0] = False + assert lblobj.removeComponent(labels[i], i) + assert called[0] + + assert lblobj.getComponents(labels[i]) == [] + assert sorted(lblobj.getAllLabels()) == labels[i + 1:] + + +def test_clearComponents(): + + ncomps = 5 + labels = [('label {}'.format(i), 'label b') for i in range(ncomps)] + lblobj = vollbls.VolumeLabels(ncomps) + + for i in range(ncomps): + for l in labels[i]: + lblobj.addLabel(i, l) + + calledValue = [] + + def removed(lo, topic, value): + calledValue.append(value) + + lblobj.register('callback', removed, topic='removed') + + lblobj.clearComponents('label b') + assert sorted(calledValue[0]) == list(zip(list(range(ncomps)), ['label b'] * ncomps)) + assert sorted(lblobj.getAllLabels()) == [l[0] for l in labels] + + # expectedAllLabels = list(it.chain(*[list(l) for l in lowers])) + + labels = [l[0] for l in labels] + + for i in range(ncomps): + + calledValue = [] + + lblobj.clearComponents(labels[i]) + + assert calledValue[0] == [(i, labels[i])] + assert lblobj.getComponents(labels[i]) == [] + assert lblobj.getLabels(i) == [] + + assert sorted(lblobj.getAllLabels()) == labels[i + 1:] + + +def test_load_fixfile_long(): + + contents = """ + path/to/analysis.ica + 1, Signal, False + 2, Unknown, False + 3, Movement, True + 4, Unclassified Noise, Random label, True + [3, 4] + """.strip() + + expected = [['signal'], + ['unknown'], + ['movement'], + ['unclassified noise', 'random label']] + + with tests.testdir() as testdir: + fname = op.join(testdir, 'labels.txt') + with open(fname, 'wt') as f: + f.write(contents) + + # Too many labels in the file + lblobj = vollbls.VolumeLabels(3) + with pytest.raises(fixlbls.InvalidLabelFileError): + lblobj.load(fname) + + # Not enough labels in the file - + # this is ok. Remaining labels + # should be given 'Unknown' + lblobj = vollbls.VolumeLabels(5) + lblobj.load(fname) + for i in range(4): + assert lblobj.getLabels(i) == expected[i] + assert lblobj.getLabels(4) == ['unknown'] + + # Right number of labels + lblobj = vollbls.VolumeLabels(4) + lblobj.load(fname) + for i in range(4): + assert lblobj.getLabels(i) == expected[i] + + +def test_load_fixfile_short(): + + contents = """[2, 3, 5]""".strip() + expected = [['signal'], + ['unclassified noise'], + ['unclassified noise'], + ['signal'], + ['unclassified noise']] + + with tests.testdir() as testdir: + fname = op.join(testdir, 'labels.txt') + with open(fname, 'wt') as f: + f.write(contents) + + # Too many labels in the file + lblobj = vollbls.VolumeLabels(3) + with pytest.raises(fixlbls.InvalidLabelFileError): + lblobj.load(fname) + + # Not enough labels in the file - + # this is ok. Remaining labels + # should be given 'Unknown' + lblobj = vollbls.VolumeLabels(6) + lblobj.load(fname) + for i in range(4): + assert lblobj.getLabels(i) == expected[i] + assert lblobj.getLabels(5) == ['unknown'] + + # Right number of labels + lblobj = vollbls.VolumeLabels(5) + lblobj.load(fname) + for i in range(4): + assert lblobj.getLabels(i) == expected[i] + + +def test_load_aromafile(): + + contents = """2, 3, 5""".strip() + expected = [['unknown'], + ['movement'], + ['movement'], + ['unknown'], + ['movement']] + + with tests.testdir() as testdir: + fname = op.join(testdir, 'labels.txt') + with open(fname, 'wt') as f: + f.write(contents) + + # Too many labels in the file + lblobj = vollbls.VolumeLabels(3) + with pytest.raises(fixlbls.InvalidLabelFileError): + lblobj.load(fname) + + # Not enough labels in the file - + # this is ok. Remaining labels + # should be given 'Unknown' + lblobj = vollbls.VolumeLabels(6) + lblobj.load(fname) + for i in range(4): + assert lblobj.getLabels(i) == expected[i] + assert lblobj.getLabels(5) == ['unknown'] + + # Right number of labels + lblobj = vollbls.VolumeLabels(5) + lblobj.load(fname) + for i in range(4): + assert lblobj.getLabels(i) == expected[i] + + +def test_save(): + + expected = textwrap.dedent(""" + 1, Signal, Default mode, False + 2, Unknown, False + 3, Unclassified noise, True + 4, Movement, True + [3, 4] + """).strip() + + lbls = vollbls.VolumeLabels(4) + lbls.addLabel(0, 'Signal') + lbls.addLabel(0, 'Default mode') + lbls.addLabel(1, 'Unknown') + lbls.addLabel(2, 'Unclassified noise') + lbls.addLabel(3, 'Movement') + + with tests.testdir() as testdir: + + fname = op.join(testdir, 'labels.txt') + + # Test saving without dirname + lbls.save(fname) + with open(fname, 'rt') as f: + assert f.read().strip() == expected.strip() + + # And with dirname + lbls.save(fname, 'path/to/analysis.ica') + expected = '{}\n{}'.format( + 'path/to/analysis.ica', + expected) + + with open(fname, 'rt') as f: + assert f.read().strip() == expected.strip()