From 2476684e3c0798fbc9979d436c4288216400d87c Mon Sep 17 00:00:00 2001
From: Steru <jerrydream111@gmail.com>
Date: Mon, 5 Aug 2024 13:08:44 +0200
Subject: Added guards for a little more stability.

---
 src/discipline/Sport.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++------
 src/discipline/Sport.h   |  2 ++
 2 files changed, 71 insertions(+), 10 deletions(-)

(limited to 'src')

diff --git a/src/discipline/Sport.cpp b/src/discipline/Sport.cpp
index 1ea8019..8d9a5c2 100644
--- a/src/discipline/Sport.cpp
+++ b/src/discipline/Sport.cpp
@@ -9,7 +9,6 @@
 #include <QJsonArray>
 #include <QJsonValueRef>
 #include <QString>
-#include <QTime>
 
 // QJsonArray filter function, provide with input array and evaluation function
 QJsonArray filter(QJsonArray input, function<bool (QJsonObject)> eval) {
@@ -74,28 +73,43 @@ bool compareMedals(const QJsonValue &left, const QJsonValue &right) {
  * @param competitors The competitors of one category.
  */
 void Sport::lastName(QJsonArray &competitors) {
+    // validate competitors
+    if (competitors.isEmpty() || !competitors[0].toObject().contains("name")) return;
+
     for (int i = 0; i < competitors.size(); ++i) {
         string fullName = competitors[i].toObject()["name"].toString().toUtf8().constData();
 
+        // regex to identify names, written in CAPS
         regex r("[A-Z']{2,}");
         smatch m;
 
         regex_search(fullName, m, r);
 
+        // combine found names again
         string lastName = "";
-        for (string s : m) {
-            lastName = lastName + s + " ";
-        }
+        for (string s : m) lastName = lastName + s + " ";
+
+        // remove last space
         QJsonValue nameValue = QJsonValue(QString(lastName.substr(0, lastName.size() - 1).c_str()));
 
+        // create new object with replaced name
         QJsonObject comp(competitors[i].toObject());
         comp.remove("name");
         comp.insert("name", nameValue);
 
-        competitors[i] = comp;
+        // replace competitor in array
+        competitors.replace(i, comp);
     }
 }
 
+/**
+ * @brief Sport::validateDiscipline Validates the discipline object. Checks for the units attribute.
+ * @return True, if discipline contains units.
+ */
+bool Sport::validateDiscipline() {
+    return this->discipline.contains("units");
+}
+
 /**
  * @brief Sport::getCategories Reads all possible categories (also called units).
  * @return A set of all category names.
@@ -103,8 +117,16 @@ void Sport::lastName(QJsonArray &competitors) {
 set<QString> Sport::getCategories() {
     set<QString> categoryNames;
 
-    for (const QJsonValueRef &unit : this->discipline["units"].toArray()) {
-        categoryNames.insert(unit.toObject()["eventUnitName"].toString());
+    if (!validateDiscipline()) return categoryNames;
+
+    // search in each unit for the category (named "eventUnitName")
+    for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) {
+        QJsonObject unit = unitRef.toObject();
+
+        // validate unit
+        if (!unit.contains("eventUnitName")) continue;
+
+        categoryNames.insert(unit["eventUnitName"].toString());
     }
 
     return categoryNames;
@@ -118,15 +140,20 @@ set<QString> Sport::getCategories() {
 QJsonArray Sport::getCompetitorsByCategory(QString category) {
     QJsonArray competitors;
 
+    if (!validateDiscipline()) return competitors;
+
     for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) {
         QJsonObject unit = unitRef.toObject();
 
+        // validate unit
+        if (!unit.contains("eventUnitName") || !unit.contains("competitors")) continue;
+
         // search all units with the same category
         if (unit["eventUnitName"].toString().compare(category, Qt::CaseSensitive) != 0) continue;
 
         // add all competitors from one unit
-        for (const QJsonValueRef &comp : unit["competitors"].toArray()) {
-            competitors.push_back(comp.toObject());
+        for (const QJsonValueRef &compRef : unit["competitors"].toArray()) {
+            competitors.push_back(compRef.toObject());
         }
     }
 
@@ -141,6 +168,8 @@ QJsonArray Sport::getCompetitorsByCategory(QString category) {
 QJsonArray Sport::getCompetitorsWithMedal() {
     map<QString, QJsonObject> competitors;
 
+    if (!validateDiscipline()) return QJsonArray();
+
     // filter all units, which have medal events
     QJsonArray units = filter(this->discipline["units"].toArray(), [](QJsonObject unit){
         // search all units with Final, Gold or Bronze in their name, because these are the categories with the medal winners
@@ -153,6 +182,9 @@ QJsonArray Sport::getCompetitorsWithMedal() {
     for (const QJsonValueRef &unitRef : units) {
         QJsonObject unit = unitRef.toObject();
 
+        // validate unit
+        if (!unit.contains("competitors")) continue;
+
         // filter all competitors, who won medals
         QJsonArray medalComps = filter(unit["competitors"].toArray(), [](QJsonObject comp) {
             if (!comp.contains("results")) return false;
@@ -164,6 +196,11 @@ QJsonArray Sport::getCompetitorsWithMedal() {
         for (const QJsonValueRef &medalCompRef : medalComps) {
             QJsonObject medalComp = medalCompRef.toObject();
 
+            // validate competitor (with medal)
+            if (!medalComp.contains("name")
+                || !medalComp.contains("results")
+                || !medalComp["results"].toObject().contains("medalType")) continue;
+
             QString name = medalComp["name"].toString();
             QString medalType = medalComp["results"].toObject()["medalType"].toString();
 
@@ -193,7 +230,17 @@ QJsonArray Sport::getCompetitorsWithMedal() {
     return output;
 }
 
+/**
+ * @brief Sport::createCompetitorWithMedals Creates a competitor QJsonObject with the following attributes: code, name, noc, medals{ME_GOLD, ME_SILVER, ME_BRONZE}
+ * @param comp The original competitor object.
+ * @return A competitor object with medal counts.
+ */
 QJsonObject Sport::createCompetitorWithMedals(QJsonObject comp) {
+    // repair competitor if something is missing
+    if (!comp.contains("code")) comp.insert("code", "0");
+    if (!comp.contains("name")) comp.insert("code", "");
+    if (!comp.contains("noc")) comp.insert("code", "");
+
     // create new competitor QJsonObject and add it to the competitor map
     QJsonObject medals {
         {"ME_GOLD", 0},
@@ -229,10 +276,17 @@ void Sport::filterByCountry(QJsonArray &competitors, QString nocShort) {
     filterCompetitors(competitors, QString("noc"), nocShort);
 }
 
+/**
+ * @brief Sport::filterCompetitors Filters the given QJsonArray by comparing the value of a certain attribute with the given filter string.
+ * @param competitors The competitors of one category.
+ * @param attribute The attribute to filter by.
+ * @param filter The string, which should be contained.
+ */
 void Sport::filterCompetitors(QJsonArray &competitors, QString attribute, QString filter) {
     for (int i = 0; i < competitors.size(); i++) {
+        QJsonObject comp = competitors[i].toObject();
 
-        if (!competitors[i].toObject()[attribute].toString().contains(filter, Qt::CaseInsensitive)) {
+        if (!comp.contains(attribute) || !comp[attribute].toString().contains(filter, Qt::CaseInsensitive)) {
             // remove the competitor, if the attribute does not fit the filter string
             competitors.removeAt(i);
             i--;
@@ -270,6 +324,11 @@ void Sport::sortByResult(QJsonArray &competitors) {
     else if (comp.contains("medals")) sortCompetitors(competitors, compareMedals);
 }
 
+/**
+ * @brief Sport::sortCompetitors Sorts the given QJsonArray according to the compare function.
+ * @param competitors The competitors of one category.
+ * @param compare A function to compare two competitors with each other. This defines the order.
+ */
 void Sport::sortCompetitors(QJsonArray &competitors, function<bool (const QJsonValue &left, const QJsonValue &right)> compare) {
     make_heap(competitors.begin(), competitors.end(), compare);
     sort_heap(competitors.begin(), competitors.end(), compare);
diff --git a/src/discipline/Sport.h b/src/discipline/Sport.h
index 9156b82..9175ad0 100644
--- a/src/discipline/Sport.h
+++ b/src/discipline/Sport.h
@@ -76,6 +76,8 @@ private:
 
     void filterCompetitors(QJsonArray &competitors, QString attribute, QString filter);
     void sortCompetitors(QJsonArray &competitors,  function<bool (const QJsonValue &left, const QJsonValue &right)> compare);
+
+    bool validateDiscipline();
     QJsonObject createCompetitorWithMedals(QJsonObject medalComp);
 
 };
-- 
cgit v1.2.3