From 178fa4f785b0c230ca9c2d63c5d6fa1291fa9d59 Mon Sep 17 00:00:00 2001 From: DonLakeFlyer Date: Mon, 17 Apr 2017 16:04:05 -0700 Subject: [PATCH] Big investment in Plan oriented unit tests Fixed all the bugs the new tests found --- qgroundcontrol.pro | 12 +- src/MissionManager/CameraSection.cc | 43 +- src/MissionManager/CameraSection.h | 5 +- src/MissionManager/CameraSectionTest.cc | 871 ++++++++++++++++++++ src/MissionManager/CameraSectionTest.h | 67 ++ src/MissionManager/MissionController.cc | 4 +- src/MissionManager/MissionSettingsItem.cc | 19 +- src/MissionManager/MissionSettingsItem.h | 2 +- src/MissionManager/Section.h | 4 +- src/MissionManager/SectionTest.cc | 101 +++ src/MissionManager/SectionTest.h | 50 ++ src/MissionManager/SimpleMissionItem.cc | 7 +- src/MissionManager/SimpleMissionItem.h | 2 +- src/MissionManager/SimpleMissionItemTest.cc | 224 +++-- src/MissionManager/SimpleMissionItemTest.h | 43 +- src/MissionManager/SpeedSection.cc | 12 +- src/MissionManager/SpeedSection.h | 11 +- src/MissionManager/SpeedSectionTest.cc | 266 ++++++ src/MissionManager/SpeedSectionTest.h | 52 ++ src/MissionManager/VisualMissionItemTest.cc | 58 ++ src/MissionManager/VisualMissionItemTest.h | 89 ++ src/qgcunittest/UnitTestList.cc | 5 + 22 files changed, 1757 insertions(+), 190 deletions(-) create mode 100644 src/MissionManager/CameraSectionTest.cc create mode 100644 src/MissionManager/CameraSectionTest.h create mode 100644 src/MissionManager/SectionTest.cc create mode 100644 src/MissionManager/SectionTest.h create mode 100644 src/MissionManager/SpeedSectionTest.cc create mode 100644 src/MissionManager/SpeedSectionTest.h create mode 100644 src/MissionManager/VisualMissionItemTest.cc create mode 100644 src/MissionManager/VisualMissionItemTest.h diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 9d4fdd951..78f5c0703 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -384,13 +384,17 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin { src/FactSystem/FactSystemTestGeneric.h \ src/FactSystem/FactSystemTestPX4.h \ src/FactSystem/ParameterManagerTest.h \ - src/MissionManager/SurveyMissionItemTest.h \ + src/MissionManager/CameraSectionTest.h \ src/MissionManager/MissionCommandTreeTest.h \ src/MissionManager/MissionControllerManagerTest.h \ src/MissionManager/MissionControllerTest.h \ src/MissionManager/MissionItemTest.h \ src/MissionManager/MissionManagerTest.h \ + src/MissionManager/SectionTest.h \ src/MissionManager/SimpleMissionItemTest.h \ + src/MissionManager/SpeedSectionTest.h \ + src/MissionManager/SurveyMissionItemTest.h \ + src/MissionManager/VisualMissionItemTest.h \ src/qgcunittest/FileDialogTest.h \ src/qgcunittest/FileManagerTest.h \ src/qgcunittest/FlightGearTest.h \ @@ -412,13 +416,17 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin { src/FactSystem/FactSystemTestGeneric.cc \ src/FactSystem/FactSystemTestPX4.cc \ src/FactSystem/ParameterManagerTest.cc \ - src/MissionManager/SurveyMissionItemTest.cc \ + src/MissionManager/CameraSectionTest.cc \ src/MissionManager/MissionCommandTreeTest.cc \ src/MissionManager/MissionControllerManagerTest.cc \ src/MissionManager/MissionControllerTest.cc \ src/MissionManager/MissionItemTest.cc \ src/MissionManager/MissionManagerTest.cc \ + src/MissionManager/SectionTest.cc \ src/MissionManager/SimpleMissionItemTest.cc \ + src/MissionManager/SpeedSectionTest.cc \ + src/MissionManager/SurveyMissionItemTest.cc \ + src/MissionManager/VisualMissionItemTest.cc \ src/qgcunittest/FileDialogTest.cc \ src/qgcunittest/FileManagerTest.cc \ src/qgcunittest/FlightGearTest.cc \ diff --git a/src/MissionManager/CameraSection.cc b/src/MissionManager/CameraSection.cc index eea8c89f4..fc35be418 100644 --- a/src/MissionManager/CameraSection.cc +++ b/src/MissionManager/CameraSection.cc @@ -48,13 +48,14 @@ CameraSection::CameraSection(Vehicle* vehicle, QObject* parent) _cameraPhotoIntervalDistanceFact.setRawValue (_cameraPhotoIntervalDistanceFact.rawDefaultValue()); _cameraPhotoIntervalTimeFact.setRawValue (_cameraPhotoIntervalTimeFact.rawDefaultValue()); - connect(this, &CameraSection::specifyGimbalChanged, this, &CameraSection::_setDirtyAndUpdateItemCount); - connect(&_cameraActionFact, &Fact::valueChanged, this, &CameraSection::_setDirtyAndUpdateItemCount); + connect(this, &CameraSection::specifyGimbalChanged, this, &CameraSection::_specifyGimbalChanged); + connect(&_cameraActionFact, &Fact::valueChanged, this, &CameraSection::_cameraActionChanged); - connect(&_gimbalPitchFact, &Fact::valueChanged, this, &CameraSection::_setDirty); - connect(&_gimbalYawFact, &Fact::valueChanged, this, &CameraSection::_setDirty); - connect(&_cameraPhotoIntervalDistanceFact, &Fact::valueChanged, this, &CameraSection::_setDirty); - connect(&_cameraPhotoIntervalTimeFact, &Fact::valueChanged, this, &CameraSection::_setDirty); + connect(&_gimbalPitchFact, &Fact::valueChanged, this, &CameraSection::_setDirty); + connect(&_gimbalYawFact, &Fact::valueChanged, this, &CameraSection::_setDirty); + connect(&_cameraPhotoIntervalDistanceFact, &Fact::valueChanged, this, &CameraSection::_setDirty); + connect(&_cameraPhotoIntervalTimeFact, &Fact::valueChanged, this, &CameraSection::_setDirty); + connect(this, &CameraSection::specifyGimbalChanged, this, &CameraSection::_setDirty); connect(&_gimbalYawFact, &Fact::valueChanged, this, &CameraSection::_updateSpecifiedGimbalYaw); } @@ -188,7 +189,7 @@ void CameraSection::appendSectionItems(QList& items, QObject* miss } } -bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanIndex) +bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int scanIndex) { bool foundGimbal = false; bool foundCameraAction = false; @@ -218,7 +219,6 @@ bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanInd case MAV_CMD_DO_MOUNT_CONTROL: if (!foundGimbal && missionItem.param2() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == MAV_MOUNT_MODE_MAVLINK_TARGETING) { foundGimbal = true; - scanIndex++; setSpecifyGimbal(true); gimbalPitch()->setRawValue(missionItem.param1()); gimbalYaw()->setRawValue(missionItem.param3()); @@ -231,7 +231,6 @@ bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanInd case MAV_CMD_IMAGE_START_CAPTURE: if (!foundCameraAction && missionItem.param1() != 0 && missionItem.param2() == 0 && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { foundCameraAction = true; - scanIndex++; cameraAction()->setRawValue(TakePhotosIntervalTime); cameraPhotoIntervalTime()->setRawValue(missionItem.param1()); visualItems->removeAt(scanIndex)->deleteLater(); @@ -251,7 +250,6 @@ bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanInd if (nextMissionItem.command() == MAV_CMD_IMAGE_STOP_CAPTURE && nextMissionItem.param1() == 0 && nextMissionItem.param2() == 0 && nextMissionItem.param3() == 0 && nextMissionItem.param4() == 0 && nextMissionItem.param5() == 0 && nextMissionItem.param6() == 0 && nextMissionItem.param7() == 0) { // We found a stop taking photos pair foundCameraAction = true; - scanIndex += 2; cameraAction()->setRawValue(StopTakingPhotos); visualItems->removeAt(scanIndex)->deleteLater(); visualItems->removeAt(scanIndex)->deleteLater(); @@ -264,7 +262,6 @@ bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanInd // We didn't find a stop taking photos pair, check for trigger distance if (missionItem.param1() > 0) { foundCameraAction = true; - scanIndex++; cameraAction()->setRawValue(TakePhotoIntervalDistance); cameraPhotoIntervalDistance()->setRawValue(missionItem.param1()); visualItems->removeAt(scanIndex)->deleteLater(); @@ -278,7 +275,6 @@ bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanInd case MAV_CMD_VIDEO_START_CAPTURE: if (!foundCameraAction && missionItem.param1() == 0 && missionItem.param2() == -1 && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { foundCameraAction = true; - scanIndex++; cameraAction()->setRawValue(TakeVideo); visualItems->removeAt(scanIndex)->deleteLater(); } @@ -288,7 +284,6 @@ bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanInd case MAV_CMD_VIDEO_STOP_CAPTURE: if (!foundCameraAction && missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { foundCameraAction = true; - scanIndex++; cameraAction()->setRawValue(StopTakingVideo); visualItems->removeAt(scanIndex)->deleteLater(); } @@ -337,3 +332,25 @@ void CameraSection::_updateSpecifiedGimbalYaw(void) { emit specifiedGimbalYawChanged(specifiedGimbalYaw()); } + +void CameraSection::_updateSettingsSpecified(void) +{ + bool newSettingsSpecified = _specifyGimbal || _cameraActionFact.rawValue().toInt() != CameraActionNone; + if (newSettingsSpecified != _settingsSpecified) { + _settingsSpecified = newSettingsSpecified; + emit settingsSpecifiedChanged(newSettingsSpecified); + } +} + +void CameraSection::_specifyGimbalChanged(bool specifyGimbal) +{ + Q_UNUSED(specifyGimbal); + _setDirtyAndUpdateItemCount(); + _updateSettingsSpecified(); +} + +void CameraSection::_cameraActionChanged(void) +{ + _setDirtyAndUpdateItemCount(); + _updateSettingsSpecified(); +} diff --git a/src/MissionManager/CameraSection.h b/src/MissionManager/CameraSection.h index da2bf5a4d..943795522 100644 --- a/src/MissionManager/CameraSection.h +++ b/src/MissionManager/CameraSection.h @@ -56,7 +56,7 @@ public: bool dirty (void) const override { return _dirty; } void setAvailable (bool available) override; void setDirty (bool dirty) override; - bool scanForSection (QmlObjectListModel* visualItems, int& scanIndex) override; + bool scanForSection (QmlObjectListModel* visualItems, int scanIndex) override; void appendSectionItems (QList& items, QObject* missionItemParent, int& seqNum) override; int itemCount (void) const override; bool settingsSpecified (void) const override {return _settingsSpecified; } @@ -69,6 +69,9 @@ private slots: void _setDirty(void); void _setDirtyAndUpdateItemCount(void); void _updateSpecifiedGimbalYaw(void); + void _specifyGimbalChanged(bool specifyGimbal); + void _updateSettingsSpecified(void); + void _cameraActionChanged(void); private: bool _available; diff --git a/src/MissionManager/CameraSectionTest.cc b/src/MissionManager/CameraSectionTest.cc new file mode 100644 index 000000000..1660e5599 --- /dev/null +++ b/src/MissionManager/CameraSectionTest.cc @@ -0,0 +1,871 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "CameraSectionTest.h" + +CameraSectionTest::CameraSectionTest(void) + : _spyCamera(NULL) + , _spySection(NULL) + , _cameraSection(NULL) + , _validGimbalItem(NULL) + , _validDistanceItem(NULL) + , _validTimeItem(NULL) + , _validStartVideoItem(NULL) + , _validStopVideoItem(NULL) + , _validStopDistanceItem(NULL) + , _validStopTimeItem(NULL) +{ + +} + +void CameraSectionTest::init(void) +{ + SectionTest::init(); + + rgCameraSignals[specifyGimbalChangedIndex] = SIGNAL(specifyGimbalChanged(bool)); + rgCameraSignals[specifiedGimbalYawChangedIndex] = SIGNAL(specifiedGimbalYawChanged(double)); + + _cameraSection = _simpleItem->cameraSection(); + _createSpy(_cameraSection, &_spyCamera); + QVERIFY(_spyCamera); + SectionTest::_createSpy(_cameraSection, &_spySection); + QVERIFY(_spySection); + + _validGimbalItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(0, MAV_CMD_DO_MOUNT_CONTROL, MAV_FRAME_MISSION, 10.1234, 0, 20.1234, 0, 0, 0, MAV_MOUNT_MODE_MAVLINK_TARGETING, true, false), + this); + _validTimeItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(0, MAV_CMD_IMAGE_START_CAPTURE, MAV_FRAME_MISSION, 48, 0,-1, 0, 0, 0, 0, true, false), + this); + _validDistanceItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(0, MAV_CMD_DO_SET_CAM_TRIGG_DIST, MAV_FRAME_MISSION, 72, 0, 0, 0, 0, 0, 0, true, false), + this); + _validStartVideoItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(0, MAV_CMD_VIDEO_START_CAPTURE, MAV_FRAME_MISSION, 0, -1, -1, 0, 0, 0, 0, true, false), + this); + _validStopVideoItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(0, MAV_CMD_VIDEO_STOP_CAPTURE, MAV_FRAME_MISSION, 0, 0, 0, 0, 0, 0, 0, true, false), + this); + _validStopDistanceItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(0, MAV_CMD_DO_SET_CAM_TRIGG_DIST, MAV_FRAME_MISSION, 0, 0, 0, 0, 0, 0, 0, true, false), + this); + _validStopTimeItem = new SimpleMissionItem(_offlineVehicle, + MissionItem(1, MAV_CMD_IMAGE_STOP_CAPTURE, MAV_FRAME_MISSION, 0, 0, 0, 0, 0, 0, 0, true, false), + this); +} + +void CameraSectionTest::cleanup(void) +{ + delete _spyCamera; + delete _spySection; + delete _validGimbalItem; + delete _validDistanceItem; + delete _validTimeItem; + delete _validStartVideoItem; + delete _validStopVideoItem; + delete _validStopDistanceItem; + delete _validStopTimeItem; + SectionTest::cleanup(); +} + +void CameraSectionTest::_createSpy(CameraSection* cameraSection, MultiSignalSpy** cameraSpy) +{ + *cameraSpy = NULL; + MultiSignalSpy* spy = new MultiSignalSpy(); + QCOMPARE(spy->init(cameraSection, rgCameraSignals, cCameraSignals), true); + *cameraSpy = spy; +} + +void CameraSectionTest::_testDirty(void) +{ + // Check for dirty not signalled if same value + _cameraSection->setSpecifyGimbal(_cameraSection->specifyGimbal()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_cameraSection->dirty(), false); + _cameraSection->gimbalPitch()->setRawValue(_cameraSection->gimbalPitch()->rawValue()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_cameraSection->dirty(), false); + _cameraSection->gimbalYaw()->setRawValue(_cameraSection->gimbalPitch()->rawValue()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_cameraSection->dirty(), false); + _cameraSection->cameraAction()->setRawValue(_cameraSection->cameraAction()->rawValue()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_cameraSection->dirty(), false); + _cameraSection->cameraPhotoIntervalTime()->setRawValue(_cameraSection->cameraPhotoIntervalTime()->rawValue()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_cameraSection->dirty(), false); + _cameraSection->cameraPhotoIntervalDistance()->setRawValue(_cameraSection->cameraPhotoIntervalDistance()->rawValue()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_cameraSection->dirty(), false); + + // Check for no duplicate dirty signalling on change + _cameraSection->setSpecifyGimbal(!_cameraSection->specifyGimbal()); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_cameraSection->dirty(), true); + _spySection->clearAllSignals(); + _cameraSection->setSpecifyGimbal(!_cameraSection->specifyGimbal()); + QVERIFY(_spySection->checkNoSignalByMask(dirtyChangedMask)); + QCOMPARE(_cameraSection->dirty(), true); + _spySection->clearAllSignals(); + + // Check that the dirty bit can be cleared + _cameraSection->setDirty(false); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), false); + QCOMPARE(_cameraSection->dirty(), false); + _spySection->clearAllSignals(); + + // Check the remaining items that should set dirty bit + _cameraSection->gimbalPitch()->setRawValue(_cameraSection->gimbalPitch()->rawValue().toDouble() + 1); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_cameraSection->dirty(), true); + _cameraSection->setDirty(false); + _spySection->clearAllSignals(); + _cameraSection->gimbalYaw()->setRawValue(_cameraSection->gimbalPitch()->rawValue().toDouble() + 1); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_cameraSection->dirty(), true); + _cameraSection->setDirty(false); + _spySection->clearAllSignals(); + _cameraSection->cameraAction()->setRawValue(_cameraSection->cameraAction()->rawValue().toInt() + 1); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_cameraSection->dirty(), true); + _cameraSection->setDirty(false); + _spySection->clearAllSignals(); + _cameraSection->cameraPhotoIntervalTime()->setRawValue(_cameraSection->cameraPhotoIntervalTime()->rawValue().toInt() + 1); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_cameraSection->dirty(), true); + _cameraSection->setDirty(false); + _spySection->clearAllSignals(); + _cameraSection->cameraPhotoIntervalDistance()->setRawValue(_cameraSection->cameraPhotoIntervalDistance()->rawValue().toDouble() + 1); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_cameraSection->dirty(), true); + _cameraSection->setDirty(false); + _spySection->clearAllSignals(); +} + +void CameraSectionTest::_testSettingsAvailable(void) +{ + // No settings specified to start + QVERIFY(_cameraSection->cameraAction()->rawValue().toInt() == CameraSection::CameraActionNone); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + + // Check correct reaction to specifyGimbal on/off + + _cameraSection->setSpecifyGimbal(true); + QCOMPARE(_cameraSection->specifyGimbal(), true); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QVERIFY(_spyCamera->checkSignalByMask(specifyGimbalChangedMask)); + QCOMPARE(_spyCamera->pullBoolFromSignalIndex(specifyGimbalChangedIndex), true); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(settingsSpecifiedChangedIndex), true); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + _cameraSection->setSpecifyGimbal(false); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + QVERIFY(_spyCamera->checkSignalByMask(specifyGimbalChangedMask)); + QCOMPARE(_spyCamera->pullBoolFromSignalIndex(specifyGimbalChangedIndex), false); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(settingsSpecifiedChangedIndex), false); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + // Check correct reaction to cameraAction on/off + + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotosIntervalTime); + QVERIFY(_cameraSection->cameraAction()->rawValue().toInt() == CameraSection::TakePhotosIntervalTime); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(settingsSpecifiedChangedIndex), true); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + QVERIFY(_cameraSection->cameraAction()->rawValue().toInt() == CameraSection::CameraActionNone); + QCOMPARE(_cameraSection->settingsSpecified(), false); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(settingsSpecifiedChangedIndex), false); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + // Check that there is not multiple signalling of settingsSpecified + + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotosIntervalTime); + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotosIntervalTime); + _cameraSection->setSpecifyGimbal(true); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); +} + +void CameraSectionTest::_checkAvailable(void) +{ + MissionItem missionItem(1, // sequence number + MAV_CMD_NAV_TAKEOFF, + MAV_FRAME_GLOBAL_RELATIVE_ALT, + 10.1234567, // param 1-7 + 20.1234567, + 30.1234567, + 40.1234567, + 50.1234567, + 60.1234567, + 70.1234567, + true, // autoContinue + false); // isCurrentItem + SimpleMissionItem* item = new SimpleMissionItem(_offlineVehicle, missionItem); + QVERIFY(item->cameraSection()); + QCOMPARE(item->cameraSection()->available(), false); +} + + +void CameraSectionTest::_testItemCount(void) +{ + // No settings specified to start + QCOMPARE(_cameraSection->itemCount(), 0); + + // Check specifyGimbal + + _cameraSection->setSpecifyGimbal(true); + QCOMPARE(_cameraSection->itemCount(), 1); + QVERIFY(_spySection->checkSignalByMask(itemCountChangedMask)); + QCOMPARE(_spySection->pullIntFromSignalIndex(itemCountChangedIndex), 1); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + _cameraSection->setSpecifyGimbal(false); + QCOMPARE(_cameraSection->itemCount(), 0); + QVERIFY(_spySection->checkSignalByMask(itemCountChangedMask)); + QCOMPARE(_spySection->pullIntFromSignalIndex(itemCountChangedIndex), 0); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + // Check camera actions + + QList rgCameraActions; + rgCameraActions << CameraSection::TakePhotosIntervalTime << CameraSection::TakePhotoIntervalDistance << CameraSection::StopTakingPhotos << CameraSection::TakeVideo << CameraSection::StopTakingVideo; + foreach(int cameraAction, rgCameraActions) { + qDebug() << "camera action" << cameraAction; + + // Reset + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + QCOMPARE(_cameraSection->itemCount(), 0); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + // Set to new action + _cameraSection->cameraAction()->setRawValue(cameraAction); + QCOMPARE(_cameraSection->itemCount(), 1); + QVERIFY(_spySection->checkSignalByMask(itemCountChangedMask)); + QCOMPARE(_spySection->pullIntFromSignalIndex(itemCountChangedIndex), 1); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + } + + // Reset + _cameraSection->setSpecifyGimbal(false); + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + QCOMPARE(_cameraSection->itemCount(), 0); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + + // Check both camera action and gimbal set + _cameraSection->setSpecifyGimbal(true); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotosIntervalTime); + QCOMPARE(_cameraSection->itemCount(), 2); + QVERIFY(_spySection->checkSignalsByMask(itemCountChangedMask)); + QCOMPARE(_spySection->pullIntFromSignalIndex(itemCountChangedIndex), 2); + _spySection->clearAllSignals(); + _spyCamera->clearAllSignals(); +} + + +void CameraSectionTest::_testAppendSectionItems(void) +{ + int seqNum = 0; + QList rgMissionItems; + + // No settings specified to start + QCOMPARE(_cameraSection->itemCount(), 0); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 0); + QCOMPARE(seqNum, 0); + rgMissionItems.clear(); + + // Test specifyGimbal + + _cameraSection->setSpecifyGimbal(true); + _cameraSection->gimbalPitch()->setRawValue(_validGimbalItem->missionItem().param1()); + _cameraSection->gimbalYaw()->setRawValue(_validGimbalItem->missionItem().param3()); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 1); + QCOMPARE(seqNum, 1); + _missionItemsEqual(*rgMissionItems[0], _validGimbalItem->missionItem()); + _cameraSection->setSpecifyGimbal(false); + rgMissionItems.clear(); + seqNum = 0; + + // Test camera actions + + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotosIntervalTime); + _cameraSection->cameraPhotoIntervalTime()->setRawValue(_validTimeItem->missionItem().param1()); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 1); + QCOMPARE(seqNum, 1); + _missionItemsEqual(*rgMissionItems[0], _validTimeItem->missionItem()); + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + rgMissionItems.clear(); + seqNum = 0; + + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotoIntervalDistance); + _cameraSection->cameraPhotoIntervalDistance()->setRawValue(_validDistanceItem->missionItem().param1()); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 1); + QCOMPARE(seqNum, 1); + _missionItemsEqual(*rgMissionItems[0], _validDistanceItem->missionItem()); + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + rgMissionItems.clear(); + seqNum = 0; + + _cameraSection->cameraAction()->setRawValue(CameraSection::TakeVideo); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 1); + QCOMPARE(seqNum, 1); + _missionItemsEqual(*rgMissionItems[0], _validStartVideoItem->missionItem()); + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + rgMissionItems.clear(); + seqNum = 0; + + _cameraSection->cameraAction()->setRawValue(CameraSection::StopTakingVideo); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 1); + QCOMPARE(seqNum, 1); + _missionItemsEqual(*rgMissionItems[0], _validStopVideoItem->missionItem()); + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + rgMissionItems.clear(); + seqNum = 0; + + _cameraSection->cameraAction()->setRawValue(CameraSection::StopTakingPhotos); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 2); + QCOMPARE(seqNum, 2); + _missionItemsEqual(*rgMissionItems[0], _validStopDistanceItem->missionItem()); + _missionItemsEqual(*rgMissionItems[1], _validStopTimeItem->missionItem()); + _cameraSection->cameraAction()->setRawValue(CameraSection::CameraActionNone); + rgMissionItems.clear(); + seqNum = 0; + + // Test both + _cameraSection->setSpecifyGimbal(true); + _cameraSection->gimbalPitch()->setRawValue(_validGimbalItem->missionItem().param1()); + _cameraSection->gimbalYaw()->setRawValue(_validGimbalItem->missionItem().param3()); + _cameraSection->cameraAction()->setRawValue(CameraSection::TakePhotosIntervalTime); + _cameraSection->cameraPhotoIntervalTime()->setRawValue(_validTimeItem->missionItem().param1()); + _cameraSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 2); + QCOMPARE(seqNum, 2); + _missionItemsEqual(*rgMissionItems[0], _validGimbalItem->missionItem()); + _missionItemsEqual(*rgMissionItems[1], _validTimeItem->missionItem()); + _cameraSection->setSpecifyGimbal(false); + rgMissionItems.clear(); + seqNum = 0; +} + +void CameraSectionTest::_testScanForGimbalSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + + // Check for a scan success + + SimpleMissionItem* newValidGimbalItem = new SimpleMissionItem(_offlineVehicle, this); + newValidGimbalItem->missionItem() = _validGimbalItem->missionItem(); + visualItems.append(newValidGimbalItem); + scanIndex = 0; + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->specifyGimbal(), true); + QCOMPARE(_cameraSection->gimbalPitch()->rawValue().toDouble(), _validGimbalItem->missionItem().param1()); + QCOMPARE(_cameraSection->gimbalYaw()->rawValue().toDouble(), _validGimbalItem->missionItem().param3()); + _cameraSection->setSpecifyGimbal(false); + visualItems.clear(); + scanIndex = 0; + +#if 0 + MAV_CMD_DO_MOUNT_CONTROL + Mission Param #1 pitch (WIP: DEPRECATED: or lat in degrees) depending on mount mode. + Mission Param #2 roll (WIP: DEPRECATED: or lon in degrees) depending on mount mode. + Mission Param #3 yaw (WIP: DEPRECATED: or alt in meters) depending on mount mode. + Mission Param #4 WIP: alt in meters depending on mount mode. + Mission Param #5 WIP: latitude in degrees * 1E7, set if appropriate mount mode. + Mission Param #6 WIP: longitude in degrees * 1E7, set if appropriate mount mode. + Mission Param #7 MAV_MOUNT_MODE enum value +#endif + + // Gimbal command but incorrect settings + + SimpleMissionItem invalidSimpleItem(_offlineVehicle, _validGimbalItem->missionItem()); + invalidSimpleItem.missionItem().setParam2(10); // roll is not supported + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validGimbalItem->missionItem(); + invalidSimpleItem.missionItem().setParam4(10); // alt is not supported + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validGimbalItem->missionItem(); + invalidSimpleItem.missionItem().setParam5(10); // lat is not supported + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validGimbalItem->missionItem(); + invalidSimpleItem.missionItem().setParam6(10); // lon is not supported + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validGimbalItem->missionItem(); + invalidSimpleItem.missionItem().setParam7(MAV_MOUNT_MODE_RETRACT); // Only MAV_MOUNT_MODE_MAVLINK_TARGETING supported + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->specifyGimbal(), false); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); +} + +void CameraSectionTest::_testScanForPhotoIntervalTimeSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + +#if 0 + MAV_CMD_IMAGE_START_CAPTURE Start image capture sequence. Sends CAMERA_IMAGE_CAPTURED after each capture. + Mission Param #1 Duration between two consecutive pictures (in seconds) + Mission Param #2 Number of images to capture total - 0 for unlimited capture + Mission Param #3 Resolution in megapixels (0.3 for 640x480, 1.3 for 1280x720, etc), set to 0 if param 4/5 are used, set to -1 for highest resolution possible. + Mission Param #4 WIP: Resolution horizontal in pixels + Mission Param #5 WIP: Resolution horizontal in pixels + Mission Param #6 WIP: Camera ID // Check for a scan success +#endif + + SimpleMissionItem* newValidTimeItem = new SimpleMissionItem(_offlineVehicle, this); + newValidTimeItem->missionItem() = _validTimeItem->missionItem(); + visualItems.append(newValidTimeItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->cameraAction()->rawValue().toInt(), (int)CameraSection::TakePhotosIntervalTime); + QCOMPARE(_cameraSection->cameraPhotoIntervalTime()->rawValue().toInt(), (int)_validTimeItem->missionItem().param1()); + visualItems.clear(); + scanIndex = 0; + + // Image start command but incorrect settings + + SimpleMissionItem invalidSimpleItem(_offlineVehicle, _validTimeItem->missionItem()); + invalidSimpleItem.missionItem().setParam2(10); // must be unlimited + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validTimeItem->missionItem(); + invalidSimpleItem.missionItem().setParam3(1.3); // must be -1 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validTimeItem->missionItem(); + invalidSimpleItem.missionItem().setParam4(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validTimeItem->missionItem(); + invalidSimpleItem.missionItem().setParam5(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validTimeItem->missionItem(); + invalidSimpleItem.missionItem().setParam6(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validTimeItem->missionItem(); + invalidSimpleItem.missionItem().setParam7(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); +} + +void CameraSectionTest::_testScanForPhotoIntervalDistanceSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + +#if 0 + MAV_CMD_DO_SET_CAM_TRIGG_DIST Mission command to set CAM_TRIGG_DIST for this flight + Mission Param #1 Camera trigger distance (meters) + Mission Param #2 Empty + Mission Param #3 Empty + Mission Param #4 Empty + Mission Param #5 Empty + Mission Param #6 Empty + Mission Param #7 Empty +#endif + + SimpleMissionItem* newValidDistanceItem = new SimpleMissionItem(_offlineVehicle, this); + newValidDistanceItem->missionItem() = _validDistanceItem->missionItem(); + visualItems.append(newValidDistanceItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->cameraAction()->rawValue().toInt(), (int)CameraSection::TakePhotoIntervalDistance); + QCOMPARE(_cameraSection->cameraPhotoIntervalDistance()->rawValue().toInt(), (int)_validDistanceItem->missionItem().param1()); + visualItems.clear(); + scanIndex = 0; + + // Trigger distance command but incorrect settings + + SimpleMissionItem invalidSimpleItem(_offlineVehicle, _validDistanceItem->missionItem()); + invalidSimpleItem.missionItem().setParam1(-1); // must be >= 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validDistanceItem->missionItem(); + invalidSimpleItem.missionItem().setParam2(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validDistanceItem->missionItem(); + invalidSimpleItem.missionItem().setParam3(1); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validDistanceItem->missionItem(); + invalidSimpleItem.missionItem().setParam4(100); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validDistanceItem->missionItem(); + invalidSimpleItem.missionItem().setParam5(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validDistanceItem->missionItem(); + invalidSimpleItem.missionItem().setParam6(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validDistanceItem->missionItem(); + invalidSimpleItem.missionItem().setParam7(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); +} + +void CameraSectionTest::_testScanForStartVideoSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + +#if 0 + MAV_CMD_VIDEO_STOP_CAPTURE Stop the current video capture (recording) + Mission Param #1 WIP: Camera ID + Mission Param #2 Reserved + Mission Param #3 Resolution in megapixels (0.3 for 640x480, 1.3 for 1280x720, etc), set to 0 if param 4/5 are used, set to -1 for highest resolution possible. + Mission Param #4 WIP: Resolution horizontal in pixels + Mission Param #5 WIP: Resolution horizontal in pixels + Mission Param #6 WIP: Frequency CAMERA_CAPTURE_STATUS messages should be sent while recording (0 for no messages, otherwise time in Hz) +#endif + + SimpleMissionItem* newValidStartVideoItem = new SimpleMissionItem(_offlineVehicle, this); + newValidStartVideoItem->missionItem() = _validStartVideoItem->missionItem(); + visualItems.append(newValidStartVideoItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->cameraAction()->rawValue().toInt(), (int)CameraSection::TakeVideo); + visualItems.clear(); + scanIndex = 0; + + // Trigger distance command but incorrect settings + + SimpleMissionItem invalidSimpleItem(_offlineVehicle, _validStartVideoItem->missionItem()); + invalidSimpleItem.missionItem().setParam1(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStartVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam2(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStartVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam3(1); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStartVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam4(100); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStartVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam5(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStartVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam6(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStartVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam7(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); +} + +void CameraSectionTest::_testScanForStopVideoSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + +#if 0 + MAV_CMD_VIDEO_STOP_CAPTURE Stop the current video capture (recording) + Mission Param #1 WIP: Camera ID +#endif + + SimpleMissionItem* newValidStopVideoItem = new SimpleMissionItem(_offlineVehicle, this); + newValidStopVideoItem->missionItem() = _validStopVideoItem->missionItem(); + visualItems.append(newValidStopVideoItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->cameraAction()->rawValue().toInt(), (int)CameraSection::StopTakingVideo); + visualItems.clear(); + scanIndex = 0; + + // Trigger distance command but incorrect settings + + SimpleMissionItem invalidSimpleItem(_offlineVehicle, _validStopVideoItem->missionItem()); + invalidSimpleItem.missionItem().setParam1(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStopVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam2(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStopVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam3(1); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStopVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam4(100); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStopVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam5(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStopVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam6(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); + + invalidSimpleItem.missionItem() = _validStopVideoItem->missionItem(); + invalidSimpleItem.missionItem().setParam7(10); // must be 0 + visualItems.append(&invalidSimpleItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); +} + +void CameraSectionTest::_testScanForStopImageSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + + SimpleMissionItem* newValidStopDistanceItem = new SimpleMissionItem(_offlineVehicle, this); + SimpleMissionItem* newValidStopTimeItem = new SimpleMissionItem(_offlineVehicle, this); + newValidStopDistanceItem->missionItem() = _validStopDistanceItem->missionItem(); + newValidStopTimeItem->missionItem() = _validStopTimeItem->missionItem(); + visualItems.append(newValidStopDistanceItem); + visualItems.append(newValidStopTimeItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->cameraAction()->rawValue().toInt(), (int)CameraSection::StopTakingPhotos); + visualItems.clear(); + + // Out of order commands + + SimpleMissionItem validStopDistanceItem(_offlineVehicle); + SimpleMissionItem validStopTimeItem(_offlineVehicle); + validStopDistanceItem.missionItem() = _validStopDistanceItem->missionItem(); + validStopTimeItem.missionItem() = _validStopTimeItem->missionItem(); + visualItems.append(&validStopTimeItem); + visualItems.append(&validStopDistanceItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 2); + QCOMPARE(_cameraSection->settingsSpecified(), false); + visualItems.clear(); +} + +void CameraSectionTest::_testScanForFullSection(void) +{ + QCOMPARE(_cameraSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_cameraSection); + + SimpleMissionItem* newValidGimbalItem = new SimpleMissionItem(_offlineVehicle, this); + SimpleMissionItem* newValidDistanceItem = new SimpleMissionItem(_offlineVehicle, this); + newValidGimbalItem->missionItem() = _validGimbalItem->missionItem(); + newValidDistanceItem->missionItem() = _validDistanceItem->missionItem(); + visualItems.append(newValidGimbalItem); + visualItems.append(newValidDistanceItem); + QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_cameraSection->settingsSpecified(), true); + QCOMPARE(_cameraSection->specifyGimbal(), true); + QCOMPARE(_cameraSection->cameraAction()->rawValue().toInt(), (int)CameraSection::TakePhotoIntervalDistance); + QCOMPARE(_cameraSection->gimbalPitch()->rawValue().toDouble(), _validGimbalItem->missionItem().param1()); + QCOMPARE(_cameraSection->gimbalYaw()->rawValue().toDouble(), _validGimbalItem->missionItem().param3()); + QCOMPARE(_cameraSection->cameraPhotoIntervalDistance()->rawValue().toInt(), (int)_validDistanceItem->missionItem().param1()); + visualItems.clear(); +} diff --git a/src/MissionManager/CameraSectionTest.h b/src/MissionManager/CameraSectionTest.h new file mode 100644 index 000000000..cf2889643 --- /dev/null +++ b/src/MissionManager/CameraSectionTest.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "SectionTest.h" +#include "CameraSection.h" + +/// Unit test for CameraSection +class CameraSectionTest : public SectionTest +{ + Q_OBJECT + +public: + CameraSectionTest(void); + + void init(void) override; + void cleanup(void) override; + +private slots: + void _testDirty(void); + void _testSettingsAvailable(void); + void _checkAvailable(void); + void _testItemCount(void); + void _testAppendSectionItems(void); + void _testScanForGimbalSection(void); + void _testScanForPhotoIntervalTimeSection(void); + void _testScanForPhotoIntervalDistanceSection(void); + void _testScanForStartVideoSection(void); + void _testScanForStopVideoSection(void); + void _testScanForStopImageSection(void); + void _testScanForFullSection(void); + +private: + void _createSpy(CameraSection* cameraSection, MultiSignalSpy** cameraSpy); + + enum { + specifyGimbalChangedIndex = 0, + specifiedGimbalYawChangedIndex, + maxSignalIndex, + }; + + enum { + specifyGimbalChangedMask = 1 << specifyGimbalChangedIndex, + specifiedGimbalYawChangedMask = 1 << specifiedGimbalYawChangedIndex + }; + + static const size_t cCameraSignals = maxSignalIndex; + const char* rgCameraSignals[cCameraSignals]; + + MultiSignalSpy* _spyCamera; + MultiSignalSpy* _spySection; + CameraSection* _cameraSection; + SimpleMissionItem* _validGimbalItem; + SimpleMissionItem* _validDistanceItem; + SimpleMissionItem* _validTimeItem; + SimpleMissionItem* _validStartVideoItem; + SimpleMissionItem* _validStopVideoItem; + SimpleMissionItem* _validStopDistanceItem; + SimpleMissionItem* _validStopTimeItem; +}; diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc index f209c5b09..df7d6ca78 100644 --- a/src/MissionManager/MissionController.cc +++ b/src/MissionManager/MissionController.cc @@ -1543,7 +1543,9 @@ void MissionController::_scanForAdditionalSettings(QmlObjectListModel* visualIte qCDebug(MissionControllerLog) << "MissionController::_scanForAdditionalSettings count:scanIndex" << visualItems->count() << scanIndex; MissionSettingsItem* settingsItem = qobject_cast(visualItem); - if (settingsItem && settingsItem->scanForMissionSettings(visualItems, scanIndex)) { + if (settingsItem) { + scanIndex++; + settingsItem->scanForMissionSettings(visualItems, scanIndex); continue; } diff --git a/src/MissionManager/MissionSettingsItem.cc b/src/MissionManager/MissionSettingsItem.cc index 3e0c78cf0..85d7bdc94 100644 --- a/src/MissionManager/MissionSettingsItem.cc +++ b/src/MissionManager/MissionSettingsItem.cc @@ -43,11 +43,12 @@ MissionSettingsItem::MissionSettingsItem(Vehicle* vehicle, QObject* parent) } _plannedHomePositionAltitudeFact.setMetaData (_metaDataMap[_plannedHomePositionAltitudeName]); - _plannedHomePositionAltitudeFact.setRawValue (_plannedHomePositionAltitudeFact.rawDefaultValue()); - setHomePositionSpecialCase(true); + _cameraSection.setAvailable(true); + _speedSection.setAvailable(true); + connect(this, &MissionSettingsItem::specifyMissionFlightSpeedChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); connect(this, &MissionSettingsItem::missionEndRTLChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); connect(&_cameraSection, &CameraSection::itemCountChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); @@ -184,17 +185,9 @@ bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems qCDebug(MissionSettingsComplexItemLog) << "MissionSettingsItem::scanForMissionSettings count:scanIndex" << visualItems->count() << scanIndex; - MissionSettingsItem* settingsItem = visualItems->value(scanIndex); - if (!settingsItem) { - qWarning() << "Item specified by scanIndex not MissionSettingsItem"; - return false; - } - // Scan through the initial mission items for possible mission settings - - scanIndex++; - foundCameraSection = settingsItem->_cameraSection.scanForSection(visualItems, scanIndex); - foundSpeedSection = settingsItem->_speedSection.scanForSection(visualItems, scanIndex); + foundCameraSection = _cameraSection.scanForSection(visualItems, scanIndex); + foundSpeedSection = _speedSection.scanForSection(visualItems, scanIndex); // Look at the end of the mission for end actions @@ -206,7 +199,7 @@ bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems if (missionItem.command() == MAV_CMD_NAV_RETURN_TO_LAUNCH && missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { qCDebug(MissionSettingsComplexItemLog) << "Scan: Found end action RTL"; - settingsItem->_missionEndRTL = true; + _missionEndRTL = true; visualItems->removeAt(lastIndex)->deleteLater(); } } diff --git a/src/MissionManager/MissionSettingsItem.h b/src/MissionManager/MissionSettingsItem.h index 2d7773178..39e9e16f5 100644 --- a/src/MissionManager/MissionSettingsItem.h +++ b/src/MissionManager/MissionSettingsItem.h @@ -37,7 +37,7 @@ public: QObject* speedSection(void) { return &_speedSection; } /// Scans the loaded items for settings items - static bool scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex); + bool scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex); /// Adds the optional mission end action to the list /// @param items Mission items list to append to diff --git a/src/MissionManager/Section.h b/src/MissionManager/Section.h index 2bb049a16..638f22be6 100644 --- a/src/MissionManager/Section.h +++ b/src/MissionManager/Section.h @@ -41,9 +41,9 @@ public: /// Scans the loaded items for the section items /// @param visualItems Item list - /// @param scanIndex[in,out] Index to start scanning from + /// @param scanIndex Index to start scanning from /// @return true: section found, items added, scanIndex updated - virtual bool scanForSection(QmlObjectListModel* visualItems, int& scanIndex) = 0; + virtual bool scanForSection(QmlObjectListModel* visualItems, int scanIndex) = 0; /// Appends the mission items associated with this section /// @param items List to append to diff --git a/src/MissionManager/SectionTest.cc b/src/MissionManager/SectionTest.cc new file mode 100644 index 000000000..cd95f96c0 --- /dev/null +++ b/src/MissionManager/SectionTest.cc @@ -0,0 +1,101 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "SectionTest.h" +#include "SurveyMissionItem.h" + +SectionTest::SectionTest(void) + : _simpleItem(NULL) +{ + +} + +void SectionTest::init(void) +{ + VisualMissionItemTest::init(); + + rgSectionSignals[availableChangedIndex] = SIGNAL(availableChanged(bool)); + rgSectionSignals[settingsSpecifiedChangedIndex] = SIGNAL(settingsSpecifiedChanged(bool)); + rgSectionSignals[dirtyChangedIndex] = SIGNAL(dirtyChanged(bool)); + rgSectionSignals[itemCountChangedIndex] = SIGNAL(itemCountChanged(int)); + + MissionItem missionItem(1, // sequence number + MAV_CMD_NAV_WAYPOINT, + MAV_FRAME_GLOBAL_RELATIVE_ALT, + 10.1234567, // param 1-7 + 20.1234567, + 30.1234567, + 40.1234567, + 50.1234567, + 60.1234567, + 70.1234567, + true, // autoContinue + false); // isCurrentItem + _simpleItem = new SimpleMissionItem(_offlineVehicle, missionItem); +} + +void SectionTest::cleanup(void) +{ + delete _simpleItem; + VisualMissionItemTest::cleanup(); +} + +void SectionTest::_createSpy(Section* section, MultiSignalSpy** sectionSpy) +{ + *sectionSpy = NULL; + MultiSignalSpy* spy = new MultiSignalSpy(); + QCOMPARE(spy->init(section, rgSectionSignals, cSectionSignals), true); + *sectionSpy = spy; +} + +void SectionTest::_missionItemsEqual(MissionItem& item1, MissionItem& item2) +{ + QCOMPARE(item1.command(), item2.command()); + QCOMPARE(item1.frame(), item2.frame()); + QCOMPARE(item1.autoContinue(), item2.autoContinue()); + QCOMPARE(item1.param1(), item2.param1()); + QCOMPARE(item1.param2(), item2.param2()); + QCOMPARE(item1.param3(), item2.param3()); + QCOMPARE(item1.param4(), item2.param4()); + QCOMPARE(item1.param5(), item2.param5()); + QCOMPARE(item1.param6(), item2.param6()); + QCOMPARE(item1.param7(), item2.param7()); +} + +void SectionTest::_commonScanTest(Section* section) +{ + QCOMPARE(section->available(), true); + + QmlObjectListModel emptyVisualItems; + + QmlObjectListModel waypointVisualItems; + MissionItem waypointItem(0, MAV_CMD_NAV_WAYPOINT, MAV_FRAME_GLOBAL_RELATIVE_ALT, 0, 0, 0, 0, 0, 0, 0, true, false); + SimpleMissionItem simpleItem(_offlineVehicle, waypointItem); + waypointVisualItems.append(&simpleItem); + waypointVisualItems.append(&simpleItem); + waypointVisualItems.append(&simpleItem); + + QmlObjectListModel complexVisualItems; + SurveyMissionItem surveyItem(_offlineVehicle); + complexVisualItems.append(&surveyItem); + + // This tests the common cases which should not lead to scan succeess + + int scanIndex = 0; + QCOMPARE(section->scanForSection(&emptyVisualItems, scanIndex), false); + QCOMPARE(scanIndex, 0); + + scanIndex = 0; + QCOMPARE(section->scanForSection(&waypointVisualItems, scanIndex), false); + QCOMPARE(scanIndex, 0); + + scanIndex = 0; + QCOMPARE(section->scanForSection(&complexVisualItems, scanIndex), false); + QCOMPARE(scanIndex, 0); +} diff --git a/src/MissionManager/SectionTest.h b/src/MissionManager/SectionTest.h new file mode 100644 index 000000000..9c85bb2c3 --- /dev/null +++ b/src/MissionManager/SectionTest.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "VisualMissionItemTest.h" +#include "SimpleMissionItemTest.h" + +/// Unit test for Sections +class SectionTest : public VisualMissionItemTest +{ + Q_OBJECT + +public: + SectionTest(void); + + void init(void) override; + void cleanup(void) override; + +protected: + void _createSpy(Section* section, MultiSignalSpy** sectionSpy); + void _missionItemsEqual(MissionItem& item1, MissionItem& item2); + void _commonScanTest(Section* section); + + enum { + availableChangedIndex = 0, + settingsSpecifiedChangedIndex, + dirtyChangedIndex, + itemCountChangedIndex, + maxSignalIndex, + }; + + enum { + availableChangedMask = 1 << availableChangedIndex, + settingsSpecifiedChangedMask = 1 << settingsSpecifiedChangedIndex, + dirtyChangedMask = 1 << dirtyChangedIndex, + itemCountChangedMask = 1 << itemCountChangedIndex + }; + + static const size_t cSectionSignals = maxSignalIndex; + const char* rgSectionSignals[cSectionSignals]; + + SimpleMissionItem* _simpleItem; +}; diff --git a/src/MissionManager/SimpleMissionItem.cc b/src/MissionManager/SimpleMissionItem.cc index ace438fab..c90b06f4b 100644 --- a/src/MissionManager/SimpleMissionItem.cc +++ b/src/MissionManager/SimpleMissionItem.cc @@ -560,7 +560,10 @@ void SimpleMissionItem::setDirty(bool dirty) { if (!_homePositionSpecialCase || (_dirty != dirty)) { _dirty = dirty; - _cameraSection->setDirty(false); + if (!dirty) { + _cameraSection->setDirty(false); + _speedSection->setDirty(false); + } emit dirtyChanged(dirty); } } @@ -690,7 +693,7 @@ double SimpleMissionItem::specifiedGimbalYaw(void) return _cameraSection->available() ? _cameraSection->specifiedGimbalYaw() : missionItem().specifiedGimbalYaw(); } -bool SimpleMissionItem::scanForSections(QmlObjectListModel* visualItems, int& scanIndex, Vehicle* vehicle) +bool SimpleMissionItem::scanForSections(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle) { bool sectionFound = false; diff --git a/src/MissionManager/SimpleMissionItem.h b/src/MissionManager/SimpleMissionItem.h index 14abcba2b..f57d8b606 100644 --- a/src/MissionManager/SimpleMissionItem.h +++ b/src/MissionManager/SimpleMissionItem.h @@ -52,7 +52,7 @@ public: /// @param scanIndex Index to start scanning from /// @param vehicle Vehicle associated with this mission /// @return true: section found, scanIndex updated - bool scanForSections(QmlObjectListModel* visualItems, int& scanIndex, Vehicle* vehicle); + bool scanForSections(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle); // Property accesors diff --git a/src/MissionManager/SimpleMissionItemTest.cc b/src/MissionManager/SimpleMissionItemTest.cc index e295fd0e1..e36795caa 100644 --- a/src/MissionManager/SimpleMissionItemTest.cc +++ b/src/MissionManager/SimpleMissionItemTest.cc @@ -9,7 +9,6 @@ #include "SimpleMissionItemTest.h" -#include "SimpleMissionItem.h" #include "QGCApplication.h" #include "QGroundControlQmlGlobal.h" #include "SettingsManager.h" @@ -21,7 +20,6 @@ const SimpleMissionItemTest::ItemInfo_t SimpleMissionItemTest::_rgItemInfo[] = { { MAV_CMD_NAV_LOITER_TIME, MAV_FRAME_GLOBAL_RELATIVE_ALT }, { MAV_CMD_NAV_LAND, MAV_FRAME_GLOBAL_RELATIVE_ALT }, { MAV_CMD_NAV_TAKEOFF, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { MAV_CMD_CONDITION_DELAY, MAV_FRAME_MISSION }, { MAV_CMD_DO_JUMP, MAV_FRAME_MISSION }, }; @@ -56,10 +54,6 @@ const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesTak { "Altitude", 70.1234567 }, }; -const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesConditionDelay[] = { - { "Hold", 10.1234567 }, -}; - const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesDoJump[] = { { "Item #", 10.1234567 }, { "Repeat", 20.1234567 }, @@ -72,30 +66,55 @@ const SimpleMissionItemTest::ItemExpected_t SimpleMissionItemTest::_rgItemExpect { sizeof(SimpleMissionItemTest::_rgFactValuesLoiterTime)/sizeof(SimpleMissionItemTest::_rgFactValuesLoiterTime[0]), SimpleMissionItemTest::_rgFactValuesLoiterTime, true }, { sizeof(SimpleMissionItemTest::_rgFactValuesLand)/sizeof(SimpleMissionItemTest::_rgFactValuesLand[0]), SimpleMissionItemTest::_rgFactValuesLand, true }, { sizeof(SimpleMissionItemTest::_rgFactValuesTakeoff)/sizeof(SimpleMissionItemTest::_rgFactValuesTakeoff[0]), SimpleMissionItemTest::_rgFactValuesTakeoff, true }, - { sizeof(SimpleMissionItemTest::_rgFactValuesConditionDelay)/sizeof(SimpleMissionItemTest::_rgFactValuesConditionDelay[0]), SimpleMissionItemTest::_rgFactValuesConditionDelay, false }, { sizeof(SimpleMissionItemTest::_rgFactValuesDoJump)/sizeof(SimpleMissionItemTest::_rgFactValuesDoJump[0]), SimpleMissionItemTest::_rgFactValuesDoJump, false }, }; SimpleMissionItemTest::SimpleMissionItemTest(void) - : _offlineVehicle(NULL) + : _simpleItem(NULL) { } void SimpleMissionItemTest::init(void) { - UnitTest::init(); - _offlineVehicle = new Vehicle(MAV_AUTOPILOT_PX4, - MAV_TYPE_QUADROTOR, - qgcApp()->toolbox()->firmwarePluginManager(), - this); + VisualMissionItemTest::init(); + + rgSimpleItemSignals[commandChangedIndex] = SIGNAL(commandChanged(int)); + rgSimpleItemSignals[frameChangedIndex] = SIGNAL(frameChanged(int)); + rgSimpleItemSignals[friendlyEditAllowedChangedIndex] = SIGNAL(friendlyEditAllowedChanged(bool)); + rgSimpleItemSignals[headingDegreesChangedIndex] = SIGNAL(headingDegreesChanged(double)); + rgSimpleItemSignals[rawEditChangedIndex] = SIGNAL(rawEditChanged(bool)); + rgSimpleItemSignals[cameraSectionChangedIndex] = SIGNAL(rawEditChanged(bool)); + rgSimpleItemSignals[speedSectionChangedIndex] = SIGNAL(rawEditChanged(bool)); + + MissionItem missionItem(1, // sequence number + MAV_CMD_NAV_WAYPOINT, + MAV_FRAME_GLOBAL_RELATIVE_ALT, + 10.1234567, // param 1-7 + 20.1234567, + 30.1234567, + 40.1234567, + 50.1234567, + 60.1234567, + 70.1234567, + true, // autoContinue + false); // isCurrentItem + _simpleItem = new SimpleMissionItem(_offlineVehicle, missionItem); + + // It's important top check that the right signals are emitted at the right time since that drives ui change. + // It's also important to check that things are not being over-signalled when they should not be, since that can lead + // to incorrect ui or perf impact of uneeded signals propogating ui change. + _spySimpleItem = new MultiSignalSpy(); + QCOMPARE(_spySimpleItem->init(_simpleItem, rgSimpleItemSignals, cSimpleItemSignals), true); + _spyVisualItem = new MultiSignalSpy(); + QCOMPARE(_spyVisualItem->init(_simpleItem, rgVisualItemSignals, cVisualItemSignals), true); } void SimpleMissionItemTest::cleanup(void) { - delete _offlineVehicle; - UnitTest::cleanup(); + delete _simpleItem; + VisualMissionItemTest::cleanup(); } void SimpleMissionItemTest::_testEditorFacts(void) @@ -140,7 +159,7 @@ void SimpleMissionItemTest::_testEditorFacts(void) } } - qDebug() << fact->name(); + qDebug() << "textFieldFact" << fact->name(); QVERIFY(found); } QCOMPARE(factCount, expected->cFactValues); @@ -163,131 +182,82 @@ void SimpleMissionItemTest::_testDefaultValues(void) void SimpleMissionItemTest::_testSignals(void) { - enum { - commandChangedIndex = 0, - frameChangedIndex, - friendlyEditAllowedChangedIndex, - headingDegreesChangedIndex, - rawEditChangedIndex, - coordinateChangedIndex, - exitCoordinateChangedIndex, - dirtyChangedIndex, - maxSignalIndex - }; - - enum { - commandChangedMask = 1 << commandChangedIndex, - frameChangedMask = 1 << frameChangedIndex, - friendlyEditAllowedChangedMask = 1 << friendlyEditAllowedChangedIndex, - headingDegreesChangedMask = 1 << headingDegreesChangedIndex, - rawEditChangedMask = 1 << rawEditChangedIndex, - coordinateChangedMask = 1 << coordinateChangedIndex, - exitCoordinateChangedMask = 1 << exitCoordinateChangedIndex, - dirtyChangedMask = 1 << dirtyChangedIndex, - }; - - static const size_t cSimpleMissionItemSignals = maxSignalIndex; - const char* rgSimpleMissionItemSignals[cSimpleMissionItemSignals]; - - rgSimpleMissionItemSignals[commandChangedIndex] = SIGNAL(commandChanged(int)); - rgSimpleMissionItemSignals[coordinateChangedIndex] = SIGNAL(coordinateChanged(const QGeoCoordinate&)); - rgSimpleMissionItemSignals[exitCoordinateChangedIndex] = SIGNAL(exitCoordinateChanged(const QGeoCoordinate&)); - rgSimpleMissionItemSignals[dirtyChangedIndex] = SIGNAL(dirtyChanged(bool)); - rgSimpleMissionItemSignals[frameChangedIndex] = SIGNAL(frameChanged(int)); - rgSimpleMissionItemSignals[friendlyEditAllowedChangedIndex] = SIGNAL(friendlyEditAllowedChanged(bool)); - rgSimpleMissionItemSignals[headingDegreesChangedIndex] = SIGNAL(headingDegreesChanged(double)); - rgSimpleMissionItemSignals[rawEditChangedIndex] = SIGNAL(rawEditChanged(bool)); + MissionItem& missionItem = _simpleItem->missionItem(); - MissionItem missionItem(1, // sequence number - MAV_CMD_NAV_WAYPOINT, - MAV_FRAME_GLOBAL_RELATIVE_ALT, - 10.1234567, // param 1-7 - 20.1234567, - 30.1234567, - 40.1234567, - 50.1234567, - 60.1234567, - 70.1234567, - true, // autoContinue - false); // isCurrentItem - SimpleMissionItem simpleMissionItem(_offlineVehicle, missionItem); - - // It's important top check that the right signals are emitted at the right time since that drives ui change. - // It's also important to check that things are not being over-signalled when they should not be, since that can lead - // to incorrect ui or perf impact of uneeded signals propogating ui change. - - MultiSignalSpy* multiSpy = new MultiSignalSpy(); - Q_CHECK_PTR(multiSpy); - QCOMPARE(multiSpy->init(&simpleMissionItem, rgSimpleMissionItemSignals, cSimpleMissionItemSignals), true); - - // Check commandChanged signalling. Call setCommand should trigger: - // commandChanged - // dirtyChanged - // coordinateChanged - since altitude will be set back to default - - simpleMissionItem.setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_WAYPOINT); - QVERIFY(multiSpy->checkNoSignals()); - simpleMissionItem.setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_LOITER_TIME); - QVERIFY(multiSpy->checkSignalsByMask(commandChangedMask | dirtyChangedMask | coordinateChangedMask)); - multiSpy->clearAllSignals(); + // Check that changing to the same coordinate does not signal + _simpleItem->setCoordinate(QGeoCoordinate(missionItem.param5(), missionItem.param6(), missionItem.param7())); + QVERIFY(_spyVisualItem->checkNoSignals()); + QVERIFY(_spySimpleItem->checkNoSignals()); // Check coordinateChanged signalling. Calling setCoordinate should trigger: // coordinateChanged // dirtyChanged - // Check that changing to the same coordinate does not signal - simpleMissionItem.setCoordinate(QGeoCoordinate(50.1234567, 60.1234567, qgcApp()->toolbox()->settingsManager()->appSettings()->defaultMissionItemAltitude()->rawValue().toDouble())); - QVERIFY(multiSpy->checkNoSignals()); - // Check that actually changing coordinate signals correctly - simpleMissionItem.setCoordinate(QGeoCoordinate(50.1234567, 60.1234567, 70.1234567)); - QVERIFY(multiSpy->checkOnlySignalByMask(coordinateChangedMask | dirtyChangedMask)); - multiSpy->clearAllSignals(); + _simpleItem->setCoordinate(QGeoCoordinate(missionItem.param5() + 1, missionItem.param6(), missionItem.param7())); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(coordinateChangedMask | dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); + _simpleItem->setCoordinate(QGeoCoordinate(missionItem.param5(), missionItem.param6() + 1, missionItem.param7())); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(coordinateChangedMask | dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); + _simpleItem->setCoordinate(QGeoCoordinate(missionItem.param5(), missionItem.param6(), missionItem.param7() + 1)); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(coordinateChangedMask | dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); // Check dirtyChanged signalling - // Reset param 1-5 for testing - simpleMissionItem.missionItem().setParam1(10.1234567); - simpleMissionItem.missionItem().setParam2(20.1234567); - simpleMissionItem.missionItem().setParam3(30.1234567); - simpleMissionItem.missionItem().setParam4(40.1234567); - multiSpy->clearAllSignals(); - - simpleMissionItem.missionItem().setParam1(10.1234567); - QVERIFY(multiSpy->checkNoSignals()); - simpleMissionItem.missionItem().setParam1(20.1234567); - QVERIFY(multiSpy->checkOnlySignalByMask(dirtyChangedMask)); - multiSpy->clearAllSignals(); - - simpleMissionItem.missionItem().setParam2(20.1234567); - QVERIFY(multiSpy->checkNoSignals()); - simpleMissionItem.missionItem().setParam2(30.1234567); - QVERIFY(multiSpy->checkOnlySignalByMask(dirtyChangedMask)); - multiSpy->clearAllSignals(); - - simpleMissionItem.missionItem().setParam3(30.1234567); - QVERIFY(multiSpy->checkNoSignals()); - simpleMissionItem.missionItem().setParam3(40.1234567); - QVERIFY(multiSpy->checkOnlySignalByMask(dirtyChangedMask)); - multiSpy->clearAllSignals(); - - simpleMissionItem.missionItem().setParam4(40.1234567); - QVERIFY(multiSpy->checkNoSignals()); - simpleMissionItem.missionItem().setParam4(50.1234567); - QVERIFY(multiSpy->checkOnlySignalByMask(dirtyChangedMask)); - multiSpy->clearAllSignals(); + missionItem.setParam1(missionItem.param1()); + QVERIFY(_spyVisualItem->checkNoSignals()); + missionItem.setParam2(missionItem.param2()); + QVERIFY(_spyVisualItem->checkNoSignals()); + missionItem.setParam3(missionItem.param3()); + QVERIFY(_spyVisualItem->checkNoSignals()); + missionItem.setParam4(missionItem.param4()); + QVERIFY(_spyVisualItem->checkNoSignals()); + + missionItem.setParam1(missionItem.param1() + 1); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); + missionItem.setParam1(missionItem.param2() + 1); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); + missionItem.setParam1(missionItem.param3() + 1); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); + missionItem.setParam1(missionItem.param4() + 1); + QVERIFY(_spyVisualItem->checkOnlySignalByMask(dirtyChangedMask)); + _spyVisualItem->clearAllSignals(); // Check frameChanged signalling. Calling setFrame should signal: // frameChanged // dirtyChanged // friendlyEditAllowedChanged - this signal is not very smart on when it gets sent - simpleMissionItem.setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_WAYPOINT); - simpleMissionItem.missionItem().setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT); - multiSpy->clearAllSignals(); - simpleMissionItem.missionItem().setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT); - QVERIFY(multiSpy->checkNoSignals()); - simpleMissionItem.missionItem().setFrame(MAV_FRAME_GLOBAL); - QVERIFY(multiSpy->checkOnlySignalByMask(frameChangedMask | dirtyChangedMask | friendlyEditAllowedChangedMask)); - multiSpy->clearAllSignals(); + missionItem.setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT); + QVERIFY(_spyVisualItem->checkNoSignals()); + QVERIFY(_spySimpleItem->checkNoSignals()); + + missionItem.setFrame(MAV_FRAME_GLOBAL); + QVERIFY(_spySimpleItem->checkOnlySignalByMask(frameChangedMask | dirtyChangedMask | friendlyEditAllowedChangedMask)); + _spySimpleItem->clearAllSignals(); + _spyVisualItem->clearAllSignals(); + + // Check commandChanged signalling. Call setCommand should trigger: + // commandChanged + // commandNameChanged + // dirtyChanged + // coordinateChanged - since altitude will be set back to default + + _simpleItem->setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_WAYPOINT); + QVERIFY(_spyVisualItem->checkNoSignals()); + QVERIFY(_spySimpleItem->checkNoSignals()); + + _simpleItem->setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_LOITER_TIME); + QVERIFY(_spySimpleItem->checkSignalsByMask(commandChangedMask)); + QVERIFY(_spyVisualItem->checkSignalsByMask(commandNameChangedMask | dirtyChangedMask | coordinateChangedMask)); +} + +void SimpleMissionItemTest::_testCameraSectionSignals(void) +{ + } diff --git a/src/MissionManager/SimpleMissionItemTest.h b/src/MissionManager/SimpleMissionItemTest.h index 28692fb3a..e28178a6c 100644 --- a/src/MissionManager/SimpleMissionItemTest.h +++ b/src/MissionManager/SimpleMissionItemTest.h @@ -7,18 +7,13 @@ * ****************************************************************************/ +#pragma once -#ifndef SimpleMissionItemTest_H -#define SimpleMissionItemTest_H - -#include "UnitTest.h" -#include "TCPLink.h" -#include "MultiSignalSpy.h" - -#include +#include "VisualMissionItemTest.h" +#include "SimpleMissionItem.h" /// Unit test for SimpleMissionItem -class SimpleMissionItemTest : public UnitTest +class SimpleMissionItemTest : public VisualMissionItemTest { Q_OBJECT @@ -30,10 +25,34 @@ public: private slots: void _testSignals(void); + void _testCameraSectionSignals(void); void _testEditorFacts(void); void _testDefaultValues(void); private: + enum { + commandChangedIndex = 0, + frameChangedIndex, + friendlyEditAllowedChangedIndex, + headingDegreesChangedIndex, + rawEditChangedIndex, + cameraSectionChangedIndex, + speedSectionChangedIndex, + maxSignalIndex, + }; + + enum { + commandChangedMask = 1 << commandChangedIndex, + frameChangedMask = 1 << frameChangedIndex, + friendlyEditAllowedChangedMask = 1 << friendlyEditAllowedChangedIndex, + headingDegreesChangedMask = 1 << headingDegreesChangedIndex, + rawEditChangedMask = 1 << rawEditChangedIndex, + cameraSectionChangedMask = 1 << cameraSectionChangedIndex, + speedSectionChangedMask = 1 << speedSectionChangedIndex + }; + + static const size_t cSimpleItemSignals = maxSignalIndex; + const char* rgSimpleItemSignals[cSimpleItemSignals]; typedef struct { MAV_CMD command; @@ -51,7 +70,9 @@ private: bool relativeAltCheckbox; } ItemExpected_t; - Vehicle* _offlineVehicle; + SimpleMissionItem* _simpleItem; + MultiSignalSpy* _spySimpleItem; + MultiSignalSpy* _spyVisualItem; static const ItemInfo_t _rgItemInfo[]; static const ItemExpected_t _rgItemExpected[]; @@ -64,5 +85,3 @@ private: static const FactValue_t _rgFactValuesConditionDelay[]; static const FactValue_t _rgFactValuesDoJump[]; }; - -#endif diff --git a/src/MissionManager/SpeedSection.cc b/src/MissionManager/SpeedSection.cc index 6ac99b869..5c45c31a7 100644 --- a/src/MissionManager/SpeedSection.cc +++ b/src/MissionManager/SpeedSection.cc @@ -41,7 +41,6 @@ SpeedSection::SpeedSection(Vehicle* vehicle, QObject* parent) _flightSpeedFact.setMetaData(_metaDataMap[_flightSpeedName]); _flightSpeedFact.setRawValue(flightSpeed); - connect(this, &SpeedSection::specifyFlightSpeedChanged, this, &SpeedSection::_setDirtyAndUpdateItemCount); connect(this, &SpeedSection::specifyFlightSpeedChanged, this, &SpeedSection::settingsSpecifiedChanged); connect(&_flightSpeedFact, &Fact::valueChanged, this, &SpeedSection::_setDirty); } @@ -66,12 +65,6 @@ void SpeedSection::_setDirty(void) setDirty(true); } -void SpeedSection::_setDirtyAndUpdateItemCount(void) -{ - setDirty(true); - emit itemCountChanged(itemCount()); -} - void SpeedSection::setDirty(bool dirty) { if (_dirty != dirty) { @@ -85,6 +78,8 @@ void SpeedSection::setSpecifyFlightSpeed(bool specifyFlightSpeed) if (specifyFlightSpeed != _specifyFlightSpeed) { _specifyFlightSpeed = specifyFlightSpeed; emit specifyFlightSpeedChanged(specifyFlightSpeed); + setDirty(true); + emit itemCountChanged(itemCount()); } } @@ -113,7 +108,7 @@ void SpeedSection::appendSectionItems(QList& items, QObject* missi } } -bool SpeedSection::scanForSection(QmlObjectListModel* visualItems, int& scanIndex) +bool SpeedSection::scanForSection(QmlObjectListModel* visualItems, int scanIndex) { if (!_available || scanIndex >= visualItems->count()) { return false; @@ -137,7 +132,6 @@ bool SpeedSection::scanForSection(QmlObjectListModel* visualItems, int& scanInde visualItems->removeAt(scanIndex)->deleteLater(); _flightSpeedFact.setRawValue(missionItem.param2()); setSpecifyFlightSpeed(true); - scanIndex++; return true; } diff --git a/src/MissionManager/SpeedSection.h b/src/MissionManager/SpeedSection.h index dc85b07ab..83069d5c7 100644 --- a/src/MissionManager/SpeedSection.h +++ b/src/MissionManager/SpeedSection.h @@ -32,7 +32,7 @@ public: bool dirty (void) const override { return _dirty; } void setAvailable (bool available) override; void setDirty (bool dirty) override; - bool scanForSection (QmlObjectListModel* visualItems, int& scanIndex) override; + bool scanForSection (QmlObjectListModel* visualItems, int scanIndex) override; void appendSectionItems (QList& items, QObject* missionItemParent, int& seqNum) override; int itemCount (void) const override; bool settingsSpecified (void) const override; @@ -42,13 +42,12 @@ signals: private slots: void _setDirty(void); - void _setDirtyAndUpdateItemCount(void); private: - bool _available; - bool _dirty; - bool _specifyFlightSpeed; - Fact _flightSpeedFact; + bool _available; + bool _dirty; + bool _specifyFlightSpeed; + Fact _flightSpeedFact; static QMap _metaDataMap; diff --git a/src/MissionManager/SpeedSectionTest.cc b/src/MissionManager/SpeedSectionTest.cc new file mode 100644 index 000000000..eeed8ee2e --- /dev/null +++ b/src/MissionManager/SpeedSectionTest.cc @@ -0,0 +1,266 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "SpeedSectionTest.h" + +SpeedSectionTest::SpeedSectionTest(void) + : _spySpeed(NULL) + , _spySection(NULL) + , _speedSection(NULL) +{ + +} + +void SpeedSectionTest::init(void) +{ + SectionTest::init(); + + rgSpeedSignals[specifyFlightSpeedChangedIndex] = SIGNAL(specifyFlightSpeedChanged(bool)); + + _speedSection = _simpleItem->speedSection(); + _createSpy(_speedSection, &_spySpeed); + QVERIFY(_spySpeed); + SectionTest::_createSpy(_speedSection, &_spySection); + QVERIFY(_spySection); +} + +void SpeedSectionTest::cleanup(void) +{ + delete _spySpeed; + delete _spySection; + SectionTest::cleanup(); +} + +void SpeedSectionTest::_createSpy(SpeedSection* speedSection, MultiSignalSpy** speedSpy) +{ + *speedSpy = NULL; + MultiSignalSpy* spy = new MultiSignalSpy(); + QCOMPARE(spy->init(speedSection, rgSpeedSignals, cSpeedSignals), true); + *speedSpy = spy; +} + +void SpeedSectionTest::_testDirty(void) +{ + // Check for dirty not signalled if same value + _speedSection->setSpecifyFlightSpeed(_speedSection->specifyFlightSpeed()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_speedSection->dirty(), false); + _speedSection->flightSpeed()->setRawValue(_speedSection->flightSpeed()->rawValue()); + QVERIFY(_spySection->checkNoSignals()); + QCOMPARE(_speedSection->dirty(), false); + + // Check for no duplicate dirty signalling on change + _speedSection->setSpecifyFlightSpeed(!_speedSection->specifyFlightSpeed()); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_speedSection->dirty(), true); + _spySection->clearAllSignals(); + _speedSection->setSpecifyFlightSpeed(!_speedSection->specifyFlightSpeed()); + QVERIFY(_spySection->checkNoSignalByMask(dirtyChangedMask)); + QCOMPARE(_speedSection->dirty(), true); + _spySection->clearAllSignals(); + + // Check that the dirty bit can be cleared + _speedSection->setDirty(false); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), false); + QCOMPARE(_speedSection->dirty(), false); + _spySection->clearAllSignals(); + + // Check the remaining items that should set dirty bit + _speedSection->flightSpeed()->setRawValue(_speedSection->flightSpeed()->rawValue().toDouble() + 1); + QVERIFY(_spySection->checkSignalByMask(dirtyChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(dirtyChangedIndex), true); + QCOMPARE(_speedSection->dirty(), true); +} + +void SpeedSectionTest::_testSettingsAvailable(void) +{ + // No settings specified to start + QCOMPARE(_speedSection->specifyFlightSpeed(), false); + QCOMPARE(_speedSection->settingsSpecified(), false); + + // Check correct reaction to specifyFlightSpeed on/off + + _speedSection->setSpecifyFlightSpeed(true); + QCOMPARE(_speedSection->specifyFlightSpeed(), true); + QCOMPARE(_speedSection->settingsSpecified(), true); + QVERIFY(_spySpeed->checkSignalByMask(specifyFlightSpeedChangedMask)); + QCOMPARE(_spySpeed->pullBoolFromSignalIndex(specifyFlightSpeedChangedIndex), true); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(settingsSpecifiedChangedIndex), true); + _spySection->clearAllSignals(); + _spySpeed->clearAllSignals(); + + _speedSection->setSpecifyFlightSpeed(false); + QCOMPARE(_speedSection->specifyFlightSpeed(), false); + QCOMPARE(_speedSection->settingsSpecified(), false); + QVERIFY(_spySpeed->checkSignalByMask(specifyFlightSpeedChangedMask)); + QCOMPARE(_spySpeed->pullBoolFromSignalIndex(specifyFlightSpeedChangedIndex), false); + QVERIFY(_spySection->checkSignalByMask(settingsSpecifiedChangedMask)); + QCOMPARE(_spySection->pullBoolFromSignalIndex(settingsSpecifiedChangedIndex), false); + _spySection->clearAllSignals(); + _spySpeed->clearAllSignals(); +} + +void SpeedSectionTest::_checkAvailable(void) +{ + MissionItem missionItem(1, // sequence number + MAV_CMD_NAV_TAKEOFF, + MAV_FRAME_GLOBAL_RELATIVE_ALT, + 10.1234567, // param 1-7 + 20.1234567, + 30.1234567, + 40.1234567, + 50.1234567, + 60.1234567, + 70.1234567, + true, // autoContinue + false); // isCurrentItem + SimpleMissionItem* item = new SimpleMissionItem(_offlineVehicle, missionItem); + QVERIFY(item->speedSection()); + QCOMPARE(item->speedSection()->available(), false); +} + +void SpeedSectionTest::_testItemCount(void) +{ + // No settings specified to start + QCOMPARE(_speedSection->itemCount(), 0); + + _speedSection->setSpecifyFlightSpeed(true); + QCOMPARE(_speedSection->itemCount(), 1); + QVERIFY(_spySection->checkSignalByMask(itemCountChangedMask)); + QCOMPARE(_spySection->pullIntFromSignalIndex(itemCountChangedIndex), 1); + _spySection->clearAllSignals(); + _spySpeed->clearAllSignals(); + + _speedSection->setSpecifyFlightSpeed(false); + QCOMPARE(_speedSection->itemCount(), 0); + QVERIFY(_spySection->checkSignalByMask(itemCountChangedMask)); + QCOMPARE(_spySection->pullIntFromSignalIndex(itemCountChangedIndex), 0); + _spySection->clearAllSignals(); + _spySpeed->clearAllSignals(); +} + +void SpeedSectionTest::_testAppendSectionItems(void) +{ + int seqNum = 0; + QList rgMissionItems; + + // No settings specified to start + QCOMPARE(_speedSection->itemCount(), 0); + + _speedSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 0); + QCOMPARE(seqNum, 0); + rgMissionItems.clear(); + + _speedSection->setSpecifyFlightSpeed(true); + _speedSection->appendSectionItems(rgMissionItems, this, seqNum); + QCOMPARE(rgMissionItems.count(), 1); + QCOMPARE(seqNum, 1); + MissionItem expectedSpeedItem(0, MAV_CMD_DO_CHANGE_SPEED, MAV_FRAME_MISSION, _offlineVehicle->multiRotor() ? 1 : 0, _speedSection->flightSpeed()->rawValue().toDouble(), -1, 0, 0, 0, 0, true, false); + _missionItemsEqual(*rgMissionItems[0], expectedSpeedItem); +} + +void SpeedSectionTest::_testScanForSection(void) +{ + QCOMPARE(_speedSection->available(), true); + + int scanIndex = 0; + QmlObjectListModel visualItems; + + _commonScanTest(_speedSection); + + // Check for a scan success + + double flightSpeed = 10.123456; + MissionItem validSpeedItem(0, MAV_CMD_DO_CHANGE_SPEED, MAV_FRAME_MISSION, _offlineVehicle->multiRotor() ? 1 : 0, flightSpeed, -1, 0, 0, 0, 0, true, false); + SimpleMissionItem simpleItem(_offlineVehicle, validSpeedItem); + MissionItem& simpleMissionItem = simpleItem.missionItem(); + visualItems.append(&simpleItem); + scanIndex = 0; + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), true); + QCOMPARE(visualItems.count(), 0); + QCOMPARE(_speedSection->settingsSpecified(), true); + QCOMPARE(_speedSection->specifyFlightSpeed(), true); + QCOMPARE(_speedSection->flightSpeed()->rawValue().toDouble(), flightSpeed); + _speedSection->setSpecifyFlightSpeed(false); + visualItems.clear(); + scanIndex = 0; + + // Flight speed command but incorrect settings + + simpleMissionItem = validSpeedItem; + simpleMissionItem.setParam1(_offlineVehicle->multiRotor() ? 0 : 1); + visualItems.append(&simpleItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; + + simpleMissionItem = validSpeedItem; + simpleMissionItem.setParam3(50); + visualItems.append(&simpleItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; + + simpleMissionItem = validSpeedItem; + simpleMissionItem.setParam4(1); + visualItems.append(&simpleItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; + + simpleMissionItem = validSpeedItem; + simpleMissionItem.setParam5(1); + visualItems.append(&simpleItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; + + simpleMissionItem = validSpeedItem; + simpleMissionItem.setParam6(1); + visualItems.append(&simpleItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; + + simpleMissionItem = validSpeedItem; + simpleMissionItem.setParam7(1); + visualItems.append(&simpleItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 1); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; + + // Valid item in wrong position + QmlObjectListModel waypointVisualItems; + MissionItem waypointMissionItem(0, MAV_CMD_NAV_WAYPOINT, MAV_FRAME_GLOBAL_RELATIVE_ALT, 0, 0, 0, 0, 0, 0, 0, true, false); + SimpleMissionItem simpleWaypointItem(_offlineVehicle, waypointMissionItem); + simpleMissionItem = validSpeedItem; + visualItems.append(&simpleWaypointItem); + visualItems.append(&simpleMissionItem); + QCOMPARE(_speedSection->scanForSection(&visualItems, scanIndex), false); + QCOMPARE(visualItems.count(), 2); + QCOMPARE(_speedSection->settingsSpecified(), false); + visualItems.clear(); + scanIndex = 0; +} diff --git a/src/MissionManager/SpeedSectionTest.h b/src/MissionManager/SpeedSectionTest.h new file mode 100644 index 000000000..406a86d67 --- /dev/null +++ b/src/MissionManager/SpeedSectionTest.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "SectionTest.h" +#include "SpeedSection.h" + +/// Unit test for CameraSection +class SpeedSectionTest : public SectionTest +{ + Q_OBJECT + +public: + SpeedSectionTest(void); + + void init(void) override; + void cleanup(void) override; + +private slots: + void _testDirty(void); + void _testSettingsAvailable(void); + void _checkAvailable(void); + void _testItemCount(void); + void _testAppendSectionItems(void); + void _testScanForSection(void); + +private: + void _createSpy(SpeedSection* speedSection, MultiSignalSpy** speedSpy); + + enum { + specifyFlightSpeedChangedIndex = 0, + maxSignalIndex, + }; + + enum { + specifyFlightSpeedChangedMask = 1 << specifyFlightSpeedChangedIndex + }; + + static const size_t cSpeedSignals = maxSignalIndex; + const char* rgSpeedSignals[cSpeedSignals]; + + MultiSignalSpy* _spySpeed; + MultiSignalSpy* _spySection; + SpeedSection* _speedSection; +}; diff --git a/src/MissionManager/VisualMissionItemTest.cc b/src/MissionManager/VisualMissionItemTest.cc new file mode 100644 index 000000000..eee77ca30 --- /dev/null +++ b/src/MissionManager/VisualMissionItemTest.cc @@ -0,0 +1,58 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "VisualMissionItemTest.h" +#include "SimpleMissionItem.h" +#include "QGCApplication.h" + +VisualMissionItemTest::VisualMissionItemTest(void) + : _offlineVehicle(NULL) +{ + +} + +void VisualMissionItemTest::init(void) +{ + UnitTest::init(); + _offlineVehicle = new Vehicle(MAV_AUTOPILOT_PX4, + MAV_TYPE_QUADROTOR, + qgcApp()->toolbox()->firmwarePluginManager(), + this); + + rgVisualItemSignals[altDifferenceChangedIndex] = SIGNAL(altDifferenceChanged(double)); + rgVisualItemSignals[altPercentChangedIndex] = SIGNAL(altPercentChanged(double)); + rgVisualItemSignals[azimuthChangedIndex] = SIGNAL(azimuthChanged(double)); + rgVisualItemSignals[commandDescriptionChangedIndex] = SIGNAL(commandDescriptionChanged()); + rgVisualItemSignals[commandNameChangedIndex] = SIGNAL(commandNameChanged()); + rgVisualItemSignals[abbreviationChangedIndex] = SIGNAL(abbreviationChanged()); + rgVisualItemSignals[coordinateChangedIndex] = SIGNAL(coordinateChanged(const QGeoCoordinate&)); + rgVisualItemSignals[exitCoordinateChangedIndex] = SIGNAL(exitCoordinateChanged(const QGeoCoordinate&)); + rgVisualItemSignals[dirtyChangedIndex] = SIGNAL(dirtyChanged(bool)); + rgVisualItemSignals[distanceChangedIndex] = SIGNAL(distanceChanged(double)); + rgVisualItemSignals[isCurrentItemChangedIndex] = SIGNAL(isCurrentItemChanged(bool)); + rgVisualItemSignals[sequenceNumberChangedIndex] = SIGNAL(sequenceNumberChanged(int)); + rgVisualItemSignals[isSimpleItemChangedIndex] = SIGNAL(isSimpleItemChanged(bool)); + rgVisualItemSignals[specifiesCoordinateChangedIndex] = SIGNAL(specifiesCoordinateChanged()); + rgVisualItemSignals[isStandaloneCoordinateChangedIndex] = SIGNAL(isStandaloneCoordinateChanged()); + rgVisualItemSignals[specifiesAltitudeOnlyChangedIndex] = SIGNAL(specifiesAltitudeOnlyChanged()); + rgVisualItemSignals[specifiedFlightSpeedChangedIndex] = SIGNAL(specifiedFlightSpeedChanged()); + rgVisualItemSignals[specifiedGimbalYawChangedIndex] = SIGNAL(specifiedGimbalYawChanged()); + rgVisualItemSignals[lastSequenceNumberChangedIndex] = SIGNAL(lastSequenceNumberChanged(int)); + rgVisualItemSignals[missionGimbalYawChangedIndex] = SIGNAL(missionGimbalYawChanged(double)); + rgVisualItemSignals[missionVehicleYawChangedIndex] = SIGNAL(missionVehicleYawChanged(double)); + rgVisualItemSignals[coordinateHasRelativeAltitudeChangedIndex] = SIGNAL(coordinateHasRelativeAltitudeChanged(bool)); + rgVisualItemSignals[exitCoordinateHasRelativeAltitudeChangedIndex] = SIGNAL(exitCoordinateHasRelativeAltitudeChanged(bool)); + rgVisualItemSignals[exitCoordinateSameAsEntryChangedIndex] = SIGNAL(exitCoordinateSameAsEntryChanged(bool)); +} + +void VisualMissionItemTest::cleanup(void) +{ + delete _offlineVehicle; + UnitTest::cleanup(); +} diff --git a/src/MissionManager/VisualMissionItemTest.h b/src/MissionManager/VisualMissionItemTest.h new file mode 100644 index 000000000..30d4c196a --- /dev/null +++ b/src/MissionManager/VisualMissionItemTest.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "UnitTest.h" +#include "TCPLink.h" +#include "MultiSignalSpy.h" + +#include + +/// Unit test for SimpleMissionItem +class VisualMissionItemTest : public UnitTest +{ + Q_OBJECT + +public: + VisualMissionItemTest(void); + + void init(void) override; + void cleanup(void) override; + +protected: + enum { + altDifferenceChangedIndex = 0, + altPercentChangedIndex, + azimuthChangedIndex, + commandDescriptionChangedIndex, + commandNameChangedIndex, + abbreviationChangedIndex, + coordinateChangedIndex, + exitCoordinateChangedIndex, + dirtyChangedIndex, + distanceChangedIndex, + isCurrentItemChangedIndex, + sequenceNumberChangedIndex, + isSimpleItemChangedIndex, + specifiesCoordinateChangedIndex, + isStandaloneCoordinateChangedIndex, + specifiesAltitudeOnlyChangedIndex, + specifiedFlightSpeedChangedIndex, + specifiedGimbalYawChangedIndex, + lastSequenceNumberChangedIndex, + missionGimbalYawChangedIndex, + missionVehicleYawChangedIndex, + coordinateHasRelativeAltitudeChangedIndex, + exitCoordinateHasRelativeAltitudeChangedIndex, + exitCoordinateSameAsEntryChangedIndex, + maxSignalIndex, + }; + + enum { + altDifferenceChangedMask = 1 << altDifferenceChangedIndex, + altPercentChangedMask = 1 << altPercentChangedIndex, + azimuthChangedMask = 1 << azimuthChangedIndex, + commandDescriptionChangedMask = 1 << commandDescriptionChangedIndex, + commandNameChangedMask = 1 << commandNameChangedIndex, + abbreviationChangedMask = 1 << abbreviationChangedIndex, + coordinateChangedMask = 1 << coordinateChangedIndex, + exitCoordinateChangedMask = 1 << exitCoordinateChangedIndex, + dirtyChangedMask = 1 << dirtyChangedIndex, + distanceChangedMask = 1 << distanceChangedIndex, + isCurrentItemChangedMask = 1 << isCurrentItemChangedIndex, + sequenceNumberChangedMask = 1 << sequenceNumberChangedIndex, + isSimpleItemChangedMask = 1 << isSimpleItemChangedIndex, + specifiesCoordinateChangedMask = 1 << specifiesCoordinateChangedIndex, + isStandaloneCoordinateChangedMask = 1 << isStandaloneCoordinateChangedIndex, + specifiesAltitudeOnlyChangedMask = 1 << specifiesAltitudeOnlyChangedIndex, + specifiedFlightSpeedChangedMask = 1 << specifiedFlightSpeedChangedIndex, + specifiedGimbalYawChangedMask = 1 << specifiedGimbalYawChangedIndex, + lastSequenceNumberChangedMask = 1 << lastSequenceNumberChangedIndex, + missionGimbalYawChangedMask = 1 << missionGimbalYawChangedIndex, + missionVehicleYawChangedMask = 1 << missionVehicleYawChangedIndex, + coordinateHasRelativeAltitudeChangedMask = 1 << coordinateHasRelativeAltitudeChangedIndex, + exitCoordinateHasRelativeAltitudeChangedMask = 1 << exitCoordinateHasRelativeAltitudeChangedIndex, + exitCoordinateSameAsEntryChangedMask = 1 << exitCoordinateSameAsEntryChangedIndex, + }; + + static const size_t cVisualItemSignals = maxSignalIndex; + const char* rgVisualItemSignals[cVisualItemSignals]; + + Vehicle* _offlineVehicle; +}; diff --git a/src/qgcunittest/UnitTestList.cc b/src/qgcunittest/UnitTestList.cc index dd108fefe..d529c9aca 100644 --- a/src/qgcunittest/UnitTestList.cc +++ b/src/qgcunittest/UnitTestList.cc @@ -32,6 +32,9 @@ #include "MissionCommandTreeTest.h" #include "LogDownloadTest.h" #include "SendMavCommandTest.h" +#include "VisualMissionItemTest.h" +#include "CameraSectionTest.h" +#include "SpeedSectionTest.h" UT_REGISTER_TEST(FactSystemTestGeneric) UT_REGISTER_TEST(FactSystemTestPX4) @@ -51,6 +54,8 @@ UT_REGISTER_TEST(MissionCommandTreeTest) UT_REGISTER_TEST(LogDownloadTest) UT_REGISTER_TEST(SendMavCommandTest) UT_REGISTER_TEST(SurveyMissionItemTest) +UT_REGISTER_TEST(CameraSectionTest) +UT_REGISTER_TEST(SpeedSectionTest) // List of unit test which are currently disabled. // If disabling a new test, include reason in comment. -- 2.22.0