File indexing completed on 2024-04-21 04:02:04

0001 /******************************************************************************
0002 *   KBlocks, a falling blocks game by KDE                                     *
0003 *   SPDX-FileCopyrightText: 2009-2021 Julian Helfferich <julian.helfferich@mailbox.org> *
0004 *                                                                             *
0005 *   SPDX-License-Identifier: GPL-2.0-or-later
0006 ******************************************************************************/
0007 #include <memory>
0008 
0009 #include <QTest>
0010 
0011 #include "Testing/MockGraphics.h"
0012 #include "Testing/MockSingleGame.h"
0013 #include "Testing/MockSound.h"
0014 #include "Testing/MockSvgItem.h"
0015 
0016 #include "Testing/TestingKBlocksItemGroup.h"
0017 
0018 class testKBlocksItemGroup : public QObject
0019 {
0020     Q_OBJECT
0021 private Q_SLOTS:
0022     void refreshPositionShouldSetCorrectPositions();
0023     void refreshPositionShouldClearCache();
0024     void updateGameShouldProcessGameActionsOnGameOver();
0025     void updateGameShouldRefreshItemsOnGameOver();
0026     void stopGameShouldProcessRemainingGameActions();
0027 };
0028 
0029 void testKBlocksItemGroup::refreshPositionShouldSetCorrectPositions()
0030 {
0031     /**
0032      * When refreshPosition is called, the positions of the SVG items
0033      * in the prepare area and the playing field are updated. The new
0034      * positions are determined from the (possibly updated) layout.
0035      */
0036     MockSingleGame singleGame;
0037     MockGraphics graphics;
0038     graphics.m_PreviewArea_CenterPoint_X = 1;
0039     graphics.m_PreviewArea_CenterPoint_Y = 1;
0040     graphics.m_Block_Size = 1;
0041     graphics.m_PlayArea_NumberOfBlocks_X = 2;
0042     graphics.m_PlayArea_NumberOfBlocks_Y = 2;
0043     graphics.m_PlayArea_OffsetPoint_X = 1;
0044     graphics.m_PlayArea_OffsetPoint_Y = 1;
0045     MockSound sound;
0046     TestingKBlocksItemGroup itemGroup(0, &singleGame, &graphics, &sound);
0047 
0048     graphics.m_PreviewArea_CenterPoint_X = 30;
0049     graphics.m_PreviewArea_CenterPoint_Y = 50;
0050     graphics.m_Block_Size = 12;
0051     graphics.m_PlayArea_OffsetPoint_X = 10;
0052     graphics.m_PlayArea_OffsetPoint_Y = 15;
0053 
0054     itemGroup.refreshPosition();
0055 
0056     std::vector<QPointF> expectedPreparePositions{
0057         { 0, 20},
0058         {12, 20},
0059         {24, 20},
0060         {36, 20},
0061         {48, 20},
0062         { 0, 32},
0063         {12, 32},
0064         {24, 32},
0065         {36, 32}
0066     };
0067 
0068     for (size_t i = 0; i < expectedPreparePositions.size(); ++i) {
0069         auto *prepareCell = itemGroup.getPrepareCell(i);
0070         QVERIFY(prepareCell != nullptr);
0071         QCOMPARE(prepareCell->pos(), expectedPreparePositions.at(i));
0072     }
0073 
0074     std::vector<QPointF> expectedFreezePositions{
0075         {10, 15},
0076         {22, 15},
0077         {10, 27},
0078         {22, 27}
0079     };
0080 
0081     for (size_t i = 0; i < expectedFreezePositions.size(); ++i) {
0082         auto *freezeCell = itemGroup.getFreezeCell(i);
0083         QVERIFY(freezeCell != nullptr);
0084         QCOMPARE(freezeCell->pos(), expectedFreezePositions.at(i));
0085     }
0086 }
0087 
0088 void testKBlocksItemGroup::refreshPositionShouldClearCache()
0089 {
0090     /**
0091      * The positions are refreshed when the layout changes. Then, also
0092      * the cache should be cleared to ensure that the graphics for each
0093      * item is updated.
0094      *
0095      * See bug 380474
0096      */
0097     MockSingleGame singleGame;
0098     MockGraphics graphics;
0099     MockSound sound;
0100     TestingKBlocksItemGroup itemGroup(0, &singleGame, &graphics, &sound);
0101 
0102     itemGroup.replacePrepareCell(0, new MockSvgItem());
0103     itemGroup.replaceFreezeCell(0, new MockSvgItem());
0104 
0105     auto *prepareCellBefore = dynamic_cast<MockSvgItem*>(
0106         itemGroup.getPrepareCell(0)
0107     );
0108     QVERIFY(prepareCellBefore != nullptr);
0109     QCOMPARE(prepareCellBefore->clearCacheCalled, false);
0110 
0111     auto *freezeCellBefore = dynamic_cast<MockSvgItem*>(
0112         itemGroup.getFreezeCell(0)
0113     );
0114     QVERIFY(freezeCellBefore != nullptr);
0115     QCOMPARE(freezeCellBefore->clearCacheCalled, false);
0116 
0117     itemGroup.refreshPosition();
0118 
0119     auto *prepareCellAfter = dynamic_cast<MockSvgItem*>(
0120         itemGroup.getPrepareCell(0)
0121     );
0122     QVERIFY(prepareCellAfter != nullptr);
0123     QCOMPARE(prepareCellAfter->clearCacheCalled, true);
0124 
0125     auto *freezeCellAfter = dynamic_cast<MockSvgItem*>(
0126         itemGroup.getFreezeCell(0)
0127     );
0128     QVERIFY(freezeCellAfter != nullptr);
0129     QCOMPARE(freezeCellAfter->clearCacheCalled, true);
0130 }
0131 
0132 
0133 void testKBlocksItemGroup::updateGameShouldProcessGameActionsOnGameOver()
0134 {
0135     /**
0136      * When updateGame is called, updateLayout should be called even
0137      * when the game is over. Otherwise, some game actions are not
0138      * processed and the play area does not show where the last item
0139      * has moved, causing the game to be over.
0140      *
0141      * See bug 407244
0142      */
0143     std::unique_ptr<SingleGameInterface> pSingleGame( new MockSingleGame() );
0144     MockSingleGame *mock = dynamic_cast<MockSingleGame*>(pSingleGame.get());
0145     mock->updateGameReturnValue = 1;
0146 
0147     std::unique_ptr<GraphicsInterface> pGraphics( new MockGraphics() );
0148     std::unique_ptr<SoundInterface> pSound( new MockSound() );
0149     TestingKBlocksItemGroup itemGroup(0, pSingleGame.get(), pGraphics.get(), pSound.get() );
0150 
0151     itemGroup.callUpdateGame();
0152 
0153     QCOMPARE( mock->numberOfPickGameActionCalls, 1 );
0154 }
0155 
0156 void testKBlocksItemGroup::updateGameShouldRefreshItemsOnGameOver()
0157 {
0158     /**
0159      * When updateGame is called, the final piece might just have been
0160      * placed, causing the game to be over. If refreshItems() is not
0161      * called, the final piece will be invisible. The correct behavior
0162      * is to fully display the final piece, making it clear how and
0163      * where it conflicted with the pieces on the field.
0164      */
0165     std::unique_ptr<SingleGameInterface> pSingleGame( new MockSingleGame() );
0166     std::unique_ptr<GraphicsInterface> pGraphics( new MockGraphics() );
0167     std::unique_ptr<SoundInterface> pSound( new MockSound() );
0168     TestingKBlocksItemGroup itemGroup(0, pSingleGame.get(), pGraphics.get(), pSound.get() );
0169 
0170     MockSvgItem *svgItem = new MockSvgItem();
0171     itemGroup.replaceFreezeCell(0, svgItem);
0172 
0173     itemGroup.callUpdateGame();
0174 
0175     QVERIFY(svgItem->updateSelfCalled);
0176 }
0177 
0178 
0179 void testKBlocksItemGroup::stopGameShouldProcessRemainingGameActions()
0180 {
0181     /**
0182      * When the game is stopped (on game over), updateLayout needs to be
0183      * called. Otherwise, the play area is updated only after highscore
0184      * has been shown.
0185      *
0186      * See bug 407244
0187      */
0188     std::unique_ptr<SingleGameInterface> pSingleGame( new MockSingleGame() );
0189     std::unique_ptr<GraphicsInterface> pGraphics( new MockGraphics() );
0190     std::unique_ptr<SoundInterface> pSound( new MockSound() );
0191     KBlocksItemGroup itemGroup(0, pSingleGame.get(), pGraphics.get(), pSound.get() );
0192 
0193     itemGroup.stopGame();
0194 
0195     MockSingleGame *mock = dynamic_cast<MockSingleGame*>(pSingleGame.get());
0196     QCOMPARE( mock->numberOfPickGameActionCalls, 1 );
0197 }
0198 
0199 
0200 QTEST_MAIN(testKBlocksItemGroup)
0201 
0202 #include "test_KBlocksItemGroup.moc"