diff --git a/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj b/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj index ac36112b..b1032bd2 100644 --- a/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj +++ b/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj @@ -67,6 +67,7 @@ + diff --git a/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj.filters b/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj.filters index 08436664..24b83c08 100644 --- a/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj.filters +++ b/VisualStudio/FiftyOne.DeviceDetection.Hash.Tests/FiftyOne.DeviceDetection.Hash.Tests.vcxproj.filters @@ -61,6 +61,7 @@ Source Files + Source Files diff --git a/src/common-cxx b/src/common-cxx index f6d1aa94..a7d32f59 160000 --- a/src/common-cxx +++ b/src/common-cxx @@ -1 +1 @@ -Subproject commit f6d1aa94618b40f532445e0e4f8653bfbef28456 +Subproject commit a7d32f59b096212768a0d3a877bf380f99f87e26 diff --git a/src/hash/EngineHash.cpp b/src/hash/EngineHash.cpp index 3375e672..61606afe 100644 --- a/src/hash/EngineHash.cpp +++ b/src/hash/EngineHash.cpp @@ -74,6 +74,7 @@ EngineHash::EngineHash( (size_t)length, exception); if (status != SUCCESS) { + Free(dataCopy); throw StatusCodeException(status); } EXCEPTION_THROW; diff --git a/src/hash/hash.c b/src/hash/hash.c index 317f9983..18549d96 100644 --- a/src/hash/hash.c +++ b/src/hash/hash.c @@ -100,7 +100,7 @@ dataSet->t = CollectionCreateFromMemory( \ reader, \ dataSet->header.t); \ if (dataSet->t == NULL) { \ - return INVALID_COLLECTION_CONFIG; \ + return CORRUPT_DATA; \ } #define COLLECTION_CREATE_FILE(t,f) \ @@ -111,7 +111,7 @@ dataSet->t = CollectionCreateFromFile( \ dataSet->header.t, \ f); \ if (dataSet->t == NULL) { \ - return INVALID_COLLECTION_CONFIG; \ + return CORRUPT_DATA; \ } /** diff --git a/test/hash/EngineHashInitTests.cpp b/test/hash/EngineHashInitTests.cpp new file mode 100644 index 00000000..21815698 --- /dev/null +++ b/test/hash/EngineHashInitTests.cpp @@ -0,0 +1,312 @@ +/* ********************************************************************* + * This Original Work is copyright of 51 Degrees Mobile Experts Limited. + * Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close, + * Caversham, Reading, Berkshire, United Kingdom RG4 7BY. + * + * This Original Work is licensed under the European Union Public Licence (EUPL) + * v.1.2 and is subject to its terms as set out below. + * + * If a copy of the EUPL was not distributed with this file, You can obtain + * one at https://opensource.org/licenses/EUPL-1.2. + * + * The 'Compatible Licences' set out in the Appendix to the EUPL (as may be + * amended by the European Commission) shall be deemed incompatible for + * the purposes of the Work and the provisions of the compatibility + * clause in Article 5 of the EUPL shall not apply. + * + * If using the Work as, or as part of, a network application, by + * including the attribution notice(s) required under Article 5 of the EUPL + * in the end user terms of the application under an appropriate heading, + * such notice(s) shall fulfill the requirements of that article. + * ********************************************************************* */ + +#include "../Constants.hpp" +#include "../EngineDeviceDetectionTests.hpp" +#include "../../src/hash/EngineHash.hpp" +#include +#include + +using namespace FiftyoneDegrees::Common; +using namespace FiftyoneDegrees::DeviceDetection; +using namespace FiftyoneDegrees::DeviceDetection::Hash; + +class EngineHashInitTests : public Base { +public: + const char* badVersionFileName = "badVersion.hash"; + const char* badDataFileName = "badData.hash"; + const char* smallDataFileName = "smallData.hash"; + const int32_t badVersion[4] = { 1, 2, 3, 4 }; + const int32_t goodVersion[4] = { 4, 1, 0, 0 }; + virtual void SetUp() { + Base::SetUp(); + writeTestFiles(); + } + virtual void TearDown() { + removeTestFiles(); + Base::TearDown(); + } + + /** + * Check that when initializing from a file which has the wrong version, + * the correct error is thrown, and memory is cleaned up. + */ + void wrongDataVersionFile(ConfigHash* config) { + RequiredPropertiesConfig properties; + try { + EngineHash* engine = new EngineHash(badVersionFileName, config, &properties); + FAIL() << L"No exception was thrown"; + } + catch (exception & e) { + const char* expected = fiftyoneDegreesStatusGetMessage( + FIFTYONE_DEGREES_STATUS_INCORRECT_VERSION, + NULL); + ASSERT_STREQ( + e.what(), + expected); + fiftyoneDegreesFree((void*)expected); + + } + } + + /** + * Check that when initializing from a file which has the correct version + * but corrupted data, the correct error is thrown, and memory is cleaned up. + */ + void badDataFile(ConfigHash* config) { + RequiredPropertiesConfig properties; + try { + EngineHash* engine = new EngineHash(badDataFileName, config, &properties); + FAIL() << L"No exception was thrown"; + } + catch (exception & e) { + const char* expected = fiftyoneDegreesStatusGetMessage( + FIFTYONE_DEGREES_STATUS_CORRUPT_DATA, + NULL); + ASSERT_STREQ( + e.what(), + expected); + fiftyoneDegreesFree((void*)expected); + } + } + + /** + * Check that when initializing from a file which is too small and does not + * contain enough data to fill the header, the correct error is thrown, + * and memory is cleaned up. + */ + void smallDataFile(ConfigHash *config) { + RequiredPropertiesConfig properties; + try { + EngineHash* engine = new EngineHash(smallDataFileName, config, &properties); + FAIL() << L"No exception was thrown"; + } + catch (exception & e) { + const char* expected = fiftyoneDegreesStatusGetMessage( + FIFTYONE_DEGREES_STATUS_CORRUPT_DATA, + NULL); + ASSERT_STREQ( + e.what(), + expected); + fiftyoneDegreesFree((void*)expected); + + } + } + +private: + void writeTestFiles() { + void* garbledHeader = + malloc(sizeof(fiftyoneDegreesDataSetHashHeader)); + for (int i = 0; i < sizeof(fiftyoneDegreesDataSetHashHeader); i++) { + ((byte*)garbledHeader)[i] = 12; + } + + ofstream badVersionFile(badVersionFileName, ios::out | ios::binary); + if (badVersionFile.is_open()) { + badVersionFile.write((char*)badVersion, sizeof(int32_t) * 4); + badVersionFile.write((char*)garbledHeader, sizeof(fiftyoneDegreesDataSetHashHeader)); + badVersionFile.close(); + } + else { + cout << "Unable to open file"; + } + + ofstream badDataFile(badDataFileName, ios::out | ios::binary); + if (badDataFile.is_open()) { + badDataFile.write((char*)goodVersion, sizeof(int32_t) * 4); + badDataFile.write((char*)garbledHeader, sizeof(fiftyoneDegreesDataSetHashHeader)); + badDataFile.close(); + } + else { + cout << "Unable to open file"; + } + + ofstream smallDataFile(smallDataFileName, ios::out | ios::binary); + if (smallDataFile.is_open()) { + smallDataFile.write((char*)garbledHeader, sizeof(byte)); + smallDataFile.close(); + } + else { + cout << "Unable to open file"; + } + free(garbledHeader); + } + void removeTestFiles() { + if (remove(badVersionFileName) != 0) { + cout << "Error deleting file"; + } + if (remove(badDataFileName) != 0) { + cout << "Error deleting file"; + } + if (remove(smallDataFileName) != 0) { + cout << "Error deleting file"; + } + } +}; + +#define TEST_WRONG_VERSION_FILE(c) \ +TEST_F(EngineHashInitTests,WrongDataVersion_File_##c) { \ + ConfigHash config; \ + config.set##c(); \ + wrongDataVersionFile(&config); \ +} + +TEST_WRONG_VERSION_FILE(HighPerformance); +TEST_WRONG_VERSION_FILE(LowMemory); +TEST_WRONG_VERSION_FILE(Balanced); +TEST_WRONG_VERSION_FILE(BalancedTemp); + +#define TEST_BAD_DATA_FILE(c) \ +TEST_F(EngineHashInitTests,BadData_File_##c) { \ + ConfigHash config; \ + config.set##c(); \ + badDataFile(&config); \ +} + +TEST_BAD_DATA_FILE(HighPerformance); +TEST_BAD_DATA_FILE(LowMemory); +TEST_BAD_DATA_FILE(Balanced); +TEST_BAD_DATA_FILE(BalancedTemp); + +#define TEST_SMALL_DATA_FILE(c) \ +TEST_F(EngineHashInitTests,SmallData_File_##c) { \ + ConfigHash config; \ + config.set##c(); \ + smallDataFile(&config); \ +} + +TEST_SMALL_DATA_FILE(HighPerformance); +TEST_SMALL_DATA_FILE(LowMemory); +TEST_SMALL_DATA_FILE(Balanced); +TEST_SMALL_DATA_FILE(BalancedTemp); + +/** + * Check that when initializing from memory which has the wrong version, + * the correct error is thrown, and memory is cleaned up. + */ +TEST_F(EngineHashInitTests, WrongDataVersion_Memory) { + ConfigHash config; + RequiredPropertiesConfig properties; + void* mem = fiftyoneDegreesMalloc(sizeof(fiftyoneDegreesDataSetHashHeader)); + ifstream file(badVersionFileName, ios::out | ios::binary); + if (file.is_open()) { + file.read((char*)mem, sizeof(fiftyoneDegreesDataSetHashHeader)); + file.close(); + } + else { + cout << "Unable to open file"; + } + + try { + EngineHash* engine = new EngineHash( + mem, + (long)sizeof(fiftyoneDegreesDataSetHashHeader), + &config, + &properties); + FAIL() << L"No exception was thrown"; + } + catch (exception & e) { + const char* expected = fiftyoneDegreesStatusGetMessage( + FIFTYONE_DEGREES_STATUS_INCORRECT_VERSION, + NULL); + ASSERT_STREQ( + e.what(), + expected); + fiftyoneDegreesFree((void*)expected); + } + fiftyoneDegreesFree(mem); +} + +/** + * Check that when initializing from memory which has the correct version + * but corrupted data, the correct error is thrown, and memory is cleaned up. + */ +TEST_F(EngineHashInitTests, BadData_Memory) { + ConfigHash config; + RequiredPropertiesConfig properties; + void* mem = fiftyoneDegreesMalloc(sizeof(fiftyoneDegreesDataSetHashHeader)); + ifstream file(badDataFileName, ios::out | ios::binary); + if (file.is_open()) { + file.read((char*)mem, sizeof(fiftyoneDegreesDataSetHashHeader)); + file.close(); + } + else { + cout << "Unable to open file"; + } + + try { + EngineHash* engine = new EngineHash( + mem, + (long)sizeof(fiftyoneDegreesDataSetHashHeader), + &config, + &properties); + FAIL() << L"No exception was thrown"; + } + catch (exception & e) { + const char* expected = fiftyoneDegreesStatusGetMessage( + FIFTYONE_DEGREES_STATUS_CORRUPT_DATA, + NULL); + ASSERT_STREQ( + e.what(), + expected); + fiftyoneDegreesFree((void*)expected); + } + fiftyoneDegreesFree(mem); +} + +/** + * Check that when initializing from memory which is too small and does not + * contain enough data to fill the header, the correct error is thrown, + * and memory is cleaned up. + */ +TEST_F(EngineHashInitTests, SmallData_Memory) { + ConfigHash config; + RequiredPropertiesConfig properties; + void* mem = fiftyoneDegreesMalloc(sizeof(fiftyoneDegreesDataSetHashHeader)); + ifstream file(smallDataFileName, ios::out | ios::binary); + if (file.is_open()) { + file.read((char*)mem, sizeof(fiftyoneDegreesDataSetHashHeader)); + file.close(); + } + else { + cout << "Unable to open file"; + } + + try { + EngineHash* engine = new EngineHash( + mem, + (long)sizeof(byte), + &config, + &properties); + FAIL() << L"No exception was thrown"; + } + catch (exception & e) { + const char* expected = fiftyoneDegreesStatusGetMessage( + FIFTYONE_DEGREES_STATUS_CORRUPT_DATA, + NULL); + ASSERT_STREQ( + e.what(), + expected); + fiftyoneDegreesFree((void*)expected); + } + fiftyoneDegreesFree(mem); +}