@function test-find-1($map, $args...) {
    @return __is-truthy(__get($map, 'a'));
}
@function test-find-2($map, $args...) {
    @return __get($map, 'a') == 3;
}
@function test-find-3($value, $args...) {
    @return if(type-of($value) == 'number', $value < 3, false);
}
@function test-find-4($chr, $index, $args...) {
    @return $index <= 2;
}
@each $method-name in 'find', 'find-last', 'find-index', 'find-last-index', 'find-key', 'find-last-key' {
    @include test-module('_#{$method-name}') {
        $func: unquote('_#{$method-name}');

        $maps: (
            ('a': 0, 'b': 0),
            ('a': 1, 'b': 1),
            ('a': 2, 'b': 2),
        );

        $expected-values: __get((
            'find': nth($maps, 2) null nth($maps, 3) nth($maps, 2),
            'find-last': nth($maps, 3) null nth($maps, 3) nth($maps, 3),
            'find-index': 2 -1 3 2,
            'find-last-index': 3 -1 3 3,
            'find-key': 2 null 3 2,
            'find-last-key': 3 null 3 3
        ), $method-name);

        @include test('should return the correct value') {
            $actual: _call($func, null, $maps, test-find-1);
            $expected: nth($expected-values, 1);

            @include assert-equal($actual, $expected);
        }

        @include xit('should work with a this-arg') {} // todo

        @include test('should return expected value if value is not found') {
            $actual: _call($func, null, $maps, test-find-2);
            $expected: nth($expected-values, 2);

            @include assert-equal($actual, $expected);
        }

        @include test('should work with a _pluck style predicate') {
            $actual: _call($func, null, $maps, 'b');
            $expected: nth($expected-values, 4);

            @include assert-equal($actual, $expected); 
        }

        @include test('should work with a _where style predicate') {
            $actual: _call($func, null, $maps, ('b': 2));
            $expected: nth($expected-values, 3);

            @include assert-equal($actual, $expected); 
        }

        @include test('should return expected value for empty collections') {
            $actual: _call($func, null, (), ('a': 3));
            $expected: nth($expected-values, 2);

            @include assert-equal($actual, $expected); 
        }

        @include test('should work with an object for collection') {
            $actual: _call($func, null, ('a': 1, 'b': 2, 'c': 3), test-find-3);
            $expected: __get((
                'find': 1,
                'find-last': 2,
                'find-key': 'a',
                'find-last-key': 'b'
            ), $method-name);

            @if ($expected != null) {
                @include assert-equal($actual, $expected); 
            } @else {
                @include assert-equal(true, true);
            }
        }

        @include test('should work with a string for collection') {
            $actual: _call($func, null, 'abc', test-find-4);
            $expected: __get((
                'find': 'a',
                'find-last': 'b',
                'find-index': 1,
                'find-last-index': 1
            ), $method-name);

            @if ($expected != null) {
                @include assert-equal($actual, $expected); 
            } @else {
                @include assert-equal(true, true);
            }
        }

        @if ($method-name == 'find') {
            @include test('should be aliased') {
                $actual: _detect(1 2 3, test-is-even);
                $expected: _find(1 2 3, test-is-even);

                @include assert-equal($actual, $expected); 
            }
        }
    }
}

@include test-module('_find-where') {
    $maps: (
        ('a': 1),
        ('a': 1),
        ('a': 1, 'b': 2),
        ('a': 2, 'b': 2),
        ('a': 3),
    );

    @include test('should filter by source properties') {
        @include assert-equal(
            _find-where($maps, ('a': 1)),
            nth($maps, 1));
        @include assert-equal(
            _find-where($maps, ('a': 2)),
            nth($maps, 4));
        @include assert-equal(
            _find-where($maps, ('a': 3)),
            nth($maps, 5));
        @include assert-equal(
            _find-where($maps, ('b': 1)),
            null);
        @include assert-equal(
            _find-where($maps, ('b': 2)),
            nth($maps, 3));
        @include assert-equal(
            _find-where($maps, ('a': 1, 'b': 2)),
            nth($maps, 3));
    }

    @include test('should match all elements when provided an empty source') {
        $actual: _find-where($maps, ());
        $expected: nth($maps, 1);

        @include assert-equal($actual, $expected);
    }
}