nest<R> abstract method

Subject<R> nest<R>(
  1. Iterable<String> label(),
  2. Extracted<R> extract(
    1. T
    ), {
  3. bool atSameLevel = false,
})

Extract a property from the value for further checking.

If the property cannot be extracted, extract should return an Extracted.rejection describing the problem. Otherwise it should return an Extracted.value.

Subsequent expectations can be checked for the extracted value on the returned Subject.

The label callback returns a description of the extracted subject as it relates to the original subject. For instance the completes to a value in:

Expected a Future<int> that:
  completes to a value that:
    is equal to <1>

A label should also be sensible when it is read as a clause. If no further expectations are checked on the extracted subject, or if the extraction is rejected, the "that:" is omitted in the output.

  Expected a Future<int> that:
    completes to a value

If atSameLevel is true then the returned Extracted.value should hold the same instance as the passed value, or an object which is is equivalent but has a type that is more convenient to test. In this case expectations applied to the returned Subject will behave as if they were applied to the subject for this context. The label will be used as if it were a "clause" argument passed to expect. If the label returns an empty iterable, the clause will be omitted. The label should only be left empty if the value extraction cannot be rejected.

Description callbacks return an Iterable<String> where each element is a line in the output. Individual elements should not contain newlines. Utilities such as prefixFirst, postfixLast, and literal may be useful to format values which are potentially multiline.

The description of an expectation may never be shown to the user, so the callback may never be invoked. If all the conditions on a subject succeed, or if the failure detail for a failed softCheck is never read, the descriptions will be unused. String formatting for the descriptions should be performed in the callback, not ahead of time.

The context for a subject may hold a real "actual" value to test against, or it may have a placeholder within a call to describe. A context with a placeholder value will not invoke the callback to check expectations.

If both callbacks are invoked, the description callback will always be called strictly after the expectation callback is called.

Callbacks passed to a context should not throw.

Subject<Foo> get someDerivedValue =>
    context.nest(() => ['has someDerivedValue'], (actual) {
      if (_cannotReadDerivedValue(actual)) {
        return Extracted.rejection(
            which: ['cannot read someDerivedValue']);
      }
      return Extracted.value(_readDerivedValue(actual));
    });

Implementation

Subject<R> nest<R>(
    Iterable<String> Function() label, Extracted<R> Function(T) extract,
    {bool atSameLevel = false});