dhcp client: add class DHCPOptionWriter

Add class DHCPOptionsWriter for writing dhcp options.
Also add the corresponding unittests.
while there, change the variable name from 'option_number'
to 'option_code' for better readability.

Bug: 25642025
TEST=compile and unittests
Change-Id: I6410651d32525760405df427b38c961ce106293f
diff --git a/dhcp_client.gyp b/dhcp_client.gyp
index 447a3f0..474c029 100644
--- a/dhcp_client.gyp
+++ b/dhcp_client.gyp
@@ -60,6 +60,7 @@
         'device_info.cc',
         'dhcp_message.cc',
         'dhcp_options_parser.cc',
+        'dhcp_options_writer.cc',
         'dhcpv4.cc',
         'message_loop_event_dispatcher.cc',
         'manager.cc',
@@ -87,6 +88,7 @@
             'device_info_unittest.cc',
             'dhcp_message_unittest.cc',
             'dhcp_options_parser_unittest.cc',
+            'dhcp_options_writer_unittest.cc',
             'testrunner.cc',
           ],
         },
diff --git a/dhcp_message.cc b/dhcp_message.cc
index 20100c8..cfb9433 100644
--- a/dhcp_message.cc
+++ b/dhcp_message.cc
@@ -27,6 +27,8 @@
 
 #include <base/logging.h>
 
+#include "dhcp_client/dhcp_options.h"
+
 using shill::ByteString;
 
 namespace dhcp_client {
@@ -35,23 +37,12 @@
 const int kClientHardwareAddressLength = 16;
 const int kServerNameLength = 64;
 const int kBootFileLength = 128;
-const int kDHCPOptionLength = 312;
 const uint32_t kMagicCookie = 0x63825363;
 const size_t kDHCPMessageMaxLength = 548;
 const size_t kDHCPMessageMinLength = 236;
 const uint8_t kDHCPMessageBootRequest = 1;
 const uint8_t kDHCPMessageBootReply = 2;
 
-// Constants for DHCP options.
-const uint8_t kDHCPOptionPad = 0;
-const uint8_t kDHCPOptionDNSServer = 6;
-const uint8_t kDHCPOptionLeaseTime = 51;
-const uint8_t kDHCPOptionMessageType = 53;
-const uint8_t kDHCPOptionServerIdentifier = 54;
-const uint8_t kDHCPOptionRenewalTime = 58;
-const uint8_t kDHCPOptionRebindingTime = 59;
-const uint8_t kDHCPOptionEnd = 255;
-
 // Follow the naming in rfc2131 for this struct.
 struct __attribute__((__packed__)) RawDHCPMessage {
   uint8_t op;
@@ -150,11 +141,11 @@
   const uint8_t* end_ptr = options + options_length;
   std::set<uint8_t> options_set;
   while (ptr < end_ptr) {
-    uint8_t option_number = *ptr++;
-    int option_number_int = static_cast<int>(option_number);
-    if (option_number == kDHCPOptionPad) {
+    uint8_t option_code = *ptr++;
+    int option_code_int = static_cast<int>(option_code);
+    if (option_code == kDHCPOptionPad) {
       continue;
-    } else if (option_number == kDHCPOptionEnd) {
+    } else if (option_code == kDHCPOptionEnd) {
       // We reach the end of the option field.
       // A DHCP message must have option 53: DHCP Message Type.
       if (options_set.find(kDHCPOptionMessageType) == options_set.end()) {
@@ -165,29 +156,29 @@
     }
     if (ptr >= end_ptr) {
       LOG(ERROR) << "Failed to decode dhcp options, no option length field"
-                    "for option: " << option_number_int;
+                    "for option: " << option_code_int;
       return false;
     }
     uint8_t option_length = *ptr++;
     if (ptr + option_length >= end_ptr) {
       LOG(ERROR) << "Failed to decode dhcp options, invalid option length field"
-                    "for option: " << option_number_int;
+                    "for option: " << option_code_int;
       return false;
     }
-    if (options_set.find(option_number) != options_set.end()) {
-      LOG(ERROR) << "Found repeated DHCP option: " << option_number_int;
+    if (options_set.find(option_code) != options_set.end()) {
+      LOG(ERROR) << "Found repeated DHCP option: " << option_code_int;
       return false;
     }
     // Here we find a valid DHCP option.
-    auto it = options_map_.find(option_number);
+    auto it = options_map_.find(option_code);
     if (it != options_map_.end()) {
       ParserContext* context = &(it->second);
       if (!context->parser->GetOption(ptr, option_length, context->output)) {
         return false;
       }
-      options_set.insert(option_number);
+      options_set.insert(option_code);
     } else {
-      DLOG(INFO) << "Ignore DHCP option: " << option_number_int;
+      DLOG(INFO) << "Ignore DHCP option: " << option_code_int;
     }
     // Move to next tag.
     ptr += option_length;
diff --git a/dhcp_message.h b/dhcp_message.h
index f8d2634..acd5db8 100644
--- a/dhcp_message.h
+++ b/dhcp_message.h
@@ -23,10 +23,10 @@
 #include <vector>
 
 #include <base/macros.h>
-
-#include <dhcp_client/dhcp_options_parser.h>
 #include <shill/net/byte_string.h>
 
+#include "dhcp_client/dhcp_options_parser.h"
+
 namespace dhcp_client {
 
 static const uint8_t kDHCPMessageTypeDiscover = 1;
diff --git a/dhcp_message_unittest.cc b/dhcp_message_unittest.cc
index 4a7f163..2b9b9c8 100644
--- a/dhcp_message_unittest.cc
+++ b/dhcp_message_unittest.cc
@@ -14,7 +14,7 @@
 // limitations under the License.
 //
 
-#include <dhcp_client/dhcp_message.h>
+#include "dhcp_client/dhcp_message.h"
 
 #include <gtest/gtest.h>
 
diff --git a/dhcp_options.h b/dhcp_options.h
new file mode 100644
index 0000000..48733c7
--- /dev/null
+++ b/dhcp_options.h
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2015 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.
+//
+
+#ifndef DHCP_CLIENT_DHCP_OPTIONS_H_
+#define DHCP_CLIENT_DHCP_OPTIONS_H_
+
+namespace dhcp_client {
+// Constants for DHCP options.
+const uint8_t kDHCPOptionPad = 0;
+const uint8_t kDHCPOptionDNSServer = 6;
+const uint8_t kDHCPOptionLeaseTime = 51;
+const uint8_t kDHCPOptionMessageType = 53;
+const uint8_t kDHCPOptionServerIdentifier = 54;
+const uint8_t kDHCPOptionRenewalTime = 58;
+const uint8_t kDHCPOptionRebindingTime = 59;
+const uint8_t kDHCPOptionEnd = 255;
+
+const int kDHCPOptionLength = 312;
+}  // namespace dhcp_client
+
+#endif  // DHCP_CLIENT_DHCP_OPTIONS_H_
diff --git a/dhcp_options_writer.cc b/dhcp_options_writer.cc
new file mode 100644
index 0000000..e6bea8c
--- /dev/null
+++ b/dhcp_options_writer.cc
@@ -0,0 +1,163 @@
+//
+// Copyright (C) 2015 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.
+//
+
+#include "dhcp_client/dhcp_options_writer.h"
+
+#include <netinet/in.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/macros.h>
+
+#include "dhcp_client/dhcp_options.h"
+
+namespace {
+base::LazyInstance<dhcp_client::DHCPOptionsWriter> g_dhcp_options_writer
+    = LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+namespace dhcp_client {
+
+DHCPOptionsWriter* DHCPOptionsWriter::GetInstance() {
+  return g_dhcp_options_writer.Pointer();
+}
+
+int DHCPOptionsWriter::WriteUInt8Option(uint8_t* buffer,
+                                        uint8_t option_code,
+                                        uint8_t value) {
+  *buffer++ = option_code;
+  *buffer++ = sizeof(uint8_t);
+  *buffer++ = value;
+  return sizeof(uint8_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteUInt16Option(uint8_t* buffer,
+                                         uint8_t option_code,
+                                         uint16_t value) {
+  *buffer++ = option_code;
+  *buffer++ = sizeof(uint16_t);
+  *reinterpret_cast<uint16_t*>(buffer) = htons(value);
+  buffer += sizeof(uint16_t);
+  return sizeof(uint16_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteUInt32Option(uint8_t* buffer,
+                                         uint8_t option_code,
+                                         uint32_t value) {
+  *buffer++ = option_code;
+  *buffer++ = sizeof(uint32_t);
+  *reinterpret_cast<uint32_t*>(buffer) = htonl(value);
+  buffer += sizeof(uint32_t);
+  return sizeof(uint32_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteUInt8ListOption(uint8_t* buffer,
+    uint8_t option_code,
+    const std::vector<uint8_t>& value) {
+  *buffer++ = option_code;
+  *buffer++ = value.size() * sizeof(uint8_t);
+  for (uint8_t element : value) {
+    *buffer++ = element;
+  }
+  return value.size() * sizeof(uint8_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteUInt16ListOption(uint8_t* buffer,
+    uint8_t option_code,
+    const std::vector<uint16_t>& value) {
+  if (value.size() == 0) {
+    LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
+               << ", because value size cannot be 0";
+    return -1;
+  }
+  *buffer++ = option_code;
+  *buffer++ = value.size() * sizeof(uint16_t);
+  for (uint16_t element : value) {
+    *reinterpret_cast<uint16_t*>(buffer) = htons(element);
+    buffer += sizeof(uint16_t);
+  }
+  return value.size() * sizeof(uint16_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteUInt32ListOption(uint8_t* buffer,
+    uint8_t option_code,
+    const std::vector<uint32_t>& value) {
+  if (value.size() == 0) {
+    LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
+               << ", because value size cannot be 0";
+    return -1;
+  }
+  *buffer++ = option_code;
+  *buffer++ = value.size() * sizeof(uint32_t);
+  for (uint32_t element : value) {
+    *reinterpret_cast<uint32_t*>(buffer) = htonl(element);
+    buffer += sizeof(uint32_t);
+  }
+  return value.size() * sizeof(uint32_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteUInt32PairListOption(uint8_t* buffer,
+    uint8_t option_code,
+    const std::vector<std::pair<uint32_t, uint32_t>>& value) {
+  if (value.size() == 0) {
+    LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
+               << ", because value size cannot be 0";
+    return -1;
+  }
+  *buffer++ = option_code;
+  *buffer++ = value.size() * 2 * sizeof(uint32_t);
+  for (auto element : value) {
+    *reinterpret_cast<uint32_t*>(buffer)  = htonl(element.first);
+    buffer += sizeof(uint32_t);
+    *reinterpret_cast<uint32_t*>(buffer) = htonl(element.second);
+    buffer += sizeof(uint32_t);
+  }
+  return value.size() * sizeof(uint32_t) * 2 + 2;
+}
+
+int DHCPOptionsWriter::WriteBoolOption(uint8_t* buffer,
+                                       uint8_t option_code,
+                                       const bool value) {
+  *buffer++ = option_code;
+  *buffer++ = sizeof(uint8_t);
+  *buffer++ = value ? 1 : 0;
+  return sizeof(uint8_t) + 2;
+}
+
+int DHCPOptionsWriter::WriteStringOption(uint8_t* buffer,
+    uint8_t option_code,
+    const std::string& value) {
+  if (value.size() == 0) {
+    LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
+               << ", because value size cannot be 0";
+    return -1;
+  }
+  *buffer++ = option_code;
+  *buffer++ = value.size() * sizeof(uint8_t);
+  for (unsigned int i = 0; i < value.size(); i++) {
+    *buffer++ = static_cast<uint8_t>(value[i]);
+  }
+  return value.size() * sizeof(uint8_t) + 2;
+}
+
+void DHCPOptionsWriter::WriteEndTag(uint8_t* buffer) {
+  *buffer = kDHCPOptionEnd;
+}
+
+}  // namespace dhcp_client
diff --git a/dhcp_options_writer.h b/dhcp_options_writer.h
new file mode 100644
index 0000000..21ed7ab
--- /dev/null
+++ b/dhcp_options_writer.h
@@ -0,0 +1,69 @@
+//
+// Copyright (C) 2015 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.
+//
+
+#ifndef DHCP_CLIENT_OPTION_WRITER_H_
+#define DHCP_CLIENT_OPTION_WRITER_H_
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/lazy_instance.h>
+
+namespace dhcp_client {
+
+class DHCPOptionsWriter {
+ public:
+  ~DHCPOptionsWriter() {}
+  static DHCPOptionsWriter* GetInstance();
+  int WriteUInt8Option(uint8_t* buffer, uint8_t option_code, uint8_t value);
+  int WriteUInt16Option(uint8_t* buffer,
+                        uint8_t option_code,
+                        uint16_t value);
+  int WriteUInt32Option(uint8_t* buffer,
+                        uint8_t option_code,
+                        uint32_t value);
+  int WriteUInt8ListOption(uint8_t* buffer,
+                           uint8_t option_code,
+                           const std::vector<uint8_t>& value);
+  int WriteUInt16ListOption(uint8_t* buffer,
+                            uint8_t option_code,
+                            const std::vector<uint16_t>& value);
+  int WriteUInt32ListOption(uint8_t* buffer,
+                            uint8_t option_code,
+                            const std::vector<uint32_t>& value);
+  int WriteUInt32PairListOption(uint8_t* buffer,
+      uint8_t option_code,
+      const std::vector<std::pair<uint32_t, uint32_t>>& value);
+  int WriteBoolOption(uint8_t* buffer,
+                      uint8_t option_code,
+                      const bool value);
+  int WriteStringOption(uint8_t* buffer,
+                        uint8_t option_code,
+                        const std::string& value);
+  void WriteEndTag(uint8_t* buffer);
+
+ protected:
+  DHCPOptionsWriter() {}
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<DHCPOptionsWriter>;
+};
+
+}  // namespace dhcp_client
+
+#endif  // DHCP_CLIENT_OPTION_WRITER_H_
diff --git a/dhcp_options_writer_unittest.cc b/dhcp_options_writer_unittest.cc
new file mode 100644
index 0000000..b9b18e5
--- /dev/null
+++ b/dhcp_options_writer_unittest.cc
@@ -0,0 +1,231 @@
+//
+// Copyright (C) 2015 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.
+//
+
+#include <dhcp_client/dhcp_options_writer.h>
+
+#include <netinet/in.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "dhcp_client/dhcp_options.h"
+
+namespace dhcp_client {
+
+namespace {
+const uint8_t kFakeOptionCode1 = 3;
+const uint8_t kFakeOptionCode2 = 45;
+const uint8_t kFakeOptionCode3 = 251;
+
+const uint8_t kFakeUInt8Option = 0x22;
+const uint8_t kFakeUInt8OptionResult[] = {
+    kFakeOptionCode1,
+    sizeof(uint8_t),
+    0x22};
+
+const uint16_t kFakeUInt16Option = 0x1516;
+const uint8_t kFakeUInt16OptionResult[] = {
+    kFakeOptionCode2,
+    sizeof(uint16_t),
+    // Use the network byte order.
+    0x15, 0x16};
+
+const uint32_t kFakeUInt32Option = 0x32a0bf01;
+const uint8_t kFakeUInt32OptionResult[] = {
+    kFakeOptionCode3,
+    sizeof(uint32_t),
+    // Use the network byte order.
+    0x32, 0xa0, 0xbf, 0x01};
+
+const std::vector<uint8_t> kFakeUInt8ListOption =
+    {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+const uint8_t kFakeUInt8ListOptionResult[] = {
+    kFakeOptionCode1,
+    static_cast<uint8_t>(kFakeUInt8ListOption.size()),
+    // Use the network byte order.
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+
+const std::vector<uint16_t> kFakeUInt16ListOption =
+    {0xb1a2, 0x0264, 0xdc03, 0x92c4, 0xa500, 0x0010};
+const uint8_t kFakeUInt16ListOptionResult[] = {
+    kFakeOptionCode2,
+    static_cast<uint8_t>(sizeof(uint16_t) * kFakeUInt16ListOption.size()),
+    // Use the network byte order.
+    0xb1, 0xa2, 0x02, 0x64, 0xdc, 0x03, 0x92, 0xc4, 0xa5, 0x00, 0x00, 0x10};
+
+const std::vector<uint32_t> kFakeUInt32ListOption =
+    {0x03a64301, 0x03f52614, 0x7c5d9eff, 0x0138b26e};
+const uint8_t kFakeUInt32ListOptionResult[] = {
+    kFakeOptionCode3,
+    static_cast<uint8_t>(sizeof(uint32_t) * kFakeUInt32ListOption.size()),
+    // Use the network byte order.
+    0x03, 0xa6, 0x43, 0x01, 0x03, 0xf5, 0x26, 0x14,
+    0x7c, 0x5d, 0x9e, 0xff, 0x01, 0x38, 0xb2, 0x6e};
+
+const std::vector<std::pair<uint32_t, uint32_t>> kFakeUInt32PairListOption =
+    {{0x03b576a1, 0xfa070054}, {0x650c3d22, 0x1397e5bb}};
+const uint8_t kFakeUInt32PairListOptionResult[] = {
+    kFakeOptionCode1,
+    static_cast<uint8_t>
+        (sizeof(uint32_t) * 2 * kFakeUInt32PairListOption.size()),
+    // Use the network byte order.
+    0x03, 0xb5, 0x76, 0xa1, 0xfa, 0x07, 0x00, 0x54,
+    0x65, 0x0c, 0x3d, 0x22, 0x13, 0x97, 0xe5, 0xbb};
+
+const std::string kFakeStringOption = "fakestring";
+const uint8_t kFakeStringOptionResult[] = {
+    kFakeOptionCode1,
+    static_cast<uint8_t>(kFakeStringOption.size()),
+    'f', 'a', 'k', 'e', 's', 't', 'r', 'i', 'n', 'g'};
+
+const uint8_t kFakeBoolOptionTrue = true;
+const uint8_t kFakeBoolOptionResultTrue[] = {
+    kFakeOptionCode1,
+    sizeof(uint8_t),
+    0x01};
+
+const uint8_t kFakeBoolOptionFalse = false;
+const uint8_t kFakeBoolOptionResultFalse[] = {
+    kFakeOptionCode2,
+    sizeof(uint8_t),
+    0x00};
+}  // namespace
+
+
+class DHCPOptionsWriterTest : public testing::Test {
+ protected:
+  DHCPOptionsWriter* options_writer_;
+};
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt8) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteUInt8Option(option,
+                                                 kFakeOptionCode1,
+                                                 kFakeUInt8Option);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt8OptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt16) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteUInt16Option(option,
+                                                  kFakeOptionCode2,
+                                                  kFakeUInt16Option);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt16OptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt32) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteUInt32Option(option,
+                                                  kFakeOptionCode3,
+                                                  kFakeUInt32Option);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt32OptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt8List) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteUInt8ListOption(option,
+                                                     kFakeOptionCode1,
+                                                     kFakeUInt8ListOption);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt8ListOptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt16List) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteUInt16ListOption(option,
+                                                      kFakeOptionCode2,
+                                                      kFakeUInt16ListOption);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt16ListOptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt32List) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteUInt32ListOption(option,
+                                                      kFakeOptionCode3,
+                                                      kFakeUInt32ListOption);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt32ListOptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteUInt32PairList) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length =
+      options_writer_->WriteUInt32PairListOption(option,
+                                                 kFakeOptionCode1,
+                                                 kFakeUInt32PairListOption);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeUInt32PairListOptionResult, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteString) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteStringOption(option,
+                                                  kFakeOptionCode1,
+                                                  kFakeStringOption);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeStringOptionResult, length));
+}
+
+
+TEST_F(DHCPOptionsWriterTest, WriteBoolTrue) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteBoolOption(option,
+                                                kFakeOptionCode1,
+                                                kFakeBoolOptionTrue);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeBoolOptionResultTrue, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteBoolFalse) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteBoolOption(option,
+                                                kFakeOptionCode2,
+                                                kFakeBoolOptionFalse);
+  EXPECT_NE(-1, length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeBoolOptionResultFalse, length));
+}
+
+TEST_F(DHCPOptionsWriterTest, WriteEndTag) {
+  uint8_t option[kDHCPOptionLength];
+  options_writer_ = DHCPOptionsWriter::GetInstance();
+  int length = options_writer_->WriteStringOption(option,
+                                                  kFakeOptionCode1,
+                                                  kFakeStringOption);
+  EXPECT_NE(-1, length);
+  options_writer_->WriteEndTag(option + length);
+  EXPECT_EQ(0, std::memcmp(option, kFakeStringOptionResult, length));
+  EXPECT_EQ(kDHCPOptionEnd, *(option + length));
+}
+
+}  // namespace dhcp_client