Add tests for the JSON decoder.

These tests will test the bej_decoder_core.c as well.

Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Ibf1c9a381a630beac09ed504dd57563160579fb0
diff --git a/test/bej_decoder_test.cpp b/test/bej_decoder_test.cpp
new file mode 100644
index 0000000..8e9da65
--- /dev/null
+++ b/test/bej_decoder_test.cpp
@@ -0,0 +1,195 @@
+#include "bej_decoder_json.hpp"
+#include "nlohmann/json.hpp"
+
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <span>
+#include <string_view>
+
+#include <gmock/gmock-matchers.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace libbej
+{
+
+struct BejTestInputFiles
+{
+    const char* jsonFile;
+    const char* schemaDictionaryFile;
+    const char* annotationDictionaryFile;
+    const char* errorDictionaryFile;
+    const char* encodedStreamFile;
+};
+
+struct BejTestInputs
+{
+    const nlohmann::json expectedJson;
+    const uint8_t* schemaDictionary;
+    const uint8_t* annotationDictionary;
+    const uint8_t* errorDictionary;
+    std::span<const uint8_t> encodedStream;
+};
+
+struct BejDecoderTestParams
+{
+    const std::string testName;
+    const BejTestInputFiles inputFiles;
+};
+
+using BejDecoderTest = testing::TestWithParam<BejDecoderTestParams>;
+
+const BejTestInputFiles driveOemTestFiles = {
+    .jsonFile = "../test/json/drive_oem.json",
+    .schemaDictionaryFile = "../test/dictionaries/drive_oem_dict.bin",
+    .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
+    .errorDictionaryFile = "",
+    .encodedStreamFile = "../test/encoded/drive_oem_enc.bin",
+};
+
+const BejTestInputFiles circuitTestFiles = {
+    .jsonFile = "../test/json/circuit.json",
+    .schemaDictionaryFile = "../test/dictionaries/circuit_dict.bin",
+    .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
+    .errorDictionaryFile = "",
+    .encodedStreamFile = "../test/encoded/circuit_enc.bin",
+};
+
+const BejTestInputFiles storageTestFiles = {
+    .jsonFile = "../test/json/storage.json",
+    .schemaDictionaryFile = "../test/dictionaries/storage_dict.bin",
+    .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
+    .errorDictionaryFile = "",
+    .encodedStreamFile = "../test/encoded/storage_enc.bin",
+};
+
+const BejTestInputFiles dummySimpleTestFiles = {
+    .jsonFile = "../test/json/dummysimple.json",
+    .schemaDictionaryFile = "../test/dictionaries/dummy_simple_dict.bin",
+    .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
+    .errorDictionaryFile = "",
+    .encodedStreamFile = "../test/encoded/dummy_simple_enc.bin",
+};
+
+// Buffer size for storing a single binary file data.
+constexpr uint32_t maxBufferSize = 16 * 1024;
+
+std::streamsize readBinaryFile(const char* fileName, std::span<uint8_t> buffer)
+{
+    std::ifstream inputStream(fileName, std::ios::binary);
+    if (!inputStream.is_open())
+    {
+        std::cerr << "Cannot open file: " << fileName << "\n";
+        return 0;
+    }
+    auto readLength = inputStream.readsome(
+        reinterpret_cast<char*>(buffer.data()), buffer.size_bytes());
+    if (inputStream.peek() != EOF)
+    {
+        std::cerr << "Failed to read the complete file: " << fileName
+                  << "  read length: " << readLength << "\n";
+        return 0;
+    }
+    return readLength;
+}
+
+std::optional<BejTestInputs> loadInputs(const BejTestInputFiles& files,
+                                        bool readErrorDictionary = false)
+{
+    std::ifstream jsonInput(files.jsonFile);
+    if (!jsonInput.is_open())
+    {
+        std::cerr << "Cannot open file: " << files.jsonFile << "\n";
+        return std::nullopt;
+    }
+    nlohmann::json expJson;
+    jsonInput >> expJson;
+
+    static uint8_t schemaDictBuffer[maxBufferSize];
+    if (readBinaryFile(files.schemaDictionaryFile,
+                       std::span(schemaDictBuffer, maxBufferSize)) == 0)
+    {
+        return std::nullopt;
+    }
+
+    static uint8_t annoDictBuffer[maxBufferSize];
+    if (readBinaryFile(files.annotationDictionaryFile,
+                       std::span(annoDictBuffer, maxBufferSize)) == 0)
+    {
+        return std::nullopt;
+    }
+
+    static uint8_t encBuffer[maxBufferSize];
+    auto encLen = readBinaryFile(files.encodedStreamFile,
+                                 std::span(encBuffer, maxBufferSize));
+    if (encLen == 0)
+    {
+        return std::nullopt;
+    }
+
+    static uint8_t errorDict[maxBufferSize];
+    if (readErrorDictionary)
+    {
+        if (readBinaryFile(files.errorDictionaryFile,
+                           std::span(errorDict, maxBufferSize)) == 0)
+        {
+            return std::nullopt;
+        }
+    }
+
+    BejTestInputs inputs = {
+        .expectedJson = expJson,
+        .schemaDictionary = schemaDictBuffer,
+        .annotationDictionary = annoDictBuffer,
+        .errorDictionary = errorDict,
+        .encodedStream = std::span(encBuffer, encLen),
+    };
+    return inputs;
+}
+
+TEST_P(BejDecoderTest, Decode)
+{
+    const BejDecoderTestParams& test_case = GetParam();
+    auto inputsOrErr = loadInputs(test_case.inputFiles);
+    EXPECT_TRUE(inputsOrErr);
+
+    BejDictionaries dictionaries = {
+        .schemaDictionary = inputsOrErr->schemaDictionary,
+        .annotationDictionary = inputsOrErr->annotationDictionary,
+        .errorDictionary = inputsOrErr->errorDictionary,
+    };
+
+    BejDecoderJson decoder;
+    EXPECT_THAT(decoder.decode(dictionaries, inputsOrErr->encodedStream), 0);
+    std::string decoded = decoder.getOutput();
+    nlohmann::json jsonDecoded = nlohmann::json::parse(decoded);
+
+    // Just comparing nlohmann::json types could lead to errors. It compares the
+    // byte values. So int64 and unit64 comparisons might be incorrect. Eg:
+    // bytes values for -5 and 18446744073709551611 are the same. So compare the
+    // string values.
+    EXPECT_TRUE(jsonDecoded.dump() == inputsOrErr->expectedJson.dump());
+}
+
+/**
+ * TODO: Add more test cases.
+ * - Test Enums inside array elemets
+ * - Array inside an array: is this a valid case?
+ * - Real numbers with exponent part
+ * - Every type inside an array.
+ */
+INSTANTIATE_TEST_SUITE_P(
+    , BejDecoderTest,
+    testing::ValuesIn<BejDecoderTestParams>({
+        {"DriveOEM", driveOemTestFiles},
+        {"Circuit", circuitTestFiles},
+        {"Storage", storageTestFiles},
+        {"DummySimple", dummySimpleTestFiles},
+    }),
+    [](const testing::TestParamInfo<BejDecoderTest::ParamType>& info) {
+        return info.param.testName;
+    });
+
+} // namespace libbej
diff --git a/test/dictionaries/annotation_dict.bin b/test/dictionaries/annotation_dict.bin
new file mode 100644
index 0000000..e329eae
--- /dev/null
+++ b/test/dictionaries/annotation_dict.bin
Binary files differ
diff --git a/test/dictionaries/circuit_dict.bin b/test/dictionaries/circuit_dict.bin
new file mode 100644
index 0000000..2143827
--- /dev/null
+++ b/test/dictionaries/circuit_dict.bin
Binary files differ
diff --git a/test/dictionaries/drive_oem_dict.bin b/test/dictionaries/drive_oem_dict.bin
new file mode 100644
index 0000000..89c2171
--- /dev/null
+++ b/test/dictionaries/drive_oem_dict.bin
Binary files differ
diff --git a/test/dictionaries/dummy_simple_dict.bin b/test/dictionaries/dummy_simple_dict.bin
new file mode 100644
index 0000000..f577e03
--- /dev/null
+++ b/test/dictionaries/dummy_simple_dict.bin
Binary files differ
diff --git a/test/dictionaries/storage_dict.bin b/test/dictionaries/storage_dict.bin
new file mode 100644
index 0000000..db21d57
--- /dev/null
+++ b/test/dictionaries/storage_dict.bin
Binary files differ
diff --git a/test/encoded/circuit_enc.bin b/test/encoded/circuit_enc.bin
new file mode 100644
index 0000000..f6f27a3
--- /dev/null
+++ b/test/encoded/circuit_enc.bin
Binary files differ
diff --git a/test/encoded/drive_oem_enc.bin b/test/encoded/drive_oem_enc.bin
new file mode 100644
index 0000000..8029947
--- /dev/null
+++ b/test/encoded/drive_oem_enc.bin
Binary files differ
diff --git a/test/encoded/dummy_simple_enc.bin b/test/encoded/dummy_simple_enc.bin
new file mode 100644
index 0000000..9cb426d
--- /dev/null
+++ b/test/encoded/dummy_simple_enc.bin
Binary files differ
diff --git a/test/encoded/storage_enc.bin b/test/encoded/storage_enc.bin
new file mode 100644
index 0000000..b530533
--- /dev/null
+++ b/test/encoded/storage_enc.bin
Binary files differ
diff --git a/test/json/circuit.json b/test/json/circuit.json
new file mode 100644
index 0000000..b40a0c0
--- /dev/null
+++ b/test/json/circuit.json
@@ -0,0 +1,72 @@
+{
+ "@odata.type": "#Circuit.v1_0_0.Circuit",
+    "Id": "A",
+    "Name": "Branch Circuit A",
+    "Status": {
+        "State": "Enabled",
+        "Health": "OK"
+    },
+    "CircuitType": "Branch",
+    "PhaseWiringType": "TwoPhase3Wire",
+    "NominalVoltage": "AC200To240V",
+    "RatedCurrentAmps": 16.0,
+    "BreakerState": "Normal",
+    "PolyPhaseVoltage": {
+        "Line1ToNeutral": {
+            "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageAL1N",
+            "Reading": 118.2
+        },
+        "Line1ToLine2": {
+            "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageAL1L2",
+            "Reading": 203.5
+        }
+    },
+    "CurrentAmps": {
+        "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/CurrentA",
+        "Reading": 5.19
+    },
+    "PolyPhaseCurrentAmps": {
+        "Line1": {
+            "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/CurrentA",
+            "Reading": 5.19
+        }
+    },
+    "PowerWatts": {
+        "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/PowerA",
+        "Reading": 937.4,
+        "ApparentVA": 937.4,
+        "ReactiveVAR": 0.0,
+        "PowerFactor": 1.0
+    },
+    "PolyPhasePowerWatts": {
+        "Line1ToNeutral": {
+            "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/PowerA1",
+            "Reading": 937.4,
+            "ApparentVA": 937.4,
+            "ReactiveVAR": 0.0,
+            "PowerFactor": 1.0
+        }
+    },
+    "FrequencyHz": {
+        "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/FrequencyA",
+        "Reading": 60.0
+    },
+    "EnergykWh": {
+        "DataSourceUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/EnergyA",
+        "Reading": 325675.0
+    },
+    "Links": {
+        "Outlets": [
+            {
+                "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/A1"
+            },
+            {
+                "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/A2"
+            },
+            {
+                "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/A3"
+            }
+        ]
+    },
+    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Branches/A"
+}
diff --git a/test/json/drive_oem.json b/test/json/drive_oem.json
new file mode 100644
index 0000000..b2bb231
--- /dev/null
+++ b/test/json/drive_oem.json
@@ -0,0 +1,114 @@
+{
+    "@odata.id": "/redfish/v1/drives/1",
+    "@odata.type": "#Drive.v1_5_0.Drive",
+    "@odata.etag": "FBS4553345",
+    "Id": "Drive1",
+    "Name": "Disk Bay 1",
+    "IndicatorLED": "Lit",
+    "Model": "Consorto MM0500FBFVQ",
+    "Revision": "C1.1",
+    "Status": {
+       "State": "Enabled",
+       "Health": "Warning"
+    },
+    "Actions": {
+       "#Drive.SecureErase": {
+          "target": "/redfish/v1/drives/1/Actions/Drive.SecureErase",
+          "title": "Secure Erase a Drive"
+       },
+      "#Drive.Reset": {
+          "target": "/redfish/v1/drives/1/Actions/Drive.Reset",
+          "title": "Reset a Drive",
+          "ResetType@Redfish.AllowableValues": [
+                "On",
+                "ForceOff",
+                "ForceRestart",
+                "Nmi",
+                "ForceOn",
+                "PushPowerButton"
+            ]
+      }
+    },
+    "Status@Message.ExtendedInfo": [
+        {
+            "MessageId": "PredictiveFailure",
+            "Severity": "Warning",
+            "RelatedProperties": ["FailurePredicted", "MediaType"]
+        },
+        {
+            "MessageId": "LinkFailure",
+            "Severity": "Warning",
+            "MessageArgs": ["Port", "1"]
+        }
+    ],
+    "CapacityBytes": 500105991946,
+    "BlockSizeBytes": 512,
+    "Identifiers": [
+        {
+            "DurableNameFormat": "NAA",
+            "DurableName": "5000C5004183A941"
+        }
+    ],
+    "FailurePredicted": true,
+    "Protocol": "SAS",
+    "MediaType": "HDD",
+    "Manufacturer": "CONSORTO",
+    "SerialNumber": "9XF11DLF00009238W7LN",
+    "PhysicalLocation": {
+       "PartLocation": {
+           "LocationOrdinalValue": 1,
+           "LocationType": "Bay",
+           "ServiceLabel": "Port=A:Bay=1"
+       }
+    },
+    "RotationSpeedRPM": 15000.0,
+    "CapableSpeedGbs": 5.0e-4,
+    "NegotiatedSpeedGbs": 12.0,
+    "Operations": [
+       {
+           "OperationName": "Erasing",
+           "PercentageComplete": 20,
+           "AssociatedTask": {
+              "@odata.id": "/redfish/v1/Tasks/1"
+           }
+       },
+       {
+           "OperationName": "Rebuilding",
+           "PercentageComplete": 70,
+           "AssociatedTask": {
+              "@odata.id": "/redfish/v1/Tasks/2"
+           }
+       }
+    ],
+   "Links": {
+      "Volumes": [
+         {
+            "@odata.id": "/redfish/v1/Systems/1/Storage/1/Volumes/1"
+         },
+         {
+            "@odata.id": "/redfish/v1/Systems/1/Storage/1/Volumes/2"
+         },
+         {
+            "@odata.id": "/redfish/v1/Systems/1/Storage/1/Volumes/3"
+         }
+      ]
+   },
+   "Oem": {
+       "OEM1": {
+           "@odata.type": "#OEMDriveExt.v1_0_0.OEM1DriveExt",
+           "ArrayOfStrings": [
+               "str1",
+               "str2",
+               "str3",
+               "str4"
+           ],
+           "ArrayOfInts": [
+               10,
+               20,
+               30,
+               40,
+               50
+           ]
+       }
+   }
+}
diff --git a/test/json/dummysimple.json b/test/json/dummysimple.json
new file mode 100644
index 0000000..96503a4
--- /dev/null
+++ b/test/json/dummysimple.json
@@ -0,0 +1,15 @@
+{
+    "Id": "Dummy ID",
+    "SampleIntegerProperty": -5,
+    "SampleRealProperty": -5576.90001,
+    "SampleEnabledProperty": null,
+    "ChildArrayProperty": [
+        {
+            "AnotherBoolean": true,
+            "LinkStatus": "NoLink"
+        },
+        {
+            "LinkStatus": "LinkDown"
+        }
+    ]
+ }
diff --git a/test/json/storage.json b/test/json/storage.json
new file mode 100644
index 0000000..007c4ff
--- /dev/null
+++ b/test/json/storage.json
@@ -0,0 +1,79 @@
+{
+   "@odata.type": "#Storage.v1_3_0.Storage",
+   "@odata.context": "/redfish/v1/$metadata#Storage.Storage",
+   "@odata.id": "/redfish/v1/Systems/1/Storage/1",
+   "Id": "RAID Controller 1",
+   "Name": "RAID Controller",
+   "Description": "RAID Controller",
+   "Status": {
+      "State": "Enabled",
+      "Health": "OK",
+      "HealthRollup": "OK"
+   },
+   "StorageControllers": [
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1#/StorageControllers/0",
+         "@odata.type": "#Storage.v1_3_0.StorageController",
+         "MemberId": "0",
+         "Name": "SAS RAID Controller",
+         "Status": {
+            "State": "Enabled",
+            "Health": "OK"
+         },
+         "Identifiers": [
+            {
+               "DurableNameFormat": "NAA",
+               "DurableName": "5045594843305852483430304E452000"
+            }
+         ],
+         "Manufacturer": "Consorto",
+         "Model": "Consorty RAID Controller XYZ",
+         "SerialNumber": "PEYHC0XRH400NE",
+         "PartNumber": "7334534",
+         "SpeedGbps": 12.0,
+         "FirmwareVersion": "1.00",
+         "SupportedControllerProtocols": [
+            "PCIe"
+         ],
+         "SupportedDeviceProtocols": [
+            "SAS",
+            "SATA"
+         ]
+      }
+   ],
+   "Drives": [
+      {
+         "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1/Drives/Disk.Bay.1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1/Drives/Disk.Bay.2"
+      },
+      {
+         "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1/Drives/Disk.Bay.3"
+      },
+      {
+         "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1/Drives/Disk.Bay.4"
+      },
+      {
+         "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1/Drives/Disk.Bay.5"
+      },
+      {
+         "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1/Drives/Disk.Bay.6"
+      }
+   ],
+   "Volumes": {
+      "@odata.id": "/redfish/v1/volcollection"
+   },
+   "Links": {
+      "Enclosures": [
+         {
+            "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1"
+         }
+      ]
+   },
+   "@Redfish.OperationApplyTime": "Immediate",
+   "@Redfish.CollectionCapabilities": {
+      "MaxMembers": 0
+   },
+   "@Message.ExtendedInfo": []
+}
diff --git a/test/json/storage_large.json b/test/json/storage_large.json
new file mode 100644
index 0000000..800e379
--- /dev/null
+++ b/test/json/storage_large.json
@@ -0,0 +1,656 @@
+{
+   "@odata.type": "#Storage.v1_3_0.Storage",
+   "@odata.context": "/redfish/v1/$metadata#Storage.Storage",
+   "@odata.id": "/redfish/v1/Systems/1/Storage/1",
+   "Id": "RAID Controller 1",
+   "Name": "RAID Controller",
+   "Description": "RAID Controller",
+   "Status": {
+      "State": "Enabled",
+      "Health": "OK",
+      "HealthRollup": "OK"
+   },
+   "StorageControllers": [
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1#/StorageControllers/0",
+         "@odata.type": "#Storage.v1_3_0.StorageController",
+         "MemberId": "0",
+         "Name": "SAS RAID Controller",
+         "Status": {
+            "State": "Enabled",
+            "Health": "OK"
+         },
+         "Identifiers": [
+            {
+               "DurableNameFormat": "NAA",
+               "DurableName": "5045594843305852483430304E452000"
+            }
+         ],
+         "Manufacturer": "Consorto",
+         "Model": "Consorty RAID Controller XYZ",
+         "SerialNumber": "PEYHC0XRH400NE",
+         "PartNumber": "7334534",
+         "SpeedGbps": 12.0,
+         "FirmwareVersion": "1.00",
+         "SupportedControllerProtocols": [
+            "PCIe"
+         ],
+         "SupportedDeviceProtocols": [
+            "SAS",
+            "SATA"
+         ]
+      }
+   ],
+   "Drives": [
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/2"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/3"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/4"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/5"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/6"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/7"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/8"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/9"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/10"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/11"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/12"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/13"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/14"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/15"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/16"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/17"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/18"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/19"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/20"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/21"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/22"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/23"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/24"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/25"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/26"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/27"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/28"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/29"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/30"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/31"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/32"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/33"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/34"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/35"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/36"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/37"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/38"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/39"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/40"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/41"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/42"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/43"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/44"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/45"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/46"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/47"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/48"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/49"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/50"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/51"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/52"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/53"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/54"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/55"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/56"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/57"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/58"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/59"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/60"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/61"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/62"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/63"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/64"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/65"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/66"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/67"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/68"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/69"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/70"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/71"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/72"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/73"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/74"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/75"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/76"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/2"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/3"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/4"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/5"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/6"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/7"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/8"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/9"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/10"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/11"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/12"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/13"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/14"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/15"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/16"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/17"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/18"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/19"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/20"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/21"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/22"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/23"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/24"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/25"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/26"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/27"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/28"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/29"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/30"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/31"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/32"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/33"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/34"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/35"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/36"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/37"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/38"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/39"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/40"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/41"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/42"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/43"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/44"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/45"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/46"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/47"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/48"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/49"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/50"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/51"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/52"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/53"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/54"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/55"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/56"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/57"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/58"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/59"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/60"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/61"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/62"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/63"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/64"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/65"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/66"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/67"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/68"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/69"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/70"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/71"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/72"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/73"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/74"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/75"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/76"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      },
+      {
+         "@odata.id": "/redfish/v1/Systems/1/Storage/1/Drives/1"
+      }
+   ],
+   "Volumes": {
+      "@odata.id": "/redfish/v1/volcollection"
+   },
+   "Links": {
+      "Enclosures": [
+         {
+            "@odata.id": "/redfish/v1/Chassis/StorageEnclosure1"
+         }
+      ]
+   }
+}
diff --git a/test/meson.build b/test/meson.build
index 8e406a7..90ccb71 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -16,6 +16,7 @@
 endif
 
 gtests = [
+  'bej_decoder',
   'rde_common',
   'bej_dictionary',
 ]