diff --git a/setclass/__init__.py b/setclass/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/setclass.py b/setclass/setclass.py similarity index 71% rename from setclass.py rename to setclass/setclass.py index 4449623..1ce37b9 100644 --- a/setclass.py +++ b/setclass/setclass.py @@ -168,72 +168,3 @@ class SetClass(list): pitches += f"{pitch}{sub}" sup = superscript(self.brightness) return f"[{pitches}]{sup}" - - -if __name__ == "__main__": - print("Running tests:") - - # Forte 0-1, the empty set - empty = SetClass() - print(f"Forte 0-1: {empty}") - assert empty.tonality == 12 - assert empty.cardinality == 0 - assert empty.brightness == 0 - assert len(empty) == 0 - assert len(empty.pitch_classes) == 0 - assert len(empty.adjacency_intervals) == 0 - assert empty.leonard_notation == '[]⁰' - print(f" Leonard: {empty.leonard_notation}") - assert len(empty.versions) == 1 - print(f" Versions ({len(empty.versions)}):") - for i in empty.versions: - print(f" {i.leonard_notation}") - assert empty.brightest_form == empty.darkest_form - - # Forte 12-1, the complement of empty (full set) - f121 = empty.complement - print(f"Forte 12-1: {empty}") - assert f121 == SetClass(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) - assert f121.tonality == 12 - assert f121.cardinality == 12 - assert f121.brightness == 66 - assert len(f121) == 12 - assert len(f121.pitch_classes) == 12 - assert len(f121.adjacency_intervals) == 12 - assert f121.leonard_notation == '[0₁1₁2₁3₁4₁5₁6₁7₁8₁9₁10₁11₁]⁶⁶' - assert len(f121.versions) == 1 - assert f121.brightest_form == f121.darkest_form - - # Forte 5-20 - f520 = SetClass(0, 1, 5, 6, 8) - print(f"{f520}") - assert f520.tonality == 12 - assert f520.cardinality == 5 - assert f520.brightness == 20 - assert len(f520) == 5 - assert len(f520.pitch_classes) == 5 - print(f"Adjacency intervals: {f520.adjacency_intervals}") - assert len(f520.adjacency_intervals) == 5 - assert len(f520.versions) == 5 - print(f"Leonard notation: {f520.leonard_notation}") - assert f520.leonard_notation == '[0₁1₄5₁6₂8₄]²⁰' - - assert f520.brightest_form.leonard_notation == '[0₄4₁5₄9₁10₂]²⁸' - assert f520.brightest_form == SetClass(0, 4, 5, 9, 10) - - sc = f520 - co = f520.complement - print(f"Versions ({len(sc.versions)}):") - for i in sc.versions: - print(f" {i.leonard_notation}") - print(f"Brightest form: {sc.brightest_form.leonard_notation}") - print(f"Darkest form: {sc.darkest_form.leonard_notation}") - print() - - print(f"Complement: {co}") - print(f"Adjacency intervals: {co.adjacency_intervals}") - print(f"Leonard notation: {co.leonard_notation}") - print(f"Versions ({len(co.versions)}):") - for i in co.versions: - print(f" {i.leonard_notation}") - print(f"Darkest form: {co.darkest_form}") diff --git a/setclass/tests/__init__.py b/setclass/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/setclass/tests/test_setclass.py b/setclass/tests/test_setclass.py new file mode 100644 index 0000000..cf8e158 --- /dev/null +++ b/setclass/tests/test_setclass.py @@ -0,0 +1,250 @@ +from setclass.setclass import SetClass + + +# ---------------------------------------------------------------------------- +# Functional tests + + +def test_zero_normalised_intervals(): + a = SetClass(0, 1, 3) + assert a == SetClass(1, 2, 4) + assert a == SetClass(4, 5, 7) + + +def test_modulo_intervals(): + a = SetClass(0, 1, 3) + assert a == SetClass(12, 13, 15) # modulo down + assert a == SetClass(-11, -9, -12) # modulo up + + +def test_negative_intervals(): + a = SetClass(0, 9, 10) + assert a == SetClass(-3, -2, 0) + + +def test_immutable_intervals(): + a = SetClass(0, 1, 3) + assert a == SetClass(0, 3, 1) + assert a == SetClass(3, 0, 1) + assert a == SetClass(1, 3, 0) + assert a == SetClass(1, 0, 3) + assert a == SetClass(3, 1, 0) + + +def test_repeat_intervals(): + a = SetClass(0, 1, 3) + assert a == SetClass(0, 1, 3, 3, 1) + assert a == SetClass(0, 12, 1, -11, 15) + assert a == SetClass(12, 1, -11, 15, -9) + + +# ---------------------------------------------------------------------------- +# Example Forte 5-20 set class +f520 = SetClass(0, 1, 5, 6, 8) + + +def test_tonality(): + assert f520.tonality == 12 + + +def test_cardinality(): + assert f520.cardinality == 5 + + +def test_brightness(): + assert f520.brightness == 20 + + +def test_pitch_classes(): + assert len(f520) == 5 + assert len(f520.pitch_classes) == 5 + + +def test_adjacency_intervals(): + assert len(f520.adjacency_intervals) == 5 + + +def test_versions(): + assert len(f520.versions) == 5 + + +def test_brightest_form(): + b = f520.brightest_form + assert b in f520.versions + assert b == SetClass(0, 4, 5, 9, 10) + assert b.leonard_notation == '[0₄4₁5₄9₁10₂]²⁸' + + +def test_darkest_form(): + d = f520.darkest_form + assert d in f520.versions + assert d == SetClass(0, 1, 3, 7, 8) + assert d.leonard_notation == '[0₁1₂3₄7₁8₄]¹⁹' + + +def test_leonard_notation(): + assert f520.leonard_notation == '[0₁1₄5₁6₂8₄]²⁰' + + +# ---------------------------------------------------------------------------- +# Complement of Forte 5-20 set class: Forte 7-20 + +def test_complement(): + assert f520.complement == SetClass(0, 1, 2, 5, 7, 8, 9) + + +def test_complement_tonality(): + assert f520.complement.tonality == 12 + + +def test_complement_cardinality(): + assert f520.complement.cardinality == 7 + + +def test_complement_brightness(): + assert f520.complement.brightness == 32 + + +def test_complement_pitch_classes(): + assert len(f520.complement) == 7 + assert len(f520.complement.pitch_classes) == 7 + + +def test_complement_adjacency_intervals(): + assert len(f520.complement.adjacency_intervals) == 7 + + +def test_complement_versions(): + assert len(f520.complement.versions) == 7 + + +def test_complement_brightest_form(): + b = f520.complement.brightest_form + assert b in f520.complement.versions + assert b == SetClass(0, 3, 5, 6, 7, 10, 11) + assert b.leonard_notation == '[0₃3₂5₁6₁7₃10₁11₁]⁴²' + + +def test_complement_darkest_form(): + d = f520.complement.darkest_form + assert d in f520.complement.versions + assert d == SetClass(0, 1, 2, 5, 6, 7, 10) + assert d.leonard_notation == '[0₁1₁2₃5₁6₁7₃10₂]³¹' + + +def test_complement_leonard_notation(): + assert f520.complement.leonard_notation == '[0₁1₁2₃5₂7₁8₁9₃]³²' + + +# ---------------------------------------------------------------------------- +# Forte 0-1, the empty set class +empty = SetClass() + + +def test_empty_tonality(): + assert empty.tonality == 12 + + +def test_empty_cardinality(): + assert empty.cardinality == 0 + + +def test_empty_brightness(): + assert empty.brightness == 0 + + +def test_empty_pitch_classes(): + assert len(empty) == 0 + assert len(empty.pitch_classes) == 0 + + +def test_empty_ajdacency_intervals(): + assert len(empty.adjacency_intervals) == 0 + + +def test_empty_versions(): + assert len(empty.versions) == 1 + assert empty.versions[0] == empty + + +def test_empty_brightest_form(): + assert empty.brightest_form == empty + + +def test_empty_darkest_form(): + assert empty.darkest_form == empty + + +def test_empty_bright_dark_forms_equal(): + assert empty.brightest_form == empty.darkest_form + + +def test_empty_duodecimal_notation(): + assert empty.duodecimal_notation == 'SetClass[]' + + +def test_empty_dozenal_notation(): + assert empty.dozenal_notation == 'SetClass[]' + + +def test_empty_leonard_notation(): + assert empty.leonard_notation == '[]⁰' + + +# ---------------------------------------------------------------------------- +# Forte 12-1, the complement of empty (full set class) +f121 = empty.complement + + +def test_empty_complement(): + assert f121 == SetClass(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) + + +def test_empty_complement_tonality(): + assert f121.tonality == 12 + + +def test_empty_complement_cardinality(): + assert f121.cardinality == 12 + + +def test_empty_complement_brightness(): + assert f121.brightness == 66 + + +def test_empty_complement_pitch_classes(): + assert len(f121) == 12 + assert len(f121.pitch_classes) == 12 + + +def test_empty_complement_adjacency_intervals(): + assert len(f121.adjacency_intervals) == 12 + + +def test_empty_complement_versions(): + assert len(f121.versions) == 1 + assert f121.versions[0] == f121 + + +def test_empty_complement_brightest_form(): + assert f121.brightest_form == f121 + + +def test_empty_complement_darkest_form(): + assert f121.darkest_form == f121 + + +def test_empty_complement_bright_dark_forms_equal(): + assert f121.brightest_form == f121.darkest_form + + +def test_empty_complement_duodecimal_notation(): + assert f121.duodecimal_notation == 'SetClass[0,1,2,3,4,5,6,7,8,9,T,E]' + + +def test_empty_complement_dozenal_notation(): + assert f121.dozenal_notation == 'SetClass[0,1,2,3,4,5,6,7,8,9,↊,↋]' + + +def test_empty_complement_leonard_notation(): + assert f121.leonard_notation == '[0₁1₁2₁3₁4₁5₁6₁7₁8₁9₁10₁11₁]⁶⁶' diff --git a/tox.ini b/tox.ini index 3a0eecb..e286263 100644 --- a/tox.ini +++ b/tox.ini @@ -6,13 +6,18 @@ skip_missing_interpreters = True [testenv] skip_install = True setenv = - PYTHONPATH = {toxroot} + PYTHONPATH = {toxroot}/setclass commands = pytest --cov=. --junitxml=junit.xml --cov-report xml:coverage.xml --cov-report term {posargs} deps = -r requirements-dev.txt [coverage:run] +omit = + ./**/tests/*.py + ./**/test_*.py + ./**/*_tests.py + ./**/tests.py [coverage:report] skip_empty = True