Produce framework tests
This commit is contained in:
@@ -75,7 +75,7 @@ allprojects {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
// backend.native/tests
|
// backend.native/tests
|
||||||
testOutputLocal {
|
testOutputLocal {
|
||||||
output.dir(rootProject.file("$testOutputRoot/local"))
|
output.dir(rootProject.file("$testOutputRoot/local"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// backend.native/tests/external
|
// backend.native/tests/external
|
||||||
@@ -87,6 +87,11 @@ allprojects {
|
|||||||
testOutputStdlib {
|
testOutputStdlib {
|
||||||
output.dir(rootProject.file("$testOutputRoot/stdlib"))
|
output.dir(rootProject.file("$testOutputRoot/stdlib"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// backend.native/tests/framework
|
||||||
|
testOutputFramework {
|
||||||
|
output.dir(rootProject.file("$testOutputRoot/framework"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +157,9 @@ def tasksOf(Closure<Task> filter) {
|
|||||||
run {
|
run {
|
||||||
def tasks = tasksOf { it instanceof KonanTest && it.inDevelopersRun }
|
def tasks = tasksOf { it instanceof KonanTest && it.inDevelopersRun }
|
||||||
dependsOn(tasks)
|
dependsOn(tasks)
|
||||||
|
|
||||||
|
// Add framework tests
|
||||||
|
dependsOn(project.tasks.withType(FrameworkTest))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect results in one json.
|
// Collect results in one json.
|
||||||
@@ -2645,6 +2653,41 @@ task produce_dynamic(type: DynamicKonanTest) {
|
|||||||
"topLevel = 777 3\n"
|
"topLevel = 777 3\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sourceSet's output path as a string
|
||||||
|
*/
|
||||||
|
static String outputPath(SourceSet set) {
|
||||||
|
return set.output.getDirs().getSingleFile().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMac() && project.testTarget != 'wasm32') {
|
||||||
|
def target = project.testTarget ?: 'host'
|
||||||
|
|
||||||
|
task testValuesFramework(type: FrameworkTest) {
|
||||||
|
frameworkName = 'Values'
|
||||||
|
konanArtifacts {
|
||||||
|
framework(frameworkName, targets: [ target ]) {
|
||||||
|
srcDir 'framework/values'
|
||||||
|
baseDir outputPath(sourceSets.testOutputFramework) + "/$frameworkName"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
swiftSources = ['framework/values/values.swift']
|
||||||
|
dependsOn "compileKonan${frameworkName}"
|
||||||
|
}
|
||||||
|
|
||||||
|
task testStdlibFramework(type: FrameworkTest) {
|
||||||
|
frameworkName = 'Stdlib'
|
||||||
|
konanArtifacts {
|
||||||
|
framework(frameworkName, targets: [ target ]) {
|
||||||
|
srcDir 'framework/stdlib'
|
||||||
|
baseDir outputPath(sourceSets.testOutputFramework) + "/$frameworkName"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
swiftSources = ['framework/stdlib/stdlib.swift']
|
||||||
|
dependsOn "compileKonan${frameworkName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
task buildKonanStdlibTests(type: BuildKonanTest) {
|
task buildKonanStdlibTests(type: BuildKonanTest) {
|
||||||
outputSourceSetName = "testOutputStdlib"
|
outputSourceSetName = "testOutputStdlib"
|
||||||
compileList = [ "stdlib_external", "testUtils.kt" ]
|
compileList = [ "stdlib_external", "testUtils.kt" ]
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 Foundation
|
||||||
|
|
||||||
|
enum TestError : Error {
|
||||||
|
case assertFailed(String)
|
||||||
|
case failure
|
||||||
|
case testsFailed([String])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- Assertions ----------------
|
||||||
|
|
||||||
|
func assertEquals<T: Equatable>(actual: T, expected: T,
|
||||||
|
_ message: String = "Assertion failed:") throws {
|
||||||
|
if (actual != expected) {
|
||||||
|
throw TestError.assertFailed(message + " Expected value: \(expected), but got: \(actual)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEquals<T: Equatable>(actual: [T], expected: [T],
|
||||||
|
_ message: String = "Assertion failed: arrays not equal") throws {
|
||||||
|
try assertEquals(actual: actual.count, expected: expected.count, "Size differs")
|
||||||
|
try assertTrue(actual.elementsEqual(expected), "Arrays elements are not equal")
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertTrue(_ value: Bool, _ message: String = "Assertion failed:") throws {
|
||||||
|
if (value != true) {
|
||||||
|
throw TestError.assertFailed(message + " Expected value to be TRUE, but got: \(value)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertFalse(_ value: Bool, _ message: String = "Assertion failed:") throws {
|
||||||
|
if (value != false) {
|
||||||
|
throw TestError.assertFailed(message + " Expected value to be FALSE, but got: \(value)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------- Utils --------------------
|
||||||
|
|
||||||
|
func withAutorelease( _ method: @escaping () throws -> Void) -> () throws -> Void {
|
||||||
|
return { () throws -> Void in
|
||||||
|
try autoreleasepool { try method() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- Execution ----------------
|
||||||
|
|
||||||
|
private final class Statistics : CustomStringConvertible {
|
||||||
|
var passed: [String] = []
|
||||||
|
var failed: [String] = []
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
return """
|
||||||
|
---- RESULTS:
|
||||||
|
PASSED: \(passed.count)
|
||||||
|
FAILED: \(failed.count)
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
static let instance = Statistics()
|
||||||
|
|
||||||
|
static func getInstance() -> Statistics {
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func start(_ name: String) {
|
||||||
|
print("---- Starting test: \(name)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func passed(_ name: String) {
|
||||||
|
print("---- PASSED test: \(name)")
|
||||||
|
passed.append(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func failed(_ name: String, error: Error) {
|
||||||
|
print("---- FAILED test: \(name) with error: \(error)")
|
||||||
|
failed.append(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* TestCase represents a single test
|
||||||
|
*/
|
||||||
|
struct TestCase {
|
||||||
|
let name: String
|
||||||
|
let method: () throws -> Void
|
||||||
|
|
||||||
|
init(name: String, method: @escaping () throws -> Void) {
|
||||||
|
self.name = name
|
||||||
|
self.method = method
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() {
|
||||||
|
let stats = Statistics.getInstance()
|
||||||
|
stats.start(name)
|
||||||
|
do {
|
||||||
|
try method()
|
||||||
|
stats.passed(name)
|
||||||
|
} catch {
|
||||||
|
stats.failed(name, error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol TestProvider {
|
||||||
|
var tests: [TestCase] { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
var providers: [TestProvider] = []
|
||||||
|
|
||||||
|
private func execute(tests: [TestCase]) {
|
||||||
|
for test in tests {
|
||||||
|
test.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point of the test
|
||||||
|
*/
|
||||||
|
private func main() {
|
||||||
|
// Generated method that instantiates TestProvider
|
||||||
|
registerProvider()
|
||||||
|
|
||||||
|
let stats = Statistics.getInstance()
|
||||||
|
for pr in providers {
|
||||||
|
execute(tests: pr.tests)
|
||||||
|
}
|
||||||
|
print(stats)
|
||||||
|
|
||||||
|
let failed = stats.failed
|
||||||
|
if !failed.isEmpty {
|
||||||
|
print()
|
||||||
|
print("Tests failed:")
|
||||||
|
for testName in failed {
|
||||||
|
print(":: \(testName)")
|
||||||
|
}
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UNUSED")
|
||||||
|
|
||||||
|
package stdlib
|
||||||
|
|
||||||
|
fun <K, V> isEmpty(map: Map<K, V>) = map.isEmpty()
|
||||||
|
|
||||||
|
fun <K, V> getKeysAsSet(map: Map<K, V>) = map.keys
|
||||||
|
fun <K, V> getKeysAsList(map: Map<K, V>) = map.keys.toList()
|
||||||
|
|
||||||
|
fun <K, V> toMutableMap(map: HashMap<K, V>) = map.toMutableMap()
|
||||||
|
|
||||||
|
fun <E> getFirstElement(collection: Collection<E>) = collection.first()
|
||||||
|
|
||||||
|
class GenericExtensionClass<K, out V, out T : Map<K, V>> (private val holder: T?) {
|
||||||
|
fun getFirstKey(): K? = holder?.entries?.first()?.key
|
||||||
|
|
||||||
|
fun getFirstValue() : V? {
|
||||||
|
holder?.entries?.forEach { e -> println("KEY: ${e.key} VALUE: ${e.value}") }
|
||||||
|
return holder?.entries?.first()?.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K, V> createPair():
|
||||||
|
Pair<LinkedHashMap<K, V>, GenericExtensionClass<K, V, Map<K, V>>> {
|
||||||
|
val l = createLinkedMap<K, V>()
|
||||||
|
val g = GenericExtensionClass(l)
|
||||||
|
return Pair(l, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K, V> createLinkedMap() = linkedMapOf<K, V>()
|
||||||
|
|
||||||
|
fun createTypedMutableMap() = linkedMapOf<Int, String>()
|
||||||
|
|
||||||
|
fun addSomeElementsToMap(map: MutableMap<String, Int>) {
|
||||||
|
map.put(key = "XYZ", value = 321)
|
||||||
|
map.put(key = "TMP", value = 451)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun list(vararg elements: Any?): Any = listOf(*elements)
|
||||||
|
fun set(vararg elements: Any?): Any = setOf(*elements)
|
||||||
|
fun map(vararg keysAndValues: Any?): Any = mutableMapOf<Any?, Any?>().apply {
|
||||||
|
(0 until keysAndValues.size step 2).forEach {index ->
|
||||||
|
this[keysAndValues[index]] = keysAndValues[index + 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emptyMutableList(): Any = mutableListOf<Any?>()
|
||||||
|
fun emptyMutableSet(): Any = mutableSetOf<Any?>()
|
||||||
|
fun emptyMutableMap(): Any = mutableMapOf<Any?, Any?>()
|
||||||
|
|
||||||
|
data class TripleVals<T>(val first: T, val second: T, val third: T)
|
||||||
|
|
||||||
|
data class TripleVars<T>(var first: T, var second: T, var third: T) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "[$first, $second, $third]"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 Foundation
|
||||||
|
import Stdlib
|
||||||
|
|
||||||
|
extension NSEnumerator {
|
||||||
|
func remainingObjects() -> [Any?] {
|
||||||
|
var result = [Any?]()
|
||||||
|
while (true) {
|
||||||
|
if let next = self.nextObject() {
|
||||||
|
result.append(next as AnyObject as Any?)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StdlibTests : TestProvider {
|
||||||
|
var tests: [TestCase] = []
|
||||||
|
|
||||||
|
init() {
|
||||||
|
tests = [
|
||||||
|
TestCase(name: "TestEmptyDictionary", method: withAutorelease(testEmptyDictionary)),
|
||||||
|
TestCase(name: "TestGenericMapUsage", method: withAutorelease(testGenericMapUsage)),
|
||||||
|
TestCase(name: "TestOrderedMapStored", method: withAutorelease(testOrderedMapStored)),
|
||||||
|
TestCase(name: "TestTypedMapUsage", method: withAutorelease(testTypedMapUsage)),
|
||||||
|
TestCase(name: "TestFirstElement", method: withAutorelease(testFirstElement)),
|
||||||
|
TestCase(name: "TestAddDictionary", method: withAutorelease(testAddDictionary)),
|
||||||
|
TestCase(name: "TestList", method: withAutorelease(testList)),
|
||||||
|
TestCase(name: "TestMutableList", method: withAutorelease(testMutableList)),
|
||||||
|
TestCase(name: "TestSet", method: withAutorelease(testSet)),
|
||||||
|
TestCase(name: "TestMutableSet", method: withAutorelease(testMutableSet)),
|
||||||
|
TestCase(name: "TestMap", method: withAutorelease(testMap)),
|
||||||
|
TestCase(name: "TestMutableMap", method: withAutorelease(testMutableMap))
|
||||||
|
]
|
||||||
|
providers.append(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass empty dictionary to Kotlin.
|
||||||
|
*/
|
||||||
|
func testEmptyDictionary() throws {
|
||||||
|
let immutableEmptyDict = [String: Int]()
|
||||||
|
try assertTrue(Stdlib.isEmpty(map: immutableEmptyDict), "Empty dictionary")
|
||||||
|
let keys = Stdlib.getKeysAsSet(map: immutableEmptyDict)
|
||||||
|
try assertTrue(keys.isEmpty, "Should have empty set")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests usage of a map with generics.
|
||||||
|
*/
|
||||||
|
func testGenericMapUsage() throws {
|
||||||
|
let map = Stdlib.createLinkedMap()
|
||||||
|
map[1] = "One"
|
||||||
|
map[10] = "Ten"
|
||||||
|
map[11] = "Eleven"
|
||||||
|
map["10"] = "Ten as string"
|
||||||
|
for (k, v) in map {
|
||||||
|
print("MAP: \(k) - \(v)")
|
||||||
|
}
|
||||||
|
|
||||||
|
try assertEquals(actual: map[11] as! String, expected: "Eleven", "An element of the map for key: 11")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks order of the underlying LinkedHashMap.
|
||||||
|
*/
|
||||||
|
func testOrderedMapStored() throws {
|
||||||
|
let pair = Stdlib.createPair()
|
||||||
|
let map = pair.first as? NSMutableDictionary
|
||||||
|
|
||||||
|
map?[1] = "One"
|
||||||
|
map?[10] = "Ten"
|
||||||
|
map?[11] = "Eleven"
|
||||||
|
map?["10"] = "Ten as string"
|
||||||
|
|
||||||
|
let gen = pair.second as! StdlibGenericExtensionClass
|
||||||
|
let value: String? = gen.getFirstValue() as? String
|
||||||
|
try assertEquals(actual: value!, expected: "One", "First value of the map")
|
||||||
|
|
||||||
|
let key: Int? = gen.getFirstKey() as? Int
|
||||||
|
try assertEquals(actual: key!, expected: 1, "First key of the map")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests typed map created in Kotlin.
|
||||||
|
*/
|
||||||
|
func testTypedMapUsage() throws {
|
||||||
|
let map = Stdlib.createTypedMutableMap()
|
||||||
|
map[1] = "One"
|
||||||
|
map[1.0 as Float] = "Float"
|
||||||
|
map[11] = "Eleven"
|
||||||
|
map["10"] = "Ten as string"
|
||||||
|
|
||||||
|
try assertEquals(actual: map["10"] as! String, expected: "Ten as string", "String key")
|
||||||
|
try assertEquals(actual: map[1.0 as Float] as! String, expected: "Float", "Float key")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get first element of the collection.
|
||||||
|
*/
|
||||||
|
func testFirstElement() throws {
|
||||||
|
let m = Stdlib.createTypedMutableMap()
|
||||||
|
m[10] = "Str"
|
||||||
|
try assertEquals(actual: Stdlib.getFirstElement(collection: m.allKeys) as! Int, expected: 10, "First key")
|
||||||
|
|
||||||
|
try assertEquals(actual: Stdlib.getFirstElement(collection: Stdlib.getKeysAsList(map: m as! Dictionary)) as! Int,
|
||||||
|
expected: 10, "First key from a list")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add element to dictionary in Kotlin
|
||||||
|
*/
|
||||||
|
func testAddDictionary() throws {
|
||||||
|
let m = [ "ABC": 10, "CDE": 12, "FGH": 3 ]
|
||||||
|
Stdlib.addSomeElementsToMap(map: StdlibMutableDictionary(dictionary: m))
|
||||||
|
for (k, v) in m {
|
||||||
|
print("MAP: \(k) - \(v)")
|
||||||
|
}
|
||||||
|
|
||||||
|
var smd = StdlibMutableDictionary<NSString, NSNumber>()
|
||||||
|
smd.setObject(333, forKey: "333" as NSString)
|
||||||
|
try assertEquals(actual: smd.object(forKey: "333" as NSString) as! Int, expected: 333, "Add element to dict")
|
||||||
|
|
||||||
|
Stdlib.addSomeElementsToMap(map: smd)
|
||||||
|
for (k, v) in smd {
|
||||||
|
print("MAP: \(k) - \(v)")
|
||||||
|
}
|
||||||
|
try assertEquals(actual: smd.object(forKey: "XYZ" as NSString) as! Int, expected: 321, "Get element from Kotlin")
|
||||||
|
}
|
||||||
|
|
||||||
|
func zeroTo(_ n: Int32) -> StdlibStdlibArray { return StdlibStdlibArray(size: n) { $0 } }
|
||||||
|
|
||||||
|
func testList() throws {
|
||||||
|
let elements = zeroTo(5)
|
||||||
|
elements.set(index: 1, value: nil)
|
||||||
|
let list = Stdlib.list(elements: elements) as! NSArray
|
||||||
|
try assertEquals(actual: list.object(at: 2) as! NSNumber, expected: NSNumber(value: 2))
|
||||||
|
try assertEquals(actual: list.object(at: 1) as! NSNull, expected: NSNull())
|
||||||
|
try assertEquals(actual: list.count, expected: 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMutableList() throws {
|
||||||
|
let kotlinList = Stdlib.emptyMutableList() as! NSMutableArray
|
||||||
|
let nsList = NSMutableArray()
|
||||||
|
|
||||||
|
func apply<T : Equatable>(op: (NSMutableArray)->T) throws {
|
||||||
|
let actual = op(kotlinList)
|
||||||
|
let expected = op(nsList)
|
||||||
|
try assertEquals(actual: actual, expected: expected)
|
||||||
|
try assertEquals(actual: kotlinList, expected: nsList)
|
||||||
|
try assertEquals(actual: kotlinList.hash, expected: nsList.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyVoid(op: (NSMutableArray)->Void) throws {
|
||||||
|
op(kotlinList)
|
||||||
|
op(nsList)
|
||||||
|
try assertEquals(actual: kotlinList, expected: nsList)
|
||||||
|
try assertEquals(actual: kotlinList.hash, expected: nsList.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
try apply { $0.count }
|
||||||
|
try applyVoid { $0.insert(0, at: 0) }
|
||||||
|
try applyVoid { $0.insert(1, at: 0) }
|
||||||
|
try applyVoid { $0.insert(2, at: 1) }
|
||||||
|
try applyVoid { $0.removeObject(at: 0) }
|
||||||
|
try applyVoid { $0.add("foo") }
|
||||||
|
try applyVoid { $0.removeLastObject() }
|
||||||
|
try applyVoid { $0.replaceObject(at: 0, with: "bar") }
|
||||||
|
let NULL: Any? = nil
|
||||||
|
try applyVoid { $0.add(NULL as Any) }
|
||||||
|
try applyVoid { $0.insert(NULL as Any, at: 2) }
|
||||||
|
try applyVoid { $0.replaceObject(at: 1, with: NULL as Any) }
|
||||||
|
try apply { $0.count }
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMutableSet() throws {
|
||||||
|
let kotlinSet = Stdlib.emptyMutableSet() as! NSMutableSet
|
||||||
|
let nsSet = NSMutableSet()
|
||||||
|
|
||||||
|
func apply<T : Equatable>(op: (NSMutableSet)->T) throws {
|
||||||
|
let actual = op(kotlinSet)
|
||||||
|
let expected = op(nsSet)
|
||||||
|
try assertEquals(actual: actual, expected: expected)
|
||||||
|
try assertEquals(actual: kotlinSet, expected: nsSet)
|
||||||
|
try assertEquals(actual: kotlinSet.hash, expected: nsSet.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyVoid(op: (NSMutableSet)->Void) throws {
|
||||||
|
op(kotlinSet)
|
||||||
|
op(nsSet)
|
||||||
|
try assertEquals(actual: kotlinSet, expected: nsSet)
|
||||||
|
try assertEquals(actual: kotlinSet.hash, expected: nsSet.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
try apply { $0.count }
|
||||||
|
try applyVoid { $0.add("foo") }
|
||||||
|
try applyVoid { $0.add("bar") }
|
||||||
|
try applyVoid { $0.remove("baz") }
|
||||||
|
try applyVoid { $0.add("baz") }
|
||||||
|
try applyVoid { $0.add(StdlibTripleVals(first: 1, second: 2, third: 3)) }
|
||||||
|
try apply { $0.member(StdlibTripleVals(first: 1, second: 2, third: 3)) as! StdlibTripleVals }
|
||||||
|
try apply { $0.member(42) == nil }
|
||||||
|
try applyVoid { $0.remove(StdlibTripleVals(first: 1, second: 2, third: 3)) }
|
||||||
|
|
||||||
|
let NULL0: Any? = nil
|
||||||
|
let NULL = NULL0 as Any
|
||||||
|
|
||||||
|
try applyVoid { $0.add(NULL) }
|
||||||
|
try apply { $0.member(NULL) == nil }
|
||||||
|
try apply { $0.member(NULL) as! NSObject }
|
||||||
|
try applyVoid { $0.remove(NULL) }
|
||||||
|
try apply { $0.member(NULL) == nil }
|
||||||
|
|
||||||
|
try apply { NSSet(array: $0.objectEnumerator().remainingObjects()) }
|
||||||
|
|
||||||
|
try apply { $0.count }
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMutableMap() throws {
|
||||||
|
// TODO: test KotlinMutableSet/Dictionary constructors
|
||||||
|
let kotlinMap = Stdlib.emptyMutableMap() as! NSMutableDictionary
|
||||||
|
let nsMap = NSMutableDictionary()
|
||||||
|
|
||||||
|
func apply<T : Equatable>(op: (NSMutableDictionary)->T) throws {
|
||||||
|
let actual = op(kotlinMap)
|
||||||
|
let expected = op(nsMap)
|
||||||
|
try assertEquals(actual: actual, expected: expected)
|
||||||
|
try assertEquals(actual: kotlinMap, expected: nsMap)
|
||||||
|
try assertEquals(actual: kotlinMap.hash, expected: nsMap.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyVoid(op: (NSMutableDictionary) throws -> Void) throws {
|
||||||
|
try op(kotlinMap)
|
||||||
|
try op(nsMap)
|
||||||
|
try assertEquals(actual: kotlinMap, expected: nsMap)
|
||||||
|
try assertEquals(actual: kotlinMap.hash, expected: nsMap.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
try apply { $0.count }
|
||||||
|
try apply { $0.object(forKey: 42) == nil }
|
||||||
|
try applyVoid { $0.setObject(42, forKey: 42 as NSNumber) }
|
||||||
|
try applyVoid { $0.setObject(17, forKey: "foo" as NSString) }
|
||||||
|
let triple = StdlibTripleVals(first: 3, second: 2, third: 1)
|
||||||
|
try applyVoid { $0.setObject("bar", forKey: triple) }
|
||||||
|
try applyVoid { $0.removeObject(forKey: 42) }
|
||||||
|
try apply { $0.count }
|
||||||
|
try apply { $0.object(forKey: 42) == nil }
|
||||||
|
try apply { $0.object(forKey: "foo") as! NSObject }
|
||||||
|
try apply { $0.object(forKey: triple) as! NSObject }
|
||||||
|
|
||||||
|
try apply { NSSet(array: $0.keyEnumerator().remainingObjects()) }
|
||||||
|
|
||||||
|
let NULL0: Any? = nil
|
||||||
|
let NULL = NULL0 as Any
|
||||||
|
|
||||||
|
try apply { $0.object(forKey: NULL) == nil }
|
||||||
|
|
||||||
|
|
||||||
|
try applyVoid { $0.setObject(42, forKey: NULL as! NSCopying) }
|
||||||
|
try applyVoid { $0.setObject(NULL, forKey: "baz" as NSString) }
|
||||||
|
try apply { $0.object(forKey: NULL) as! NSObject }
|
||||||
|
try apply { $0.object(forKey: "baz") as! NSObject }
|
||||||
|
|
||||||
|
try apply { NSSet(array: $0.keyEnumerator().remainingObjects()) }
|
||||||
|
|
||||||
|
try applyVoid { $0.removeObject(forKey: NULL) }
|
||||||
|
try applyVoid { $0.removeObject(forKey: "baz") }
|
||||||
|
|
||||||
|
try applyVoid { $0.removeAllObjects() }
|
||||||
|
|
||||||
|
let myKey = MyKey()
|
||||||
|
try applyVoid { $0.setObject(myKey, forKey: myKey) }
|
||||||
|
try applyVoid {
|
||||||
|
let key = $0.allKeys[0] as! MyKey
|
||||||
|
let value = $0.allValues[0] as! MyKey
|
||||||
|
try assertFalse(key === myKey)
|
||||||
|
try assertTrue(value === myKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc class MyKey : NSObject, NSCopying {
|
||||||
|
override var hash: Int {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
|
||||||
|
override func isEqual(_ object: Any?) -> Bool {
|
||||||
|
return object is MyKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func copy(with: NSZone? = nil) -> Any {
|
||||||
|
return MyKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSet() throws {
|
||||||
|
let elements = StdlibStdlibArray(size: 2) { index in nil }
|
||||||
|
elements.set(index: 0, value: nil)
|
||||||
|
elements.set(index: 1, value: 42)
|
||||||
|
let set = Stdlib.set(elements: elements) as! NSSet
|
||||||
|
try assertEquals(actual: set.count, expected: 2)
|
||||||
|
try assertEquals(actual: set.member(NSNull()) as! NSNull, expected: NSNull())
|
||||||
|
try assertEquals(actual: set.member(42) as! NSNumber, expected: NSNumber(value: 42 as Int32))
|
||||||
|
try assertTrue(set.member(17) == nil)
|
||||||
|
try assertFalse(set.member(42) as AnyObject === NSNumber(value: 42 as Int32))
|
||||||
|
try assertTrue(set.contains(42))
|
||||||
|
try assertTrue(set.contains(nil as Any?))
|
||||||
|
try assertFalse(set.contains(17))
|
||||||
|
|
||||||
|
try assertEquals(actual: NSSet(array: set.objectEnumerator().remainingObjects()), expected: NSSet(array: [nil, 42] as [AnyObject]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMap() throws {
|
||||||
|
let elements = StdlibStdlibArray(size: 6) { index in nil }
|
||||||
|
elements.set(index: 0, value: nil)
|
||||||
|
elements.set(index: 1, value: 42)
|
||||||
|
elements.set(index: 2, value: "foo")
|
||||||
|
elements.set(index: 3, value: "bar")
|
||||||
|
elements.set(index: 4, value: 42)
|
||||||
|
elements.set(index: 5, value: nil)
|
||||||
|
|
||||||
|
let map = Stdlib.map(keysAndValues: elements) as! NSDictionary
|
||||||
|
try assertEquals(actual: map.count, expected: 3)
|
||||||
|
|
||||||
|
try assertEquals(actual: map.object(forKey: NSNull()) as! NSNumber, expected: NSNumber(value: 42))
|
||||||
|
try assertEquals(actual: map.object(forKey: "foo") as! String, expected: "bar")
|
||||||
|
try assertEquals(actual: map.object(forKey: 42) as! NSNull, expected: NSNull())
|
||||||
|
try assertTrue(map.object(forKey: "bar") == nil)
|
||||||
|
|
||||||
|
try assertEquals(actual: NSSet(array: map.keyEnumerator().remainingObjects()), expected: NSSet(array: [nil, 42, "foo"] as [AnyObject]))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// All classes and methods should be used in tests
|
||||||
|
@file:Suppress("UNUSED")
|
||||||
|
|
||||||
|
package conversions
|
||||||
|
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const val dbl: Double = 3.14
|
||||||
|
const val flt: Float = 2.73F
|
||||||
|
const val integer: Int = 42
|
||||||
|
const val longInt: Long = 1984
|
||||||
|
|
||||||
|
// Vars
|
||||||
|
var intVar: Int = 451
|
||||||
|
var str = "Kotlin String"
|
||||||
|
var strAsAny: Any = "Kotlin String as Any"
|
||||||
|
|
||||||
|
// MIN/MAX values as Numbers
|
||||||
|
var minDoubleVal: kotlin.Number = Double.MIN_VALUE
|
||||||
|
var maxDoubleVal: kotlin.Number = Double.MAX_VALUE
|
||||||
|
|
||||||
|
// Infinities and NaN
|
||||||
|
val nanDoubleVal: Double = Double.NaN
|
||||||
|
val nanFloatVal: Float = Float.NaN
|
||||||
|
val infDoubleVal: Double = Double.POSITIVE_INFINITY
|
||||||
|
val infFloatVal: Float = Float.NEGATIVE_INFINITY
|
||||||
|
|
||||||
|
// Boolean
|
||||||
|
val boolVal: Boolean = true
|
||||||
|
val boolAnyVal: Any = false
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
val numbersList: List<Number> = listOf(1.toByte(), 2.toShort(), 13)
|
||||||
|
val anyList: List<Any> = listOf("Str", 42, 3.14, true)
|
||||||
|
|
||||||
|
// lateinit
|
||||||
|
lateinit var lateinitIntVar: Any
|
||||||
|
|
||||||
|
// lazy
|
||||||
|
val lazyVal: String by lazy {
|
||||||
|
println("Lazy value initialization")
|
||||||
|
"Lazily initialized string"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegation
|
||||||
|
var delegatedGlobalArray: Array<String> by DelegateClass()
|
||||||
|
|
||||||
|
class DelegateClass: ReadWriteProperty<Nothing?, Array<String>> {
|
||||||
|
|
||||||
|
private var holder: Array<String> = arrayOf("property")
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Nothing?, property: KProperty<*>): Array<String> {
|
||||||
|
return arrayOf("Delegated", "global", "array") + holder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Nothing?, property: KProperty<*>, value: Array<String>) {
|
||||||
|
holder = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter with delegation
|
||||||
|
val delegatedList: List<String>
|
||||||
|
get() = delegatedGlobalArray.toList()
|
||||||
|
|
||||||
|
// Null
|
||||||
|
val nullVal: Any? = null
|
||||||
|
var nullVar: String? = ""
|
||||||
|
|
||||||
|
// Any
|
||||||
|
var anyValue: Any = "Str"
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
fun emptyFun() { }
|
||||||
|
|
||||||
|
fun strFun(): String = "fooStr"
|
||||||
|
|
||||||
|
fun argsFun(i: Int, l: Long, d: Double, s: String): Any = s + i + l + d
|
||||||
|
|
||||||
|
fun funArgument(foo: () -> String): String = foo()
|
||||||
|
|
||||||
|
// Generic functions
|
||||||
|
fun <T, R> genericFoo(t: T, foo: (T) -> R): R = foo(t)
|
||||||
|
|
||||||
|
fun <T : Number, R : T> fooGenericNumber(r: R, foo: (T) -> Number): Number = foo(r)
|
||||||
|
|
||||||
|
fun <T> varargToList(vararg args: T): List<T> = args.toList()
|
||||||
|
|
||||||
|
// Extensions
|
||||||
|
fun String.subExt(i: Int): String {
|
||||||
|
return if (i < this.length) this[i].toString() else "nothing"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Any?.toString(): String = this?.toString() ?: "null"
|
||||||
|
|
||||||
|
fun Any?.print() = println(this.toString())
|
||||||
|
|
||||||
|
// Lambdas
|
||||||
|
val sumLambda = { x: Int, y: Int -> x + y }
|
||||||
|
|
||||||
|
|
||||||
|
// Inheritance
|
||||||
|
interface I {
|
||||||
|
fun iFun(): String = "I::iFun"
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface PI {
|
||||||
|
fun piFun(): Any
|
||||||
|
fun iFun(): String = "PI::iFun"
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultInterfaceExt : I
|
||||||
|
|
||||||
|
open class OpenClassI : I {
|
||||||
|
override fun iFun(): String = "OpenClassI::iFun"
|
||||||
|
}
|
||||||
|
|
||||||
|
class FinalClassExtOpen : OpenClassI() {
|
||||||
|
override fun iFun(): String = "FinalClassExtOpen::iFun"
|
||||||
|
}
|
||||||
|
|
||||||
|
open class MultiExtClass : OpenClassI(), PI {
|
||||||
|
override fun piFun(): Any {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iFun(): String = super<PI>.iFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ConstrClass(open val i: Int, val s: String, val a: Any = "AnyS") : OpenClassI()
|
||||||
|
|
||||||
|
class ExtConstrClass(override val i: Int) : ConstrClass(i, "String") {
|
||||||
|
override fun iFun(): String = "ExtConstrClass::iFun::$i-$s-$a"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enum
|
||||||
|
enum class Enumeration(val enumValue: Int) {
|
||||||
|
ANSWER(42), YEAR(1984), TEMPERATURE(451)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun passEnum(): Enumeration {
|
||||||
|
return Enumeration.ANSWER
|
||||||
|
}
|
||||||
|
|
||||||
|
fun receiveEnum(e: Int) {
|
||||||
|
println("ENUM got: ${get(e).enumValue}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(value: Int): Enumeration {
|
||||||
|
return Enumeration.values()[value]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data class values and generated properties: component# and toString()
|
||||||
|
data class TripleVals<T>(val first: T, val second: T, val third: T)
|
||||||
|
|
||||||
|
data class TripleVars<T>(var first: T, var second: T, var third: T) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "[$first, $second, $third]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class WithCompanionAndObject {
|
||||||
|
companion object {
|
||||||
|
val str = "String"
|
||||||
|
var named: I? = Named
|
||||||
|
}
|
||||||
|
|
||||||
|
object Named : OpenClassI() {
|
||||||
|
override fun iFun(): String = "WithCompanionAndObject.Named::iFun"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCompanionObject() = WithCompanionAndObject.Companion
|
||||||
|
fun getNamedObject() = WithCompanionAndObject.Named
|
||||||
|
fun getNamedObjectInterface(): OpenClassI = WithCompanionAndObject.Named
|
||||||
|
|
||||||
|
typealias EE = Enumeration
|
||||||
|
fun EE.getAnswer() : EE = Enumeration.ANSWER
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 Foundation
|
||||||
|
import Values
|
||||||
|
|
||||||
|
// -------- Tests --------
|
||||||
|
|
||||||
|
func testVals() throws {
|
||||||
|
print("Values from Swift")
|
||||||
|
let dbl = Values.dbl
|
||||||
|
let flt = Values.flt
|
||||||
|
let int = Values.integer
|
||||||
|
let long = Values.longInt
|
||||||
|
|
||||||
|
print(dbl)
|
||||||
|
print(flt)
|
||||||
|
print(int)
|
||||||
|
print(long)
|
||||||
|
|
||||||
|
try assertEquals(actual: dbl, expected: 3.14 as Double, "Double value isn't equal.")
|
||||||
|
try assertEquals(actual: flt, expected: 2.73 as Float, "Float value isn't equal.")
|
||||||
|
try assertEquals(actual: int, expected: 42)
|
||||||
|
try assertEquals(actual: long, expected: 1984)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVars() throws {
|
||||||
|
print("Variables from Swift")
|
||||||
|
var intVar = Values.intVar
|
||||||
|
var strVar = Values.str
|
||||||
|
var strAsId = Values.strAsAny
|
||||||
|
|
||||||
|
print(intVar)
|
||||||
|
print(strVar)
|
||||||
|
print(strAsId)
|
||||||
|
|
||||||
|
try assertEquals(actual: intVar, expected: 451)
|
||||||
|
try assertEquals(actual: strVar, expected: "Kotlin String")
|
||||||
|
try assertEquals(actual: strAsId as! String, expected: "Kotlin String as Any")
|
||||||
|
|
||||||
|
strAsId = "Swift str"
|
||||||
|
Values.strAsAny = strAsId
|
||||||
|
print(Values.strAsAny)
|
||||||
|
try assertEquals(actual: Values.strAsAny as! String, expected: strAsId as! String)
|
||||||
|
|
||||||
|
// property with custom getter/setter backed by the Kotlin's var
|
||||||
|
var intProp : Int32 {
|
||||||
|
get {
|
||||||
|
return Values.intVar * 2
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
Values.intVar = 123 + value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intProp += 10
|
||||||
|
print(intProp)
|
||||||
|
print(Values.intVar)
|
||||||
|
try assertEquals(actual: Values.intVar * 2, expected: intProp, "Property backed by var")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDoubles() throws {
|
||||||
|
print("Doubles in Swift")
|
||||||
|
let minDouble = Values.minDoubleVal as! Double
|
||||||
|
let maxDouble = Values.maxDoubleVal as! NSNumber
|
||||||
|
|
||||||
|
print(minDouble)
|
||||||
|
print(maxDouble)
|
||||||
|
print(Values.nanDoubleVal)
|
||||||
|
print(Values.nanFloatVal)
|
||||||
|
print(Values.infDoubleVal)
|
||||||
|
print(Values.infFloatVal)
|
||||||
|
|
||||||
|
try assertEquals(actual: minDouble, expected: Double.leastNonzeroMagnitude, "Min double")
|
||||||
|
try assertEquals(actual: maxDouble, expected: Double.greatestFiniteMagnitude as NSNumber, "Max double")
|
||||||
|
try assertTrue(Values.nanDoubleVal.isNaN, "NaN double")
|
||||||
|
try assertTrue(Values.nanFloatVal.isNaN, "NaN float")
|
||||||
|
try assertEquals(actual: Values.infDoubleVal, expected: Double.infinity, "Inf double")
|
||||||
|
try assertEquals(actual: Values.infFloatVal, expected: -Float.infinity, "-Inf float")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLists() throws {
|
||||||
|
let numbersList = Values.numbersList
|
||||||
|
let gold = [1, 2, 13]
|
||||||
|
for i in 0..<gold.count {
|
||||||
|
try assertEquals(actual: gold[i], expected: Int(numbersList[i] as! NSNumber), "Numbers list")
|
||||||
|
}
|
||||||
|
|
||||||
|
let anyList = Values.anyList
|
||||||
|
for i in anyList {
|
||||||
|
print(i)
|
||||||
|
}
|
||||||
|
// try assertEquals(actual: gold, expected: anyList, "Numbers list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLazyVal() throws {
|
||||||
|
let lazyVal = Values.lazyVal
|
||||||
|
print(lazyVal)
|
||||||
|
try assertEquals(actual: lazyVal, expected: "Lazily initialized string", "lazy value")
|
||||||
|
}
|
||||||
|
|
||||||
|
let goldenArray = ["Delegated", "global", "array", "property"]
|
||||||
|
|
||||||
|
func testDelegatedProp() throws {
|
||||||
|
let delegatedGlobalArray = Values.delegatedGlobalArray
|
||||||
|
guard Int(delegatedGlobalArray.size) == goldenArray.count else {
|
||||||
|
throw TestError.assertFailed("Size differs")
|
||||||
|
}
|
||||||
|
for i in 0..<delegatedGlobalArray.size {
|
||||||
|
print(delegatedGlobalArray.get(index: i)!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetterDelegate() throws {
|
||||||
|
let delegatedList = Values.delegatedList
|
||||||
|
guard delegatedList.count == goldenArray.count else {
|
||||||
|
throw TestError.assertFailed("Size differs")
|
||||||
|
}
|
||||||
|
for val in delegatedList {
|
||||||
|
print(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNulls() throws {
|
||||||
|
let nilVal : Any? = Values.nullVal
|
||||||
|
try assertTrue(nilVal == nil, "Null value")
|
||||||
|
|
||||||
|
Values.nullVar = nil
|
||||||
|
var nilVar : Any? = Values.nullVar
|
||||||
|
try assertTrue(nilVar == nil, "Null variable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAnyVar() throws {
|
||||||
|
let anyVar : Any = Values.anyValue
|
||||||
|
print(anyVar)
|
||||||
|
if let str = anyVar as? String {
|
||||||
|
print(str)
|
||||||
|
try assertEquals(actual: str, expected: "Str")
|
||||||
|
} else {
|
||||||
|
throw TestError.assertFailed("Incorrect type passed from Any")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFunctions() throws {
|
||||||
|
let _: Any? = Values.emptyFun()
|
||||||
|
|
||||||
|
let str = Values.strFun()
|
||||||
|
try assertEquals(actual: str, expected: "fooStr")
|
||||||
|
|
||||||
|
try assertEquals(actual: Values.argsFun(i: 10, l: 20, d: 3.5, s: "res") as! String,
|
||||||
|
expected: "res10203.5")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFuncType() throws {
|
||||||
|
let s = "str"
|
||||||
|
let fFunc: () -> String = { return s }
|
||||||
|
try assertEquals(actual: Values.funArgument(foo: fFunc), expected: s, "Using function type arguments failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGenericsFoo() throws {
|
||||||
|
let fun = { (i: Int) -> String in return "S \(i)" }
|
||||||
|
// wrap lambda to workaround issue with type conversion inability:
|
||||||
|
// (Int) -> String can't be cast to (Any?) -> Any?
|
||||||
|
let wrapper = { (t: Any?) -> Any? in return fun(t as! Int) }
|
||||||
|
let res = Values.genericFoo(t: 42, foo: wrapper)
|
||||||
|
try assertEquals(actual: res as! String, expected: "S 42")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVararg() throws {
|
||||||
|
let ktArray = ValuesStdlibArray(size: 3, init: { (_) -> Int in return 42 })
|
||||||
|
let arr: [Int] = Values.varargToList(args: ktArray) as! [Int]
|
||||||
|
try assertEquals(actual: arr, expected: [42, 42, 42])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStrExtFun() throws {
|
||||||
|
try assertEquals(actual: Values.subExt("String", i: 2), expected: "r")
|
||||||
|
try assertEquals(actual: Values.subExt("A", i: 2), expected: "nothing")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAnyToString() throws {
|
||||||
|
try assertEquals(actual: Values.toString(nil), expected: "null")
|
||||||
|
try assertEquals(actual: Values.toString(42), expected: "42")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAnyPrint() throws {
|
||||||
|
print("BEGIN")
|
||||||
|
Values.print(nil)
|
||||||
|
Values.print("Print")
|
||||||
|
Values.print(123456789)
|
||||||
|
Values.print(3.14)
|
||||||
|
Values.print([3, 2, 1])
|
||||||
|
print("END")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLambda() throws {
|
||||||
|
try assertEquals(actual: Values.sumLambda(3, 4), expected: 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Tests for classes and interfaces -------
|
||||||
|
class ValIEmptyExt : ValuesI {
|
||||||
|
func iFun() -> String {
|
||||||
|
return "ValIEmptyExt::iFun"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValIExt : ValuesI {
|
||||||
|
func iFun() -> String {
|
||||||
|
return "ValIExt::iFun"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInterfaceExtension() throws {
|
||||||
|
try assertEquals(actual: ValIEmptyExt().iFun(), expected: "ValIEmptyExt::iFun")
|
||||||
|
try assertEquals(actual: ValIExt().iFun(), expected: "ValIExt::iFun")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testClassInstances() throws {
|
||||||
|
try assertEquals(actual: ValuesOpenClassI().iFun(), expected: "OpenClassI::iFun")
|
||||||
|
try assertEquals(actual: ValuesDefaultInterfaceExt().iFun(), expected: "I::iFun")
|
||||||
|
try assertEquals(actual: ValuesFinalClassExtOpen().iFun(), expected: "FinalClassExtOpen::iFun")
|
||||||
|
try assertEquals(actual: ValuesMultiExtClass().iFun(), expected: "PI::iFun")
|
||||||
|
try assertEquals(actual: ValuesMultiExtClass().piFun() as! Int, expected: 42)
|
||||||
|
try assertEquals(actual: ValuesConstrClass(i: 1, s: "str", a: "Any").iFun(), expected: "OpenClassI::iFun")
|
||||||
|
try assertEquals(actual: ValuesExtConstrClass(i: 123).iFun(), expected: "ExtConstrClass::iFun::123-String-AnyS")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEnum() throws {
|
||||||
|
try assertEquals(actual: Values.passEnum().enumValue, expected: 42)
|
||||||
|
try assertEquals(actual: Values.passEnum().name, expected: "ANSWER")
|
||||||
|
Values.receiveEnum(e: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDataClass() throws {
|
||||||
|
let f = "1"
|
||||||
|
let s = "2"
|
||||||
|
let t = "3"
|
||||||
|
|
||||||
|
let tripleVal = ValuesTripleVals(first: f, second: s, third: t)
|
||||||
|
try assertEquals(actual: tripleVal.first as! String, expected: f, "Data class' value")
|
||||||
|
try assertEquals(actual: tripleVal.component2() as! String, expected: s, "Data class' component")
|
||||||
|
print(tripleVal)
|
||||||
|
try assertEquals(actual: String(describing: tripleVal), expected: "TripleVals(first=\(f), second=\(s), third=\(t))")
|
||||||
|
|
||||||
|
let tripleVar = ValuesTripleVars(first: f, second: s, third: t)
|
||||||
|
try assertEquals(actual: tripleVar.first as! String, expected: f, "Data class' value")
|
||||||
|
try assertEquals(actual: tripleVar.component2() as! String, expected: s, "Data class' component")
|
||||||
|
print(tripleVar)
|
||||||
|
try assertEquals(actual: String(describing: tripleVar), expected: "[\(f), \(s), \(t)]")
|
||||||
|
|
||||||
|
tripleVar.first = t
|
||||||
|
tripleVar.second = f
|
||||||
|
tripleVar.third = s
|
||||||
|
try assertEquals(actual: tripleVar.component2() as! String, expected: f, "Data class' component")
|
||||||
|
try assertEquals(actual: String(describing: tripleVar), expected: "[\(t), \(f), \(s)]")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCompanionObj() throws {
|
||||||
|
try assertEquals(actual: ValuesWithCompanionAndObjectCompanion().str, expected: "String")
|
||||||
|
try assertEquals(actual: Values.getCompanionObject().str, expected: "String")
|
||||||
|
|
||||||
|
let namedFromCompanion = Values.getCompanionObject().named
|
||||||
|
let named = Values.getNamedObject()
|
||||||
|
try assertTrue(named === namedFromCompanion, "Should be the same Named object")
|
||||||
|
|
||||||
|
try assertEquals(actual: Values.getNamedObjectInterface().iFun(), expected: named.iFun(), "Named object's method")
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Execution of the test --------
|
||||||
|
|
||||||
|
class ValuesTests : TestProvider {
|
||||||
|
var tests: [TestCase] = []
|
||||||
|
|
||||||
|
init() {
|
||||||
|
providers.append(self)
|
||||||
|
tests = [
|
||||||
|
TestCase(name: "TestValues", method: withAutorelease(testVals)),
|
||||||
|
TestCase(name: "TestVars", method: withAutorelease(testVars)),
|
||||||
|
TestCase(name: "TestDoubles", method: withAutorelease(testDoubles)),
|
||||||
|
TestCase(name: "TestLists", method: withAutorelease(testLists)),
|
||||||
|
TestCase(name: "TestLazyValues", method: withAutorelease(testLazyVal)),
|
||||||
|
TestCase(name: "TestDelegatedProperties", method: withAutorelease(testDelegatedProp)),
|
||||||
|
TestCase(name: "TestGetterDelegate", method: withAutorelease(testGetterDelegate)),
|
||||||
|
TestCase(name: "TestNulls", method: withAutorelease(testNulls)),
|
||||||
|
TestCase(name: "TestAnyVar", method: withAutorelease(testAnyVar)),
|
||||||
|
TestCase(name: "TestFunctions", method: withAutorelease(testFunctions)),
|
||||||
|
TestCase(name: "TestFuncType", method: withAutorelease(testFuncType)),
|
||||||
|
TestCase(name: "TestGenericsFoo", method: withAutorelease(testGenericsFoo)),
|
||||||
|
TestCase(name: "TestVararg", method: withAutorelease(testVararg)),
|
||||||
|
TestCase(name: "TestStringExtension", method: withAutorelease(testStrExtFun)),
|
||||||
|
TestCase(name: "TestAnyToString", method: withAutorelease(testAnyToString)),
|
||||||
|
TestCase(name: "TestAnyPrint", method: withAutorelease(testAnyPrint)),
|
||||||
|
TestCase(name: "TestLambda", method: withAutorelease(testLambda)),
|
||||||
|
TestCase(name: "TestInterfaceExtension", method: withAutorelease(testInterfaceExtension)),
|
||||||
|
TestCase(name: "TestClassInstances", method: withAutorelease(testClassInstances)),
|
||||||
|
TestCase(name: "TestEnum", method: withAutorelease(testEnum)),
|
||||||
|
TestCase(name: "TestDataClass", method: withAutorelease(testDataClass)),
|
||||||
|
TestCase(name: "TestCompanionObj", method: withAutorelease(testCompanionObj)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,9 @@ interface ExecutorService {
|
|||||||
fun execute(action: Action<in ExecSpec>): ExecResult?
|
fun execute(action: Action<in ExecSpec>): ExecResult?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ExecutorService depending on a test target -Ptest_target
|
||||||
|
*/
|
||||||
fun create(project: Project): ExecutorService {
|
fun create(project: Project): ExecutorService {
|
||||||
val platformManager = project.rootProject.findProperty("platformManager") as PlatformManager
|
val platformManager = project.rootProject.findProperty("platformManager") as PlatformManager
|
||||||
val testTarget = platformManager.targetManager(project.findProperty("testTarget") as String?).target
|
val testTarget = platformManager.targetManager(project.findProperty("testTarget") as String?).target
|
||||||
@@ -87,6 +90,39 @@ fun create(project: Project): ExecutorService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ProcessOutput(val stdOut: String, val stdErr: String, val exitCode: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs process using a given executor.
|
||||||
|
*
|
||||||
|
* @param executor a method that is able to run a given executable, e.g. ExecutorService::execute
|
||||||
|
* @param executable a process executable to be run
|
||||||
|
* @param args arguments for a process
|
||||||
|
*/
|
||||||
|
fun runProcess(executor: (Action<in ExecSpec>) -> ExecResult?,
|
||||||
|
executable: String, args: List<String>) : ProcessOutput {
|
||||||
|
val outStream = ByteArrayOutputStream()
|
||||||
|
val errStream = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
val execResult = executor(Action {
|
||||||
|
it.executable = executable
|
||||||
|
it.args = args.toList()
|
||||||
|
it.standardOutput = outStream
|
||||||
|
it.errorOutput = errStream
|
||||||
|
it.isIgnoreExitValue = true
|
||||||
|
})
|
||||||
|
|
||||||
|
checkNotNull(execResult)
|
||||||
|
|
||||||
|
val stdOut = outStream.toString("UTF-8")
|
||||||
|
val stdErr = errStream.toString("UTF-8")
|
||||||
|
|
||||||
|
return ProcessOutput(stdOut, stdErr, execResult!!.exitValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runProcess(executor: (Action<in ExecSpec>) -> ExecResult?,
|
||||||
|
executable: String, vararg args: String) = runProcess(executor, executable, args.toList())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a given action with iPhone Simulator.
|
* Executes a given action with iPhone Simulator.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package org.jetbrains.kotlin
|
||||||
|
|
||||||
|
import org.gradle.api.Action
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.gradle.api.tasks.SourceSet
|
||||||
|
import org.gradle.api.tasks.SourceSetContainer
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import org.gradle.process.ExecSpec
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.target.*
|
||||||
|
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test task for -produce framework testing. Requires a framework to be built by the Konan plugin
|
||||||
|
* with konanArtifacts { framework(frameworkName, targets: [ testTarget] ) } and a dependency set
|
||||||
|
* according to a pattern "compileKonan${frameworkName}".
|
||||||
|
*
|
||||||
|
* @property swiftSources Swift-language test sources that use a given framework
|
||||||
|
* @property frameworkName a framework name
|
||||||
|
*/
|
||||||
|
open class FrameworkTest : DefaultTask() {
|
||||||
|
@Input
|
||||||
|
lateinit var swiftSources: List<String>
|
||||||
|
|
||||||
|
@Input
|
||||||
|
lateinit var frameworkName: String
|
||||||
|
|
||||||
|
private val testOutput by lazy {
|
||||||
|
((project.findProperty("sourceSets") as SourceSetContainer)
|
||||||
|
.getByName("testOutputFramework") as SourceSet).output.dirs.singleFile.absolutePath
|
||||||
|
?: throw RuntimeException("Empty sourceSet")
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun run() {
|
||||||
|
val frameworkPath = "$testOutput/$frameworkName/${project.testTarget().name}"
|
||||||
|
|
||||||
|
// Sign framework
|
||||||
|
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor, executable = "/usr/bin/codesign",
|
||||||
|
args = listOf("--verbose", "-s", "-", Paths.get(frameworkPath, "$frameworkName.framework").toString()))
|
||||||
|
check(exitCode == 0, { """
|
||||||
|
|Codesign failed with exitCode: $exitCode
|
||||||
|
|stdout: $stdOut
|
||||||
|
|stderr: $stdErr
|
||||||
|
""".trimMargin()
|
||||||
|
})
|
||||||
|
|
||||||
|
// create a test provider and get main entry point
|
||||||
|
val provider = Paths.get(testOutput, frameworkName, "provider.swift")
|
||||||
|
FileWriter(provider.toFile()).use {
|
||||||
|
it.write("""
|
||||||
|
|// THIS IS AUTOGENERATED FILE
|
||||||
|
|// This method is invoked by the main routine to get a list of tests
|
||||||
|
|func registerProvider() {
|
||||||
|
| // TODO: assuming this naming for now
|
||||||
|
| ${frameworkName}Tests()
|
||||||
|
|}
|
||||||
|
""".trimMargin())
|
||||||
|
}
|
||||||
|
val testHome = project.file("framework").toPath()
|
||||||
|
val swiftMain = Paths.get(testHome.toString(), "main.swift").toString()
|
||||||
|
|
||||||
|
// Compile swift sources
|
||||||
|
val sources = swiftSources.map { Paths.get(it).toString() } +
|
||||||
|
listOf(provider.toString(), swiftMain)
|
||||||
|
val options = listOf("-g", "-Xlinker", "-rpath", "-Xlinker", frameworkPath, "-F", frameworkPath)
|
||||||
|
val testExecutable = Paths.get(testOutput, frameworkName, "swiftTestExecutable")
|
||||||
|
swiftc(sources, options, testExecutable)
|
||||||
|
|
||||||
|
runTest(testExecutable)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runTest(testExecutable: Path) {
|
||||||
|
val executor = (project.convention.plugins["executor"] as? ExecutorService)
|
||||||
|
?: throw RuntimeException("Executor wasn't found")
|
||||||
|
val (stdOut, stdErr, exitCode) = runProcess(executor = executor::execute,
|
||||||
|
executable = testExecutable.toString())
|
||||||
|
|
||||||
|
println("""
|
||||||
|
|stdout: $stdOut
|
||||||
|
|stderr: $stdErr
|
||||||
|
""".trimMargin())
|
||||||
|
check(exitCode == 0, { "Execution failed with exit code: $exitCode "})
|
||||||
|
}
|
||||||
|
|
||||||
|
private val localExecutor = { a: Action<in ExecSpec> -> project.exec(a) }
|
||||||
|
|
||||||
|
private fun Project.platformManager() = rootProject.findProperty("platformManager") as PlatformManager
|
||||||
|
|
||||||
|
private fun Project.testTarget() = platformManager()
|
||||||
|
.targetManager(project.findProperty("testTarget") as String?).target
|
||||||
|
|
||||||
|
private fun swiftc(sources: List<String>, options: List<String>, output: Path) {
|
||||||
|
val target = project.testTarget()
|
||||||
|
val platform = project.platformManager().platform(target)
|
||||||
|
assert(platform.configurables is AppleConfigurables)
|
||||||
|
val configs = platform.configurables as AppleConfigurables
|
||||||
|
val compiler = configs.absoluteTargetToolchain + "/usr/bin/swiftc"
|
||||||
|
|
||||||
|
val swiftTarget = when (target) {
|
||||||
|
KonanTarget.IOS_X64 -> "x86_64-apple-ios" + configs.osVersionMin
|
||||||
|
KonanTarget.IOS_ARM64 -> "arm64_64-apple-ios" + configs.osVersionMin
|
||||||
|
KonanTarget.MACOS_X64 -> "x86_64-apple-macosx" + configs.osVersionMin
|
||||||
|
else -> throw IllegalStateException("Test target $target is not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
|
||||||
|
options + "-o" + output.toString() + sources
|
||||||
|
|
||||||
|
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor, executable = compiler, args = args)
|
||||||
|
|
||||||
|
println("""
|
||||||
|
|$compiler finished with exit code: $exitCode
|
||||||
|
|options: ${args.joinToString(separator = " ")}
|
||||||
|
|stdout: $stdOut
|
||||||
|
|stderr: $stdErr
|
||||||
|
""".trimMargin())
|
||||||
|
check(exitCode == 0, { "Compilation failed" })
|
||||||
|
check(output.toFile().exists(), { "Compiler swiftc hasn't produced an output file: $output" })
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user