Add tests and fix errors tests have discovered
This commit is contained in:
parent
fecceb41a3
commit
588099d1f8
@ -20,17 +20,6 @@ linux:build:
|
|||||||
- tv_rename_gui
|
- tv_rename_gui
|
||||||
expire_in: 30 min
|
expire_in: 30 min
|
||||||
|
|
||||||
linux:test:
|
|
||||||
image: debian
|
|
||||||
stage: test
|
|
||||||
needs: ["linux:build"]
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- apt update
|
|
||||||
- apt install -y libcurl4 sqlite3
|
|
||||||
script:
|
|
||||||
- ./tv_rename --help
|
|
||||||
|
|
||||||
linux:codacy:
|
linux:codacy:
|
||||||
image: debian
|
image: debian
|
||||||
stage: test
|
stage: test
|
||||||
@ -43,7 +32,6 @@ linux:codacy:
|
|||||||
script:
|
script:
|
||||||
- make test.out
|
- make test.out
|
||||||
- make check
|
- make check
|
||||||
after_script:
|
|
||||||
- find . -type f -name "*.gcno" -execdir gcov -pb -r {} +
|
- find . -type f -name "*.gcno" -execdir gcov -pb -r {} +
|
||||||
- gcovr --root . -k -j 2 --xml -o gcovr_report.xml --exclude-directories "tests" --exclude-directories "gtk" --exclude-directories "win*" --exclude-directories "sqlite-am*" --exclude-directories "rapidjson"
|
- gcovr --root . -k -j 2 --xml -o gcovr_report.xml --exclude-directories "tests" --exclude-directories "gtk" --exclude-directories "win*" --exclude-directories "sqlite-am*" --exclude-directories "rapidjson"
|
||||||
- bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r "gcovr_report.xml" --language CPP --force-language
|
- bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r "gcovr_report.xml" --language CPP --force-language
|
||||||
|
2
Makefile
2
Makefile
@ -188,7 +188,7 @@ locale/%/LC_MESSAGES/tv_rename.mo: translations/%.po locale/%/LC_MESSAGES
|
|||||||
|
|
||||||
test.out: tests/test.cpp functions.cpp unix/network.cpp progress.cpp\
|
test.out: tests/test.cpp functions.cpp unix/network.cpp progress.cpp\
|
||||||
unix/filesystem.cpp tv_rename.cpp
|
unix/filesystem.cpp tv_rename.cpp
|
||||||
$(CXX) $^ -lcurl -lsqlite3 --coverage -o test.out
|
$(CXX) $^ -lcurl -lsqlite3 --coverage -g -fsanitize=address,undefined -o test.out
|
||||||
|
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: test.out
|
check: test.out
|
||||||
|
@ -28,6 +28,7 @@ bool exists( const string &path );
|
|||||||
bool isDirectory( const string &path );
|
bool isDirectory( const string &path );
|
||||||
bool rename( const string &file_a, const string &file_b );
|
bool rename( const string &file_a, const string &file_b );
|
||||||
string canonical( const string &path );
|
string canonical( const string &path );
|
||||||
|
bool createDirectoryFull( const string &path );
|
||||||
|
|
||||||
class Directory {
|
class Directory {
|
||||||
public:
|
public:
|
||||||
|
@ -56,27 +56,20 @@ std::wstring LMsg( int id, ... ) {
|
|||||||
static wchar_t local[MAX_PATH];
|
static wchar_t local[MAX_PATH];
|
||||||
auto hInstance = GetModuleHandle( NULL );
|
auto hInstance = GetModuleHandle( NULL );
|
||||||
LoadString( hInstance, id, local, MAX_PATH );
|
LoadString( hInstance, id, local, MAX_PATH );
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start( args, id );
|
|
||||||
int count = 0;
|
|
||||||
const wchar_t *p;
|
|
||||||
while ( ( p = va_arg( args, const wchar_t * ) ) != NULL )
|
|
||||||
count++;
|
|
||||||
va_end( args );
|
|
||||||
|
|
||||||
if ( count == 0 )
|
|
||||||
return local;
|
|
||||||
|
|
||||||
va_start( args, id );
|
va_start( args, id );
|
||||||
// _vscprintf doesn't count ending '\0'
|
// _vscprintf doesn't count ending '\0'
|
||||||
int len = _vscwprintf( local, args ) + 1;
|
int len = _vscwprintf( local, args ) + 1;
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
wchar_t *text = new wchar_t[len];
|
wchar_t *text = new wchar_t[len];
|
||||||
va_start( args, id );
|
va_start( args, id );
|
||||||
vswprintf( text, len + 1, local, args );
|
vswprintf( text, len + 1, local, args );
|
||||||
|
va_end( args );
|
||||||
std::wstring ret = text;
|
std::wstring ret = text;
|
||||||
delete[] text;
|
delete[] text;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,24 +78,18 @@ std::wstring LMsg( int id, ... ) {
|
|||||||
std::string getlocalized( const char *id, ... ) {
|
std::string getlocalized( const char *id, ... ) {
|
||||||
const char *local = gettext( id );
|
const char *local = gettext( id );
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start( args, id );
|
|
||||||
int count = 0;
|
|
||||||
const char *p;
|
|
||||||
while ( ( p = va_arg( args, const char * ) ) != NULL )
|
|
||||||
count++;
|
|
||||||
va_end( args );
|
|
||||||
|
|
||||||
if ( count == 0 )
|
|
||||||
return local;
|
|
||||||
|
|
||||||
va_start( args, id );
|
va_start( args, id );
|
||||||
int len = vsnprintf( nullptr, 0, local, args );
|
int len = vsnprintf( nullptr, 0, local, args ) + 1;
|
||||||
va_end( args );
|
va_end( args );
|
||||||
char *text = new char[len + 1];
|
|
||||||
|
char *text = new char[len];
|
||||||
va_start( args, id );
|
va_start( args, id );
|
||||||
vsnprintf( text, len + 1, local, args );
|
vsnprintf( text, len + 1, local, args );
|
||||||
|
va_end( args );
|
||||||
std::string ret = text;
|
std::string ret = text;
|
||||||
delete[] text;
|
delete[] text;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,10 +129,14 @@ bool searchSeason( const char_t *const path, size_t &season_pos,
|
|||||||
if ( ( path[cur_pos] == 's' || path[cur_pos] == 'S' ) &&
|
if ( ( path[cur_pos] == 's' || path[cur_pos] == 'S' ) &&
|
||||||
iswdigit( path[cur_pos + 1] ) ) {
|
iswdigit( path[cur_pos + 1] ) ) {
|
||||||
cur_pos++;
|
cur_pos++;
|
||||||
|
if ( path[cur_pos] == '\0' )
|
||||||
|
return false;
|
||||||
season_pos = cur_pos; // after ++ because we want the first pos to
|
season_pos = cur_pos; // after ++ because we want the first pos to
|
||||||
// point to season's number
|
// point to season's number
|
||||||
while ( iswdigit( path[cur_pos] ) )
|
while ( iswdigit( path[cur_pos] ) )
|
||||||
cur_pos++;
|
cur_pos++;
|
||||||
|
if ( path[cur_pos] == '\0' )
|
||||||
|
return false;
|
||||||
if ( ( path[cur_pos] == 'e' || path[cur_pos] == 'E' ) &&
|
if ( ( path[cur_pos] == 'e' || path[cur_pos] == 'E' ) &&
|
||||||
iswdigit( path[cur_pos + 1] ) ) {
|
iswdigit( path[cur_pos + 1] ) ) {
|
||||||
ep_pos = cur_pos + 1;
|
ep_pos = cur_pos + 1;
|
||||||
@ -228,7 +219,7 @@ void printPatternHelp() {
|
|||||||
cout << " %season - " << _( PATTERN_SEASON ) << std::endl;
|
cout << " %season - " << _( PATTERN_SEASON ) << std::endl;
|
||||||
cout << " " << _( PATTERN_LEADING_ZERO ) << std::endl;
|
cout << " " << _( PATTERN_LEADING_ZERO ) << std::endl;
|
||||||
cout << " %2season " << _( PATTERN_LEADING_NUM ) << std::endl;
|
cout << " %2season " << _( PATTERN_LEADING_NUM ) << std::endl;
|
||||||
cout << " %episode - " << _( PATTERN_EPISODE ) << std::endl;
|
cout << " %episode - " << _( PATTERN_EPISODE ) << std::endl;
|
||||||
cout << " " << _( PATTERN_LEADING_ZERO ) << std::endl;
|
cout << " " << _( PATTERN_LEADING_ZERO ) << std::endl;
|
||||||
cout << " %2episode " << _( PATTERN_LEADING_NUM ) << std::endl;
|
cout << " %2episode " << _( PATTERN_LEADING_NUM ) << std::endl;
|
||||||
cout << _( PATTERN_DEFAULT ) << " \"%filename - %epname\"" << std::endl;
|
cout << _( PATTERN_DEFAULT ) << " \"%filename - %epname\"" << std::endl;
|
||||||
@ -426,11 +417,17 @@ string sanitize( const string &str ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void prepareDB( const string &_pattern ) {
|
void prepareDB( const string &_pattern ) {
|
||||||
|
auto dbPath = getDBName();
|
||||||
|
auto dbDir =
|
||||||
|
dbPath.substr( 0, dbPath.find_last_of( TEXT( "/" ), dbPath.length() ) );
|
||||||
|
if ( !FSLib::exists( dbDir ) )
|
||||||
|
FSLib::createDirectoryFull( dbDir );
|
||||||
|
|
||||||
SQLite::Database db{};
|
SQLite::Database db{};
|
||||||
try {
|
try {
|
||||||
db.open( getDBName(), SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE );
|
db.open( dbPath, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE );
|
||||||
} catch ( std::exception &e ) {
|
} catch ( std::exception &e ) {
|
||||||
cerr << _( DB_NOT_CREATE ) << " " << getDBName() << std::endl;
|
cerr << _( DB_NOT_CREATE ) << " " << dbPath << std::endl;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
db.exec(
|
db.exec(
|
||||||
|
@ -30,14 +30,14 @@
|
|||||||
#ifndef GUI // Don't need terminal specific functions in GUI
|
#ifndef GUI // Don't need terminal specific functions in GUI
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
size_t getTermWidth() {
|
int getTermWidth() {
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
|
||||||
GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi );
|
GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi );
|
||||||
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||||
}
|
}
|
||||||
#else // UNIX
|
#else // UNIX
|
||||||
size_t getTermWidth() {
|
int getTermWidth() {
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
ioctl( 0, TIOCGWINSZ, &w );
|
ioctl( 0, TIOCGWINSZ, &w );
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ void home( size_t width ) {
|
|||||||
|
|
||||||
#endif // not GUI
|
#endif // not GUI
|
||||||
|
|
||||||
size_t getNum( size_t width, int perc ) {
|
int getNum( int width, int perc ) {
|
||||||
return ( width * perc ) / 100;
|
return ( width * perc ) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +72,8 @@ void ProgressBar::print( int perc ) {
|
|||||||
auto width = getTermWidth();
|
auto width = getTermWidth();
|
||||||
home( width );
|
home( width );
|
||||||
auto count = getNum( width - 7, perc );
|
auto count = getNum( width - 7, perc );
|
||||||
|
if ( count < 0 )
|
||||||
|
count = 0;
|
||||||
cout << "[" << string( count, TEXT( '=' ) ).c_str();
|
cout << "[" << string( count, TEXT( '=' ) ).c_str();
|
||||||
if ( perc != 100 ) {
|
if ( perc != 100 ) {
|
||||||
int wc = width - 8 - count;
|
int wc = width - 8 - count;
|
||||||
|
712
tests/test.cpp
712
tests/test.cpp
@ -1,8 +1,51 @@
|
|||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include "../filesystem.hpp"
|
||||||
#include "../functions.hpp"
|
#include "../functions.hpp"
|
||||||
|
#include "../resources_linux.h"
|
||||||
|
#include "../tv_rename.hpp"
|
||||||
|
#include "../sqlitepp.hpp"
|
||||||
|
#include <set>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// declaring functions that aren't in functions.hpp
|
||||||
|
|
||||||
|
std::string sanitize( const std::string &str );
|
||||||
|
std::string getDBName();
|
||||||
|
void cleanUpLine();
|
||||||
|
std::vector< std::tuple< int, string, string, string > >
|
||||||
|
|
||||||
|
getRenamedFiles( const string &show, int season, const string &id,
|
||||||
|
const string &language, const string &pattern,
|
||||||
|
const bool &unix_names, const std::map< int, string > &files,
|
||||||
|
bool dvd );
|
||||||
|
std::map< string, string > getLangs();
|
||||||
|
|
||||||
|
// functions required for testing
|
||||||
|
|
||||||
|
bool authenticated = false;
|
||||||
|
|
||||||
|
void testDB() {
|
||||||
|
if ( !FSLib::exists( getDBName() ) ) {
|
||||||
|
prepareDB( "S%2seasonE%2episode - %epname" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool runBash( const std::string &command ) {
|
||||||
|
std::string cmd = "/bin/bash -c \"" + command + "\"";
|
||||||
|
return system( cmd.c_str() ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticateTest() {
|
||||||
|
if ( !authenticated ) {
|
||||||
|
authenticate( "42B66F5E-C6BF-423F-ADF9-CC97163472F6" );
|
||||||
|
authenticated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// functions.hpp
|
||||||
|
|
||||||
TEST_CASE( "encodeUrl" ) {
|
TEST_CASE( "encodeUrl" ) {
|
||||||
std::string url1 = "http://google.com";
|
std::string url1 = "http://google.com";
|
||||||
std::string url1_expected = "http%3A%2F%2Fgoogle.com";
|
std::string url1_expected = "http%3A%2F%2Fgoogle.com";
|
||||||
@ -16,17 +59,676 @@ TEST_CASE( "encodeUrl" ) {
|
|||||||
TEST_CASE( "userHome" ) {
|
TEST_CASE( "userHome" ) {
|
||||||
SECTION( "correct usage" ) {
|
SECTION( "correct usage" ) {
|
||||||
auto home = userHome();
|
auto home = userHome();
|
||||||
std::string command = "/bin/bash -c \"if [ \"${HOME}\" == \"";
|
std::string command = "if [ \"\\${HOME}\" == \"";
|
||||||
command += home;
|
command += home;
|
||||||
command += "\" ] ; then exit 0 ; else exit 1 ; fi\"";
|
command += "\" ] ; then exit 0 ; else exit 1 ; fi";
|
||||||
REQUIRE( system( command.c_str() ) == 0 );
|
REQUIRE( runBash( command ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid_t original_u{ 0 }, original_e{ 0 }, original_s{ 0 };
|
||||||
|
gid_t original_g{ 0 }, original_ge{ 0 }, original_gs{ 0 };
|
||||||
|
|
||||||
|
getresuid( &original_u, &original_e, &original_s );
|
||||||
|
getresgid( &original_g, &original_ge, &original_gs );
|
||||||
|
|
||||||
SECTION( "exception with non existing user" ) {
|
SECTION( "exception with non existing user" ) {
|
||||||
setresgid( 1025, 1025, 1025 );
|
setresuid( 1025, 1025, -1 );
|
||||||
setresuid( 1025, 1025, 1025 );
|
|
||||||
REQUIRE_THROWS_WITH(
|
REQUIRE_THROWS_WITH(
|
||||||
userHome(), Catch::Matchers::Contains( "User with uid" ) &&
|
userHome(), Catch::Matchers::Contains( "User with uid" ) &&
|
||||||
Catch::Matchers::Contains( "doesn't exist!" ) );
|
Catch::Matchers::Contains( "doesn't exist!" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setresuid( original_u, original_e, original_s );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "getlocalized" ) {
|
||||||
|
auto ret = getlocalized( ADDING_TO_DB );
|
||||||
|
REQUIRE( ret == "Adding to database" );
|
||||||
|
ret = getlocalized( UPDATING_IN_DB, "test" );
|
||||||
|
REQUIRE( ret == "Updating test in database" );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "getDBPattern" ) {
|
||||||
|
testDB();
|
||||||
|
REQUIRE( "S%2seasonE%2episode - %epname" == getDBPattern() );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "searchSeason" ) {
|
||||||
|
size_t seasonpos{ 0 }, eppos{ 0 };
|
||||||
|
REQUIRE( searchSeason( "s001e003", seasonpos, eppos ) );
|
||||||
|
REQUIRE( ( seasonpos == 1 && eppos == 5 ) );
|
||||||
|
REQUIRE( searchSeason( "s001e003", seasonpos ) );
|
||||||
|
REQUIRE( seasonpos == 1 );
|
||||||
|
REQUIRE_FALSE( searchSeason( "e01S013", seasonpos, eppos ) );
|
||||||
|
REQUIRE(
|
||||||
|
searchSeason( "TesTSOIHSADF0239s023S23iewahoiehwf001e22E33sS1E1.mkv",
|
||||||
|
seasonpos, eppos ) );
|
||||||
|
REQUIRE( ( seasonpos == 45 && eppos == 47 ) );
|
||||||
|
REQUIRE_FALSE( searchSeason( "s01sE01.mkv", seasonpos ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "iterateFS" ) {
|
||||||
|
runBash(
|
||||||
|
"mkdir test_iteratefs ; cd test_iteratefs ; for f in {01..10} ; do "
|
||||||
|
"mkdir \\\"Season \\${f}\\\" ; cd \\\"Season \\${f}\\\" ; for g in "
|
||||||
|
"{01..30} ; do touch \\\"S\\${f}E\\${g}.mkv\\\" ; done ; cd .. ; "
|
||||||
|
"done" );
|
||||||
|
std::map< int, std::map< int, string > > seasons;
|
||||||
|
iterateFS( seasons, "test_iteratefs" );
|
||||||
|
REQUIRE( seasons.size() == 10 );
|
||||||
|
for ( auto &x : seasons ) {
|
||||||
|
REQUIRE( x.second.size() == 30 );
|
||||||
|
for ( auto &ep : x.second ) {
|
||||||
|
std::string epfile = "S";
|
||||||
|
if ( x.first <= 9 )
|
||||||
|
epfile += "0";
|
||||||
|
epfile += std::to_string( x.first );
|
||||||
|
epfile += "E";
|
||||||
|
if ( ep.first <= 9 )
|
||||||
|
epfile += "0";
|
||||||
|
epfile += std::to_string( ep.first );
|
||||||
|
epfile += ".mkv";
|
||||||
|
REQUIRE_THAT( ep.second, Catch::Contains( epfile ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE_THROWS_WITH( iterateFS( seasons, "nonexistendir" ),
|
||||||
|
Catch::Contains( "Directory" ) &&
|
||||||
|
Catch::Contains( "doesn't exist" ) );
|
||||||
|
REQUIRE_THROWS_WITH(
|
||||||
|
iterateFS( seasons, "test_iteratefs/Season 01/S01E01.mkv" ),
|
||||||
|
Catch::Contains( "Directory" ) &&
|
||||||
|
Catch::Contains( "isn't a directory" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "printing functions" ) {
|
||||||
|
std::string expectedHelp =
|
||||||
|
"Usage:\n tv_rename [options] [path]\n\n -h, --help "
|
||||||
|
"show this help message and exit\n\n path can be either a file or a "
|
||||||
|
"directory, if it's a directory\n all files in it and its "
|
||||||
|
"subdirectories will be renamed\n\nOPTIONS\n -s, --show <string> "
|
||||||
|
"TV show from which you want the episode names\n -n, --season "
|
||||||
|
"<numbers> Season number/s (if multiple seasons,\n "
|
||||||
|
" must be seperated by one space) or 'all'\n "
|
||||||
|
" for all seasons in selected directory\n\n -d, --dvd "
|
||||||
|
" use dvd ordering instead of aired ordering\n --name-pattern "
|
||||||
|
"<string> Pattern to which change the file name.\n --pattern-help "
|
||||||
|
" Print pattern help\n -c, --correct-path This is the "
|
||||||
|
"correct path, stop asking me!\n -t, --trust Don't ask "
|
||||||
|
"whether the names are correct\n -x, --linux Don't "
|
||||||
|
"replace characters characters that are\n "
|
||||||
|
"illegal in Windows\n -l, --lang <string> Select which language "
|
||||||
|
"the episode names shoud be in\n --print-langs Print "
|
||||||
|
"available languages\n\nDATABASE OPTIONS\n --db-add "
|
||||||
|
"Add path to the database\n --db-refresh Refresh "
|
||||||
|
"episode names for all paths in the database\n --db-update "
|
||||||
|
" Check all paths in the database,\n if "
|
||||||
|
"they contain new files, rename them\n --db-name-pattern <string> "
|
||||||
|
"Change name pattern used for files\n "
|
||||||
|
"managed by database\n --db-clean Remove deleted "
|
||||||
|
"files from the database\n --db-remove Remove path "
|
||||||
|
"from the database\n";
|
||||||
|
|
||||||
|
std::string expectedPattern =
|
||||||
|
"Possible pattern sequences are:\n %filename - original filename "
|
||||||
|
"(without filetype extension)\n %show - show name from thetvdb\n "
|
||||||
|
"%epname - episode name from thetvdb\n %season - season number\n "
|
||||||
|
"it's possible to specify leading 0 like this:\n %2season (number "
|
||||||
|
"means how many zeros)\n %episode - episode number\n it's possible "
|
||||||
|
"to specify leading 0 like this:\n %2episode (number means how "
|
||||||
|
"many zeros)\nDefault pattern is \"%filename - %epname\"\n";
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
auto original_cout = std::cout.rdbuf();
|
||||||
|
std::cout.rdbuf( oss.rdbuf() );
|
||||||
|
printHelp();
|
||||||
|
REQUIRE( oss.str() == expectedHelp );
|
||||||
|
|
||||||
|
oss.str( "" );
|
||||||
|
oss.clear();
|
||||||
|
printPatternHelp();
|
||||||
|
REQUIRE( oss.str() == expectedPattern );
|
||||||
|
|
||||||
|
std::cout.rdbuf( original_cout );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "parseSeasonNumber" ) {
|
||||||
|
std::set< int > season_nums{};
|
||||||
|
parseSeasonNumbers( season_nums, "1 2 3 4 5 6" );
|
||||||
|
REQUIRE( season_nums.size() == 6 );
|
||||||
|
for ( int i = 1; i < 7; i++ ) {
|
||||||
|
REQUIRE( season_nums.find( i ) != season_nums.end() );
|
||||||
|
}
|
||||||
|
season_nums.clear();
|
||||||
|
|
||||||
|
parseSeasonNumbers( season_nums, "this is not a number" );
|
||||||
|
REQUIRE( season_nums.size() == 0 );
|
||||||
|
|
||||||
|
parseSeasonNumbers( season_nums,
|
||||||
|
"this is not a number 1 2 3 this is the end 4 5 6" );
|
||||||
|
REQUIRE( season_nums.size() == 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string testCompilePattern( const std::string &pattern ) {
|
||||||
|
return compilePattern( pattern, 45, 914, "episode_of_show_s45e914",
|
||||||
|
"The one where everyone dies", "Enemies" );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "compilePattern" ) {
|
||||||
|
REQUIRE( testCompilePattern( "%filename" ) == "episode_of_show_s45e914" );
|
||||||
|
REQUIRE( testCompilePattern( "%show" ) == "Enemies" );
|
||||||
|
REQUIRE( testCompilePattern( "%epname" ) == "The one where everyone dies" );
|
||||||
|
REQUIRE( testCompilePattern( "%season" ) == "45" );
|
||||||
|
REQUIRE( testCompilePattern( "%episode" ) == "914" );
|
||||||
|
REQUIRE( testCompilePattern( "%1season" ) ==
|
||||||
|
testCompilePattern( "%2season" ) );
|
||||||
|
REQUIRE( testCompilePattern( "%20season" ) == "00000000000000000045" );
|
||||||
|
REQUIRE( testCompilePattern( "%1episode" ) ==
|
||||||
|
testCompilePattern( "%2episode" ) );
|
||||||
|
REQUIRE( testCompilePattern( "%20episode" ) == "00000000000000000914" );
|
||||||
|
REQUIRE( testCompilePattern(
|
||||||
|
"%filename - %show - S%3seasonE%3episode - %epname" ) ==
|
||||||
|
"episode_of_show_s45e914 - Enemies - S045E914 - The one where "
|
||||||
|
"everyone dies" );
|
||||||
|
REQUIRE( testCompilePattern( "\\%filename" ) == "%filename" );
|
||||||
|
REQUIRE( testCompilePattern( "\\\\%filename" ) ==
|
||||||
|
"\\episode_of_show_s45e914" );
|
||||||
|
REQUIRE( testCompilePattern( "\\filename" ) == "\\filename" );
|
||||||
|
REQUIRE( testCompilePattern( "%notakeyword" ) == "%notakeyword" );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "sanitize" ) {
|
||||||
|
REQUIRE( sanitize( "I am a nice input" ) == "I am a nice input" );
|
||||||
|
REQUIRE(
|
||||||
|
sanitize( "I am an evil input!'; DROP TABLE USER_ACCOUNT_BALANCE;" ) ==
|
||||||
|
"I am an evil input!''; DROP TABLE USER_ACCOUNT_BALANCE;" );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "cleanUpLine" ) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
auto original_cout = std::cout.rdbuf();
|
||||||
|
std::cout.rdbuf( oss.rdbuf() );
|
||||||
|
|
||||||
|
cleanUpLine();
|
||||||
|
std::cout << std::flush;
|
||||||
|
|
||||||
|
REQUIRE_THAT( oss.str().substr( 3 ), Catch::Contains( "\x1b[2A" ) );
|
||||||
|
|
||||||
|
std::cout.rdbuf( original_cout );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "addToDB" ) {
|
||||||
|
testDB();
|
||||||
|
authenticateTest();
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\n" );
|
||||||
|
|
||||||
|
runBash( "mkdir add_dir ; touch add_dir/s01e01.mkv" );
|
||||||
|
|
||||||
|
std::string show = "simpsons";
|
||||||
|
addToDB( show, "add_dir", "en", true, false );
|
||||||
|
|
||||||
|
SQLite::Database db{};
|
||||||
|
db.open( getDBName(), SQLite::OPEN_READONLY );
|
||||||
|
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > > result_eps{};
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > >
|
||||||
|
result_shows{};
|
||||||
|
db.exec( "SELECT * FROM EPISODES;", result_eps );
|
||||||
|
db.exec( "SELECT * FROM SHOWS;", result_shows );
|
||||||
|
|
||||||
|
std::string wanted_id{};
|
||||||
|
|
||||||
|
for ( auto &x : result_shows ) {
|
||||||
|
if ( x["SHOW"] == "The Simpsons" ) {
|
||||||
|
wanted_id = x["ID"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foundCorrect = false;
|
||||||
|
for ( auto &x : result_eps ) {
|
||||||
|
if ( x["PATH"].find(
|
||||||
|
"S01E01 - Simpsons Roasting on an Open Fire.mkv" ) !=
|
||||||
|
std::string::npos &&
|
||||||
|
x["SHOWID"] == wanted_id ) {
|
||||||
|
foundCorrect = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE( foundCorrect );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "refreshDB" ) {
|
||||||
|
testDB();
|
||||||
|
authenticateTest();
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\n" );
|
||||||
|
|
||||||
|
runBash( "mkdir refresh_dir ; touch refresh_dir/s01e01.mkv" );
|
||||||
|
|
||||||
|
std::string show = "friends";
|
||||||
|
addToDB( show, "refresh_dir", "en", true, false );
|
||||||
|
runBash( "touch refresh_dir/s01e02.mkv" );
|
||||||
|
refreshDB( true );
|
||||||
|
|
||||||
|
SQLite::Database db{};
|
||||||
|
db.open( getDBName(), SQLite::OPEN_READONLY );
|
||||||
|
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > > result_eps{};
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > >
|
||||||
|
result_shows{};
|
||||||
|
db.exec( "SELECT * FROM EPISODES;", result_eps );
|
||||||
|
db.exec( "SELECT * FROM SHOWS;", result_shows );
|
||||||
|
|
||||||
|
std::string wanted_id{};
|
||||||
|
|
||||||
|
for ( auto &x : result_shows ) {
|
||||||
|
if ( x["SHOW"] == "Friends" ) {
|
||||||
|
wanted_id = x["ID"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foundCorrect = false;
|
||||||
|
for ( auto &x : result_eps ) {
|
||||||
|
if ( x["PATH"].find(
|
||||||
|
"S01E02 - The One With The Sonogram At The End.mkv" ) !=
|
||||||
|
std::string::npos &&
|
||||||
|
x["SHOWID"] == wanted_id ) {
|
||||||
|
foundCorrect = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE( foundCorrect );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "updateDB" ) {
|
||||||
|
testDB();
|
||||||
|
authenticateTest();
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\n" );
|
||||||
|
|
||||||
|
runBash( "mkdir update_dir ; touch update_dir/s01e01.mkv" );
|
||||||
|
|
||||||
|
std::string show = "seinfeld";
|
||||||
|
addToDB( show, "update_dir", "en", true, false );
|
||||||
|
runBash( "touch update_dir/s01e02.mkv" );
|
||||||
|
updateDB( true );
|
||||||
|
|
||||||
|
SQLite::Database db{};
|
||||||
|
db.open( getDBName(), SQLite::OPEN_READONLY );
|
||||||
|
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > > result_eps{};
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > >
|
||||||
|
result_shows{};
|
||||||
|
db.exec( "SELECT * FROM EPISODES;", result_eps );
|
||||||
|
db.exec( "SELECT * FROM SHOWS;", result_shows );
|
||||||
|
|
||||||
|
std::string wanted_id{};
|
||||||
|
|
||||||
|
for ( auto &x : result_shows ) {
|
||||||
|
if ( x["SHOW"] == "Seinfeld" ) {
|
||||||
|
wanted_id = x["ID"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foundCorrect = false;
|
||||||
|
for ( auto &x : result_eps ) {
|
||||||
|
if ( x["PATH"].find( "S01E02 - The Stake Out.mkv" ) !=
|
||||||
|
std::string::npos &&
|
||||||
|
x["SHOWID"] == wanted_id ) {
|
||||||
|
foundCorrect = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE( foundCorrect );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "cleanDB" ) {
|
||||||
|
testDB();
|
||||||
|
authenticateTest();
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\n" );
|
||||||
|
|
||||||
|
runBash( "mkdir clean_dir ; touch clean_dir/s01e01.mkv" );
|
||||||
|
|
||||||
|
std::string show = "scrubs";
|
||||||
|
addToDB( show, "clean_dir", "en", true, false );
|
||||||
|
runBash( "rm clean_dir/S01E01*" );
|
||||||
|
cleanDB();
|
||||||
|
|
||||||
|
SQLite::Database db{};
|
||||||
|
db.open( getDBName(), SQLite::OPEN_READONLY );
|
||||||
|
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > > result_eps{};
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > >
|
||||||
|
result_shows{};
|
||||||
|
db.exec( "SELECT * FROM EPISODES;", result_eps );
|
||||||
|
db.exec( "SELECT * FROM SHOWS;", result_shows );
|
||||||
|
|
||||||
|
std::string wanted_id{};
|
||||||
|
|
||||||
|
for ( auto &x : result_shows ) {
|
||||||
|
if ( x["SHOW"] == "Scrubs" ) {
|
||||||
|
wanted_id = x["ID"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for ( auto &x : result_eps ) {
|
||||||
|
if ( x["PATH"].find( "S01E01 - My First Day.mkv" ) !=
|
||||||
|
std::string::npos &&
|
||||||
|
x["SHOWID"] == wanted_id ) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE_FALSE( found );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "removeFromDB" ) {
|
||||||
|
testDB();
|
||||||
|
authenticateTest();
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\n" );
|
||||||
|
|
||||||
|
runBash( "mkdir remove_dir ; touch remove_dir/s01e01.mkv" );
|
||||||
|
|
||||||
|
std::string show = "how i met";
|
||||||
|
addToDB( show, "remove_dir", "en", true, false );
|
||||||
|
|
||||||
|
SQLite::Database db{};
|
||||||
|
db.open( getDBName(), SQLite::OPEN_READONLY );
|
||||||
|
|
||||||
|
std::vector< std::unordered_map< std::string, std::string > >
|
||||||
|
result_shows{};
|
||||||
|
db.exec( "SELECT * FROM SHOWS;", result_shows );
|
||||||
|
|
||||||
|
std::string wanted_id{ "0" };
|
||||||
|
|
||||||
|
for ( auto &x : result_shows ) {
|
||||||
|
if ( x["SHOW"] == "How I Met Your Mother" ) {
|
||||||
|
wanted_id = x["ID"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE( wanted_id != "0" );
|
||||||
|
removeFromDB( FSLib::canonical( "." ) + "/remove_dir" );
|
||||||
|
wanted_id = "0";
|
||||||
|
result_shows.clear();
|
||||||
|
db.exec( "SELECT * FROM SHOWS;", result_shows );
|
||||||
|
|
||||||
|
for ( auto &x : result_shows ) {
|
||||||
|
if ( x["SHOW"] == "How I Met Your Mother" ) {
|
||||||
|
wanted_id = x["ID"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE( wanted_id == "0" );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "changeDBPattern" ) {
|
||||||
|
testDB();
|
||||||
|
std::string old_pattern = "S%2seasonE%2episode - %epname";
|
||||||
|
std::string new_pattern = "THIS IS NOT A GOOD PATTERN";
|
||||||
|
REQUIRE( getDBPattern() == old_pattern );
|
||||||
|
changeDBPattern( new_pattern );
|
||||||
|
REQUIRE( getDBPattern() == new_pattern );
|
||||||
|
changeDBPattern( old_pattern );
|
||||||
|
REQUIRE( getDBPattern() == old_pattern );
|
||||||
|
}
|
||||||
|
|
||||||
|
// filesystem.hpp
|
||||||
|
|
||||||
|
TEST_CASE( "Directory" ) {
|
||||||
|
std::string command =
|
||||||
|
"mkdir test_dir ; cd test_dir ; for f in {01..10} ; do "
|
||||||
|
"touch \\${f} ; done";
|
||||||
|
runBash( command );
|
||||||
|
FSLib::Directory d( "test_dir" );
|
||||||
|
std::set< std::string > files = { "01", "02", "03", "04", "05",
|
||||||
|
"06", "07", "08", "09", "10" };
|
||||||
|
int counter = 0;
|
||||||
|
for ( auto x : d ) {
|
||||||
|
counter++;
|
||||||
|
REQUIRE( files.find( x ) != files.end() );
|
||||||
|
}
|
||||||
|
REQUIRE( counter == 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Filesystem" ) {
|
||||||
|
std::string command =
|
||||||
|
"mkdir test_dir2 ; cd test_dir2 ; for f in {01..10} ; do "
|
||||||
|
"touch \\${f} ; done";
|
||||||
|
runBash( command );
|
||||||
|
std::set< std::string > files = { "01", "02", "03", "04", "05",
|
||||||
|
"06", "07", "08", "09", "10" };
|
||||||
|
|
||||||
|
// exists
|
||||||
|
REQUIRE( FSLib::exists( "test_dir2" ) );
|
||||||
|
for ( auto &x : files ) {
|
||||||
|
REQUIRE( FSLib::exists( "test_dir2/" + x ) );
|
||||||
|
REQUIRE_FALSE( FSLib::exists( x ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDirectory
|
||||||
|
REQUIRE( FSLib::isDirectory( "test_dir2" ) );
|
||||||
|
REQUIRE( FSLib::isDirectory( "." ) );
|
||||||
|
REQUIRE_FALSE( FSLib::isDirectory( "test_dir2/01" ) );
|
||||||
|
REQUIRE_FALSE( FSLib::isDirectory( "nonexistentfile" ) );
|
||||||
|
|
||||||
|
// canonical
|
||||||
|
auto pwd = FSLib::canonical( "." );
|
||||||
|
command = "if [ \"\\${PWD}\" == \"";
|
||||||
|
command += pwd;
|
||||||
|
command += "\" ] ; then exit 0 ; else exit 1 ; fi";
|
||||||
|
REQUIRE( runBash( command ) );
|
||||||
|
REQUIRE( FSLib::canonical( "nonexistentfile" ) == "" );
|
||||||
|
|
||||||
|
// rename
|
||||||
|
for ( auto &x : files ) {
|
||||||
|
REQUIRE( FSLib::rename( "test_dir2/" + x, "test_dir2/renamed_" + x ) );
|
||||||
|
REQUIRE_FALSE(
|
||||||
|
FSLib::rename( "test_dir2/" + x, "test_dir2/renamed_" + x ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_dir2/renamed_" + x ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tv_rename.cpp
|
||||||
|
|
||||||
|
TEST_CASE( "getRenamedFiles Windows chars" ) {
|
||||||
|
std::map< int, std::string > files{};
|
||||||
|
files[1] = "I am a windows illegal file \\|<>:?\"*";
|
||||||
|
auto res = getRenamedFiles( "simpsons", 1, "71663", "en", "%filename",
|
||||||
|
false, files, false );
|
||||||
|
REQUIRE( std::get< 0 >( res[0] ) == 1 );
|
||||||
|
REQUIRE( std::get< 1 >( res[0] ) == "." );
|
||||||
|
REQUIRE( std::get< 2 >( res[0] ) ==
|
||||||
|
"I am a windows illegal file \\|<>:?\"*" );
|
||||||
|
REQUIRE( std::get< 3 >( res[0] ) ==
|
||||||
|
"I am a windows illegal file -<> - " );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "getLangs" ) {
|
||||||
|
authenticateTest();
|
||||||
|
auto langs = getLangs();
|
||||||
|
REQUIRE_FALSE( langs.empty() );
|
||||||
|
bool containsEn = false;
|
||||||
|
bool containsCs = false;
|
||||||
|
for ( auto &x : langs ) {
|
||||||
|
if ( x.first == "en" )
|
||||||
|
containsEn = true;
|
||||||
|
if ( x.first == "cs" )
|
||||||
|
containsCs = true;
|
||||||
|
}
|
||||||
|
REQUIRE( containsEn );
|
||||||
|
REQUIRE( containsCs );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "singleSeason" ) {
|
||||||
|
runBash(
|
||||||
|
"mkdir test_singleseason ; cd test_singleseason ; for f in {01..10} ;"
|
||||||
|
"do mkdir \\\"Season \\${f}\\\" ; cd \\\"Season \\${f}\\\" ; for g in "
|
||||||
|
"{01..30} ; do touch \\\"S\\${f}E\\${g}.mkv\\\" ; done ; cd .. ; "
|
||||||
|
"done" );
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "y\n" );
|
||||||
|
|
||||||
|
singleSeason( "test_singleseason", "simpsons", 1, "71663", "en",
|
||||||
|
"S%2seasonE%2episode - %epname", false, false, nullptr, false,
|
||||||
|
false );
|
||||||
|
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 01/S01E01 - Simpsons "
|
||||||
|
"Roasting on an Open Fire.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E02 - Bart the Genius.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E03 - Homer's Odyssey.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 01/S01E04 - There's No "
|
||||||
|
"Disgrace Like Home.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E05 - Bart the General.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E06 - Moaning Lisa.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E07 - The Call of the Simpsons.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E08 - The Telltale Head.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E09 - Life on the Fast Lane.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E10 - Homer's Night Out.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E11 - The Crepes of Wrath.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E12 - Krusty Gets Busted.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_singleseason/Season 01/S01E13 - Some Enchanted Evening.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 02/S02E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 03/S03E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 04/S04E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 05/S05E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 06/S06E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 07/S07E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 08/S08E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 09/S09E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_singleseason/Season 10/S10E01.mkv" ) );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "multipleSeasons" ) {
|
||||||
|
runBash( "mkdir test_multipleseasons ; cd test_multipleseasons ;"
|
||||||
|
"for f in {01..10} ; do mkdir \\\"Season \\${f}\\\" ; cd "
|
||||||
|
"\\\"Season \\${f}\\\" ; for g in "
|
||||||
|
"{01..30} ; do touch \\\"S\\${f}E\\${g}.mkv\\\" ; done ; cd .. ; "
|
||||||
|
"done" );
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\ny\ny\ny\n" );
|
||||||
|
|
||||||
|
multipleSeasons( "test_multipleseasons", "simpsons", { 1, 2, 3 }, "en",
|
||||||
|
"S%2seasonE%2episode - %epname", 0 );
|
||||||
|
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 01/S01E01 - Simpsons "
|
||||||
|
"Roasting on an Open Fire.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_multipleseasons/Season 02/S02E01 - Bart Gets an F.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_multipleseasons/Season 03/S03E01 - Stark Raving Dad.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 04/S04E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 05/S05E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 06/S06E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 07/S07E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 08/S08E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 09/S09E01.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_multipleseasons/Season 10/S10E01.mkv" ) );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "allSeasons" ) {
|
||||||
|
runBash( "mkdir test_allseasons ; cd test_allseasons ;"
|
||||||
|
"for f in {01..10} ; do mkdir \\\"Season \\${f}\\\" ; cd "
|
||||||
|
"\\\"Season \\${f}\\\" ; for g in "
|
||||||
|
"{01..30} ; do touch \\\"S\\${f}E\\${g}.mkv\\\" ; done ; cd .. ; "
|
||||||
|
"done" );
|
||||||
|
std::istringstream iss;
|
||||||
|
auto original_cin = std::cin.rdbuf();
|
||||||
|
std::cin.rdbuf( iss.rdbuf() );
|
||||||
|
std::cout.setstate( std::ios_base::failbit );
|
||||||
|
iss.str( "1\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n" );
|
||||||
|
|
||||||
|
allSeasons( "test_allseasons", "simpsons", "en",
|
||||||
|
"S%2seasonE%2episode - %epname", 0 );
|
||||||
|
|
||||||
|
REQUIRE( FSLib::exists( "test_allseasons/Season 01/S01E01 - Simpsons "
|
||||||
|
"Roasting on an Open Fire.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 02/S02E01 - Bart Gets an F.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 03/S03E01 - Stark Raving Dad.mkv" ) );
|
||||||
|
REQUIRE(
|
||||||
|
FSLib::exists( "test_allseasons/Season 04/S04E01 - Kamp Krusty.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 05/S05E01 - Homer's Barbershop Quartet.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 06/S06E01 - Bart of Darkness.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 07/S07E01 - Who Shot Mr. Burns (2).mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 08/S08E01 - Treehouse of Horror VII.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists( "test_allseasons/Season 09/S09E01 - The City of "
|
||||||
|
"New York vs. Homer Simpson.mkv" ) );
|
||||||
|
REQUIRE( FSLib::exists(
|
||||||
|
"test_allseasons/Season 10/S10E01 - Lard of the Dance.mkv" ) );
|
||||||
|
|
||||||
|
std::cin.rdbuf( original_cin );
|
||||||
|
std::cout.clear();
|
||||||
}
|
}
|
||||||
|
@ -215,11 +215,21 @@ getRenamedFiles( const string &show, int season, const string &id,
|
|||||||
|
|
||||||
if ( ep_num < episodes.size() ) {
|
if ( ep_num < episodes.size() ) {
|
||||||
auto pos = og_name.find_last_of( TEXT( "." ) );
|
auto pos = og_name.find_last_of( TEXT( "." ) );
|
||||||
|
string og_name_without_extension{};
|
||||||
|
string og_name_extension{};
|
||||||
|
|
||||||
|
if ( pos == string::npos ) {
|
||||||
|
og_name_without_extension = og_name;
|
||||||
|
} else {
|
||||||
|
og_name_without_extension = og_name.substr( 0, pos );
|
||||||
|
og_name_extension = og_name.substr( pos );
|
||||||
|
}
|
||||||
|
|
||||||
// get desired filename
|
// get desired filename
|
||||||
auto name = compilePattern( pattern, season, x.first,
|
auto name = compilePattern( pattern, season, x.first,
|
||||||
og_name.substr( 0, pos ),
|
og_name_without_extension,
|
||||||
episodes[ep_num], show ) +
|
episodes[ep_num], show ) +
|
||||||
og_name.substr( pos );
|
og_name_extension;
|
||||||
// replace '/' with '|'
|
// replace '/' with '|'
|
||||||
for ( size_t i = 0; i < name.size(); i++ ) {
|
for ( size_t i = 0; i < name.size(); i++ ) {
|
||||||
if ( name[i] == '/' ) {
|
if ( name[i] == '/' ) {
|
||||||
@ -346,7 +356,7 @@ void singleSeason( const string &path, const string &show, int season,
|
|||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if ( print || !trust ) {
|
if ( print || !trust ) {
|
||||||
for ( const auto renamed : renamed_files ) {
|
for ( const auto &renamed : renamed_files ) {
|
||||||
cout << std::get< 2 >( renamed ) << " --> "
|
cout << std::get< 2 >( renamed ) << " --> "
|
||||||
<< std::get< 3 >( renamed ) << std::endl;
|
<< std::get< 3 >( renamed ) << std::endl;
|
||||||
}
|
}
|
||||||
@ -363,7 +373,7 @@ void singleSeason( const string &path, const string &show, int season,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( const auto renamed : renamed_files ) {
|
for ( const auto &renamed : renamed_files ) {
|
||||||
FSLib::rename( std::get< 1 >( renamed ) + _tv_rename_dir_divider +
|
FSLib::rename( std::get< 1 >( renamed ) + _tv_rename_dir_divider +
|
||||||
std::get< 2 >( renamed ),
|
std::get< 2 >( renamed ),
|
||||||
std::get< 1 >( renamed ) + _tv_rename_dir_divider +
|
std::get< 1 >( renamed ) + _tv_rename_dir_divider +
|
||||||
@ -391,7 +401,7 @@ void singleSeason( const string &path, const string &show, int season,
|
|||||||
|
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
|
|
||||||
void multipleSeasons( const string &path, string &show,
|
void multipleSeasons( const string &path, const string &show,
|
||||||
const std::set< int > &seasons, const string &language,
|
const std::set< int > &seasons, const string &language,
|
||||||
const string &pattern, const size_t &flags ) {
|
const string &pattern, const size_t &flags ) {
|
||||||
std::map< int, std::map< int, string > > season_map;
|
std::map< int, std::map< int, string > > season_map;
|
||||||
@ -406,7 +416,7 @@ void multipleSeasons( const string &path, string &show,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void allSeasons( const string &path, string &show, const string &language,
|
void allSeasons( const string &path, const string &show, const string &language,
|
||||||
const string &pattern, const size_t &flags ) {
|
const string &pattern, const size_t &flags ) {
|
||||||
std::map< int, std::map< int, string > > seasons;
|
std::map< int, std::map< int, string > > seasons;
|
||||||
// get all season number from this directory and subdirectories
|
// get all season number from this directory and subdirectories
|
||||||
|
@ -54,11 +54,11 @@ std::vector< std::pair< string, string > > getLangs();
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void multipleSeasons( const string &path, string &show,
|
void multipleSeasons( const string &path, const string &show,
|
||||||
const std::set< int > &seasons, const string &language,
|
const std::set< int > &seasons, const string &language,
|
||||||
const string &pattern, const size_t &flags );
|
const string &pattern, const size_t &flags );
|
||||||
|
|
||||||
void allSeasons( const string &path, string &show, const string &language,
|
void allSeasons( const string &path, const string &show, const string &language,
|
||||||
const string &pattern, const size_t &flags );
|
const string &pattern, const size_t &flags );
|
||||||
|
|
||||||
string getShowId( const string &show, const string &language );
|
string getShowId( const string &show, const string &language );
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
#include "../filesystem.hpp"
|
#include "../filesystem.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) {}
|
FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) {}
|
||||||
|
|
||||||
FSLib::Directory::Iterator::Iterator( const Directory &d_ )
|
FSLib::Directory::Iterator::Iterator( const Directory &d_ )
|
||||||
: d( opendir( d_.path() ) ) {
|
: d( opendir( d_.path() ) ) {
|
||||||
|
if ( !exists( d_.path() ) || !isDirectory( d_.path() ) ) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string( "Directory " ) + d_.path() +
|
||||||
|
" either doesn't exist or isn't a directory" );
|
||||||
|
}
|
||||||
|
|
||||||
current_entry = readdir( d );
|
current_entry = readdir( d );
|
||||||
|
|
||||||
// skip "." and ".."
|
// skip "." and ".."
|
||||||
@ -56,6 +63,27 @@ bool FSLib::rename( const string &file_a, const string &file_b ) {
|
|||||||
return ::rename( file_a.c_str(), file_b.c_str() ) == 0;
|
return ::rename( file_a.c_str(), file_b.c_str() ) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FSLib::createDirectoryFull( const string &path ) {
|
||||||
|
uint64_t pos{};
|
||||||
|
// go through all directories leading to the last one
|
||||||
|
// and create them if they don't exist
|
||||||
|
do {
|
||||||
|
// get partial directory path
|
||||||
|
pos = path.find_first_of( "/", pos );
|
||||||
|
if ( pos > 0 ) {
|
||||||
|
auto dirname = path.substr( 0, pos );
|
||||||
|
// create it if it doesn't exist
|
||||||
|
if ( !FSLib::exists( dirname ) ) {
|
||||||
|
if ( mkdir( dirname.c_str(),
|
||||||
|
S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) != 0 )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
} while ( pos < path.length() && pos != 0 );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FSLib::Directory::iterator FSLib::Directory::end() {
|
FSLib::Directory::iterator FSLib::Directory::end() {
|
||||||
return Iterator( *this, nullptr );
|
return Iterator( *this, nullptr );
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "../filesystem.hpp"
|
#include "../filesystem.hpp"
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) {
|
FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) {
|
||||||
@ -9,6 +10,10 @@ FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FSLib::Directory::Iterator::Iterator( const Directory &d_ ) {
|
FSLib::Directory::Iterator::Iterator( const Directory &d_ ) {
|
||||||
|
if ( !exists( d_.path() ) || !isDirectory( d_.path() ) ) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Directory either doesn't exist or isn't a directory" );
|
||||||
|
}
|
||||||
hFind = FindFirstFileW( d_.path(), &data );
|
hFind = FindFirstFileW( d_.path(), &data );
|
||||||
if ( hFind != INVALID_HANDLE_VALUE ) {
|
if ( hFind != INVALID_HANDLE_VALUE ) {
|
||||||
if ( !wcscmp( data.cFileName, L"." ) ||
|
if ( !wcscmp( data.cFileName, L"." ) ||
|
||||||
@ -75,6 +80,26 @@ bool FSLib::rename( const string &file_a, const string &file_b ) {
|
|||||||
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING );
|
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FSLib::createDirectoryFull( const string &path ) {
|
||||||
|
uint64_t pos = path.find_first_of( L":", 0 ) + 2;
|
||||||
|
if ( pos == string::npos )
|
||||||
|
pos = 0;
|
||||||
|
// go through all directories leading to the last one
|
||||||
|
// and create them if they don't exist
|
||||||
|
do {
|
||||||
|
// get partial directory path
|
||||||
|
pos = path.find_first_of( L"\\", pos );
|
||||||
|
auto dirname = path.substr( 0, pos );
|
||||||
|
// create it if it doesn't exist
|
||||||
|
if ( !FSLib::exists( dirname ) ) {
|
||||||
|
if ( !CreateDirectoryW( dirname.c_str(), NULL ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
} while ( pos < path.length() && pos != 0 );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FSLib::Directory::iterator FSLib::Directory::end() {
|
FSLib::Directory::iterator FSLib::Directory::end() {
|
||||||
return Iterator( true );
|
return Iterator( true );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user