Split validation and import.

Added validation for unused fields.
This commit is contained in:
Erik C. Thauvin 2016-08-27 17:25:15 -07:00
parent c9de7a0754
commit fa05584827
3 changed files with 85 additions and 67 deletions

View file

@ -72,10 +72,42 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
val PAUSE = ',' val PAUSE = ','
} }
@NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
fun importConfig(intent: Intent) {
val errors = StringBuilder()
val tmp: Config? = try {
Gson().fromJson(InputStreamReader(contentResolver.openInputStream(intent.data)),
Config::class.java)
} catch (jse: JsonSyntaxException) {
val cause = jse.cause
if (cause != null) {
errors.append(cause.message)
} else {
errors.append(jse.message)
}
null
}
if (tmp != null && validateConfig(tmp, errors)) {
config = tmp
saveConfig()
recreate()
}
if (errors.length > 0) {
alert {
title(R.string.alert_config_error)
message(Html.fromHtml("$errors"))
cancelButton { }
}.show()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == read_request_code && resultCode == Activity.RESULT_OK) { if (requestCode == read_request_code && resultCode == Activity.RESULT_OK) {
if (data != null) { if (data != null) {
MainActivityPermissionsDispatcher.validateConfigWithCheck(this, data) MainActivityPermissionsDispatcher.importConfigWithCheck(this, data)
} }
} }
} }
@ -271,6 +303,12 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
defaultConfigs.forEach { defaultConfigs.forEach {
config = Gson().fromJson(InputStreamReader(resources.openRawResource(it)), config = Gson().fromJson(InputStreamReader(resources.openRawResource(it)),
Config::class.java) Config::class.java)
// val errors = StringBuilder()
// if (!validateConfig(config, errors)) {
// info("${config.params.name}: $errors")
// }
confs.configs.put(config.params.name, config) confs.configs.put(config.params.name, config)
} }
@ -297,91 +335,70 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
} }
} }
@NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) fun validateConfig(config: Config, errors: StringBuilder): Boolean {
fun validateConfig(intent: Intent) { val len = errors.length
val errors = StringBuilder()
val tmp: Config? = try { with(config) {
Gson().fromJson(InputStreamReader(contentResolver.openInputStream(intent.data)), if (params.name.isBlank()) {
Config::class.java) errors.append(getString(R.string.validate_missing_param, "name"))
} catch (jse: JsonSyntaxException) {
val cause = jse.cause
if (cause != null) {
errors.append(cause.message)
} else {
errors.append(jse.message)
} }
null
}
if (tmp != null) { if (params.size < 1) {
with(tmp) { errors.append(getString(R.string.validate_invalid_param, "size"))
if (params.name.isBlank()) { }
errors.append(getString(R.string.validate_missing_param, "name"))
if (params.star.isBlank()) {
errors.append(getString(R.string.validate_missing_param, "star"))
}
if (opts.size == 0) {
errors.append(getString(R.string.validate_missing_opts))
}
opts.forEachIndexed { i, option ->
if (option.fields.size == 0) {
errors.append(getString(R.string.validate_missing_fields, i + 1))
} }
if (params.size < 1) { if (option.nosteps && option.nodial) {
errors.append(getString(R.string.validate_invalid_param, "size")) errors.append(getString(R.string.validate_invalid_option, i + 1, "nodial/nosteps"))
} }
if (params.star.isBlank()) { if (option.dtmf.isBlank()) {
errors.append(getString(R.string.validate_missing_param, "star")) errors.append(getString(R.string.validate_invalid_dtmf, i + 1, "''"))
} }
if (opts.size == 0) { option.fields.forEachIndexed { j, field ->
errors.append(getString(R.string.validate_missing_opts)) if (field.size <= 0) {
} errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "size"))
opts.forEachIndexed { i, option ->
if (option.fields.size == 0) {
errors.append(getString(R.string.validate_missing_fields, i + 1))
} }
if (option.nosteps && option.nodial) { if (!field.alpha) {
errors.append(getString(R.string.validate_invalid_option, i + 1, "nodial/nosteps")) if (field.min >= 0 || field.max >= 0) {
} if (field.max < 1) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "max"))
option.fields.forEachIndexed { j, field -> } else if (field.min < 0) {
if (field.size <= 0) { errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "min"))
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "size")) } else if (field.min > field.max) {
} errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "max/min"))
if (!field.alpha) {
if (field.min >= 0 || field.max >= 0) {
if (field.max < 1) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "max"))
} else if (field.min < 0) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "min"))
} else if (field.min > field.max) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "max/min"))
}
} }
} }
} }
val blank = "\\0" if (!option.dtmf.contains(Dtmf.DTMF_FIELD.format(j + 1))) {
val dtmf = Dtmf.mock(option, blank) errors.append(getString(R.string.validate_unused_field, i + 1, j + 1))
if (!Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.star}${params.hash}$blank")) {
errors.append(getString(R.string.validate_invalid_dtmf, i + 1, dtmf.replace(blank, "&#10003;")))
} }
} }
}
if (errors.length == 0) { val blank = "\\0"
config = tmp val dtmf = Dtmf.mock(option, blank)
saveConfig() if (!Dtmf.validate(dtmf, "${MainActivity.Companion.PAUSE}${params.star}${params.hash}$blank")) {
recreate() errors.append(getString(R.string.validate_invalid_dtmf, i + 1, dtmf.replace(blank, "&#10003;")))
}
} }
} }
if (errors.length > 0) { return errors.length == len
alert {
title(R.string.alert_config_error)
message(Html.fromHtml("$errors"))
cancelButton { }
}.show()
}
} }
fun validateFields(fields: ArrayList<EditText>, size: Int): Boolean { fun validateFields(fields: ArrayList<EditText>, size: Int): Boolean {

View file

@ -24,8 +24,8 @@ import java.util.*
class Dtmf { class Dtmf {
companion object { companion object {
private val DTMF_MASTER = "[MASTER]" val DTMF_MASTER = "[MASTER]"
private val DTMF_FIELD = "[FIELD:%1\$d]" val DTMF_FIELD = "[FIELD:%1\$d]"
private fun alphaToDigits(text: String, star: String): String { private fun alphaToDigits(text: String, star: String): String {
val result = StringBuffer() val result = StringBuffer()

View file

@ -21,4 +21,5 @@
<string name="validate_missing_fields">&lt;p>&lt;b>opts[<xliff:g id="opts">%1$d</xliff:g>]&lt;/b>: &lt;font color=\"red\">fields&lt;/font> missing</string> <string name="validate_missing_fields">&lt;p>&lt;b>opts[<xliff:g id="opts">%1$d</xliff:g>]&lt;/b>: &lt;font color=\"red\">fields&lt;/font> missing</string>
<string name="validate_missing_param">&lt;p>&lt;p>&lt;b>params&lt;/b>: &lt;font color=\"red\"><xliff:g id="param">%1$s</xliff:g>&lt;/font> missing&lt;/p></string> <string name="validate_missing_param">&lt;p>&lt;p>&lt;b>params&lt;/b>: &lt;font color=\"red\"><xliff:g id="param">%1$s</xliff:g>&lt;/font> missing&lt;/p></string>
<string name="validate_missing_opts">&lt;font color=\"red\">opts&lt;/font> missing.</string> <string name="validate_missing_opts">&lt;font color=\"red\">opts&lt;/font> missing.</string>
<string name="validate_unused_field">&lt;b>opts[<xliff:g id="opts">%1$d</xliff:g>]&lt;/b>, &lt;font color=\"red\">fields[<xliff:g id="field">%2$d</xliff:g>]&lt;/font>: unused</string>
</resources> </resources>