This repo is a Kotlin Native playground.
I've followed the official guide to setup the iOS and the Android modules
These are the things that I wanna explore:
- Enums
- Enums with arguments
- Sealed classes
- Objects
- Nullability
- Companion objects
- Generics
- Higher-Order Functions and Lambdas
- DSL
- Inheritance
- Unit tests in the common module
- Import pure kotlin library in the common module
-  Distribution as library
- maven for the (android + common) as android library
- cocoapods for the (iOS + common) as framework
 
Table of contents
Enum definition
enum class SimpleEnum{
    FIRST, SECOND, THIRD
}Into the android module I'm able to do all the common stuff that we are used to do with enums (access to the cases, iterate and count). So we can write a test that looks like
@Test
fun usageOfSimpleEnum() {
    assertEquals(3, SimpleEnum.values().size)
    SimpleEnum.values().forEach {
        println(it)
    }
}Into the ios module I can access to the enum cases, but I don't know how iterate or get the enum size. So we can write a test that looks like
func testUsageOfSimpleEnum() {
    print(KotlinLibrarySimpleEnum.first)
    print(KotlinLibrarySimpleEnum.second)
    print(KotlinLibrarySimpleEnum.third)
}Enum definition
enum class EnumWithValue(val associatedValue: Int) {
    ONE(1),
    TWO(2)
}As in the previous section, even with the enums with argument, we can do everything we expect with an enum. So the test can be:
@Test
fun usageOfEnumWithValue() {
    assertEquals(2, EnumWithValue.values().size)
    EnumWithValue.values().forEach {
        println("$it : ${it.associatedValue}")
    }
}As above, the same "issues" with the enum are still present even with the enums with values. At least we can access the value of the variable:
func testUsageOfEnumWithValue() {
    XCTAssert(KotlinLibraryEnumWithValue.one.associatedValue == 1)
    XCTAssert(KotlinLibraryEnumWithValue.two.associatedValue == 2)
}sealed class definition
sealed class SealedClassExample {
    class Success(val successMessage: String) : SealedClassExample()
    object Error : SealedClassExample()
}As usual into the android module we can do everything we expect with a sealed class. So the test can be:
@Test
fun usageOfSealedClass() {
    val successMessage = "We are the champions"
    val success: SealedClassExample = SealedClassExample.Success(successMessage)
    assertSuccess(success, successMessage)
    val error: SealedClassExample = SealedClassExample.Error
    assertError(error)
    when (success) {
        is SealedClassExample.Success -> println("SealedClassExample.Success instance")
        is SealedClassExample.Error -> println("SealedClassExample.Error instance")
    }
}
private fun assertSuccess(sealed: SealedClassExample, expectedMessage: String) {
    assertTrue(sealed is SealedClassExample.Success)
    assertTrue((sealed as SealedClassExample.Success).successMessage == expectedMessage)
}
private fun assertError(sealed: SealedClassExample) {
    assertTrue(sealed === SealedClassExample.Error)
}As far as I know swift and objective-c have no concept of sealed classes. Therefore I do not think it is possible to have something similar to the when of kotlin.
The tests we can have are like:
func testSealedClassUsage() {
    let successMessage = "I'm the winner"
    assertSuccessInstance(selead : KotlinLibrarySealedClassExampleSuccess(successMessage: successMessage), expectedMessage : successMessage)
    assertErrorInstance(selead : KotlinLibrarySealedClassExampleError())
}
private func assertSuccessInstance(selead : KotlinLibrarySealedClassExample, expectedMessage: String){
    XCTAssert(selead is KotlinLibrarySealedClassExampleSuccess,"Failed: sealed is \(String(describing: selead.self))")
    let success = selead as! KotlinLibrarySealedClassExampleSuccess
    XCTAssert(success.successMessage == expectedMessage,"Failed: message is '\(String(describing: success.successMessage))' the expected is '\(String(describing: expectedMessage))' ")
}
private func assertErrorInstance(selead : KotlinLibrarySealedClassExample){
    XCTAssert(selead is KotlinLibrarySealedClassExampleError)
}Object definition
object KotlinObject {
    val INITIAL_VALUE_FOR_NULLABLE_STRING_PROPERTY = null
    const val INITIAL_VALUE_FOR_INT_PROPERTY = 0
    const val INITIAL_VALUE_FOR_NULLABLE_ANY_PROPERTY = "any variable initial state"
    var internalStateNullableString: String? = INITIAL_VALUE_FOR_NULLABLE_STRING_PROPERTY
    var internalStateInt: Int = INITIAL_VALUE_FOR_INT_PROPERTY
    var internalStateNullableAny: Any? = INITIAL_VALUE_FOR_NULLABLE_ANY_PROPERTY
}As usual, no surprises
@Test
fun usageOfKotlinObject() {
    assertTrue(KotlinObject === KotlinObject)
}Well, even here in the ios module the kotlin object is a singleton π
KotlinLibraryKotlinObject() give us always the same instance
func testKotlinObjectUsage() {
    XCTAssert(KotlinLibraryKotlinObject() === KotlinLibraryKotlinObject())
}Reusing the object defined in the section above
Once again, no surprises
@Test
fun usageOfKotlinObject_properties() {
    playWithIntProperty()
    playWithNullableAnyProperty()
    playWithNullableStringProperty()
}
private fun playWithIntProperty() {
    assertTrue(KotlinObject.internalStateInt == KotlinObject.INITIAL_VALUE_FOR_INT_PROPERTY)
    KotlinObject.internalStateInt = 123
    assertTrue(KotlinObject.internalStateInt == 123)
}
private fun playWithNullableAnyProperty() {
    assertTrue(KotlinObject.internalStateNullableAny == KotlinObject.INITIAL_VALUE_FOR_NULLABLE_ANY_PROPERTY)
    KotlinObject.internalStateNullableAny = 123
    assertTrue(KotlinObject.internalStateInt == 123)
    KotlinObject.internalStateNullableAny = "Now I'm a string"
    assertTrue(KotlinObject.internalStateNullableAny == "Now I'm a string")
}
private fun playWithNullableStringProperty() {
    assertTrue(KotlinObject.internalStateNullableString == KotlinObject.INITIAL_VALUE_FOR_NULLABLE_STRING_PROPERTY)
    KotlinObject.internalStateNullableString = "Now I'm not null"
    assertTrue(KotlinObject.internalStateNullableString == "Now I'm not null")
}There's something weird happening
func testKotlinObjectUsage_properties() {
    playWithIntProperty()
    playWithNullableAnyProperty()
    playWithNullableStringProperty()
}
private func playWithIntProperty(){
    XCTAssert(KotlinLibraryKotlinObject().internalStateInt == KotlinLibraryKotlinObject().initial_VALUE_FOR_INT_PROPERTY) // #1
    KotlinLibraryKotlinObject().internalStateInt = 123
    XCTAssert(KotlinLibraryKotlinObject().internalStateInt == 123)
}
private func playWithNullableAnyProperty(){
    XCTAssert((KotlinLibraryKotlinObject().internalStateNullableAny as! String) == KotlinLibraryKotlinObject().initial_VALUE_FOR_NULLABLE_ANY_PROPERTY) 
    KotlinLibraryKotlinObject().internalStateNullableAny = 123
    XCTAssert((KotlinLibraryKotlinObject().internalStateNullableAny as! Int) == 123) 
    KotlinLibraryKotlinObject().internalStateNullableAny = "Now I'm a string"
    XCTAssert((KotlinLibraryKotlinObject().internalStateNullableAny as! String) == "Now I'm a string")
}
private func playWithNullableStringProperty(){
    XCTAssert(KotlinLibraryKotlinObject().internalStateNullableString == (KotlinLibraryKotlinObject().initial_VALUE_FOR_NULLABLE_STRING_PROPERTY as! String?)) #2
    KotlinLibraryKotlinObject().internalStateNullableString = "Now I'm not null"
    XCTAssert(KotlinLibraryKotlinObject().internalStateNullableString! == "Now I'm not null")
}- the kotlin val defined as const val INITIAL_VALUE_FOR_INT_PROPERTY = 0is mapped ininitial_VALUE_FOR_INT_PROPERTYwith "initial" lowercase
- the kotlin val defined as val INITIAL_VALUE_FOR_NULLABLE_STRING_PROPERTY = nullhasNothing?as type (doc as reference π¬). Xcode tell us that the kotlin val was mapped into avar initial_VALUE_FOR_NULLABLE_STRING_PROPERTY: KotlinLibraryStdlibNothing?so, a cast toString?seems to be inevitable
Companion object definition
class Container(val state: String) {
    fun getDecoratedState(): String {
        return "${sharedVar ?: ""} $state"
    }
    companion object {
        const val MY_SUPER_NICE_CONST = 12
        var sharedVar: String? = null
    }
}As usual, no surprises
@Test
fun usageOfCompanionObject() {
    assertEquals(12, Container.MY_SUPER_NICE_CONST)
    val firstContainer = Container("first")
    val secondContainer = Container("second")
    assertFalse(firstContainer === secondContainer)
    Container.sharedVar = "Hello"
    assertEquals("Hello first", firstContainer.getDecoratedState())
    assertEquals("Hello second", secondContainer.getDecoratedState())
}As we could see into the objects section, even the swift usage of a companion object is straightforward
func testCompanionObjectUsage() {
    XCTAssertEqual(12, KotlinLibraryContainerCompanion().my_SUPER_NICE_CONST)
    let firstContainer = KotlinLibraryContainer(state: "first")
    let secondContainer = KotlinLibraryContainer(state: "second")
    
    XCTAssertFalse(firstContainer === secondContainer)
    
    KotlinLibraryContainerCompanion().sharedVar = "Hello"
    
    XCTAssert(firstContainer.getDecoratedState() == "Hello first")
    XCTAssert(secondContainer.getDecoratedState() == "Hello second")
}fun topLevelFunction(): String {
    return "I am a top level"
}
fun Int.extensionFuction(): Int {
    return this * 2
}
fun higherOrderFunctionWithParameter(a: Int, b: Int, f: (Int, Int) -> Int): Int {
    return f(a, b)
}
fun higherOrderFunctionWithReturn(functionType: FunctionType): (Int, Int) -> Int {
    return when (functionType) {
        FunctionType.SUM -> { a, b -> a + b }
        FunctionType.MULTIPLY -> { a, b -> a * b }
    }
}
fun higherOrderFunctionBoth(a: Double, b: Double, f: (Double, Double) -> Double): Double {
    return f(a, b)
}
fun lambdaWithReceiver(arg: Int, func: Int.() -> Int): Int {
    return func(arg)
}
enum class FunctionType {
    SUM, MULTIPLY
}As usual, no surprises. It is still useful to report the tests for those who do not usually develop in kotlin.
@Test
fun topLevelFunctionUsage() {
    assertEquals("I am a top level", topLevelFunction())
}
@Test
fun extensionFunctionUsage() {
    assertEquals(4, 2.extensionFuction())
}
@Test
fun higherOrderFunctionWithParameterUsage() {
    assertEquals(5, higherOrderFunctionWithParameter(2, 3) { a, b -> a + b })
}
@Test
fun higherOrderFunctionWithReturnUsage() {
    assertEquals(5, higherOrderFunctionWithReturn(FunctionType.SUM)(2, 3))
    val higherOrderFunctionWithReturn = higherOrderFunctionWithReturn(FunctionType.MULTIPLY)
    assertEquals(6, higherOrderFunctionWithReturn(2, 3))
}
@Test
fun higherOrderFunctionBothUsage() {
    assertEquals(25, higherOrderFunctionBoth(2.0, 3.0) { a, b -> (a + b).pow(2) }.toInt())
}Kotlin top level functions are accessible directly from KotlinLibrary.
Also the extension functions are accessible via KotlinLibrary. As we could expect, since kotlin generates objective-c code, extensions can not be invoked directly on the type that extend.
The higher order functions seem to be mapped as function pointers, for this reason the parameters defined as double in kotlin are now NSNumber
func testTopLevelFunctionUsage() {
    XCTAssert("I am a top level" == KotlinLibrary.topLevelFunction())
}
func testExtensionFunctionUsage() {
    XCTAssert(4 == KotlinLibrary.extensionFuction(2))
}
func testHigherOrderFunctionWithParameterUsage() {
    XCTAssert(5 == KotlinLibrary.higherOrderFunctionBoth(a: 2, b: 3, f: {
        NSNumber(value: ($0.doubleValue + $1.doubleValue))
    }))
}
func testHigherOrderFunctionWithReturnUsage() {
    XCTAssert(5 == KotlinLibrary.higherOrderFunctionWithReturn(functionType: KotlinLibraryFunctionType.sum)(2, 3))
    let higherOrderFunctionWithReturn = KotlinLibrary.higherOrderFunctionWithReturn(functionType: KotlinLibraryFunctionType.multiply)
    XCTAssert(6 == higherOrderFunctionWithReturn(2, 3))
}
func testHigherOrderFunctionBothUsage() {
    XCTAssert(25 == KotlinLibrary.higherOrderFunctionBoth(a: 2, b: 3, f: {
        NSNumber(value: pow(($0.doubleValue + $1.doubleValue),2))
    }))
}By using well-named functions as builders in combination with function literals with receiver it is possible to create type-safe, statically-typed builders in >Kotlin.
Type-safe builders allow for creating Kotlin-based domain-specific languages (DSLs) suitable for building complex hierarchical data structures in a semi-declarative way. Some of the example use cases for the builders are:
- Generating markup with Kotlin code, such as HTML or XML;
- Programmatically laying out UI components: Anko
- Configuring routes for a web server: Ktor.
-- from official documentation
Here everything we need for define a micro DSL:
data class Port(var value: Int = 0, var isSecure: Boolean = false) {
    operator fun invoke(init: Port.() -> Unit) {
        init()
    }
}
data class Configuration(var host: String = "", var port: Port = Port())
fun configuration(init: Configuration.() -> Unit): Configuration {
    val configuration = Configuration()
    configuration.init()
    return configuration
}- Two data class: PortandConfiguration
- An operator overload: operator fun invoke(init: Port.() -> Unit)
- A lambda with receiver fun configuration(init: Configuration.() -> Unit): Configuration
With the code above we can write a test like:
@Test
fun dslUsage() {
    val conf = configuration {
        host = "127.0.0.1"
        port {
            value = 8080
            isSecure = false
        }
    }
    
    assertEquals("127.0.0.1", conf.host)
    assertEquals(8080, conf.port.value)
    assertEquals(false, conf.port.isSecure)
}In swift we can achieve a similar result. In my opinion, compared to the kotlin version, we lose a bit of readability but the result is still acceptable.
func testDslUsage() {
    let conf = KotlinLibrary.configuration(init: {
        $0.host = "127.0.0.1"
        $0.port.invoke(init: {
            $0.value = 8080
            $0.isSecure = false
            return KotlinLibraryStdlibUnit()
        })
        return KotlinLibraryStdlibUnit()
    })
    
    XCTAssert(conf.host == "127.0.0.1")
    XCTAssert(conf.port.value == 8080)
    XCTAssert(conf.port.isSecure == false)
}Common code:
data class Box<T>(var elemet: T)
data class AnimalBox<T : Animal>(var elemet: T)
val mapIntegersToStrings: MutableMap<Int, String> = mutableMapOf()
interface Animal {
    fun speak(): String
}
class Dog : Animal {
    override fun speak() = "woof"
}
class Cat : Animal {
    override fun speak() = "meow"
}Box is a generic container, AnimalBox is a container that allows only subclasses of Animal as element.
mapIntegersToStrings is a top level property, map with int key and string values
Nothing to explain, all straightforward
@Test
fun genericsBasicUsage() {
    val intBox = Box(8)
    val stringBox = Box("Hi")
    assertEquals(8, intBox.elemet)
    assertEquals("Hi", stringBox.elemet)
    // intBox.elemet = "World" <--- compilation error
}
@Test
fun genericsUsage() {
    val animalBox: AnimalBox<Animal> = AnimalBox(Do())
    assertEquals("woof", animalBox.elemet.speak())
    animalBox.elemet = Cat()
    assertEquals("meow", animalBox.elemet.speak())
    // animalBox.elemet = 2 <--- compilation error
}
@Test
fun genericsMapUsage() {
    mapIntegersToStrings[1] = "one"
    mapIntegersToStrings[2] = "two"
    // mapIntegersToStrings[3] = 3 <--- compilation error
    // mapIntegersToStrings["three"] = "three" <---compilation error
}Apple introduces Generics in Objective-C since 2015. The main goal is to enable Swift Generics to convert to Objective-C syntax without extra overhead (as it is called as βlightweight genericsβ).
-- from Generics in Objective-C
func testGenericsBasicUsage() { //1
   let intBox = KotlinLibraryBox(elemet: 8)
   let stringBox = KotlinLibraryBox(elemet: "Hi")
        
    XCTAssert(intBox.elemet as! Int == 8)
    XCTAssert(stringBox.elemet as! String == "Hi")
        
    intBox.elemet = "World" //<--- NO compilation error!!
    XCTAssert(intBox.elemet as! String == "World")
}
    
func testGenericsUsage() {
    let animalBox = KotlinLibraryAnimalBox(elemet: KotlinLibraryDog())
    XCTAssert(animalBox.elemet.speak() == "woof")
    animalBox.elemet = KotlinLibraryCat()
    XCTAssert(animalBox.elemet.speak() == "meow")
 
    //animalBox.elemet = 2 // <--- compilation error
}
    
func testGenericsMapUsage() {
    KotlinLibrary.mapIntegersToStrings[0] = "zero"
    KotlinLibrary.mapIntegersToStrings[1] = "one"
    KotlinLibrary.mapIntegersToStrings[2] = 2
    KotlinLibrary.mapIntegersToStrings["three"] = "three"
        
    XCTAssert("zero" == KotlinLibrary.mapIntegersToStrings[0] as! String)
    XCTAssert("one" == KotlinLibrary.mapIntegersToStrings[1] as! String)
    XCTAssert(2 == KotlinLibrary.mapIntegersToStrings[2] as! Int)
    XCTAssert("three" == KotlinLibrary.mapIntegersToStrings["three"] as! String)
}testGenericsBasicUsage π
Into testGenericsBasicUsage we can see that Box<T> element is mapped as a nullable pointer to any type @property id _Nullable elemet;. For this reason we can do intBox.elemet = "World" without compilation errors.
testGenericsUsage π
Here, the AnimalBox<T : Animal> element is mapped as @property id<KotlinLibraryAnimal> elemet. So, finally, operations like animalBox.elemet = 2  are forbidden.
testGenericsMapUsage π€
mapIntegersToStrings in kotlin is a MutableMap<Int, String> and the objective-c generate code is @property (class, readonly) KotlinLibraryMutableDictionary<NSNumber *, NSString *> *mapIntegersToStrings. Reading <NSNumber *, NSString *>  I personally thought that it was not possible to do neither  KotlinLibrary.mapIntegersToStrings[2] = 2 nor mapIntegersToStrings["three"] = "three". Instead, no compilation errors and no failing tests.
class CannotInheritFromMe(val parentValue: Int)
open class YouCanInheritFromMe(val parentValue: Int)
abstract class AbstractClass(val abstractClassValue: Int) {
    abstract fun transformValue(): String
    fun concreteFunction(): Int{
        return transformValue().length
    }
}
interface Shape {
    var interfaceVariable: String
    val interfaceValue: Int
    fun area(): Float
    fun perim(): Float
}
class Square(val side: Float) : Shape {
    override var interfaceVariable: String = "Hi I'm a square with side = $side"
    override val interfaceValue: Int = 123
    override fun area() = side.pow(2)
    override fun perim() = 4 * side
}
Here we have:
- class CannotInheritFromMethat, as design, is final
- open class YouCanInheritFromMethat, with the open annotation, allows others to inherit from it
- abstract class AbstractClasswith a default constructor, an abstract function- transformValue(): Stringand a concrete function- concreteFunction(): Int
- interface Shape
- Squarethat implements- Shape
Once, again, no surprises:
@Test
fun inheritanceForFinalClass() {
    // class Attempt(val parentValue: Int) : CannotInheritFromMe(parentValue) <--- compilation error
}
@Test
fun inheritanceForOpenClass() {
    class Attempt(val childValue: String, parentValue: Int) : YouCanInheritFromMe(parentValue)
    val attempt = Attempt(childValue = "value for Child", parentValue = 1)
    assertEquals("value for Child", attempt.childValue)
    assertEquals(1, attempt.parentValue)
}
@Test
fun inheritanceForAbstractClass() {
    class Attempt(val childValue: String, parentValue: Int) : AbstractClass(parentValue) {
        override fun transformValue(): String {
            return "$childValue : $abstractClassValue"
        }
    }
    val attempt = Attempt(childValue = "value for Child", parentValue = 1)
    assertEquals("value for Child", attempt.childValue)
    assertEquals(1, attempt.abstractClassValue)
    assertEquals("value for Child : 1", attempt.transformValue())
    assertEquals(19, attempt.concreteFunction())
}
@Test
fun inheritanceForInterface() {
    class Rect(val width: Float, val height: Float) : Shape {
        override var interfaceVariable = "Hi I'm a rect with width = $width and height = $height"
        override val interfaceValue: Int = 456
        override fun area() = width * height
        override fun perim() = 2 * (width + height)
    }
    val rect = Rect(2f, 3f)
    val square = Square(2f)
    assertTrue(rect is Shape)
    assertTrue(square is Shape)
    assertEquals(10f, rect.perim())
    assertEquals(6f, rect.area())
    assertEquals("Hi I'm a rect with width = 2.0 and height = 3.0", rect.interfaceVariable)
    assertEquals(456, rect.interfaceValue)
    assertEquals(2f, square.side)
    assertEquals(8f, square.perim())
    assertEquals(4f, square.area())
    assertEquals("Hi I'm a square with side = 2.0", square.interfaceVariable)
    assertEquals(123, square.interfaceValue)
}
inheritanceForFinalClass
Inheritance from a final class is forbidden
inheritanceForOpenClass
Inheritance from an open class is allowed. Attempt has a constructor with a val childValue: String and a parentValue: Int; parentValue is used to feed the constructor of YouCanInheritFromMe
inheritanceForAbstractClass
Inheritance from an abstract class is allow. Attempt has a constructor with a val childValue: String and a parentValue: Int; parentValue is used to feed the constructor of AbstractClass. In addition to this, Attempt has also the concrete implementation of transformValue(): String, the abstract method of AbstractClass.
inheritanceForInterface
In the common module we have defined Shape as interface, and Square as class that implements Shape.
Into the test case we have Rect, an other class that implements Shape.
Once, again, weird things π
Swift:
func testInheritanceForFinalClass(){
        
    class Attempt: KotlinLibraryCannotInheritFromMe { //<--- NO compilation error!!
            
        override init(parentValue: Int32) {
            super.init(parentValue: parentValue)
        }
    }
        
    let attempt = Attempt(parentValue: 24)
    XCTAssert(attempt.parentValue == 24)
}
    
func testInheritanceForOpenClass(){
        
    class Attempt: KotlinLibraryYouCanInheritFromMe {
            
        override init(parentValue: Int32) {
            super.init(parentValue: parentValue)
        }
    }
        
    let attempt = Attempt(parentValue: 24)
    XCTAssert(attempt.parentValue == 24)
}
    
    
func testInheritanceForAbstractClass(){
        
    class Attempt: KotlinLibraryAbstractClass {
        var value : String
            
        init(childValue: String, abstractClassValue: Int32) {
            value = childValue
            super.init(abstractClassValue: abstractClassValue)
        }
            
        override func transformValue() -> String {
            return "\(value) : \(abstractClassValue)"
        }
            
    }
        
    let attempt = Attempt(childValue: "value for Child", abstractClassValue: 1)
    XCTAssert(attempt.abstractClassValue == 1)
    XCTAssert(attempt.value == "value for Child")
    XCTAssert("value for Child : 1" == attempt.transformValue())
    XCTAssert(19 == attempt.concreteFunction())
}
func testInheritanceForInterface(){
        
    class Rect : KotlinLibraryShape {
        let width, height: Float
            
        init(width: Float, height: Float) {
            self.width = width
            self.height = height
        }
            
        var interfaceValue: Int32{
            get {
                return 456
            }
        }
            
        lazy var interfaceVariable = "Hi I'm a rect with width = \(width) and height = \(height)"
            
        func area() -> Float {
            return width * height
        }
            
        func perim() -> Float {
            return 2 * (width + height)
        }
            
    }
        
    let rect = Rect(width: 2.0, height: 3.0)
    let square = KotlinLibrarySquare(side:2.0)
        
    XCTAssert(rect is KotlinLibraryShape)
    XCTAssert(square is KotlinLibraryShape)
        
    XCTAssert(10.0 == rect.perim())
    XCTAssert(6.0 == rect.area())
    XCTAssert("Hi I'm a rect with width = 2.0 and height = 3.0" == rect.interfaceVariable)
    XCTAssert(456 == rect.interfaceValue, "Failed: rect.interfaceVariable is \(String(describing: rect.interfaceValue))")
        
    XCTAssert(2.0 == square.side)
    XCTAssert(8.0 == square.perim())
    XCTAssert(4.0 == square.area())
    XCTAssert("Hi I'm a square with side = 2.0" == square.interfaceVariable)
    XCTAssert(123 == square.interfaceValue)
}Objective-C:
@import KotlinLibrary;
@interface Attempt: KotlinLibraryCannotInheritFromMe // <--- compilation error : Cannot subclass a class that was declared with the 'objc_subclassing_restricted' attribute 
@end
 
@implementation Attempt
@endtestInheritanceForFinalClass π±
From an objective-c file, inherit from a kotlin final class is forbidden π
From a swift file, instead, the inheritation from a kotlin final class is allowed π¦
If we jump into the definition of KotlinLibraryCannotInheritFromMe we can see
From KotlinLibrary.h:
__attribute__((objc_subclassing_restricted))
@interface KotlinLibraryCannotInheritFromMe : KotlinBase
-(instancetype)initWithParentValue:(int32_t)parentValue NS_SWIFT_NAME(init(parentValue:)) NS_DESIGNATED_INITIALIZER;From the KotlinLibrary import:
open class KotlinLibraryCannotInheritFromMe : KotlinBase {
    public init(parentValue: Int32)
    
    open var parentValue: Int32 { get }
}Seeing the definitions, it is clear the reason of the two different behaviours. Googling it seems that:
Make an Objective-C class final in Swift
It seems this is impossible right now. Objective-C doesn't support final classes so Swift supposes that every Obj-C class is not final.
-- from stackoverflow
Add
objc_subclassing_restrictedattributeThis patch adds an
objc_subclassing_restrictedattribute into clang. This attribute acts similarly to 'final' - Objective-C classes with this attribute can't be subclassed. However,@interfacedeclarations that haveobjc_subclassing_restrictedbut don't have@implementationare allowed to inherit other@interfacedeclarations withobjc_subclassing_restricted. This is needed to describe the Swift class hierarchy in clang while making sure that the Objective-C classes can't subclass the Swift classes.-- from reviews.llvm.org
testInheritanceForOpenClass
If even the inheritance from a final class is conceded, the inheritance from an open class can only be allowed π
testInheritanceForAbstractClass
Ehm, objective-c has no compile-time enforcement that prevents instantiation of an abstract class, so, yes we can inherit from an abstract class, not override any of the abstract methods and have no compiling errors π
In our case the abstract fun transformValue() is used into the concrete function so we have wonderful SIGABRT ERROR at runtime π π
testInheritanceForInterface
Finally a straightforward case! ππ
To support common modules unit testing, Kotlin team made kotlin.test library. To use it, we need to add the following dependencies into our common module build.gradle file
testCompile "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version" 
testCompile "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"Once added the dependencies we can write test in the common module:
class TestExample {
    @Test
    fun `square should respect the perim and area formulas`() {
        val square = Square(2f)
        assertEquals(2f, square.side)
        assertEquals(8f, square.perim())
        assertEquals(4f, square.area())
        assertEquals("Hi I'm a square with side = 2.0", square.interfaceVariable)
        assertEquals(123, square.interfaceValue)
    }
    @Test
    fun `Greeting()_greeting() should start with 'Hello, '`() {
        assertTrue {
            Greeting().greeting().startsWith("Hello, ")
        }
    }
}To run the tests we have to run them on platform modules
In order to run test in the JVM module we need the following dependencies into the build.gradle of the android module
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"Now we can run tests on JVM using
./gradlew :kotlinLibrary:android:testAn HTML report is generated in android/build/reports/tests/test/index.html
We have already done the setup to run the test in the iOS environment writing into the build.gradle of the iOS module
konanArtifacts {
    
    //... STUFF ...
    program('NativeTest') {
        srcDir 'src/test/kotlin'
        commonSourceSet 'test'
        libraries {
            artifact 'NativeLib'
        }
        extraOpts '-tr'
    }
}
task test(dependsOn: 'compileKonanNativeTestIos_x64', type: Exec) {
    def textExecutable = tasks["compileKonanNativeTestIos_x64"].artifactPath
    commandLine("xcrun", "simctl", "spawn", "iPhone 8", textExecutable)
}so, similarly to Android we can run tests on iOS using
./gradlew :kotlinLibrary:ios:testAnd the output is
> Task :kotlinLibrary:ios:test
[==========] Running 2 tests from 1 test cases.
[----------] Global test environment set-up.
[----------] 2 tests from com.ndefiorenze.TestExample
[ RUN      ] com.ndefiorenze.TestExample.square should respect the perim and area formulas
[       OK ] com.ndefiorenze.TestExample.square should respect the perim and area formulas (2 ms)
[ RUN      ] com.ndefiorenze.TestExample.Greeting()_greeting() should start with 'Hello, '
[       OK ] com.ndefiorenze.TestExample.Greeting()_greeting() should start with 'Hello, ' (0 ms)
[----------] 2 tests from com.ndefiorenze.TestExample (3 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test cases ran. (3 ms total)
[  PASSED  ] 2 tests.