// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // 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:meta/meta.dart'; import 'package:test/test.dart'; const Duration _oneSecond = Duration(seconds: 1); /// Returns a [DateTime] with an exact second-precision by removing the /// milliseconds and microseconds from the specified [time]. /// /// If [time] is not specified, it will default to the current time. DateTime floor([DateTime? time]) { time ??= DateTime.now(); return time.subtract(Duration( milliseconds: time.millisecond, microseconds: time.microsecond, )); } /// Returns a [DateTime] with an exact second precision, rounding up to the /// nearest second if necessary. /// /// If [time] is not specified, it will default to the current time. DateTime ceil([DateTime? time]) { time ??= DateTime.now(); int microseconds = (1000 * time.millisecond) + time.microsecond; return (microseconds == 0) ? time // Add just enough milliseconds and microseconds to reach the next second. : time.add(Duration(microseconds: 1000000 - microseconds)); } /// Returns 1 second before the [floor] of the specified [DateTime]. // TODO(jamesderlin): Remove this and use [floor], https://github.com/dart-lang/sdk/issues/42444 DateTime downstairs([DateTime? time]) => floor(time).subtract(_oneSecond); /// Successfully matches against a [DateTime] that is the same moment or before /// the specified [time]. Matcher isSameOrBefore(DateTime time) => _IsSameOrBefore(time); /// Successfully matches against a [DateTime] that is the same moment or after /// the specified [time]. Matcher isSameOrAfter(DateTime time) => _IsSameOrAfter(time); /// Successfully matches against a [DateTime] that is after the specified /// [time]. Matcher isAfter(DateTime time) => _IsAfter(time); abstract class _CompareDateTime extends Matcher { const _CompareDateTime(this._time, this._matcher); final DateTime _time; final Matcher _matcher; @override bool matches(dynamic item, Map matchState) { return item is DateTime && _matcher.matches(item.compareTo(_time), {}); } @protected String get descriptionOperator; @override Description describe(Description description) => description.add('a DateTime $descriptionOperator $_time'); @protected String get mismatchAdjective; @override Description describeMismatch( dynamic item, Description description, Map matchState, bool verbose, ) { if (item is DateTime) { Duration diff = item.difference(_time).abs(); return description.add('is $mismatchAdjective $_time by $diff'); } else { return description.add('is not a DateTime'); } } } class _IsSameOrBefore extends _CompareDateTime { const _IsSameOrBefore(DateTime time) : super(time, isNonPositive); @override String get descriptionOperator => '<='; @override String get mismatchAdjective => 'after'; } class _IsSameOrAfter extends _CompareDateTime { const _IsSameOrAfter(DateTime time) : super(time, isNonNegative); @override String get descriptionOperator => '>='; @override String get mismatchAdjective => 'before'; } class _IsAfter extends _CompareDateTime { const _IsAfter(DateTime time) : super(time, isPositive); @override String get descriptionOperator => '>'; @override String get mismatchAdjective => 'before'; }