+23
-7
@@ -91,18 +91,18 @@ class MusicXMLTests(unittest.TestCase):
|
||||
self.assertEqual(fraction(result[0]['pitches'][1]['duration']), 1)
|
||||
self.assertEqual(result[0]['pitches'][0]['tie_to'], result[1]['pitches'][0]['id'])
|
||||
self.assertNotIn('tie_to', result[0]['pitches'][1])
|
||||
def test_standard_minor_harmonies_preserve_display_and_pitches(self):
|
||||
def test_standard_minor_harmonies_normalize_display_and_preserve_pitches(self):
|
||||
from generator.harmony import pitch_classes
|
||||
for text, kind, expected in (('-7', 'minor-seventh', (0, 3, 7, 10)), ('-7b5', 'half-diminished', (0, 3, 6, 10)), ('-maj7', 'major-minor', (0, 3, 7, 11)), ('-6', 'minor-sixth', (0, 3, 7, 9))):
|
||||
for text, kind, label, expected in (('-7', 'minor-seventh', 'm7', (0, 3, 7, 10)), ('-7b5', 'half-diminished', 'm7b5', (0, 3, 6, 10)), ('-maj7', 'major-minor', 'mM7', (0, 3, 7, 11)), ('-6', 'minor-sixth', 'm6', (0, 3, 7, 9))):
|
||||
with self.subTest(text=text):
|
||||
content = f'<harmony><root><root-step>C</root-step></root><kind text="{text}">{kind}</kind></harmony>'
|
||||
score = parse(xml_score(content + xml_note()))
|
||||
chord = score['staves'][0]['measures'][0]['harmonies'][0]
|
||||
self.assertEqual(chord['symbol'], 'C' + text)
|
||||
self.assertEqual(chord['symbol'], 'C' + label)
|
||||
self.assertEqual(pitch_classes(chord), expected)
|
||||
def test_other_harmony_requires_explicit_degrees(self):
|
||||
for kind in ('<kind>other</kind>', '<kind text="">other</kind>', '<kind text="-7">other</kind>', '<kind text="unknown">other</kind>'):
|
||||
with self.subTest(kind=kind), self.assertRaisesRegex(MusicXMLError, r"fixture.xml: part P1, measure 1: harmony kind 'other' requires explicit added degrees"):
|
||||
def test_other_harmony_requires_degrees_or_recognized_text(self):
|
||||
for kind in ('<kind>other</kind>', '<kind text="">other</kind>', '<kind text="unknown">other</kind>'):
|
||||
with self.subTest(kind=kind), self.assertRaisesRegex(MusicXMLError, r'fixture.xml: part P1, measure 1:'):
|
||||
parse(xml_score('<harmony><root><root-step>C</root-step></root>' + kind + '</harmony>' + xml_note()))
|
||||
def test_other_harmony_with_explicit_degrees_remains_supported(self):
|
||||
from generator.harmony import pitch_classes
|
||||
@@ -111,7 +111,7 @@ class MusicXMLTests(unittest.TestCase):
|
||||
score = parse(xml_score(content + xml_note()))
|
||||
chord = score['staves'][0]['measures'][0]['harmonies'][0]
|
||||
self.assertEqual(chord['kind'], 'other')
|
||||
self.assertEqual(chord['symbol'], 'C-7')
|
||||
self.assertEqual(chord['symbol'], 'Cm7')
|
||||
self.assertEqual(pitch_classes(chord), (0, 3, 7, 10))
|
||||
with self.assertRaisesRegex(MusicXMLError, 'contradictory harmony text'):
|
||||
parse(xml_score(content.replace('text="-7"', 'text="maj7"') + xml_note()))
|
||||
@@ -162,6 +162,22 @@ class MusicXMLTests(unittest.TestCase):
|
||||
for content in (marker + xml_note(), marker + marker + h + xml_note(), marker.replace('optional-chord', 'unknown') + xml_note()):
|
||||
with self.assertRaisesRegex(MusicXMLError, 'measure 1'):
|
||||
parse(xml_score(content))
|
||||
def test_repeat_navigation_and_pass_specific_ties_are_rejected(self):
|
||||
rejected = [
|
||||
'<barline location="left"><repeat direction="forward"/></barline>',
|
||||
'<barline><repeat direction="backward" times="3"/></barline>',
|
||||
'<barline location="left"><ending number="1" type="start"/></barline>',
|
||||
'<barline><ending number="2" type="discontinue" print-object="no"/></barline>',
|
||||
'<direction><direction-type><segno/></direction-type></direction>',
|
||||
'<direction><direction-type><coda/></direction-type></direction>',
|
||||
'<sound dacapo="yes"/>', '<sound dalsegno="segno"/>', '<sound tocoda="coda"/>',
|
||||
]
|
||||
for content in rejected:
|
||||
with self.subTest(content=content), self.assertRaisesRegex(MusicXMLError, 'measure 1'):
|
||||
parse(xml_score(content + xml_note()))
|
||||
for passes in ('1', ''):
|
||||
with self.assertRaisesRegex(MusicXMLError, 'pass-specific ties'):
|
||||
parse(xml_score(xml_note(extra=f'<tie type="start" time-only="{passes}"/>')))
|
||||
def test_rejects_musical_content_outside_contract(self):
|
||||
extras = ['<notations><slur type="start"/></notations>', '<notations><articulations><accent/></articulations></notations>',
|
||||
'<voice>2</voice><staff>2</staff>', '<pitch><unpitched/></pitch>',
|
||||
|
||||
Reference in New Issue
Block a user