2016-07-30 23:17:49 +02:00
# include <c++utilities/conversion/stringconversion.h>
2016-08-03 17:48:53 +02:00
# include <c++utilities/io/catchiofailure.h>
2018-02-03 17:41:58 +01:00
# include <c++utilities/io/misc.h>
2018-02-20 21:36:55 +01:00
# include <c++utilities/io/path.h>
2016-07-30 23:17:49 +02:00
# include <c++utilities/tests/testutils.h>
2016-08-03 17:48:53 +02:00
# include <tagparser/mediafileinfo.h>
2016-07-30 23:17:49 +02:00
# include <cppunit/extensions/HelperMacros.h>
# include <cppunit/TestFixture.h>
# include <iostream>
2016-08-03 17:48:53 +02:00
# include <fstream>
2016-07-30 23:17:49 +02:00
using namespace std ;
using namespace TestUtilities ;
2017-05-30 23:57:16 +02:00
using namespace TestUtilities : : Literals ;
2016-08-03 17:48:53 +02:00
using namespace ConversionUtilities ;
using namespace Media ;
2016-07-30 23:17:49 +02:00
using namespace CPPUNIT_NS ;
enum class TagStatus
{
Original ,
TestMetaDataPresent ,
Removed
} ;
/*!
* \ brief The CliTests class tests the command line interface .
*/
class CliTests : public TestFixture
{
CPPUNIT_TEST_SUITE ( CliTests ) ;
# ifdef PLATFORM_UNIX
CPPUNIT_TEST ( testBasicReadingAndWriting ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_TEST ( testSpecifyingNativeFieldIds ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_TEST ( testHandlingOfTargets ) ;
2016-08-05 01:48:36 +02:00
CPPUNIT_TEST ( testId3SpecificOptions ) ;
2017-05-18 02:34:07 +02:00
CPPUNIT_TEST ( testEncodingOption ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_TEST ( testMultipleFiles ) ;
2016-08-07 22:03:52 +02:00
CPPUNIT_TEST ( testOutputFile ) ;
2018-02-20 21:36:55 +01:00
CPPUNIT_TEST ( testBackupDir ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_TEST ( testMultipleValuesPerField ) ;
CPPUNIT_TEST ( testHandlingAttachments ) ;
2016-07-31 23:22:22 +02:00
CPPUNIT_TEST ( testDisplayingInfo ) ;
2017-06-14 00:09:10 +02:00
CPPUNIT_TEST ( testSettingTrackMetaData ) ;
2016-07-31 23:22:22 +02:00
CPPUNIT_TEST ( testExtraction ) ;
CPPUNIT_TEST ( testReadingAndWritingDocumentTitle ) ;
2016-11-15 22:45:19 +01:00
CPPUNIT_TEST ( testFileLayoutOptions ) ;
2018-02-03 17:41:58 +01:00
CPPUNIT_TEST ( testJsonExport ) ;
2016-07-30 23:17:49 +02:00
# endif
CPPUNIT_TEST_SUITE_END ( ) ;
public :
void setUp ( ) ;
void tearDown ( ) ;
# ifdef PLATFORM_UNIX
void testBasicReadingAndWriting ( ) ;
2017-01-23 00:27:21 +01:00
void testSpecifyingNativeFieldIds ( ) ;
2016-07-30 23:17:49 +02:00
void testHandlingOfTargets ( ) ;
2016-08-05 01:48:36 +02:00
void testId3SpecificOptions ( ) ;
2017-05-18 02:34:07 +02:00
void testEncodingOption ( ) ;
2016-07-30 23:17:49 +02:00
void testMultipleFiles ( ) ;
2016-08-07 22:03:52 +02:00
void testOutputFile ( ) ;
2018-02-20 21:36:55 +01:00
void testBackupDir ( ) ;
2016-07-30 23:17:49 +02:00
void testMultipleValuesPerField ( ) ;
void testHandlingAttachments ( ) ;
2016-07-31 23:22:22 +02:00
void testDisplayingInfo ( ) ;
2017-06-14 00:09:10 +02:00
void testSettingTrackMetaData ( ) ;
2016-07-31 23:22:22 +02:00
void testExtraction ( ) ;
void testReadingAndWritingDocumentTitle ( ) ;
2016-11-15 22:45:19 +01:00
void testFileLayoutOptions ( ) ;
2018-02-03 17:41:58 +01:00
void testJsonExport ( ) ;
2016-07-30 23:17:49 +02:00
# endif
private :
} ;
CPPUNIT_TEST_SUITE_REGISTRATION ( CliTests ) ;
void CliTests : : setUp ( )
{ }
void CliTests : : tearDown ( )
{ }
# ifdef PLATFORM_UNIX
2017-01-23 00:27:21 +01:00
template < typename StringType , bool negateErrorCond = false >
bool testContainsSubstrings ( const StringType & str , std : : initializer_list < const typename StringType : : value_type * > substrings )
{
2017-09-22 00:19:24 +02:00
vector < const typename StringType : : value_type * > failedSubstrings ;
typename StringType : : size_type currentPos = 0 ;
for ( const auto * substr : substrings ) {
if ( ( currentPos = str . find ( substr , currentPos ) ) = = StringType : : npos ) {
failedSubstrings . emplace_back ( substr ) ;
}
currentPos + = std : : strlen ( substr ) ;
}
bool res = failedSubstrings . empty ( ) ;
2017-01-23 00:27:21 +01:00
if ( negateErrorCond ) {
res = ! res ;
}
if ( ! res ) {
if ( ! negateErrorCond ) {
cout < < " - test failed: output does NOT contain required substrings \n " ;
} else {
cout < < " - test failed: output DOES contain substrings it shouldn't \n " ;
}
cout < < " Output: \n " < < str ;
2017-09-22 00:19:24 +02:00
cout < < " Failed substrings: \n " ;
for ( const auto & substr : failedSubstrings ) {
2017-01-23 00:27:21 +01:00
cout < < substr < < " \n " ;
}
}
return res ;
}
template < typename StringType >
bool testNotContainsSubstrings ( const StringType & str , std : : initializer_list < const typename StringType : : value_type * > substrings )
{
return testContainsSubstrings < StringType , true > ( str , substrings ) ;
}
2016-07-30 23:17:49 +02:00
/*!
* \ brief Tests basic reading and writing of tags .
*/
void CliTests : : testBasicReadingAndWriting ( )
{
2016-08-05 01:48:36 +02:00
cout < < " \n Basic reading and writing " < < endl ;
2016-07-30 23:17:49 +02:00
string stdout , stderr ;
// get specific field
2016-07-31 23:22:22 +02:00
const string mkvFile ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
2016-08-03 17:48:53 +02:00
const string mkvFileBackup ( mkvFile + " .bak " ) ;
2016-07-30 23:17:49 +02:00
const char * const args1 [ ] = { " tageditor " , " get " , " title " , " -f " , mkvFile . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
// context of the following fields is the album (so "Title" means the title of the album)
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" album " ,
" Title Elephant Dream - test 2 "
} ) ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stdout . find ( " Year 2010 " ) = = string : : npos ) ;
// get all fields
const char * const args2 [ ] = { " tageditor " , " get " , " -f " , mkvFile . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Title Elephant Dream - test 2 " ,
" Year 2010 " ,
" Comment Matroska Validation File 2, 100,000 timecode scale, odd aspect ratio, and CRC-32. Codecs are AVC and AAC "
} ) ) ;
2016-07-30 23:17:49 +02:00
// set some fields, keep other field
const char * const args3 [ ] = { " tageditor " , " set " , " title=A new title " , " genre=Testfile " , " -f " , mkvFile . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args3 ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stdout . find ( " Changes have been applied " ) ! = string : : npos ) ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Title A new title " ,
" Genre Testfile " ,
" Year 2010 " ,
" Comment Matroska Validation File 2, 100,000 timecode scale, odd aspect ratio, and CRC-32. Codecs are AVC and AAC "
} ) ) ;
// clear backup file
remove ( mkvFileBackup . data ( ) ) ;
2016-07-30 23:17:49 +02:00
// set some fields, discard other
const char * const args4 [ ] = { " tageditor " , " set " , " title=Foo " , " artist=Bar " , " --remove-other-fields " , " -f " , mkvFile . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args4 ) ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Title Foo " ,
" Artist Bar "
} ) ) ;
2016-07-30 23:17:49 +02:00
CPPUNIT_ASSERT ( stdout . find ( " Year " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Comment " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Genre " ) = = string : : npos ) ;
2016-08-03 17:48:53 +02:00
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFileBackup . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
2017-01-23 00:27:21 +01:00
/*!
* \ brief Tests specifying native fields IDs when getting and setting fields .
*/
void CliTests : : testSpecifyingNativeFieldIds ( )
{
cout < < " \n Specifying native field IDs " < < endl ;
string stdout , stderr ;
// get specific field
const string mkvFile ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
const string mkvFileBackup ( mkvFile + " .bak " ) ;
const string mp4File ( workingCopyPath ( " mtx-test-data/aac/he-aacv2-ps.m4a " ) ) ;
const string mp4FileBackup ( mp4File + " .bak " ) ;
const char * const args1 [ ] = { " tageditor " , " set " , " mkv:FOO=bar " , " mp4:©foo=bar " , " mp4:invalid " , " -f " , mkvFile . data ( ) , mp4File . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
// FIXME: provide a way to specify raw data type
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " making MP4 tag field ©foo: It was not possible to find an appropriate raw data type id. UTF-8 will be assumed. " } ) ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " Unable to parse denoted field ID \" invalid \" : MP4 ID must be exactly 4 chars " } ) ) ;
const char * const args2 [ ] = { " tageditor " , " get " , " mkv:FOO " , " mp4:©foo " , " generic:year " , " -f " , mkvFile . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " Year 2010 " } ) ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " FOO bar " } ) ) ;
const char * const args3 [ ] = { " tageditor " , " get " , " mkv:FOO " , " mp4:©foo " , " mp4:invalid " , " generic:year " , " -f " , mp4File . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args3 ) ;
CPPUNIT_ASSERT ( stderr . empty ( ) ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " test " } ) ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " Year none " } ) ) ;
// FIXME: number of whitespaces currently not correct because UTF-8 ©-sign counts as two characters
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " ©foo bar " } ) ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " invalid unable to parse - MP4 ID must be exactly 4 chars " } ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFileBackup . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp4File . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp4FileBackup . data ( ) ) ) ;
2017-01-23 00:27:21 +01:00
}
2016-07-30 23:17:49 +02:00
/*!
* \ brief Tests adding and removing of targets .
*/
void CliTests : : testHandlingOfTargets ( )
{
2016-08-05 01:48:36 +02:00
cout < < " \n Handling of targets " < < endl ;
2016-07-30 23:17:49 +02:00
string stdout , stderr ;
2016-07-31 23:22:22 +02:00
const string mkvFile ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
2016-08-03 17:48:53 +02:00
const string mkvFileBackup ( mkvFile + " .bak " ) ;
2016-07-30 23:17:49 +02:00
const char * const args1 [ ] = { " tageditor " , " get " , " -f " , mkvFile . data ( ) , nullptr } ;
// add song title (title field for tag with level 30)
const char * const args2 [ ] = { " tageditor " , " set " , " target-level=30 " , " title=The song title " , " genre=The song genre " , " target-level=50 " , " genre=The album genre " , " -f " , mkvFile . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args2 ) ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" song " ,
" Title The song title " ,
" Genre The song genre "
} ) ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" album " ,
" Title Elephant Dream - test 2 " ,
" Genre The album genre "
} ) ) ;
remove ( mkvFileBackup . data ( ) ) ;
2016-07-30 23:17:49 +02:00
// remove tags targeting level 30 and 50 and add new tag targeting level 30 and the audio track
2016-07-31 23:22:22 +02:00
const char * const args3 [ ] = { " tageditor " , " set " , " target-level=30 " , " target-tracks=3134325680 " , " title=The audio track " , " encoder=likely some AAC encoder " , " --remove-target " , " target-level=30 " , " --remove-target " , " target-level=50 " , " -f " , mkvFile . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args3 ) ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , { " song " } ) ) ;
CPPUNIT_ASSERT ( testNotContainsSubstrings ( stdout , { " song " , " song " } ) ) ;
2016-08-03 17:48:53 +02:00
CPPUNIT_ASSERT ( stdout . find ( " album " ) = = string : : npos ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" 3134325680 " ,
" Title The audio track " ,
" Encoder likely some AAC encoder "
} ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFileBackup . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
/*!
2016-08-05 01:48:36 +02:00
* \ brief Tests ID3v1 / D3v2 / MP3 specific options .
2016-07-30 23:17:49 +02:00
*/
2016-08-05 01:48:36 +02:00
void CliTests : : testId3SpecificOptions ( )
2016-07-30 23:17:49 +02:00
{
2016-08-05 01:48:36 +02:00
cout < < " \n ID3/MP3 specific options " < < endl ;
string stdout , stderr ;
const string mp3File1 ( workingCopyPath ( " mtx-test-data/mp3/id3-tag-and-xing-header.mp3 " ) ) ;
const string mp3File1Backup ( mp3File1 + " .bak " ) ;
// verify both ID3 tags are detected
const char * const args1 [ ] = { " tageditor " , " get " , " -f " , mp3File1 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-09-22 00:19:24 +02:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
" - \ e[1mID3v1 tag \ e[0m \n "
" Title Cohesion \n "
" Album Double Nickels On The Dime \n "
" Artist Minutemen \n "
" Genre Punk Rock \n "
" Year 1984 \n "
" Comment ExactAudioCopy v0.95b4 \n "
" Track 4 \n " ,
" - \ e[1mID3v2 tag (version 2.3.0) \ e[0m \n "
" Title Cohesion \n "
" Album Double Nickels On The Dime \n "
" Artist Minutemen \n "
" Genre Punk Rock \n "
" Year 1984 \n "
" Comment ExactAudioCopy v0.95b4 \n "
" Track 4/43 \n "
" Duration 00:00:00 \n "
" Encoder settings LAME 64bits version 3.99 (http://lame.sf.net) "
} ) ) ;
2016-08-05 01:48:36 +02:00
// remove ID3v1 tag, convert ID3v2 tag to version 4
const char * const args2 [ ] = { " tageditor " , " set " , " --id3v1-usage " , " never " , " --id3v2-version " , " 4 " , " -f " , mp3File1 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-09-22 00:19:24 +02:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
" - \ e[1mID3v2 tag (version 2.4.0) \ e[0m \n "
" Title Cohesion \n "
" Album Double Nickels On The Dime \n "
" Artist Minutemen \n "
" Genre Punk Rock \n "
" Year 1984 \n "
" Comment ExactAudioCopy v0.95b4 \n "
" Track 4/43 \n "
" Duration 00:00:00 \n "
" Encoder settings LAME 64bits version 3.99 (http://lame.sf.net) "
} ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp3File1Backup . data ( ) ) ) ;
2016-08-05 01:48:36 +02:00
2016-12-28 00:20:00 +01:00
// convert remaining ID3v2 tag to version 2, add an ID3v1 tag again and set a field with unicode char by the way
const char * const args3 [ ] = { " tageditor " , " set " , " album=Dóuble Nickels On The Dime " , " --id3v1-usage " , " always " , " --id3v2-version " , " 2 " , " --id3-init-on-create " , " -f " , mp3File1 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
CPPUNIT_ASSERT_EQUAL ( 0 , execApp ( args3 , stdout , stderr ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , execApp ( args1 , stdout , stderr ) ) ;
2017-09-22 00:19:24 +02:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
" - \ e[1mID3v1 tag \ e[0m \n "
" Title Cohesion \n "
" Album Dóuble Nickels On The Dime \n "
" Artist Minutemen \n "
" Genre Punk Rock \n "
" Year 1984 \n "
" Comment ExactAudioCopy v0.95b4 \n "
" Track 4 \n " ,
" - \ e[1mID3v2 tag (version 2.2.0) \ e[0m \n "
" Title Cohesion \n "
" Album Dóuble Nickels On The Dime \n "
" Artist Minutemen \n "
" Genre Punk Rock \n "
" Year 1984 \n "
" Comment ExactAudioCopy v0.95b4 \n "
" Track 4/43 \n "
" Duration 00:00:00 \n "
" Encoder settings LAME 64bits version 3.99 (http://lame.sf.net) " } ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp3File1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp3File1Backup . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
2017-05-18 02:34:07 +02:00
bool bufferContains ( const char * buffer , size_t bufferSize , const char * needle , size_t needleSize )
{
for ( const char * const bufferEnd = buffer + bufferSize , * const needleEnd = needle + needleSize ; buffer ! = bufferEnd ; + + buffer ) {
const char * needleIterator = needle ;
for ( const char * bufferIterator = buffer ; needleIterator ! = needleEnd & & * needleIterator = = * bufferIterator ; + + needleIterator , + + bufferIterator ) ;
if ( needleIterator > = needleEnd ) {
return true ;
}
}
return false ;
}
template < size_t headSize >
bool fileHeadContains ( const string & fileName , const char * needle , size_t needleSize )
{
ifstream file ;
file . exceptions ( ios_base : : failbit | ios_base : : badbit ) ;
file . open ( fileName , ios_base : : in | ios_base : : binary ) ;
char buffer [ headSize ] ;
file . read ( buffer , sizeof ( buffer ) ) ;
return bufferContains ( buffer , sizeof ( buffer ) , needle , needleSize ) ;
}
/*!
* \ brief Tests the option to set the encoding .
*/
void CliTests : : testEncodingOption ( )
{
cout < < " \n Encoding option " < < endl ;
string stdout , stderr ;
const string mp3File1 ( workingCopyPath ( " mtx-test-data/mp3/id3-tag-and-xing-header.mp3 " ) ) ;
const string mp3File1Backup ( mp3File1 + " .bak " ) ;
// try to use UTF-8 for ID3v2.3: not supported and hence should be ignored, UTF-8 CLI arguments must be converted to UTF-16
const char * const args1 [ ] = { " tageditor " , " set " , " album=Täst " , " --encoding " , " utf8 " , " --id3v1-usage " , " never " , " --id3v2-version " , " 3 " , " -f " , mp3File1 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
CPPUNIT_ASSERT ( stdout . find ( " setting tags: Can't use specified encoding \" utf8 \" in ID3v2 tag (version 2.3.0) because the tag format/version doesn't support it. " ) ! = string : : npos ) ;
// check whether encoding is UTF-16 and BOM is present
CPPUNIT_ASSERT ( fileHeadContains < 1024 > ( mp3File1 , " \x01 \xff \xfe \x54 \x00 \xe4 \x00 \x73 \x00 \x74 \x00 \x00 \x00 " , 13 ) ) ;
remove ( mp3File1Backup . data ( ) ) ;
// try to use UTF-8 for ID3v2.4: UTF-8 should be supported
const char * const args2 [ ] = { " tageditor " , " set " , " album=Täst " , " --encoding " , " utf8 " , " --id3v1-usage " , " never " , " --id3v2-version " , " 4 " , " -f " , mp3File1 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Can't use specified encoding " ) = = string : : npos ) ;
// check whether encoding is UTF-8
CPPUNIT_ASSERT ( fileHeadContains < 1024 > ( mp3File1 , " \x03 \x54 \xc3 \xa4 \x73 \x74 \x00 " , 7 ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp3File1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp3File1Backup . data ( ) ) ) ;
2017-05-18 02:34:07 +02:00
}
2016-07-30 23:17:49 +02:00
/*!
* \ brief Tests reading and writing multiple files at once .
*/
void CliTests : : testMultipleFiles ( )
{
2016-08-05 01:48:36 +02:00
cout < < " \n Reading and writing multiple files at once " < < endl ;
2016-07-30 23:17:49 +02:00
string stdout , stderr ;
2016-07-31 23:22:22 +02:00
const string mkvFile1 ( workingCopyPath ( " matroska_wave1/test1.mkv " ) ) ;
const string mkvFile2 ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
const string mkvFile3 ( workingCopyPath ( " matroska_wave1/test3.mkv " ) ) ;
2016-07-30 23:17:49 +02:00
// get tags of 3 files at once
const char * const args1 [ ] = { " tageditor " , " get " , " -f " , mkvFile1 . data ( ) , mkvFile2 . data ( ) , mkvFile3 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Title Big Buck Bunny - test 1 " ,
" Title Elephant Dream - test 2 " ,
" Title Elephant Dream - test 3 "
} ) ) ;
// clear backup files
remove ( ( mkvFile1 + " .bak " ) . c_str ( ) ) , remove ( ( mkvFile2 + " .bak " ) . c_str ( ) ) , remove ( ( mkvFile3 + " .bak " ) . c_str ( ) ) ;
2016-07-30 23:17:49 +02:00
// set title and part number of 3 files at once
const char * const args2 [ ] = { " tageditor " , " set " , " target-level=30 " , " title=test1 " , " title=test2 " , " title=test3 " , " part+=1 " , " target-level=50 " , " title=MKV testfiles " , " totalparts=3 " , " -f " , mkvFile1 . data ( ) , mkvFile2 . data ( ) , mkvFile3 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args2 ) ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mMatroska tag targeting \" level 50 'album, opera, concert, movie, episode' \" \ e[0m \n "
" Title MKV testfiles \n "
" Year 2010 \n "
" Comment Matroska Validation File1, basic MPEG4.2 and MP3 with only SimpleBlock \n "
" Total parts 3 \n "
" - \ e[1mMatroska tag targeting \" level 30 'track, song, chapter' \" \ e[0m \n "
" Title test1 \n "
" Part 1 " ,
" - \ e[1mMatroska tag targeting \" level 50 'album, opera, concert, movie, episode' \" \ e[0m \n "
" Title MKV testfiles \n "
" Year 2010 \n "
" Comment Matroska Validation File 2, 100,000 timecode scale, odd aspect ratio, and CRC-32. Codecs are AVC and AAC \n "
" Total parts 3 \n "
" - \ e[1mMatroska tag targeting \" level 30 'track, song, chapter' \" \ e[0m \n "
" Title test2 \n "
" Part 2 " ,
" - \ e[1mMatroska tag targeting \" level 50 'album, opera, concert, movie, episode' \" \ e[0m \n "
" Title MKV testfiles \n "
" Year 2010 \n "
" Comment Matroska Validation File 3, header stripping on the video track and no SimpleBlock \n "
" Total parts 3 " ,
" - \ e[1mMatroska tag targeting \" level 30 'track, song, chapter' \" \ e[0m \n "
" Title test3 \n "
" Part 3 "
2016-08-03 17:48:53 +02:00
} ) ) ;
// clear working copies if all tests have been
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile2 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile3 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile1 + " .bak " ) . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile2 + " .bak " ) . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile3 + " .bak " ) . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
2016-08-07 22:03:52 +02:00
/*!
* \ brief Tests reading and writing multiple files at once with output files are specified .
*/
void CliTests : : testOutputFile ( )
{
cout < < " \n Reading and writing multiple files at once with output files specified " < < endl ;
string stdout , stderr ;
const string mkvFile1 ( workingCopyPath ( " matroska_wave1/test1.mkv " ) ) ;
const string mkvFile2 ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
const char * const args1 [ ] = { " tageditor " , " set " , " target-level=30 " , " title=test1 " , " title=test2 " , " -f " , mkvFile1 . data ( ) , mkvFile2 . data ( ) , " -o " , " /tmp/test1.mkv " , " /tmp/test2.mkv " , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
// original files have not been modified
const char * const args2 [ ] = { " tageditor " , " get " , " -f " , mkvFile1 . data ( ) , mkvFile2 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Matroska tag targeting " ) ! = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Title test1 " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Title test2 " ) = = string : : npos ) ;
// specified output files contain new titles
const char * const args3 [ ] = { " tageditor " , " get " , " -f " , " /tmp/test1.mkv " , " /tmp/test2.mkv " , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args3 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mMatroska tag targeting \" level 30 'track, song, chapter' \" \ e[0m \n "
" Title test1 \n " ,
" - \ e[1mMatroska tag targeting \" level 30 'track, song, chapter' \" \ e[0m \n "
" Title test2 \n "
2016-08-07 22:03:52 +02:00
} ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile2 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( " /tmp/test1.mkv " ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( " /tmp/test2.mkv " ) ) ;
2016-08-07 22:03:52 +02:00
}
2018-02-20 21:36:55 +01:00
/*!
* \ brief Tests the " --temp-dir /some/path " option of the set operation .
*/
void CliTests : : testBackupDir ( )
{
cout < < " \n Specifying a backup/temp dir for set operation " < < endl ;
string stdout , stderr ;
const string mkvFileName ( " matroska_wave1/test1.mkv " ) ;
const auto mkvFile ( workingCopyPath ( mkvFileName ) ) ;
CPPUNIT_ASSERT ( mkvFile . size ( ) > = mkvFileName . size ( ) ) ;
const auto backupDir ( mkvFile . substr ( 0 , mkvFile . size ( ) - mkvFileName . size ( ) ) ) ;
const char * const args1 [ ] = { " tageditor " , " set " , " target-level=30 " , " title=test1 " , " -f " , mkvFile . data ( ) , " --temp-dir " , " .. " , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
// specified output file contains new title
const char * const args2 [ ] = { " tageditor " , " get " , " -f " , mkvFile . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
" - \ e[1mMatroska tag targeting \" level 30 'track, song, chapter' \" \ e[0m \n "
" Title test1 \n " ,
} ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( backupDir + " test1.mkv " ) . data ( ) ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT ( remove ( ( mkvFile + " .bak " ) . data ( ) ) ) ;
2018-02-20 21:36:55 +01:00
}
2016-07-30 23:17:49 +02:00
/*!
* \ brief Tests tagging multiple values per field .
*/
void CliTests : : testMultipleValuesPerField ( )
{
2016-08-05 01:48:36 +02:00
cout < < " \n Multiple values per field " < < endl ;
2016-08-03 17:48:53 +02:00
string stdout , stderr ;
2016-08-14 22:47:50 +02:00
const string mkvFile1 ( workingCopyPath ( " matroska_wave1/test1.mkv " ) ) ;
const string mkvFile2 ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
const char * const args1 [ ] = { " tageditor " , " set " , " artist=test1 " , " +artist=test2 " , " +artist=test3 " , " artist=test4 " , " -f " , mkvFile1 . data ( ) , mkvFile2 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2016-08-14 22:47:50 +02:00
const char * const args2 [ ] = { " tageditor " , " get " , " -f " , mkvFile1 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Artist test1 " ,
" Artist test2 " ,
" Artist test3 "
} ) ) ;
2016-08-14 22:47:50 +02:00
CPPUNIT_ASSERT ( stdout . find ( " Artist test4 " ) = = string : : npos ) ; // should be in mkvFile2
2016-08-03 17:48:53 +02:00
2016-08-14 22:47:50 +02:00
const char * const args3 [ ] = { " tageditor " , " get " , " -f " , mkvFile2 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args3 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Artist test1 " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Artist test2 " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Artist test3 " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Artist test4 " ) ! = string : : npos ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile2 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile1 + " .bak " ) . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile2 + " .bak " ) . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
/*!
* \ brief Tests handling attachments .
*/
void CliTests : : testHandlingAttachments ( )
2016-07-31 23:22:22 +02:00
{
2016-08-05 01:48:36 +02:00
cout < < " \n Attachments " < < endl ;
2016-07-31 23:22:22 +02:00
string stdout , stderr ;
const string mkvFile1 ( workingCopyPath ( " matroska_wave1/test1.mkv " ) ) ;
2016-08-03 17:48:53 +02:00
const string mkvFile1Backup ( mkvFile1 + " .bak " ) ;
2016-07-31 23:22:22 +02:00
const string mkvFile2 ( " path= " + testFilePath ( " matroska_wave1/test2.mkv " ) ) ;
// add attachment
const char * const args2 [ ] = { " tageditor " , " set " , " --add-attachment " , " name=test2.mkv " , " mime=video/x-matroska " , " desc=Test attachment " , mkvFile2 . data ( ) , " -f " , mkvFile1 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2016-07-31 23:22:22 +02:00
const char * const args1 [ ] = { " tageditor " , " info " , " -f " , mkvFile1 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Attachments: " ,
" Name test2.mkv " ,
" MIME-type video/x-matroska " ,
" Description Test attachment " ,
" Size 20.16 MiB (21142764 byte) "
} ) ) ;
// clear backup file
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1Backup . data ( ) ) ) ;
2016-07-31 23:22:22 +02:00
// update attachment
const char * const args3 [ ] = { " tageditor " , " set " , " --update-attachment " , " name=test2.mkv " , " desc=Updated test attachment " , " -f " , mkvFile1 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args3 ) ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2016-08-03 17:48:53 +02:00
" Attachments: " ,
" Name test2.mkv " ,
" MIME-type video/x-matroska " ,
" Description Updated test attachment " ,
" Size 20.16 MiB (21142764 byte) "
} ) ) ;
// clear backup file
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1Backup . data ( ) ) ) ;
2016-08-03 17:48:53 +02:00
// extract assigned attachment again
const char * const args4 [ ] = { " tageditor " , " extract " , " --attachment " , " name=test2.mkv " , " -f " , mkvFile1 . data ( ) , " -o " , " /tmp/extracted.mkv " , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args4 ) ;
2016-08-03 17:48:53 +02:00
fstream origFile , extFile ;
origFile . exceptions ( ios_base : : failbit | ios_base : : badbit ) , extFile . exceptions ( ios_base : : failbit | ios_base : : badbit ) ;
origFile . open ( mkvFile2 . data ( ) + 5 , ios_base : : in | ios_base : : binary ) , extFile . open ( " /tmp/extracted.mkv " , ios_base : : in | ios_base : : binary ) ;
origFile . seekg ( 0 , ios_base : : end ) , extFile . seekg ( 0 , ios_base : : end ) ;
int64 origFileSize = origFile . tellg ( ) , extFileSize = extFile . tellg ( ) ;
CPPUNIT_ASSERT_EQUAL ( origFileSize , extFileSize ) ;
for ( origFile . seekg ( 0 ) , extFile . seekg ( 0 ) ; origFileSize > 0 ; - - origFileSize ) {
CPPUNIT_ASSERT_EQUAL ( origFile . get ( ) , extFile . get ( ) ) ;
}
remove ( " /tmp/extracted.mkv " ) ;
2016-07-31 23:22:22 +02:00
// remove assigned attachment
const char * const args5 [ ] = { " tageditor " , " set " , " --remove-attachment " , " name=test2.mkv " , " -f " , mkvFile1 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args5 ) ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2016-07-31 23:22:22 +02:00
CPPUNIT_ASSERT ( stdout . find ( " Attachments: " ) = = string : : npos ) ;
CPPUNIT_ASSERT ( stdout . find ( " Name test2.mkv " ) = = string : : npos ) ;
2016-08-03 17:48:53 +02:00
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile1Backup . data ( ) ) ) ;
2016-07-31 23:22:22 +02:00
}
/*!
* \ brief Tests displaying general file info .
*/
void CliTests : : testDisplayingInfo ( )
{
2016-08-05 01:48:36 +02:00
cout < < " \n Displaying general file info " < < endl ;
string stdout , stderr ;
// test Matroska file
const string mkvFile ( testFilePath ( " matroska_wave1/test2.mkv " ) ) ;
const char * const args1 [ ] = { " tageditor " , " info " , " -f " , mkvFile . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mContainer format: Matroska \ e[0m \n "
2016-08-05 01:48:36 +02:00
" Document type matroska \n "
" Read version 1 \n "
" Version 1 \n "
" Document read version 2 \n "
" Document version 2 \n "
2016-11-16 22:06:51 +01:00
" Duration 47 s 509 ms \n "
" Tag position before data \n "
" Index position before data \n " ,
2017-09-22 00:19:24 +02:00
" - \ e[1mTracks: H.264-576p / AAC-LC-2ch \ e[0m \n "
2016-08-05 01:48:36 +02:00
" ID 1863976627 \n "
" Type Video \n "
" Format Advanced Video Coding Main Profile \n "
" Abbreviation H.264 \n "
" Raw format ID V_MPEG4/ISO/AVC \n "
" FPS 24 \n " ,
" ID 3134325680 \n "
" Type Audio \n "
" Format Advanced Audio Coding Low Complexity Profile \n "
" Abbreviation MPEG-4 AAC-LC \n "
" Raw format ID A_AAC \n "
" Channel config 2 channels: front-left, front-right \n "
" Sampling frequency 48000 Hz " } ) ) ;
// test MP4 file with AAC track using SBR and PS extensions
const string mp4File ( testFilePath ( " mtx-test-data/aac/he-aacv2-ps.m4a " ) ) ;
const char * const args2 [ ] = { " tageditor " , " info " , " -f " , mp4File . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2017-01-23 00:27:21 +01:00
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mContainer format: MPEG-4 Part 14 \ e[0m \n "
2016-08-05 01:48:36 +02:00
" Document type mp42 \n "
" Duration 3 min \n "
" Creation time 2014-12-10 16:22:41 \n "
" Modification time 2014-12-10 16:22:41 \n " ,
2017-09-22 00:19:24 +02:00
" - \ e[1mTracks: HE-AAC-2ch \ e[0m \n "
2016-08-05 01:48:36 +02:00
" ID 1 \n "
" Name soun \n "
" Type Audio \n "
" Format Advanced Audio Coding Low Complexity Profile \n "
" Abbreviation MPEG-4 AAC-LC \n "
" Extensions Spectral Band Replication and Parametric Stereo / HE-AAC v2 \n "
" Raw format ID mp4a \n "
" Size 879.65 KiB (900759 byte) \n "
2017-09-14 22:10:17 +02:00
" Duration 3 min 138 ms 666 µs 600 ns \n "
2016-08-05 01:48:36 +02:00
" Channel config 1 channel: front-center \n "
" Extension channel config 2 channels: front-left, front-right \n "
" Bitrate 40 kbit/s \n "
" Bits per sample 16 \n "
2017-06-14 00:09:10 +02:00
" Sampling frequency 24000 Hz \n "
" Extension sampling frequency 48000 Hz \n "
" Sample count 4222 \n "
" Creation time 2014-12-10 16:22:41 \n "
" Modification time 2014-12-10 16:22:41 " } ) ) ;
}
/*!
* \ brief Tests setting track meta - data .
*/
void CliTests : : testSettingTrackMetaData ( )
{
cout < < " \n Setting track meta-data " < < endl ;
string stdout , stderr ;
// test Matroska file
const string mkvFile ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
const string mp4File ( workingCopyPath ( " mtx-test-data/aac/he-aacv2-ps.m4a " ) ) ;
const char * const args1 [ ] = { " tageditor " , " set " , " title=title of tag " ,
" track=1863976627 " , " name=video track " ,
" track=3134325680 " , " name=audio track " , " language=ger " , " default=yes " , " forced=yes " ,
" tag=any " , " artist=setting tag value again " ,
" track=any " , " name1=sbr and ps " , " language1=eng " ,
" -f " , mkvFile . data ( ) , mp4File . data ( ) , nullptr } ;
const char * const args2 [ ] = { " tageditor " , " info " , " -f " , mkvFile . data ( ) , nullptr } ;
const char * const args3 [ ] = { " tageditor " , " get " , " -f " , mkvFile . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mContainer format: Matroska \ e[0m \n "
2017-06-14 00:09:10 +02:00
" Document type matroska \n "
" Read version 1 \n "
" Version 1 \n "
" Document read version 2 \n "
" Document version 2 \n "
" Duration 47 s 509 ms \n "
" Tag position before data \n "
" Index position before data \n " ,
2017-09-22 00:19:24 +02:00
" - \ e[1mTracks: H.264-576p / AAC-LC-2ch-ger \ e[0m \n "
2017-06-14 00:09:10 +02:00
" ID 1863976627 \n "
" Name video track \n "
" Type Video \n "
" Format Advanced Video Coding Main Profile \n "
" Abbreviation H.264 \n "
" Raw format ID V_MPEG4/ISO/AVC \n "
" FPS 24 \n " ,
" ID 3134325680 \n "
" Name audio track \n "
" Type Audio \n "
" Language ger \n "
" Format Advanced Audio Coding Low Complexity Profile \n "
" Abbreviation MPEG-4 AAC-LC \n "
" Raw format ID A_AAC \n "
" Channel config 2 channels: front-left, front-right \n "
" Sampling frequency 48000 Hz \n "
" Labeled as default, forced " } ) ) ;
TESTUTILS_ASSERT_EXEC ( args3 ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mMatroska tag targeting \" level 50 'album, opera, concert, movie, episode' \" \ e[0m \n "
" Title title of tag \n "
" Artist setting tag value again \n "
" Year 2010 \n "
" Comment Matroska Validation File 2, 100,000 timecode scale, odd aspect ratio, and CRC-32. Codecs are AVC and AAC "
2017-06-14 00:09:10 +02:00
} ) ) ;
const char * const args4 [ ] = { " tageditor " , " info " , " -f " , mp4File . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args4 ) ;
CPPUNIT_ASSERT ( testContainsSubstrings ( stdout , {
2017-09-22 00:19:24 +02:00
" - \ e[1mContainer format: MPEG-4 Part 14 \ e[0m \n "
2017-06-14 00:09:10 +02:00
" Document type mp42 \n "
" Duration 3 min \n "
" Creation time 2014-12-10 16:22:41 \n "
" Modification time 2014-12-10 16:22:41 \n " ,
2017-09-22 00:19:24 +02:00
" - \ e[1mTracks: HE-AAC-2ch-eng \ e[0m \n "
2017-06-14 00:09:10 +02:00
" ID 1 \n "
" Name sbr and ps \n "
" Type Audio \n "
" Language eng \n "
" Format Advanced Audio Coding Low Complexity Profile \n "
" Abbreviation MPEG-4 AAC-LC \n "
" Extensions Spectral Band Replication and Parametric Stereo / HE-AAC v2 \n "
" Raw format ID mp4a \n "
" Size 879.65 KiB (900759 byte) \n "
2017-09-14 22:10:17 +02:00
" Duration 3 min 138 ms 645 µs 800 ns \n "
2017-06-14 00:09:10 +02:00
" Channel config 1 channel: front-center \n "
" Extension channel config 2 channels: front-left, front-right \n "
" Bitrate 40 kbit/s \n "
" Bits per sample 16 \n "
2016-08-05 01:48:36 +02:00
" Sampling frequency 24000 Hz \n "
" Extension sampling frequency 48000 Hz \n "
" Sample count 4222 \n "
" Creation time 2014-12-10 16:22:41 \n "
" Modification time 2014-12-10 16:22:41 " } ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp4File . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile + " .bak " ) . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mp4File + " .bak " ) . data ( ) ) ) ;
2016-07-31 23:22:22 +02:00
}
/*!
2016-08-03 17:48:53 +02:00
* \ brief Tests extraction of field values ( used to extract cover or other binary fields ) .
* \ remarks Extraction of attachments is already tested in testHandlingAttachments ( ) .
2016-07-31 23:22:22 +02:00
*/
void CliTests : : testExtraction ( )
2016-07-30 23:17:49 +02:00
{
2016-08-05 01:48:36 +02:00
cout < < " \n Extraction " < < endl ;
2016-08-03 17:48:53 +02:00
string stdout , stderr ;
2016-08-05 01:48:36 +02:00
const string mp4File1 ( testFilePath ( " mtx-test-data/alac/othertest-itunes.m4a " ) ) ;
2016-08-03 17:48:53 +02:00
// test extraction of cover
2016-08-05 01:48:36 +02:00
const char * const args1 [ ] = { " tageditor " , " extract " , " cover " , " -f " , mp4File1 . data ( ) , " -o " , " /tmp/extracted.jpeg " , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
2016-08-03 17:48:53 +02:00
MediaFileInfo extractedInfo ( " /tmp/extracted.jpeg " ) ;
extractedInfo . open ( true ) ;
extractedInfo . parseContainerFormat ( ) ;
2017-05-30 23:57:16 +02:00
CPPUNIT_ASSERT_EQUAL ( 22771 _st , extractedInfo . size ( ) ) ;
2016-08-03 17:48:53 +02:00
CPPUNIT_ASSERT ( ContainerFormat : : Jpeg = = extractedInfo . containerFormat ( ) ) ;
extractedInfo . invalidate ( ) ;
// test assignment of cover by the way
const string mp4File2 ( workingCopyPath ( " mtx-test-data/aac/he-aacv2-ps.m4a " ) ) ;
const char * const args2 [ ] = { " tageditor " , " set " , " cover=/tmp/extracted.jpeg " , " -f " , mp4File2 . data ( ) , nullptr } ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args2 ) ;
2016-08-03 17:48:53 +02:00
const char * const args3 [ ] = { " tageditor " , " extract " , " cover " , " -f " , mp4File2 . data ( ) , " -o " , " /tmp/extracted.jpeg " , nullptr } ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( " /tmp/extracted.jpeg " ) ) ;
2016-08-05 01:48:36 +02:00
TESTUTILS_ASSERT_EXEC ( args3 ) ;
2016-08-03 17:48:53 +02:00
extractedInfo . open ( true ) ;
extractedInfo . parseContainerFormat ( ) ;
2017-05-30 23:57:16 +02:00
CPPUNIT_ASSERT_EQUAL ( 22771 _st , extractedInfo . size ( ) ) ;
2016-08-03 17:48:53 +02:00
CPPUNIT_ASSERT ( ContainerFormat : : Jpeg = = extractedInfo . containerFormat ( ) ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( " /tmp/extracted.jpeg " ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp4File2 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mp4File2 + " .bak " ) . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
/*!
2016-07-31 23:22:22 +02:00
* \ brief Tests reading and writing the document title .
2016-07-30 23:17:49 +02:00
*/
2016-07-31 23:22:22 +02:00
void CliTests : : testReadingAndWritingDocumentTitle ( )
2016-07-30 23:17:49 +02:00
{
2016-08-05 01:48:36 +02:00
cout < < " \n Document title " < < endl ;
string stdout , stderr ;
const string mkvFile ( workingCopyPath ( " matroska_wave1/test2.mkv " ) ) ;
const char * const args1 [ ] = { " tageditor " , " set " , " --doc-title " , " Foo " , " -f " , mkvFile . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args1 ) ;
const char * const args2 [ ] = { " tageditor " , " info " , " -f " , mkvFile . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Title Foo " ) ! = string : : npos ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mkvFile . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mkvFile + " .bak " ) . data ( ) ) ) ;
2016-07-30 23:17:49 +02:00
}
2016-11-15 22:45:19 +01:00
/*!
* \ brief Tests options for controlling file layout .
*/
void CliTests : : testFileLayoutOptions ( )
{
cout < < " \n File layout options " < < endl ;
string stdout , stderr ;
const string mp4File1 ( workingCopyPath ( " mtx-test-data/alac/othertest-itunes.m4a " ) ) ;
2016-11-19 21:46:20 +01:00
const char * const args1 [ ] = { " tageditor " , " set " , " --tag-pos " , " back " , " --force " , " -f " , mp4File1 . data ( ) , nullptr } ;
2016-11-15 22:45:19 +01:00
TESTUTILS_ASSERT_EXEC ( args1 ) ;
const char * const args2 [ ] = { " tageditor " , " info " , " -f " , mp4File1 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args2 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Tag position after data " ) ! = string : : npos ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp4File1 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mp4File1 + " .bak " ) . data ( ) ) ) ;
2016-11-19 21:46:20 +01:00
const string mp4File2 ( workingCopyPath ( " mp4/test1.m4a " ) ) ;
const char * const args3 [ ] = { " tageditor " , " set " , " genre=Rock " , " --index-pos " , " back " , " --force " , " -f " , mp4File2 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args3 ) ;
const char * const args4 [ ] = { " tageditor " , " info " , " -f " , mp4File2 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args4 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Tag position after data " ) ! = string : : npos ) ;
const char * const args5 [ ] = { " tageditor " , " get " , " -f " , mp4File2 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args5 ) ;
2017-09-22 00:19:24 +02:00
CPPUNIT_ASSERT ( stdout . find ( " - \ e[1mMP4/iTunes tag \ e[0m \n "
" Title You Shook Me All Night Long \n "
" Album Who Made Who \n "
" Artist ACDC \n "
" Genre Rock \n "
" Year 1986 \n "
" Track 2/9 \n "
" Encoder Nero AAC codec / 1.5.3.0, remuxed with Lavf57.56.100 \n "
" Encoder settings ndaudio 1.5.3.0 / -q 0.34 " ) ! = string : : npos ) ;
2016-11-19 21:46:20 +01:00
remove ( ( mp4File2 + " .bak " ) . data ( ) ) ;
const char * const args6 [ ] = { " tageditor " , " set " , " --index-pos " , " front " , " --force " , " -f " , mp4File2 . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args6 ) ;
TESTUTILS_ASSERT_EXEC ( args4 ) ;
CPPUNIT_ASSERT ( stdout . find ( " Tag position before data " ) ! = string : : npos ) ;
2018-02-21 17:24:13 +01:00
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( mp4File2 . data ( ) ) ) ;
CPPUNIT_ASSERT_EQUAL ( 0 , remove ( ( mp4File2 + " .bak " ) . data ( ) ) ) ;
2016-11-15 22:45:19 +01:00
}
2018-02-03 17:41:58 +01:00
/*!
* \ brief Tests the JSON export .
*/
void CliTests : : testJsonExport ( )
{
cout < < " \n JSON export " < < endl ;
string stdout , stderr ;
const auto file ( testFilePath ( " matroska_wave1/test3.mkv " ) ) ;
const auto expectedJson ( IoUtilities : : readFile ( testFilePath ( " matroska_wave1-test3.json " ) , 2048 ) ) ;
const char * const args [ ] = { " tageditor " , " export " , " --pretty " , " -f " , file . data ( ) , nullptr } ;
TESTUTILS_ASSERT_EXEC ( args ) ;
CPPUNIT_ASSERT_EQUAL ( expectedJson , stdout ) ;
}
2016-07-30 23:17:49 +02:00
# endif