< Summary - Backend C Tests - Coverage Report

Information
Class: alert_service_c
Assembly: src.backend.database
File(s): C:\Users\yagiz\Desktop\Project\smart-maintenance-suite\src\backend\database\alert_service.c
Line coverage
73%
Covered lines: 73
Uncovered lines: 27
Coverable lines: 100
Total lines: 217
Line coverage: 73%
Branch coverage
72%
Covered branches: 29
Total branches: 40
Branch coverage: 72.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
severity_to_str50%0060%
create_alert100%0088.89%
check_and_trigger_alerts100%0089.47%
get_recent_alerts50%0060.61%
alert_service_serialize_alerts50%0070%

File(s)

C:\Users\yagiz\Desktop\Project\smart-maintenance-suite\src\backend\database\alert_service.c

#LineLine coverage
 1#include "alert_service.h"
 2#include "db_connection.h"
 3#include "logger.h"
 4#include <stdio.h>
 5#include <string.h>
 6#include <stdlib.h>
 7
 8/* ------------------------------------------------------------------
 9 * PRIVATE HELPERS
 10 * ------------------------------------------------------------------ */
 11
 1112const char *severity_to_str(AlertSeverity severity) {
 1113  switch (severity) {
 014    case SEVERITY_INFO:
 015      return "INFO";
 16
 717    case SEVERITY_WARNING:
 718      return "WARNING";
 19
 420    case SEVERITY_CRITICAL:
 421      return "CRITICAL";
 22
 023    default:
 024      return "UNKNOWN";
 25  }
 26}
 27
 28/* ------------------------------------------------------------------
 29 * PUBLIC API
 30 * ------------------------------------------------------------------ */
 31#ifndef TEST_MODE
 32
 733bool create_alert(int sensor_id, AlertSeverity severity, const char *message) {
 734  DBConnection *conn_wrapper = db_pool_acquire();
 35
 736  if (!conn_wrapper) {
 137    LOG_ERROR("Could not acquire connection to create alert.");
 138    return false;
 39  }
 40
 41  char query[1024];
 642  snprintf(query, sizeof(query),
 43           "INSERT INTO alerts (sensor_id, severity, message) VALUES (%d, '%s', '%s');",
 44           sensor_id, severity_to_str(severity), message);
 645  PGresult *res = PQexec(conn_wrapper->pg_conn, query);
 46
 647  if (PQresultStatus(res) != PGRES_COMMAND_OK) {
 148    LOG_ERROR("Failed to insert alert: %s", PQerrorMessage(conn_wrapper->pg_conn));
 149    PQclear(res);
 150    db_pool_release(conn_wrapper);
 151    return false;
 52  }
 53
 554  PQclear(res);
 555  db_pool_release(conn_wrapper);
 556  LOG_INFO("[ALERT CREATED] Sensor %d: %s (%s)", sensor_id, message, severity_to_str(severity));
 557  return true;
 58}
 59
 60/* ------------------------------------------------------------------ */
 61
 862void check_and_trigger_alerts(int sensor_id, const char *sensor_type, double value) {
 863  if (strcmp(sensor_type, "Temperature") == 0) {
 364    if (value > 90.0) {
 65      char msg[128];
 166      snprintf(msg, sizeof(msg), "Critical Temperature detected: %.2f C", value);
 167      create_alert(sensor_id, SEVERITY_CRITICAL, msg);
 268    } else if (value > 75.0) {
 69      char msg[128];
 170      snprintf(msg, sizeof(msg), "High Temperature warning: %.2f C", value);
 171      create_alert(sensor_id, SEVERITY_WARNING, msg);
 72    }
 573  } else if (strcmp(sensor_type, "Vibration") == 0) {
 274    if (value > 5.0) {
 75      char msg[128];
 176      snprintf(msg, sizeof(msg), "Excessive Vibration detected: %.2f Hz", value);
 177      create_alert(sensor_id, SEVERITY_CRITICAL, msg);
 78    }
 379  } else if (strcmp(sensor_type, "Pressure") == 0) {
 280    if (value > 12.0) {
 81      char msg[128];
 182      snprintf(msg, sizeof(msg), "High Pressure detected: %.2f Bar", value);
 183      create_alert(sensor_id, SEVERITY_WARNING, msg);
 84    }
 85  }
 886}
 87
 88/* ------------------------------------------------------------------ */
 89
 390int get_recent_alerts(AlertInfo *out_alerts, int max_alerts) {
 391  DBConnection *conn_wrapper = db_pool_acquire();
 92
 393  if (!conn_wrapper) return 0;
 94
 95  char query[256];
 296  snprintf(query, sizeof(query),
 97           "SELECT id, sensor_id, severity, message, to_char(alert_time, 'YYYY-MM-DD HH24:MI:SS') "
 98           "FROM alerts ORDER BY alert_time DESC LIMIT %d;",
 99           max_alerts);
 2100  PGresult *res = PQexec(conn_wrapper->pg_conn, query);
 101
 2102  if (PQresultStatus(res) != PGRES_TUPLES_OK) {
 0103    LOG_ERROR("Failed to fetch alerts: %s", PQerrorMessage(conn_wrapper->pg_conn));
 0104    PQclear(res);
 0105    db_pool_release(conn_wrapper);
 0106    return 0;
 107  }
 108
 2109  int rows = PQntuples(res);
 2110  int count = (rows < max_alerts) ? rows : max_alerts;
 111
 5112  for (int i = 0; i < count; i++) {
 3113    out_alerts[i].id = atoi(PQgetvalue(res, i, 0));
 3114    out_alerts[i].sensor_id = atoi(PQgetvalue(res, i, 1));
 3115    strncpy(out_alerts[i].severity, PQgetvalue(res, i, 2), 15);
 3116    out_alerts[i].severity[15] = '\0';
 3117    strncpy(out_alerts[i].message, PQgetvalue(res, i, 3), 255);
 3118    out_alerts[i].message[255] = '\0';
 3119    strncpy(out_alerts[i].created_at, PQgetvalue(res, i, 4), 31);
 3120    out_alerts[i].created_at[31] = '\0';
 121  }
 122
 2123  PQclear(res);
 2124  db_pool_release(conn_wrapper);
 2125  return count;
 126}
 127
 128#endif // TEST_MODE
 129
 130/* ------------------------------------------------------------------
 131 * JSON SERIALIZATION (API ENDPOINTS)
 132 * ------------------------------------------------------------------ */
 133
 134#ifndef TEST_MODE
 135
 1136char *alert_service_serialize_alerts(void) {
 137  AlertInfo alerts[50];
 1138  int count = get_recent_alerts(alerts, 50);
 1139  char *json = (char *)malloc(4096);
 140
 1141  if (!json) return NULL;
 142
 1143  char *ptr = json;
 1144  ptr += sprintf(ptr, "{\"alerts\":[");
 145
 2146  for (int i = 0; i < count; i++) {
 1147    if (i > 0) {
 0148      ptr += sprintf(ptr, ",");
 149    }
 150
 1151    ptr += sprintf(ptr,
 152                   "{"
 153                   "\"id\":%d,"
 154                   "\"sensor_id\":%d,"
 155                   "\"severity\":\"%s\","
 156                   "\"message\":\"%s\","
 157                   "\"created_at\":\"%s\""
 158                   "}",
 159                   alerts[i].id,
 160                   alerts[i].sensor_id,
 1161                   alerts[i].severity,
 1162                   alerts[i].message,
 1163                   alerts[i].created_at
 164                  );
 165  }
 166
 1167  ptr += sprintf(ptr, "]}");
 1168  return json;
 169}
 170
 171#endif
 172
 173
 174
 175/* ------------------------------------------------------------------
 176 * TEST/MOCK VERSION (compile with -DTEST_MODE)
 177 * ------------------------------------------------------------------ */
 178
 179#ifdef TEST_MODE
 180
 0181char *alert_service_serialize_alerts(void) {
 0182  char *json = (char *)malloc(256);
 183
 0184  if (json) {
 0185    strcpy(json, "{\"alerts\":[]}");
 186  }
 187
 0188  return json;
 189}
 190
 0191bool create_alert(int sensor_id, AlertSeverity severity, const char *message) {
 192  (void)sensor_id;
 193  (void)severity;
 194  (void)message;
 0195  return true;
 196}
 197
 0198void check_and_trigger_alerts(int sensor_id, const char *sensor_type, double value) {
 199  (void)sensor_id;
 200  (void)sensor_type;
 201  (void)value;
 0202}
 203
 0204int get_recent_alerts(AlertInfo *out_alerts, int max_alerts) {
 0205  if (out_alerts && max_alerts > 0) {
 0206    out_alerts[0].id = 1;
 0207    out_alerts[0].sensor_id = 1;
 0208    strcpy(out_alerts[0].severity, "CRITICAL");
 0209    strcpy(out_alerts[0].message, "Mock critical alert");
 0210    strcpy(out_alerts[0].created_at, "2025-01-01 10:00:00");
 0211    return 1;
 212  }
 213
 0214  return 0;
 215}
 216
 217#endif