Produce framework tests

This commit is contained in:
Pavel Punegov
2018-04-16 19:22:49 +03:00
committed by GitHub
parent 09c9a60b30
commit afe9f04487
8 changed files with 1292 additions and 1 deletions
+44 -1
View File
@@ -75,7 +75,7 @@ allprojects {
sourceSets {
// backend.native/tests
testOutputLocal {
output.dir(rootProject.file("$testOutputRoot/local"))
output.dir(rootProject.file("$testOutputRoot/local"))
}
// backend.native/tests/external
@@ -87,6 +87,11 @@ allprojects {
testOutputStdlib {
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 {
def tasks = tasksOf { it instanceof KonanTest && it.inDevelopersRun }
dependsOn(tasks)
// Add framework tests
dependsOn(project.tasks.withType(FrameworkTest))
}
// Collect results in one json.
@@ -2645,6 +2653,41 @@ task produce_dynamic(type: DynamicKonanTest) {
"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) {
outputSourceSetName = "testOutputStdlib"
compileList = [ "stdlib_external", "testUtils.kt" ]
+155
View File
@@ -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?
}
/**
* Creates an ExecutorService depending on a test target -Ptest_target
*/
fun create(project: Project): ExecutorService {
val platformManager = project.rootProject.findProperty("platformManager") as PlatformManager
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.
*
@@ -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" })
}
}