summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-10-11 21:37:48 +0000
committerAntoine A <>2023-10-11 21:37:48 +0000
commit61f560d3624f30f78b90b9a804db7d5126e1a7da (patch)
treecf3ad0132b0fc2a8f70e996470171f127088c25e
parent9d43dc08ac94ff1f30d76ee3978ea2f4571c4369 (diff)
downloadlibeufin-61f560d3624f30f78b90b9a804db7d5126e1a7da.tar.gz
libeufin-61f560d3624f30f78b90b9a804db7d5126e1a7da.tar.bz2
libeufin-61f560d3624f30f78b90b9a804db7d5126e1a7da.zip
Support currency specification
-rw-r--r--bank/conf/test.conf17
-rw-r--r--bank/conf/test_restrict.conf17
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt29
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/IntegrationApiHandlers.kt5
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Main.kt95
-rw-r--r--bank/src/test/kotlin/Common.kt2
-rw-r--r--bank/src/test/kotlin/LibeuFinApiTest.kt2
-rw-r--r--bank/src/test/kotlin/TalerApiTest.kt4
-rw-r--r--bank/src/test/kotlin/helpers.kt18
-rw-r--r--util/src/main/kotlin/TalerConfig.kt122
-rw-r--r--util/src/test/kotlin/TalerConfigTest.kt8
11 files changed, 176 insertions, 143 deletions
diff --git a/bank/conf/test.conf b/bank/conf/test.conf
new file mode 100644
index 00000000..fe7450a6
--- /dev/null
+++ b/bank/conf/test.conf
@@ -0,0 +1,17 @@
+[libeufin-bank]
+CURRENCY = KUDOS
+DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:100
+DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
+REGISTRATION_BONUS_ENABLED = NO
+SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.example.com
+
+[currency-kudos]
+ENABLED = YES
+name = "Kudos (Taler Demonstrator)"
+code = "KUDOS"
+decimal_separator = ","
+fractional_input_digits = 2
+fractional_normal_digits = 2
+fractional_trailing_zero_digits = 2
+is_currency_name_leading = NO
+alt_unit_names = {"0":"ク"} \ No newline at end of file
diff --git a/bank/conf/test_restrict.conf b/bank/conf/test_restrict.conf
new file mode 100644
index 00000000..462d94e6
--- /dev/null
+++ b/bank/conf/test_restrict.conf
@@ -0,0 +1,17 @@
+[libeufin-bank]
+CURRENCY = KUDOS
+DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:100
+DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
+REGISTRATION_BONUS_ENABLED = NO
+restrict_registration = YES
+
+[currency-kudos]
+ENABLED = YES
+name = "Kudos (Taler Demonstrator)"
+code = "KUDOS"
+decimal_separator = ","
+fractional_input_digits = 2
+fractional_normal_digits = 2
+fractional_trailing_zero_digits = 2
+is_currency_name_leading = NO
+alt_unit_names = {"0":"ク"} \ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
index 67fe6a96..cefe8841 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
@@ -468,12 +468,14 @@ data class Cashout(
// Type to return as GET /config response
@Serializable // Never used to parse JSON.
data class Config(
- val name: String = "libeufin-bank",
- val version: String = "0:0:0",
- val have_cashout: Boolean = false,
+ val currency: CurrencySpecification,
+) {
+ val name: String = "libeufin-bank"
+ val version: String = "0:0:0"
+ val have_cashout: Boolean = false
// Following might probably get renamed:
val fiat_currency: String? = null
-)
+}
enum class CorebankCreditDebitInfo {
credit, debit
@@ -636,9 +638,22 @@ enum class BankTransactionResult {
// GET /config response from the Taler Integration API.
@Serializable
data class TalerIntegrationConfigResponse(
- val name: String = "taler-bank-integration",
- val version: String = "0:0:0",
- val currency: String
+ val currency: String,
+ val currency_specification: CurrencySpecification,
+) {
+ val name: String = "taler-bank-integration";
+ val version: String = "0:0:0";
+}
+
+@Serializable
+data class CurrencySpecification(
+ val name: String,
+ val decimal_separator: String,
+ val num_fractional_input_digits: Int,
+ val num_fractional_normal_digits: Int,
+ val num_fractional_trailing_zero_digits: Int,
+ val is_currency_name_leading: Boolean,
+ val alt_unit_names: Map<String, String>
)
/**
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/IntegrationApiHandlers.kt b/bank/src/main/kotlin/tech/libeufin/bank/IntegrationApiHandlers.kt
index b117a8d8..bd867c59 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/IntegrationApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/IntegrationApiHandlers.kt
@@ -31,7 +31,10 @@ import tech.libeufin.util.stripIbanPayto
fun Routing.talerIntegrationHandlers(db: Database, ctx: BankApplicationContext) {
get("/taler-integration/config") {
val internalCurrency: String = ctx.currency
- call.respond(TalerIntegrationConfigResponse(currency = internalCurrency))
+ call.respond(TalerIntegrationConfigResponse(
+ currency = internalCurrency,
+ currency_specification = ctx.currencySpecification
+ ))
return@get
}
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 8030a881..be706ef0 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -83,6 +83,7 @@ data class BankApplicationContext(
* Main, internal currency of the bank.
*/
val currency: String,
+ val currencySpecification: CurrencySpecification,
/**
* Restrict account registration to the administrator.
*/
@@ -124,7 +125,43 @@ data class BankApplicationContext(
* SPA is located.
*/
val spaCaptchaURL: String?,
-)
+) {
+ companion object {
+ /**
+ * Read the configuration of the bank from a config file.
+ * Throws an exception if the configuration is malformed.
+ */
+ fun readFromConfig(cfg: TalerConfig): BankApplicationContext {
+ val currency = cfg.requireString("libeufin-bank", "currency")
+ val currencySpecification = cfg.sections.find {
+ it.startsWith("CURRENCY-") && cfg.requireBoolean(it, "enabled") && cfg.requireString(it, "code") == currency
+ }?.let {
+ CurrencySpecification(
+ name = cfg.requireString(it, "name"),
+ decimal_separator = cfg.requireString(it, "decimal_separator"),
+ num_fractional_input_digits = cfg.requireNumber(it, "fractional_input_digits"),
+ num_fractional_normal_digits = cfg.requireNumber(it, "fractional_normal_digits"),
+ num_fractional_trailing_zero_digits = cfg.requireNumber(it, "fractional_trailing_zero_digits"),
+ is_currency_name_leading = cfg.requireBoolean(it, "is_currency_name_leading"),
+ alt_unit_names = Json.decodeFromString(cfg.requireString(it, "alt_unit_names"))
+ )
+ } ?: throw TalerConfigError("missing currency config for $currency")
+ return BankApplicationContext(
+ currency = currency,
+ restrictRegistration = cfg.lookupBoolean("libeufin-bank", "restrict_registration") ?: false,
+ cashoutCurrency = cfg.lookupString("libeufin-bank", "cashout_currency"),
+ defaultCustomerDebtLimit = cfg.requireAmount("libeufin-bank", "default_customer_debt_limit", currency),
+ registrationBonusEnabled = cfg.lookupBoolean("libeufin-bank", "registration_bonus_enabled") ?: false,
+ registrationBonus = cfg.requireAmount("libeufin-bank", "registration_bonus", currency),
+ suggestedWithdrawalExchange = cfg.lookupString("libeufin-bank", "suggested_withdrawal_exchange"),
+ defaultAdminDebtLimit = cfg.requireAmount("libeufin-bank", "default_admin_debt_limit", currency),
+ spaCaptchaURL = cfg.lookupString("libeufin-bank", "spa_captcha_url"),
+ restrictAccountDeletion = cfg.lookupBoolean("libeufin-bank", "restrict_account_deletion") ?: true,
+ currencySpecification = currencySpecification
+ )
+ }
+ }
+}
/**
@@ -404,7 +441,7 @@ fun Application.corebankWebApp(db: Database, ctx: BankApplicationContext) {
}
routing {
get("/config") {
- call.respond(Config())
+ call.respond(Config(ctx.currencySpecification))
return@get
}
this.accountsMgmtHandlers(db, ctx)
@@ -471,15 +508,12 @@ fun durationFromPretty(s: String): Long {
return durationUs
}
-fun TalerConfig.requireValueAmount(section: String, option: String, currency: String): TalerAmount {
- val amountStr = lookupValueString(section, option)
- if (amountStr == null) {
+fun TalerConfig.requireAmount(section: String, option: String, currency: String): TalerAmount {
+ val amountStr = lookupString(section, option) ?:
throw TalerConfigError("expected amount for section $section, option $option, but config value is empty")
- }
- val amount = parseTalerAmount2(amountStr, FracDigits.EIGHT)
- if (amount == null) {
+ val amount = parseTalerAmount2(amountStr, FracDigits.EIGHT) ?:
throw TalerConfigError("expected amount for section $section, option $option, but amount is malformed")
- }
+
if (amount.currency != currency) {
throw TalerConfigError(
"expected amount for section $section, option $option, but currency is wrong (got ${amount.currency} expected $currency"
@@ -488,27 +522,6 @@ fun TalerConfig.requireValueAmount(section: String, option: String, currency: St
return amount
}
-/**
- * Read the configuration of the bank from a config file.
- * Throws an exception if the configuration is malformed.
- */
-fun readBankApplicationContextFromConfig(cfg: TalerConfig): BankApplicationContext {
- val currency = cfg.requireValueString("libeufin-bank", "currency")
- return BankApplicationContext(
- currency = currency,
- restrictRegistration = cfg.lookupValueBooleanDefault("libeufin-bank", "restrict_registration", false),
- cashoutCurrency = cfg.lookupValueString("libeufin-bank", "cashout_currency"),
- defaultCustomerDebtLimit = cfg.requireValueAmount("libeufin-bank", "default_customer_debt_limit", currency),
- registrationBonusEnabled = cfg.lookupValueBooleanDefault("libeufin-bank", "registration_bonus_enabled", false),
- registrationBonus = cfg.requireValueAmount("libeufin-bank", "registration_bonus", currency),
- suggestedWithdrawalExchange = cfg.lookupValueString("libeufin-bank", "suggested_withdrawal_exchange"),
- defaultAdminDebtLimit = cfg.requireValueAmount("libeufin-bank", "default_admin_debt_limit", currency),
- spaCaptchaURL = cfg.lookupValueString("libeufin-bank", "spa_captcha_url"),
- restrictAccountDeletion = cfg.lookupValueBooleanDefault("libeufin-bank", "restrict_account_deletion", true)
- )
-}
-
-
class BankDbInit : CliktCommand("Initialize the libeufin-bank database", name = "dbinit") {
private val configFile by option(
"--config", "-c",
@@ -529,8 +542,8 @@ class BankDbInit : CliktCommand("Initialize the libeufin-bank database", name =
override fun run() {
val config = TalerConfig(BANK_CONFIG_SOURCE)
config.load(this.configFile)
- val dbConnStr = config.requireValueString("libeufin-bankdb-postgres", "config")
- val sqlDir = config.requireValuePath("libeufin-bankdb-postgres", "sql_dir")
+ val dbConnStr = config.requireString("libeufin-bankdb-postgres", "config")
+ val sqlDir = config.requirePath("libeufin-bankdb-postgres", "sql_dir")
if (requestReset) {
resetDatabaseTables(dbConnStr, sqlDir)
}
@@ -553,15 +566,15 @@ class ServeBank : CliktCommand("Run libeufin-bank HTTP server", name = "serve")
override fun run() {
val config = TalerConfig(BANK_CONFIG_SOURCE)
config.load(this.configFile)
- val ctx = readBankApplicationContextFromConfig(config)
- val dbConnStr = config.requireValueString("libeufin-bankdb-postgres", "config")
+ val ctx = BankApplicationContext.readFromConfig(config)
+ val dbConnStr = config.requireString("libeufin-bankdb-postgres", "config")
logger.info("using database '$dbConnStr'")
- val serveMethod = config.requireValueString("libeufin-bank", "serve")
+ val serveMethod = config.requireString("libeufin-bank", "serve")
if (serveMethod.lowercase() != "tcp") {
logger.info("Can only serve libeufin-bank via TCP")
exitProcess(1)
}
- val servePortLong = config.requireValueNumber("libeufin-bank", "port")
+ val servePortLong = config.requireNumber("libeufin-bank", "port")
val servePort = servePortLong.toInt()
val db = Database(dbConnStr, ctx.currency)
if (!maybeCreateAdminAccount(db, ctx)) // logs provided by the helper
@@ -589,9 +602,9 @@ class ChangePw : CliktCommand("Change account password", name = "passwd") {
override fun run() {
val config = TalerConfig(BANK_CONFIG_SOURCE)
config.load(this.configFile)
- val ctx = readBankApplicationContextFromConfig(config)
- val dbConnStr = config.requireValueString("libeufin-bankdb-postgres", "config")
- config.requireValueNumber("libeufin-bank", "port")
+ val ctx = BankApplicationContext.readFromConfig(config)
+ val dbConnStr = config.requireString("libeufin-bankdb-postgres", "config")
+ config.requireNumber("libeufin-bank", "port")
val db = Database(dbConnStr, ctx.currency)
if (!maybeCreateAdminAccount(db, ctx)) // logs provided by the helper
exitProcess(1)
@@ -671,14 +684,14 @@ class BankConfigGet : CliktCommand("Lookup config value", name = "get") {
val config = TalerConfig(BANK_CONFIG_SOURCE)
config.load(this.configFile)
if (isPath) {
- val res = config.lookupValuePath(sectionName, optionName)
+ val res = config.lookupPath(sectionName, optionName)
if (res == null) {
logger.info("value not found in config")
exitProcess(2)
}
println(res)
} else {
- val res = config.lookupValueString(sectionName, optionName)
+ val res = config.lookupString(sectionName, optionName)
if (res == null) {
logger.info("value not found in config")
exitProcess(2)
diff --git a/bank/src/test/kotlin/Common.kt b/bank/src/test/kotlin/Common.kt
index 7bb6e518..02e4327d 100644
--- a/bank/src/test/kotlin/Common.kt
+++ b/bank/src/test/kotlin/Common.kt
@@ -28,7 +28,7 @@ fun initDb(): Database {
// We assume that libeufin-bank is installed. We could also try to locate the source tree here.
val config = TalerConfig(ConfigSource("libeufin-bank", "libeufin-bank"))
config.load()
- val sqlPath = config.requireValuePath("libeufin-bankdb-postgres", "SQL_DIR")
+ val sqlPath = config.requirePath("libeufin-bankdb-postgres", "SQL_DIR")
val dbConnStr = "postgresql:///libeufincheck"
resetDatabaseTables(dbConnStr, sqlPath)
initializeDatabaseTables(dbConnStr, sqlPath)
diff --git a/bank/src/test/kotlin/LibeuFinApiTest.kt b/bank/src/test/kotlin/LibeuFinApiTest.kt
index 5cb98a3b..d50e3f99 100644
--- a/bank/src/test/kotlin/LibeuFinApiTest.kt
+++ b/bank/src/test/kotlin/LibeuFinApiTest.kt
@@ -569,7 +569,7 @@ class LibeuFinApiTest {
* Test admin-only account creation
*/
@Test
- fun createAccountRestrictedTest() = setup(restrictRegistration = true) { db, ctx ->
+ fun createAccountRestrictedTest() = setup(conf = "test_restrict.conf") { db, ctx ->
testApplication {
application {
corebankWebApp(db, ctx)
diff --git a/bank/src/test/kotlin/TalerApiTest.kt b/bank/src/test/kotlin/TalerApiTest.kt
index 308355ac..0d645c08 100644
--- a/bank/src/test/kotlin/TalerApiTest.kt
+++ b/bank/src/test/kotlin/TalerApiTest.kt
@@ -543,7 +543,7 @@ class TalerApiTest {
}
// Selecting withdrawal details from the Integration API endpoint.
@Test
- fun intSelect() = setup(suggestedExchange = "payto://iban/ABC123") { db, ctx ->
+ fun intSelect() = setup { db, ctx ->
val uuid = UUID.randomUUID()
assertNotNull(db.customerCreate(customerFoo))
assertNotNull(db.bankAccountCreate(bankAccountFoo))
@@ -568,7 +568,7 @@ class TalerApiTest {
}
// Showing withdrawal details from the Integrtion API endpoint.
@Test
- fun intGet() = setup(suggestedExchange = "payto://iban/ABC123") { db, ctx ->
+ fun intGet() = setup { db, ctx ->
val uuid = UUID.randomUUID()
assert(db.customerCreate(customerFoo) != null)
assert(db.bankAccountCreate(bankAccountFoo) != null)
diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt
index 413d1e45..fa10e05d 100644
--- a/bank/src/test/kotlin/helpers.kt
+++ b/bank/src/test/kotlin/helpers.kt
@@ -17,23 +17,13 @@ fun setupDb(lambda: (Database) -> Unit) {
}
fun setup(
- restrictRegistration: Boolean = false,
- suggestedExchange: String = "https://exchange.example.com",
+ conf: String = "test.conf",
lambda: (Database, BankApplicationContext) -> Unit
){
val db = initDb()
- val ctx = BankApplicationContext(
- currency = "KUDOS",
- restrictRegistration = restrictRegistration,
- cashoutCurrency = "EUR",
- defaultCustomerDebtLimit = TalerAmount(100, 0, "KUDOS"),
- defaultAdminDebtLimit = TalerAmount(10000, 0, "KUDOS"),
- registrationBonusEnabled = false,
- registrationBonus = null,
- suggestedWithdrawalExchange = suggestedExchange,
- spaCaptchaURL = null,
- restrictAccountDeletion = true
- )
+ val config = TalerConfig(BANK_CONFIG_SOURCE)
+ config.load("conf/$conf")
+ val ctx = BankApplicationContext.readFromConfig(config)
db.use {
lambda(db, ctx)
}
diff --git a/util/src/main/kotlin/TalerConfig.kt b/util/src/main/kotlin/TalerConfig.kt
index a8cf0ae0..684a8a1b 100644
--- a/util/src/main/kotlin/TalerConfig.kt
+++ b/util/src/main/kotlin/TalerConfig.kt
@@ -23,10 +23,8 @@ import kotlin.io.path.Path
import kotlin.io.path.isReadable
import kotlin.io.path.listDirectoryEntries
-private data class Entry(val value: String)
-
private data class Section(
- val entries: MutableMap<String, Entry>,
+ val entries: MutableMap<String, String>,
)
private val reEmptyLine = Regex("^\\s*$")
@@ -57,6 +55,7 @@ class TalerConfig(
private val componentName = configSource.componentName
private val installPathBinary = configSource.installPathBinary
+ val sections: Set<String> get() = sectionMap.keys
private fun internalLoadFromString(s: String, sourceFilename: String?) {
val lines = s.lines()
@@ -125,9 +124,7 @@ class TalerConfig(
optVal = optVal.substring(1, optVal.length - 1)
}
val section = provideSection(currentSection)
- section.entries[optName] = Entry(
- value = optVal
- )
+ section.entries[optName] = optVal
continue
}
throw TalerConfigError("expected section header, option assignment or directive in line $lineNum file ${sourceFilename ?: "<input>"}")
@@ -187,77 +184,15 @@ class TalerConfig(
internalLoadFromString(s, null)
}
- private fun lookupEntry(section: String, option: String): Entry? {
- val canonSection = section.uppercase()
- val canonOption = option.uppercase()
- return this.sectionMap[canonSection]?.entries?.get(canonOption)
- }
-
- /**
- * Look up a string value from the configuration.
- *
- * Return null if the value was not found in the configuration.
- */
- fun lookupValueString(section: String, option: String): String? {
- return lookupEntry(section, option)?.value
- }
-
- fun requireValueString(section: String, option: String): String {
- val entry = lookupEntry(section, option)
- if (entry == null) {
- throw TalerConfigError("expected string in configuration section $section option $option")
- }
- return entry.value
- }
-
- fun requireValueNumber(section: String, option: String): Long {
- val entry = lookupEntry(section, option)
- if (entry == null) {
- throw TalerConfigError("expected string in configuration section $section option $option")
- }
- return entry.value.toLong(10)
- }
-
- fun lookupValueBooleanDefault(section: String, option: String, default: Boolean): Boolean {
- val entry = lookupEntry(section, option)
- if (entry == null) {
- return default
- }
- val v = entry.value.lowercase()
- if (v == "yes") {
- return true;
- }
- if (v == "false") {
- return false;
- }
- throw TalerConfigError("expected yes/no in configuration section $section option $option but got $v")
- }
-
private fun setSystemDefault(section: String, option: String, value: String) {
// FIXME: The value should be marked as a system default for diagnostics pretty printing
val sec = provideSection(section)
- sec.entries[option.uppercase()] = Entry(value = value)
+ sec.entries[option.uppercase()] = value
}
fun putValueString(section: String, option: String, value: String) {
val sec = provideSection(section)
- sec.entries[option.uppercase()] = Entry(value = value)
- }
-
- fun lookupValuePath(section: String, option: String): String? {
- val entry = lookupEntry(section, option)
- if (entry == null) {
- return null
- }
- return pathsub(entry.value)
- }
-
- fun requireValuePath(section: String, option: String): String {
- val res = lookupValuePath(section, option)
- if (res == null) {
- throw TalerConfigError("expected path for section $section option $option")
- }
- return res
+ sec.entries[option.uppercase()] = value
}
/**
@@ -272,7 +207,7 @@ class TalerConfig(
outStr.appendLine("[$sectionName]")
headerWritten = true
}
- outStr.appendLine("$optionName = ${entry.value}")
+ outStr.appendLine("$optionName = $entry")
}
if (headerWritten) {
outStr.appendLine()
@@ -316,7 +251,7 @@ class TalerConfig(
}
private fun variableLookup(x: String, recursionDepth: Int = 0): String? {
- val pathRes = this.lookupValueString("PATHS", x)
+ val pathRes = this.lookupString("PATHS", x)
if (pathRes != null) {
return pathsub(pathRes, recursionDepth + 1)
}
@@ -483,4 +418,47 @@ class TalerConfig(
}
return "/usr"
}
+
+ /* ----- Lookup ----- */
+
+ /**
+ * Look up a string value from the configuration.
+ *
+ * Return null if the value was not found in the configuration.
+ */
+ fun lookupString(section: String, option: String): String? {
+ val canonSection = section.uppercase()
+ val canonOption = option.uppercase()
+ return this.sectionMap[canonSection]?.entries?.get(canonOption)
+ }
+
+ fun requireString(section: String, option: String): String =
+ lookupString(section, option) ?:
+ throw TalerConfigError("expected string in configuration section $section option $option")
+
+ fun requireNumber(section: String, option: String): Int =
+ lookupString(section, option)?.toInt() ?:
+ throw TalerConfigError("expected number in configuration section $section option $option")
+
+ fun lookupBoolean(section: String, option: String): Boolean? {
+ val entry = lookupString(section, option) ?: return null
+ return when (val v = entry.lowercase()) {
+ "yes" -> true
+ "no" -> false
+ else -> throw TalerConfigError("expected yes/no in configuration section $section option $option but got $v")
+ }
+ }
+
+ fun requireBoolean(section: String, option: String): Boolean =
+ lookupBoolean(section, option) ?:
+ throw TalerConfigError("expected boolean in configuration section $section option $option")
+
+ fun lookupPath(section: String, option: String): String? {
+ val entry = lookupString(section, option) ?: return null
+ return pathsub(entry)
+ }
+
+ fun requirePath(section: String, option: String): String =
+ lookupPath(section, option) ?:
+ throw TalerConfigError("expected path for section $section option $option")
}
diff --git a/util/src/test/kotlin/TalerConfigTest.kt b/util/src/test/kotlin/TalerConfigTest.kt
index f07edede..4be47948 100644
--- a/util/src/test/kotlin/TalerConfigTest.kt
+++ b/util/src/test/kotlin/TalerConfigTest.kt
@@ -39,7 +39,7 @@ class TalerConfigTest {
println(conf.stringify())
- assertEquals("baz", conf.lookupValueString("foo", "bar"))
+ assertEquals("baz", conf.lookupString("foo", "bar"))
println(conf.getInstallPath())
}
@@ -52,11 +52,11 @@ class TalerConfigTest {
conf.putValueString("foo", "bar", "baz")
conf.putValueString("foo", "bar2", "baz")
- assertEquals("baz", conf.lookupValueString("foo", "bar"))
- assertEquals("baz", conf.lookupValuePath("foo", "bar"))
+ assertEquals("baz", conf.lookupString("foo", "bar"))
+ assertEquals("baz", conf.lookupPath("foo", "bar"))
conf.putValueString("foo", "dir1", "foo/\$DATADIR/bar")
- assertEquals("foo/mydir/bar", conf.lookupValuePath("foo", "dir1"))
+ assertEquals("foo/mydir/bar", conf.lookupPath("foo", "dir1"))
}
}