pw_string: add pw::string::Copy methods

Adds pw::string::Copy helper methods as a safer alternative to
std::strncpy which unfortunately does not always null terminate.

In addition, the existing StringCopy methods are renamed to
StringOrNullCopy to denote that they support nullptr source strings
unlike pw::string::Copy.

Change-Id: I046c12da02721c5ad2f6601b9ac742d9dfa90c71
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/42931
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_string/type_to_string_test.cc b/pw_string/type_to_string_test.cc
index 4deb657..ffadc27 100644
--- a/pw_string/type_to_string_test.cc
+++ b/pw_string/type_to_string_test.cc
@@ -407,71 +407,84 @@
   EXPECT_STREQ("", buffer_);
 }
 
-class CopyStringTest : public TestWithBuffer {};
+class CopyStringOrNullTest : public TestWithBuffer {};
 
 using namespace std::literals::string_view_literals;
 
-TEST_F(CopyStringTest, EmptyStringView_WritesNullTerminator) {
-  EXPECT_EQ(0u, CopyString("", buffer_).size());
+TEST_F(CopyStringOrNullTest, NullSource_WritesNullPointerString) {
+  EXPECT_EQ(kNullPointerString.size(),
+            CopyStringOrNull(nullptr, buffer_).size());
+  EXPECT_EQ(kNullPointerString, buffer_);
+}
+
+TEST_F(CopyStringOrNullTest, EmptyStringView_WritesNullTerminator) {
+  EXPECT_EQ(0u, CopyStringOrNull("", buffer_).size());
   EXPECT_EQ('\0', buffer_[0]);
 }
 
-TEST_F(CopyStringTest, EmptyBuffer_WritesNothing) {
-  auto result = CopyString("Hello", std::span(buffer_, 0));
+TEST_F(CopyStringOrNullTest, EmptyBuffer_WritesNothing) {
+  auto result = CopyStringOrNull("Hello", std::span(buffer_, 0));
   EXPECT_EQ(0u, result.size());
   EXPECT_FALSE(result.ok());
   EXPECT_STREQ(kStartingString, buffer_);
 }
 
-TEST_F(CopyStringTest, TooSmall_Truncates) {
-  auto result = CopyString("Hi!", std::span(buffer_, 3));
+TEST_F(CopyStringOrNullTest, TooSmall_Truncates) {
+  auto result = CopyStringOrNull("Hi!", std::span(buffer_, 3));
   EXPECT_EQ(2u, result.size());
   EXPECT_FALSE(result.ok());
   EXPECT_STREQ("Hi", buffer_);
 }
 
-TEST_F(CopyStringTest, ExactFit) {
-  auto result = CopyString("Hi!", std::span(buffer_, 4));
+TEST_F(CopyStringOrNullTest, ExactFit) {
+  auto result = CopyStringOrNull("Hi!", std::span(buffer_, 4));
   EXPECT_EQ(3u, result.size());
   EXPECT_TRUE(result.ok());
   EXPECT_STREQ("Hi!", buffer_);
 }
 
-TEST_F(CopyStringTest, NullTerminatorsInString) {
-  ASSERT_EQ(4u, CopyString("\0!\0\0"sv, std::span(buffer_, 5)).size());
+TEST_F(CopyStringOrNullTest, NullTerminatorsInString) {
+  ASSERT_EQ(4u, CopyStringOrNull("\0!\0\0"sv, std::span(buffer_, 5)).size());
   EXPECT_EQ("\0!\0\0"sv, std::string_view(buffer_, 4));
 }
 
-class CopyEntireStringTest : public TestWithBuffer {};
+class CopyEntireStringOrNullTest : public TestWithBuffer {};
 
-TEST_F(CopyEntireStringTest, EmptyStringView_WritesNullTerminator) {
-  EXPECT_EQ(0u, CopyEntireString("", buffer_).size());
+TEST_F(CopyEntireStringOrNullTest, NullSource_WritesNullPointerString) {
+  EXPECT_EQ(kNullPointerString.size(),
+            CopyEntireStringOrNull(nullptr, buffer_).size());
+  EXPECT_EQ(kNullPointerString, buffer_);
+}
+
+TEST_F(CopyEntireStringOrNullTest, EmptyStringView_WritesNullTerminator) {
+  EXPECT_EQ(0u, CopyEntireStringOrNull("", buffer_).size());
   EXPECT_EQ('\0', buffer_[0]);
 }
 
-TEST_F(CopyEntireStringTest, EmptyBuffer_WritesNothing) {
-  auto result = CopyEntireString("Hello", std::span(buffer_, 0));
+TEST_F(CopyEntireStringOrNullTest, EmptyBuffer_WritesNothing) {
+  auto result = CopyEntireStringOrNull("Hello", std::span(buffer_, 0));
   EXPECT_EQ(0u, result.size());
   EXPECT_FALSE(result.ok());
   EXPECT_STREQ(kStartingString, buffer_);
 }
 
-TEST_F(CopyEntireStringTest, TooSmall_WritesNothing) {
-  auto result = CopyEntireString("Hi!", std::span(buffer_, 3));
+TEST_F(CopyEntireStringOrNullTest, TooSmall_WritesNothing) {
+  auto result = CopyEntireStringOrNull("Hi!", std::span(buffer_, 3));
   EXPECT_EQ(0u, result.size());
   EXPECT_FALSE(result.ok());
   EXPECT_STREQ("", buffer_);
 }
 
-TEST_F(CopyEntireStringTest, ExactFit) {
-  auto result = CopyEntireString("Hi!", std::span(buffer_, 4));
+TEST_F(CopyEntireStringOrNullTest, ExactFit) {
+  auto result = CopyEntireStringOrNull("Hi!", std::span(buffer_, 4));
   EXPECT_EQ(3u, result.size());
   EXPECT_TRUE(result.ok());
   EXPECT_STREQ("Hi!", buffer_);
 }
 
-TEST_F(CopyEntireStringTest, NullTerminatorsInString) {
-  ASSERT_EQ(4u, CopyEntireString("\0!\0\0"sv, std::span(buffer_, 5)).size());
+TEST_F(CopyEntireStringOrNullTest, NullTerminatorsInString) {
+  ASSERT_EQ(4u,
+            CopyEntireStringOrNull("\0!\0\0"sv, std::span(buffer_, 5)).size());
   EXPECT_EQ("\0!\0\0"sv, std::string_view(buffer_, 4));
 }