Skip to content

Commit 8aadd17

Browse files
committed
Merge branch 'add-unittest--swapscreens'
2 parents f6e5fa7 + cd65b92 commit 8aadd17

15 files changed

+195
-24
lines changed

.appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ before_build:
2626
-DDownloadTestPDF=ON
2727
-DBoostStaticLink=ON
2828
-DWindowsStaticLink=OFF
29+
-DRunDualScreenTests=OFF
2930
-DBOOST_ROOT=\libraries\boost
3031
-DBOOST_LIBRARYDIR=\libraries\boost\lib32-msvc-12.0
3132

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ qt4_deps: &q4dep
1212
- texlive-latex-recommended
1313
- texlive-pictures
1414
- latex-beamer
15+
- xserver-xorg-video-dummy
1516
qt5_deps: &q5dep
1617
- libboost-program-options-dev
1718
- libboost-test-dev
@@ -25,6 +26,7 @@ qt5_deps: &q5dep
2526
- texlive-latex-recommended
2627
- texlive-pictures
2728
- latex-beamer
29+
- xserver-xorg-video-dummy
2830
addons:
2931
apt:
3032
packages: *q4dep

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
3535
option(UseQtFive "Build with Qt5 and libpoppler-qt5" ON)
3636
option(UpdateTranslations "Do you want to update the .ts files (WARNING: running make clean will delete them!)" OFF)
3737
option(BuildTests "Build unit tests (this requires pdflatex or internet access and DownloadTestPDFs=ON)" ON)
38+
option(RunDualScreenTests "Also run tests that require two screens to be connected" ON)
3839
option(BoostStaticLink "Link statically against the boost libraries" OFF)
3940
option(WindowsStaticLink "Windows/MSVC only: Link statically against the dependencies and set /MT instead of /MD" ON)
4041
option(DownloadTestPDF "Download test PDFs from http://danny-edel.de, rather then building them using latex-beamer" OFF)

_travis/configure

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,17 @@ cd build
99

1010
CMAKE_PARAMETERS="-DCMAKE_VERBOSE_MAKEFILE=ON"
1111

12-
# on OSX: Download Test PDF,
13-
# rather than install pdflatex
12+
CMAKE_PARAMETERS+=" -DCMAKE_BUILD_TYPE=Debug"
13+
14+
# OSX specific stuff
1415
if [ "$TRAVIS_OS_NAME" = "osx" ] ; then
16+
# Download Test PDF,
17+
# rather than install pdflatex
1518
CMAKE_PARAMETERS+=" -DDownloadTestPDF=ON"
19+
20+
# Skip dual screen tests since we don't have
21+
# xvfb-run
22+
CMAKE_PARAMETERS+=" -DRunDualScreenTests=OFF"
1623
fi
1724

1825
# Activate code coverage analysis

_travis/test

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
set -ex
33
cd build
44

5-
XVFB=
65
# Call CTest test runner within XvFB
76
if [ "$TRAVIS_OS_NAME" = "linux" ] ; then
8-
XVFB="xvfb-run -a"
7+
xvfb-run -a -s '-screen 0 1920x1080x24 -screen 1 1920x1200x24' \
8+
ctest --output-on-failure --timeout 60
9+
else
10+
ctest --output-on-failure --timeout 60
911
fi
10-
$XVFB ctest --output-on-failure --timeout 60
1112

1213
# print coverage report, ignore errors
1314
ctest -T coverage || true

dspdfviewer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,11 @@ void DSPDFViewer::toggleSecondaryScreenDuplication()
376376
}
377377
emit renderPage();
378378
}
379+
380+
const QRect DSPDFViewer::audienceGeometry() const {
381+
return audienceWindow.geometry();
382+
}
383+
384+
const QRect DSPDFViewer::secondGeometry() const {
385+
return secondaryWindow.geometry();
386+
}

dspdfviewer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ private slots:
9393

9494
bool isAudienceScreenBlank() const;
9595

96+
/** Allow const access to the windows' positions.
97+
* Needed for tests to inspect things. */
98+
const QRect audienceGeometry() const;
99+
const QRect secondGeometry() const;
100+
96101
signals:
97102
void wallClockUpdate(const QTime& wallClock) const;
98103
void slideClockUpdate(const QTime& slideClock) const;

renderthread.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,11 @@ RenderThread::RenderThread(const PDFDocumentReference& theDocument, const Render
3333

3434
void RenderThread::run()
3535
{
36-
DEBUGOUT << "RenderThread for " << renderMe.pageNumber() << renderMe.requestedPageSize() << " started";
36+
DEBUGOUT << "RenderThread for" << renderMe << "started";
3737
QImage renderImage = RenderUtils::renderPagePart(m_page.page, renderMe.requestedPageSize(), renderMe.pagePart());
3838
if ( renderImage.isNull() )
3939
{
40-
WARNINGOUT << "RenderThread for " << renderMe.pageNumber() <<
41-
renderMe.requestedPageSize().width() << renderMe.requestedPageSize().height() << " failed";
40+
WARNINGOUT << "RenderThread for" << renderMe << "failed";
4241
QSharedPointer<RenderingIdentifier> ri( new RenderingIdentifier(renderMe) );
4342
emit renderingFailed(ri);
4443
return;
@@ -57,6 +56,6 @@ void RenderThread::run()
5756
}
5857
}
5958
QSharedPointer<RenderedPage> renderResult(new RenderedPage( renderImage, links, renderMe ));
60-
DEBUGOUT << "RenderThread for " << renderMe.pageNumber() << renderMe.requestedPageSize() << " successful, image has size " << renderResult->getImage().size();
59+
DEBUGOUT << "RenderThread for" << renderMe << "successful, image has size" << renderResult->getImage().size();
6160
emit renderingFinished(renderResult);
6261
}

sconnect.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
* Quick and dirty hack to check QObject::connect()'s return value
66
*/
77
template<typename Sender, typename Signal, typename Receiver, typename Slot>
8-
void sconnect(Sender sender, Signal signal, Receiver receiver, Slot slot) {
8+
void sconnect(Sender sender, Signal signal, Receiver receiver, Slot slot, Qt::ConnectionType type=Qt::AutoConnection) {
99
bool okay = QObject::connect(
10-
sender, signal, receiver, slot);
10+
sender, signal, receiver, slot, type);
1111
if ( ! okay ) {
1212
throw std::runtime_error(
1313
std::string("QObject::connect failed. sender: ")+signal+" receiver: "+slot);

testing/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,31 @@ set_tests_properties(
118118
PASS_REGULAR_EXPRESSION ${DSPDFVIEWER_VERSION}
119119
)
120120

121+
# Only build and run the swap screen test on Qt5
122+
if(UseQtFive)
123+
add_executable(testswapscreen
124+
testswapscreen.cc
125+
testswapscreen-main.cc
126+
)
127+
target_link_libraries(testswapscreen
128+
testhelp
129+
)
130+
131+
if(RunDualScreenTests)
132+
add_test(NAME testswapscreen
133+
COMMAND testswapscreen
134+
--prerender-prev=0
135+
--prerender-next=0
136+
images.pdf
137+
)
138+
set_tests_properties(testswapscreen
139+
PROPERTIES
140+
TIMEOUT 60
141+
SKIP_RETURN_CODE 77
142+
)
143+
endif()
144+
endif()
145+
121146

122147
# On windows you cannot change the locale on a case-by-case basis.
123148
#

testing/testhelpers.hh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ namespace TestHelpers {
5151
QColor grabPixelColor( uint x, uint y);
5252
};
5353

54+
template<typename T1, typename T2>
55+
inline
56+
void check(const T1& lhs, const T2& rhs, int failcode=2) {
57+
if ( ! (lhs == rhs) ) {
58+
WARNINGOUT << "Failure:" << lhs << "!=" << rhs;
59+
QApplication::exit(failcode);
60+
} else {
61+
DEBUGOUT << "All right." << lhs << "==" << rhs;
62+
}
63+
}
5464
}
5565

5666
/** Print a QSize to a standard output stream */

testing/testswapscreen-main.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "testswapscreen.h"
2+
#include "testhelpers.hh"
3+
4+
int main(int argc, char** argv) {
5+
6+
QApplication qapp(argc,argv);
7+
8+
qRegisterMetaType< QSharedPointer<RenderedPage> >("QSharedPointer<RenderedPage>");
9+
10+
RuntimeConfiguration rc{argc, argv};
11+
12+
DSPDFViewer dsp{rc};
13+
SwapScreensAndCheckAlign testdriver{dsp};
14+
15+
sconnect(&testdriver, SIGNAL(screenSwapRequested()), &dsp, SLOT(swapScreens()));
16+
sconnect(&testdriver, SIGNAL(quitRequested()), &dsp, SLOT(exit()));
17+
18+
return qapp.exec();
19+
}

testing/testswapscreen.cc

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,75 @@
1+
#include "testswapscreen.h"
12
#include "testhelpers.hh"
23

3-
int main() {
4-
// Spawn Xvfb
5-
// Launch dspdfviewer on the rectangles PDF file
6-
// Check left and right screen center colors
7-
// Send S Keystroke
8-
// Check colors again, make sure they are swapped
4+
#include <QDesktopWidget>
5+
#include <QRect>
96

10-
throw std::runtime_error("Not supported yet.");
7+
using namespace std;
8+
using namespace TestHelpers;
9+
10+
SwapScreensAndCheckAlign::SwapScreensAndCheckAlign(DSPDFViewer& d):
11+
dspdfviewer(d),
12+
screenPrimary( QApplication::desktop()->screenGeometry( 0 ) ),
13+
screenSecondary( QApplication::desktop()->screenGeometry( 1 ) ),
14+
verify(true)
15+
{
16+
DEBUGOUT << "Number of screens:" << QApplication::desktop()->numScreens() ;
17+
18+
DEBUGOUT << "screen 0 [pri]:" << screenPrimary;
19+
DEBUGOUT << "screen 1 [sec]:" << screenSecondary;
20+
21+
22+
if ( QApplication::desktop()->numScreens() != 2 ) {
23+
WARNINGOUT << "Not running in a dual-screen environment";
24+
verify = false;
25+
} else if ( screenPrimary == screenSecondary ) {
26+
WARNINGOUT << "Cannot tell the screens apart";
27+
verify = false;
28+
} else if ( screenPrimary.width() == 0 || screenPrimary.height() == 0 ) {
29+
WARNINGOUT << "Cannot query primary screen size";
30+
verify = false;
31+
} else if ( screenSecondary.width() == 0 || screenSecondary.height() == 0 ) {
32+
WARNINGOUT << "Cannot query secondary screen size";
33+
verify = false;
34+
}
35+
if ( ! verify ) {
36+
WARNINGOUT << "Disabling verification.";
37+
}
38+
// 1 Second time to boot
39+
QTimer::singleShot(1000, this, SLOT(checkStartPositions()));
40+
}
41+
42+
void SwapScreensAndCheckAlign::checkStartPositions() {
43+
DEBUGOUT << "Start positions";
44+
if ( verify ) {
45+
check(dspdfviewer.audienceGeometry(), screenSecondary); // Audience starts on external
46+
check(dspdfviewer.secondGeometry(), screenPrimary); // Presenter starts on internal
47+
}
48+
DEBUGOUT << "Firing screen swap event";
49+
emit screenSwapRequested();
50+
// 0.5 sec to swap
51+
QTimer::singleShot(500, this, SLOT(checkAfterFirstSwap()));
52+
}
53+
54+
void SwapScreensAndCheckAlign::checkAfterFirstSwap() {
55+
DEBUGOUT << "Check after first swap";
56+
if ( verify ) {
57+
check(dspdfviewer.audienceGeometry(), screenPrimary); // Audience window on laptop
58+
check(dspdfviewer.secondGeometry(), screenSecondary); // Presenter window on beamer
59+
}
60+
emit screenSwapRequested();
61+
// 0.5 sec time to swap
62+
QTimer::singleShot(500, this, SLOT(checkAfterSwapBack()));
63+
}
64+
65+
void SwapScreensAndCheckAlign::checkAfterSwapBack() {
66+
DEBUGOUT << "Check after swapping back";
67+
if ( verify ) {
68+
check(dspdfviewer.audienceGeometry(), screenSecondary);
69+
check(dspdfviewer.secondGeometry(), screenPrimary);
70+
emit quitRequested();
71+
}
72+
else {
73+
QCoreApplication::exit(77);
74+
}
1175
}

testing/testswapscreen.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include "dspdfviewer.h"
4+
5+
/** Test driver
6+
*
7+
* If it detects two screens, it will verify that the windows switch to the
8+
* specified positions.
9+
* If running on single-screen, the commands will be executed without verification,
10+
* just to make sure the code doesn't segfault or similar.
11+
*
12+
* Rinse and repeat 3 times.
13+
*
14+
*/
15+
class SwapScreensAndCheckAlign: public QObject {
16+
Q_OBJECT
17+
18+
DSPDFViewer& dspdfviewer;
19+
QRect screenPrimary;
20+
QRect screenSecondary;
21+
bool verify;
22+
public:
23+
SwapScreensAndCheckAlign(DSPDFViewer& app);
24+
signals:
25+
void screenSwapRequested();
26+
void quitRequested();
27+
public slots:
28+
void checkStartPositions();
29+
void checkAfterFirstSwap();
30+
void checkAfterSwapBack();
31+
};

windowrole.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22
#include <stdexcept>
33

44
QString to_QString( const WindowRole& wr) {
5-
switch( wr ) {
6-
case WindowRole::AudienceWindow:
7-
return QString::fromUtf8("Audience_Window");
8-
case WindowRole::PresenterWindow:
9-
return QString::fromUtf8("Secondary_Window");
5+
if( wr == WindowRole::AudienceWindow ) {
6+
return QString::fromUtf8("Audience_Window");
7+
} else {
8+
return QString::fromUtf8("Secondary_Window");
109
}
11-
throw std::runtime_error("Control should never get here.");
1210
}

0 commit comments

Comments
 (0)