# include <commands.hxx>
# include <webpage.hxx>
# include <QApplication>
# include <QFile>
# include <QWebView>
# include <QStringList>
# include <QCommandLineParser>
# include <iostream>
# include <sstream>
# include <fstream>
# include <QDateTime>
# include <xml-cxx/xml.hxx>
# include <mrw/string.hxx>
# include <version.hxx>
using namespace NAMESPACE ;
QString format ( QString txt , int indent = 2 , int cpl = 60 ) {
QStringList res ;
QStringList lines ( txt . split ( ' \n ' ) ) ;
QString ind ( indent , ' ' ) ;
Q_FOREACH ( QString line , lines ) {
line . insert ( 0 , ind ) ;
for ( int pos ( 0 ) ; line . size ( ) - pos > cpl ; + + pos ) {
pos = line . lastIndexOf ( ' ' , pos + cpl ) ;
line . remove ( pos , 1 ) ;
line . insert ( pos , " \n " + ind ) ;
}
res + = line ;
}
return res . join ( ' \n ' ) ;
}
QString format ( std : : string txt , int indent = 2 , int cpl = 60 ) {
return format ( QString : : fromStdString ( txt ) , indent , cpl ) ;
}
QString help ( const Script & s ) {
std : : ostringstream ss ;
ss < < " Synopsis " < < std : : endl
< < std : : endl
< < " webrunner [<OPTIONS>] [<file1> [<file2> [...]]] " < < std : : endl
< < std : : endl
< < " DESCRIPTION " < < std : : endl
< < std : : endl
< < format ( description ( ) ) . toStdString ( ) < < std : : endl
< < std : : endl
< < format ( readme ( ) ) . toStdString ( ) < < std : : endl
< < std : : endl
< < " SCRIPT SYNTAX " < < std : : endl
< < std : : endl
< < format ( s . syntax ( ) ) . toStdString ( ) < < std : : endl
< < std : : endl
< < " SCRIPT COMMANDS " < < std : : endl
< < std : : endl
< < format ( s . commands ( ) ) . toStdString ( ) < < std : : endl ;
return QString : : fromStdString ( ss . str ( ) ) ;
}
int main ( int argc , char * argv [ ] ) try {
bool failed ( false ) ;
QApplication a ( argc , argv ) ;
QWebView p ;
p . setPage ( new TestWebPage ( & p , true ) ) ;
QCommandLineParser parser ;
Script script ;
parser . setApplicationDescription ( help ( script ) ) ;
parser . addHelpOption ( ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " x " < < " xml " ,
" store XML output in <xmlfile> " , " xmlfile " ) ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " r " < < " retries " ,
" on error retry up to <maxretries> times " ,
" maxretries " , " 0 " ) ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " W " < < " width " ,
" set screenshot size to <width> pixel " , " width " , " 2048 " ) ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " H " < < " height " ,
" set screenshot size to <height> pixel " , " height " , " 2048 " ) ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " v " < < " version " ,
" show version information " ) ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " s " < < " skipped " ,
" treat skipped test cases as failure in XML output file " ) ) ;
parser . addOption ( QCommandLineOption
( QStringList ( ) < < " t " < < " target-path " ,
" set screenshot target path to <path> " , " path " ,
QDir ( ) . absolutePath ( ) + QDir : : separator ( ) + " attachments " ) ) ;
parser . process ( a ) ;
if ( parser . isSet ( " version " ) ) {
std : : cout < < * argv < < std : : endl
< < " from package " < < package_string ( ) < < std : : endl
< < " by " < < author ( ) < < std : : endl
< < " built on " < < build_date ( ) < < std : : endl ;
return 0 ;
}
int retries ( parser . value ( " retries " ) . toInt ( ) ) ;
int width ( parser . value ( " width " ) . toInt ( ) ) ;
int height ( parser . value ( " height " ) . toInt ( ) ) ;
QString target ( parser . value ( " target-path " ) ) ;
p . resize ( width , height ) ;
xml : : Node testsuites ( " testsuites " ) ;
Q_FOREACH ( QString file , parser . positionalArguments ( ) ) {
int expectedtestcases ( - 1 ) ;
xml : : Node testsuite ( " testsuite " ) ;
testsuite . attr ( " name " ) = QFileInfo ( file ) . baseName ( ) . toStdString ( ) ;
testsuite . attr ( " timestamp " ) =
QDateTime : : currentDateTime ( ) . toString ( Qt : : ISODate ) . toStdString ( ) ;
xml : : Node testcase ( " testcase " ) ;
testcase . attr ( " classname " ) = " testsuite-preparation " ;
try {
script . reset ( ) ;
script . log ( " ===================== " ) ;
script . log ( " TEST: " + file ) ;
script . log ( " --------------------- " ) ;
testcase . attr ( " name " ) = " open test suite file " ;
testsuite < < testcase ;
QFile f ( file ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) )
throw std : : runtime_error ( " cannot open file " + file . toStdString ( ) ) ;
QString txt ( QString : : fromUtf8 ( f . readAll ( ) ) ) ;
testcase . attr ( " name " ) = " parse test suite file " ;
testsuite < < testcase ;
script . parse ( txt . split ( ' \n ' ) ) ;
expectedtestcases = script . steps ( ) + 2 ;
if ( failed ) {
script . log ( " FAILED: " + file + " skipped due to previous error " ) ;
testcase . attr ( " name " ) = " testsuite " ;
xml : : Node failure ( " failure " ) ;
failure . attr ( " message " ) = " ignored due to previous failure " ;
testsuite < < ( testcase < < failure ) ;
testsuite . attr ( " failures " ) =
mrw : : string ( expectedtestcases + 1 - testsuite . children ( ) ) ;
if ( parser . isSet ( " skipped " ) ) {
testcase . attr ( " name " ) = " skipped test case " ;
failure . attr ( " message " ) = " skipped due to previous failure " ;
testcase < < failure ;
for ( int i ( testsuite . children ( ) ) ; i < expectedtestcases ; + + i )
testsuite < < testcase ;
}
} else {
script . run ( p . page ( ) - > mainFrame ( ) , testsuite ,
target + QDir : : separator ( ) + QFileInfo ( file ) . baseName ( ) ,
true , retries ) ;
testsuite . attr ( " failures " ) = " 0 " ;
script . log ( " SUCCESS: " + file ) ;
}
} catch ( std : : exception & e ) {
script . log ( " FAILED: " + file + " with " + e . what ( ) ) ;
xml : : Node failure ( " failure " ) ;
failure . attr ( " message " ) = Script : : xmlattr ( e . what ( ) ) . toStdString ( ) ;
testsuite [ testsuite . children ( ) - 1 ] < < failure ;
if ( expectedtestcases = = - 1 )
testsuite . attr ( " failures " ) = " 1 " ;
else
testsuite . attr ( " failures " ) =
mrw : : string ( expectedtestcases + 1 - testsuite . children ( ) ) ;
if ( parser . isSet ( " skipped " ) ) {
testcase . attr ( " name " ) = " skipped test case " ;
failure . attr ( " message " ) = " skipped due to previous failure " ;
testcase < < failure ;
for ( int i ( testsuite . children ( ) ) ; i < expectedtestcases ; + + i )
testsuite < < testcase ;
failed = true ;
}
}
if ( expectedtestcases = = - 1 ) {
testsuite . attr ( " tests " ) = mrw : : string ( testsuite . children ( ) ) ;
} else {
testsuite . attr ( " tests " ) = mrw : : string ( expectedtestcases ) ;
}
if ( script . cout ( ) . size ( ) )
testsuite < < ( xml : : String ( " system-out " ) =
script . xmlattr ( script . cout ( ) ) . toStdString ( ) ) ;
if ( script . cerr ( ) . size ( ) )
testsuite < < ( xml : : String ( " system-err " ) =
script . xmlattr ( script . cerr ( ) ) . toStdString ( ) ) ;
testsuites < < testsuite ;
}
if ( parser . isSet ( " xml " ) ) { // todo: write xml file
std : : ofstream xmlfile ( parser . value ( " xml " ) . toStdString ( ) ) ;
xmlfile < < testsuites < < std : : endl ;
}
return failed ? 1 : 0 ;
} catch ( std : : exception & e ) {
return 1 ;
}