setclass/setclass/tests/test_setclass.py

198 lines
5.4 KiB
Python

from setclass.setclass import SetClass
# ----------------------------------------------------------------------------
# Functional tests
def test_zero_normalised_pc():
"Pitch classes are normalised to start at zero"
a = SetClass(0, 1, 3)
assert a == SetClass(1, 2, 4)
assert a == SetClass(4, 5, 7)
def test_modulo_pc():
"Pitch classes are normalised to modulo tonality (12)"
a = SetClass(0, 1, 3)
assert a == SetClass(12, 13, 15) # modulo down
assert a == SetClass(-11, -9, -12) # modulo up
def test_negative_pc():
"Negative pitch classes are modulo tonality (12)"
a = SetClass(0, 9, 10)
assert a == SetClass(-3, -2, 0)
def test_unordered_pc():
"Set classes are unordered; normalised to incremental sort"
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_resolve_duplicate_pc():
"Set classes are sets, so duplicates (including after modulo) are eliminated"
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)
def test_interval_vector():
"Set classes have an interval vector"
test = [
# 2-tuple of set class, expected interval vector
(SetClass(0, 3, 4, 7, 8, 11), [3, 0, 3, 6, 3, 0]),
(SetClass(0, 1, 3, 5, 6, 8, 10), [2, 5, 4, 3, 6, 1]),
]
for (sc, iv) in test:
assert sc.interval_vector == iv
def test_interval_vector_invarant():
"The interval vector is invariant under inversion and transposition (rotation)"
test = [
# 2-tuple of set class, expected interval vector
(SetClass(0, 3, 4, 7, 8, 11), [3, 0, 3, 6, 3, 0]),
(SetClass(0, 1, 3, 5, 6, 8, 10), [2, 5, 4, 3, 6, 1]),
]
for (sc, iv) in test:
for version in (sc.versions + sc.inversion.versions):
assert version.interval_vector == iv
# ----------------------------------------------------------------------------
# Example Forte 5-20 set class
f520 = SetClass(0, 1, 5, 6, 8)
def test_tonality():
"Set classes has a default tonality of 12"
assert f520.tonality == 12
def test_cardinality():
"Set classes has a set cardinality"
assert f520.cardinality == 5
def test_brightness():
"Set classes have a brightness (sum of normalised pitch class values)"
assert f520.brightness == 20
def test_pitch_classes():
"Set classes have pitch classes"
assert len(f520) == 5
assert len(f520.pitch_classes) == 5
def test_adjacency_intervals():
"Set classes have a set of adjacency intervals"
assert len(f520.adjacency_intervals) == 5
def test_versions():
"Set classes have a set of transpositions (rotations)"
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₁T₂]⁽²⁸⁾'
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_rahn_normal_form():
r = f520.rahn_normal_form
assert r in f520.versions
assert r == SetClass(0, 1, 5, 6, 8)
def test_inversion():
i = f520.inversion
assert i not in f520.versions
assert i not in f520.complement.versions
assert i not in f520.complement.inversion.versions
assert i == SetClass(0, 4, 6, 7, 11)
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_rahn_normal_form():
r = f520.complement.rahn_normal_form
assert r in f520.complement.versions
assert r == SetClass(0, 2, 3, 4, 7, 8, 9)
def test_complement_inversion():
i = f520.complement.inversion
assert i not in f520.versions
assert i not in f520.inversion.versions
assert i not in f520.complement.versions
assert i == SetClass(0, 3, 4, 5, 7, 10, 11)
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₃T₁E₁]⁽⁴²⁾'
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₃T₂]⁽³¹⁾'
def test_complement_leonard_notation():
assert f520.complement.leonard_notation == '[0₁1₁2₃5₂7₁8₁9₃]⁽³²⁾'