Skip to content

Commit 7e5a0e1

Browse files
committed
Refactor naming
1 parent 0f06153 commit 7e5a0e1

4 files changed

Lines changed: 57 additions & 56 deletions

File tree

core/src/main/kotlin/org/evomaster/core/solver/SMTConditionVisitor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.evomaster.core.solver
22

33
import org.evomaster.client.java.controller.api.dto.database.schema.TableDto
4+
import org.evomaster.core.utils.StringUtils.convertToAscii
45
import org.evomaster.dbconstraint.ast.*
56
import org.evomaster.solver.smtlib.AssertSMTNode
67
import org.evomaster.solver.smtlib.EmptySMTNode
@@ -31,7 +32,7 @@ class SMTConditionVisitor(
3132
* @return The SMT-LIB column reference string.
3233
*/
3334
private fun getColumnReference(tableName: String, columnName: String): String {
34-
return "(${SmtLibGenerator.sanitizeSmtIdentifier(columnName).uppercase()} ${SmtLibGenerator.sanitizeSmtIdentifier(tableName).lowercase()}$rowIndex)"
35+
return "(${convertToAscii(columnName).uppercase()} ${convertToAscii(tableName).lowercase()}$rowIndex)"
3536
}
3637

3738
/**

core/src/main/kotlin/org/evomaster/core/solver/SMTLibZ3DbConstraintSolver.kt

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.evomaster.core.search.gene.sql.SqlPrimaryKeyGene
2020
import org.evomaster.core.search.gene.string.StringGene
2121
import org.evomaster.core.sql.SqlAction
2222
import org.evomaster.core.sql.schema.*
23+
import org.evomaster.core.utils.StringUtils.convertToAscii
2324
import org.evomaster.solver.Z3DockerExecutor
2425
import org.evomaster.solver.smtlib.SMTLib
2526
import org.evomaster.solver.smtlib.value.*
@@ -152,42 +153,42 @@ class SMTLibZ3DbConstraintSolver() : DbConstraintSolver {
152153

153154
// Create the list of genes with the values
154155
val genes = mutableListOf<Gene>()
155-
for (columnName in columns.fields) {
156-
// columnName is the sanitized (ASCII) version from Z3; resolve back to original DB column name
157-
val originalColumn = table.columns.firstOrNull {
158-
SmtLibGenerator.sanitizeSmtIdentifier(it.name).equals(columnName, ignoreCase = true)
156+
// smtColumn is the Ascii version from SmtLib; resolve back to original DB column name
157+
for (smtColumn in columns.fields) {
158+
val dbColumn = table.columns.firstOrNull {
159+
convertToAscii(it.name).equals(smtColumn, ignoreCase = true)
159160
}
160-
val actualColumnName = originalColumn?.name ?: columnName
161+
val dbColumnName = dbColumn?.name ?: smtColumn
161162

162-
var gene: Gene = IntegerGene(actualColumnName, 0)
163-
when (val columnValue = columns.getField(columnName)) {
163+
var gene: Gene = IntegerGene(dbColumnName, 0)
164+
when (val columnValue = columns.getField(smtColumn)) {
164165
is StringValue -> {
165-
gene = if (hasColumnType(schemaDto, table, actualColumnName, "BOOLEAN")) {
166-
BooleanGene(actualColumnName, toBoolean(columnValue.value))
166+
gene = if (hasColumnType(schemaDto, table, dbColumnName, "BOOLEAN")) {
167+
BooleanGene(dbColumnName, toBoolean(columnValue.value))
167168
} else {
168-
StringGene(actualColumnName, columnValue.value)
169+
StringGene(dbColumnName, columnValue.value)
169170
}
170171
}
171172
is LongValue -> {
172-
gene = if (hasColumnType(schemaDto, table, actualColumnName, "TIMESTAMP")) {
173+
gene = if (hasColumnType(schemaDto, table, dbColumnName, "TIMESTAMP")) {
173174
val epochSeconds = columnValue.value.toLong()
174175
val localDateTime = LocalDateTime.ofInstant(
175176
Instant.ofEpochSecond(epochSeconds), ZoneOffset.UTC
176177
)
177178
val formatted = localDateTime.format(
178179
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
179180
)
180-
ImmutableDataHolderGene(actualColumnName, formatted, inQuotes = true)
181+
ImmutableDataHolderGene(dbColumnName, formatted, inQuotes = true)
181182
} else {
182-
IntegerGene(actualColumnName, columnValue.value.toInt())
183+
IntegerGene(dbColumnName, columnValue.value.toInt())
183184
}
184185
}
185186
is RealValue -> {
186-
gene = DoubleGene(actualColumnName, columnValue.value)
187+
gene = DoubleGene(dbColumnName, columnValue.value)
187188
}
188189
}
189-
if (originalColumn != null && originalColumn.primaryKey) {
190-
gene = SqlPrimaryKeyGene(actualColumnName, table.id, gene, actionId)
190+
if (dbColumn != null && dbColumn.primaryKey) {
191+
gene = SqlPrimaryKeyGene(dbColumnName, table.id, gene, actionId)
191192
}
192193
gene.markAllAsInitialized()
193194
genes.add(gene)

core/src/main/kotlin/org/evomaster/core/solver/SmtLibGenerator.kt

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import org.evomaster.core.utils.StringUtils
1515
import org.evomaster.dbconstraint.ConstraintDatabaseType
1616
import org.evomaster.dbconstraint.ast.SqlCondition
1717
import net.sf.jsqlparser.JSQLParserException
18+
import org.evomaster.core.utils.StringUtils.convertToAscii
1819
import org.evomaster.dbconstraint.parser.SqlConditionParserException
1920
import org.evomaster.dbconstraint.parser.jsql.JSqlConditionParser
2021
import org.evomaster.solver.smtlib.*
2122
import org.evomaster.solver.smtlib.assertion.*
22-
import java.util.*
2323

2424
/**
2525
* Generates SMT-LIB constraints from SQL queries and schema definitions.
@@ -58,7 +58,7 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
5858
*/
5959
private fun appendTableDefinitions(smt: SMTLib) {
6060
for (table in schema.tables) {
61-
val sanitizedTableName = sanitizeSmtIdentifier(table.id.name)
61+
val sanitizedTableName = convertToAscii(table.id.name)
6262
val dataTypeName = "${StringUtils.capitalization(sanitizedTableName)}Row"
6363

6464
// Declare datatype for the table
@@ -92,10 +92,10 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
9292
* @param table The table for which unique constraints are added.
9393
*/
9494
private fun appendUniqueConstraints(smt: SMTLib, table: TableDto) {
95-
val tableName = sanitizeSmtIdentifier(table.id.name).lowercase()
95+
val tableName = convertToAscii(table.id.name).lowercase()
9696
for (column in table.columns) {
9797
if (column.unique) {
98-
val nodes = assertForDistinctField(sanitizeSmtIdentifier(column.name), tableName)
98+
val nodes = assertForDistinctField(convertToAscii(column.name), tableName)
9999
smt.addNodes(nodes)
100100
}
101101
}
@@ -132,7 +132,7 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
132132
* @return The corresponding SMT node.
133133
*/
134134
private fun parseCheckExpression(table: TableDto, condition: SqlCondition, index: Int): SMTNode {
135-
val visitor = SMTConditionVisitor(sanitizeSmtIdentifier(table.id.name).lowercase(), emptyMap(), schema.tables, index)
135+
val visitor = SMTConditionVisitor(convertToAscii(table.id.name).lowercase(), emptyMap(), schema.tables, index)
136136
return condition.accept(visitor, null) as SMTNode
137137
}
138138

@@ -168,10 +168,10 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
168168

169169
private fun appendBooleanConstraints(smt: SMTLib) {
170170
for (table in schema.tables) {
171-
val tableName = sanitizeSmtIdentifier(table.id.name).lowercase()
171+
val tableName = convertToAscii(table.id.name).lowercase()
172172
for (column in table.columns) {
173173
if (column.type.equals("BOOLEAN", ignoreCase = true)) {
174-
val columnName = sanitizeSmtIdentifier(column.name).uppercase()
174+
val columnName = convertToAscii(column.name).uppercase()
175175
for (i in 1..numberOfRows) {
176176
smt.addNode(
177177
AssertSMTNode(
@@ -195,10 +195,10 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
195195

196196
private fun appendTimestampConstraints(smt: SMTLib) {
197197
for (table in schema.tables) {
198-
val tableName = sanitizeSmtIdentifier(table.id.name).lowercase()
198+
val tableName = convertToAscii(table.id.name).lowercase()
199199
for (column in table.columns) {
200200
if (column.type.equals("TIMESTAMP", ignoreCase = true)) {
201-
val columnName = sanitizeSmtIdentifier(column.name).uppercase()
201+
val columnName = convertToAscii(column.name).uppercase()
202202
val lowerBound = 0 // Example for Unix epoch start
203203
val upperBound = 32503680000 // Example for year 3000 in seconds
204204

@@ -233,11 +233,11 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
233233
* @param table The table for which primary key constraints are added.
234234
*/
235235
private fun appendPrimaryKeyConstraints(smt: SMTLib, table: TableDto) {
236-
val tableName = sanitizeSmtIdentifier(table.id.name).lowercase()
236+
val tableName = convertToAscii(table.id.name).lowercase()
237237
val primaryKeys = table.columns.filter { it.primaryKey }
238238

239239
for (primaryKey in primaryKeys) {
240-
val nodes = assertForDistinctField(sanitizeSmtIdentifier(primaryKey.name), tableName)
240+
val nodes = assertForDistinctField(convertToAscii(primaryKey.name), tableName)
241241
smt.addNodes(nodes)
242242
}
243243
}
@@ -275,16 +275,16 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
275275
* @param table The table for which foreign key constraints are added.
276276
*/
277277
private fun appendForeignKeyConstraints(smt: SMTLib, table: TableDto) {
278-
val sourceTableName = sanitizeSmtIdentifier(table.id.name).lowercase()
278+
val sourceTableName = convertToAscii(table.id.name).lowercase()
279279

280280
for (foreignKey in table.foreignKeys) {
281281
val referencedTable = findReferencedTable(foreignKey)
282-
val referencedTableName = sanitizeSmtIdentifier(referencedTable.id.name).lowercase()
283-
val referencedColumnSelector = sanitizeSmtIdentifier(findReferencedPKSelector(table, referencedTable, foreignKey))
282+
val referencedTableName = convertToAscii(referencedTable.id.name).lowercase()
283+
val referencedColumnSelector = convertToAscii(findReferencedPKSelector(table, referencedTable, foreignKey))
284284

285285
for (sourceColumn in foreignKey.sourceColumns) {
286286
val nodes = assertForEqualsAny(
287-
sanitizeSmtIdentifier(sourceColumn), sourceTableName,
287+
convertToAscii(sourceColumn), sourceTableName,
288288
referencedColumnSelector, referencedTableName
289289
)
290290
smt.addNodes(nodes)
@@ -435,7 +435,7 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
435435
* @return The corresponding SMT node.
436436
*/
437437
private fun parseQueryCondition(tableAliases: Map<String, String>, defaultTableName: String, condition: SqlCondition, index: Int): SMTNode {
438-
val visitor = SMTConditionVisitor(sanitizeSmtIdentifier(defaultTableName), tableAliases, schema.tables, index)
438+
val visitor = SMTConditionVisitor(convertToAscii(defaultTableName), tableAliases, schema.tables, index)
439439
return condition.accept(visitor, null) as SMTNode
440440
}
441441

@@ -520,10 +520,10 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
520520
// Only add GetValueSMTNode for the mentioned tables
521521
for (table in schema.tables) {
522522
val tableNameLower = table.id.name.lowercase()
523-
val sanitizedTableNameLower = sanitizeSmtIdentifier(tableNameLower)
523+
val smtColumnName = convertToAscii(tableNameLower)
524524
if (tablesMentioned.contains(tableNameLower)) {
525525
for (i in 1..numberOfRows) {
526-
smt.addNode(GetValueSMTNode("$sanitizedTableNameLower$i"))
526+
smt.addNode(GetValueSMTNode("$smtColumnName$i"))
527527
}
528528
}
529529
}
@@ -539,29 +539,11 @@ class SmtLibGenerator(private val schema: DbInfoDto, private val numberOfRows: I
539539
return table.columns.map { c ->
540540
val smtType = TYPE_MAP[c.type.uppercase()]
541541
?: throw RuntimeException("Unsupported column type: ${c.type}")
542-
DeclareConstSMTNode(sanitizeSmtIdentifier(c.name), smtType)
542+
DeclareConstSMTNode(convertToAscii(c.name), smtType)
543543
}
544544
}
545545

546546
companion object {
547-
/**
548-
* Replaces non-ASCII characters in a name to make it a valid SMT-LIB identifier.
549-
* SMT-LIB unquoted symbols are restricted to ASCII, so characters like Æ, Ø, Å must be transliterated.
550-
*
551-
* This is needed because our test suite includes Norwegian APIs whose database schemas
552-
* contain column and table names with Norwegian characters (Æ, Ø, Å).
553-
*
554-
* Characters that do not decompose under NFD (Ø, Æ) are replaced explicitly.
555-
* Characters that decompose under NFD (Å→A, and other accented letters like é, ü, ñ)
556-
* are handled by normalizing to NFD form and stripping the remaining non-ASCII combining marks.
557-
*/
558-
fun sanitizeSmtIdentifier(name: String): String {
559-
val replaced = name
560-
.replace('Ø', 'O').replace('ø', 'o')
561-
.replace("Æ", "AE").replace("æ", "ae")
562-
return java.text.Normalizer.normalize(replaced, java.text.Normalizer.Form.NFD)
563-
.replace(Regex("[^\\x00-\\x7F]"), "")
564-
}
565547

566548
// Maps database column types to SMT-LIB types
567549
private val TYPE_MAP = mapOf(

core/src/main/kotlin/org/evomaster/core/utils/StringUtils.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.evomaster.core.utils
22

3-
import java.util.*
4-
53
object StringUtils {
64

75
/**
@@ -82,4 +80,23 @@ object StringUtils {
8280
}
8381
return lines
8482
}
83+
84+
/**
85+
* Replaces non-ASCII characters in a name to make it a valid SMT-LIB identifier.
86+
* SMT-LIB unquoted symbols are restricted to ASCII, so characters like Æ, Ø, Å must be transliterated.
87+
*
88+
* This is needed because our test suite includes Norwegian APIs whose database schemas
89+
* contain column and table names with Norwegian characters (Æ, Ø, Å).
90+
*
91+
* Characters that do not decompose under NFD (Ø, Æ) are replaced explicitly.
92+
* Characters that decompose under NFD (Å→A, and other accented letters like é, ü, ñ)
93+
* are handled by normalizing to NFD form and stripping the remaining non-ASCII combining marks.
94+
*/
95+
fun convertToAscii(name: String): String {
96+
val replaced = name
97+
.replace('Ø', 'O').replace('ø', 'o')
98+
.replace("Æ", "AE").replace("æ", "ae")
99+
return java.text.Normalizer.normalize(replaced, java.text.Normalizer.Form.NFD)
100+
.replace(Regex("[^\\x00-\\x7F]"), "")
101+
}
85102
}

0 commit comments

Comments
 (0)