/*
 * Copyright 2009-present MongoDB, Inc.
 *
 * 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 <mongoc/mongoc-client-private.h>
#include <mongoc/mongoc-handshake-os-private.h>
#include <mongoc/mongoc-linux-distro-scanner-private.h>

#include <mongoc/mongoc.h>

#include <TestSuite.h>
#include <test-conveniences.h>
#include <test-libmongoc.h>

#ifdef MONGOC_OS_IS_LINUX
static void
test_read_generic_release_file(void)
{
   char *name;
   char *version;
   const char *paths[] = {
      OS_RELEASE_FILE_DIR "/lol-im-not-here.txt",
      OS_RELEASE_FILE_DIR "/also-not-here.txt",
      OS_RELEASE_FILE_DIR "/example-etc-fedora-release.txt",
      NULL,
   };

   const char *paths2[] = {
      OS_RELEASE_FILE_DIR "/example-etc-xyz-release-no-delimiter.txt",
      NULL,
   };

   const char *paths3[] = {
      OS_RELEASE_FILE_DIR "/empty-file.txt",
      NULL,
   };

   _mongoc_linux_distro_scanner_read_generic_release_file(paths, &name, &version);
   ASSERT(name);
   ASSERT(version);
   ASSERT_CMPSTR("Fedora", name);
   ASSERT_CMPSTR("8 (Werewolf)", version);
   bson_free(name);
   bson_free(version);

   _mongoc_linux_distro_scanner_read_generic_release_file(paths2, &name, &version);
   ASSERT(name);
   ASSERT_CMPSTR("This one just has name, not that R word", name);
   ASSERT(version == NULL);
   bson_free(name);

   _mongoc_linux_distro_scanner_read_generic_release_file(paths3, &name, &version);
   ASSERT(name == NULL);
   ASSERT(version == NULL);

   _mongoc_linux_distro_scanner_split_line_by_release(" release ", -1, &name, &version);
   ASSERT(name == NULL);
   ASSERT(version == NULL);

   _mongoc_linux_distro_scanner_split_line_by_release("ends with release ", -1, &name, &version);
   ASSERT_CMPSTR("ends with", name);
   ASSERT(version == NULL);
   bson_free(name);

   _mongoc_linux_distro_scanner_split_line_by_release("", -1, &name, &version);
   ASSERT_CMPSTR(name, "");
   ASSERT(version == NULL);
   bson_free(name);
}


static void
test_read_key_value_file(void)
{
   char *name = NULL;
   char *version = NULL;

   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-lsb-file.txt", "DISTRIB_ID", -1, &name, "DISTRIB_RELEASE", -1, &version);

   ASSERT(name);
   ASSERT_CMPSTR(name, "Ubuntu");
   ASSERT(version);
   ASSERT_CMPSTR(version, "12.04");

   bson_free(name);
   bson_free(version);

   _mongoc_linux_distro_scanner_read_key_value_file(OS_RELEASE_FILE_DIR "/example-lsb-file-with-super-long-line.txt",
                                                    "DISTRIB_ID",
                                                    -1,
                                                    &name,
                                                    "DISTRIB_RELEASE",
                                                    -1,
                                                    &version);
   ASSERT(!name);
   ASSERT(version);
   ASSERT_CMPSTR(version, "12.04");
   bson_free(version);


   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-etc-os-release.txt", "NAME", -1, &name, "VERSION_ID", -1, &version);

   ASSERT_CMPSTR(name, "Fedora");
   ASSERT_CMPSTR(version, "17");

   bson_free(name);
   bson_free(version);

   /* Now try some weird inputs */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-etc-os-release.txt", "ID=", -1, &name, "VERSION_ID=", -1, &version);

   ASSERT(name == NULL);
   ASSERT(version == NULL);

   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-etc-os-release.txt", "", -1, &name, "", -1, &version);

   ASSERT(name == NULL);
   ASSERT(version == NULL);

   /* Test case where we get one but not the other */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-etc-os-release.txt", "NAME", -1, &name, "VERSION_", -1, &version);

   ASSERT_CMPSTR(name, "Fedora");
   ASSERT(version == NULL);
   bson_free(name);

   /* Case where we say the key is the whole line */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-etc-os-release.txt", "NAME", -1, &name, "VERSION_ID=17", -1, &version);
   ASSERT_CMPSTR(name, "Fedora");
   ASSERT(version == NULL);
   bson_free(name);

   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-etc-os-release-ubuntu1604.txt", "NAME", -1, &name, "VERSION_ID", -1, &version);
   ASSERT_CMPSTR("Ubuntu", name);
   ASSERT_CMPSTR("16.04", version);
   bson_free(name);
   bson_free(version);


   /* Case where the key is duplicated, make sure we keep first version */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-key-value-file.txt", "key", -1, &name, "normalkey", -1, &version);
   ASSERT_CMPSTR(name, "first value");
   ASSERT_CMPSTR(version, "normalval");
   bson_free(name);
   bson_free(version);

   /* Case where the key is duplicated, make sure we keep first version */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-key-value-file.txt", "a-key-without-a-value", -1, &name, "normalkey", -1, &version);
   ASSERT_CMPSTR(name, "");
   ASSERT_CMPSTR(version, "normalval");
   bson_free(name);
   bson_free(version);

   /* Try to get value from a line like:
    * just-a-key
    * (No equals, no value) */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-key-value-file.txt", "just-a-key", -1, &name, "normalkey", -1, &version);
   ASSERT(name == NULL);
   ASSERT_CMPSTR(version, "normalval");
   bson_free(name);
   bson_free(version);

   /* Try to get a key which is on line 101 of the file
    * (we stop reading at line 100) */
   _mongoc_linux_distro_scanner_read_key_value_file(
      OS_RELEASE_FILE_DIR "/example-key-value-file.txt", "lastkey", -1, &name, "normalkey", -1, &version);
   ASSERT(name == NULL);
   ASSERT_CMPSTR(version, "normalval");
   bson_free(version);
}

/* We only expect this function to actually read anything on linux platforms */
static void
test_distro_scanner_reads(void)
{
   char *name;
   char *version;

   _mongoc_linux_distro_scanner_get_distro(&name, &version);

#ifdef __linux__
   ASSERT(name);
   ASSERT(strlen(name) > 0);

   /* Some linux distros don't have a version (like arch) but we should always
    * return a version (at the very least, we'll return the kernel version) */
   ASSERT(version);
   ASSERT(strlen(version));
#endif
   bson_free(name);
   bson_free(version);
}
#endif

void
test_linux_distro_scanner_install(TestSuite *suite)
{
   BSON_UNUSED(suite);

#ifdef MONGOC_OS_IS_LINUX
   TestSuite_Add(suite, "/LinuxDistroScanner/test_read_generic_release_file", test_read_generic_release_file);
   TestSuite_Add(suite, "/LinuxDistroScanner/test_read_key_value_file", test_read_key_value_file);
   TestSuite_Add(suite, "/LinuxDistroScanner/test_distro_scanner_reads", test_distro_scanner_reads);
#endif
}
