Chromium Code Reviews| Index: lib/src/frontend/timeout.dart |
| diff --git a/lib/src/frontend/timeout.dart b/lib/src/frontend/timeout.dart |
| index 54ce540415dc2c9af0eda2eccc679c9950a1103e..bfaf50d6cf068ec708c48f34e265b84e345d8abe 100644 |
| --- a/lib/src/frontend/timeout.dart |
| +++ b/lib/src/frontend/timeout.dart |
| @@ -2,6 +2,21 @@ |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| +import 'package:string_scanner/string_scanner.dart'; |
| + |
| +/// A regular expression that matches text until a letter or whitespace. |
| +/// |
| +/// This is intended to scan through a number without actually encoding the full |
| +/// Dart number grammar. It doesn't stop on "e" because that can be a component |
| +/// of numbers. |
| +final _untilUnit = new RegExp(r"[^a-df-z\s]+", caseSensitive: false); |
| + |
| +/// A regular expression that matches a time unit. |
| +final _unit = new RegExp(r"([um]s|[dhms])", caseSensitive: false); |
| + |
| +/// A regular expression that matches a section of whitespace. |
| +final _whitespace = new RegExp(r"\s+"); |
| + |
| /// A class representing a modification to the default timeout for a test. |
| /// |
| /// By default, a test will time out after 30 seconds. With [new Timeout], that |
| @@ -39,6 +54,69 @@ class Timeout { |
| : scaleFactor = null, |
| duration = null; |
| + /// Parse the timeout from a user-provided string. |
| + /// |
| + /// This supports the following formats: |
| + /// |
| + /// * `Number "x"`, which produces a relative timeout with the given scale |
| + /// factor. |
| + /// |
| + /// * `(Number ("d" | "h" | "m" | "s" | "ms" | "us") (" ")?)+`, which produces |
| + /// an absolute timeout with the duration given by the sum of the given |
| + /// units. |
| + /// |
| + /// * `"none"`, which produces [Timeout.none]. |
| + /// |
| + /// Throws a [FormatException] if [timeout] is not in a valid format |
| + factory Timeout.parse(String timeout) { |
|
Lasse Reichstein Nielsen
2016/01/26 09:58:59
We generally make "parse" a static function, not a
nweiz
2016/01/26 23:15:40
This is true in the SDK, but externally pretty muc
|
| + var scanner = new StringScanner(timeout); |
| + |
| + // First check for the string "none". |
| + if (scanner.scan("none")) { |
| + scanner.expectDone(); |
| + return Timeout.none; |
| + } |
| + |
| + // Scan a number. This will be either a time unit or a scale factor. |
| + scanner.expect(_untilUnit, name: "number"); |
| + var number = double.parse(scanner.lastMatch[0]); |
| + |
| + // A number followed by "x" is a scale factor. |
| + if (scanner.scan("x") || scanner.scan("X")) { |
| + scanner.expectDone(); |
| + return new Timeout.factor(number); |
| + } |
| + |
| + // Parse time units until none are left. The condition is in the middle of |
| + // the loop because we've already parsed the first number. |
| + var microseconds = 0; |
| + while (true) { |
| + scanner.expect(_unit, name: "unit"); |
| + microseconds += _microsecondsFor(number, scanner.lastMatch[0]); |
| + |
| + scanner.scan(_whitespace); |
| + |
| + // Scan the next number, if it's avaialble. |
| + if (!scanner.scan(_untilUnit)) break; |
| + number = double.parse(scanner.lastMatch[0]); |
| + } |
| + |
| + scanner.expectDone(); |
| + return new Timeout(new Duration(microseconds: microseconds.round())); |
| + } |
| + |
| + static double _microsecondsFor(double number, String unit) { |
| + switch (unit) { |
| + case "d": return number * 24 * 60 * 60 * 1000000; |
|
Lasse Reichstein Nielsen
2016/01/26 09:58:59
Maybe parenthesize (24 * 60 * 60 * 1000000).
nweiz
2016/01/26 23:15:40
I don't think that adds much.
|
| + case "h": return number * 60 * 60 * 1000000; |
| + case "m": return number * 60 * 1000000; |
| + case "s": return number * 1000000; |
| + case "ms": return number * 1000; |
| + case "us": return number; |
| + default: throw "Unknown unit $unit."; |
|
Lasse Reichstein Nielsen
2016/01/26 09:58:58
Consider making this an error instead of just a st
nweiz
2016/01/26 23:15:39
Done.
|
| + } |
| + } |
| + |
| /// Returns a new [Timeout] that merges [this] with [other]. |
| /// |
| /// If [other] declares a [duration], that takes precedence. Otherwise, this |
| @@ -58,6 +136,11 @@ class Timeout { |
| return duration == null ? base * scaleFactor : duration; |
| } |
| + int get hashCode => duration.hashCode ^ 4 * scaleFactor.hashCode; |
|
Lasse Reichstein Nielsen
2016/01/26 09:58:58
Any particular reason for the 4*? Consider somethi
nweiz
2016/01/26 23:15:39
Done.
|
| + |
| + bool operator==(other) => other is Timeout && other.duration == duration && |
| + other.scaleFactor == scaleFactor; |
| + |
| String toString() { |
| if (duration != null) return duration.toString(); |
| if (scaleFactor != null) return "${scaleFactor}x"; |