Adds poker base import

realmasync
Laurent 3 years ago
parent d852d62c93
commit d122f3fd53
  1. 4
      app/build.gradle
  2. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  3. 20
      app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt
  4. 13
      app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt
  5. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  6. 23
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  7. 164
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt
  8. 12
      app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt
  9. 18
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  10. 6
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  11. 5
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt
  12. 5
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt
  13. 3
      app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt
  14. 1
      app/src/main/res/values-de/strings.xml
  15. 1
      app/src/main/res/values-es/strings.xml
  16. 1
      app/src/main/res/values-fr/strings.xml
  17. 1
      app/src/main/res/values-hi/strings.xml
  18. 1
      app/src/main/res/values-it/strings.xml
  19. 1
      app/src/main/res/values-ja/strings.xml
  20. 1
      app/src/main/res/values-pt/strings.xml
  21. 1
      app/src/main/res/values-ru/strings.xml
  22. 1
      app/src/main/res/values-zh/strings.xml
  23. 1
      app/src/main/res/values/strings.xml
  24. 11
      app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt
  25. 3
      app/src/test/java/net/pokeranalytics/android/HandHistoryTest.kt

@ -35,8 +35,8 @@ android {
applicationId "net.pokeranalytics.android"
minSdkVersion 23
targetSdkVersion 32
versionCode 145
versionName "6.0.2"
versionCode 146
versionName "6.0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

@ -31,7 +31,8 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name
BONUS(2, true),
STACKING_INCOMING(3, true),
STACKING_OUTGOING(4, false),
TRANSFER(5, false);
TRANSFER(5, false),
EXPENSE(6, false); // not created by default, only used for poker base import atm
companion object : IntSearchable<Value> {
@ -49,6 +50,7 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name
STACKING_INCOMING -> R.string.stacking_incoming
STACKING_OUTGOING -> R.string.stacking_outgoing
TRANSFER -> R.string.transfer
EXPENSE -> R.string.expense
}
}
@ -70,6 +72,10 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name
throw PAIllegalStateException("Transaction type ${value.name} should exist in database!")
}
fun getOrCreate(realm: Realm, value: Value, context: Context): TransactionType {
return getOrCreate(realm, value.localizedTitle(context), value.additive)
}
fun getOrCreate(realm: Realm, name: String, additive: Boolean): TransactionType {
val type = realm.where(TransactionType::class.java).equalTo("name", name).findFirst()
return if (type != null) {

@ -17,15 +17,19 @@ class Seed(var context:Context) : Realm.Transaction {
fun createDefaultTransactionTypes(values: Array<TransactionType.Value>, context: Context, realm: Realm) {
values.forEach { value ->
val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll()
if (existing.isEmpty()) {
val type = TransactionType()
type.name = value.localizedTitle(context)
type.additive = value.additive
type.kind = value.uniqueIdentifier
type.lock = true
realm.insertOrUpdate(type)
if (value != TransactionType.Value.EXPENSE) {
val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll()
if (existing.isEmpty()) {
val type = TransactionType()
type.name = value.localizedTitle(context)
type.additive = value.additive
type.kind = value.uniqueIdentifier
type.lock = true
realm.insertOrUpdate(type)
}
}
}
}
}

@ -18,7 +18,6 @@ import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.ui.fragment.ImportFragment
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.extensions.count
import timber.log.Timber
class ImportActivity : BaseActivity() {
@ -64,11 +63,13 @@ class ImportActivity : BaseActivity() {
val fragmentTransaction = supportFragmentManager.beginTransaction()
val fragment = ImportFragment()
val fis = contentResolver.openInputStream(fileURI)
Timber.d("Load fragment data with: $fis")
fis?.let {
fragment.setData(it)
}
fragment.setData(fileURI)
// val fis = contentResolver.openInputStream(fileURI)
// Timber.d("Load fragment data with: $fis")
// fis?.let {
// fragment.setData(it)
// }
fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit()

@ -1,5 +1,6 @@
package net.pokeranalytics.android.ui.fragment
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -24,6 +25,7 @@ class ImportFragment : RealmFragment(), ImportDelegate {
private lateinit var filePath: String
private lateinit var inputStream: InputStream
private lateinit var uri: Uri
private lateinit var importer: CSVImporter
private var _binding: FragmentImportBinding? = null
@ -52,6 +54,10 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.inputStream = inputStream
}
fun setData(uri: Uri) {
this.uri = uri
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -86,7 +92,7 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.parentActivity?.paApplication?.reportWhistleBlower?.pause()
this.importer = CSVImporter(inputStream)
this.importer = CSVImporter(uri, requireContext())
this.importer.delegate = this
CoroutineScope(coroutineContext).launch {

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm
import io.realm.kotlin.deleteFromRealm
import net.pokeranalytics.android.model.interfaces.Identifiable
@ -7,7 +8,6 @@ import net.pokeranalytics.android.model.interfaces.ObjectIdentifier
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.extensions.findById
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
/**
* The various sources of CSV
@ -18,7 +18,8 @@ enum class DataSource {
POKER_INCOME,
POKER_BANKROLL_TRACKER,
RUN_GOOD,
POKER_AGENT;
POKER_AGENT,
POKER_BASE;
val availableDateFormats: List<String>
get() {
@ -28,6 +29,14 @@ enum class DataSource {
}
}
val delimiter: Char
get() {
return when (this) {
POKER_BASE -> ';'
else -> ','
}
}
}
/**
@ -40,11 +49,11 @@ abstract class DataCSVDescriptor<T : Identifiable>(source: DataSource, vararg el
*/
private val realmModelIds = mutableListOf<ObjectIdentifier>()
abstract fun parseData(realm: Realm, record: CSVRecord): T?
abstract fun parseData(realm: Realm, record: CSVRecord, context: Context): T?
override fun parse(realm: Realm, record: CSVRecord): Int {
override fun parse(realm: Realm, record: CSVRecord, context: Context): Int {
val data = this.parseData(realm, record)
val data = this.parseData(realm, record, context)
data?.let {
// Timber.d(">>>>>>> identifier added: ${it.id}")
this.realmModelIds.add(it.objectIdentifier)
@ -144,7 +153,7 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField)
/**
* Method called when iterating on a CSVRecord
*/
abstract fun parse(realm: Realm, record: CSVRecord): Int
abstract fun parse(realm: Realm, record: CSVRecord, context: Context): Int
open fun save(realm: Realm) {
@ -171,7 +180,7 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField)
}
}
val mandatoryFields = this.fields.filter { !it.optional }
Timber.d("source= ${this.source.name} > total fields = ${this.fields.size}, identified = $count")
// Timber.d("source= ${this.source.name} > total fields = ${this.fields.size}, identified = $count")
return count >= mandatoryFields.size
}

@ -1,16 +1,15 @@
package net.pokeranalytics.android.util.csv
import android.content.Context
import android.net.Uri
import android.os.Handler
import android.os.Looper
import io.realm.Realm
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.extensions.count
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVParser
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
import java.io.FileReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.Reader
@ -23,12 +22,12 @@ interface ImportDelegate {
/**
* A CSVImporter is a class in charge of parsing a CSV file and processing it
* When starting the parsing of a file, the instance will search for a CSVDescriptor, which describes
* the format of a CSV file.
* When finding a descriptor, the CSVImporter then continue to parse the file and delegates the parsing of each row
* to the CSVDescriptor
* When starting the parsing of a file, the instance will search for a CSVDescriptor,
* which describes the format of a CSV file.
* When finding a descriptor, the CSVImporter then continue to parse the file and
* delegates the parsing of each row to the CSVDescriptor
*/
open class CSVImporter(istream: InputStream) {
open class CSVImporter(uri: Uri, var context: Context) {
/**
* The object being notified of the import progress
@ -52,10 +51,11 @@ open class CSVImporter(istream: InputStream) {
* The path of the CSV file
*/
private var path: String? = null
/**
* The InputStream containing a file content
* The Uri of the file to import
*/
private var inputStream: InputStream? = istream
private var uri: Uri? = uri
/**
* The current number of attempts at finding a valid CSVDescriptor
@ -85,97 +85,117 @@ open class CSVImporter(istream: InputStream) {
/**
* The CSV parser
*/
private lateinit var parser: CSVParser
// private var parser: CSVParser? = null
val reader: Reader
get() {
this.uri?.let { uri ->
// it's required to open the stream each time we start a new parser
val inputStream = context.contentResolver.openInputStream(uri)
return InputStreamReader(inputStream)
}
return if (this.path != null) {
FileReader(this.path)
} else {
throw PAIllegalStateException("No data source")
}
}
/**
* Constructs a CSVParser object and starts parsing the CSV
*/
fun start() {
Timber.d("Starting import...")
val realm = Realm.getDefaultInstance()
realm.beginTransaction()
var reader: Reader? = null
if (this.path != null) {
reader = FileReader(this.path)
}
if (this.inputStream != null) {
reader = InputStreamReader(this.inputStream)
}
val descriptorsByDelimiter = ProductCSVDescriptors.all.groupBy { it.source.delimiter }
this.parser = CSVFormat.DEFAULT.withAllowMissingColumnNames().parse(reader)
for ((delimiter, descriptors) in descriptorsByDelimiter) {
Timber.d("Starting import...")
if (this.currentDescriptor != null) {
break
}
realm.beginTransaction()
Timber.d("====== Trying with delimiter '$delimiter'")
val format = CSVFormat.DEFAULT
.withAllowMissingColumnNames()
.withDelimiter(delimiter)
val parser = format.parse(this.reader)
this.parser.forEachIndexed { index, record ->
Timber.d("parse delim = ${format.delimiter}")
parser.forEachIndexed { index, record ->
// Timber.d("line $index")
this.notifyDelegate()
this.notifyDelegate()
if (this.currentDescriptor == null) { // find descriptor
this.currentDescriptor = this.findDescriptor(record)
if (this.currentDescriptor == null) { // find descriptor
this.currentDescriptor = this.findDescriptor(record, descriptors)
this.currentDescriptor?.hasMatched(realm, record)
this.currentDescriptor?.hasMatched(realm, record)
if (this.currentDescriptor == null) {
if (this.currentDescriptor == null) {
if (record.size() >= VALID_RECORD_COLUMNS) {
this.descriptorFindingAttempts++
}
if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) {
realm.cancelTransaction()
realm.close()
throw ImportException("This type of file is not supported")
if (record.size() >= VALID_RECORD_COLUMNS) {
this.descriptorFindingAttempts++
}
if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) {
realm.cancelTransaction()
realm.close()
throw ImportException("This type of file is not supported")
}
}
}
} else { // parse
} else { // parse
// batch commit
val parsingIndex = index + 1
if (parsingIndex % COMMIT_FREQUENCY == 0) {
Timber.d("****** committing at $parsingIndex sessions...")
realm.commitTransaction()
realm.beginTransaction()
}
// batch commit
val parsingIndex = index + 1
if (parsingIndex % COMMIT_FREQUENCY == 0) {
Timber.d("****** committing at $parsingIndex sessions...")
realm.commitTransaction()
realm.beginTransaction()
}
this.currentDescriptor?.let {
if (record.size() == 0) {
this.usedDescriptors.add(it)
this.currentDescriptor =
null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file)
this.descriptorFindingAttempts = 0
} else {
this.currentDescriptor?.let {
if (record.size() == 0) {
this.usedDescriptors.add(it)
this.currentDescriptor =
null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file)
this.descriptorFindingAttempts = 0
} else {
try {
val count = it.parse(realm, record)
try {
val count = it.parse(realm, record, this.context)
this.importedRecords += count
this.totalParsedRecords++
this.importedRecords += count
this.totalParsedRecords++
this.notifyDelegate()
this.notifyDelegate()
} catch (e: Exception) {
this.delegate?.exceptionCaught(e)
}
} catch (e: Exception) {
this.delegate?.exceptionCaught(e)
}
}
} ?: run {
realm.cancelTransaction()
realm.close()
throw ImportException("CSVDescriptor should never be null here")
}
} ?: run {
realm.cancelTransaction()
realm.close()
throw ImportException("CSVDescriptor should never be null here")
}
}
parser.close()
}
Timber.d("Ending import...")
this.notifyDelegate()
realm.commitTransaction()
Timber.d("Ending import...")
realm.close()
}
@ -188,9 +208,9 @@ open class CSVImporter(istream: InputStream) {
/**
* Search for a descriptor in the list of managed formats
*/
private fun findDescriptor(record: CSVRecord): CSVDescriptor? {
private fun findDescriptor(record: CSVRecord, descriptors: List<CSVDescriptor>): CSVDescriptor? {
ProductCSVDescriptors.all.forEach { descriptor ->
descriptors.forEach { descriptor ->
if (descriptor.matches(record)) {
this.currentDescriptor = descriptor
Timber.d("Identified source: ${descriptor.source}")
@ -201,7 +221,7 @@ open class CSVImporter(istream: InputStream) {
}
fun save(realm: Realm) {
this.parser.close()
// this.parser?.close()
realm.refresh()
this.currentDescriptor?.save(realm)
@ -211,7 +231,7 @@ open class CSVImporter(istream: InputStream) {
}
fun cancel(realm: Realm) {
this.parser.close()
// this.parser?.close()
realm.refresh()
this.currentDescriptor?.cancel(realm)

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit
@ -42,7 +43,7 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
/**
* Parses a [record] and return an optional Session
*/
protected fun parseSession(realm: Realm, record: CSVRecord): Session? {
protected fun parseSession(realm: Realm, record: CSVRecord, context: Context): Session? {
val isTournament = isTournament ?: false
val session = Session.newInstance(realm, isTournament, managed = false)
@ -58,6 +59,7 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
var stackingIn: Double? = null
var stackingOut: Double? = null
var expense: Double? = null
var sb: Double? = null
var bb: Double? = null
@ -216,6 +218,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
is SessionField.StackingOut -> {
stackingOut = field.parse(value)
}
is SessionField.Expense -> {
expense = field.parse(value)
}
is SessionField.ListCustomField -> {
val entry = field.customField.getOrCreateEntry(realm, value)
session.customFieldEntries.add(entry)
@ -275,6 +280,11 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!)
this.addAdditionallyCreatedIdentifiable(transaction)
}
if (expense != null && expense != 0.0) {
val type = TransactionType.getOrCreate(realm, TransactionType.Value.EXPENSE, context)
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, expense!!)
this.addAdditionallyCreatedIdentifiable(transaction)
}
return managedSession
} else {

@ -20,7 +20,8 @@ class ProductCSVDescriptors {
pokerAnalytics6iOS,
pokerAnalyticsAndroidSessions,
pokerAnalyticsAndroid6Sessions,
pokerAnalyticsAndroidTransactions
pokerAnalyticsAndroidTransactions,
pokerBase
)
private val pokerAgent: CSVDescriptor
@ -159,6 +160,21 @@ class ProductCSVDescriptors {
)
}
private val pokerBase: CSVDescriptor
get() {
return SessionCSVDescriptor(
DataSource.POKER_BASE,
null,
SessionField.Start("start", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
SessionField.End("end", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
SessionField.Location("location"),
SessionField.Bankroll("currency"),
SessionField.CurrencyCode("currency"),
SessionField.Expense("expenses"),
SessionField.NetResult("profit"),
)
}
private val pokerAnalyticsiOS: SessionCSVDescriptor
get() {
return SessionCSVDescriptor(

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit
@ -30,11 +31,10 @@ class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg el
this.fields.add(f)
}
realm.close()
}
override fun parseData(realm: Realm, record: CSVRecord): Session? {
return this.parseSession(realm, record)
override fun parseData(realm: Realm, record: CSVRecord, context: Context): Session? {
return this.parseSession(realm, record, context)
}
override fun toCSV(data: Session, field: CSVField): String? {

@ -174,6 +174,11 @@ sealed class SessionField {
override var callback: ((String) -> Double?)? = null
) : NumberCSVField
data class Expense(
override var header: String,
override var callback: ((String) -> Double?)? = null
) : NumberCSVField
data class Blind(override var header: String,
override var callback: ((String) -> Pair<Double, Double>?)? = null
) : BlindCSVField

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.realm.Bankroll
@ -36,7 +37,7 @@ class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean?
/**
* Parses a [record] and return an optional Session
*/
override fun parseData(realm: Realm, record: CSVRecord): Identifiable? {
override fun parseData(realm: Realm, record: CSVRecord, context: Context): Identifiable? {
var dataType: DataType? = null
val typeField = fields.firstOrNull { it is SessionField.SessionType }
@ -49,7 +50,7 @@ class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean?
return when (dataType) {
DataType.TRANSACTION -> parseTransaction(realm, record)
else -> parseSession(realm, record)
else -> parseSession(realm, record, context)
}
}

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.realm.Bankroll
@ -13,7 +14,7 @@ import java.util.*
class TransactionCSVDescriptor(source: DataSource, vararg elements: CSVField) :
DataCSVDescriptor<Transaction>(source, *elements) {
override fun parseData(realm: Realm, record: CSVRecord): Transaction? {
override fun parseData(realm: Realm, record: CSVRecord, context: Context): Transaction? {
var date: Date? = null
var typeName: String? = null

@ -779,5 +779,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -783,6 +783,7 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -788,5 +788,6 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="transaction_filter">Filtre de transactions</string>
<string name="expense">frais</string>
</resources>

@ -778,5 +778,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -778,5 +778,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -782,5 +782,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -777,5 +777,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -779,5 +779,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -772,5 +772,6 @@
<string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources>

@ -832,5 +832,6 @@
<string name="less_sign"><![CDATA[<]]></string>
<string name="empty_reports_screen">This screen will show where you perform the best when you\'ll have more data. You also can create custom reports using the top right button.</string>
<string name="transaction_filter">Transaction Filter</string>
<string name="expense">expense</string>
</resources>

@ -7,6 +7,7 @@ import net.pokeranalytics.android.util.Parser
import net.pokeranalytics.android.util.extensions.kmbFormatted
import org.junit.Assert
import org.junit.Test
import java.text.SimpleDateFormat
class BasicUnitTest : RealmUnitTest() {
@ -92,4 +93,14 @@ class BasicUnitTest : RealmUnitTest() {
}
@Test
fun testDateFormat() {
val dateString = "2019-01-01T02:00:00.000Z"
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val date = dateFormat.parse(dateString)
Assert.assertNotNull(date)
}
}

@ -24,8 +24,7 @@ class HandHistoryTest {
private fun handHistoryInstance(players: Int): HandHistory {
val hh = HandHistory()
val hs = HandSetup()
hs.smallBlind = 1.0
hs.bigBlind = 2.0
hs.blinds = "1/2"
hs.tableSize = players
hh.configure(hs)

Loading…
Cancel
Save