Added Kotlin/Native target

This commit is contained in:
dankito 2022-02-13 00:19:00 +01:00
parent 56f951314a
commit 2563051082
14 changed files with 171 additions and 59 deletions

View File

@ -4,6 +4,17 @@ plugins {
}
allprojects {
configurations.all {
resolutionStrategy {
// otherwise Kotlin throws an exception even though it is on the classpath:
// "Ktor native HttpClient requires kotlinx.coroutines version with `native-mt` suffix (like `1.3.9-native-mt`)"
force("org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}-native-mt")
}
}
}
kotlin {
jvm {
compilations.all {
@ -31,13 +42,13 @@ kotlin {
}
}
// def hostOs = System.getProperty("os.name")
// def isMingwX64 = hostOs.startsWith("Windows")
// def nativeTarget
// if (hostOs == "Mac OS X") nativeTarget = macosX64('native') { binaries.executable() }
// else if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries.executable() }
// else if (isMingwX64) nativeTarget = mingwX64("native") { binaries.executable() }
// else throw new GradleException("Host OS is not supported in Kotlin/Native.")
def hostOs = System.getProperty("os.name")
def isMingwX64 = hostOs.startsWith("Windows")
def nativeTarget
if (hostOs == "Mac OS X") nativeTarget = macosX64('native')
else if (hostOs == "Linux") nativeTarget = linuxX64("native")
else if (isMingwX64) nativeTarget = mingwX64("native")
else throw new GradleException("Host OS is not supported in Kotlin/Native.")
sourceSets {
@ -120,7 +131,7 @@ private val jsJodaTz = JsJodaTimeZoneModule
nativeMain {
dependencies {
// ktor Native needs "-native-mt" coroutines version. Export it so that referencing applications don't need to import it on their own
api"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion-native-mt"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}-native-mt"
// requires cURL to be installed on your system
implementation "io.ktor:ktor-client-curl:$ktorVersion"

View File

@ -53,8 +53,8 @@ open class JobContext(
open fun startNewDialog(closeDialog: Boolean = true, dialogId: String = DialogContext.InitialDialogId,
versionOfSecurityProcedure: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.Version_2,
chunkedResponseHandler: ((BankResponse) -> Unit)? = dialog.chunkedResponseHandler) : DialogContext {
versionOfSecurityProcedure: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.Version_2,
chunkedResponseHandler: ((BankResponse) -> Unit)? = dialog.chunkedResponseHandler) : DialogContext {
val newDialogContext = DialogContext(closeDialog, dialogId, chunkedResponseHandler)

View File

@ -37,13 +37,13 @@ abstract class FinTsTestBase {
const val ControlReference = "4477"
val Bank = BankData(BankCode, CustomerId, Pin, BankFinTsServerAddress, Bic, "", BankCountryCode, selectedTanMethod = TanMethod("chipTAN-optisch", SecurityFunction, TanMethodType.ChipTanFlickercode), selectedLanguage = Language)
val Bank = createTestBank()
val Currency = "EUR"
val AccountHolderName = "Martina Musterfrau"
val Account = AccountData(CustomerId, null, BankCountryCode, BankCode, Iban, CustomerId, AccountType.Girokonto, Currency, AccountHolderName, null, null, listOf(), listOf())
val Account = createTestAccount()
const val ProductName = "FinTS-TestClient25Stellen"
@ -59,11 +59,20 @@ abstract class FinTsTestBase {
init {
Bank.changeTanMediumParameters = ChangeTanMediaParameters(JobParameters("", 1, 1, 1, ":0:0"), false, false, false, false, false, listOf())
}
fun createTestBank(): BankData {
return BankData(BankCode, CustomerId, Pin, BankFinTsServerAddress, Bic, "", BankCountryCode, selectedTanMethod = TanMethod("chipTAN-optisch", SecurityFunction, TanMethodType.ChipTanFlickercode), selectedLanguage = Language)
}
fun createTestAccount(): AccountData {
return AccountData(CustomerId, null, BankCountryCode, BankCode, Iban, CustomerId, AccountType.Girokonto, Currency, AccountHolderName, null, null, listOf(), listOf())
}
}
protected open fun createContext(dialogId: String = DialogContext.InitialDialogId): JobContext {
val context = JobContext(JobContextType.AnonymousBankInfo, SimpleFinTsClientCallback(), Product, Bank)
protected open fun createContext(bank: BankData = Bank, dialogId: String = DialogContext.InitialDialogId): JobContext {
val context = JobContext(JobContextType.AnonymousBankInfo, SimpleFinTsClientCallback(), Product, bank)
context.startNewDialog(dialogId = dialogId)
return context

View File

@ -67,7 +67,6 @@ inline fun <reified T : Throwable> assertThrows(action: () -> Unit) {
action()
fail("action() didn't throw any exception. Expected was ${T::class.qualifiedName}")
} catch (throwable: Throwable) {
println("Throwable is of type ${throwable::class.simpleName}: $throwable")
assertTrue(throwable is T)
}
}

View File

@ -34,9 +34,12 @@ class MessageBuilderTest : FinTsTestBase() {
}
// we need to create our own copy as otherwise Kotlin/Native throws an InvalidMutabilityException
private val bank = createTestBank()
@AfterTest
fun tearDown() {
Bank.supportedJobs = listOf()
bank.supportedJobs = listOf()
}
@ -44,7 +47,7 @@ class MessageBuilderTest : FinTsTestBase() {
fun createAnonymousDialogInitMessage() {
// given
val context = createContext()
val context = createContext(bank)
// when
val result = underTest.createAnonymousDialogInitMessage(context).createdMessage
@ -63,7 +66,7 @@ class MessageBuilderTest : FinTsTestBase() {
// given
val dialogId = createDialogId()
val context = createContext(dialogId)
val context = createContext(bank, dialogId)
// when
val result = underTest.createAnonymousDialogEndMessage(context).createdMessage ?: ""
@ -81,7 +84,7 @@ class MessageBuilderTest : FinTsTestBase() {
fun createDialogInitMessage() {
// given
val context = createContext()
val context = createContext(bank)
// when
val result = underTest.createSynchronizeCustomerSystemIdMessage(context).createdMessage ?: ""
@ -105,7 +108,7 @@ class MessageBuilderTest : FinTsTestBase() {
// given
val dialogId = createDialogId()
val context = createContext(dialogId)
val context = createContext(bank, dialogId)
// when
val result = underTest.createDialogEndMessage(context).createdMessage ?: ""
@ -126,10 +129,10 @@ class MessageBuilderTest : FinTsTestBase() {
fun createGetTransactionsMessage_JobIsNotAllowed() {
// given
val context = createContext()
val context = createContext(bank)
// when
val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(Bank, Account))
val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(bank, Account))
// then
assertFalse(result.isJobAllowed)
@ -141,14 +144,14 @@ class MessageBuilderTest : FinTsTestBase() {
// given
val getTransactionsJob = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:73:5")
val getTransactionsJobWithPreviousVersion = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:72:4")
Bank.supportedJobs = listOf(getTransactionsJob)
bank.supportedJobs = listOf(getTransactionsJob)
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJobWithPreviousVersion))
Bank.addAccount(account)
bank.addAccount(account)
val context = createContext()
val context = createContext(bank)
// when
val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(Bank, account))
val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(bank, account))
// then
assertTrue(result.isJobAllowed)
@ -160,19 +163,19 @@ class MessageBuilderTest : FinTsTestBase() {
// given
val getTransactionsJob = RetrieveAccountTransactionsParameters(JobParameters(CustomerSegmentId.AccountTransactionsMt940.id, 1, 1, null, "HIKAZS:73:5"), 180, true, false)
Bank.supportedJobs = listOf(getTransactionsJob)
Bank.pinInfo = PinInfo(getTransactionsJob, null, null, null, null, null, listOf(JobTanConfiguration(CustomerSegmentId.AccountTransactionsMt940.id, true)))
bank.supportedJobs = listOf(getTransactionsJob)
bank.pinInfo = PinInfo(getTransactionsJob, null, null, null, null, null, listOf(JobTanConfiguration(CustomerSegmentId.AccountTransactionsMt940.id, true)))
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
Bank.addAccount(account)
bank.addAccount(account)
val context = createContext()
val context = createContext(bank)
val fromDate = LocalDate(2019, Month.AUGUST, 6)
val toDate = LocalDate(2019, Month.OCTOBER, 21)
val maxCountEntries = 99
// when
val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(Bank, account, false, fromDate, toDate, maxCountEntries))
val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(bank, account, false, fromDate, toDate, maxCountEntries))
// then
assertNotNull(result.createdMessage)
@ -194,12 +197,12 @@ class MessageBuilderTest : FinTsTestBase() {
// given
val getTransactionsJob = RetrieveAccountTransactionsParameters(JobParameters(CustomerSegmentId.AccountTransactionsMt940.id, 1, 1, null, "HIKAZS:73:5"), 180, true, false)
Bank.supportedJobs = listOf(getTransactionsJob)
Bank.pinInfo = PinInfo(getTransactionsJob, null, null, null, null, null, listOf(JobTanConfiguration(CustomerSegmentId.AccountTransactionsMt940.id, true)))
bank.supportedJobs = listOf(getTransactionsJob)
bank.pinInfo = PinInfo(getTransactionsJob, null, null, null, null, null, listOf(JobTanConfiguration(CustomerSegmentId.AccountTransactionsMt940.id, true)))
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
Bank.addAccount(account)
bank.addAccount(account)
val context = createContext()
val context = createContext(bank)
val fromDate = LocalDate(2019, Month.AUGUST, 6)
val toDate = LocalDate(2019, Month.OCTOBER, 21)
@ -208,7 +211,7 @@ class MessageBuilderTest : FinTsTestBase() {
// when
val result = underTest.createGetTransactionsMessage(context, // TODO: test Aufsetzpunkt / continuationId
GetAccountTransactionsParameter(Bank, account, false, fromDate, toDate, maxCountEntries, false))
GetAccountTransactionsParameter(bank, account, false, fromDate, toDate, maxCountEntries, false))
// then
assertNotNull(result.createdMessage)

View File

@ -30,8 +30,14 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
}
// we need to create our own copy as otherwise Kotlin/Native throws an InvalidMutabilityException
private val bank = createTestBank()
private val account = createTestAccount()
init {
Bank.addAccount(Account)
bank.addAccount(account)
}
@ -41,7 +47,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, false, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -58,7 +64,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, true, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -75,7 +81,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, false, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -92,7 +98,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, true, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(1, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -110,7 +116,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, false, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -127,7 +133,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, true, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -144,7 +150,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, false, false, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -161,7 +167,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, false, false, true, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when
@ -178,7 +184,7 @@ class TanGeneratorTanMediumAnOderUmmeldenTest: FinTsTestBase() {
// given
val parameters = ChangeTanMediaParameters(createEmptyJobParameters(), false, true, true, true, false, listOf())
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, Bank, NewActiveTanMedium, TAN, ATC, null, parameters)
val underTest = TanGeneratorTanMediumAnOderUmmelden(2, SegmentNumber, bank, NewActiveTanMedium, TAN, ATC, null, parameters)
// when

View File

@ -36,9 +36,6 @@ class Mt940ParserTest : FinTsTestBase() {
val AccountStatement1ClosingBalanceAmount = Amount("13580,23")
val AccountStatement1With2TransactionsClosingBalanceAmount = Amount("13148,13")
val Mt940DateFormatter = DateFormatter("yyMMdd")
val BookingDateFormatter = DateFormatter("MMdd")
}
private val underTest = Mt940Parser()
@ -388,11 +385,13 @@ class Mt940ParserTest : FinTsTestBase() {
private fun convertMt940Date(date: LocalDate): String {
return date.format(Mt940DateFormatter)
// don't use DateFormatter for this as it's not implemented in Kotlin/Native
return (date.year % 100).toString() + date.monthNumber.toStringWithTwoDigits() + date.dayOfMonth.toStringWithTwoDigits()
}
private fun convertToShortBookingDate(date: LocalDate): String {
return date.format(BookingDateFormatter)
// don't use DateFormatter for this as it's not implemented in Kotlin/Native
return date.monthNumber.toStringWithTwoDigits() + date.dayOfMonth.toStringWithTwoDigits()
}
}

View File

@ -34,13 +34,13 @@ kotlin {
}
}
// def hostOs = System.getProperty("os.name")
// def isMingwX64 = hostOs.startsWith("Windows")
// def nativeTarget
// if (hostOs == "Mac OS X") nativeTarget = macosX64('native') { binaries.executable() }
// else if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries.executable() }
// else if (isMingwX64) nativeTarget = mingwX64("native") { binaries.executable() }
// else throw new GradleException("Host OS is not supported in Kotlin/Native.")
def hostOs = System.getProperty("os.name")
def isMingwX64 = hostOs.startsWith("Windows")
def nativeTarget
if (hostOs == "Mac OS X") nativeTarget = macosX64('native')
else if (hostOs == "Linux") nativeTarget = linuxX64("native")
else if (isMingwX64) nativeTarget = mingwX64("native")
else throw new GradleException("Host OS is not supported in Kotlin/Native.")
sourceSets {

View File

@ -7,6 +7,8 @@ enum class OsType {
Android,
iOS
iOS,
Native // TODO: get if running on Linux, Windows or macOs
}

View File

@ -0,0 +1,29 @@
package net.dankito.utils.multiplatform
import kotlinx.datetime.*
actual class DateFormatter actual constructor(pattern: String) {
actual constructor(dateStyle: DateFormatStyle)
: this("")
actual constructor(dateStyle: DateFormatStyle, timeStyle: DateFormatStyle)
: this("")
// TODO: implement for Logger, get current time formatted as string
actual fun format(date: LocalDateTime): String {
return "" // is only used in rare cases, don't implement right now
}
actual fun parseDate(dateString: String): LocalDate? {
return null // is only used in rare cases, don't implement right now
}
actual fun parse(dateString: String): LocalDateTime? {
return null // is only used in rare cases, don't implement right now
}
}

View File

@ -0,0 +1,10 @@
package net.dankito.utils.multiplatform
actual class StackTraceHelper {
actual fun getStackTrace(e: Throwable, maxCountStackTraceElements: Int?): String {
// TODO: is this a nice string?
return e.getStackTrace().take(maxCountStackTraceElements ?: Int.MAX_VALUE).joinToString("\n")
}
}

View File

@ -0,0 +1,28 @@
package net.dankito.utils.multiplatform
actual class Thread {
actual companion object {
actual val current: Thread
get() = Thread()
actual fun printCurrentThreadStackTrace() {
Thread.current.printStackTrace()
}
}
actual val threadName: String
get() = "main"
actual fun printStackTrace() {
// TODO: find a better way
Exception("Nothing happened, just to print the stack trace").printStackTrace()
}
}

View File

@ -0,0 +1,9 @@
package net.dankito.utils.multiplatform.log
actual class DefaultLoggerFactory actual constructor() {
actual fun createDefaultLoggerFactory(): ILoggerFactory {
return LogToConsoleLoggerFactory()
}
}

View File

@ -0,0 +1,7 @@
package net.dankito.utils.multiplatform.os
actual class OsHelper actual constructor() {
actual val osType = OsType.Native
}