chromium/base/files/file_path_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include "base/files/file_path.h"

#include <stddef.h>

#include <sstream>
#include <string_view>

#include "base/files/safe_base_name.h"
#include "base/strings/utf_ostream_operators.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"

#if BUILDFLAG(ENABLE_BASE_TRACING)
#include "third_party/perfetto/include/perfetto/test/traced_value_test_support.h"  // no-presubmit-check nogncheck
#endif  // BUILDFLAG(ENABLE_BASE_TRACING)

#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
#include "base/test/scoped_locale.h"
#endif

// This macro helps test `FILE_PATH_LITERAL` macro expansion.
#define TEST_FILE

// This macro helps avoid wrapped lines in the test structs.
#define FPL(x)

// This macro constructs strings which can contain NULs.
#define FPS(x)

namespace base {

struct UnaryTestData {};

struct UnaryBooleanTestData {};

struct BinaryTestData {};

struct BinaryBooleanTestData {};

struct BinaryIntTestData {};

struct UTF8TestData {};

// file_util winds up using autoreleased objects on the Mac, so this needs
// to be a PlatformTest
FilePathTest;

TEST_F(FilePathTest, DirName) {}

TEST_F(FilePathTest, BaseName) {}

TEST_F(FilePathTest, Append) {}

TEST_F(FilePathTest, StripTrailingSeparators) {}

TEST_F(FilePathTest, IsAbsoluteOrNetwork) {}

TEST_F(FilePathTest, PathComponentsTest) {}

TEST_F(FilePathTest, IsParentTest) {}

TEST_F(FilePathTest, AppendRelativePathTest) {}

TEST_F(FilePathTest, EqualityTest) {}

TEST_F(FilePathTest, MacroExpansion) {}

TEST_F(FilePathTest, Extension) {}

TEST_F(FilePathTest, Extension2) {}

TEST_F(FilePathTest, InsertBeforeExtension) {}

TEST_F(FilePathTest, RemoveExtension) {}

TEST_F(FilePathTest, ReplaceExtension) {}

TEST_F(FilePathTest, AddExtension) {}

TEST_F(FilePathTest, MatchesExtension) {}

TEST_F(FilePathTest, MatchesFinalExtension) {}

TEST_F(FilePathTest, CompareIgnoreCase) {}

TEST_F(FilePathTest, ReferencesParent) {}

TEST_F(FilePathTest, FromASCII) {}

TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {}

TEST_F(FilePathTest, ConstructWithNUL) {}

TEST_F(FilePathTest, AppendWithNUL) {}

TEST_F(FilePathTest, AppendBaseName) {}

TEST_F(FilePathTest, ReferencesParentWithNUL) {}

#if defined(FILE_PATH_USES_WIN_SEPARATORS)
TEST_F(FilePathTest, NormalizePathSeparators) {
  const struct UnaryTestData cases[] = {
    { FPL("foo/bar"), FPL("foo\\bar") },
    { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") },
    { FPL("foo\\bar"), FPL("foo\\bar") },
    { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") },
    { FPL("foo"), FPL("foo") },
    // Trailing slashes don't automatically get stripped.  That's what
    // StripTrailingSeparators() is for.
    { FPL("foo\\"), FPL("foo\\") },
    { FPL("foo/"), FPL("foo\\") },
    { FPL("foo/bar\\"), FPL("foo\\bar\\") },
    { FPL("foo\\bar/"), FPL("foo\\bar\\") },
    { FPL("foo/bar/"), FPL("foo\\bar\\") },
    { FPL("foo\\bar\\"), FPL("foo\\bar\\") },
    { FPL("\\foo/bar"), FPL("\\foo\\bar") },
    { FPL("/foo\\bar"), FPL("\\foo\\bar") },
    { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") },
    { FPL("/foo/bar/"), FPL("\\foo\\bar\\") },
    { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") },
    { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") },
    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
    { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") },
    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
    // This method does not normalize the number of path separators.
    { FPL("foo\\\\bar"), FPL("foo\\\\bar") },
    { FPL("foo//bar"), FPL("foo\\\\bar") },
    { FPL("foo/\\bar"), FPL("foo\\\\bar") },
    { FPL("foo\\/bar"), FPL("foo\\\\bar") },
    { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") },
    { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") },
    { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") },
    { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") },
  };
  for (size_t i = 0; i < std::size(cases); ++i) {
    FilePath input(cases[i].input);
    FilePath observed = input.NormalizePathSeparators();
    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
              "i: " << i << ", input: " << input.value();
  }
}
#endif

TEST_F(FilePathTest, EndsWithSeparator) {}

TEST_F(FilePathTest, AsEndingWithSeparator) {}

#if BUILDFLAG(IS_ANDROID)
TEST_F(FilePathTest, ContentUriTest) {
  const struct UnaryBooleanTestData cases[] = {
    { FPL("content://foo.bar"),    true },
    { FPL("content://foo.bar/"),   true },
    { FPL("content://foo/bar"),    true },
    { FPL("CoNTenT://foo.bar"),    true },
    { FPL("content://"),           true },
    { FPL("content:///foo.bar"),   true },
    { FPL("content://3foo/bar"),   true },
    { FPL("content://_foo/bar"),   true },
    { FPL(".. "),                  false },
    { FPL("foo.bar"),              false },
    { FPL("content:foo.bar"),      false },
    { FPL("content:/foo.ba"),      false },
    { FPL("content:/dir/foo.bar"), false },
    { FPL("content: //foo.bar"),   false },
    { FPL("content%2a%2f%2f"),     false },
  };

  for (size_t i = 0; i < std::size(cases); ++i) {
    FilePath input(cases[i].input);
    bool observed = input.IsContentUri();
    EXPECT_EQ(cases[i].expected, observed) <<
              "i: " << i << ", input: " << input.value();
  }
}
#endif

// Test the operator<<(ostream, FilePath).
TEST_F(FilePathTest, PrintToOstream) {}

#if BUILDFLAG(ENABLE_BASE_TRACING)
TEST_F(FilePathTest, TracedValueSupport) {}
#endif  // BUILDFLAG(ENABLE_BASE_TRACING)

// Test GetHFSDecomposedForm should return empty result for invalid UTF-8
// strings.
#if BUILDFLAG(IS_APPLE)
TEST_F(FilePathTest, GetHFSDecomposedFormWithInvalidInput) {
  const FilePath::CharType* cases[] = {
    FPL("\xc3\x28"),
    FPL("\xe2\x82\x28"),
    FPL("\xe2\x28\xa1"),
    FPL("\xf0\x28\x8c\xbc"),
    FPL("\xf0\x28\x8c\x28"),
  };
  for (auto* invalid_input : cases) {
    FilePath::StringType observed = FilePath::GetHFSDecomposedForm(
        invalid_input);
    EXPECT_TRUE(observed.empty());
  }
}

TEST_F(FilePathTest, CompareIgnoreCaseWithInvalidInput) {
  const FilePath::CharType* cases[] = {
      FPL("\xc3\x28"),         FPL("\xe2\x82\x28"),     FPL("\xe2\x28\xa1"),
      FPL("\xf0\x28\x8c\xbc"), FPL("\xf0\x28\x8c\x28"),
  };
  for (auto* invalid_input : cases) {
    // All example inputs will be greater than the string "fixed".
    EXPECT_EQ(FilePath::CompareIgnoreCase(invalid_input, FPL("fixed")), 1);
  }
}
#endif

}  // namespace base