Vendored
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
// Resolved by CMake Tools:
|
// Resolved by CMake Tools:
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": [ "[bluetooth_service]" ],
|
"args": [ "[Dev]" ],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [
|
"environment": [
|
||||||
|
|||||||
+27
-14
@@ -19,25 +19,38 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "BeastServer.hpp"
|
#include "BeastServer.hpp"
|
||||||
|
#include "MemDebug.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
TEST_CASE( "BeastServer shutdown", "[beastServerShutdown]" ) {
|
TEST_CASE("BeastServer shutdown", "[beastServerShutdown][Build][Dev]")
|
||||||
|
{
|
||||||
|
MemStats initialMemory = GetMemStats();
|
||||||
|
{
|
||||||
|
auto const address = boost::asio::ip::make_address("0.0.0.0");
|
||||||
|
auto const port = 8081;
|
||||||
|
std::string doc_root = ".";
|
||||||
|
auto const threads = 3;
|
||||||
|
|
||||||
auto const address = boost::asio::ip::make_address("0.0.0.0");
|
auto server = createBeastServer(
|
||||||
auto const port = 8081;
|
address, port, doc_root.c_str(), threads);
|
||||||
std::string doc_root = ".";
|
server->RunInBackground();
|
||||||
auto const threads = 3;
|
sleep(5);
|
||||||
|
server->ShutDown(1000);
|
||||||
|
sleep(1);
|
||||||
|
server->Join();
|
||||||
|
}
|
||||||
|
MemStats finalMemory = GetMemStats();
|
||||||
|
|
||||||
auto server = createBeastServer(
|
// currently leaking one allocation of 8 bytes. Acceptable.
|
||||||
address,port,doc_root.c_str(),threads);
|
if (finalMemory.allocations > initialMemory.allocations+1)
|
||||||
server->RunInBackground();
|
{
|
||||||
sleep(30000);
|
std::cout << "Leaked Allocations: " << (finalMemory.allocations- initialMemory.allocations) << std::endl;
|
||||||
server->ShutDown(1000);
|
std::cout << "Leaked Memory: " << (finalMemory.allocated - initialMemory.allocated) << " bytes" << std::endl;
|
||||||
sleep(1);
|
|
||||||
server->Join();
|
REQUIRE(finalMemory.allocations == initialMemory.allocations);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ add_executable(pipedaltest ${PIPEDAL_SOURCES} testMain.cpp
|
|||||||
SystemConfigFileTest.cpp
|
SystemConfigFileTest.cpp
|
||||||
BeastServerTest.cpp
|
BeastServerTest.cpp
|
||||||
MemDebug.cpp
|
MemDebug.cpp
|
||||||
|
MemDebug.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file(config.hpp.in config.hpp)
|
configure_file(config.hpp.in config.hpp)
|
||||||
@@ -207,6 +208,13 @@ target_link_libraries(pipedaltest PRIVATE pthread atomic stdc++fs asound
|
|||||||
${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} systemd SDBusCpp::sdbus-c++
|
${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} systemd SDBusCpp::sdbus-c++
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Build machine tests. Run tests that are not dependent on hardware.
|
||||||
|
add_test(NAME BuildTest COMMAND pipedaltest "[Build]")
|
||||||
|
|
||||||
|
# Developer tests. Run tests that only succeed on a Raspberry Pi with attached UBS Audio.
|
||||||
|
add_test(NAME DevTest COMMAND pipedaltest "[Dev]")
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+22
-3
@@ -25,13 +25,32 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Lv2Host.hpp"
|
#include "Lv2Host.hpp"
|
||||||
|
#include "MemDebug.hpp"
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE( "Lv2Host memory leak", "[lv2host_leak]" ) {
|
TEST_CASE( "Lv2Host memory leak", "[lv2host_leak][Build][Dev]" ) {
|
||||||
|
|
||||||
Lv2Host host;
|
MemStats initialMemory = GetMemStats();
|
||||||
|
{
|
||||||
|
Lv2Host host;
|
||||||
|
|
||||||
host.Load("/usr/lib/lv2:/usr/local/lib/lv2:/usr/modep/lv2");
|
host.Load("/usr/lib/lv2:/usr/local/lib/lv2:/usr/modep/lv2");
|
||||||
|
}
|
||||||
|
MemStats finalMemory = GetMemStats();
|
||||||
|
|
||||||
|
// Something lilv leaks a Dublin Core url.
|
||||||
|
// Acceptable.
|
||||||
|
const int ACCEPTABLE_ALLOCATION_LEAKS = 4;
|
||||||
|
const int ACCEPTABLE_MEMORY_LEAK = 400;
|
||||||
|
|
||||||
|
if (finalMemory.allocations > initialMemory.allocations + ACCEPTABLE_ALLOCATION_LEAKS
|
||||||
|
|| finalMemory.allocated > initialMemory.allocated + ACCEPTABLE_MEMORY_LEAK)
|
||||||
|
{
|
||||||
|
std::cout << "Leaked Allocations: " << (finalMemory.allocations- initialMemory.allocations) << std::endl;
|
||||||
|
std::cout << "Leaked Memory: " << (finalMemory.allocated - initialMemory.allocated) << " bytes" << std::endl;
|
||||||
|
|
||||||
|
REQUIRE(finalMemory.allocations == initialMemory.allocations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+110
-31
@@ -1,69 +1,148 @@
|
|||||||
|
// Copyright (c) 2022 Robin Davies
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
// subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#ifdef DEBUG
|
#include "MemDebug.hpp"
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
using namespace pipedal;
|
||||||
|
|
||||||
static std::mutex memMutex;
|
static std::mutex memMutex;
|
||||||
|
|
||||||
struct MemStats {
|
|
||||||
size_t allocated = 0;
|
|
||||||
size_t allocations = 0;
|
static MemStats memStats;
|
||||||
|
|
||||||
|
const MemStats&pipedal::GetMemStats()
|
||||||
|
{
|
||||||
|
return memStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t MEM_GUARD = (size_t)0xBAADF00DBAADF00D;
|
||||||
|
|
||||||
|
struct MemHeader {
|
||||||
|
size_t size = 0;
|
||||||
|
MemHeader*pNext = nullptr;
|
||||||
|
MemHeader *pPrev = nullptr;
|
||||||
|
size_t mem_guard = MEM_GUARD;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MemStats memStats;
|
static MemHeader memHead;
|
||||||
|
|
||||||
void *operator new(size_t size)
|
void *operator new(size_t size)
|
||||||
{
|
{
|
||||||
|
char *p = (char*)malloc(size+32+4);
|
||||||
{
|
{
|
||||||
std::lock_guard lock(memMutex);
|
std::lock_guard lock(memMutex);
|
||||||
|
MemHeader *pHead = (MemHeader*)p;
|
||||||
|
pHead->size = size;
|
||||||
|
pHead->pNext = nullptr;
|
||||||
|
pHead->pPrev = nullptr;
|
||||||
|
pHead->mem_guard = MEM_GUARD;
|
||||||
memStats.allocated += size;
|
memStats.allocated += size;
|
||||||
memStats.allocations++;
|
memStats.allocations++;
|
||||||
}
|
|
||||||
|
|
||||||
char *p = (char*)malloc(size+8);
|
// link block into allocation chain
|
||||||
((size_t*)p)[0] = size;
|
if (memHead.pNext == nullptr)
|
||||||
return p+8;
|
{
|
||||||
|
memHead.pNext = memHead.pPrev = pHead;
|
||||||
|
pHead->pNext = pHead->pPrev = &memHead;
|
||||||
|
} else {
|
||||||
|
pHead->pNext = memHead.pNext;
|
||||||
|
pHead->pNext->pPrev = pHead;
|
||||||
|
pHead->pPrev = &memHead;
|
||||||
|
memHead.pNext = pHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p+32;
|
||||||
|
char *endGuard = p + size;
|
||||||
|
*endGuard++ = (char)0xBA;
|
||||||
|
*endGuard++ = (char)0xAD;
|
||||||
|
*endGuard++ = (char)0xF0;
|
||||||
|
*endGuard++ = (char)0x0D;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bad_alloc();
|
||||||
|
|
||||||
void operator delete(void*mem)
|
void operator delete(void*mem)
|
||||||
{
|
{
|
||||||
|
if (mem == nullptr) return;
|
||||||
|
|
||||||
char *p = ((char*)mem);
|
char *p = ((char*)mem);
|
||||||
size_t size = *(size_t*)(p-8);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
MemHeader *pHeader = (MemHeader*)(p-32);
|
||||||
std::lock_guard lock(memMutex);
|
std::lock_guard lock(memMutex);
|
||||||
memStats.allocated -= size;
|
memStats.allocated -= pHeader->size;
|
||||||
memStats.allocations--;
|
memStats.allocations--;
|
||||||
|
|
||||||
|
// check the memory guards.
|
||||||
|
if (pHeader->mem_guard != MEM_GUARD)
|
||||||
|
{
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
char *pTail = p + pHeader->size;
|
||||||
|
if (*pTail++ != (char)0xBA) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
if (*pTail++ != (char)0xAD) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
if (*pTail++ != (char)0xF0) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
if (*pTail++ != (char)0x0D) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
// invalidate the memory guards (double free, eg).
|
||||||
|
pHeader->mem_guard = (size_t)0xDDDDDDDD;
|
||||||
|
pTail = p + pHeader->size;
|
||||||
|
*pTail++ = (char)0xDD;
|
||||||
|
*pTail++ = (char)0xDD;
|
||||||
|
*pTail++ = (char)0xDD;
|
||||||
|
*pTail++ = (char)0xDD;
|
||||||
|
|
||||||
|
// unlink the block from the allocation chain.
|
||||||
|
pHeader->pNext->pPrev = pHeader->pPrev;
|
||||||
|
pHeader->pPrev->pNext = pHeader->pNext;
|
||||||
|
pHeader->pNext = nullptr;
|
||||||
|
pHeader->pPrev = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
free(p-32);
|
||||||
|
|
||||||
|
|
||||||
free(p-8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new[](size_t size)
|
void* operator new[](size_t size)
|
||||||
{
|
{
|
||||||
{
|
return operator new(size);
|
||||||
std::lock_guard lock(memMutex);
|
|
||||||
memStats.allocated += size;
|
|
||||||
memStats.allocations++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *p = (char*)malloc(size+8);
|
|
||||||
((size_t*)p)[0] = size;
|
|
||||||
return p+8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete[](void*mem)
|
void operator delete[](void*mem)
|
||||||
{
|
{
|
||||||
char *p = ((char*)mem);
|
return operator delete(mem);
|
||||||
size_t size = *(size_t*)(p-8);
|
|
||||||
{
|
|
||||||
std::lock_guard lock(memMutex);
|
|
||||||
memStats.allocated -= size;
|
|
||||||
memStats.allocations--;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(p-8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2022 Robin Davies
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
// subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace pipedal {
|
||||||
|
struct MemStats {
|
||||||
|
size_t allocated = 0;
|
||||||
|
size_t allocations = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MemStats &GetMemStats();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,16 +22,17 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "PiPedalAlsa.hpp"
|
#include "PiPedalAlsa.hpp"
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
TEST_CASE( "ALSA Test", "[pipedal_alsa_test]" ) {
|
TEST_CASE( "ALSA Test", "[pipedal_alsa_test][Build][Dev]" ) {
|
||||||
|
|
||||||
PiPedalAlsaDevices devices;
|
PiPedalAlsaDevices devices;
|
||||||
auto result = devices.GetAlsaDevices();
|
auto result = devices.GetAlsaDevices();
|
||||||
REQUIRE(result.size() >= 1);
|
std::cout << result.size() << " ALSA devices found." << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ static std::string makeLine(const std::string &key, const std::string &value)
|
|||||||
|
|
||||||
void SystemConfigFile::Load(const std::filesystem::path &path)
|
void SystemConfigFile::Load(const std::filesystem::path &path)
|
||||||
{
|
{
|
||||||
this->lines.clear();
|
|
||||||
|
|
||||||
ifstream f(path);
|
ifstream f(path);
|
||||||
if (!f.is_open())
|
if (!f.is_open())
|
||||||
@@ -53,6 +52,12 @@ void SystemConfigFile::Load(const std::filesystem::path &path)
|
|||||||
s << "File not found: " << path;
|
s << "File not found: " << path;
|
||||||
throw PiPedalException(s.str());
|
throw PiPedalException(s.str());
|
||||||
}
|
}
|
||||||
|
Load(f);
|
||||||
|
this->currentPath = path;
|
||||||
|
}
|
||||||
|
void SystemConfigFile::Load(std::istream&f) {
|
||||||
|
this->lines.clear();
|
||||||
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -64,7 +69,6 @@ void SystemConfigFile::Load(const std::filesystem::path &path)
|
|||||||
}
|
}
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
}
|
}
|
||||||
this->currentPath = path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t SystemConfigFile::GetLine(const std::string &key) const
|
int64_t SystemConfigFile::GetLine(const std::string &key) const
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
Load(path);
|
Load(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Load(std::istream &input);
|
||||||
void Load(const std::filesystem::path&path);
|
void Load(const std::filesystem::path&path);
|
||||||
|
|
||||||
void Save(std::ostream &os);
|
void Save(std::ostream &os);
|
||||||
|
|||||||
@@ -25,30 +25,94 @@
|
|||||||
#include "PiPedalException.hpp"
|
#include "PiPedalException.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
#include "SystemConfigFile.hpp"
|
#include "SystemConfigFile.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
|
static std::string GetTestFile()
|
||||||
|
{
|
||||||
|
std::stringstream s;
|
||||||
|
s
|
||||||
|
<< "interface=wlan0" << std::endl
|
||||||
|
<< "driver=nl80211" << std::endl
|
||||||
|
<< "country_code=CA" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# Wi-Fi features" << std::endl
|
||||||
|
<< "ieee80211n=1" << std::endl
|
||||||
|
<< "ieee80211d=1" << std::endl
|
||||||
|
<< "ieee80211ac=1" << std::endl
|
||||||
|
<< "ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# Authentication options" << std::endl
|
||||||
|
<< "wmm_enabled=1" << std::endl
|
||||||
|
<< "auth_algs=1" << std::endl
|
||||||
|
<< "wpa=2" << std::endl
|
||||||
|
<< "wpa_pairwise=TKIP CCMP" << std::endl
|
||||||
|
<< "wpa_ptk_rekey=600" << std::endl
|
||||||
|
<< "rsn_pairwise=CCMP" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# Access point configuration" << std::endl
|
||||||
|
<< "ssid=pipedal" << std::endl
|
||||||
|
<< "hw_mode=g" << std::endl
|
||||||
|
<< "channel=8" << std::endl
|
||||||
|
<< "wpa_passphrase=PASSWORD" << std::endl;
|
||||||
|
|
||||||
TEST_CASE( "SystemConfigFile Test", "[system_config_file_test]" ) {
|
return s.str();
|
||||||
std::filesystem::path path("/etc/hostapd/hostapd.conf");
|
}
|
||||||
|
static std::string GetExpectedFile()
|
||||||
|
{
|
||||||
|
std::stringstream s;
|
||||||
|
s
|
||||||
|
<< "interface=wlan0" << std::endl
|
||||||
|
<< "driver=nl80211" << std::endl
|
||||||
|
<< "country_code=FR" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# Wi-Fi features" << std::endl
|
||||||
|
<< "ieee80211n=1" << std::endl
|
||||||
|
<< "ieee80211d=1" << std::endl
|
||||||
|
<< "ieee80211ac=1" << std::endl
|
||||||
|
<< "ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# Authentication options" << std::endl
|
||||||
|
<< "wmm_enabled=1" << std::endl
|
||||||
|
<< "auth_algs=1" << std::endl
|
||||||
|
<< "wpa=2" << std::endl
|
||||||
|
<< "wpa_pairwise=TKIP CCMP" << std::endl
|
||||||
|
<< "wpa_ptk_rekey=600" << std::endl
|
||||||
|
<< "rsn_pairwise=CCMP" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# Access point configuration" << std::endl
|
||||||
|
<< "ssid=newSsid" << std::endl
|
||||||
|
<< "hw_mode=g" << std::endl
|
||||||
|
<< "channel=8" << std::endl
|
||||||
|
<< "wpa_passphrase=PASSWORD" << std::endl
|
||||||
|
<< "" << std::endl
|
||||||
|
<< "# A new feature." << std::endl
|
||||||
|
<< "xx=new_feature" << std::endl;
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
SystemConfigFile file(path);
|
TEST_CASE("SystemConfigFile Test", "[system_config_file_test]")
|
||||||
std::string driverName;
|
{
|
||||||
|
|
||||||
|
std::stringstream testFile(GetTestFile());
|
||||||
|
|
||||||
|
SystemConfigFile file;
|
||||||
|
file.Load(testFile);
|
||||||
|
|
||||||
REQUIRE(file.Get("driver") == "nl80211");
|
REQUIRE(file.Get("driver") == "nl80211");
|
||||||
|
|
||||||
file.Set("ssid","ssid","Name of the access point");
|
file.Set("ssid", "ssid", "Name of the access point");
|
||||||
file.Set("xx","new_feature","A new feature.");
|
file.Set("xx", "new_feature", "A new feature.");
|
||||||
file.Set("ssid","newSsid");
|
file.Set("ssid", "newSsid");
|
||||||
file.Set("country_code","FR");
|
file.Set("country_code", "FR");
|
||||||
|
|
||||||
|
|
||||||
file.Save(std::cout);
|
|
||||||
|
|
||||||
|
std::stringstream outputFile;
|
||||||
|
file.Save(outputFile);
|
||||||
|
|
||||||
|
std::string stringOutput = outputFile.str();
|
||||||
|
std::cout << stringOutput;
|
||||||
|
|
||||||
|
std::string expected = GetExpectedFile();
|
||||||
|
REQUIRE(stringOutput == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-2
@@ -162,10 +162,17 @@ private:
|
|||||||
std::vector<json_member_reference_base<CLASS>* > members_;
|
std::vector<json_member_reference_base<CLASS>* > members_;
|
||||||
json_map_impl(const json_map_impl&) { } // disable copy constructor.
|
json_map_impl(const json_map_impl&) { } // disable copy constructor.
|
||||||
public:
|
public:
|
||||||
json_map_impl(std::vector<json_member_reference_base<CLASS>*> members)
|
using members_t = std::vector<json_member_reference_base<CLASS>*>;
|
||||||
|
|
||||||
|
json_map_impl(const members_t &members)
|
||||||
: members_(members)
|
: members_(members)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
json_map_impl(members_t &&members)
|
||||||
|
: members_(std::forward<members_t>(members))
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
virtual ~json_map_impl()
|
virtual ~json_map_impl()
|
||||||
{
|
{
|
||||||
@@ -185,12 +192,20 @@ public:
|
|||||||
|
|
||||||
class json_map {
|
class json_map {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
template <typename CLASS> class storage_type : public json_map_impl<CLASS> {
|
template <typename CLASS> class storage_type : public json_map_impl<CLASS> {
|
||||||
public:
|
public:
|
||||||
storage_type(std::vector<json_member_reference_base<CLASS>*> members)
|
|
||||||
|
using members_t = std::vector<json_member_reference_base<CLASS>*>;
|
||||||
|
|
||||||
|
storage_type(const members_t &members)
|
||||||
: json_map_impl<CLASS>(members)
|
: json_map_impl<CLASS>(members)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
storage_type(members_t &&members)
|
||||||
|
: json_map_impl<CLASS>(std::forward<members_t>(members))
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
template <typename CLASS, typename MEMBER_TYPE>
|
template <typename CLASS, typename MEMBER_TYPE>
|
||||||
static json_member_reference<CLASS,MEMBER_TYPE> *
|
static json_member_reference<CLASS,MEMBER_TYPE> *
|
||||||
|
|||||||
+1
-1
@@ -149,7 +149,7 @@ TEST_CASE( "json read", "[json_read_test]" ) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE( "json smart ptrs", "[json_smart_ptrs]" ) {
|
TEST_CASE( "json smart ptrs", "[json_smart_ptrs][Build][Dev]" ) {
|
||||||
std::string json =get_json();
|
std::string json =get_json();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user