Remove a number of unused members (#1881)
Made members only used within a library private
Moved a number of items only used it tests closer to their usage
diff --git a/lib/src/git.dart b/lib/src/git.dart
index 04883d5..9ea1e15 100644
--- a/lib/src/git.dart
+++ b/lib/src/git.dart
@@ -73,18 +73,6 @@
return result.stdout;
}
-/// Starts a git process and returns it.
-Future<PubProcess> start(List<String> args,
- {String workingDir, Map<String, String> environment}) {
- if (!isInstalled) {
- fail("Cannot find a Git executable.\n"
- "Please ensure Git is correctly installed.");
- }
-
- return startProcess(command, args,
- workingDir: workingDir, environment: environment);
-}
-
/// Returns the name of the git command-line app, or null if Git could not be
/// found on the user's PATH.
String get command {
diff --git a/lib/src/io.dart b/lib/src/io.dart
index bce55b7..f153033 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -70,7 +70,7 @@
while (components.isNotEmpty) {
seen.add(path.join(newPath, path.joinAll(components)));
var resolvedPath =
- resolveLink(path.join(newPath, components.removeFirst()));
+ _resolveLink(path.join(newPath, components.removeFirst()));
var relative = path.relative(resolvedPath, from: newPath);
// If the resolved path of the component relative to `newPath` is just ".",
@@ -138,7 +138,7 @@
/// return `"B"`).
///
/// This accepts paths to non-links or broken links, and returns them as-is.
-String resolveLink(String link) {
+String _resolveLink(String link) {
var seen = new Set<String>();
while (linkExists(link) && !seen.contains(link)) {
seen.add(link);
@@ -173,32 +173,21 @@
log.fine("Contents:\n$contents");
}
- _deleteIfLink(file);
+ deleteIfLink(file);
new File(file).writeAsStringSync(contents, encoding: encoding);
return file;
}
-/// Creates [file] and writes [contents] to it.
-String writeBinaryFile(String file, List<int> contents) {
- log.io("Writing ${contents.length} bytes to binary file $file.");
- _deleteIfLink(file);
- new File(file).openSync(mode: FileMode.WRITE)
- ..writeFromSync(contents)
- ..closeSync();
- log.fine("Wrote text file $file.");
- return file;
-}
-
/// Writes [stream] to a new file at path [file].
///
/// Replaces any file already at that path. Completes when the file is done
/// being written.
-Future<String> createFileFromStream(Stream<List<int>> stream, String file) {
+Future<String> _createFileFromStream(Stream<List<int>> stream, String file) {
// TODO(nweiz): remove extra logging when we figure out the windows bot issue.
log.io("Creating $file from stream.");
return _descriptorPool.withResource(() async {
- _deleteIfLink(file);
+ deleteIfLink(file);
await stream.pipe(new File(file).openWrite());
log.fine("Created $file from stream.");
return file;
@@ -209,36 +198,12 @@
///
/// The [File] class overwrites the symlink targets when writing to a file,
/// which is never what we want, so this delete the symlink first if necessary.
-void _deleteIfLink(String file) {
+void deleteIfLink(String file) {
if (!linkExists(file)) return;
log.io("Deleting symlink at $file.");
new Link(file).deleteSync();
}
-/// Copies all files in [files] to the directory [destination].
-///
-/// Their locations in [destination] will be determined by their relative
-/// location to [baseDir]. Any existing files at those paths will be
-/// overwritten.
-void copyFiles(Iterable<String> files, String baseDir, String destination) {
- for (var file in files) {
- var newPath = path.join(destination, path.relative(file, from: baseDir));
- ensureDir(path.dirname(newPath));
- copyFile(file, newPath);
- }
-}
-
-/// Copies a file from [source] to [destination].
-void copyFile(String source, String destination) {
- writeBinaryFile(destination, readBinaryFile(source));
-}
-
-/// Creates a directory [dir].
-String createDir(String dir) {
- new Directory(dir).createSync();
- return dir;
-}
-
/// Ensures that [dir] and all its parent directories exist.
///
/// If they don't exist, creates them.
@@ -261,7 +226,7 @@
/// 'pub_' with characters appended to it to make a unique name.
///
/// Returns the path of the created directory.
-String createSystemTempDir() {
+String _createSystemTempDir() {
var tempDir = Directory.systemTemp.createTempSync('pub_');
log.io("Created temp directory ${tempDir.path}");
return tempDir.resolveSymbolicLinksSync();
@@ -508,7 +473,7 @@
/// test package's test runner.
///
/// The test runner starts all tests from a `data:` URI.
-final bool runningAsTestRunner = Platform.script.scheme == 'data';
+final bool _runningAsTestRunner = Platform.script.scheme == 'data';
/// Whether the current process is a pub subprocess being run from a test.
///
@@ -518,7 +483,7 @@
/// Whether pub is running from within the Dart SDK, as opposed to from the Dart
/// source repository.
-final bool runningFromSdk =
+final bool _runningFromSdk =
!runningFromTest && Platform.script.path.endsWith('.snapshot');
/// A regular expression to match the script path of a pub script running from
@@ -534,7 +499,7 @@
/// This can happen when running tests against the repo, as well as when
/// building Observatory.
final bool runningFromDartRepo = (() {
- if (runningAsTestRunner) {
+ if (_runningAsTestRunner) {
// When running from the test runner, we can't find our location via
// Platform.script since the runner munges that. However, it guarantees that
// the working directory is <repo>/third_party/pkg/pub.
@@ -545,15 +510,10 @@
}
})();
-/// Resolves [target] relative to the path to pub's `asset` directory.
-String assetPath(String target) => runningFromSdk
- ? sdkAssetPath(target)
- : path.join(pubRoot, 'lib', 'src', 'asset', target);
-
/// Resolves [target] relative to the Dart SDK's `asset` directory.
///
/// Throws a [StateError] if called from within the Dart repo.
-String sdkAssetPath(String target) {
+String _sdkAssetPath(String target) {
if (runningFromDartRepo) {
throw new StateError("Can't get SDK assets from within the Dart repo.");
}
@@ -566,12 +526,12 @@
///
/// This throws a [StateError] if it's called when running pub from the SDK.
final String pubRoot = (() {
- if (runningFromSdk) {
+ if (_runningFromSdk) {
throw new StateError("Can't get pub's root from the SDK.");
}
// The test runner always runs from the working directory.
- if (runningAsTestRunner) return path.current;
+ if (_runningAsTestRunner) return path.current;
var script = path.fromUri(Platform.script);
if (runningAsTest) {
@@ -595,7 +555,7 @@
throw new StateError("Not running from source in the Dart repo.");
}
- if (runningAsTestRunner) {
+ if (_runningAsTestRunner) {
// When running in test code started by the test runner, the working
// directory will always be <repo>/third_party/pkg/pub.
return path.dirname(path.dirname(path.dirname(path.current)));
@@ -609,7 +569,7 @@
})();
/// A line-by-line stream of standard input.
-final Stream<String> stdinLines =
+final Stream<String> _stdinLines =
streamToLines(new ByteStream(stdin).toStringStream());
/// Displays a message and reads a yes/no confirmation from the user.
@@ -626,17 +586,10 @@
} else {
stdout.write(log.format("$message (y/n)? "));
}
- return streamFirst(stdinLines)
+ return streamFirst(_stdinLines)
.then((line) => new RegExp(r"^[yY]").hasMatch(line));
}
-/// Reads and discards all output from [stream].
-///
-/// Returns a [Future] that completes when the stream is closed.
-Future drainStream(Stream stream) {
- return stream.fold(null, (x, y) {});
-}
-
/// Flushes the stdout and stderr streams, then exits the program with the given
/// status code.
///
@@ -651,7 +604,7 @@
/// Returns a [EventSink] that pipes all data to [consumer] and a [Future] that
/// will succeed when [EventSink] is closed or fail with any errors that occur
/// while writing.
-Pair<EventSink<T>, Future> consumerToSink<T>(StreamConsumer<T> consumer) {
+Pair<EventSink<T>, Future> _consumerToSink<T>(StreamConsumer<T> consumer) {
var controller = new StreamController<T>(sync: true);
var done = controller.stream.pipe(consumer);
return new Pair(controller.sink, done);
@@ -668,7 +621,7 @@
/// more data or errors will be piped from [stream] to [sink]. If
/// [cancelOnError] and [closeSink] are both true, [sink] will then be
/// closed.
-Future store(Stream stream, EventSink sink,
+Future _store(Stream stream, EventSink sink,
{bool cancelOnError: true, bool closeSink: true}) {
var completer = new Completer();
stream.listen(sink.add, onError: (e, stackTrace) {
@@ -715,7 +668,7 @@
/// The spawned process will inherit its parent's environment variables. If
/// [environment] is provided, that will be used to augment (not replace) the
/// the inherited variables.
-Future<PubProcess> startProcess(String executable, List<String> args,
+Future<_PubProcess> _startProcess(String executable, List<String> args,
{workingDir, Map<String, String> environment, bool runInShell: false}) {
return _descriptorPool.request().then((resource) async {
var ioProcess = await _doProcess(Process.start, executable, args,
@@ -723,7 +676,7 @@
environment: environment,
runInShell: runInShell);
- var process = new PubProcess(ioProcess);
+ var process = new _PubProcess(ioProcess);
process.exitCode.whenComplete(resource.release);
return process;
});
@@ -743,7 +696,7 @@
}
/// A wrapper around [Process] that exposes `dart:async`-style APIs.
-class PubProcess {
+class _PubProcess {
/// The underlying `dart:io` [Process].
final Process _process;
@@ -802,11 +755,11 @@
/// error handler unless nothing has handled it.
Future<int> get exitCode => _exitCode;
- /// Creates a new [PubProcess] wrapping [process].
- PubProcess(Process process) : _process = process {
+ /// Creates a new [_PubProcess] wrapping [process].
+ _PubProcess(Process process) : _process = process {
var errorGroup = new ErrorGroup();
- var pair = consumerToSink(process.stdin);
+ var pair = _consumerToSink(process.stdin);
_stdin = pair.first;
_stdinClosed = errorGroup.registerFuture(pair.last);
@@ -867,7 +820,7 @@
/// Returns a future that completes to the value that the future returned from
/// [fn] completes to.
Future<T> withTempDir<T>(Future<T> fn(String path)) async {
- var tempDir = createSystemTempDir();
+ var tempDir = _createSystemTempDir();
try {
return await fn(tempDir);
} finally {
@@ -911,15 +864,15 @@
args.insert(0, "--warning=no-unknown-keyword");
}
- var process = await startProcess("tar", args);
+ var process = await _startProcess("tar", args);
// Ignore errors on process.std{out,err}. They'll be passed to
// process.exitCode, and we don't want them being top-levelled by
// std{out,err}Sink.
- store(process.stdout.handleError((_) {}), stdout, closeSink: false);
- store(process.stderr.handleError((_) {}), stderr, closeSink: false);
+ _store(process.stdout.handleError((_) {}), stdout, closeSink: false);
+ _store(process.stderr.handleError((_) {}), stderr, closeSink: false);
var results =
- await Future.wait([store(stream, process.stdin), process.exitCode]);
+ await Future.wait([_store(stream, process.stdin), process.exitCode]);
var exitCode = results[1];
if (exitCode != exit_codes.SUCCESS) {
@@ -951,8 +904,8 @@
return major >= 2 || (major == 1 && minor >= 23);
}
-final String pathTo7zip = (() {
- if (!runningFromDartRepo) return sdkAssetPath(path.join('7zip', '7za.exe'));
+final String _pathTo7zip = (() {
+ if (!runningFromDartRepo) return _sdkAssetPath(path.join('7zip', '7za.exe'));
return path.join(dartRepoRoot, 'third_party', '7zip', '7za.exe');
})();
@@ -967,14 +920,14 @@
return withTempDir((tempDir) async {
// Write the archive to a temp file.
var dataFile = path.join(tempDir, 'data.tar.gz');
- await createFileFromStream(stream, dataFile);
+ await _createFileFromStream(stream, dataFile);
// 7zip can't unarchive from gzip -> tar -> destination all in one step
// first we un-gzip it to a tar file.
// Note: Setting the working directory instead of passing in a full file
// path because 7zip says "A full path is not allowed here."
- var unzipResult =
- await runProcess(pathTo7zip, ['e', 'data.tar.gz'], workingDir: tempDir);
+ var unzipResult = await runProcess(_pathTo7zip, ['e', 'data.tar.gz'],
+ workingDir: tempDir);
if (unzipResult.exitCode != exit_codes.SUCCESS) {
throw new Exception(
@@ -991,7 +944,7 @@
// Untar the archive into the destination directory.
var untarResult =
- await runProcess(pathTo7zip, ['x', tarFile], workingDir: destination);
+ await runProcess(_pathTo7zip, ['x', tarFile], workingDir: destination);
if (untarResult.exitCode != exit_codes.SUCCESS) {
throw new Exception(
'Could not un-tar (exit code ${untarResult.exitCode}). Error:\n'
@@ -1075,7 +1028,7 @@
// input file, relative paths in the mtree file are interpreted as
// relative to the current working directory, not the "--directory"
// argument.
- var process = await startProcess("tar", args, workingDir: baseDir);
+ var process = await _startProcess("tar", args, workingDir: baseDir);
process.stdin.add(utf8.encode(stdin));
process.stdin.close();
return process.stdout;
@@ -1083,7 +1036,7 @@
// Don't use [withTempDir] here because we don't want to delete the temp
// directory until the returned stream has closed.
- var tempDir = createSystemTempDir();
+ var tempDir = _createSystemTempDir();
try {
// Create the file containing the list of files to compress.
@@ -1099,12 +1052,12 @@
// files added to the archive have the correct relative path in the
// archive. The latter enables relative paths in the "-i" args to be
// resolved.
- await runProcess(pathTo7zip, args, workingDir: baseDir);
+ await runProcess(_pathTo7zip, args, workingDir: baseDir);
// GZIP it. 7zip doesn't support doing both as a single operation.
// Send the output to stdout.
args = ["a", "unused", "-tgzip", "-so", tarFile];
- return (await startProcess(pathTo7zip, args))
+ return (await _startProcess(_pathTo7zip, args))
.stdout
.transform(onDoneTransformer(() => deleteEntry(tempDir)));
} catch (_) {
@@ -1133,21 +1086,3 @@
bool get success => exitCode == exit_codes.SUCCESS;
}
-
-/// Returns the top level directory in [uri].
-///
-/// Throws an [ArgumentError] if [uri] is just a filename with no directory.
-String topLevelDir(String uri) {
- var parts = path.url.split(path.url.normalize(uri));
- String error;
- if (parts.length == 1) {
- error = 'The uri `$uri` does not contain a directory.';
- } else if (parts.first == '..') {
- error = 'The uri `$uri` reaches outside the root directory.';
- }
- if (error != null) {
- throw new ArgumentError(
- 'Cannot compute top level dir for path `$uri`. $error');
- }
- return parts.first;
-}
diff --git a/lib/src/log.dart b/lib/src/log.dart
index d6ead03..dfa3ba7 100644
--- a/lib/src/log.dart
+++ b/lib/src/log.dart
@@ -42,15 +42,13 @@
/// The list of recorded log messages. Will only be recorded if
/// [recordTranscript()] is called.
-Transcript<Entry> _transcript;
+Transcript<_Entry> _transcript;
/// The currently-animated progress indicator, if any.
///
/// This will also be in [_progresses].
Progress _animatedProgress;
-_Collapser _collapser;
-
final _cyan = getSpecial('\u001b[36m');
final _green = getSpecial('\u001b[32m');
final _magenta = getSpecial('\u001b[35m');
@@ -103,7 +101,7 @@
String toString() => name;
}
-typedef _LogFn(Entry entry);
+typedef _LogFn(_Entry entry);
/// An enum type to control which log levels are displayed and how they are
/// displayed.
@@ -189,11 +187,11 @@
}
/// A single log entry.
-class Entry {
+class _Entry {
final Level level;
final List<String> lines;
- Entry(this.level, this.lines);
+ _Entry(this.level, this.lines);
}
/// Logs [message] at [Level.ERROR].
@@ -227,9 +225,6 @@
/// Logs [message] at [level].
void write(Level level, message) {
- // Don't allow interleaving collapsible messages with other kinds.
- if (_collapser != null) _collapser.end();
-
message = message.toString();
var lines = splitLines(message);
@@ -239,7 +234,7 @@
lines.removeLast();
}
- var entry = new Entry(level, lines.map(format).toList());
+ var entry = new _Entry(level, lines.map(format).toList());
var logFn = verbosity._loggers[level];
if (logFn != null) logFn(entry);
@@ -271,32 +266,6 @@
return string;
}
-/// Logs an asynchronous IO operation.
-///
-/// Logs [startMessage] before the operation starts, then when [operation]
-/// completes, invokes [endMessage] with the completion value and logs the
-/// result of that. Returns a future that completes after the logging is done.
-///
-/// If [endMessage] is omitted, then logs "Begin [startMessage]" before the
-/// operation and "End [startMessage]" after it.
-Future ioAsync(String startMessage, Future operation,
- [String endMessage(value)]) {
- if (endMessage == null) {
- io("Begin $startMessage.");
- } else {
- io(startMessage);
- }
-
- return operation.then((result) {
- if (endMessage == null) {
- io("End $startMessage.");
- } else {
- io(endMessage(result));
- }
- return result;
- });
-}
-
/// Logs the spawning of an [executable] process with [arguments] at [IO]
/// level.
void process(
@@ -376,7 +345,7 @@
/// Enables recording of log entries.
void recordTranscript() {
- _transcript = new Transcript<Entry>(_MAX_TRANSCRIPT);
+ _transcript = new Transcript<_Entry>(_MAX_TRANSCRIPT);
}
/// If [recordTranscript()] was called, then prints the previously recorded log
@@ -440,31 +409,6 @@
_numMutes--;
}
-/// Logs a collapsible [message].
-///
-/// If a number of collapsible messages are printed in short succession, they
-/// are collapsed to just showing [template] with "##" replaced with the number
-/// of collapsed messages. Avoids spamming the output with not-very-interesting
-/// output.
-void collapsible(String message, String template) {
- // Only collapse messages when the output is not verbose.
- if (verbosity._loggers[Level.MESSAGE] != _logToStdout) {
- write(Level.MESSAGE, message);
- return;
- }
-
- // If this is a different set of collapsed messages, end the previous ones.
- if (_collapser != null && _collapser._template != template) {
- _collapser.end();
- }
-
- if (_collapser != null) {
- _collapser.increment();
- } else {
- _collapser = new _Collapser(message, template);
- }
-}
-
/// Wraps [text] in the ANSI escape codes to make it bold when on a platform
/// that supports that.
///
@@ -533,32 +477,32 @@
}
/// Log function that prints the message to stdout.
-void _logToStdout(Entry entry) {
+void _logToStdout(_Entry entry) {
_logToStream(stdout, entry, showLabel: false);
}
/// Log function that prints the message to stdout with the level name.
-void _logToStdoutWithLabel(Entry entry) {
+void _logToStdoutWithLabel(_Entry entry) {
_logToStream(stdout, entry, showLabel: true);
}
/// Log function that prints the message to stderr.
-void _logToStderr(Entry entry) {
+void _logToStderr(_Entry entry) {
_logToStream(stderr, entry, showLabel: false);
}
/// Log function that prints the message to stderr with the level name.
-void _logToStderrWithLabel(Entry entry) {
+void _logToStderrWithLabel(_Entry entry) {
_logToStream(stderr, entry, showLabel: true);
}
-void _logToStream(IOSink sink, Entry entry, {bool showLabel}) {
+void _logToStream(IOSink sink, _Entry entry, {bool showLabel}) {
if (json.enabled) return;
_printToStream(sink, entry, showLabel: showLabel);
}
-void _printToStream(IOSink sink, Entry entry, {bool showLabel}) {
+void _printToStream(IOSink sink, _Entry entry, {bool showLabel}) {
_stopProgress();
bool firstLine = true;
@@ -620,57 +564,3 @@
print(jsonEncode(message));
}
}
-
-/// Collapses a series of collapsible messages into a single line of output if
-/// they happen within a short window of time.
-class _Collapser {
- /// The window of time where a series of calls to [collapsible] will be
- /// collapsed to a single message.
- static final _window = new Duration(milliseconds: 100);
-
- /// The Timer used to coalesce a number of collapsible messages.
- ///
- /// This is `null` if no collapsible messages are waiting to be displayed.
- Timer _timer;
-
- /// The first collapsible message waiting to be displayed.
- String _firstMessage;
-
- /// The template used to display the number of collapsed messages when more
- /// than one collapsible message is logged within the window of time.
- ///
- /// Inside the template, "##" will be replaced with the number of collapsed
- /// messages.
- String _template;
-
- /// The number of collapsible messages that are waiting to be logged.
- int _count = 1;
-
- _Collapser(this._firstMessage, this._template) {
- _initTimer();
- }
-
- void increment() {
- // Reset the timer.
- _timer.cancel();
- _initTimer();
-
- _count++;
- }
-
- void end() {
- // Clear this first so we don't stack overflow when we call message() below.
- _collapser = null;
-
- _timer.cancel();
- if (_count == 1) {
- message(_firstMessage);
- } else {
- message(_template.replaceAll("##", _count.toString()));
- }
- }
-
- void _initTimer() {
- _timer = new Timer(_window, end);
- }
-}
diff --git a/lib/src/oauth2.dart b/lib/src/oauth2.dart
index 281ad6a..e38c3af 100644
--- a/lib/src/oauth2.dart
+++ b/lib/src/oauth2.dart
@@ -34,7 +34,7 @@
/// a refresh token from the server. See the [Google OAuth2 documentation][].
///
/// [Google OAuth2 documentation]: https://developers.google.com/accounts/docs/OAuth2WebServer#offline
-final authorizationEndpoint =
+final _authorizationEndpoint =
Uri.parse('https://accounts.google.com/o/oauth2/auth?access_type=offline'
'&approval_prompt=force');
@@ -67,7 +67,7 @@
Credentials _credentials;
/// Delete the cached credentials, if they exist.
-void clearCredentials(SystemCache cache) {
+void _clearCredentials(SystemCache cache) {
_credentials = null;
var credentialsFile = _credentialsFile(cache);
if (entryExists(credentialsFile)) deleteEntry(credentialsFile);
@@ -97,7 +97,7 @@
message = "$message (${error.description})";
}
log.error("$message.");
- clearCredentials(cache);
+ _clearCredentials(cache);
return withClient(cache, fn);
} else {
throw error;
@@ -171,7 +171,7 @@
/// Returns a Future that completes to a fully-authorized [Client].
Future<Client> _authorize() {
var grant = new AuthorizationCodeGrant(
- _identifier, authorizationEndpoint, tokenEndpoint,
+ _identifier, _authorizationEndpoint, tokenEndpoint,
secret: _secret,
// Google's OAuth2 API doesn't support basic auth.
basicAuth: false,
diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart
index f412546..65d3253 100644
--- a/lib/src/pubspec.dart
+++ b/lib/src/pubspec.dart
@@ -42,11 +42,11 @@
///
/// This has a default value of `true` but can be overridden with the
/// PUB_ALLOW_PRERELEASE_SDK system environment variable.
-bool get allowPreReleaseSdk => allowPreReleaseSdkValue != 'false';
+bool get _allowPreReleaseSdk => _allowPreReleaseSdkValue != 'false';
/// The value of the PUB_ALLOW_PRERELEASE_SDK environment variable, defaulted
/// to `true`.
-final String allowPreReleaseSdkValue = () {
+final String _allowPreReleaseSdkValue = () {
var value =
Platform.environment["PUB_ALLOW_PRERELEASE_SDK"]?.toLowerCase() ?? 'true';
if (!['true', 'quiet', 'false'].contains(value)) {
@@ -61,7 +61,7 @@
}();
/// Whether or not to warn about pre-release SDK overrides.
-bool get warnAboutPreReleaseSdkOverrides => allowPreReleaseSdkValue != 'quiet';
+bool get warnAboutPreReleaseSdkOverrides => _allowPreReleaseSdkValue != 'quiet';
/// The parsed contents of a pubspec file.
///
@@ -289,7 +289,7 @@
///
/// This is true if the following conditions are met:
///
- /// - [allowPreReleaseSdk] is `true`
+ /// - [_allowPreReleaseSdk] is `true`
/// - The user's current SDK is a pre-release version.
/// - The original [sdkConstraint] max version is exclusive (`includeMax`
/// is `false`).
@@ -297,7 +297,7 @@
/// - The original [sdkConstraint] matches the exact same major, minor, and
/// patch versions as the user's current SDK.
bool _shouldEnableCurrentSdk(VersionRange sdkConstraint) {
- if (!allowPreReleaseSdk) return false;
+ if (!_allowPreReleaseSdk) return false;
if (!sdk.version.isPreRelease) return false;
if (sdkConstraint.includeMax) return false;
if (sdkConstraint.min != null &&
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 2ae6db5..565c136 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -70,7 +70,7 @@
///
/// If pub isn't attached to a terminal, uses an infinite line length and does
/// not wrap text.
-final int lineLength = () {
+final int _lineLength = () {
try {
return stdout.terminalColumns;
} on StdoutException {
@@ -163,23 +163,10 @@
});
}
-// TODO(rnystrom): Move into String?
-/// Pads [source] to [length] by adding spaces at the end.
-String padRight(String source, int length) {
- final result = new StringBuffer();
- result.write(source);
-
- while (result.length < length) {
- result.write(' ');
- }
-
- return result.toString();
-}
-
/// Pads [source] to [length] by adding [char]s at the beginning.
///
/// If [char] is `null`, it defaults to a space.
-String padLeft(String source, int length, [String char]) {
+String _padLeft(String source, int length, [String char]) {
if (char == null) char = ' ';
if (source.length >= length) return source;
@@ -237,23 +224,6 @@
return string;
}
-/// Creates a URL string for [address]:[port].
-///
-/// Handles properly formatting IPv6 addresses.
-Uri baseUrlForAddress(InternetAddress address, int port) {
- if (address.isLoopback) {
- return new Uri(scheme: "http", host: "localhost", port: port);
- }
-
- // IPv6 addresses in URLs need to be enclosed in square brackets to avoid
- // URL ambiguity with the ":" in the address.
- if (address.type == InternetAddressType.IP_V6) {
- return new Uri(scheme: "http", host: "[${address.address}]", port: port);
- }
-
- return new Uri(scheme: "http", host: address.address, port: port);
-}
-
/// Returns whether [host] is a host for a localhost or loopback URL.
///
/// Unlike [InternetAddress.isLoopback], this hostnames from URLs as well as
@@ -380,49 +350,6 @@
future.then(completer.complete, onError: completer.completeError);
}
-/// Ensures that [stream] can emit at least one value successfully (or close
-/// without any values).
-///
-/// For example, reading asynchronously from a non-existent file will return a
-/// stream that fails on the first chunk. In order to handle that more
-/// gracefully, you may want to check that the stream looks like it's working
-/// before you pipe the stream to something else.
-///
-/// This lets you do that. It returns a [Future] that completes to a [Stream]
-/// emitting the same values and errors as [stream], but only if at least one
-/// value can be read successfully. If an error occurs before any values are
-/// emitted, the returned Future completes to that error.
-Future<Stream<T>> validateStream<T>(Stream<T> stream) {
- var completer = new Completer<Stream>();
- var controller = new StreamController(sync: true);
-
- StreamSubscription subscription;
- subscription = stream.listen((value) {
- // We got a value, so the stream is valid.
- if (!completer.isCompleted) completer.complete(controller.stream);
- controller.add(value);
- }, onError: (error, [StackTrace stackTrace]) {
- // If the error came after values, it's OK.
- if (completer.isCompleted) {
- controller.addError(error, stackTrace);
- return;
- }
-
- // Otherwise, the error came first and the stream is invalid.
- completer.completeError(error, stackTrace);
-
- // We won't be returning the stream at all in this case, so unsubscribe
- // and swallow the error.
- subscription.cancel();
- }, onDone: () {
- // It closed with no errors, so the stream is valid.
- if (!completer.isCompleted) completer.complete(controller.stream);
- controller.close();
- });
-
- return completer.future;
-}
-
// TODO(nweiz): remove this when issue 7964 is fixed.
/// Returns a [Future] that will complete to the first element of [stream].
///
@@ -493,14 +420,6 @@
];
}
-/// Adds additional query parameters to [url], overwriting the original
-/// parameters if a name conflict occurs.
-Uri addQueryParameters(Uri url, Map<String, String> parameters) {
- var queryMap = queryToMap(url.query);
- queryMap.addAll(parameters);
- return url.resolve("?${mapToQuery(queryMap)}");
-}
-
/// Convert a URL query string (or `application/x-www-form-urlencoded` body)
/// into a [Map] from parameter names to values.
Map<String, String> queryToMap(String queryList) {
@@ -508,29 +427,13 @@
for (var pair in queryList.split("&")) {
var split = split1(pair, "=");
if (split.isEmpty) continue;
- var key = urlDecode(split[0]);
- var value = split.length > 1 ? urlDecode(split[1]) : "";
+ var key = _urlDecode(split[0]);
+ var value = split.length > 1 ? _urlDecode(split[1]) : "";
map[key] = value;
}
return map;
}
-/// Convert a [Map] from parameter names to values to a URL query string.
-String mapToQuery(Map<String, String> map) {
- var pairs = <List<String>>[];
- map.forEach((key, value) {
- key = Uri.encodeQueryComponent(key);
- value = (value == null || value.isEmpty)
- ? null
- : Uri.encodeQueryComponent(value);
- pairs.add([key, value]);
- });
- return pairs.map((pair) {
- if (pair[1] == null) return pair[0];
- return "${pair[0]}=${pair[1]}";
- }).join("&");
-}
-
/// Returns a human-friendly representation of [duration].
String niceDuration(Duration duration) {
var hasMinutes = duration.inMinutes > 0;
@@ -542,43 +445,19 @@
// If we're using verbose logging, be more verbose but more accurate when
// reporting timing information.
var msString = log.verbosity.isLevelVisible(log.Level.FINE)
- ? padLeft(ms.toString(), 3, '0')
+ ? _padLeft(ms.toString(), 3, '0')
: (ms ~/ 100).toString();
- return "$result${hasMinutes ? padLeft(s.toString(), 2, '0') : s}"
+ return "$result${hasMinutes ? _padLeft(s.toString(), 2, '0') : s}"
".${msString}s";
}
/// Decodes a URL-encoded string.
///
/// Unlike [Uri.decodeComponent], this includes replacing `+` with ` `.
-String urlDecode(String encoded) =>
+String _urlDecode(String encoded) =>
Uri.decodeComponent(encoded.replaceAll("+", " "));
-/// Takes a simple data structure (composed of [Map]s, [Iterable]s, scalar
-/// objects, and [Future]s) and recursively resolves all the [Future]s contained
-/// within.
-///
-/// Completes with the fully resolved structure.
-Future<T> awaitObject<T>(T object) async {
- // Unroll nested futures.
- if (object is Future) return await awaitObject(await object);
-
- if (object is Iterable) {
- return await Future.wait(object.map(awaitObject)) as T;
- }
-
- if (object is Map) {
- var newMap = {};
- await Future.wait(object.keys.map((key) async {
- newMap[key] = await awaitObject(await object[key]);
- }));
- return newMap as T;
- }
-
- return object;
-}
-
/// Whether "special" strings such as Unicode characters or color escapes are
/// safe to use.
///
@@ -723,7 +602,7 @@
'${chars.substring(12, 16)}-${chars.substring(16, 20)}-${chars.substring(20, 32)}';
}
-/// Wraps [text] so that it fits within [lineLength], if there is a line length.
+/// Wraps [text] so that it fits within [_lineLength], if there is a line length.
///
/// This preserves existing newlines and doesn't consider terminal color escapes
/// part of a word's length. It only splits words on spaces, not on other sorts
@@ -732,7 +611,7 @@
/// If [prefix] is passed, it's added at the beginning of any wrapped lines.
String wordWrap(String text, {String prefix}) {
// If there is no limit, don't wrap.
- if (lineLength == null) return text;
+ if (_lineLength == null) return text;
prefix ??= "";
return text.split("\n").map((originalLine) {
@@ -740,8 +619,8 @@
var lengthSoFar = 0;
var firstLine = true;
for (var word in originalLine.split(" ")) {
- var wordLength = withoutColors(word).length;
- if (wordLength > lineLength) {
+ var wordLength = _withoutColors(word).length;
+ if (wordLength > _lineLength) {
if (lengthSoFar != 0) buffer.writeln();
if (!firstLine) buffer.write(prefix);
buffer.writeln(word);
@@ -750,7 +629,7 @@
if (!firstLine) buffer.write(prefix);
buffer.write(word);
lengthSoFar = wordLength + prefix.length;
- } else if (lengthSoFar + 1 + wordLength > lineLength) {
+ } else if (lengthSoFar + 1 + wordLength > _lineLength) {
buffer.writeln();
buffer.write(prefix);
buffer.write(word);
@@ -769,7 +648,7 @@
final _colorCode = new RegExp('\u001b\\[[0-9;]+m');
/// Returns [str] without any color codes.
-String withoutColors(String str) => str.replaceAll(_colorCode, '');
+String _withoutColors(String str) => str.replaceAll(_colorCode, '');
/// A regular expression to match the exception prefix that some exceptions'
/// [Object.toString] values contain.
diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart
index 7f8d908..30a828a 100644
--- a/lib/src/validator/sdk_constraint.dart
+++ b/lib/src/validator/sdk_constraint.dart
@@ -8,7 +8,6 @@
import '../entrypoint.dart';
import '../sdk.dart';
-import '../utils.dart';
import '../validator.dart';
/// A validator that validates that a package's SDK constraint doesn't use the
diff --git a/test/descriptor/tar.dart b/test/descriptor/tar.dart
index f8f4e6e..3e1480d 100644
--- a/test/descriptor/tar.dart
+++ b/test/descriptor/tar.dart
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
+import 'dart:io';
import 'package:path/path.dart' as path;
+import 'package:pub/src/log.dart' as log;
import 'package:pub/src/io.dart';
import 'package:test_descriptor/test_descriptor.dart';
@@ -28,7 +30,7 @@
await createTarGz(createdContents, baseDir: tempDir).toBytes();
var file = path.join(parent ?? sandbox, name);
- writeBinaryFile(file, bytes);
+ _writeBinaryFile(file, bytes);
return file;
});
}
@@ -49,3 +51,14 @@
}));
}
}
+
+/// Creates [file] and writes [contents] to it.
+String _writeBinaryFile(String file, List<int> contents) {
+ log.io("Writing ${contents.length} bytes to binary file $file.");
+ deleteIfLink(file);
+ new File(file).openSync(mode: FileMode.WRITE)
+ ..writeFromSync(contents)
+ ..closeSync();
+ log.fine("Wrote text file $file.");
+ return file;
+}
diff --git a/test/descriptor_server.dart b/test/descriptor_server.dart
index f438cf7..92b9066 100644
--- a/test/descriptor_server.dart
+++ b/test/descriptor_server.dart
@@ -83,7 +83,7 @@
requestedPaths.add(path);
try {
- var stream = await validateStream(_baseDir.load(path));
+ var stream = await _validateStream(_baseDir.load(path));
return new shelf.Response.ok(stream);
} catch (_) {
return new shelf.Response.notFound('File "$path" not found.');
@@ -103,3 +103,46 @@
/// Closes this server.
Future close() => _server.close();
}
+
+/// Ensures that [stream] can emit at least one value successfully (or close
+/// without any values).
+///
+/// For example, reading asynchronously from a non-existent file will return a
+/// stream that fails on the first chunk. In order to handle that more
+/// gracefully, you may want to check that the stream looks like it's working
+/// before you pipe the stream to something else.
+///
+/// This lets you do that. It returns a [Future] that completes to a [Stream]
+/// emitting the same values and errors as [stream], but only if at least one
+/// value can be read successfully. If an error occurs before any values are
+/// emitted, the returned Future completes to that error.
+Future<Stream<T>> _validateStream<T>(Stream<T> stream) {
+ var completer = new Completer<Stream>();
+ var controller = new StreamController(sync: true);
+
+ StreamSubscription subscription;
+ subscription = stream.listen((value) {
+ // We got a value, so the stream is valid.
+ if (!completer.isCompleted) completer.complete(controller.stream);
+ controller.add(value);
+ }, onError: (error, [StackTrace stackTrace]) {
+ // If the error came after values, it's OK.
+ if (completer.isCompleted) {
+ controller.addError(error, stackTrace);
+ return;
+ }
+
+ // Otherwise, the error came first and the stream is invalid.
+ completer.completeError(error, stackTrace);
+
+ // We won't be returning the stream at all in this case, so unsubscribe
+ // and swallow the error.
+ subscription.cancel();
+ }, onDone: () {
+ // It closed with no errors, so the stream is valid.
+ if (!completer.isCompleted) completer.complete(controller.stream);
+ controller.close();
+ });
+
+ return completer.future;
+}
diff --git a/test/error_group_test.dart b/test/error_group_test.dart
index 5b912c4..020481b 100644
--- a/test/error_group_test.dart
+++ b/test/error_group_test.dart
@@ -5,7 +5,6 @@
import 'dart:async';
import 'package:pub/src/error_group.dart';
-import 'package:pub/src/utils.dart';
import 'package:test/test.dart';
ErrorGroup errorGroup;
diff --git a/test/io_test.dart b/test/io_test.dart
index a381e08..33be4ff 100644
--- a/test/io_test.dart
+++ b/test/io_test.dart
@@ -16,7 +16,7 @@
writeTextFile(path.join(temp, 'file1.txt'), '');
writeTextFile(path.join(temp, 'file2.txt'), '');
writeTextFile(path.join(temp, '.file3.txt'), '');
- createDir(path.join(temp, '.subdir'));
+ _createDir(path.join(temp, '.subdir'));
writeTextFile(path.join(temp, '.subdir', 'file3.txt'), '');
expect(
@@ -31,7 +31,7 @@
writeTextFile(path.join(temp, 'file1.txt'), '');
writeTextFile(path.join(temp, 'file2.txt'), '');
writeTextFile(path.join(temp, '.file3.txt'), '');
- createDir(path.join(temp, '.subdir'));
+ _createDir(path.join(temp, '.subdir'));
writeTextFile(path.join(temp, '.subdir', 'file3.txt'), '');
expect(
@@ -67,7 +67,7 @@
group('canonicalize', () {
test('resolves a non-link', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var filePath = path.join(temp, 'file');
writeTextFile(filePath, '');
expect(canonicalize(filePath), equals(filePath));
@@ -75,15 +75,15 @@
});
test('resolves a non-existent file', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
expect(canonicalize(path.join(temp, 'nothing')),
equals(path.join(temp, 'nothing')));
}), completes);
});
test('resolves a symlink', () {
- expect(withCanonicalTempDir((temp) {
- createDir(path.join(temp, 'linked-dir'));
+ expect(_withCanonicalTempDir((temp) {
+ _createDir(path.join(temp, 'linked-dir'));
createSymlink(path.join(temp, 'linked-dir'), path.join(temp, 'dir'));
expect(canonicalize(path.join(temp, 'dir')),
equals(path.join(temp, 'linked-dir')));
@@ -91,8 +91,8 @@
});
test('resolves a relative symlink', () {
- expect(withCanonicalTempDir((temp) {
- createDir(path.join(temp, 'linked-dir'));
+ expect(_withCanonicalTempDir((temp) {
+ _createDir(path.join(temp, 'linked-dir'));
createSymlink(path.join(temp, 'linked-dir'), path.join(temp, 'dir'),
relative: true);
expect(canonicalize(path.join(temp, 'dir')),
@@ -101,7 +101,7 @@
});
test('resolves a single-level horizontally recursive symlink', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var linkPath = path.join(temp, 'foo');
createSymlink(linkPath, linkPath);
expect(canonicalize(linkPath), equals(linkPath));
@@ -109,7 +109,7 @@
});
test('resolves a multi-level horizontally recursive symlink', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var fooPath = path.join(temp, 'foo');
var barPath = path.join(temp, 'bar');
var bazPath = path.join(temp, 'baz');
@@ -126,7 +126,7 @@
});
test('resolves a broken symlink', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
createSymlink(path.join(temp, 'nonexistent'), path.join(temp, 'foo'));
expect(canonicalize(path.join(temp, 'foo')),
equals(path.join(temp, 'nonexistent')));
@@ -134,13 +134,13 @@
});
test('resolves multiple nested symlinks', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var dir1 = path.join(temp, 'dir1');
var dir2 = path.join(temp, 'dir2');
var subdir1 = path.join(dir1, 'subdir1');
var subdir2 = path.join(dir2, 'subdir2');
- createDir(dir2);
- createDir(subdir2);
+ _createDir(dir2);
+ _createDir(subdir2);
createSymlink(dir2, dir1);
createSymlink(subdir2, subdir1);
expect(canonicalize(path.join(subdir1, 'file')),
@@ -149,12 +149,12 @@
});
test('resolves a nested vertical symlink', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var dir1 = path.join(temp, 'dir1');
var dir2 = path.join(temp, 'dir2');
var subdir = path.join(dir1, 'subdir');
- createDir(dir1);
- createDir(dir2);
+ _createDir(dir1);
+ _createDir(dir2);
createSymlink(dir2, subdir);
expect(canonicalize(path.join(subdir, 'file')),
equals(path.join(dir2, 'file')));
@@ -162,10 +162,10 @@
});
test('resolves a vertically recursive symlink', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var dir = path.join(temp, 'dir');
var subdir = path.join(dir, 'subdir');
- createDir(dir);
+ _createDir(dir);
createSymlink(dir, subdir);
expect(
canonicalize(path.join(
@@ -176,11 +176,11 @@
test('resolves a symlink that links to a path that needs more resolving',
() {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var dir = path.join(temp, 'dir');
var linkdir = path.join(temp, 'linkdir');
var linkfile = path.join(dir, 'link');
- createDir(dir);
+ _createDir(dir);
createSymlink(dir, linkdir);
createSymlink(path.join(linkdir, 'file'), linkfile);
expect(canonicalize(linkfile), equals(path.join(dir, 'file')));
@@ -188,7 +188,7 @@
});
test('resolves a pair of pathologically-recursive symlinks', () {
- expect(withCanonicalTempDir((temp) {
+ expect(_withCanonicalTempDir((temp) {
var foo = path.join(temp, 'foo');
var subfoo = path.join(foo, 'subfoo');
var bar = path.join(temp, 'bar');
@@ -263,7 +263,7 @@
test('returns $forDirectory for a directory', () {
expect(withTempDir((temp) {
var file = path.join(temp, "dir");
- createDir(file);
+ _createDir(file);
expect(predicate(file), equals(forDirectory));
}), completes);
});
@@ -272,7 +272,7 @@
expect(withTempDir((temp) {
var targetPath = path.join(temp, "dir");
var symlinkPath = path.join(temp, "linkdir");
- createDir(targetPath);
+ _createDir(targetPath);
createSymlink(targetPath, symlinkPath);
expect(predicate(symlinkPath), equals(forDirectorySymlink));
}), completes);
@@ -285,7 +285,7 @@
var targetPath = path.join(temp, "dir");
var symlink1Path = path.join(temp, "link1dir");
var symlink2Path = path.join(temp, "link2dir");
- createDir(targetPath);
+ _createDir(targetPath);
createSymlink(targetPath, symlink1Path);
createSymlink(symlink1Path, symlink2Path);
expect(predicate(symlink2Path), equals(forMultiLevelDirectorySymlink));
@@ -296,7 +296,7 @@
expect(withTempDir((temp) {
var targetPath = path.join(temp, "dir");
var symlinkPath = path.join(temp, "linkdir");
- createDir(targetPath);
+ _createDir(targetPath);
createSymlink(targetPath, symlinkPath);
deleteEntry(targetPath);
expect(predicate(symlinkPath), equals(forBrokenSymlink));
@@ -309,7 +309,7 @@
var targetPath = path.join(temp, "dir");
var symlink1Path = path.join(temp, "link1dir");
var symlink2Path = path.join(temp, "link2dir");
- createDir(targetPath);
+ _createDir(targetPath);
createSymlink(targetPath, symlink1Path);
createSymlink(symlink1Path, symlink2Path);
deleteEntry(targetPath);
@@ -344,25 +344,14 @@
});
}
});
-
- group('topLevelDir', () {
- test('returns the top level dir in a path', () {
- expect(topLevelDir('foo/bar/baz.dart'), 'foo');
- expect(topLevelDir('foo/../bar/baz.dart'), 'bar');
- expect(topLevelDir('./foo/baz.dart'), 'foo');
- });
-
- test('throws for invalid paths', () {
- expect(() => topLevelDir('foo/../../bar.dart'), throwsArgumentError,
- reason: 'Paths reaching outside the root dir should throw.');
- expect(() => topLevelDir('foo.dart'), throwsArgumentError,
- reason: 'Paths to the root directory should throw.');
- expect(() => topLevelDir('foo/../foo.dart'), throwsArgumentError,
- reason: 'Normalized paths to the root directory should throw.');
- });
- });
}
/// Like [withTempDir], but canonicalizes the path before passing it to [fn].
-Future withCanonicalTempDir(Future fn(String path)) =>
+Future _withCanonicalTempDir(Future fn(String path)) =>
withTempDir((temp) => fn(canonicalize(temp)));
+
+/// Creates a directory [dir].
+String _createDir(String dir) {
+ new Directory(dir).createSync();
+ return dir;
+}
diff --git a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
index c4a0884..e383cd4 100644
--- a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
+++ b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
@@ -6,8 +6,6 @@
import 'package:shelf_test_handler/shelf_test_handler.dart';
import 'package:test/test.dart';
-import 'package:pub/src/io.dart';
-
import '../descriptor.dart' as d;
import '../test_pub.dart';
import 'utils.dart';
@@ -24,7 +22,7 @@
handleUploadForm(server);
server.handler.expect('POST', '/upload', (request) async {
- await drainStream(request.read());
+ await request.read().drain();
return new shelf.Response(200);
});
diff --git a/test/lish/cloud_storage_upload_provides_an_error_test.dart b/test/lish/cloud_storage_upload_provides_an_error_test.dart
index 1b0a93d..452b73f 100644
--- a/test/lish/cloud_storage_upload_provides_an_error_test.dart
+++ b/test/lish/cloud_storage_upload_provides_an_error_test.dart
@@ -6,8 +6,6 @@
import 'package:shelf_test_handler/shelf_test_handler.dart';
import 'package:test/test.dart';
-import 'package:pub/src/io.dart';
-
import '../descriptor.dart' as d;
import '../test_pub.dart';
import 'utils.dart';
@@ -24,7 +22,7 @@
handleUploadForm(server);
server.handler.expect('POST', '/upload', (request) {
- return drainStream(request.read()).then((_) {
+ return request.read().drain().then((_) {
return new shelf.Response.notFound(
'<Error><Message>Your request sucked.</Message></Error>',
headers: {'content-type': 'application/xml'});
diff --git a/test/lish/utils.dart b/test/lish/utils.dart
index c6d8400..02c74b8 100644
--- a/test/lish/utils.dart
+++ b/test/lish/utils.dart
@@ -8,8 +8,6 @@
import 'package:shelf_test_handler/shelf_test_handler.dart';
import 'package:test/test.dart';
-import 'package:pub/src/io.dart';
-
void handleUploadForm(ShelfTestServer server, [Map body]) {
server.handler.expect('GET', '/api/packages/versions/new', (request) {
expect(
@@ -31,7 +29,9 @@
server.handler.expect('POST', '/upload', (request) {
// TODO(nweiz): Once a multipart/form-data parser in Dart exists, validate
// that the request body is correctly formatted. See issue 6952.
- return drainStream(request.read())
+ return request
+ .read()
+ .drain()
.then((_) => server.url)
.then((url) => new shelf.Response.found(url.resolve('/create')));
});
diff --git a/test/oauth2/utils.dart b/test/oauth2/utils.dart
index 51610d6..7bbf1d1 100644
--- a/test/oauth2/utils.dart
+++ b/test/oauth2/utils.dart
@@ -26,7 +26,7 @@
expect(match, isNotNull);
var redirectUrl = Uri.parse(Uri.decodeComponent(match.group(1)));
- redirectUrl = addQueryParameters(redirectUrl, {'code': 'access code'});
+ redirectUrl = _addQueryParameters(redirectUrl, {'code': 'access code'});
var response = await (new http.Request('GET', redirectUrl)
..followRedirects = false)
.send();
@@ -46,3 +46,27 @@
headers: {'content-type': 'application/json'});
});
}
+
+/// Adds additional query parameters to [url], overwriting the original
+/// parameters if a name conflict occurs.
+Uri _addQueryParameters(Uri url, Map<String, String> parameters) {
+ var queryMap = queryToMap(url.query);
+ queryMap.addAll(parameters);
+ return url.resolve("?${_mapToQuery(queryMap)}");
+}
+
+/// Convert a [Map] from parameter names to values to a URL query string.
+String _mapToQuery(Map<String, String> map) {
+ var pairs = <List<String>>[];
+ map.forEach((key, value) {
+ key = Uri.encodeQueryComponent(key);
+ value = (value == null || value.isEmpty)
+ ? null
+ : Uri.encodeQueryComponent(value);
+ pairs.add([key, value]);
+ });
+ return pairs.map((pair) {
+ if (pair[1] == null) return pair[0];
+ return "${pair[0]}=${pair[1]}";
+ }).join("&");
+}
diff --git a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
index eaa17a4..c41afc1 100644
--- a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
+++ b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
@@ -4,7 +4,6 @@
import 'dart:convert';
-import 'package:pub/src/io.dart';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf_test_handler/shelf_test_handler.dart';
import 'package:test/test.dart';
@@ -32,7 +31,7 @@
await confirmPublish(pub);
server.handler.expect('POST', '/token', (request) {
- return drainStream(request.read()).then((_) {
+ return request.read().drain().then((_) {
return new shelf.Response(400,
body: jsonEncode({"error": "invalid_request"}),
headers: {'content-type': 'application/json'});