// -*- swift -*-
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test

%{
from gyb_stdlib_support import (
    TRAVERSALS,
    collectionTypeName
)
}%

import StdlibUnittest
import StdlibCollectionUnittest


/// Reference-type collection for testing the `base` property.
class ReferenceCollection : RandomAccessCollection {
  typealias Index = Int

  var startIndex: Int {
    return 0
  }

  var endIndex: Int {
    return 1
  }

  subscript(index: Int) -> String {
    return ""
  }

  func index(after i: Int) -> Int {
    return 1
  }

  func index(before i: Int) -> Int {
    return 0
  }
}

var SliceTests = TestSuite("Collection")

//===----------------------------------------------------------------------===//
// Slice<Base>
//===----------------------------------------------------------------------===//

% for Traversal in TRAVERSALS:
%   for Mutable in [ False, True ]:
%     for RangeReplaceable in [ False, True ]:
%       Collection = 'Minimal' + collectionTypeName(traversal=Traversal, mutable=Mutable, rangeReplaceable=RangeReplaceable)

SliceTests.test("${Collection}.Slice/AssociatedTypes") {
 do {
    typealias Collection = ${Collection}<OpaqueValue<Int>>
    typealias CollectionSlice = Slice<Collection>
    expectSliceType(CollectionSlice.self)
    expectCollectionAssociatedTypes(
      collectionType: CollectionSlice.self,
      iteratorType: IndexingIterator<CollectionSlice>.self,
      subSequenceType: CollectionSlice.self,
      indexType: MinimalIndex.self,
      indicesType: Collection.Indices.self)
  }

  func checkStaticTypealiases1<Base : Collection>(_: Base) {
    expectEqualType(Base.Index.self, Slice<Base>.Index.self)
  }

  func checkStaticTypealiases2<
    Base : MutableCollection
  >(_: Base) {
    expectEqualType(Base.Index.self, Slice<Base>.Index.self)
  }
}

SliceTests.test("${Collection}.Slice/init(base:bounds:)") {
  for test in subscriptRangeTests {
    let base = ${Collection}(elements: test.collection)
    var slice = Slice(base: base, bounds: test.bounds(in: base))
    expectType(Slice<${Collection}<OpaqueValue<Int>>>.self, &slice)
    expectType(${Collection}<OpaqueValue<Int>>.SubSequence.self, &slice)

    checkCollection(
      test.expected,
      slice,
      stackTrace: SourceLocStack().with(test.loc))
      { $0.value == $1.value }
  }
}

% if RangeReplaceable == False and Mutable == False:
SliceTests.test("${Collection}.Slice/baseProperty") {
  let referenceCollection = ReferenceCollection()
  let testSlice = Slice(base: referenceCollection, bounds: 0..<1)
  expectTrue(testSlice.base === referenceCollection)
}
% end

SliceTests.test("${Collection}.Slice.{startIndex,endIndex}") {
  for test in subscriptRangeTests {
    let c = ${Collection}(elements: test.collection)
    let bounds = test.bounds(in: c)
    var slice = Slice(base: c, bounds: bounds)
    expectType(Slice<${Collection}<OpaqueValue<Int>>>.self, &slice)
    expectType(${Collection}<OpaqueValue<Int>>.SubSequence.self, &slice)

    expectEqual(bounds.lowerBound, slice.startIndex)
    expectEqual(bounds.upperBound, slice.endIndex)
  }
}

%     end
%   end
% end

SliceTests.test("${Collection}.Slice.withContiguousStorageIfAvailable") {
  for test in subscriptRangeTests {
    let c = ${Collection}(elements: test.collection)
    let bounds = test.bounds(in: c)
    var slice = Slice(base: c, bounds: bounds)
    let r = slice.withContiguousStorageIfAvailable { _ in }
    expectNil(r) // None of the minimal collection types implement this.
  }
}

//===----------------------------------------------------------------------===//
// MutableSlice<Base>
//===----------------------------------------------------------------------===//

extension Slice {
  func _checkBaseSubSequenceElementIsElement() {
    expectEqualType(
      Element.self,
      Iterator.Element.self)
    expectEqualType(
      Element.self,
      Base.Iterator.Element.self)
    expectEqualType(
      Element.self,
      Iterator.Element.self)
    expectEqualType(
      Element.self,
      Base.SubSequence.Iterator.Element.self)
  }
}

runAllTests()