From 8fbd5d407377aa69858795f6431c61883303e07d Mon Sep 17 00:00:00 2001 From: h2zero Date: Wed, 18 May 2022 12:12:47 -0600 Subject: [PATCH] Fix false positive device detection / enhance testing. Some device checks were not being performed when multiple cases were specified, this is now corrected. * Enhanced the fail testing to ensure device data that should not be detected does not return a positive result. --- src/decoder.cpp | 43 +++++++++++++++++--------------- tests/BLE_fail/test_ble_fail.cpp | 42 ++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/decoder.cpp b/src/decoder.cpp index 8ec947d5..58da6f0a 100644 --- a/src/decoder.cpp +++ b/src/decoder.cpp @@ -181,9 +181,11 @@ bool TheengsDecoder::checkDeviceMatch(const JsonArray& condition, if (svc_data != nullptr && strstr(cond_str, SVC_DATA) != nullptr) { len_idx = data_length_is_valid(strlen(svc_data), m_minSvcDataLen, condition, i); if (len_idx >= 0) { - i += len_idx; + if (len_idx > 0) { + i += len_idx; + match = true; + } cmp_str = svc_data; - match = true; } else { match = false; break; @@ -191,9 +193,11 @@ bool TheengsDecoder::checkDeviceMatch(const JsonArray& condition, } else if (mfg_data != nullptr && strstr(cond_str, MFG_DATA) != nullptr) { len_idx = data_length_is_valid(strlen(mfg_data), m_minMfgDataLen, condition, i); if (len_idx >= 0) { - i += len_idx; + if (len_idx > 0) { + i += len_idx; + match = true; + } cmp_str = mfg_data; - match = true; } else { match = false; break; @@ -206,22 +210,22 @@ bool TheengsDecoder::checkDeviceMatch(const JsonArray& condition, break; } - cond_str = condition[i + 1].as(); - if (cond_str) { + cond_str = condition[++i].as(); + if (cond_str != nullptr && *cond_str != '&' && *cond_str != '|') { if (cmp_str == svc_uuid && !strncmp(cmp_str, "0x", 2)) { cmp_str += 2; } if (strstr(cond_str, "contain") != nullptr) { - if (strstr(cmp_str, condition[i + 2].as()) != nullptr) { + if (strstr(cmp_str, condition[++i].as()) != nullptr) { match = true; } else { match = false; } - i += 3; + i++; } else if (strstr(cond_str, "index") != nullptr) { - size_t cond_index = condition[i + 2].as(); - size_t cond_len = strlen(condition[i + 3].as()); + size_t cond_index = condition[++i].as(); + size_t cond_len = strlen(condition[++i].as()); if (!data_index_is_valid(cmp_str, cond_index, cond_len)) { DEBUG_PRINT("Invalid data %s; skipping\n", cmp_str); @@ -230,31 +234,30 @@ bool TheengsDecoder::checkDeviceMatch(const JsonArray& condition, } bool inverse = false; - if (*condition[i + 3].as() == '!') { + if (*condition[i].as() == '!') { inverse = true; + i++; } - DEBUG_PRINT("comparing value: %s to %s at index %u\n", + DEBUG_PRINT("comparing value: %s to %s at index %lu\n", &cmp_str[cond_index], - condition[i + 3 + inverse].as(), - condition[i + 2].as()); + condition[i].as(), + cond_index); if (strncmp(&cmp_str[cond_index], - condition[i + 3 + inverse].as(), + condition[i].as(), cond_len) == 0) { match = inverse ? false : true; } else { match = inverse ? true : false; } - i += 4 + inverse; + i++; } cond_str = condition[i].as(); } - size_t cond_size = condition.size(); - if (i < cond_size && cond_str != nullptr) { if (!match && *cond_str == '|') { i++; @@ -268,7 +271,7 @@ bool TheengsDecoder::checkDeviceMatch(const JsonArray& condition, if (!condition[++i].is()) { continue; } - cond_str = condition[++i].as(); + cond_str = condition[i].as(); } if (i < cond_size && cond_str != nullptr) { @@ -490,7 +493,7 @@ int TheengsDecoder::decodeBLEJson(JsonObject& jsondata) { } } - /* If there is any underscores at the beginning of the property name, there is multiple + /* If there is any underscores at the beginning of the property name, there is multiple * properties of this type, we need remove the underscores for creating the key. */ std::string _key = sanitizeJsonKey(kv.key().c_str()); diff --git a/tests/BLE_fail/test_ble_fail.cpp b/tests/BLE_fail/test_ble_fail.cpp index fa5cf223..9c52ee57 100644 --- a/tests/BLE_fail/test_ble_fail.cpp +++ b/tests/BLE_fail/test_ble_fail.cpp @@ -72,25 +72,27 @@ TheengsDecoder::BLE_ID_NUM test_svcdata_id_num[]{ // manufacturer data test input [test name] [device name] [data] const char* test_mfgdata[][3] = { {"Inkbird TH1", "sps", "660a03150110805908"}, - {"SHOULD FAIL", "fail", "270201508094c014"} + {"SHOULD FAIL", "fail", "270201508094c014"}, + {"SHOULD FAIL", "fail_tpms", "000180eaca10ca8ff46503007c0c00003300"}, }; TheengsDecoder::BLE_ID_NUM test_mfgdata_id_num[]{ TheengsDecoder::BLE_ID_NUM::IBSTH1, TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL, + TheengsDecoder::BLE_ID_NUM::TPMS, }; // uuid test input [test name] [uuid] [data source] [data] const char* test_uuid[][4] = { {"MiBand", "fee0", "servicedata", "a21e0000"}, {"SHOULD FAIL", "fa11", "servicedata", "123456789ABCDEF"}, - {"SHOULD FAIL", "0x181d", "servicedata", "a2a22bb2070103003526"} + {"SHOULD FAIL", "0x181d", "servicedata", "f2a22bb2070103003526"} }; TheengsDecoder::BLE_ID_NUM test_uuid_id_num[]{ TheengsDecoder::BLE_ID_NUM::MIBAND, TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL, - TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL, + TheengsDecoder::BLE_ID_NUM::XMTZC04HM, }; int main() { StaticJsonDocument<2048> doc; @@ -105,6 +107,13 @@ int main() { bleObject = doc.as(); decode_res = decoder.decodeBLEJson(bleObject); + if (strcmp(test_servicedata[i][0], "SHOULD FAIL") == 0 && + decode_res != TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL) { + std::cout << "Decode result returned model ID: " << bleObject["model_id"] << " UNKNOWN_MODEL expected " + << test_servicedata[i][0] << " : " << test_servicedata[i][1] << std::endl; + return 1; + } + if (decode_res == test_svcdata_id_num[i]) { std::cout << "Found : "; bleObject.remove("servicedata"); @@ -113,7 +122,8 @@ int main() { } else if (strcmp(test_servicedata[i][0], "SHOULD FAIL") == 0) { continue; } else { - std::cout << "FAILED! Error parsing: " << test_servicedata[i][0] << " : " << test_servicedata[i][1] << std::endl; + std::cout << "FAILED! Error parsing: " << test_servicedata[i][0] + << " : " << test_servicedata[i][1] << std::endl; return 1; } } @@ -126,6 +136,13 @@ int main() { bleObject = doc.as(); decode_res = decoder.decodeBLEJson(bleObject); + if (strcmp(test_mfgdata[i][0], "SHOULD FAIL") == 0 && + decode_res != TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL) { + std::cout << "Decode result returned model ID: " << bleObject["model_id"] << " UNKNOWN_MODEL expected " + << test_mfgdata[i][0] << " : " << test_mfgdata[i][1] << " : " + << test_mfgdata[i][2] << std::endl; + return 1; + } if (decode_res == test_mfgdata_id_num[i]) { std::cout << "Found : "; bleObject.remove("name"); @@ -135,7 +152,9 @@ int main() { } else if (strcmp(test_mfgdata[i][0], "SHOULD FAIL") == 0) { continue; } else { - std::cout << "FAILED! Error parsing: " << test_mfgdata[i][0] << " : " << test_mfgdata[i][1] << " : " << test_mfgdata[i][2] << std::endl; + std::cout << "FAILED! Error parsing: " + << test_mfgdata[i][0] << " : " << test_mfgdata[i][1] << " : " + << test_mfgdata[i][2] << std::endl; return 1; } } @@ -148,6 +167,15 @@ int main() { bleObject = doc.as(); decode_res = decoder.decodeBLEJson(bleObject); + if (strcmp(test_uuid[i][0], "SHOULD FAIL") == 0 && + decode_res != TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL) { + std::cout << "Decode result returned model ID: " << bleObject["model_id"] << " UNKNOWN_MODEL expected " + << test_uuid[i][0] << " : " + << test_uuid[i][1] << " : " << test_uuid[i][2] << " : " + << test_uuid[i][3] << std::endl; + return 1; + } + if (decode_res == test_uuid_id_num[i]) { std::cout << "Found : "; bleObject.remove("servicedatauuid"); @@ -157,7 +185,9 @@ int main() { } else if (strcmp(test_uuid[i][0], "SHOULD FAIL") == 0) { continue; } else { - std::cout << "FAILED! Error parsing: " << test_uuid[i][0] << " : " << test_uuid[i][1] << " : " << test_uuid[i][2] << " : " << test_uuid[i][3] << std::endl; + std::cout << "FAILED! Error parsing: " << test_uuid[i][0] << " : " + << test_uuid[i][1] << " : " << test_uuid[i][2] << " : " + << test_uuid[i][3] << std::endl; serializeJson(doc, std::cout); std::cout << std::endl; return 1;