Skip to content

Commit

Permalink
Merge pull request #328 from microsoft/jsonattrs
Browse files Browse the repository at this point in the history
Add AccessPointAttributes JSON serialization/deserialization support
  • Loading branch information
abeltrano authored Jul 27, 2024
2 parents e85cf6d + 4297f78 commit ebc50e5
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 11 deletions.
25 changes: 25 additions & 0 deletions src/common/net/wifi/core/AccessPointAttributes.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

#include <istream>
#include <optional>
#include <string>
#include <unordered_map>

#include <microsoft/net/wifi/AccessPointAttributes.hxx>

#include "AccessPointAttributesJsonSerialization.hxx"

using namespace Microsoft::Net::Wifi;

/* static */
std::optional<std::unordered_map<std::string, AccessPointAttributes>>
AccessPointAttributes::TryParseJson(const std::string& json)
{
return ParseAccessPointAttributesFromJson(json);
}

/* static */
std::optional<std::unordered_map<std::string, AccessPointAttributes>>
AccessPointAttributes::TryParseJson(std::istream& json)
{
return ParseAccessPointAttributesFromJson(json);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

#include <microsoft/net/wifi/AccessPointAttributes.hxx>
#include <nlohmann/json.hpp>

#include "AccessPointAttributesJsonSerialization.hxx"

namespace Microsoft::Net::Wifi
{
void
to_json(nlohmann::json& accessPointAttributesJson, const AccessPointAttributes& accessPointAttributes)
{
accessPointAttributesJson = nlohmann::json{
{ "Properties", accessPointAttributes.Properties }
};
}

void
from_json(const nlohmann::json& accessPointAttributesJson, AccessPointAttributes& accessPointAttributes)
{
accessPointAttributesJson.at("Properties").get_to(accessPointAttributes.Properties);
}

} // namespace Microsoft::Net::Wifi
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

#ifndef ACCESS_POINT_ATTRIBUTES_JSON_SERIALIZATION_HXX
#define ACCESS_POINT_ATTRIBUTES_JSON_SERIALIZATION_HXX

#include <format>
#include <optional>
#include <string>
#include <unordered_map>

#include <microsoft/net/wifi/AccessPointAttributes.hxx>
#include <nlohmann/json.hpp>
#include <plog/Log.h>

namespace Microsoft::Net::Wifi
{
/**
* @brief Serialize access point attributes to JSON.
*
* @param accessPointAttributesJson The JSON object to hold the serialized data.
* @param accessPointAttributes The access point attributes to serialize.
*/
void
to_json(nlohmann::json& accessPointAttributesJson, const AccessPointAttributes& accessPointAttributes);

/**
* @brief Deserialize access point attributes from JSON.
*
* @param accessPointAttributesJson The JSON object to deserialize.
* @param accessPointAttributes The access point attributes to populate.
*/
void
from_json(const nlohmann::json& accessPointAttributesJson, AccessPointAttributes& accessPointAttributes);

/**
* @brief Parse access point attributes from a JSON input type.
*
* @tparam InputType The input type holding the JSON to parse. This must be one of the types supported by
* nlohmann::json::parse (input stream, string, iterator pair, contiguous container, character array).
* @param json The JSON input to parse.
* @return std::optional<std::unordered_map<std::string, AccessPointAttributes>>
*/
template <typename InputType>
std::optional<std::unordered_map<std::string, AccessPointAttributes>>
ParseAccessPointAttributesFromJson(InputType& json)
{
std::unordered_map<std::string, AccessPointAttributes> accessPointAttributesMap;
nlohmann::json accessPointAttributesJson;

try {
accessPointAttributesJson = nlohmann::json::parse(json);
accessPointAttributesJson.get_to(accessPointAttributesMap);
} catch (const nlohmann::json::parse_error& e) {
LOGE << std::format("Failed to parse access point access point attributes JSON: {}", e.what());
return std::nullopt;
}

return accessPointAttributesMap;
}

} // namespace Microsoft::Net::Wifi

#endif // ACCESS_POINT_ATTRIBUTES_JSON_SERIALIZATION_HXX
5 changes: 5 additions & 0 deletions src/common/net/wifi/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ set(WIFI_CORE_PUBLIC_INCLUDE_PREFIX ${WIFI_CORE_PUBLIC_INCLUDE}/${WIFI_CORE_PUBL
target_sources(wifi-core
PRIVATE
AccessPoint.cxx
AccessPointAttributes.cxx
AccessPointAttributesJsonSerialization.cxx
AccessPointAttributesJsonSerialization.hxx
AccessPointController.cxx
AccessPointOperationStatus.cxx
AccessPointOperationStatusLogOnExit.cxx
Expand All @@ -19,6 +22,7 @@ target_sources(wifi-core
BASE_DIRS ${WIFI_CORE_PUBLIC_INCLUDE}
FILES
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPoint.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointAttributes.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointController.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointOperationStatus.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointOperationStatusLogOnExit.hxx
Expand All @@ -33,6 +37,7 @@ target_sources(wifi-core
target_link_libraries(wifi-core
PRIVATE
magic_enum::magic_enum
nlohmann_json::nlohmann_json
notstd
strings
PUBLIC
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

#ifndef ACCESS_POINT_ATTRIBUTES_HXX
#define ACCESS_POINT_ATTRIBUTES_HXX

#include <istream>
#include <optional>
#include <string>
#include <unordered_map>

namespace Microsoft::Net::Wifi
{
/**
* @brief Container to hold static attributes about an access point.
*/
struct AccessPointAttributes
{
/**
* @brief Attempt to deserialize a JSON string into a map of access point attributes.
*
* @param json The JSON input string to parse.
* @return std::optional<std::unordered_map<std::string, AccessPointAttributes>>
*/
static std::optional<std::unordered_map<std::string, AccessPointAttributes>>
TryParseJson(const std::string& json);

/**
* @brief Attempt to deserialize a JSON stream into a map of access point attributes.
*
* @param json The JSON input stream to parse.
* @return std::optional<std::unordered_map<std::string, AccessPointAttributes>>
*/
static std::optional<std::unordered_map<std::string, AccessPointAttributes>>
TryParseJson(std::istream& json);

std::unordered_map<std::string, std::string> Properties{};
};
} // namespace Microsoft::Net::Wifi

#endif // ACCESS_POINT_ATTRIBUTES_HXX
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,12 @@
#include <string_view>
#include <unordered_map>

#include <microsoft/net/wifi/AccessPointAttributes.hxx>
#include <microsoft/net/wifi/IAccessPointController.hxx>
#include <microsoft/net/wifi/Ieee80211.hxx>

namespace Microsoft::Net::Wifi
{

/**
* @brief Container to hold static attributes about an access point.
*/
struct AccessPointAttributes
{
std::unordered_map<std::string, std::string> Properties{};
};

/**
* @brief Represents a wireless access point.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ MakeAccessPoint(const std::shared_ptr<AccessPointFactoryLinux> &accessPointFacto
std::future<std::vector<std::shared_ptr<IAccessPoint>>>
AccessPointDiscoveryAgentOperationsNetlink::ProbeAsync()
{
const auto ToAccessPoint = [this](const Nl80211Interface &nl80211Interface) {
return detail::MakeAccessPoint(m_accessPointFactory, nl80211Interface);
const auto ToAccessPoint = [accessPointFactory = m_accessPointFactory](const Nl80211Interface &nl80211Interface) {
return detail::MakeAccessPoint(accessPointFactory, nl80211Interface);
};

std::promise<std::vector<std::shared_ptr<IAccessPoint>>> probePromise{};
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/net/wifi/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ target_sources(wifi-core-test-unit
PRIVATE
Main.cxx
TestAccessPoint.cxx
TestAccessPointAttributes.cxx
TestAccessPointOperationStatus.cxx
TestIeee80211.cxx
)
Expand All @@ -18,6 +19,7 @@ target_link_libraries(wifi-core-test-unit
PRIVATE
Catch2::Catch2
magic_enum::magic_enum
nlohmann_json::nlohmann_json
plog::plog
strings
wifi-core
Expand Down
75 changes: 75 additions & 0 deletions tests/unit/net/wifi/core/TestAccessPointAttributes.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

#include <string>
#include <unordered_map>

#include <catch2/catch_test_macros.hpp>
#include <microsoft/net/wifi/AccessPointAttributes.hxx>
#include <nlohmann/json.hpp>

TEST_CASE("AccessPointAttributes JSON Serialization and Deserialization", "[wifi][core][ap][serialization]")
{
using namespace Microsoft::Net::Wifi;

auto accessPointAttributesJson = R"(
{
"wlan0": {
"Properties": {
"key1": "value1",
"key2": "value2"
}
},
"wlan1": {
"Properties": {
"key1": "value1",
"key2": "value2"
}
}
}
)";

// clang-format off
std::unordered_map<std::string, AccessPointAttributes> AccessPointAttributesMap{
{
"wlan0",
AccessPointAttributes{
{
{ "key1", "value1" },
{ "key2", "value2" }
}
},
},
{
"wlan1",
AccessPointAttributes{
{
{ "key1", "value1" },
{ "key2", "value2" }
}
}
}
};
// clang-format on

SECTION("Deserialization (direct) doesn't cause a crash")
{
REQUIRE_NOTHROW(nlohmann::json::parse(accessPointAttributesJson));
}

SECTION("Deserialization (wrapped) doesn't cause a crash")
{
REQUIRE_NOTHROW(AccessPointAttributes::TryParseJson(accessPointAttributesJson));
}

SECTION("Deserialization (wrapped) populates the access point attributes")
{
auto deserializedAccessPointAttributesOpt = AccessPointAttributes::TryParseJson(accessPointAttributesJson);
REQUIRE(deserializedAccessPointAttributesOpt.has_value());
auto& deserializedAccessPointAttributes = deserializedAccessPointAttributesOpt.value();
REQUIRE(std::size(deserializedAccessPointAttributes) == std::size(AccessPointAttributesMap));

for (const auto& [interfaceName, accessPointAttributes] : AccessPointAttributesMap) {
REQUIRE(deserializedAccessPointAttributes.contains(interfaceName));
REQUIRE(deserializedAccessPointAttributes[interfaceName].Properties == accessPointAttributes.Properties);
}
}
}

0 comments on commit ebc50e5

Please sign in to comment.