// Copyright (c) 2018, 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:matcher/matcher.dart';
import 'package:test/test.dart' show test, expect, throwsA, group;

import 'test_utils.dart';

void main() {
  test('success', () {
    shouldPass(new RangeError('details'), _rangeMatcher);
  });

  test('failure', () {
    shouldFail(
        new RangeError.range(-1, 1, 10),
        _rangeMatcher,
        "Expected: <Instance of 'RangeError'> with "
        "`message`: contains 'details' and `start`: null and `end`: null "
        'Actual: RangeError:<RangeError: '
        'Invalid value: Not in range 1..10, inclusive: -1> '
        "Which: has `message` with value 'Invalid value'");
  });

  // This code is used in the [TypeMatcher] doc comments.
  test('integaration and example', () {
    void shouldThrowRangeError(int value) {
      throw new RangeError.range(value, 10, 20);
    }

    expect(
        () => shouldThrowRangeError(5),
        throwsA(const TypeMatcher<RangeError>()
            .having((e) => e.start, 'start', greaterThanOrEqualTo(10))
            .having((e) => e.end, 'end', lessThanOrEqualTo(20))));

    expect(
        () => shouldThrowRangeError(5),
        throwsA(isRangeError
            .having((e) => e.start, 'start', greaterThanOrEqualTo(10))
            .having((e) => e.end, 'end', lessThanOrEqualTo(20))));
  });

  group('CustomMater copy', () {
    test("Feature Matcher", () {
      var w = new Widget();
      w.price = 10;
      shouldPass(w, _hasPrice(10));
      shouldPass(w, _hasPrice(greaterThan(0)));
      shouldFail(
          w,
          _hasPrice(greaterThan(10)),
          "Expected: <Instance of 'Widget'> with `price`: a value greater than <10> "
          "Actual: <Instance of 'Widget'> "
          "Which: has `price` with value <10> which is not "
          "a value greater than <10>");
    });

    test("Custom Matcher Exception", () {
      shouldFail(
          'a',
          _badCustomMatcher(),
          allOf([
            contains(
                "Expected: <Instance of 'Widget'> with `feature`: {1: 'a'} "),
            contains("Actual: 'a'"),
          ]));
      shouldFail(
          new Widget(),
          _badCustomMatcher(),
          allOf([
            contains(
                "Expected: <Instance of 'Widget'> with `feature`: {1: 'a'} "),
            contains("Actual: <Instance of 'Widget'> "),
            contains("Which: threw 'Exception: bang' "),
          ]));
    });
  });
}

final _rangeMatcher = isRangeError
    .having((e) => e.message, 'message', contains('details'))
    .having((e) => e.start, 'start', isNull)
    .having((e) => e.end, 'end', isNull);

Matcher _hasPrice(matcher) =>
    const TypeMatcher<Widget>().having((e) => e.price, 'price', matcher);

Matcher _badCustomMatcher() => const TypeMatcher<Widget>()
    .having((e) => throw new Exception("bang"), 'feature', {1: "a"});
