Merge "fastboot: Introduce ParseNetworkSerial unit tests"
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 208b1a8..430ff14 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -317,28 +317,7 @@
     return -1;
 }
 
-struct NetworkSerial {
-    Socket::Protocol protocol;
-    std::string address;
-    int port;
-};
-
-class ParseNetworkAddressError {
-  public:
-    enum Type { WRONG_PREFIX = 1, WRONG_ADDRESS = 2 };
-
-    ParseNetworkAddressError(Type&& type) : type_(std::forward<Type>(type)) {}
-
-    Type value() const { return type_; }
-    operator Type() const { return value(); }
-    std::string print() const { return ""; }
-
-  private:
-    Type type_;
-};
-
-static Result<NetworkSerial, ParseNetworkAddressError> ParseNetworkSerial(
-        const std::string& serial) {
+Result<NetworkSerial, FastbootError> ParseNetworkSerial(const std::string& serial) {
     Socket::Protocol protocol;
     const char* net_address = nullptr;
     int port = 0;
@@ -352,7 +331,7 @@
         net_address = serial.c_str() + strlen("udp:");
         port = udp::kDefaultPort;
     } else {
-        return Error<ParseNetworkAddressError>(ParseNetworkAddressError::Type::WRONG_PREFIX)
+        return Error<FastbootError>(FastbootError::Type::NETWORK_SERIAL_WRONG_PREFIX)
                << "protocol prefix ('tcp:' or 'udp:') is missed: " << serial << ". "
                << "Expected address format:\n"
                << "<protocol>:<address>:<port> (tcp:localhost:5554)";
@@ -361,7 +340,7 @@
     std::string error;
     std::string host;
     if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) {
-        return Error<ParseNetworkAddressError>(ParseNetworkAddressError::Type::WRONG_ADDRESS)
+        return Error<FastbootError>(FastbootError::Type::NETWORK_SERIAL_WRONG_ADDRESS)
                << "invalid network address '" << net_address << "': " << error;
     }
 
@@ -380,8 +359,7 @@
 // object, and the caller should not attempt to delete the returned Transport.
 static Transport* open_device(const char* local_serial, bool wait_for_device = true,
                               bool announce = true) {
-    const Result<NetworkSerial, ParseNetworkAddressError> network_serial =
-            ParseNetworkSerial(local_serial);
+    const Result<NetworkSerial, FastbootError> network_serial = ParseNetworkSerial(local_serial);
 
     Transport* transport = nullptr;
     while (true) {
@@ -398,7 +376,8 @@
             if (transport == nullptr && announce) {
                 LOG(ERROR) << "error: " << error;
             }
-        } else if (network_serial.error().code() == ParseNetworkAddressError::Type::WRONG_PREFIX) {
+        } else if (network_serial.error().code() ==
+                   FastbootError::Type::NETWORK_SERIAL_WRONG_PREFIX) {
             // WRONG_PREFIX is special because it happens when user wants to communicate with USB
             // device
             transport = usb_open(match_fastboot(local_serial));
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index c4366a9..09666aa 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -33,6 +33,10 @@
 
 #include <bootimg.h>
 
+#include "result.h"
+#include "socket.h"
+#include "util.h"
+
 class FastBootTool {
   public:
     int Main(int argc, char* argv[]);
@@ -89,3 +93,11 @@
 std::string find_item(const std::string& item);
 void reboot_to_userspace_fastboot();
 void syntax_error(const char* fmt, ...);
+
+struct NetworkSerial {
+    Socket::Protocol protocol;
+    std::string address;
+    int port;
+};
+
+Result<NetworkSerial, FastbootError> ParseNetworkSerial(const std::string& serial);
\ No newline at end of file
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
index 79f37fd..1863e95 100644
--- a/fastboot/fastboot_test.cpp
+++ b/fastboot/fastboot_test.cpp
@@ -203,6 +203,54 @@
     ParseRequirementLineTestMalformed("require-for-product :");
 }
 
+static void ParseNetworkSerialTest(const std::string& description, const std::string& serial,
+                                   const std::string& expected_address,
+                                   const Socket::Protocol expected_protocol,
+                                   const int expected_port) {
+    const Result<NetworkSerial, FastbootError> parsed = ParseNetworkSerial(serial);
+
+    ASSERT_RESULT_OK(parsed) << description;
+
+    const NetworkSerial network_serial = parsed.value();
+    EXPECT_EQ(network_serial.address, expected_address) << description;
+    EXPECT_EQ(network_serial.protocol, expected_protocol) << description;
+    EXPECT_EQ(network_serial.port, expected_port) << description;
+}
+
+static void ParseNetworkSerialNegativeTest(const std::string& description,
+                                           const std::string& serial,
+                                           const FastbootError::Type expected_error) {
+    const Result<NetworkSerial, FastbootError> parsed = ParseNetworkSerial(serial);
+
+    EXPECT_FALSE(parsed.ok()) << description;
+    EXPECT_EQ(parsed.error().code(), expected_error) << description;
+}
+
+TEST(FastBoot, ParseNetworkSerial) {
+    ParseNetworkSerialTest("tcp IPv4 parsed", "tcp:192.168.1.0", "192.168.1.0",
+                           Socket::Protocol::kTcp, 5554);
+
+    ParseNetworkSerialTest("udp IPv4 parsed", "udp:192.168.1.0", "192.168.1.0",
+                           Socket::Protocol::kUdp, 5554);
+
+    ParseNetworkSerialTest("port parsed", "udp:192.168.1.0:9999", "192.168.1.0",
+                           Socket::Protocol::kUdp, 9999);
+
+    ParseNetworkSerialTest("IPv6 parsed", "tcp:2001:db8:3333:4444:5555:6666:7777:8888",
+                           "2001:db8:3333:4444:5555:6666:7777:8888", Socket::Protocol::kTcp, 5554);
+
+    ParseNetworkSerialTest("empty IPv6 parsed", "tcp:::", "::", Socket::Protocol::kTcp, 5554);
+
+    ParseNetworkSerialNegativeTest("wrong prefix", "tcpa:192.168.1.0",
+                                   FastbootError::Type::NETWORK_SERIAL_WRONG_PREFIX);
+
+    ParseNetworkSerialNegativeTest("no prefix", "192.168.1.0",
+                                   FastbootError::Type::NETWORK_SERIAL_WRONG_PREFIX);
+
+    ParseNetworkSerialNegativeTest("wrong port", "tcp:192.168.1.0:-1",
+                                   FastbootError::Type::NETWORK_SERIAL_WRONG_ADDRESS);
+}
+
 int main(int argc, char* argv[]) {
     ::testing::InitGoogleTest(&argc, argv);
     android::base::InitLogging(argv);
diff --git a/fastboot/result.h b/fastboot/result.h
new file mode 100644
index 0000000..dfa5e10
--- /dev/null
+++ b/fastboot/result.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <android-base/result.h>
+
+#include "util.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+using android::base::ResultError;
+
+class FastbootError {
+  public:
+    enum Type { NETWORK_SERIAL_WRONG_PREFIX = 1, NETWORK_SERIAL_WRONG_ADDRESS = 2 };
+
+    FastbootError(Type&& type) : type_(std::forward<Type>(type)) {}
+
+    Type value() const { return type_; }
+    operator Type() const { return value(); }
+    std::string print() const { return ""; }
+
+  private:
+    Type type_;
+};
+
+template <typename T, typename U>
+inline T Expect(Result<T, U> r) {
+    if (r.ok()) {
+        return r.value();
+    }
+
+    die(r.error().message());
+
+    return r.value();
+}
\ No newline at end of file
diff --git a/fastboot/util.h b/fastboot/util.h
index 8a79e13..290d0d5 100644
--- a/fastboot/util.h
+++ b/fastboot/util.h
@@ -6,29 +6,11 @@
 #include <string>
 #include <vector>
 
-#include <android-base/logging.h>
-#include <android-base/result.h>
 #include <android-base/unique_fd.h>
 #include <bootimg.h>
 #include <liblp/liblp.h>
 #include <sparse/sparse.h>
 
-using android::base::ErrnoError;
-using android::base::Error;
-using android::base::Result;
-using android::base::ResultError;
-
-template <typename T, typename U>
-inline T Expect(Result<T, U> r) {
-    if (r.ok()) {
-        return r.value();
-    }
-
-    LOG(FATAL) << r.error().message();
-
-    return r.value();
-}
-
 using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
 
 /* util stuff */