code: //=============================================================================
  //  MuseScore
  //  Music Composition & Notation
  //
  //  Copyright (C) 2012-2014 Werner Schweer
  //
  //  This program is free software; you can redistribute it and/or modify
  //  it under the terms of the GNU General Public License version 2
  //  as published by the Free Software Foundation and appearing in
  //  the file LICENCE.GPL
  //=============================================================================
  
  #include <QtTest/QtTest>
  #include "mtest/testutils.h"
  #include "libmscore/score.h"
  #include "mscore/preferences.h"
  // start includes required for fixupScore()
  #include "libmscore/measure.h"
  #include "libmscore/staff.h"
  #include "libmscore/keysig.h"
  // end includes required for fixupScore()
  
  namespace Ms {
  extern bool saveMxl(Score*, const QString&);
  }
  
  #define DIR QString("musicxml/io/")
  
  using namespace Ms;
  
  //---------------------------------------------------------
  //   TestMxmlIO
  //---------------------------------------------------------
  
  class TestMxmlIO : public QObject, public MTest
        {
        Q_OBJECT
  
        void mxmlIoTest(const char* file);
        void mxmlIoTestRef(const char* file);
        void mxmlIoTestRefBreaks(const char* file);
        void mxmlMscxExportTestRef(const char* file);
        void mxmlMscxExportTestRefBreaks(const char* file);
        void mxmlReadTestCompr(const char* file);
        void mxmlReadWriteTestCompr(const char* file);
  
  
        // The list of MusicXML regression tests
        // Currently failing tests are commented out and annotated with the failure reason
        // To extract the list in a shell script use:
        // cat tst_mxml_io.cpp | grep "{ <test>" | awk -F\" '{print $2}'
        // where <test> is mxmlIoTest or mxmlIoTestRef
  
  private slots:
        void initTestCase();
  
        void accidentals1() { mxmlIoTest("testAccidentals1"); }
        void accidentals2() { mxmlIoTest("testAccidentals2"); }
        void accidentals3() { mxmlIoTest("testAccidentals3"); }
        void arpGliss1() { mxmlIoTest("testArpGliss1"); }
        void arpGliss2() { mxmlIoTest("testArpGliss2"); }
        void arpGliss3() { mxmlIoTest("testArpGliss3"); }
        void barStyles() { mxmlIoTest("testBarStyles"); }
        void barStyles2() { mxmlIoTest("testBarStyles2"); }
        void barStyles3() { mxmlIoTest("testBarStyles3"); }
        void breaksImplExpl() { mxmlMscxExportTestRefBreaks("testBreaksImplExpl"); }
        void breaksMMRest() { mxmlMscxExportTestRefBreaks("testBreaksMMRest"); }
        void breaksManual() { mxmlIoTestRefBreaks("testBreaksManual"); }
        void breaksPage() { mxmlMscxExportTestRefBreaks("testBreaksPage"); }
        void breaksSystem() { mxmlMscxExportTestRefBreaks("testBreaksSystem"); }
        void chordDiagrams1() { mxmlIoTest("testChordDiagrams1"); }
        void chordNoVoice() { mxmlIoTestRef("testChordNoVoice"); }
        void clefs1() { mxmlIoTest("testClefs1"); }
        void completeMeasureRests() { mxmlIoTest("testCompleteMeasureRests"); }
        void cueNotes() { mxmlIoTest("testCueNotes"); }
        void cueNotes2() { mxmlMscxExportTestRef("testCueNotes2"); }
        void dalSegno() { mxmlIoTest("testDalSegno"); }
        void dcalCoda() { mxmlIoTest("testDCalCoda"); }
        void dcalFine() { mxmlIoTest("testDCalFine"); }
        void directions1() { mxmlIoTest("testDirections1"); }
        void directions2() { mxmlIoTest("testDirections2"); }
        void divisionsDefinedTooLate1() { mxmlIoTestRef("testDivsDefinedTooLate1"); }
        void divisionsDefinedTooLate2() { mxmlIoTestRef("testDivsDefinedTooLate2"); }
        void doubleClefError() { mxmlIoTestRef("testDoubleClefError"); }
        void drumset1() { mxmlIoTest("testDrumset1"); }
        void drumset2() { mxmlIoTest("testDrumset2"); }
        void durationRoundingError() { mxmlIoTestRef("testDurationRoundingError"); }
        void dynamics1() { mxmlIoTest("testDynamics1"); }
        void dynamics2() { mxmlIoTest("testDynamics2"); }
        void dynamics3() { mxmlIoTestRef("testDynamics3"); }
        void emptyMeasure() { mxmlIoTestRef("testEmptyMeasure"); }
        void emptyVoice1() { mxmlIoTestRef("testEmptyVoice1"); }
        void extendedLyrics() { mxmlIoTestRef("testExtendedLyrics"); }
        void figuredBass1() { mxmlIoTest("testFiguredBass1"); }
        void figuredBass2() { mxmlIoTest("testFiguredBass2"); }
        void figuredBass3() { mxmlIoTest("testFiguredBass3"); }
        void formattedThings() { mxmlIoTest("testFormattedThings"); }
        void fractionMinus() { mxmlIoTestRef("testFractionMinus"); }
        void fractionPlus() { mxmlIoTestRef("testFractionPlus"); }
        void fractionTicks() { mxmlIoTestRef("testFractionTicks"); }
        void grace1() { mxmlIoTest("testGrace1"); }
        void grace2() { mxmlIoTest("testGrace2"); }
        void harmony1() { mxmlIoTest("testHarmony1"); }
        void harmony2() { mxmlIoTest("testHarmony2"); }
        void harmony3() { mxmlIoTest("testHarmony3"); }
        void harmony4() { mxmlIoTest("testHarmony4"); }
        void harmony5() { mxmlIoTest("testHarmony5"); } // chordnames without chordrest
        void hello() { mxmlIoTest("testHello"); }
        void helloReadCompr() { mxmlReadTestCompr("testHello"); }
        void helloReadWriteCompr() { mxmlReadWriteTestCompr("testHello"); }
        void implicitMeasure1() { mxmlIoTest("testImplicitMeasure1"); }
        void incorrectStaffNumber1() { mxmlIoTestRef("testIncorrectStaffNumber1"); }
        void incorrectStaffNumber2() { mxmlIoTestRef("testIncorrectStaffNumber2"); }
        void instrumentChangeMIDIportExport() { mxmlMscxExportTestRef("testInstrumentChangeMIDIportExport"); }
        void instrumentSound() { mxmlIoTestRef("testInstrumentSound"); }
        void invalidTimesig() { mxmlIoTestRef("testInvalidTimesig"); }
        void invisibleElements() { mxmlIoTest("testInvisibleElements"); }
        void keysig1() { mxmlIoTest("testKeysig1"); }
        void keysig2() { mxmlIoTest("testKeysig2"); }
        void lines1() { mxmlIoTest("testLines1"); }
        void lines2() { mxmlIoTest("testLines2"); }
        void lines3() { mxmlIoTest("testLines3"); }
        void lyricColor() { mxmlIoTest("testLyricColor"); }
        void lyrics1() { mxmlIoTestRef("testLyrics1"); }
        void lyricsVoice2a() { mxmlIoTest("testLyricsVoice2a"); }
        void lyricsVoice2b() { mxmlIoTestRef("testLyricsVoice2b"); }
        void measureLength() { mxmlIoTestRef("testMeasureLength"); }
        void midiPortExport() { mxmlMscxExportTestRef("testMidiPortExport"); }
        void multiInstrumentPart1() { mxmlIoTest("testMultiInstrumentPart1"); }
        void multiInstrumentPart2() { mxmlIoTest("testMultiInstrumentPart2"); }
        void multiMeasureRest1() { mxmlIoTestRef("testMultiMeasureRest1"); }
        void multiMeasureRest2() { mxmlIoTestRef("testMultiMeasureRest2"); }
        void multiMeasureRest3() { mxmlIoTestRef("testMultiMeasureRest3"); }
        void multiMeasureRest4() { mxmlIoTestRef("testMultiMeasureRest4"); }
        void multipleNotations() { mxmlIoTestRef("testMultipleNotations"); }
        void nonStandardKeySig1() { mxmlIoTest("testNonStandardKeySig1"); }
        void nonStandardKeySig2() { mxmlIoTest("testNonStandardKeySig2"); }
        void nonStandardKeySig3() { mxmlIoTest("testNonStandardKeySig3"); }
        void nonUniqueThings() { mxmlIoTestRef("testNonUniqueThings"); }
        void noteAttributes1() { mxmlIoTest("testNoteAttributes1"); }
        void noteAttributes2() { mxmlIoTestRef("testNoteAttributes2"); }
        void noteAttributes3() { mxmlIoTest("testNoteAttributes3"); }
        void noteColor() { mxmlIoTest("testNoteColor"); }
        void noteheadParentheses() { mxmlIoTest("testNoteheadParentheses"); }
        void noteheads() { mxmlIoTest("testNoteheads"); }
        void noteheadsFilled() { mxmlIoTest("testNoteheadsFilled"); }
        void notesRests1() { mxmlIoTest("testNotesRests1"); }
        void notesRests2() { mxmlIoTest("testNotesRests2"); }
        void numberedLyrics() { mxmlIoTestRef("testNumberedLyrics"); }
        void overlappingSpanners() { mxmlIoTest("testOverlappingSpanners"); }
        void printSpacingNo() { mxmlIoTestRef("testPrintSpacingNo"); }
        void repeatCounts() { mxmlIoTest("testRepeatCounts"); }
        void repeatSingleMeasure() { mxmlIoTest("testRepeatSingleMeasure"); }
        void restNotations() { mxmlIoTestRef("testRestNotations"); }
        void restsNoType() { mxmlIoTestRef("testRestsNoType"); }
        void restsTypeWhole() { mxmlIoTestRef("testRestsTypeWhole"); }
        void slurTieLineStyle() { mxmlIoTest("testSlurTieLineStyle"); }
        void slurs() { mxmlIoTest("testSlurs"); }
        void slurs2() { mxmlIoTest("testSlurs2"); }
        void sound1() { mxmlIoTestRef("testSound1"); }
        void sound2() { mxmlIoTestRef("testSound2"); }
        void specialCharacters() { mxmlIoTest("testSpecialCharacters"); }
        void staffTwoKeySigs() { mxmlIoTest("testStaffTwoKeySigs"); }
        void stringVoiceName() { mxmlIoTestRef("testStringVoiceName"); }
        void systemBrackets1() { mxmlIoTest("testSystemBrackets1"); }
        void systemBrackets2() { mxmlIoTest("testSystemBrackets2"); }
        void tablature1() { mxmlIoTest("testTablature1"); }
        void tablature2() { mxmlIoTest("testTablature2"); }
        void tablature3() { mxmlIoTest("testTablature3"); }
        void tablature4() { mxmlIoTest("testTablature4"); }
        void tablature5() { mxmlIoTestRef("testTablature5"); }
        void tboxAboveBelow1() { mxmlMscxExportTestRef("testTboxAboveBelow1"); }
        void tboxAboveBelow2() { mxmlMscxExportTestRef("testTboxAboveBelow2"); }
        void tboxAboveBelow3() { mxmlMscxExportTestRef("testTboxAboveBelow3"); }
        void tboxMultiPage1() { mxmlMscxExportTestRef("testTboxMultiPage1"); }
        void tboxVbox1() { mxmlMscxExportTestRef("testTboxVbox1"); }
        void tboxWords1() { mxmlMscxExportTestRef("testTboxWords1"); }
        void tempo1() { mxmlIoTest("testTempo1"); }
        void tempo2() { mxmlIoTestRef("testTempo2"); }
        void tempo3() { mxmlIoTestRef("testTempo3"); }
        void tempo4() { mxmlIoTestRef("testTempo4"); }
        void timesig1() { mxmlIoTest("testTimesig1"); }
        void timesig3() { mxmlIoTest("testTimesig3"); }
        void trackHandling() { mxmlIoTest("testTrackHandling"); }
        void tremolo() { mxmlIoTest("testTremolo"); }
        void tuplets1() { mxmlIoTestRef("testTuplets1"); }
        void tuplets2() { mxmlIoTestRef("testTuplets2"); }
        void tuplets3() { mxmlIoTestRef("testTuplets3"); }
        void tuplets4() { mxmlIoTest("testTuplets4"); }
        void tuplets5() { mxmlIoTestRef("testTuplets5"); }
        void tuplets6() { mxmlIoTestRef("testTuplets6"); }
        void tuplets7() { mxmlIoTest("testTuplets7"); }
        void uninitializedDivisions() { mxmlIoTestRef("testUninitializedDivisions"); }
        void unusualDurations() { mxmlIoTestRef("testUnusualDurations"); }
        void virtualInstruments() { mxmlIoTestRef("testVirtualInstruments"); }
        void voiceMapper1() { mxmlIoTestRef("testVoiceMapper1"); }
        void voiceMapper2() { mxmlIoTestRef("testVoiceMapper2"); }
        void voiceMapper3() { mxmlIoTestRef("testVoiceMapper3"); }
        void voicePiano1() { mxmlIoTest("testVoicePiano1"); }
        void volta1() { mxmlIoTest("testVolta1"); }
        void wedge1() { mxmlIoTest("testWedge1"); }
        void wedge2() { mxmlIoTest("testWedge2"); }
        void wedge3() { mxmlIoTest("testWedge3"); }
        void words1() { mxmlIoTest("testWords1"); }
        void words2() { mxmlIoTest("testWords2"); }
        };
  
  //---------------------------------------------------------
  //   initTestCase
  //---------------------------------------------------------
  
  void TestMxmlIO::initTestCase()
        {
        initMTest();
        }
  
  //---------------------------------------------------------
  //   fixupScore -- do required fixups after MusicXML import
  //   see mscore/file.cpp MuseScore::readScore(Score* score, QString name)
  //---------------------------------------------------------
  
  static void fixupScore(Score* score)
        {
        score->connectTies();
        score->masterScore()->rebuildMidiMapping();
        score->setCreated(false);
        score->setSaved(false);
        }
  
  //---------------------------------------------------------
  //   mxmlIoTest
  //   read a MusicXML file, write to a new file and verify both files are identical
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlIoTest(const char* file)
        {
        MScore::debugMode = true;
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, true);
        preferences.setPreference(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, false);
        MasterScore* score = readScore(DIR + file + ".xml");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + ".xml"));
        delete score;
        }
  
  //---------------------------------------------------------
  //   mxmlIoTestRef
  //   read a MusicXML file, write to a new file and verify against reference
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlIoTestRef(const char* file)
        {
        MScore::debugMode = true;
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, true);
        MasterScore* score = readScore(DIR + file + ".xml");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_ref.xml"));
        delete score;
        }
  
  //---------------------------------------------------------
  //   mxmlIoTestRefBreaks
  //   read a MusicXML file, write to a new file and verify against reference
  //   using all possible settings for PREF_EXPORT_MUSICXML_EXPORTBREAKS
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlIoTestRefBreaks(const char* file)
        {
        MScore::debugMode = true;
        preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, true);
        preferences.setPreference(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, false);
        MasterScore* score = readScore(DIR + file + ".xml");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::NO);
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_no_ref.xml"));
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_manual_ref.xml"));
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::ALL);
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_all_ref.xml"));
        delete score;
        }
  
  //---------------------------------------------------------
  //   mxmlMscxExportTestRef
  //   read a MuseScore mscx file, write to a MusicXML file and verify against reference
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlMscxExportTestRef(const char* file)
        {
        MScore::debugMode = true;
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        preferences.setPreference(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, false);
        MasterScore* score = readScore(DIR + file + ".mscx");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_ref.xml"));
        delete score;
        }
  
  //---------------------------------------------------------
  //   mxmlMscxExportTestRefBreaks
  //   read a MuseScore mscx file, write to a MusicXML file and verify against reference
  //   using all possible settings for PREF_EXPORT_MUSICXML_EXPORTBREAKS
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlMscxExportTestRefBreaks(const char* file)
        {
        MScore::debugMode = true;
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        preferences.setPreference(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, false);
        MasterScore* score = readScore(DIR + file + ".mscx");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::NO);
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_no_ref.xml"));
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_manual_ref.xml"));
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::ALL);
        QVERIFY(saveMusicXml(score, QString(file) + ".xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + ".xml", DIR + file + "_all_ref.xml"));
        delete score;
        }
  
  //---------------------------------------------------------
  //   mxmlReadTestCompr
  //   read a compressed MusicXML file, write to a new file and verify against reference
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlReadTestCompr(const char* file)
        {
        MScore::debugMode = true;
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, true);
        MasterScore* score = readScore(DIR + file + ".mxl");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        QVERIFY(saveMusicXml(score, QString(file) + "_mxl_read.xml"));
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + "_mxl_read.xml", DIR + file + ".xml"));
        delete score;
        }
  
  //---------------------------------------------------------
  //   mxmlReadWriteTestCompr
  //   read a MusicXML file, write to a compressed MusicXML file,
  //   read the compressed MusicXML file, write to a new file and verify files are identical
  //---------------------------------------------------------
  
  void TestMxmlIO::mxmlReadWriteTestCompr(const char* file)
        {
        // read xml
        MScore::debugMode = true;
        preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
        preferences.setPreference(PREF_IMPORT_MUSICXML_IMPORTBREAKS, true);
        MasterScore* score = readScore(DIR + file + ".xml");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        // write mxl
        QVERIFY(saveMxl(score, QString(file) + "_mxl_read_write.mxl"));
        delete score;
        // read mxl
        score = readCreatedScore(QString(file) + "_mxl_read_write.mxl");
        QVERIFY(score);
        fixupScore(score);
        score->doLayout();
        // write and verify
        QVERIFY(saveCompareMusicXmlScore(score, QString(file) + "_mxl_read_write.xml", DIR + file + ".xml"));
        delete score;
        }
  
  QTEST_MAIN(TestMxmlIO)
  #include "tst_mxml_io.moc"
  