Skip to content

Commit

Permalink
Add first round of tests, and associated bug fixes (flutter#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
tvolkert authored Dec 13, 2016
1 parent ec6b430 commit 1520d7c
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 44 deletions.
3 changes: 3 additions & 0 deletions lib/src/backends/local/local_file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class LocalFileSystem extends FileSystem {
@override
File file(String path) => new _LocalFile(this, new io.File(path));

@override
Link link(String path) => new _LocalLink(this, new io.Link(path));

@override
Directory get currentDirectory => directory(io.Directory.current.path);

Expand Down
7 changes: 3 additions & 4 deletions lib/src/backends/memory/memory_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ class _MemoryFile extends _MemoryFileSystemEntity implements File {
if (currentSegment == finalSegment) {
if (child != null) {
if (_isLink(child)) {
StringBuffer ledger = new StringBuffer();
List<String> ledger = <String>[];
child = _resolveLinks(child, () => newPath, ledger: ledger);
_checkExists(child, () => newPath);
parent = child.parent;
childName = fileSystem._context.basename(ledger.toString());
childName = ledger.last;
assert(parent.children.containsKey(childName));
}
if (child.type != expectedType) {
Expand Down Expand Up @@ -289,9 +289,8 @@ class _FileSink implements io.IOSink {
}

@override
Future flush() {
Future flush() async {
_checkNotStreaming();
return new Future.value();
}

@override
Expand Down
38 changes: 23 additions & 15 deletions lib/src/backends/memory/memory_file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,24 @@ class MemoryFileSystem extends FileSystem {
@override
File file(String path) => new _MemoryFile(this, path);

@override
Link link(String path) => new _MemoryLink(this, path);

@override
Directory get currentDirectory => directory(_cwd);

@override
set currentDirectory(dynamic path) {
String value;
if (path is Directory) {
if (path is io.Directory) {
value = path.path;
} else if (path is String) {
value = path;
} else {
throw new TypeError();
throw new ArgumentError('Invalid type for "path": ${path?.runtimeType}');
}
value = _context.canonicalize(value);

value = directory(value).resolveSymbolicLinksSync();
_Node node = _findNode(value);
_checkExists(node, () => value);
_checkIsDir(node, () => value);
Expand All @@ -83,7 +87,7 @@ class MemoryFileSystem extends FileSystem {
@override
io.FileStat statSync(String path) {
try {
return _findNode(path)?.stat;
return _findNode(path)?.stat ?? _MemoryFileStat._notFound;
} on io.FileSystemException {
return _MemoryFileStat._notFound;
}
Expand All @@ -95,8 +99,8 @@ class MemoryFileSystem extends FileSystem {

@override
bool identicalSync(String path1, String path2) {
_Node node1 = _findNode(path1);
_Node node2 = _findNode(path2);
_Node node1 = _findNode(path1, resolveTailLink: true);
_Node node2 = _findNode(path2, resolveTailLink: true);
return node1 != null && node1 == node2;
}

Expand All @@ -114,16 +118,13 @@ class MemoryFileSystem extends FileSystem {
io.FileSystemEntityType typeSync(String path, {bool followLinks: true}) {
_Node node;
try {
node = _findNode(path);
node = _findNode(path, resolveTailLink: followLinks);
} on io.FileSystemException {
node = null;
}
if (node = null) {
if (node == null) {
return io.FileSystemEntityType.NOT_FOUND;
}
if (followLinks && _isLink(node)) {
node = _resolveLinks(node, () => path);
}
return node.type;
}

Expand All @@ -146,8 +147,9 @@ class MemoryFileSystem extends FileSystem {
///
/// If the last element in [path] represents a symbolic link, this will
/// return the [_LinkNode] node for the link (it will not return the
/// node to which the link points). However, directory links in the middle
/// of the path will be followed in order to find the node.
/// node to which the link points), unless [resolveTailLink] is true.
/// Directory links in the middle of the path will be followed in order to
/// find the node regardless of the value of [resolveTailLink].
///
/// If [segmentVisitor] is specified, it will be invoked for every path
/// segment visited along the way starting where the reference (root folder
Expand All @@ -164,7 +166,8 @@ class MemoryFileSystem extends FileSystem {
String path, {
_Node reference,
_SegmentVisitor segmentVisitor,
StringBuffer pathWithSymlinks,
List<String> pathWithSymlinks,
bool resolveTailLink: false,
}) {
if (path == null) {
throw new ArgumentError.notNull('path');
Expand Down Expand Up @@ -207,12 +210,17 @@ class MemoryFileSystem extends FileSystem {
if (_isLink(child)) {
child = _resolveLinks(child, subpath, ledger: pathWithSymlinks);
} else if (pathWithSymlinks != null) {
pathWithSymlinks..write(_separator)..write(basename);
pathWithSymlinks..add(_separator)..add(basename);
}
_checkIsDir(child, subpath);
directory = child;
} else if (pathWithSymlinks != null) {
pathWithSymlinks..add(_separator)..add(basename);
}
}
if (_isLink(child) && resolveTailLink) {
child = _resolveLinks(child, () => path);
}
return child;
}
}
11 changes: 5 additions & 6 deletions lib/src/backends/memory/memory_file_system_entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,11 @@ abstract class _MemoryFileSystemEntity implements FileSystemEntity {

@override
String resolveSymbolicLinksSync() {
StringBuffer ledger = new StringBuffer();
_Node node = fileSystem._findNode(path, pathWithSymlinks: ledger);
if (_isLink(node)) {
_resolveLinks(node, () => path, ledger: ledger);
}
String resolved = ledger.toString();
List<String> ledger = <String>[];
_Node node = fileSystem._findNode(path,
pathWithSymlinks: ledger, resolveTailLink: true);
_checkExists(node, () => path);
String resolved = ledger.join(_separator);
if (!isAbsolute) {
resolved = fileSystem._cwd + resolved;
}
Expand Down
32 changes: 13 additions & 19 deletions lib/src/backends/memory/utils.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
part of file.src.backends.memory;

/// Checks if `node.type` returns [io.FileSystemEntityType.FILE].
bool _isFile(_Node node) => node.type == io.FileSystemEntityType.FILE;
bool _isFile(_Node node) => node?.type == io.FileSystemEntityType.FILE;

/// Checks if `node.type` returns [io.FileSystemEntityType.DIRECTORY].
bool _isDirectory(_Node node) => node.type == io.FileSystemEntityType.DIRECTORY;
bool _isDirectory(_Node node) =>
node?.type == io.FileSystemEntityType.DIRECTORY;

/// Checks if `node.type` returns [io.FileSystemEntityType.LINK].
bool _isLink(_Node node) => node.type == io.FileSystemEntityType.LINK;
bool _isLink(_Node node) => node?.type == io.FileSystemEntityType.LINK;

/// Tells whether the specified path represents an absolute path.
bool _isAbsolute(String path) => path.startsWith(_separator);
Expand Down Expand Up @@ -46,40 +47,33 @@ bool _isEmpty(String str) => str.isEmpty;
/// [io.FileSystemException], calling [path] to generate the path.
///
/// If [ledger] is specified, the resolved path to the terminal node will be
/// appended to the ledger. The path will not be normalized, meaning
/// `..` and `.` path segments will not be resolved.
/// appended to the ledger (or overwritten in the ledger if a link target
/// specified an absolute path). The path will not be normalized, meaning
/// `..` and `.` path segments may be present.
_Node _resolveLinks(
_LinkNode link,
_PathGenerator path, {
StringBuffer ledger,
List<String> ledger,
}) {
// Record a breadcrumb trail to guard against symlink loops.
Set<_LinkNode> breadcrumbs = new Set<_LinkNode>();

List<String> ledgerEntryBuilder = ledger != null ? <String>[''] : null;
_Node node = link;
while (_isLink(node)) {
link = node;
if (!breadcrumbs.add(node)) {
throw new io.FileSystemException('Loop found in link chain', path());
}
if (ledgerEntryBuilder != null) {
if (ledger != null) {
if (_isAbsolute(link.target)) {
ledgerEntryBuilder.clear;
ledgerEntryBuilder.addAll(link.target.split(_separator));
} else {
if (ledgerEntryBuilder.isNotEmpty) {
ledgerEntryBuilder.removeLast();
}
ledgerEntryBuilder.addAll(link.target.split(_separator));
ledger.clear();
} else if (ledger.isNotEmpty) {
ledger.removeLast();
}
ledger.addAll(link.target.split(_separator));
}
node = link.referent;
}

if (ledger != null) {
ledger.write(ledgerEntryBuilder.join(_separator));
}

return node;
}
4 changes: 4 additions & 0 deletions lib/src/interface/file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:io' as io;

import 'directory.dart';
import 'file.dart';
import 'link.dart';

/// A generic representation of a file system.
///
Expand All @@ -19,6 +20,9 @@ abstract class FileSystem {
/// Returns a reference to a [File] at [path].
File file(String path);

/// Returns a reference to a [Link] at [path].
Link link(String path);

/// Creates a directory object pointing to the current working directory.
Directory get currentDirectory;

Expand Down
Loading

0 comments on commit 1520d7c

Please sign in to comment.