From 1f18cc54167b34c0c970b841fd754dd760faefaa Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 1 Oct 2017 09:13:43 -0700 Subject: [PATCH] Add SaveEntries() and LoadEntries(). (#233) These allow saving and loading non-persistent entries in the persistent file format. --- .../wpi/first/networktables/NetworkTable.java | 21 ++++++++ .../networktables/NetworkTableInstance.java | 23 ++++++++ .../first/networktables/NetworkTablesJNI.java | 3 ++ src/main/native/cpp/Storage.cpp | 25 +++++++++ src/main/native/cpp/Storage.h | 15 ++++-- src/main/native/cpp/Storage_load.cpp | 28 ++++++---- src/main/native/cpp/Storage_save.cpp | 42 +++++++++++++++ src/main/native/cpp/jni/NetworkTablesJNI.cpp | 53 +++++++++++++++++++ .../native/cpp/networktables/NetworkTable.cpp | 14 +++++ src/main/native/cpp/ntcore_c.cpp | 13 ++++- src/main/native/cpp/ntcore_cpp.cpp | 16 ++++++ .../include/networktables/NetworkTable.h | 19 +++++++ .../networktables/NetworkTableInstance.h | 23 +++++++- .../networktables/NetworkTableInstance.inl | 11 ++++ src/main/native/include/ntcore_c.h | 28 +++++++++- src/main/native/include/ntcore_cpp.h | 24 ++++++++- src/test/native/cpp/StorageTest.cpp | 20 +++---- 17 files changed, 352 insertions(+), 26 deletions(-) diff --git a/src/main/java/edu/wpi/first/networktables/NetworkTable.java b/src/main/java/edu/wpi/first/networktables/NetworkTable.java index eae400c9b7..c168ce3e9c 100644 --- a/src/main/java/edu/wpi/first/networktables/NetworkTable.java +++ b/src/main/java/edu/wpi/first/networktables/NetworkTable.java @@ -264,6 +264,27 @@ public final class NetworkTable { return path; } + /** + * Save table values to a file. The file format used is identical to + * that used for SavePersistent. + * @param filename filename + * @throws PersistentException if error saving file + */ + public void saveEntries(String filename) throws PersistentException { + inst.saveEntries(filename, pathWithSep); + } + + /** + * Load table values from a file. The file format used is identical to + * that used for SavePersistent / LoadPersistent. + * @param filename filename + * @return List of warnings (errors result in an exception instead) + * @throws PersistentException if error saving file + */ + public String[] loadEntries(String filename) throws PersistentException { + return inst.loadEntries(filename, pathWithSep); + } + @Override public boolean equals(Object o) { if (o == this) { diff --git a/src/main/java/edu/wpi/first/networktables/NetworkTableInstance.java b/src/main/java/edu/wpi/first/networktables/NetworkTableInstance.java index 7e0e3fbc7c..4d53f67fba 100644 --- a/src/main/java/edu/wpi/first/networktables/NetworkTableInstance.java +++ b/src/main/java/edu/wpi/first/networktables/NetworkTableInstance.java @@ -935,6 +935,29 @@ public final class NetworkTableInstance { return NetworkTablesJNI.loadPersistent(m_handle, filename); } + /** + * Save table values to a file. The file format used is identical to + * that used for SavePersistent. + * @param filename filename + * @param prefix save only keys starting with this prefix + * @throws PersistentException if error saving file + */ + public void saveEntries(String filename, String prefix) throws PersistentException { + NetworkTablesJNI.saveEntries(m_handle, filename, prefix); + } + + /** + * Load table values from a file. The file format used is identical to + * that used for SavePersistent / LoadPersistent. + * @param filename filename + * @param prefix load only keys starting with this prefix + * @return List of warnings (errors result in an exception instead) + * @throws PersistentException if error saving file + */ + public String[] loadEntries(String filename, String prefix) throws PersistentException { + return NetworkTablesJNI.loadEntries(m_handle, filename, prefix); + } + private final ReentrantLock m_loggerLock = new ReentrantLock(); private final Map> m_loggers = new HashMap<>(); private Thread m_loggerThread; diff --git a/src/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java b/src/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java index b8e2452234..818b322ff2 100644 --- a/src/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java +++ b/src/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java @@ -169,6 +169,9 @@ public final class NetworkTablesJNI { public static native void savePersistent(int inst, String filename) throws PersistentException; public static native String[] loadPersistent(int inst, String filename) throws PersistentException; // returns warnings + public static native void saveEntries(int inst, String filename, String prefix) throws PersistentException; + public static native String[] loadEntries(int inst, String filename, String prefix) throws PersistentException; // returns warnings + public static native long now(); public static native int createLoggerPoller(int inst); diff --git a/src/main/native/cpp/Storage.cpp b/src/main/native/cpp/Storage.cpp index 18eec5c74b..7f2083c024 100644 --- a/src/main/native/cpp/Storage.cpp +++ b/src/main/native/cpp/Storage.cpp @@ -948,6 +948,31 @@ bool Storage::GetPersistentEntries( return true; } +bool Storage::GetEntries( + StringRef prefix, + std::vector>>* entries) + const { + // copy values out of storage as quickly as possible so lock isn't held + { + std::lock_guard lock(m_mutex); + entries->reserve(m_entries.size()); + for (auto& i : m_entries) { + Entry* entry = i.getValue(); + // only write values with given prefix + if (!i.getKey().startswith(prefix)) continue; + entries->emplace_back(i.getKey(), entry->value); + } + } + + // sort in name order + std::sort(entries->begin(), entries->end(), + [](const std::pair>& a, + const std::pair>& b) { + return a.first < b.first; + }); + return true; +} + void Storage::CreateRpc(unsigned int local_id, StringRef def, unsigned int rpc_uid) { std::unique_lock lock(m_mutex); diff --git a/src/main/native/cpp/Storage.h b/src/main/native/cpp/Storage.h index 8f7dbc7e29..44aae5af88 100644 --- a/src/main/native/cpp/Storage.h +++ b/src/main/native/cpp/Storage.h @@ -129,12 +129,18 @@ class Storage : public IStorage { StringRef filename, std::function warn) override; + const char* SaveEntries(StringRef filename, StringRef prefix) const; + const char* LoadEntries( + StringRef filename, StringRef prefix, + std::function warn); + // Stream-based save/load functions (exposed for testing purposes). These // implement the guts of the filename-based functions. void SavePersistent(llvm::raw_ostream& os, bool periodic) const; - bool LoadPersistent( - wpi::raw_istream& is, - std::function warn); + bool LoadEntries(wpi::raw_istream& is, StringRef prefix, bool persistent, + std::function warn); + + void SaveEntries(llvm::raw_ostream& os, StringRef prefix) const; // RPC configuration needs to come through here as RPC definitions are // actually special Storage value types. @@ -231,6 +237,9 @@ class Storage : public IStorage { bool periodic, std::vector>>* entries) const; + bool GetEntries(StringRef prefix, + std::vector>>* + entries) const; void SetEntryValueImpl(Entry* entry, std::shared_ptr value, std::unique_lock& lock, bool local); void SetEntryFlagsImpl(Entry* entry, unsigned int flags, diff --git a/src/main/native/cpp/Storage_load.cpp b/src/main/native/cpp/Storage_load.cpp index ee24d933a9..eb2a56e1db 100644 --- a/src/main/native/cpp/Storage_load.cpp +++ b/src/main/native/cpp/Storage_load.cpp @@ -30,7 +30,7 @@ class LoadPersistentImpl { LoadPersistentImpl(wpi::raw_istream& is, WarnFunc warn) : m_is(is), m_warn(warn) {} - bool Load(std::vector* entries); + bool Load(StringRef prefix, std::vector* entries); private: bool ReadLine(); @@ -141,7 +141,7 @@ static llvm::StringRef UnescapeString(llvm::StringRef source, return llvm::StringRef{buf.data(), buf.size()}; } -bool LoadPersistentImpl::Load(std::vector* entries) { +bool LoadPersistentImpl::Load(StringRef prefix, std::vector* entries) { if (!ReadHeader()) return false; // header while (ReadLine()) { @@ -155,7 +155,7 @@ bool LoadPersistentImpl::Load(std::vector* entries) { // name llvm::SmallString<128> buf; llvm::StringRef name = ReadName(buf); - if (name.empty()) continue; + if (name.empty() || !name.startswith(prefix)) continue; // = m_line = m_line.ltrim(" \t"); @@ -361,14 +361,14 @@ std::shared_ptr LoadPersistentImpl::ReadStringArrayValue() { return Value::MakeStringArray(std::move(m_buf_string_array)); } -bool Storage::LoadPersistent( - wpi::raw_istream& is, +bool Storage::LoadEntries( + wpi::raw_istream& is, StringRef prefix, bool persistent, std::function warn) { // entries to add std::vector entries; // load file - if (!LoadPersistentImpl(is, warn).Load(&entries)) return false; + if (!LoadPersistentImpl(is, warn).Load(prefix, &entries)) return false; // copy values into storage as quickly as possible so lock isn't held std::vector> msgs; @@ -378,7 +378,7 @@ bool Storage::LoadPersistent( auto old_value = entry->value; entry->value = i.second; bool was_persist = entry->IsPersistent(); - if (!was_persist) entry->flags |= NT_PERSISTENT; + if (!was_persist && persistent) entry->flags |= NT_PERSISTENT; // if we're the server, assign an id if it doesn't have one if (m_server && entry->id == 0xffff) { @@ -397,7 +397,7 @@ bool Storage::LoadPersistent( if (!was_persist) notify_flags |= NT_NOTIFY_FLAGS; m_notifier.NotifyEntry(entry->local_id, i.first, i.second, notify_flags); - } else if (!was_persist) { + } else if (!was_persist && persistent) { m_notifier.NotifyEntry(entry->local_id, i.first, i.second, NT_NOTIFY_FLAGS | NT_NOTIFY_LOCAL); } @@ -436,6 +436,16 @@ const char* Storage::LoadPersistent( std::error_code ec; wpi::raw_fd_istream is(filename, ec); if (ec.value() != 0) return "could not open file"; - if (!LoadPersistent(is, warn)) return "error reading file"; + if (!LoadEntries(is, "", true, warn)) return "error reading file"; + return nullptr; +} + +const char* Storage::LoadEntries( + StringRef filename, StringRef prefix, + std::function warn) { + std::error_code ec; + wpi::raw_fd_istream is(filename, ec); + if (ec.value() != 0) return "could not open file"; + if (!LoadEntries(is, prefix, false, warn)) return "error reading file"; return nullptr; } diff --git a/src/main/native/cpp/Storage_save.cpp b/src/main/native/cpp/Storage_save.cpp index 4463dbd114..0e72d4db9e 100644 --- a/src/main/native/cpp/Storage_save.cpp +++ b/src/main/native/cpp/Storage_save.cpp @@ -224,3 +224,45 @@ done: if (err && periodic) m_persistent_dirty = true; return err; } + +void Storage::SaveEntries(llvm::raw_ostream& os, StringRef prefix) const { + std::vector entries; + if (!GetEntries(prefix, &entries)) return; + SavePersistentImpl(os).Save(entries); +} + +const char* Storage::SaveEntries(StringRef filename, StringRef prefix) const { + llvm::SmallString<128> fn = filename; + llvm::SmallString<128> tmp = filename; + tmp += ".tmp"; + llvm::SmallString<128> bak = filename; + bak += ".bak"; + + // Get entries before creating file + std::vector entries; + if (!GetEntries(prefix, &entries)) return nullptr; + + // start by writing to temporary file + std::error_code ec; + llvm::raw_fd_ostream os(tmp, ec, llvm::sys::fs::F_Text); + if (ec.value() != 0) { + return "could not open file"; + } + DEBUG("saving file '" << filename << "'"); + SavePersistentImpl(os).Save(entries); + os.close(); + if (os.has_error()) { + std::remove(tmp.c_str()); + return "error saving file"; + } + + // Safely move to real file. We ignore any failures related to the backup. + std::remove(bak.c_str()); + std::rename(fn.c_str(), bak.c_str()); + if (std::rename(tmp.c_str(), fn.c_str()) != 0) { + std::rename(bak.c_str(), fn.c_str()); // attempt to restore backup + return "could not rename temp file to real file"; + } + + return nullptr; +} diff --git a/src/main/native/cpp/jni/NetworkTablesJNI.cpp b/src/main/native/cpp/jni/NetworkTablesJNI.cpp index d94c7c564f..5bb3e99e4a 100644 --- a/src/main/native/cpp/jni/NetworkTablesJNI.cpp +++ b/src/main/native/cpp/jni/NetworkTablesJNI.cpp @@ -1604,6 +1604,59 @@ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI return MakeJStringArray(env, warns); } +/* + * Class: edu_wpi_first_networktables_NetworkTablesJNI + * Method: saveEntries + * Signature: (ILjava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI_saveEntries + (JNIEnv *env, jclass, jint inst, jstring filename, jstring prefix) +{ + if (!filename) { + nullPointerEx.Throw(env, "filename cannot be null"); + return; + } + if (!prefix) { + nullPointerEx.Throw(env, "prefix cannot be null"); + return; + } + const char* err = + nt::SaveEntries(inst, JStringRef{env, filename}, JStringRef{env, prefix}); + if (err) persistentEx.Throw(env, err); +} + +/* + * Class: edu_wpi_first_networktables_NetworkTablesJNI + * Method: loadEntries + * Signature: (ILjava/lang/String;Ljava/lang/String;)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI_loadEntries + (JNIEnv *env, jclass, jint inst, jstring filename, jstring prefix) +{ + if (!filename) { + nullPointerEx.Throw(env, "filename cannot be null"); + return nullptr; + } + if (!prefix) { + nullPointerEx.Throw(env, "prefix cannot be null"); + return nullptr; + } + std::vector warns; + const char* err = + nt::LoadEntries(inst, JStringRef{env, filename}, JStringRef{env, prefix}, + [&](size_t line, const char* msg) { + llvm::SmallString<128> warn; + llvm::raw_svector_ostream oss(warn); + oss << line << ": " << msg; + warns.emplace_back(oss.str()); + }); + if (err) { + persistentEx.Throw(env, err); + return nullptr; + } + return MakeJStringArray(env, warns); +} + /* * Class: edu_wpi_first_networktables_NetworkTablesJNI * Method: now diff --git a/src/main/native/cpp/networktables/NetworkTable.cpp b/src/main/native/cpp/networktables/NetworkTable.cpp index 3e8cfd5d73..d8f886a670 100644 --- a/src/main/native/cpp/networktables/NetworkTable.cpp +++ b/src/main/native/cpp/networktables/NetworkTable.cpp @@ -460,3 +460,17 @@ std::shared_ptr NetworkTable::GetValue(StringRef key) const { } StringRef NetworkTable::GetPath() const { return m_path; } + +const char* NetworkTable::SaveEntries(StringRef filename) const { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + return nt::SaveEntries(m_inst, filename, path); +} + +const char* NetworkTable::LoadEntries( + StringRef filename, + std::function warn) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + return nt::LoadEntries(m_inst, filename, path, warn); +} diff --git a/src/main/native/cpp/ntcore_c.cpp b/src/main/native/cpp/ntcore_c.cpp index 533107c855..68df49c25a 100644 --- a/src/main/native/cpp/ntcore_c.cpp +++ b/src/main/native/cpp/ntcore_c.cpp @@ -633,7 +633,7 @@ struct NT_ConnectionInfo* NT_GetConnections(NT_Inst inst, size_t* count) { } /* - * Persistent Functions + * File Save/Load Functions */ const char* NT_SavePersistent(NT_Inst inst, const char* filename) { @@ -645,6 +645,17 @@ const char* NT_LoadPersistent(NT_Inst inst, const char* filename, return nt::LoadPersistent(inst, filename, warn); } +const char* NT_SaveEntries(NT_Inst inst, const char* filename, + const char* prefix, size_t prefix_len) { + return nt::SaveEntries(inst, filename, StringRef(prefix, prefix_len)); +} + +const char* NT_LoadEntries(NT_Inst inst, const char* filename, + const char* prefix, size_t prefix_len, + void (*warn)(size_t line, const char* msg)) { + return nt::LoadEntries(inst, filename, StringRef(prefix, prefix_len), warn); +} + /* * Utility Functions */ diff --git a/src/main/native/cpp/ntcore_cpp.cpp b/src/main/native/cpp/ntcore_cpp.cpp index 9d0dbe0d56..6e13f64a0b 100644 --- a/src/main/native/cpp/ntcore_cpp.cpp +++ b/src/main/native/cpp/ntcore_cpp.cpp @@ -936,6 +936,22 @@ const char* LoadPersistent( return ii->storage.LoadPersistent(filename, warn); } +const char* SaveEntries(NT_Inst inst, StringRef filename, StringRef prefix) { + auto ii = InstanceImpl::Get(Handle{inst}.GetTypedInst(Handle::kInstance)); + if (!ii) return "invalid instance handle"; + + return ii->storage.SaveEntries(filename, prefix); +} + +const char* LoadEntries( + NT_Inst inst, StringRef filename, StringRef prefix, + std::function warn) { + auto ii = InstanceImpl::Get(Handle{inst}.GetTypedInst(Handle::kInstance)); + if (!ii) return "invalid instance handle"; + + return ii->storage.LoadEntries(filename, prefix, warn); +} + void SetLogger(LogFunc func, unsigned int min_level) { auto ii = InstanceImpl::GetDefault(); static std::mutex mutex; diff --git a/src/main/native/include/networktables/NetworkTable.h b/src/main/native/include/networktables/NetworkTable.h index f8d629804a..b3a8f2fa05 100644 --- a/src/main/native/include/networktables/NetworkTable.h +++ b/src/main/native/include/networktables/NetworkTable.h @@ -644,6 +644,25 @@ class NetworkTable final : public ITable { * @return The path (e.g "", "/foo"). */ StringRef GetPath() const override; + + /** + * Save table values to a file. The file format used is identical to + * that used for SavePersistent. + * @param filename filename + * @return error string, or nullptr if successful + */ + const char* SaveEntries(StringRef filename) const; + + /** + * Load table values from a file. The file format used is identical to + * that used for SavePersistent / LoadPersistent. + * @param filename filename + * @param warn callback function for warnings + * @return error string, or nullptr if successful + */ + const char* LoadEntries( + StringRef filename, + std::function warn); }; #ifdef __GNUC__ diff --git a/src/main/native/include/networktables/NetworkTableInstance.h b/src/main/native/include/networktables/NetworkTableInstance.h index 03a30d147c..8d75d3e4ab 100644 --- a/src/main/native/include/networktables/NetworkTableInstance.h +++ b/src/main/native/include/networktables/NetworkTableInstance.h @@ -430,7 +430,7 @@ class NetworkTableInstance final { /** @} */ /** - * @defgroup PersistentFunctions Persistent Functions + * @defgroup FileFunctions File Save/Load Functions * @{ */ @@ -455,6 +455,27 @@ class NetworkTableInstance final { StringRef filename, std::function warn); + /** + * Save table values to a file. The file format used is identical to + * that used for SavePersistent. + * @param filename filename + * @param prefix save only keys starting with this prefix + * @return error string, or nullptr if successful + */ + const char* SaveEntries(StringRef filename, StringRef prefix) const; + + /** + * Load table values from a file. The file format used is identical to + * that used for SavePersistent / LoadPersistent. + * @param filename filename + * @param prefix load only keys starting with this prefix + * @param warn callback function for warnings + * @return error string, or nullptr if successful + */ + const char* LoadEntries( + StringRef filename, StringRef prefix, + std::function warn); + /** @} */ /** diff --git a/src/main/native/include/networktables/NetworkTableInstance.inl b/src/main/native/include/networktables/NetworkTableInstance.inl index 09c1de64c8..82403f11b8 100644 --- a/src/main/native/include/networktables/NetworkTableInstance.inl +++ b/src/main/native/include/networktables/NetworkTableInstance.inl @@ -157,6 +157,17 @@ inline const char* NetworkTableInstance::LoadPersistent( return ::nt::LoadPersistent(m_handle, filename, warn); } +inline const char* NetworkTableInstance::SaveEntries( + StringRef filename, StringRef prefix) const { + return ::nt::SaveEntries(m_handle, filename, prefix); +} + +inline const char* NetworkTableInstance::LoadEntries( + StringRef filename, StringRef prefix, + std::function warn) { + return ::nt::LoadEntries(m_handle, filename, prefix, warn); +} + inline NT_Logger NetworkTableInstance::AddLogger( std::function func, unsigned int min_level, unsigned int max_level) { diff --git a/src/main/native/include/ntcore_c.h b/src/main/native/include/ntcore_c.h index a4b9456223..324d6579be 100644 --- a/src/main/native/include/ntcore_c.h +++ b/src/main/native/include/ntcore_c.h @@ -1114,7 +1114,7 @@ NT_Bool NT_IsConnected(NT_Inst inst); /** @} */ /** - * @defgroup PersistentFunctions Persistent Functions + * @defgroup FileFunctions File Save/Load Functions * @{ */ @@ -1140,6 +1140,32 @@ const char* NT_SavePersistent(NT_Inst inst, const char* filename); const char* NT_LoadPersistent(NT_Inst inst, const char* filename, void (*warn)(size_t line, const char* msg)); +/** + * Save table values to a file. The file format used is identical to + * that used for SavePersistent. + * @param inst instance handle + * @param filename filename + * @param prefix save only keys starting with this prefix + * @param prefix_len length of prefix in bytes + * @return error string, or nullptr if successful + */ +const char* NT_SaveEntries(NT_Inst inst, const char* filename, + const char* prefix, size_t prefix_len); + +/** + * Load table values from a file. The file format used is identical to + * that used for SavePersistent / LoadPersistent. + * @param inst instance handle + * @param filename filename + * @param prefix load only keys starting with this prefix + * @param prefix_len length of prefix in bytes + * @param warn callback function for warnings + * @return error string, or nullptr if successful + */ +const char* NT_LoadEntries(NT_Inst inst, const char* filename, + const char* prefix, size_t prefix_len, + void (*warn)(size_t line, const char* msg)); + /** @} */ /** diff --git a/src/main/native/include/ntcore_cpp.h b/src/main/native/include/ntcore_cpp.h index e7b1c4336f..098b3fb0a6 100644 --- a/src/main/native/include/ntcore_cpp.h +++ b/src/main/native/include/ntcore_cpp.h @@ -1272,7 +1272,7 @@ bool IsConnected(NT_Inst inst); /** @} */ /** - * @defgroup PersistentFunctions Persistent Functions + * @defgroup FileFunctions File Save/Load Functions * @{ */ @@ -1313,6 +1313,28 @@ const char* LoadPersistent( NT_Inst inst, StringRef filename, std::function warn); +/** + * Save table values to a file. The file format used is identical to + * that used for SavePersistent. + * @param inst instance handle + * @param filename filename + * @param prefix save only keys starting with this prefix + * @return error string, or nullptr if successful + */ +const char* SaveEntries(NT_Inst inst, StringRef filename, StringRef prefix); + +/** + * Load table values from a file. The file format used is identical to + * that used for SavePersistent / LoadPersistent. + * @param inst instance handle + * @param filename filename + * @param prefix load only keys starting with this prefix + * @param warn callback function for warnings + * @return error string, or nullptr if successful + */ +const char* LoadEntries(NT_Inst inst, StringRef filename, StringRef prefix, + std::function warn); + /** @} */ /** diff --git a/src/test/native/cpp/StorageTest.cpp b/src/test/native/cpp/StorageTest.cpp index 8c7c3821fb..2241ed8ba3 100644 --- a/src/test/native/cpp/StorageTest.cpp +++ b/src/test/native/cpp/StorageTest.cpp @@ -624,14 +624,14 @@ TEST_P(StorageTestEmpty, LoadPersistentBadHeader) { EXPECT_CALL( warn, Warn(1, llvm::StringRef("header line mismatch, ignoring rest of file"))); - EXPECT_FALSE(storage.LoadPersistent(iss, warn_func)); + EXPECT_FALSE(storage.LoadEntries(iss, "", true, warn_func)); wpi::raw_mem_istream iss2("[NetworkTables"); EXPECT_CALL( warn, Warn(1, llvm::StringRef("header line mismatch, ignoring rest of file"))); - EXPECT_FALSE(storage.LoadPersistent(iss2, warn_func)); + EXPECT_FALSE(storage.LoadEntries(iss2, "", true, warn_func)); EXPECT_TRUE(entries().empty()); EXPECT_TRUE(idmap().empty()); } @@ -644,7 +644,7 @@ TEST_P(StorageTestEmpty, LoadPersistentCommentHeader) { wpi::raw_mem_istream iss( "\n; comment\n# comment\n[NetworkTables Storage 3.0]\n"); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); EXPECT_TRUE(entries().empty()); EXPECT_TRUE(idmap().empty()); } @@ -656,7 +656,7 @@ TEST_P(StorageTestEmpty, LoadPersistentEmptyName) { }; wpi::raw_mem_istream iss("[NetworkTables Storage 3.0]\nboolean \"\"=true\n"); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); EXPECT_TRUE(entries().empty()); EXPECT_TRUE(idmap().empty()); } @@ -680,7 +680,7 @@ TEST_P(StorageTestEmpty, LoadPersistentAssign) { wpi::raw_mem_istream iss( "[NetworkTables Storage 3.0]\nboolean \"foo\"=true\n"); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); auto entry = GetEntry("foo"); EXPECT_EQ(*value, *entry->value); EXPECT_EQ(NT_PERSISTENT, entry->flags); @@ -705,7 +705,7 @@ TEST_P(StorageTestPopulated, LoadPersistentUpdateFlags) { wpi::raw_mem_istream iss( "[NetworkTables Storage 3.0]\ndouble \"foo2\"=0.0\n"); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); auto entry = GetEntry("foo2"); EXPECT_EQ(*Value::MakeDouble(0.0), *entry->value); EXPECT_EQ(NT_PERSISTENT, entry->flags); @@ -734,7 +734,7 @@ TEST_P(StorageTestPopulated, LoadPersistentUpdateValue) { wpi::raw_mem_istream iss( "[NetworkTables Storage 3.0]\ndouble \"foo2\"=1.0\n"); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); auto entry = GetEntry("foo2"); EXPECT_EQ(*value, *entry->value); EXPECT_EQ(NT_PERSISTENT, entry->flags); @@ -770,7 +770,7 @@ TEST_P(StorageTestPopulated, LoadPersistentUpdateValueFlags) { wpi::raw_mem_istream iss( "[NetworkTables Storage 3.0]\ndouble \"foo2\"=1.0\n"); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); auto entry = GetEntry("foo2"); EXPECT_EQ(*value, *entry->value); EXPECT_EQ(NT_PERSISTENT, entry->flags); @@ -817,7 +817,7 @@ TEST_P(StorageTestEmpty, LoadPersistent) { .Times(22); wpi::raw_mem_istream iss(in); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); ASSERT_EQ(22u, entries().size()); EXPECT_EQ(*Value::MakeBoolean(true), *storage.GetEntryValue("boolean/true")); @@ -870,7 +870,7 @@ TEST_P(StorageTestEmpty, LoadPersistentWarn) { EXPECT_CALL( warn, Warn(2, llvm::StringRef( "unrecognized boolean value, not 'true' or 'false'"))); - EXPECT_TRUE(storage.LoadPersistent(iss, warn_func)); + EXPECT_TRUE(storage.LoadEntries(iss, "", true, warn_func)); EXPECT_TRUE(entries().empty()); EXPECT_TRUE(idmap().empty());