psutils: Move functions from updater to utils

Move common, utility functions from updater.*pp to utils.*pp.  This will
enable those functions to be used by other command line options in the
psutils tool.

Modify --get-version and --get-model to use the new utility functions.

Also update --get-version to provide a single getVersion() function that
handles the existence of the psu.json file as a low-level implementation
detail.

Tested:
* Verified all automated tests run successfully
* Verified --get-version still works
  * With psu.json file
  * Without psu.json file
* Verified --get-model still works
  * With psu.json file
  * Without psu.json file
* Verified --update still gets correct device path, device name, and I2C
  bus/address from functions that moved to utils.*pp
* The complete test plan is available at
  https://gist.github.com/smccarney/c049e24655d32e22cab9d521d145774a

Change-Id: I51ceca10957dc9a924d0d7516dc29632a6ed82d3
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
diff --git a/tools/power-utils/test/test_utils.cpp b/tools/power-utils/test/test_utils.cpp
new file mode 100644
index 0000000..b88d024
--- /dev/null
+++ b/tools/power-utils/test/test_utils.cpp
@@ -0,0 +1,50 @@
+/**
+ * Copyright © 2024 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../utils.hpp"
+
+#include <stdexcept>
+#include <tuple>
+
+#include <gtest/gtest.h>
+
+using namespace utils;
+
+TEST(TestUtils, getDeviceName)
+{
+    auto ret = getDeviceName("");
+    EXPECT_TRUE(ret.empty());
+
+    ret = getDeviceName("/sys/bus/i2c/devices/3-0069");
+    EXPECT_EQ("3-0069", ret);
+
+    ret = getDeviceName("/sys/bus/i2c/devices/3-0069/");
+    EXPECT_EQ("3-0069", ret);
+}
+
+TEST(TestUtils, parseDeviceName)
+{
+    auto [id, addr] = parseDeviceName("3-0068");
+    EXPECT_EQ(3, id);
+    EXPECT_EQ(0x68, addr);
+
+    std::tie(id, addr) = parseDeviceName("11-0069");
+    EXPECT_EQ(11, id);
+    EXPECT_EQ(0x69, addr);
+
+    EXPECT_THROW(parseDeviceName("no-number"), std::invalid_argument);
+
+    EXPECT_DEATH(parseDeviceName("invalid"), "");
+}