From 30895dfb4b4591a16edbbb36355cb8872af67947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 3 Jul 2021 00:02:58 +0200 Subject: [PATCH 01/10] createSymlinkIfSupportedByFilesystem(): Add support for directory symlinks used on Windows --- test/FilesystemUtils.cpp | 9 +++++++-- test/FilesystemUtils.h | 6 +++++- test/libsolutil/CommonIO.cpp | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/test/FilesystemUtils.cpp b/test/FilesystemUtils.cpp index 08d4845043d2..4abbb51f4ed6 100644 --- a/test/FilesystemUtils.cpp +++ b/test/FilesystemUtils.cpp @@ -39,11 +39,16 @@ void solidity::test::createFileWithContent(boost::filesystem::path const& _path, bool solidity::test::createSymlinkIfSupportedByFilesystem( boost::filesystem::path const& _targetPath, - boost::filesystem::path const& _linkName + boost::filesystem::path const& _linkName, + bool directorySymlink ) { boost::system::error_code symlinkCreationError; - boost::filesystem::create_symlink(_targetPath, _linkName, symlinkCreationError); + + if (directorySymlink) + boost::filesystem::create_directory_symlink(_targetPath, _linkName, symlinkCreationError); + else + boost::filesystem::create_symlink(_targetPath, _linkName, symlinkCreationError); if (!symlinkCreationError) return true; diff --git a/test/FilesystemUtils.h b/test/FilesystemUtils.h index f8ad320444fc..c39edec4db62 100644 --- a/test/FilesystemUtils.h +++ b/test/FilesystemUtils.h @@ -34,12 +34,16 @@ void createFileWithContent(boost::filesystem::path const& _path, std::string con /// Creates a symlink between two paths. /// The target does not have to exist. +/// If @p directorySymlink is true, indicate to the operating system that this is a directory +/// symlink. On some systems (e.g. Windows) it's possible to create a non-directory symlink pointing +/// at a directory, which makes such a symlinks unusable. /// @returns true if the symlink has been successfully created, false if the filesystem does not /// support symlinks. /// Throws an exception of the operation fails for a different reason. bool createSymlinkIfSupportedByFilesystem( boost::filesystem::path const& _targetPath, - boost::filesystem::path const& _linkName + boost::filesystem::path const& _linkName, + bool directorySymlink ); } diff --git a/test/libsolutil/CommonIO.cpp b/test/libsolutil/CommonIO.cpp index e83bebecea2e..9c7fd447991c 100644 --- a/test/libsolutil/CommonIO.cpp +++ b/test/libsolutil/CommonIO.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(readFileAsString_symlink) TemporaryDirectory tempDir("common-io-test-"); createFileWithContent(tempDir.path() / "test.txt", "ABC\ndef\n"); - if (!createSymlinkIfSupportedByFilesystem("test.txt", tempDir.path() / "symlink.txt")) + if (!createSymlinkIfSupportedByFilesystem("test.txt", tempDir.path() / "symlink.txt", false)) return; BOOST_TEST(readFileAsString((tempDir.path() / "symlink.txt").string()) == "ABC\ndef\n"); From e1036c24af48d001cf8675677a3d51b59b443cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 15 Jun 2021 14:52:53 +0200 Subject: [PATCH 02/10] FileReader: Normalize base path and strip it from normalized source paths --- Changelog.md | 1 + docs/path-resolution.rst | 48 ++- libsolidity/interface/FileReader.cpp | 145 ++++++- libsolidity/interface/FileReader.h | 48 ++- test/CMakeLists.txt | 1 + test/libsolidity/interface/FileReader.cpp | 443 ++++++++++++++++++++++ 6 files changed, 676 insertions(+), 10 deletions(-) create mode 100644 test/libsolidity/interface/FileReader.cpp diff --git a/Changelog.md b/Changelog.md index 9638d597ad75..72b6274f27ab 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Language Features: Compiler Features: * AssemblyStack: Also run opcode-based optimizer when compiling Yul code. + * Commandline Interface: Normalize paths specified on the command line and make them relative whenever files are located inside base path. * Yul EVM Code Transform: Do not reuse stack slots that immediately become unreachable. * Yul EVM Code Transform: Also pop unused argument slots for functions without return variables (under the same restrictions as for functions with return variables). * Yul Optimizer: Move function arguments and return variables to memory with the experimental Stack Limit Evader (which is not enabled by default). diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index 5848e3f9aae6..513a7131a6a0 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -71,8 +71,10 @@ The initial content of the VFS depends on how you invoke the compiler: solc contract.sol /usr/local/dapp-bin/token.sol - The source unit name of a file loaded this way is simply the specified path after shell expansion - and with platform-specific separators converted to forward slashes. + The source unit name of a file loaded this way is constructed by converting its path to a + canonical form and making it relative to the base path if it is located inside. + See :ref:`Base Path Normalization and Stripping ` for + a detailed description of this process. .. index:: standard JSON @@ -313,6 +315,46 @@ interpreted as absolute paths on disk. If the base path itself is relative, it is also interpreted as relative to the current working directory of the compiler. +.. _base-path-normalization-and-stripping: + +Base Path Normalization and Stripping +------------------------------------- + +When source file paths are specified on the command line, the base path affects the source unit +names assigned to them in the compiler's VFS. +To compute the names, both base path and source file paths must first be converted to a canonical form. +This ensures that the result is predictable and as platform-independent as possible: + +- If a path is relative, it is made absolute by prepending the current working directory to it. + + - If the path to the working directory contains symbolic links, they are resolved into actual + directories. + +- Internal ``.`` and ``..`` segments are collapsed. +- Platform-specific path separators are replaced with forward slashes. +- Sequences of multiple consecutive path separators are squashed into a single separator (unless + they are the leading slashes of an `UNC path `_). +- If the path includes a root name (e.g. a drive letter on Windows) and the root is the same as the + root of the current working directory, the root is replaced with ``/``. +- Symbolic links in the path itself are **not** resolved. +- The original case of the path is preserved even if the filesystem is case-insensitive but + `case-preserving `_ and the actual case on + disk is different. + +.. note:: + + There are situations where paths cannot be made platform-independent. + For example on Windows the compiler can avoid using drive letters by referring to the root + directory of the current drive as ``/`` but drive letters are still necessary for paths leading + to other drives. + You can avoid such situations by ensuring that all the files are available within a single + directory tree on the same drive. + +Once canonicalized, the base path is stripped from all source file paths that start with it. +If the base path is empty (e.g. if it is not explicitly provided), it is treated as if it was equal +to the path to the current working directory with all symbolic links resolved. +The result becomes the source unit name. + .. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target .. _import-remapping: @@ -414,7 +456,7 @@ Here are the detailed rules governing the behaviour of remappings: .. code-block:: bash - solc /project/=/contracts/ /project/contract.sol --base-path /project # source unit name: /project/contract.sol + solc /project/=/contracts/ /project/contract.sol --base-path /project # source unit name: contract.sol .. code-block:: solidity :caption: /project/contract.sol diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 53a0b2cbde99..a4d640c68d3a 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -22,6 +22,8 @@ #include #include +#include + using solidity::frontend::ReadCallback; using solidity::langutil::InternalCompilerError; using solidity::util::errinfo_comment; @@ -31,9 +33,17 @@ using std::string; namespace solidity::frontend { +void FileReader::setBasePath(boost::filesystem::path const& _path) +{ + m_basePath = (_path.empty() ? "" : normalizeCLIPathForVFS(_path)); +} + void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source) { - m_sourceCodes[_path.generic_string()] = std::move(_source); + boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_path); + boost::filesystem::path prefix = (m_basePath.empty() ? normalizeCLIPathForVFS(".") : m_basePath); + + m_sourceCodes[stripPrefixIfPresent(prefix, normalizedPath).generic_string()] = std::move(_source); } void FileReader::setSources(StringMap _sources) @@ -92,5 +102,138 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so } } +boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::path const& _path) +{ + // Detailed normalization rules: + // - Makes the path either be absolute or have slash as root (note that on Windows paths with + // slash as root are not considered absolute by Boost). If it is empty, it becomes + // the current working directory. + // - Collapses redundant . and .. segments. + // - Removes leading .. segments from an absolute path (i.e. /../../ becomes just /). + // - Squashes sequences of multiple path separators into one. + // - Ensures that forward slashes are used as path separators on all platforms. + // - Removes the root name (e.g. drive letter on Windows) when it matches the root name in the + // path to the current working directory. + // + // Also note that this function: + // - Does NOT resolve symlinks (except for symlinks in the path to the current working directory). + // - Does NOT check if the path refers to a file or a directory. If the path ends with a slash, + // the slash is preserved even if it's a file. + // - Preserves case. Even if the filesystem is case-insensitive but case-preserving and the + // case differs, the actual case from disk is NOT detected. + + boost::filesystem::path canonicalWorkDir = boost::filesystem::weakly_canonical(boost::filesystem::current_path()); + + // NOTE: On UNIX systems the path returned from current_path() has symlinks resolved while on + // Windows it does not. To get consistent results we resolve them on all platforms. + boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, canonicalWorkDir); + + // NOTE: boost path preserves certain differences that are ignored by its operator ==. + // E.g. "a//b" vs "a/b" or "a/b/" vs "a/b/.". lexically_normal() does remove these differences. + boost::filesystem::path normalizedPath = absolutePath.lexically_normal(); + solAssert(normalizedPath.is_absolute() || normalizedPath.root_path() == "/", ""); + + // lexically_normal() will not squash paths like "/../../" into "/". We have to do it manually. + boost::filesystem::path dotDotPrefix = absoluteDotDotPrefix(normalizedPath); + + // If the path is on the same drive as the working dir, for portability we prefer not to + // include the root name. Do this only for non-UNC paths - my experiments show that on Windows + // when the working dir is an UNC path, / does not not actually refer to the root of the UNC path. + boost::filesystem::path normalizedRootPath = normalizedPath.root_path(); + if (!isUNCPath(normalizedPath)) + { + boost::filesystem::path workingDirRootPath = canonicalWorkDir.root_path(); + if (normalizedRootPath == workingDirRootPath) + normalizedRootPath = "/"; + } + + boost::filesystem::path normalizedPathNoDotDot = normalizedPath; + if (dotDotPrefix.empty()) + normalizedPathNoDotDot = normalizedRootPath / normalizedPath.relative_path(); + else + normalizedPathNoDotDot = normalizedRootPath / normalizedPath.lexically_relative(normalizedPath.root_path() / dotDotPrefix); + solAssert(!hasDotDotSegments(normalizedPathNoDotDot), ""); + + // NOTE: On Windows lexically_normal() converts all separators to forward slashes. Convert them back. + // Separators do not affect path comparison but remain in internal representation returned by native(). + // This will also normalize the root name to start with // in UNC paths. + normalizedPathNoDotDot = normalizedPathNoDotDot.generic_string(); + + // For some reason boost considers "/." different than "/" even though for other directories + // the trailing dot is ignored. + if (normalizedPathNoDotDot == "/.") + return "/"; + + return normalizedPathNoDotDot; +} + +bool FileReader::isPathPrefix(boost::filesystem::path _prefix, boost::filesystem::path const& _path) +{ + solAssert(!_prefix.empty() && !_path.empty(), ""); + // NOTE: On Windows paths starting with a slash (rather than a drive letter) are considered relative by boost. + solAssert(_prefix.is_absolute() || isUNCPath(_prefix) || _prefix.root_path() == "/", ""); + solAssert(_path.is_absolute() || isUNCPath(_path) || _path.root_path() == "/", ""); + solAssert(_prefix == _prefix.lexically_normal() && _path == _path.lexically_normal(), ""); + solAssert(!hasDotDotSegments(_prefix) && !hasDotDotSegments(_path), ""); + + // Before 1.72.0 lexically_relative() was not handling paths with empty, dot and dot dot segments + // correctly (see https://github.com/boostorg/filesystem/issues/76). The only case where this + // is possible after our normalization is a directory name ending in a slash (filename is a dot). + if (_prefix.filename_is_dot()) + _prefix.remove_filename(); + + boost::filesystem::path strippedPath = _path.lexically_relative(_prefix); + return !strippedPath.empty() && *strippedPath.begin() != ".."; } +boost::filesystem::path FileReader::stripPrefixIfPresent(boost::filesystem::path _prefix, boost::filesystem::path const& _path) +{ + if (!isPathPrefix(_prefix, _path)) + return _path; + + if (_prefix.filename_is_dot()) + _prefix.remove_filename(); + + boost::filesystem::path strippedPath = _path.lexically_relative(_prefix); + solAssert(strippedPath.empty() || *strippedPath.begin() != "..", ""); + return strippedPath; +} + +boost::filesystem::path FileReader::absoluteDotDotPrefix(boost::filesystem::path const& _path) +{ + solAssert(_path.is_absolute() || _path.root_path() == "/", ""); + + boost::filesystem::path _pathWithoutRoot = _path.relative_path(); + boost::filesystem::path prefix; + for (boost::filesystem::path const& segment: _pathWithoutRoot) + if (segment.filename_is_dot_dot()) + prefix /= segment; + + return prefix; +} + +bool FileReader::hasDotDotSegments(boost::filesystem::path const& _path) +{ + for (boost::filesystem::path const& segment: _path) + if (segment.filename_is_dot_dot()) + return true; + + return false; +} + +bool FileReader::isUNCPath(boost::filesystem::path const& _path) +{ + string rootName = _path.root_name().string(); + + return ( + rootName.size() == 2 || + (rootName.size() > 2 && rootName[2] != rootName[1]) + ) && ( + (rootName[0] == '/' && rootName[1] == '/') +#if defined(_WIN32) + || (rootName[0] == '\\' && rootName[1] == '\\') +#endif + ); +} + +} diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index 5aca710db34c..76c283c46e45 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -45,12 +45,13 @@ class FileReader boost::filesystem::path _basePath = {}, FileSystemPathSet _allowedDirectories = {} ): - m_basePath(std::move(_basePath)), m_allowedDirectories(std::move(_allowedDirectories)), m_sourceCodes() - {} + { + setBasePath(_basePath); + } - void setBasePath(boost::filesystem::path _path) { m_basePath = std::move(_path); } + void setBasePath(boost::filesystem::path const& _path); boost::filesystem::path const& basePath() const noexcept { return m_basePath; } void allowDirectory(boost::filesystem::path _path) { m_allowedDirectories.insert(std::move(_path)); } @@ -58,14 +59,14 @@ class FileReader StringMap const& sourceCodes() const noexcept { return m_sourceCodes; } - /// Retrieves the source code for a given source unit ID. + /// Retrieves the source code for a given source unit name. SourceCode const& sourceCode(SourceUnitName const& _sourceUnitName) const { return m_sourceCodes.at(_sourceUnitName); } - /// Resets all sources to the given map of source unit ID to source codes. + /// Resets all sources to the given map of source unit name to source codes. /// Does not enforce @a allowedDirectories(). void setSources(StringMap _sources); - /// Adds the source code for a given source unit ID. + /// Adds the source code under a source unit name created by normalizing the file path. /// Does not enforce @a allowedDirectories(). void setSource(boost::filesystem::path const& _path, SourceCode _source); @@ -83,7 +84,42 @@ class FileReader return [this](std::string const& _kind, std::string const& _path) { return readFile(_kind, _path); }; } + /// Normalizes a filesystem path to make it include all components up to the filesystem root, + /// remove small, inconsequential differences that do not affect the meaning and make it look + /// the same on all platforms (if possible). Symlinks in the path are not resolved. + /// The resulting path uses forward slashes as path separators, has no redundant separators, + /// has no redundant . or .. segments and has no root name if removing it does not change the meaning. + /// The path does not have to actually exist. + static boost::filesystem::path normalizeCLIPathForVFS(boost::filesystem::path const& _path); + + /// @returns true if all the path components of @a _prefix are present at the beginning of @a _path. + /// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no + /// multiple consecutive slashes). + /// Paths are treated as case-sensitive. Does not require the path to actually exist in the + /// filesystem and does not follow symlinks. Only considers whole segments, e.g. /abc/d is not + /// considered a prefix of /abc/def. Both paths must be non-empty. + static bool isPathPrefix(boost::filesystem::path _prefix, boost::filesystem::path const& _path); + + /// If @a _prefix is actually a prefix of @p _path, removes it from @a _path to make it relative. + /// @returns The path without the prefix or unchanged path if there is not prefix. + /// If @a _path and @_prefix are identical, the result is '.'. + static boost::filesystem::path stripPrefixIfPresent(boost::filesystem::path _prefix, boost::filesystem::path const& _path); + + // @returns true if the specified path is an UNC path. + // UNC paths start with // followed by a name (on Windows they can also start with \\). + // They are used for network shares on Windows. On UNIX systems they do not have the same + // functionality but usually they are still recognized and treated in a special way. + static bool isUNCPath(boost::filesystem::path const& _path); + private: + /// If @a _path starts with a number of .. segments, returns a path consisting only of those + /// segments (root name is not included). Otherwise returns an empty path. @a _path must be + /// absolute (or have slash as root). + static boost::filesystem::path absoluteDotDotPrefix(boost::filesystem::path const& _path); + + /// @returns true if the path contains any .. segments. + static bool hasDotDotSegments(boost::filesystem::path const& _path); + /// Base path, used for resolving relative paths in imports. boost::filesystem::path m_basePath; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 17300c660a08..2afed29b247c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -103,6 +103,7 @@ set(libsolidity_sources libsolidity/SyntaxTest.h libsolidity/ViewPureChecker.cpp libsolidity/analysis/FunctionCallGraph.cpp + libsolidity/interface/FileReader.cpp ) detect_stray_source_files("${libsolidity_sources}" "libsolidity/") diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp new file mode 100644 index 000000000000..aa55b5d42241 --- /dev/null +++ b/test/libsolidity/interface/FileReader.cpp @@ -0,0 +1,443 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +/// Unit tests for libsolidity/interface/FileReader.h + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace solidity::test; + + +namespace solidity::frontend::test +{ + +BOOST_AUTO_TEST_SUITE(FileReaderTest) + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path) +{ + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/.") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./.") == "/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a") == "/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/") == "/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/.") == "/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./a") == "/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./a/") == "/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./a/.") == "/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b") == "/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/") == "/a/b/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/./b/") == "/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/../a/b/") == "/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/..") == "/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/../") == "/a/b/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../") == "/"); +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) +{ + TemporaryDirectory tempDir("file-reader-test-"); + boost::filesystem::create_directories(tempDir.path() / "x/y/z"); + TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "x/y/z"); + + // NOTE: If path to work dir contains symlinks (often the case on macOS), boost might resolve + // them, making the path different from tempDirPath. + boost::filesystem::path expectedPrefix = boost::filesystem::current_path().parent_path().parent_path().parent_path(); + // On Windows tempDir.path() normally contains the drive letter while the normalized path should not. + expectedPrefix = "/" / expectedPrefix.relative_path(); + soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS(".") == expectedPrefix / "x/y/z/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("./") == expectedPrefix / "x/y/z/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../") == expectedPrefix / "x/y/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a") == expectedPrefix / "x/y/z/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/") == expectedPrefix / "x/y/z/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/.") == expectedPrefix / "x/y/z/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a") == expectedPrefix / "x/y/z/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a/") == expectedPrefix / "x/y/z/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a/.") == expectedPrefix / "x/y/z/a/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b") == expectedPrefix / "x/y/z/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b/") == expectedPrefix / "x/y/z/a/b/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a/b") == expectedPrefix / "x/y/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/b") == expectedPrefix / "x/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a/b") == expectedPrefix / "x/y/z/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("././a/b") == expectedPrefix / "x/y/z/a/b"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/./b/") == expectedPrefix / "x/y/z/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/../a/b/") == expectedPrefix / "x/y/z/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b/c/..") == expectedPrefix / "x/y/z/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b/c/../") == expectedPrefix / "x/y/z/a/b/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b") == expectedPrefix / "a/b"); + +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes) +{ + BOOST_TEST(FileReader::normalizeCLIPathForVFS("///") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("////") == "/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("////a/b/") == "/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a//b/") == "/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a////b/") == "/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b//") == "/a/b/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b////") == "/a/b/"); +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) +{ + TemporaryDirectory tempDir("file-reader-test-"); + TemporaryWorkingDirectory tempWorkDir(tempDir.path()); + + // On Windows tempDir.path() normally contains the drive letter while the normalized path should not. + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path(); + soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", ""); + + // UNC paths start with // or \\ followed by a name. They are used for network shares on Windows. + // On UNIX systems they are not supported but still treated in a special way. + BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host/") == "//host/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host/a/b") == "//host/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host/a/b/") == "//host/a/b/"); + +#if defined(_WIN32) + // On Windows an UNC path can also start with \\ instead of // + BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/") == "//host/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b") == "//host/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/") == "//host/a/b/"); +#else + // On UNIX systems it's just a fancy relative path instead + BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/") == expectedWorkDir / "\\\\host/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b") == expectedWorkDir / "\\\\host/a/b"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/") == expectedWorkDir / "\\\\host/a/b/"); +#endif +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) +{ + TemporaryDirectory tempDir("file-reader-test-"); + TemporaryWorkingDirectory tempWorkDir(tempDir.path()); + + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path(); + soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", ""); + + // A root **path** consists of a directory name (typically / or \) and the root name (drive + // letter (C:), UNC host name (//host), etc.). Either can be empty. Root path as a whole may be + // an absolute path but root name on its own is considered relative. For example on Windows + // C:\ represents the root directory of drive C: but C: on its own refers to the current working + // directory. + + // UNC paths + BOOST_TEST(FileReader::normalizeCLIPathForVFS("//") == "//" / expectedWorkDir); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host") == "//host" / expectedWorkDir); + + // On UNIX systems root name is empty. + BOOST_TEST(FileReader::normalizeCLIPathForVFS("") == expectedWorkDir); + +#if defined(_WIN32) + boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name(); + solAssert(!driveLetter.empty(), ""); + solAssert(driveLetter.is_relative(), ""); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS(driveLetter) == expectedWorkDir); +#endif +} + +#if defined(_WIN32) +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name) +{ + TemporaryDirectory tempDir("file-reader-test-"); + TemporaryWorkingDirectory tempWorkDir(tempDir.path()); + + soltestAssert(boost::filesystem::current_path().is_absolute(), ""); + soltestAssert(!boost::filesystem::current_path().root_name().empty(), ""); + + boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(boost::filesystem::current_path()); + BOOST_TEST(normalizedPath == "/" / boost::filesystem::current_path().relative_path()); + BOOST_TEST(normalizedPath.root_name().empty()); + BOOST_TEST(normalizedPath.root_directory() == "/"); +} +#endif + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) +{ + TemporaryWorkingDirectory tempWorkDir("/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../.") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../a") == "/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../a/..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../a/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../../a") == "/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../../a/..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../../a/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/../../b/../..") == "/"); + + BOOST_TEST(FileReader::normalizeCLIPathForVFS("..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../.") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a") == "/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a/..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a") == "/a"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/../..") == "/"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/../../b/../..") == "/"); +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) +{ + TemporaryDirectory tempDir("file-reader-test-"); + TemporaryWorkingDirectory tempWorkDir(tempDir.path()); + boost::filesystem::create_directories(tempDir.path() / "abc"); + + boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); + soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); + + bool caseSensitiveFilesystem = boost::filesystem::create_directories(tempDir.path() / "ABC"); + soltestAssert(boost::filesystem::equivalent(tempDir.path() / "abc", tempDir.path() / "ABC") != caseSensitiveFilesystem, ""); + + BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "abc")) == (expectedPrefix / "abc"))); + BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "abc")) != (expectedPrefix / "ABC"))); + BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "ABC")) != (expectedPrefix / "abc"))); + BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "ABC")) == (expectedPrefix / "ABC"))); +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators) +{ + // Even on Windows we want / as a separator. + BOOST_TEST((FileReader::normalizeCLIPathForVFS("/a/b/c").native() == boost::filesystem::path("/a/b/c").native())); +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) +{ + TemporaryDirectory tempDir("file-reader-test-"); + soltestAssert(tempDir.path().is_absolute(), ""); + boost::filesystem::create_directories(tempDir.path() / "abc"); + + if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true)) + return; + + boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); + soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); + + BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol")); + BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol")); +} + +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative) +{ + TemporaryDirectory tempDir("file-reader-test-"); + soltestAssert(tempDir.path().is_absolute(), ""); + boost::filesystem::create_directories(tempDir.path() / "abc"); + + if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true)) + return; + + TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "sym"); + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::weakly_canonical(boost::filesystem::current_path()).relative_path(); + soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", ""); + + boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); + soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); + + BOOST_TEST((FileReader::normalizeCLIPathForVFS("contract.sol") == expectedWorkDir / "contract.sol")); + BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol")); + BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol")); +} + +BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix) +{ + BOOST_TEST(FileReader::isPathPrefix("/", "/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/contract.sol", "/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/contract.sol/", "/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/contract.sol/.", "/contract.sol")); + + BOOST_TEST(FileReader::isPathPrefix("/", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a/", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a/bc", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a/bc/def/contract.sol", "/a/bc/def/contract.sol")); + + BOOST_TEST(FileReader::isPathPrefix("/", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a/", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a/bc", "/a/bc/def/contract.sol")); + BOOST_TEST(FileReader::isPathPrefix("/a/bc/def/contract.sol", "/a/bc/def/contract.sol")); + + BOOST_TEST(!FileReader::isPathPrefix("/contract.sol", "/token.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/contract", "/contract.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/contract.sol", "/contract")); + BOOST_TEST(!FileReader::isPathPrefix("/contract.so", "/contract.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/contract.sol", "/contract.so")); + + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/contract.sol", "/a/b/contract.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/contract.sol", "/a/b/c/contract.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/contract.sol", "/a/b/c/d/contract.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/d/contract.sol", "/a/b/c/contract.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/contract.sol", "/contract.sol")); +} + +BOOST_AUTO_TEST_CASE(isPathPrefix_directory_prefix) +{ + BOOST_TEST(FileReader::isPathPrefix("/", "/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/", "/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c", "/")); + + BOOST_TEST(FileReader::isPathPrefix("/", "/a/bc/")); + BOOST_TEST(FileReader::isPathPrefix("/a", "/a/bc/")); + BOOST_TEST(FileReader::isPathPrefix("/a/", "/a/bc/")); + BOOST_TEST(FileReader::isPathPrefix("/a/bc", "/a/bc/")); + BOOST_TEST(FileReader::isPathPrefix("/a/bc/", "/a/bc/")); + + BOOST_TEST(!FileReader::isPathPrefix("/a", "/b/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/", "/b/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/contract.sol", "/a/b/")); + + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/", "/a/b/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c", "/a/b/")); +} + +BOOST_AUTO_TEST_CASE(isPathPrefix_unc_path) +{ + BOOST_TEST(FileReader::isPathPrefix("//host/a/b/", "//host/a/b/")); + BOOST_TEST(FileReader::isPathPrefix("//host/a/b", "//host/a/b/")); + BOOST_TEST(FileReader::isPathPrefix("//host/a/", "//host/a/b/")); + BOOST_TEST(FileReader::isPathPrefix("//host/a", "//host/a/b/")); + BOOST_TEST(FileReader::isPathPrefix("//host/", "//host/a/b/")); + + // NOTE: //host and // cannot be passed to isPathPrefix() because they are considered relative. + + BOOST_TEST(!FileReader::isPathPrefix("//host1/", "//host2/")); + BOOST_TEST(!FileReader::isPathPrefix("//host1/a/b/", "//host2/a/b/")); + + BOOST_TEST(!FileReader::isPathPrefix("/a/b/c/", "//a/b/c/")); + BOOST_TEST(!FileReader::isPathPrefix("//a/b/c/", "/a/b/c/")); +} + +BOOST_AUTO_TEST_CASE(isPathPrefix_case_sensitivity) +{ + BOOST_TEST(!FileReader::isPathPrefix("/a.sol", "/A.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/A.sol", "/a.sol")); + BOOST_TEST(!FileReader::isPathPrefix("/A/", "/a/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/", "/A/")); + BOOST_TEST(!FileReader::isPathPrefix("/a/BC/def/", "/a/bc/def/contract.sol")); +} + +BOOST_AUTO_TEST_CASE(stripPrefixIfPresent_file_prefix) +{ + BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/contract.sol") == "contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol", "/contract.sol") == "."); + BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol/", "/contract.sol") == "."); + BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol/.", "/contract.sol") == "."); + + BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/a/bc/def/contract.sol") == "a/bc/def/contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a", "/a/bc/def/contract.sol") == "bc/def/contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/", "/a/bc/def/contract.sol") == "bc/def/contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc", "/a/bc/def/contract.sol") == "def/contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc/def/", "/a/bc/def/contract.sol") == "contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc/def/contract.sol", "/a/bc/def/contract.sol") == "."); + + + BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol", "/token.sol") == "/token.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/contract", "/contract.sol") == "/contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol", "/contract") == "/contract"); + + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/c/contract.sol", "/a/b/contract.sol") == "/a/b/contract.sol"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/contract.sol", "/a/b/c/contract.sol") == "/a/b/c/contract.sol"); +} + +BOOST_AUTO_TEST_CASE(stripPrefixIfPresent_directory_prefix) +{ + BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/") == "."); + + BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/a/bc/def/") == "a/bc/def/"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a", "/a/bc/def/") == "bc/def/"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/", "/a/bc/def/") == "bc/def/"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc", "/a/bc/def/") == "def/"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc/def/", "/a/bc/def/") == "."); + + BOOST_TEST(FileReader::stripPrefixIfPresent("/a", "/b/") == "/b/"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/", "/b/") == "/b/"); + + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/c/", "/a/b/") == "/a/b/"); + BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/c", "/a/b/") == "/a/b/"); +} + +BOOST_AUTO_TEST_CASE(isUNCPath) +{ + BOOST_TEST(FileReader::isUNCPath("//")); + BOOST_TEST(FileReader::isUNCPath("//root")); + BOOST_TEST(FileReader::isUNCPath("//root/")); + +#if defined(_WIN32) + // On Windows boost sees these as ///, which is equivalent to / + BOOST_TEST(!FileReader::isUNCPath("//\\")); + BOOST_TEST(!FileReader::isUNCPath("\\\\/")); + BOOST_TEST(!FileReader::isUNCPath("\\/\\")); + + BOOST_TEST(FileReader::isUNCPath("\\\\")); + BOOST_TEST(FileReader::isUNCPath("\\\\root")); + BOOST_TEST(FileReader::isUNCPath("\\\\root/")); +#else + // On UNIX it's actually an UNC path + BOOST_TEST(FileReader::isUNCPath("//\\")); + + // On UNIX these are just weird relative directory names consisting only of backslashes. + BOOST_TEST(!FileReader::isUNCPath("\\\\/")); + BOOST_TEST(!FileReader::isUNCPath("\\/\\")); + + BOOST_TEST(!FileReader::isUNCPath("\\\\")); + BOOST_TEST(!FileReader::isUNCPath("\\\\root")); + BOOST_TEST(!FileReader::isUNCPath("\\\\root/")); +#endif + + BOOST_TEST(!FileReader::isUNCPath("\\/")); + BOOST_TEST(!FileReader::isUNCPath("/\\")); + + BOOST_TEST(!FileReader::isUNCPath("")); + BOOST_TEST(!FileReader::isUNCPath(".")); + BOOST_TEST(!FileReader::isUNCPath("..")); + BOOST_TEST(!FileReader::isUNCPath("/")); + BOOST_TEST(!FileReader::isUNCPath("a")); + BOOST_TEST(!FileReader::isUNCPath("a/b/c")); + BOOST_TEST(!FileReader::isUNCPath("contract.sol")); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace solidity::frontend::test From 8e1f005226196ff845bdf1f06b84cffe5db02329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 21 Jul 2021 18:50:58 +0200 Subject: [PATCH 03/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- libsolidity/interface/FileReader.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index 76c283c46e45..57cc9dce0b32 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -98,6 +98,7 @@ class FileReader /// Paths are treated as case-sensitive. Does not require the path to actually exist in the /// filesystem and does not follow symlinks. Only considers whole segments, e.g. /abc/d is not /// considered a prefix of /abc/def. Both paths must be non-empty. + /// Ignores the trailing slash, i.e. /a/b/c.sol/ is treated as a valid prefix of /a/b/c.sol. static bool isPathPrefix(boost::filesystem::path _prefix, boost::filesystem::path const& _path); /// If @a _prefix is actually a prefix of @p _path, removes it from @a _path to make it relative. From 69cd3d9305419531229909d86b6928b7be182a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 23 Jul 2021 21:57:25 +0200 Subject: [PATCH 04/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- libsolidity/interface/FileReader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index a4d640c68d3a..ce5e5e57d46d 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -133,9 +133,6 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa boost::filesystem::path normalizedPath = absolutePath.lexically_normal(); solAssert(normalizedPath.is_absolute() || normalizedPath.root_path() == "/", ""); - // lexically_normal() will not squash paths like "/../../" into "/". We have to do it manually. - boost::filesystem::path dotDotPrefix = absoluteDotDotPrefix(normalizedPath); - // If the path is on the same drive as the working dir, for portability we prefer not to // include the root name. Do this only for non-UNC paths - my experiments show that on Windows // when the working dir is an UNC path, / does not not actually refer to the root of the UNC path. @@ -147,6 +144,9 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa normalizedRootPath = "/"; } + // lexically_normal() will not squash paths like "/../../" into "/". We have to do it manually. + boost::filesystem::path dotDotPrefix = absoluteDotDotPrefix(normalizedPath); + boost::filesystem::path normalizedPathNoDotDot = normalizedPath; if (dotDotPrefix.empty()) normalizedPathNoDotDot = normalizedRootPath / normalizedPath.relative_path(); From 5a28939c276139a639b0467f285c61804b54cf33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 22 Jul 2021 22:30:28 +0200 Subject: [PATCH 05/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- test/libsolidity/interface/FileReader.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index aa55b5d42241..734756b8d59e 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -223,14 +223,10 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) { TemporaryDirectory tempDir("file-reader-test-"); TemporaryWorkingDirectory tempWorkDir(tempDir.path()); - boost::filesystem::create_directories(tempDir.path() / "abc"); boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - bool caseSensitiveFilesystem = boost::filesystem::create_directories(tempDir.path() / "ABC"); - soltestAssert(boost::filesystem::equivalent(tempDir.path() / "abc", tempDir.path() / "ABC") != caseSensitiveFilesystem, ""); - BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "abc")) == (expectedPrefix / "abc"))); BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "abc")) != (expectedPrefix / "ABC"))); BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "ABC")) != (expectedPrefix / "abc"))); From b1f487cac40f5fa6a32aaa23ff2486f754475f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 20 Jul 2021 12:22:09 +0200 Subject: [PATCH 06/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- test/libsolidity/interface/FileReader.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index 734756b8d59e..13d7cb0db02b 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -31,6 +31,7 @@ using namespace std; using namespace solidity::test; +#define TEST_CASE_NAME (boost::unit_test::framework::current_test_case().p_name) namespace solidity::frontend::test { @@ -64,7 +65,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); boost::filesystem::create_directories(tempDir.path() / "x/y/z"); TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "x/y/z"); @@ -116,7 +117,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); TemporaryWorkingDirectory tempWorkDir(tempDir.path()); // On Windows tempDir.path() normally contains the drive letter while the normalized path should not. @@ -144,7 +145,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); TemporaryWorkingDirectory tempWorkDir(tempDir.path()); boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path(); @@ -175,7 +176,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) #if defined(_WIN32) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); TemporaryWorkingDirectory tempWorkDir(tempDir.path()); soltestAssert(boost::filesystem::current_path().is_absolute(), ""); @@ -221,7 +222,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); TemporaryWorkingDirectory tempWorkDir(tempDir.path()); boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); @@ -241,7 +242,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); soltestAssert(tempDir.path().is_absolute(), ""); boost::filesystem::create_directories(tempDir.path() / "abc"); @@ -257,7 +258,7 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative) { - TemporaryDirectory tempDir("file-reader-test-"); + TemporaryDirectory tempDir(TEST_CASE_NAME); soltestAssert(tempDir.path().is_absolute(), ""); boost::filesystem::create_directories(tempDir.path() / "abc"); From 8b25944ccbfd4a2e446135c4845f245dcbd8262e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 23 Jul 2021 15:08:30 +0200 Subject: [PATCH 07/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- test/libsolidity/interface/FileReader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index 13d7cb0db02b..dab2568e5ed7 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -228,10 +228,10 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "abc")) == (expectedPrefix / "abc"))); - BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "abc")) != (expectedPrefix / "ABC"))); - BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "ABC")) != (expectedPrefix / "abc"))); - BOOST_TEST((FileReader::normalizeCLIPathForVFS((tempDir.path() / "ABC")) == (expectedPrefix / "ABC"))); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") == expectedPrefix / "abc"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") != expectedPrefix / "ABC"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") != expectedPrefix / "abc"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") == expectedPrefix / "ABC"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators) @@ -252,8 +252,8 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol")); - BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol")); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative) @@ -272,9 +272,9 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_w boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_TEST((FileReader::normalizeCLIPathForVFS("contract.sol") == expectedWorkDir / "contract.sol")); - BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol")); - BOOST_TEST((FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol")); + BOOST_TEST(FileReader::normalizeCLIPathForVFS("contract.sol") == expectedWorkDir / "contract.sol"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol"); } BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix) From 1dd630ad56c7bde4e84b13563c96b4fcb52012fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 23 Jul 2021 15:53:50 +0200 Subject: [PATCH 08/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- test/libsolidity/interface/FileReader.cpp | 254 +++++++++++----------- 1 file changed, 126 insertions(+), 128 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index dab2568e5ed7..a446976b31ee 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -40,27 +40,27 @@ BOOST_AUTO_TEST_SUITE(FileReaderTest) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path) { - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/.") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./.") == "/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a") == "/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/") == "/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/.") == "/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./a") == "/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./a/") == "/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/./a/.") == "/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b") == "/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/") == "/a/b/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/./b/") == "/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/../a/b/") == "/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/..") == "/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/../") == "/a/b/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../") == "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/"), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./"), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./."), "/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a"), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/"), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/."), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a"), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/"), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/."), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b"), "/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/"), "/a/b/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/.."), "/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../"), "/a/b/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../"), "/"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) @@ -76,43 +76,42 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) expectedPrefix = "/" / expectedPrefix.relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(".") == expectedPrefix / "x/y/z/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("./") == expectedPrefix / "x/y/z/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../") == expectedPrefix / "x/y/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a") == expectedPrefix / "x/y/z/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/") == expectedPrefix / "x/y/z/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/.") == expectedPrefix / "x/y/z/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a") == expectedPrefix / "x/y/z/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a/") == expectedPrefix / "x/y/z/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a/.") == expectedPrefix / "x/y/z/a/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b") == expectedPrefix / "x/y/z/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b/") == expectedPrefix / "x/y/z/a/b/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a/b") == expectedPrefix / "x/y/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/b") == expectedPrefix / "x/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("./a/b") == expectedPrefix / "x/y/z/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("././a/b") == expectedPrefix / "x/y/z/a/b"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/./b/") == expectedPrefix / "x/y/z/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/../a/b/") == expectedPrefix / "x/y/z/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b/c/..") == expectedPrefix / "x/y/z/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/b/c/../") == expectedPrefix / "x/y/z/a/b/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b") == expectedPrefix / "a/b"); - + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("."), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./"), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), expectedPrefix / "x/y/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a"), expectedPrefix / "x/y/z/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/."), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a"), expectedPrefix / "x/y/z/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/."), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b"), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/"), expectedPrefix / "x/y/z/a/b/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b"), expectedPrefix / "x/y/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b"), expectedPrefix / "x/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b"), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b"), expectedPrefix / "x/y/z/a/b"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/"), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/"), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/.."), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../"), expectedPrefix / "x/y/z/a/b/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b"), expectedPrefix / "a/b"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes) { - BOOST_TEST(FileReader::normalizeCLIPathForVFS("///") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("////") == "/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("////a/b/") == "/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a//b/") == "/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a////b/") == "/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b//") == "/a/b/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/b////") == "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///"), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////"), "/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////"), "/a/b/"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) @@ -126,20 +125,20 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) // UNC paths start with // or \\ followed by a name. They are used for network shares on Windows. // On UNIX systems they are not supported but still treated in a special way. - BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host/") == "//host/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host/a/b") == "//host/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host/a/b/") == "//host/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/"), "//host/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b"), "//host/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/"), "//host/a/b/"); #if defined(_WIN32) // On Windows an UNC path can also start with \\ instead of // - BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/") == "//host/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b") == "//host/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/") == "//host/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), "//host/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), "//host/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), "//host/a/b/"); #else // On UNIX systems it's just a fancy relative path instead - BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/") == expectedWorkDir / "\\\\host/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b") == expectedWorkDir / "\\\\host/a/b"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/") == expectedWorkDir / "\\\\host/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), expectedWorkDir / "\\\\host/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), expectedWorkDir / "\\\\host/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), expectedWorkDir / "\\\\host/a/b/"); #endif } @@ -158,18 +157,18 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) // directory. // UNC paths - BOOST_TEST(FileReader::normalizeCLIPathForVFS("//") == "//" / expectedWorkDir); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("//host") == "//host" / expectedWorkDir); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//"), "//" / expectedWorkDir); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host"), "//host" / expectedWorkDir); // On UNIX systems root name is empty. - BOOST_TEST(FileReader::normalizeCLIPathForVFS("") == expectedWorkDir); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(""), expectedWorkDir); #if defined(_WIN32) boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name(); solAssert(!driveLetter.empty(), ""); solAssert(driveLetter.is_relative(), ""); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(driveLetter) == expectedWorkDir); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter), expectedWorkDir); #endif } @@ -183,9 +182,9 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name) soltestAssert(!boost::filesystem::current_path().root_name().empty(), ""); boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(boost::filesystem::current_path()); - BOOST_TEST(normalizedPath == "/" / boost::filesystem::current_path().relative_path()); + BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path()); BOOST_TEST(normalizedPath.root_name().empty()); - BOOST_TEST(normalizedPath.root_directory() == "/"); + BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/"); } #endif @@ -193,31 +192,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) { TemporaryWorkingDirectory tempWorkDir("/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../.") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../a") == "/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../a/..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../a/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../../a") == "/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../../a/..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/../../a/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("/a/../../b/../..") == "/"); - - BOOST_TEST(FileReader::normalizeCLIPathForVFS("..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../.") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a") == "/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a/..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../a/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a") == "/a"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("../../a/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/../..") == "/"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("a/../../b/../..") == "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../"), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a"), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a"), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../.."), "/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a"), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a"), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../.."), "/"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) @@ -252,8 +251,8 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol"); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative) @@ -272,9 +271,9 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_w boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_TEST(FileReader::normalizeCLIPathForVFS("contract.sol") == expectedWorkDir / "contract.sol"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol") == expectedPrefix / "sym/contract.sol"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol") == expectedPrefix / "abc/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("contract.sol"), expectedWorkDir / "contract.sol"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol"); } BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix) @@ -357,42 +356,41 @@ BOOST_AUTO_TEST_CASE(isPathPrefix_case_sensitivity) BOOST_AUTO_TEST_CASE(stripPrefixIfPresent_file_prefix) { - BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/contract.sol") == "contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol", "/contract.sol") == "."); - BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol/", "/contract.sol") == "."); - BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol/.", "/contract.sol") == "."); - - BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/a/bc/def/contract.sol") == "a/bc/def/contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a", "/a/bc/def/contract.sol") == "bc/def/contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/", "/a/bc/def/contract.sol") == "bc/def/contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc", "/a/bc/def/contract.sol") == "def/contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc/def/", "/a/bc/def/contract.sol") == "contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc/def/contract.sol", "/a/bc/def/contract.sol") == "."); - - - BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol", "/token.sol") == "/token.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/contract", "/contract.sol") == "/contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/contract.sol", "/contract") == "/contract"); - - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/c/contract.sol", "/a/b/contract.sol") == "/a/b/contract.sol"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/contract.sol", "/a/b/c/contract.sol") == "/a/b/c/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/", "/contract.sol"), "contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/contract.sol", "/contract.sol"), "."); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/contract.sol/", "/contract.sol"), "."); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/contract.sol/.", "/contract.sol"), "."); + + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/", "/a/bc/def/contract.sol"), "a/bc/def/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a", "/a/bc/def/contract.sol"), "bc/def/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/", "/a/bc/def/contract.sol"), "bc/def/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/bc", "/a/bc/def/contract.sol"), "def/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/bc/def/", "/a/bc/def/contract.sol"), "contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/bc/def/contract.sol", "/a/bc/def/contract.sol"), "."); + + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/contract.sol", "/token.sol"), "/token.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/contract", "/contract.sol"), "/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/contract.sol", "/contract"), "/contract"); + + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/b/c/contract.sol", "/a/b/contract.sol"), "/a/b/contract.sol"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/b/contract.sol", "/a/b/c/contract.sol"), "/a/b/c/contract.sol"); } BOOST_AUTO_TEST_CASE(stripPrefixIfPresent_directory_prefix) { - BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/") == "."); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/", "/"), "."); - BOOST_TEST(FileReader::stripPrefixIfPresent("/", "/a/bc/def/") == "a/bc/def/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a", "/a/bc/def/") == "bc/def/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/", "/a/bc/def/") == "bc/def/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc", "/a/bc/def/") == "def/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/bc/def/", "/a/bc/def/") == "."); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/", "/a/bc/def/"), "a/bc/def/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a", "/a/bc/def/"), "bc/def/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/", "/a/bc/def/"), "bc/def/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/bc", "/a/bc/def/"), "def/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/bc/def/", "/a/bc/def/"), "."); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a", "/b/") == "/b/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/", "/b/") == "/b/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a", "/b/"), "/b/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/", "/b/"), "/b/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/c/", "/a/b/") == "/a/b/"); - BOOST_TEST(FileReader::stripPrefixIfPresent("/a/b/c", "/a/b/") == "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/b/c/", "/a/b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::stripPrefixIfPresent("/a/b/c", "/a/b/"), "/a/b/"); } BOOST_AUTO_TEST_CASE(isUNCPath) From 3a944d586a4d7d471cd5efdba0fa884aed81e4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 23 Jul 2021 17:06:44 +0200 Subject: [PATCH 09/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- libsolidity/interface/FileReader.cpp | 2 ++ test/libsolidity/interface/FileReader.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index ce5e5e57d46d..34980e9f2bcb 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -119,6 +119,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa // - Does NOT resolve symlinks (except for symlinks in the path to the current working directory). // - Does NOT check if the path refers to a file or a directory. If the path ends with a slash, // the slash is preserved even if it's a file. + // - The only exception are paths where the file name is a dot (e.g. '.' or 'a/b/.'). These + // always have a trailing slash after normalization. // - Preserves case. Even if the filesystem is case-insensitive but case-preserving and the // case differs, the actual case from disk is NOT detected. diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index a446976b31ee..53a7d928724e 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -78,7 +78,10 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("."), expectedPrefix / "x/y/z/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./"), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//"), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), expectedPrefix / "x/y"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), expectedPrefix / "x/y/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//"), expectedPrefix / "x/y/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a"), expectedPrefix / "x/y/z/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/"), expectedPrefix / "x/y/z/a/"); @@ -86,6 +89,11 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a"), expectedPrefix / "x/y/z/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/"), expectedPrefix / "x/y/z/a/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/."), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./."), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/"), expectedPrefix / "x/y/z/a/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b"), expectedPrefix / "x/y/z/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/"), expectedPrefix / "x/y/z/a/b/"); @@ -98,6 +106,10 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/"), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/.."), expectedPrefix / "x/y/z/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../"), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//"), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../.."), expectedPrefix / "x/y/z/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//"), expectedPrefix / "x/y/z/a/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b"), expectedPrefix / "a/b"); } From b8e7786ada9290b44f2d25ee5c4806e3b3d1e96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 24 Jul 2021 02:38:54 +0200 Subject: [PATCH 10/10] fixup! FileReader: Normalize base path and strip it from normalized source paths --- test/libsolidity/interface/FileReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index 53a7d928724e..be0cd32f963f 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -184,21 +184,21 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) #endif } -#if defined(_WIN32) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name) { TemporaryDirectory tempDir(TEST_CASE_NAME); TemporaryWorkingDirectory tempWorkDir(tempDir.path()); soltestAssert(boost::filesystem::current_path().is_absolute(), ""); +#if defined(_WIN32) soltestAssert(!boost::filesystem::current_path().root_name().empty(), ""); +#endif boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(boost::filesystem::current_path()); BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path()); BOOST_TEST(normalizedPath.root_name().empty()); BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/"); } -#endif BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) {