// Copyright 2018 Dart Mockito authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'package:mockito/mockito.dart';
import 'package:mockito/src/mock.dart' show resetMockitoState;
import 'package:test/test.dart';

import 'utils.dart';

class RealClass {
  RealClass innerObj;
  String methodWithNormalArgs(int x) => 'Real';
  String methodWithListArgs(List<int> x) => 'Real';
  String methodWithPositionalArgs(int x, [int y]) => 'Real';
  set setter(String arg) {
    throw new StateError('I must be mocked');
  }
}

class MockedClass extends Mock implements RealClass {}

void main() {
  MockedClass mock;

  var isNsmForwarding = assessNsmForwarding();

  setUp(() {
    mock = new MockedClass();
  });

  tearDown(() {
    // In some of the tests that expect an Error to be thrown, Mockito's
    // global state can become invalid. Reset it.
    resetMockitoState();
  });

  group('capture', () {
    test('captureAny should match anything', () {
      mock.methodWithNormalArgs(42);
      expect(
          verify(mock.methodWithNormalArgs(typed(captureAny))).captured.single,
          equals(42));
    });

    test('captureThat should match some things', () {
      mock.methodWithNormalArgs(42);
      mock.methodWithNormalArgs(44);
      mock.methodWithNormalArgs(43);
      mock.methodWithNormalArgs(45);
      expect(
          verify(mock.methodWithNormalArgs(typed(captureThat(lessThan(44)))))
              .captured,
          equals([42, 43]));
    });

    test('should capture list arguments', () {
      mock.methodWithListArgs([42]);
      expect(verify(mock.methodWithListArgs(typed(captureAny))).captured.single,
          equals([42]));
    });

    test('should capture multiple arguments', () {
      mock.methodWithPositionalArgs(1, 2);
      expect(
          verify(mock.methodWithPositionalArgs(
                  typed(captureAny), typed(captureAny)))
              .captured,
          equals([1, 2]));
    });

    test('should capture with matching arguments', () {
      mock.methodWithPositionalArgs(1);
      mock.methodWithPositionalArgs(2, 3);
      var expectedCaptures = isNsmForwarding ? [1, null, 2, 3] : [2, 3];
      expect(
          verify(mock.methodWithPositionalArgs(
                  typed(captureAny), typed(captureAny)))
              .captured,
          equals(expectedCaptures));
    });

    test('should capture multiple invocations', () {
      mock.methodWithNormalArgs(1);
      mock.methodWithNormalArgs(2);
      expect(verify(mock.methodWithNormalArgs(typed(captureAny))).captured,
          equals([1, 2]));
    });
  });

  // TODO(srawlins): Test capturing in a setter.
  // TODO(srawlins): Test capturing named arguments.
}
