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);
+}