mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1671035 - Add a WebIDL backed path manipulation utility r=Gijs,nika
PathUtils is a path manipulation component to IOUtils, which is based on simplified file I/O. This work is part of the larger goal of removing osfile.jsm et al., ospath.jsm et al., and the entire OS.* namespace, especially from the startup path. No equivalent was provided for OS.Path.fromFileURI because it is unused. Differential Revision: https://phabricator.services.mozilla.com/D95105
This commit is contained in:
parent
f3863e87b5
commit
ac6be32a0a
73
dom/chrome-webidl/PathUtils.webidl
Normal file
73
dom/chrome-webidl/PathUtils.webidl
Normal file
@ -0,0 +1,73 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PathUtils is a set of utilities for operating on absolute paths.
|
||||
*/
|
||||
[ChromeOnly, Exposed=(Window, Worker)]
|
||||
namespace PathUtils {
|
||||
/**
|
||||
* Return the last path component.
|
||||
*
|
||||
* @param path An absolute path.
|
||||
*
|
||||
* @returns The last path component.
|
||||
*/
|
||||
[Throws]
|
||||
DOMString filename(DOMString path);
|
||||
|
||||
/**
|
||||
* Return the parent directory name of the given path.
|
||||
*
|
||||
* @param path An absolute path.
|
||||
*
|
||||
* @return The parent directory.
|
||||
*
|
||||
* If the path provided is a root path (e.g., `C:` on Windows or `/`
|
||||
* on *NIX), then null is returned.
|
||||
*/
|
||||
[Throws]
|
||||
DOMString? parent(DOMString path);
|
||||
|
||||
/**
|
||||
* Join the given components into a full path.
|
||||
*
|
||||
* @param components The path components. The first component must be an
|
||||
* absolute path.
|
||||
*/
|
||||
[Throws]
|
||||
DOMString join(DOMString... components);
|
||||
|
||||
/**
|
||||
* Normalize a path by removing multiple separators and `..` and `.`
|
||||
* directories.
|
||||
*
|
||||
* On UNIX platforms, the path must exist as symbolic links will be resolved.
|
||||
*
|
||||
* @param path The absolute path to normalize.
|
||||
*
|
||||
*/
|
||||
[Throws]
|
||||
DOMString normalize(DOMString path);
|
||||
|
||||
/**
|
||||
* Split a path into its components.
|
||||
*
|
||||
* @param path An absolute path.
|
||||
*/
|
||||
[Throws]
|
||||
sequence<DOMString> split(DOMString path);
|
||||
|
||||
/**
|
||||
* Transform a file path into a file: URI
|
||||
*
|
||||
* @param path An absolute path.
|
||||
*
|
||||
* @return The file: URI as a string.
|
||||
*/
|
||||
[Throws]
|
||||
UTF8String toFileURI(DOMString path);
|
||||
};
|
@ -65,6 +65,7 @@ WEBIDL_FILES = [
|
||||
"MozStorageAsyncStatementParams.webidl",
|
||||
"MozStorageStatementParams.webidl",
|
||||
"MozStorageStatementRow.webidl",
|
||||
"PathUtils.webidl",
|
||||
"PrecompiledScript.webidl",
|
||||
"PromiseDebugging.webidl",
|
||||
"SessionStoreUtils.webidl",
|
||||
|
242
dom/system/PathUtils.cpp
Normal file
242
dom/system/PathUtils.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "PathUtils.h"
|
||||
|
||||
#include "mozilla/ErrorNames.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "mozilla/dom/DOMParser.h"
|
||||
#include "mozilla/dom/PathUtilsBinding.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsLocalFile.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static constexpr auto ERROR_EMPTY_PATH =
|
||||
"PathUtils does not support empty paths"_ns;
|
||||
static constexpr auto ERROR_INITIALIZE_PATH = "Could not initialize path"_ns;
|
||||
static constexpr auto ERROR_GET_PARENT = "Could not get parent path"_ns;
|
||||
|
||||
static void ThrowError(ErrorResult& aErr, const nsresult aResult,
|
||||
const nsCString& aMessage) {
|
||||
nsAutoCStringN<32> errName;
|
||||
GetErrorName(aResult, errName);
|
||||
|
||||
nsAutoCStringN<256> formattedMsg;
|
||||
formattedMsg.Append(aMessage);
|
||||
formattedMsg.Append(": "_ns);
|
||||
formattedMsg.Append(errName);
|
||||
|
||||
switch (aResult) {
|
||||
case NS_ERROR_FILE_UNRECOGNIZED_PATH:
|
||||
aErr.ThrowOperationError(formattedMsg);
|
||||
break;
|
||||
|
||||
case NS_ERROR_FILE_ACCESS_DENIED:
|
||||
aErr.ThrowInvalidAccessError(formattedMsg);
|
||||
break;
|
||||
|
||||
case NS_ERROR_FAILURE:
|
||||
default:
|
||||
aErr.ThrowUnknownError(formattedMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the leaf name, including leading path separators in the case of
|
||||
* Windows UNC drive paths.
|
||||
*
|
||||
* @param aFile The file whose leaf name is to be returned.
|
||||
* @param aResult The string to hold the resulting leaf name.
|
||||
* @param aParent The pre-computed parent of |aFile|. If not provided, it will
|
||||
* be computed.
|
||||
*/
|
||||
static nsresult GetLeafNamePreservingRoot(nsIFile* aFile, nsString& aResult,
|
||||
nsIFile* aParent = nullptr) {
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
nsCOMPtr<nsIFile> parent = aParent;
|
||||
if (!parent) {
|
||||
MOZ_TRY(aFile->GetParent(getter_AddRefs(parent)));
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
return aFile->GetLeafName(aResult);
|
||||
}
|
||||
|
||||
// We have reached the root path. On Windows, the leafname for a UNC path
|
||||
// will not have the leading backslashes, so we need to use the entire path
|
||||
// here:
|
||||
//
|
||||
// * for a UNIX root path (/) this will be /;
|
||||
// * for a Windows drive path (e.g., C:), this will be the drive path (C:);
|
||||
// and
|
||||
// * for a Windows UNC server path (e.g., \\\\server), this will be the full
|
||||
// server path (\\\\server).
|
||||
return aFile->GetPath(aResult);
|
||||
}
|
||||
|
||||
void PathUtils::Filename(const GlobalObject&, const nsAString& aPath,
|
||||
nsString& aResult, ErrorResult& aErr) {
|
||||
if (aPath.IsEmpty()) {
|
||||
aErr.ThrowNotAllowedError("PathUtils does not support empty paths");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> path = new nsLocalFile();
|
||||
if (nsresult rv = path->InitWithPath(aPath); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_INITIALIZE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsresult rv = GetLeafNamePreservingRoot(path, aResult); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, "Could not get leaf name of path"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PathUtils::Parent(const GlobalObject&, const nsAString& aPath,
|
||||
nsString& aResult, ErrorResult& aErr) {
|
||||
if (aPath.IsEmpty()) {
|
||||
aErr.ThrowNotAllowedError(ERROR_EMPTY_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> path = new nsLocalFile();
|
||||
if (nsresult rv = path->InitWithPath(aPath); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_INITIALIZE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
if (nsresult rv = path->GetParent(getter_AddRefs(parent)); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_GET_PARENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
MOZ_ALWAYS_SUCCEEDS(parent->GetPath(aResult));
|
||||
} else {
|
||||
aResult = VoidString();
|
||||
}
|
||||
}
|
||||
|
||||
void PathUtils::Join(const GlobalObject&, const Sequence<nsString>& aComponents,
|
||||
nsString& aResult, ErrorResult& aErr) {
|
||||
if (aComponents.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (aComponents[0].IsEmpty()) {
|
||||
aErr.ThrowNotAllowedError(ERROR_EMPTY_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> path = new nsLocalFile();
|
||||
if (nsresult rv = path->InitWithPath(aComponents[0]); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_INITIALIZE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto components = Span<const nsString>(aComponents).Subspan(1);
|
||||
for (const auto& component : components) {
|
||||
if (nsresult rv = path->Append(component); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, "Could not append to path"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(path->GetPath(aResult));
|
||||
}
|
||||
|
||||
void PathUtils::Normalize(const GlobalObject&, const nsAString& aPath,
|
||||
nsString& aResult, ErrorResult& aErr) {
|
||||
if (aPath.IsEmpty()) {
|
||||
aErr.ThrowNotAllowedError(ERROR_EMPTY_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> path = new nsLocalFile();
|
||||
if (nsresult rv = path->InitWithPath(aPath); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_INITIALIZE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsresult rv = path->Normalize(); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, "Could not normalize path"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(path->GetPath(aResult));
|
||||
}
|
||||
|
||||
void PathUtils::Split(const GlobalObject&, const nsAString& aPath,
|
||||
nsTArray<nsString>& aResult, ErrorResult& aErr) {
|
||||
if (aPath.IsEmpty()) {
|
||||
aErr.ThrowNotAllowedError(ERROR_EMPTY_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> path = new nsLocalFile();
|
||||
if (nsresult rv = path->InitWithPath(aPath); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_INITIALIZE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
while (path) {
|
||||
auto* component = aResult.EmplaceBack(fallible);
|
||||
if (!component) {
|
||||
aErr.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
if (nsresult rv = path->GetParent(getter_AddRefs(parent)); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_GET_PARENT);
|
||||
return;
|
||||
}
|
||||
|
||||
// GetLeafPreservingRoot cannot fail if we pass it a parent path.
|
||||
MOZ_ALWAYS_SUCCEEDS(GetLeafNamePreservingRoot(path, *component, parent));
|
||||
|
||||
path = parent;
|
||||
}
|
||||
|
||||
aResult.Reverse();
|
||||
}
|
||||
|
||||
void PathUtils::ToFileURI(const GlobalObject&, const nsAString& aPath,
|
||||
nsCString& aResult, ErrorResult& aErr) {
|
||||
if (aPath.IsEmpty()) {
|
||||
aErr.ThrowNotAllowedError(ERROR_EMPTY_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> path = new nsLocalFile();
|
||||
if (nsresult rv = path->InitWithPath(aPath); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, ERROR_INITIALIZE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (nsresult rv = NS_NewFileURI(getter_AddRefs(uri), path); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, "Could not initialize File URI"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsresult rv = uri->GetSpec(aResult); NS_FAILED(rv)) {
|
||||
ThrowError(aErr, rv, "Could not retrieve URI spec"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
42
dom/system/PathUtils.h
Normal file
42
dom/system/PathUtils.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PathUtils__
|
||||
#define mozilla_dom_PathUtils__
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/DOMParser.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PathUtils final {
|
||||
public:
|
||||
static void Filename(const GlobalObject&, const nsAString& aPath,
|
||||
nsString& aResult, ErrorResult& aErr);
|
||||
|
||||
static void Parent(const GlobalObject&, const nsAString& aPath,
|
||||
nsString& aResult, ErrorResult& aErr);
|
||||
|
||||
static void Join(const GlobalObject&, const Sequence<nsString>& aComponents,
|
||||
nsString& aResult, ErrorResult& aErr);
|
||||
|
||||
static void Normalize(const GlobalObject&, const nsAString& aPath,
|
||||
nsString& aResult, ErrorResult& aErr);
|
||||
|
||||
static void Split(const GlobalObject&, const nsAString& aPath,
|
||||
nsTArray<nsString>& aResult, ErrorResult& aErr);
|
||||
|
||||
static void ToFileURI(const GlobalObject&, const nsAString& aPath,
|
||||
nsCString& aResult, ErrorResult& aErr);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // namespace mozilla_dom_PathUtils__
|
@ -75,6 +75,7 @@ EXPORTS.mozilla += [
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
"IOUtils.h",
|
||||
"PathUtils.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
@ -82,6 +83,7 @@ UNIFIED_SOURCES += [
|
||||
"nsDeviceSensors.cpp",
|
||||
"nsOSPermissionRequestBase.cpp",
|
||||
"OSFileConstants.cpp",
|
||||
"PathUtils.cpp",
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
|
@ -3,3 +3,4 @@ support-files =
|
||||
worker_constants.js
|
||||
|
||||
[test_constants.xhtml]
|
||||
[test_pathutils.html]
|
||||
|
364
dom/system/tests/test_pathutils.html
Normal file
364
dom/system/tests/test_pathutils.html
Normal file
@ -0,0 +1,364 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>PathUtils tests</title>
|
||||
</head>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
const { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm");
|
||||
const { Services } = ChromeUtils.import(
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
|
||||
const UNRECOGNIZED_PATH = /Could not initialize path: NS_ERROR_FILE_UNRECOGNIZED_PATH/;
|
||||
const EMPTY_PATH = /PathUtils does not support empty paths/;
|
||||
|
||||
add_task(function test_filename() {
|
||||
Assert.throws(
|
||||
() => PathUtils.filename(""),
|
||||
EMPTY_PATH,
|
||||
"PathUtils.filename() does not support empty paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.filename("foo.txt"),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.filename() does not support relative paths"
|
||||
);
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
is(
|
||||
PathUtils.filename("C:"),
|
||||
"C:",
|
||||
"PathUtils.filename() with a drive path"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("C:\\"),
|
||||
"C:",
|
||||
"PathUtils.filename() with a drive path"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("C:\\Windows"),
|
||||
"Windows",
|
||||
"PathUtils.filename() with a path with 2 components"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("C:\\Windows\\"),
|
||||
"Windows",
|
||||
"PathUtils.filename() with a path with 2 components and a trailing slash"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("C:\\Windows\\System32"),
|
||||
"System32",
|
||||
"PathUtils.filename() with a path with 3 components"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("\\\\server"),
|
||||
"\\\\server",
|
||||
"PathUtils.filename() with a UNC server path"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("C:\\file.dat"),
|
||||
"file.dat",
|
||||
"PathUtils.filename() with a file path"
|
||||
);
|
||||
} else {
|
||||
is(
|
||||
PathUtils.filename("/"),
|
||||
"/",
|
||||
"PathUtils.filename() with a root path"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("/usr/"),
|
||||
"usr",
|
||||
"PathUtils.filename() with a non-root path"
|
||||
);
|
||||
is(
|
||||
PathUtils.filename("/usr/lib/libfoo.so"),
|
||||
"libfoo.so",
|
||||
"PathUtils.filename() with a path with 3 components"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function test_parent() {
|
||||
Assert.throws(
|
||||
() => PathUtils.parent("."),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.parent() does not support relative paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.parent(""),
|
||||
EMPTY_PATH,
|
||||
"PathUtils.parent() does not support empty paths"
|
||||
);
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
is(
|
||||
PathUtils.parent("C:"),
|
||||
null,
|
||||
"PathUtils.parent() with a drive path"
|
||||
);
|
||||
is(
|
||||
PathUtils.parent("\\\\server"),
|
||||
null,
|
||||
"PathUtils.parent() with a UNC server path"
|
||||
);
|
||||
is(
|
||||
PathUtils.parent("\\\\server\\foo"),
|
||||
"\\\\server",
|
||||
"PathUtils.parent() with a UNC server path and child component"
|
||||
);
|
||||
} else {
|
||||
is(
|
||||
PathUtils.parent("/"),
|
||||
null,
|
||||
"PathUtils.parent() with a root path"
|
||||
);
|
||||
is(
|
||||
PathUtils.parent("/var"),
|
||||
"/",
|
||||
"PathUtils.parent() with a 2 component path"
|
||||
);
|
||||
is(
|
||||
PathUtils.parent("/var/run"),
|
||||
"/var",
|
||||
"PathUtils.parent() with a 3 component path"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function test_join() {
|
||||
is(
|
||||
PathUtils.join(),
|
||||
"",
|
||||
"PathUtils.join() with an empty sequence"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.join(""),
|
||||
EMPTY_PATH,
|
||||
"PathUtils.join() does not support empty paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.join("foo", "bar"),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.join() does not support relative paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.join("."),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.join() does not support relative paths"
|
||||
);
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
is(
|
||||
PathUtils.join("C:"),
|
||||
"C:",
|
||||
"PathUtils.join() with a single path"
|
||||
);
|
||||
is(
|
||||
PathUtils.join("C:\\Windows", "System32"),
|
||||
"C:\\Windows\\System32",
|
||||
"PathUtils.join() with a 2 component path and an additional component"
|
||||
);
|
||||
is(
|
||||
PathUtils.join("C:", "Users", "Example"),
|
||||
"C:\\Users\\Example",
|
||||
"PathUtils.join() with a root path and two additional components"
|
||||
);
|
||||
is(
|
||||
PathUtils.join("\\\\server", "Files", "Example.dat"),
|
||||
"\\\\server\\Files\\Example.dat",
|
||||
"PathUtils.join() with a server path"
|
||||
);
|
||||
} else {
|
||||
is(
|
||||
PathUtils.join("/"),
|
||||
"/",
|
||||
"PathUtils.join() with a root path"
|
||||
);
|
||||
is(
|
||||
PathUtils.join("/usr", "lib"),
|
||||
"/usr/lib",
|
||||
"PathUtils.join() with a 2 component path and an additional component"
|
||||
);
|
||||
is(
|
||||
PathUtils.join("/", "home", "example"),
|
||||
"/home/example",
|
||||
"PathUtils.join() with a root path and two additional components"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_normalize() {
|
||||
Assert.throws(
|
||||
() => PathUtils.normalize(""),
|
||||
EMPTY_PATH,
|
||||
"PathUtils.normalize() does not support empty paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.normalize("."),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.normalize() does not support relative paths"
|
||||
);
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
is(
|
||||
PathUtils.normalize("C:\\\\Windows\\\\..\\\\\\.\\Users\\..\\Windows"),
|
||||
"C:\\Windows",
|
||||
"PathUtils.normalize() with a non-normalized path"
|
||||
);
|
||||
} else {
|
||||
// nsLocalFileUnix::Normalize() calls realpath, which resolves symlinks
|
||||
// and requires the file to exist.
|
||||
//
|
||||
// On Darwin, the temp directory is located in `/private/var`, which is a
|
||||
// symlink to `/var`, so we need to pre-normalize our temporary directory
|
||||
// or expected paths won't match.
|
||||
const tmpDir = PathUtils.join(
|
||||
PathUtils.normalize(Services.dirsvc.get("TmpD", Ci.nsIFile).path),
|
||||
"pathutils_test"
|
||||
);
|
||||
|
||||
await IOUtils.makeDirectory(tmpDir, { ignoreExisting: true });
|
||||
info(`created tmpDir ${tmpDir}`);
|
||||
SimpleTest.registerCleanupFunction(async () => {
|
||||
await IOUtils.remove(tmpDir, {
|
||||
recursive: true,
|
||||
});
|
||||
});
|
||||
|
||||
await IOUtils.makeDirectory(PathUtils.join(tmpDir, "foo", "bar"), {
|
||||
createAncestors: true,
|
||||
});
|
||||
|
||||
is(
|
||||
PathUtils.normalize("/"),
|
||||
"/",
|
||||
"PathUtils.normalize() with a normalized path"
|
||||
);
|
||||
|
||||
is(
|
||||
PathUtils.normalize(
|
||||
PathUtils.join(
|
||||
tmpDir,
|
||||
"foo",
|
||||
".",
|
||||
"..",
|
||||
"foo",
|
||||
".",
|
||||
"bar",
|
||||
"..",
|
||||
"bar"
|
||||
)
|
||||
),
|
||||
PathUtils.join(tmpDir, "foo", "bar"),
|
||||
"PathUtils.normalize() with a non-normalized path"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function test_split() {
|
||||
Assert.throws(
|
||||
() => PathUtils.split("foo"),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.split() does not support relative paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.split(""),
|
||||
EMPTY_PATH,
|
||||
"PathUtils.split() does not support empty paths"
|
||||
);
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
Assert.deepEqual(
|
||||
PathUtils.split("C:\\Users\\Example"),
|
||||
["C:", "Users", "Example"],
|
||||
"PathUtils.split() on an absolute path"
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
PathUtils.split("C:\\Users\\Example\\"),
|
||||
["C:", "Users", "Example"],
|
||||
"PathUtils.split() on an absolute path with a trailing slash"
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
PathUtils.split("\\\\server\\Files\\Example.dat"),
|
||||
["\\\\server", "Files", "Example.dat"],
|
||||
"PathUtils.split() with a server as the root"
|
||||
);
|
||||
} else {
|
||||
Assert.deepEqual(
|
||||
PathUtils.split("/home/foo"),
|
||||
["/", "home", "foo"],
|
||||
"PathUtils.split() on absolute path"
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
PathUtils.split("/home/foo/"),
|
||||
["/", "home", "foo"],
|
||||
"PathUtils.split() on absolute path with trailing slash"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function test_toFileURI() {
|
||||
Assert.throws(
|
||||
() => PathUtils.toFileURI("."),
|
||||
UNRECOGNIZED_PATH,
|
||||
"PathUtils.toFileURI() does not support relative paths"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PathUtils.toFileURI(""),
|
||||
EMPTY_PATH,
|
||||
"Pathutils.toFileURI() does not support empty paths"
|
||||
);
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
is(
|
||||
PathUtils.toFileURI("C:\\"),
|
||||
"file:///C:/",
|
||||
"PathUtils.toFileURI() with a root path"
|
||||
);
|
||||
|
||||
is(
|
||||
PathUtils.toFileURI("C:\\Windows\\"),
|
||||
"file:///C:/Windows/",
|
||||
"PathUtils.toFileURI() with a non-root directory path"
|
||||
);
|
||||
|
||||
is(
|
||||
PathUtils.toFileURI("C:\\Windows\\system32\\notepad.exe"),
|
||||
"file:///C:/Windows/system32/notepad.exe",
|
||||
"PathUtils.toFileURI() with a file path"
|
||||
);
|
||||
} else {
|
||||
is(
|
||||
PathUtils.toFileURI("/"),
|
||||
"file:///",
|
||||
"PathUtils.toFileURI() with a root path"
|
||||
);
|
||||
|
||||
is(
|
||||
PathUtils.toFileURI("/bin"),
|
||||
"file:///bin/",
|
||||
"PathUtils.toFileURI() with a non-root directory path"
|
||||
);
|
||||
|
||||
is(
|
||||
PathUtils.toFileURI("/bin/ls"),
|
||||
"file:///bin/ls",
|
||||
"PathUtils.toFileURI() with a file path"
|
||||
);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -402,6 +402,7 @@ module.exports = {
|
||||
PannerNode: false,
|
||||
ParentProcessMessageManager: false,
|
||||
Path2D: false,
|
||||
PathUtils: false,
|
||||
PaymentAddress: false,
|
||||
PaymentMethodChangeEvent: false,
|
||||
PaymentRequest: false,
|
||||
|
Loading…
Reference in New Issue
Block a user