//
// Copyright (C) 2020 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 <gtest/gtest.h>
#include <stdlib.h>
#include "absl/log/log.h"
#include "absl/strings/str_replace.h"

#include <filesystem>
#include <fstream>

#include "cuttlefish/common/libs/fs/shared_select.h"
#include "cuttlefish/common/libs/utils/files.h"
#include "cuttlefish/host/commands/assemble_cvd/flags_defaults.h"
#include "cuttlefish/host/commands/modem_simulator/channel_monitor.h"
#include "cuttlefish/host/commands/modem_simulator/device_config.h"
#include "cuttlefish/host/commands/modem_simulator/modem_simulator.h"
#include "cuttlefish/host/libs/config/cuttlefish_config.h"
namespace fs = std::filesystem;

#include "iccfile.h"

static const std::string tmp_test_dir = std::string(fs::temp_directory_path()) +
                                        std::string("/cuttlefish_modem_test");
using namespace cuttlefish;

class ModemServiceTest : public ::testing::Test {
 protected:
  static void SetUpTestSuite() {
    {
      cuttlefish::CuttlefishConfig tmp_config_obj;
      std::string config_file = tmp_test_dir + "/.cuttlefish_config.json";
      tmp_config_obj.set_root_dir(tmp_test_dir + "/cuttlefish");
      std::vector<int> instance_nums;
      for (int i = 0; i < 1; i++) {
        instance_nums.push_back(cuttlefish::GetInstance() + i);
      }
      for (const auto &num : instance_nums) {
        auto instance = tmp_config_obj.ForInstance(num);  // Trigger creation in map
        instance.set_ril_dns(CF_DEFAULTS_RIL_DNS);
      }

      for (auto instance : tmp_config_obj.Instances()) {
        fs::create_directories(instance.instance_dir());
        if (!tmp_config_obj.SaveToFile(
                instance.PerInstancePath("cuttlefish_config.json"))) {
          LOG(ERROR) << "Unable to save copy config object";
          return;
        }
        std::string icfilename =
            instance.PerInstancePath("/iccprofile_for_sim0.xml");
        std::ofstream offile = modem::DeviceConfig::open_ofstream_crossplat(icfilename.c_str(), std::ofstream::out);
        offile << std::string(myiccfile);
        offile.close();
        fs::copy_file(instance.PerInstancePath("/cuttlefish_config.json"),
                      config_file, fs::copy_options::overwrite_existing);
      }

      ::setenv("CUTTLEFISH_CONFIG_FILE", config_file.c_str(), 1);
    }
    cuttlefish::SharedFD ril_shared_fd, modem_shared_fd;
    if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &ril_shared_fd,
                              &modem_shared_fd)) {
      LOG(ERROR) << "Unable to create client socket pair: " << strerror(errno);
    }
    ASSERT_TRUE(ril_shared_fd->IsOpen());
    ASSERT_TRUE(modem_shared_fd->IsOpen());

    NvramConfig::InitNvramConfigService(1, 1);

    ril_side_ = new Client(ril_shared_fd);
    modem_side_ = new Client(modem_shared_fd);
    modem_simulator_ = new ModemSimulator(0);

    cuttlefish::SharedFD server;
    auto channel_monitor =
        std::make_unique<ChannelMonitor>(*modem_simulator_, server);
    modem_simulator_->Initialize(std::move(channel_monitor));
  }

  static void TearDownTestSuite() {
    delete ril_side_;
    delete modem_side_;
    delete modem_simulator_;
    fs::remove_all(tmp_test_dir);
  };

  void SendCommand(std::string command, std::string prefix = "") {
    command_prefix_ = prefix;
    modem_simulator_->DispatchCommand(*modem_side_, command);
  }

  void ReadCommandResponse(std::vector<std::string>& response) {
    do {
      std::vector<char> buffer(4096);  // kMaxCommandLength
      auto bytes_read =
          ril_side_->client_read_fd_->Read(buffer.data(), buffer.size());
      if (bytes_read <= 0) {
        // Close here to ensure the other side gets reset if it's still
        // connected
        ril_side_->client_read_fd_->Close();
        ril_side_->client_write_fd_->Close();
        LOG(WARNING) << "Detected close from the other side";
        break;
      }

      std::string& incomplete_command = ril_side_->incomplete_command;

      // Add the incomplete command from the last read
      auto commands = std::string{incomplete_command.data()};
      commands.append(buffer.data());

      incomplete_command.clear();
      incomplete_command.resize(0);

      // replacing '\n' with '\r'
      absl::StrReplaceAll({{"\n", "\r"}}, &commands);

      // split into commands and dispatch
      size_t pos = 0, r_pos = 0;  // '\r' or '\n'
      while (r_pos != std::string::npos) {
        r_pos = commands.find('\r', pos);
        if (r_pos != std::string::npos) {
          auto command = commands.substr(pos, r_pos - pos);
          if (!command.empty()) {  // "\r\r" ?
            VLOG(0) << "AT< " << command;
            if (IsFinalResponseSuccess(command) || IsFinalResponseError(command)) {
              response.push_back(command);
              return;
            } else if (IsIntermediateResponse(command)) {
              response.push_back(command);
            } else {
              ; // Ignore unsolicited command
            }
          }
          pos = r_pos + 1;  // skip '\r'
        } else if (pos < commands.length()) {  // incomplete command
          incomplete_command = commands.substr(pos);
          VLOG(1) << "incomplete command: " << incomplete_command;
        }
      }
    } while (true);

    // read response
  }

  inline bool IsFinalResponseSuccess(std::string response) {
    auto iter = kFinalResponseSuccess.begin();
    for (; iter != kFinalResponseSuccess.end(); ++iter) {
      if (*iter == response) {
        return true;
      }
    }

    return false;
  }

  inline bool IsFinalResponseError(std::string response) {
    auto iter = kFinalResponseError.begin();
    for (; iter != kFinalResponseError.end(); ++iter) {
      if (response.compare(0, iter->size(), *iter) == 0) {
        return true;
      }
    }

    return false;
  }

  inline bool IsIntermediateResponse(std::string response) {
    if (response.compare(0, command_prefix_.size(), command_prefix_) == 0) {
      return true;
    }

    return false;
  }

  int openLogicalChannel(std::string& name) {
    // Create and send command
    std::string command = "AT+CCHO=";
    command.append(name);
    std::vector<std::string> response;
    SendCommand(command);
    ReadCommandResponse(response);
    int channel = std::stoi(response[0]);
    return channel;
  }

  bool closeLogicalChannel(int channel) {
    std::string command = "AT+CCHC=";
    command += std::to_string(channel);
    std::vector<std::string> response;
    SendCommand(command);
    ReadCommandResponse(response);
    std::string expect = "+CCHC";
    return (response[0].compare(0, expect.size(), expect) == 0);
  }

  const std::vector<std::string> kFinalResponseSuccess = {"OK", "CONNECT", "> "};
  const std::vector<std::string> kFinalResponseError = {
      "ERROR",
      "+CMS ERROR:",
      "+CME ERROR:",
      "NO CARRIER", /* sometimes! */
      "NO ANSWER",
      "NO DIALTONE",
  };

  static Client* ril_side_;
  static Client* modem_side_;
  static ModemSimulator* modem_simulator_;

  // For distinguishing the response from command response or unsolicited command
  std::string command_prefix_;
};

ModemSimulator* ModemServiceTest::modem_simulator_ = nullptr;
Client* ModemServiceTest::ril_side_ = nullptr;
Client* ModemServiceTest::modem_side_ = nullptr;

/* Sim Service Test */
TEST_F(ModemServiceTest, GetIccCardStatus) {
  const char *expects[]  = {"+CPIN: READY",
                            "OK"};

  std::string command = "AT+CPIN?";
  std::vector<std::string> response;
  SendCommand(command, "+CPIN:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[0].c_str(), expects[0]);
  ASSERT_STREQ(response[1].c_str(), expects[1]);
}

TEST_F(ModemServiceTest, ChangeOrEnterPIN) {
  std::vector<std::string> commands = {"AT+CPIN=1234,0000",
                                       "AT+CPIN=1111,2222",};
  std::vector<std::string> expects  = {"OK",
                                       "+CME ERROR: 16",};
  std::vector<std::string> response;
  auto expects_iter = expects.begin();
  for (auto iter = commands.begin(); iter != commands.end(); ++iter, ++expects_iter) {
    SendCommand(*iter);
    ReadCommandResponse(response);
    ASSERT_STREQ(response[0].c_str(), (*expects_iter).c_str());
    response.clear();
  }
}

TEST_F(ModemServiceTest, SIM_IO) {
  std::vector<std::string> commands = {"AT+CRSM=192,12258,0,0,15",
                                       "AT+CRSM=192,28436,0,0,15",
                                       "AT+CRSM=220,28618,1,4,5,0000000000"};
  std::vector<std::string> expects  = {"+CRSM: 144,0,62178202412183022FE28A01058B032F06038002000A880110",
                                       "+CRSM: 106,130",
                                       "+CRSM: 144,0"};

  std::vector<std::string> response;
  auto expects_iter = expects.begin();
  for (auto iter = commands.begin(); iter != commands.end(); ++iter, ++expects_iter) {
    SendCommand(*iter);
    ReadCommandResponse(response);
    ASSERT_EQ(response.size(), 2);
    ASSERT_STREQ(response[0].c_str(), (*expects_iter).c_str());
    response.clear();
  }
}

TEST_F(ModemServiceTest, GetIMSI) {
  std::string command = "AT+CIMI";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *expect = "460110031689666";
  ASSERT_STREQ(response[0].c_str(),expect);
}

TEST_F(ModemServiceTest, GetIccId) {
  std::string command = "AT+CICCID";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *expect = "89860318640220133897";
  ASSERT_STREQ(response[0].c_str(),expect);
}

TEST_F(ModemServiceTest, FacilityLock) {
  std::vector<std::string> commands =
        { "AT+CLCK=\"FD\",2,"",7",
          "AT+CLCK=\"SC\",2,"",7",
          "AT+CLCK=\"SC\",1,\"1234\",7",
          "AT+CLCK=\"SC\",1,\"023000\",7"
  };
  std::vector<std::string> expects =
        { "+CLCK: 0",
          "+CLCK: 0",
          "+CME ERROR: 16",
          "+CME ERROR: 16"
  };
  std::vector<std::string> response;
  auto expects_iter = expects.begin();
  for (auto iter = commands.begin(); iter != commands.end(); ++iter, ++expects_iter) {
    SendCommand(*iter);
    ReadCommandResponse(response);
    ASSERT_STREQ(response[0].c_str(), (*expects_iter).c_str());
    response.clear();
  }
}

TEST_F(ModemServiceTest, OpenLogicalChannel) {
  std::string command= "A000000063504B43532D3135";
  int firstChannel = openLogicalChannel(command);
  ASSERT_EQ(firstChannel, 1);

  command= "A000000063504B43532D3135";
  int secondChannel = openLogicalChannel(command);
  ASSERT_GE(secondChannel, 1);

  closeLogicalChannel(firstChannel);
  closeLogicalChannel(secondChannel);
}

TEST_F(ModemServiceTest, CloseLogicalChannel) {
  std::string command= "A000000063504B43532D3135";
  int channel = openLogicalChannel(command);
  ASSERT_EQ(channel, 1);

  ASSERT_FALSE(closeLogicalChannel(channel + 3));
  ASSERT_TRUE(closeLogicalChannel(channel));
}

TEST_F(ModemServiceTest, TransmitLogicalChannel) {
  std::string command= "A000000063504B43532D3135";
  int channel = openLogicalChannel(command);
  ASSERT_EQ(channel, 1);
  command = "AT+CGLA=";
  command += channel;
  command += ",10,80caff4000";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *expect = "+CME ERROR: 21";
  ASSERT_STREQ(response[0].c_str(),expect);
  ASSERT_TRUE(closeLogicalChannel(channel));
}

/* Network Service Test */
TEST_F(ModemServiceTest, testRadioPowerReq) {
  std::string command = "AT+CFUN?";
  std::vector<std::string> response;
  SendCommand(command, "+CFUN:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testSetRadioPower) {
  std::string command = "AT+CFUN=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testSignalStrength) {
  std::string command = "AT+CSQ";
  std::vector<std::string> response;
  SendCommand(command, "+CSQ:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testQueryNetworkSelectionMode) {
  std::string command = "AT+COPS?";
  std::vector<std::string> response;
  SendCommand(command, "+COPS:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testRequestOperator) {
  std::string command = "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?";
  std::vector<std::string> response;
  SendCommand(command, "+COPS:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 4);
}

TEST_F(ModemServiceTest, testVoiceNetworkRegistration) {
  std::string command = "AT+CREG?";
  std::vector<std::string> response;
  SendCommand(command, "+CREG:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testDataNetworkRegistration) {
  std::string command = "AT+CGREG?";
  std::vector<std::string> response;
  SendCommand(command, "+CGREG:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testDataNetworkRegistrationWithLte2) {
  std::string command = "AT+CEREG?";
  std::vector<std::string> response;
  SendCommand(command, "+CEREG:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testGetPreferredNetworkType) {
  std::string command = "AT+CTEC?";
  std::vector<std::string> response;
  SendCommand(command, "+CTEC:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testQuerySupportedTechs) {
  std::string command = "AT+CTEC=?";
  std::vector<std::string> response;
  SendCommand(command, "+CTEC:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testSetPreferredNetworkType) {
  std::string command = "AT+CTEC=1,\"201\"";
  std::vector<std::string> response;
  SendCommand(command, "+CTEC:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

/* Call Service Test */
TEST_F(ModemServiceTest, testCurrentCalls) {
  std::string command = "AT+CLCC";
  std::vector<std::string> response;
  SendCommand(command, "+CLCC:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
}

TEST_F(ModemServiceTest, testHangup) {
  for (int i = 0; i < 5; i ++) {
    std::stringstream ss;
    ss.clear();
    ss << "AT+CHLD=" << i;
    SendCommand(ss.str());
  }
  std::vector<std::string> response;
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testMute) {
  std::string command = "AT+CMUT=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testSendDtmf) {
  std::string command = "AT+VTS=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testExitEmergencyMode) {
  std::string command = "AT+WSOS=0";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

/* Data Service Test */
TEST_F(ModemServiceTest, SetPDPContext) {
  std::string command = "AT+CGDCONT=1,\"IPV4V6\",\"ctlte\",,0,0";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response.at(0).c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, QueryPDPContextList) {
  for (int i = 1; i < 5; i ++) {
    std::stringstream ss;
    ss.clear();
    ss << "AT+CGDCONT=" << i << ",\"IPV4V6\",\"ctlte\",,0,0";
    SendCommand(ss.str());
  }
  std::string command = "AT+CGDCONT?";
  std::vector<std::string> response;
  SendCommand(command, "+CGDCONT:");
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, ActivateDataCall) {
  std::string command = "AT+CGACT= 1,0";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[0].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, QueryDataCallList) {
  std::string command = "AT+CGACT?";
  std::vector<std::string> response;
  SendCommand(command, "+CGACT:");
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, ReadDynamicParamTrue) {
  std::string command = "AT+CGCONTRDP=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, ReadDynamicParamFalse) {
  std::string command = "AT+CGCONTRDP=10";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  const char *expect = "+CME ERROR: 21";
  ASSERT_STREQ(result, expect);
}

TEST_F(ModemServiceTest, EnterDataState) {
  std::string command = "AT+CGDATA=1,1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[1].c_str());
}

/* SMS Service Test */
TEST_F(ModemServiceTest, SendSMS) {
  std::string command = "AT+CMGS=35";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  const char *expect = "> ";
  ASSERT_STREQ(result, expect);
  command = "0001000D91688118109844F0000017AFD7903AB55A9BBA69D639D4ADCBF99E3DCCAE9701^Z";
  //command += '\032';
  SendCommand(command);
  ReadCommandResponse(response);
  // TODO (bohu) for some reason the following asserts fail, fix them
  // ASSERT_EQ(response.size(), 3);
  // ASSERT_STREQ(response[response.size() - 1].c_str(),
  // kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, WriteSMSToSim) {
  std::string command = "AT+CMGW=24,3";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  const char *expect = "> ";
  ASSERT_STREQ(result, expect);
  command = "00240B815123106351F100000240516054410005C8329BFD06^Z";
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 3);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, SMSAcknowledge) {
  std::string command = "AT+CNMA=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, DeleteSmsOnSimTure) {
  std::string command = "AT+CMGD=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[0].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, DeleteSmsOnSimFalse) {
  std::string command = "AT+CMGD=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[0].c_str();
  const char *expect = "+CME ERROR: 21";
  ASSERT_STREQ(result, expect);
}

TEST_F(ModemServiceTest, SetBroadcastConfig) {
  std::string command = "AT+CSCB=0,\"4356\",\"0-255\"";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  const char *result = response[0].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, GetBroadcastConfig) {
  std::string command = "AT+CSCB?";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, SetSmscAddress) {
  std::string command = "AT+CSCA=\"91688115667566F4\",16";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, GetSmscAddress) {
  std::string command = "AT+CSCA?";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *result = response[response.size() - 1].c_str();
  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
}

/* SUP Service Test */
TEST_F(ModemServiceTest, testUSSD) {
  std::string command = "AT+CUSD=1";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testCLIR) {
  std::string command = "AT+CLIR=2";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testQueryCLIR) {
  std::string command = "AT+CLIR?";
  std::vector<std::string> response;
  SendCommand(command, "+CLIR:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
}

TEST_F(ModemServiceTest, testCallWaiting) {
  std::string command = "AT+CCWA";
  std::vector<std::string> response;
  SendCommand(command, "+CCWA:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
}

TEST_F(ModemServiceTest, testCLIP) {
  std::string command = "AT+CLIP?";
  std::vector<std::string> response;
  SendCommand(command, "+CLIP:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
}

TEST_F(ModemServiceTest, testCallForward) {
  std::string command = "AT+CCFCU=1,1,2,145,\"10086\"";
  std::vector<std::string> response;
  SendCommand(command, "+CCFCU:");
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 1);
}

/* STK Service Test */
TEST_F(ModemServiceTest, ReportStkServiceIsRunning) {
  std::string command = "AT+CUSATD?";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *result = response[0].c_str();
  const char *expect = "+CUSATD: 0,1";
  ASSERT_STREQ(result, expect);
}

TEST_F(ModemServiceTest, SendEnvelope) {
  std::string command = "AT+CUSATT=\"810301250002028281830100\"";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *result = response[0].c_str();
  const char *expect = "+CUSATT: 0";
  ASSERT_STREQ(result, expect);
}

TEST_F(ModemServiceTest, GetSendTerminalResponseToSim) {
  std::string command = "AT+CUSATE=\"D3078202018190014E\"";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *result = response[0].c_str();
  const char *expect = "+CUSATE: 0";
  ASSERT_STREQ(result, expect);
}

/* Misc Service Test */
TEST_F(ModemServiceTest, GetIMEI) {
  std::string command = "AT+CGSN";
  std::vector<std::string> response;
  SendCommand(command);
  ReadCommandResponse(response);
  ASSERT_EQ(response.size(), 2);
  const char *result = response[0].c_str();
  const char *expect = "867400022047199";
  ASSERT_STREQ(result, expect);
}
