1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
"""Tests for XML output."""
import datetime
import difflib
import glob
import ly.musicxml
from lxml import etree
import os
import os.path
import io
import pytest
import re
import sys
def test_glissando():
compare_output('glissando')
def test_tie():
compare_output('tie')
def test_merge_voice():
compare_output('merge_voice')
def test_variable():
compare_output('variable')
def test_dynamics():
compare_output('dynamics')
def test_tuplet():
compare_output('tuplet')
def test_merge_voice_slurs():
compare_output('merge_voice_slurs')
def test_break():
compare_output('break')
def test_mark():
compare_output('mark')
@pytest.mark.xfail
def test_partial():
compare_output('partial')
def test_full_bar():
compare_output('full_bar_rest')
def test_stem_direction():
compare_output('stem')
def test_church():
compare_output('church_modes')
@pytest.mark.xfail
def test_markup():
compare_output('markup')
def test_breathe():
compare_output('breathe')
def test_no_barcheck():
compare_output('no_barcheck')
def ly_to_xml(filename):
"""Read Lilypond file and return XML string."""
writer = ly.musicxml.writer()
with open(filename, 'r') as lyfile:
writer.parse_text(lyfile.read())
xml = writer.musicxml()
sio = io.BytesIO()
xml.write(sio, "utf-8")
return sio.getvalue().decode("utf-8")
encoding_date_element_re = re.compile(r'(?<=<encoding-date>)\d{4}-\d{2}-\d{2}(?=</encoding-date>)')
def read_expected_xml(filename):
"""Return string with expected XML from file."""
with open(filename, 'r') as xmlfile:
output = xmlfile.read()
# Replace date in XML file with today's date
output = encoding_date_element_re.sub(str(datetime.date.today()), output)
return output
def compare_output(filename):
"""Compare XML output with expected output."""
filebase = os.path.join(os.path.dirname(__file__), 'test_xml_files',
filename)
output = ly_to_xml(filebase + '.ly')
expected_output = read_expected_xml(filebase + '.xml')
assert_multi_line_equal(expected_output, output)
validate_xml(output)
def validate_xml(xml):
"""Validate XML against XSD file."""
xsdname = os.path.join(os.path.dirname(__file__), 'musicxml.xsd')
xsdfile = open(xsdname, 'r')
xmlschema_doc = etree.parse(xsdfile)
xsdfile.close()
xmlschema = etree.XMLSchema(xmlschema_doc)
parser = etree.XMLParser(schema=xmlschema)
xml_bytes = xml.encode('utf-8')
# Raises Exception if not valid:
etree.fromstring(xml_bytes, parser)
def assert_multi_line_equal(first, second, msg=None):
"""Assert that two multi-line strings are equal.
If they aren't, show a nice diff.
"""
assert isinstance(first, str), 'First argument is not a string'
assert isinstance(second, str), 'Second argument is not a string'
if first != second:
message = ''.join(difflib.ndiff(first.splitlines(True),
second.splitlines(True)))
if msg:
message += " : " + msg
assert False, "Multi-line strings are unequal:\n" + message
def regenerate_xml():
"""Regenerate the XML files"""
extension_re = re.compile(r'\.ly$')
for ly_path in glob.glob(os.path.join(os.path.dirname(__file__), 'test_xml_files/*.ly')):
xml_path = extension_re.sub('.xml', ly_path)
xml = ly_to_xml(ly_path)
with open(xml_path, 'w') as fw:
fw.write(xml)
# Run
# $ test_xml.py regenerate
# to generate the expected XML files anew with current python-ly
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'regenerate':
regenerate_xml()
|