Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/LS25000142/Fix concurrence between DS and File #696

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
4bab1c6
Implemented test
davidepalladino-apuliasoft Jan 13, 2025
7df9a4a
Improved test for more readable
davidepalladino-apuliasoft Jan 15, 2025
a182782
Improved `DbMock` for using mocked values for DB.
davidepalladino-apuliasoft Jan 15, 2025
c832676
Improved `executeMUDRNRAPU00189` by adding mocked values
davidepalladino-apuliasoft Jan 15, 2025
dfab296
Updated test doc
davidepalladino-apuliasoft Jan 15, 2025
d90f13f
Added a new test (`MUDRNRAPU00190`) which writes to a field of DS wit…
davidepalladino-apuliasoft Jan 15, 2025
8d12b57
Improved `MUDRNRAPU00190`
davidepalladino-apuliasoft Jan 15, 2025
f5a263f
Merged develop
davidepalladino-apuliasoft Jan 16, 2025
2290f1d
Merge branch 'develop' into bugfix/LS25000142/fix-concurrence-between…
davidepalladino-apuliasoft Jan 21, 2025
84b1037
Implemented a logic to filter the file fields on root of CU `DataDefi…
davidepalladino-apuliasoft Jan 21, 2025
dbbd697
Fixed data resolution in `SymbolTable` by finding it in fields of DS …
davidepalladino-apuliasoft Jan 21, 2025
eb3ce4b
Made `MUTE13_41` test as ignored
davidepalladino-apuliasoft Jan 22, 2025
bc69628
Improved filter for `SymbolTable.dataDefinitionByName`
davidepalladino-apuliasoft Jan 23, 2025
e6e648d
Prepared blank `SymbolTableTest`
davidepalladino-apuliasoft Jan 24, 2025
5fd9b2e
Moved `DbMock` into `utils` folder for next utilization
davidepalladino-apuliasoft Jan 24, 2025
40a45b0
Made `ST01` metadata
davidepalladino-apuliasoft Jan 24, 2025
a01bdf0
Made `STDSUNQUALIFIED1` test
davidepalladino-apuliasoft Jan 24, 2025
dd65e57
Made `STDSCHAIN1` test
davidepalladino-apuliasoft Jan 24, 2025
8f2767b
Made `STFCHAIN1` test
davidepalladino-apuliasoft Jan 24, 2025
d9f38dd
Resolved issue after Kotlin Check
davidepalladino-apuliasoft Jan 24, 2025
514ea57
Merge branch 'develop' into bugfix/LS25000142/fix-concurrence-between…
davidepalladino-apuliasoft Jan 24, 2025
54e1620
Removed `dbMock` folder from `interpreter` folder and its metadata fr…
davidepalladino-apuliasoft Jan 24, 2025
8ffe701
Updated `STDSCHAIN1` to `ST_F_WITH_DS_UNQUALIFIED1`
davidepalladino-apuliasoft Jan 24, 2025
ddc52bd
Removed `STDSUNQUALIFIED1` and `SFTCHAIN1`
davidepalladino-apuliasoft Jan 24, 2025
d2de59d
Made `ST_F_WITH_DS_UNQUALIFIED2` test
davidepalladino-apuliasoft Jan 24, 2025
24ec37b
Provided DOC
davidepalladino-apuliasoft Jan 24, 2025
2be1fce
Merge branch 'develop' into bugfix/LS25000142/fix-concurrence-between…
davidepalladino-apuliasoft Jan 24, 2025
d1da782
Typo
davidepalladino-apuliasoft Jan 24, 2025
19bcc62
Typo
davidepalladino-apuliasoft Jan 24, 2025
39935dc
Made `ST_F_WITHOUT_DS1`
davidepalladino-apuliasoft Jan 24, 2025
a463c7b
Implemented the only one performance test for `SymbolTableTest`
davidepalladino-apuliasoft Jan 27, 2025
28f5dfe
Improved `dataDefinitionByName` for performance
davidepalladino-apuliasoft Jan 27, 2025
37f0f0d
Renamed test related to performance
davidepalladino-apuliasoft Jan 27, 2025
02ecdf1
Made test with assertions for the same RGP source.
davidepalladino-apuliasoft Jan 27, 2025
d1fd408
Renamed `predicate` into `testExecution` for `DbMock`
davidepalladino-apuliasoft Jan 27, 2025
af6325a
Added reason for `executeMUTE13_41`
davidepalladino-apuliasoft Jan 27, 2025
8e9b390
Added new fields to DS
davidepalladino-apuliasoft Jan 27, 2025
208cd02
Improved performance test by adding ratio result
davidepalladino-apuliasoft Jan 27, 2025
f6377f4
Introduced another DS
davidepalladino-apuliasoft Jan 27, 2025
31bd6e9
Improved test execution
davidepalladino-apuliasoft Jan 27, 2025
f2011f0
Restored decorator fot performance test
davidepalladino-apuliasoft Jan 27, 2025
c03f740
Fixed assertion
davidepalladino-apuliasoft Jan 27, 2025
8ae5c08
Improved DbMock
davidepalladino-apuliasoft Jan 27, 2025
7f01a90
Removed timeout from Test decorator by using a sum
davidepalladino-apuliasoft Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,25 @@ class SymbolTable : ISymbolTable {
if (MainExecutionContext.isLoggingEnabled) getWithLogging(dataName) else getInternal(dataName)

override fun dataDefinitionByName(dataName: String): AbstractDataDefinition? {
lanarimarco marked this conversation as resolved.
Show resolved Hide resolved
return names[dataName.uppercase()] ?: parentSymbolTable?.let { (parentSymbolTable as SymbolTable).names[dataName.uppercase()] }
/*
* In order, try to resolve a Data Definition, by its name and by finding it:
* 1. in root because might be a Data Definition;
* 2. in DS declared as not `QUALIFIED` because might be a Field Definition with access without dot notation. In this
* case will be added in `names` if found.
* 3. in parent Symbol Table.
*/
return names.compute(dataName.uppercase()) { key, value ->
value ?: names
.asSequence()
.filter { name ->
name.value.type is DataStructureType &&
!(name.value.type as AbstractDataStructureType).isQualified &&
name.value is DataDefinition
}
.map { it.value }
.flatMap { dataStructure -> (dataStructure as DataDefinition).fields }
.firstOrNull { field -> field.name.equals(key, ignoreCase = true) } as AbstractDataDefinition?
} ?: parentSymbolTable?.let { (parentSymbolTable as SymbolTable).names[dataName.uppercase()] }
}

override operator fun set(data: AbstractDataDefinition, value: Value): Value? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ private fun List<StatementContext?>.getDataDefinition(
fileDefinitions = fileDefinitions
)
}
dataDefinitionProviders.addAll(firstPassProviders)
dataDefinitionProviders
.removeFileFieldsDefinedInDs(firstPassProviders)
.addAll(firstPassProviders)

// Second pass, everything, I mean everything
val secondPassProviders = sortedStatements.getValidDataDefinitionHolders(
Expand All @@ -156,6 +158,27 @@ private fun List<StatementContext?>.getDataDefinition(
return Pair(dataDefinitionProviders, knownDataDefinitions)
}

/**
* Removes file fields from the root of the `dataDefinitionProviders` when they are also defined in a data structure (DS)
* that uses `EXTNAME` in RPG, ensuring that field manipulations apply to both the file and the DS.
*
* The function scans through `firstPassProviders`, extracts the fields, filters out those not of `RecordFormatType`,
* and removes corresponding file fields from the mutable list to avoid redundancy and potential conflicts.
*
* @param firstPassProviders a list of `DataDefinitionProvider` objects from the first pass to extract fields from
* @return the updated mutable list with the file fields removed, ensuring only the DS manages those fields
*/
private fun MutableList<DataDefinitionProvider>.removeFileFieldsDefinedInDs(firstPassProviders: List<DataDefinitionProvider>): MutableList<DataDefinitionProvider> {
firstPassProviders
.flatMap { provider -> provider.toDataDefinition().fields }
.filter { field -> field.type !is RecordFormatType }
.forEach { field ->
this.removeIf { provider -> provider.toDataDefinition().name.equals(field.name, ignoreCase = true) }
}

return this
}

private fun List<StatementContext>.getValidDataDefinitionHolders(
conf: ToAstConfiguration = ToAstConfiguration(),
knownDataDefinitions: KnownDataDefinitionInstance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ open class MuteExecutionTest : AbstractTest() {
}

@Test
@Ignore("Until is improved Encode/Decode to/from Packed")
fun executeMUTE13_41() {
executePgm("mute/MUTE13_41", configuration = smeupConfig)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -672,15 +672,15 @@ class JarikoCallbackTest : AbstractTest() {
*/
@Test
fun executeERROR36CallBackTest() {
TABDS01LDbMock().usePopulated {
TABDS01LDbMock().usePopulated({
executePgmCallBackTest(
pgm = "ERROR36",
sourceReferenceType = SourceReferenceType.Program,
sourceId = "ERROR36",
lines = listOf(6),
reloadConfig = it.createReloadConfig()
)
}
})
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package com.smeup.rpgparser.interpreter

import com.smeup.rpgparser.AbstractTest
import com.smeup.rpgparser.PerformanceTest
import com.smeup.rpgparser.parsing.ast.CompilationUnit
import org.junit.experimental.categories.Category
import kotlin.test.*
import kotlin.time.DurationUnit
import kotlin.time.measureTime

/**
* The purpose of this test suite is to validate the behaviour around Symbol Table.
* The resources about this suite starts with `ST` (Symbol Table), followed by any string which describes the purpose.
*/
class SymbolTableTest : AbstractTest() {
/**
* Performance test for accessing standalone fields and data structure fields in a symbol table.
*
* This test measures the execution time required to perform repeated lookups of standalone fields and
* data structure fields in a symbol table created from an Abstract Syntax Tree (AST). It verifies that
* the AST can be produced successfully and evaluates the performance of symbol table lookups for
* specific fields.
*
* Steps:
* 1. Produce an AST from the specified example program (`symboltable/ST_PERFORMANCE_ACCESS01`).
* 2. Create a symbol table (`ISymbolTable`) from the AST.
* 3. Perform 1,000,000 lookups for the standalone field `VAR1`.
* 4. Perform 1,000,000 lookups for the last field of the data structure `DS10_FLD50`.
* 5. Measure and log the total execution time for these operations.
*
* The goal is to evaluate the efficiency of symbol table lookups and ensure performance is within an acceptable range.
*
* @throws TimeoutException if the test does not complete within 6 seconds
* @see ISymbolTable
*/
@Test
@Category(PerformanceTest::class)
fun executeST_F_WITH_DS_UNQUALIFIED1_PERFORMANCE() {
assertASTCanBeProduced(
lanarimarco marked this conversation as resolved.
Show resolved Hide resolved
exampleName = "symboltable/ST_PERFORMANCE_ACCESS01",
afterAstCreation = { ast ->
val symbolTable: ISymbolTable = ast.createSymbolTable()

val timeVAR1 = measureTime {
for (i in 1..1_000_000) {
symbolTable.dataDefinitionByName("VAR1")
}
}.also { time ->
println("Time execution during the resolution of VAR1: $time")
}

val timeDS10_FLD50 = measureTime {
for (i in 1..1_000_000) {
symbolTable.dataDefinitionByName("DS10_FLD50")
}
}.also { time ->
println("Time execution during the resolution of DS10_FLD50: $time")
}

println("Ratio execution during the resolution of Standalone and DS field: ${timeVAR1 / timeDS10_FLD50}")

assertTrue((timeVAR1 + timeDS10_FLD50).toLong(DurationUnit.MILLISECONDS) < 3000)
}
)
}

/**
* Test for validating symbol table lookups of standalone fields and data structure fields.
*
* This test verifies the correctness of symbol table entries for:
* 1. A standalone field (`VAR1`).
* 2. Fields within a data structure (`DS10_FLD50` and `DS10_FLD51`).
*
* Steps:
* 1. Produce an Abstract Syntax Tree (AST) from the example program `symboltable/ST_PERFORMANCE_ACCESS01`.
* 2. Create a symbol table (`ISymbolTable`) from the AST.
* 3. Perform lookups for:
* - `VAR1`: A standalone field expected to be found as a `DataDefinition`.
* - `DS10_FLD50`: A field in the data structure `DS1`, expected to be found as a `FieldDefinition`.
* - `DS10_FLD51`: Another field, expected not to exist in the symbol table (returns `null`).
* 4. Assert the types and properties of the retrieved definitions:
* - Verify `VAR1` is a `DataDefinition`.
* - Verify `DS10_FLD50` is a `FieldDefinition` and belongs to the parent data structure `DS1`.
* - Verify `DS10_FLD51` is not found in the symbol table (`null`).
*
* Assertions:
* - The type and parent relationships of the retrieved definitions are validated.
* - The name of the parent data structure for `DS10_FLD50` is confirmed as `DS1`.
* - It is asserted that `DS10_FLD51` does not exist in the symbol table.
*
* @see ISymbolTable
* @see DataDefinition
* @see FieldDefinition
*/
@Test
fun executeST_F_WITH_DS_UNQUALIFIED1() {
assertASTCanBeProduced(
exampleName = "symboltable/ST_PERFORMANCE_ACCESS01",
afterAstCreation = { ast ->
val symbolTable: ISymbolTable = ast.createSymbolTable()

val dataDefinition = symbolTable.dataDefinitionByName("VAR1")
val fieldDefinition1 = symbolTable.dataDefinitionByName("DS10_FLD50")
val fieldDefinition2 = symbolTable.dataDefinitionByName("DS10_FLD51")

assertIs<DataDefinition>(dataDefinition)
assertIs<FieldDefinition>(fieldDefinition1)
assertIs<DataDefinition>(fieldDefinition1.parent)
assertEquals("DS10", (fieldDefinition1.parent as DataDefinition).name, "DS10_FLD50 is field DS1.")
assertNull(fieldDefinition2, "DS10_FLD51 field not found.")
}
)
}

/**
* Creates a symbol table for the current `CompilationUnit`, mapping each `DataDefinition` to its corresponding `Value`.
*
* The symbol table (`ISymbolTable`) acts as a container for `DataDefinition`-to-`Value` mappings.
* For each `DataDefinition` in the `CompilationUnit`, this function generates a pair consisting of:
* - The `DataDefinition` as the key.
* - The associated `Value`, which is either the default value of the `DataDefinition` or a blank value based on its type.
*
* @return an `ISymbolTable` containing mappings of all `DataDefinition` objects in the `CompilationUnit`
*/
private fun CompilationUnit.createSymbolTable(): ISymbolTable {
val symbolTable: ISymbolTable = SymbolTable()
for (pair in this.dataDefinitions.map { dataDefinition -> makePairDataDefinitionValue(dataDefinition) }) {
symbolTable[pair.first] = pair.second
}

return symbolTable
}

/**
* Creates a key-value pair for a `DataDefinition` and its associated `Value`.
*
* This function takes a `DataDefinition` and generates a pair consisting of:
* - The `DataDefinition` itself as the key.
* - The associated `Value`, which is determined as follows:
* - If the `DataDefinition` has a `defaultValue`, that is used.
* - Otherwise, a blank value is generated based on the `DataDefinition`'s type.
*
* @param dataDefinition the `DataDefinition` for which the key-value pair is created
* @return a `Pair` where the key is the `DataDefinition` and the value is the associated `Value`
*/
private fun makePairDataDefinitionValue(dataDefinition: DataDefinition): Pair<DataDefinition, Value> {
return Pair(
dataDefinition,
dataDefinition.defaultValue ?: dataDefinition.type.blank()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,13 @@ open class MULANGT02ConstAndDSpecTest : MULANGTTest() {
*/
@Test
fun executeMUDRNRAPU00101() {
MULANGTLDbMock().usePopulated {
MULANGTLDbMock().usePopulated({
val expected = listOf("HELLO THERE")
assertEquals(
expected = expected,
"smeup/MUDRNRAPU00101".outputOf(configuration = smeupConfig)
)
}
})
}

/**
Expand Down Expand Up @@ -269,10 +269,10 @@ open class MULANGT02ConstAndDSpecTest : MULANGTTest() {

@Test
fun executeMUDRNRAPU00202() {
MULANGTLDbMock().usePopulated {
MULANGTLDbMock().usePopulated({
val expected = listOf("ok")
assertEquals(expected, "smeup/MUDRNRAPU00202".outputOf(configuration = smeupConfig))
}
})
}

/**
Expand Down Expand Up @@ -861,6 +861,20 @@ open class MULANGT02ConstAndDSpecTest : MULANGTTest() {
assertEquals(expected, "smeup/MUDRNRAPU00171".outputOf(configuration = turnOnZAddLegacyFlagConfig))
}

/**
* Writing on a field of DS which use `EXTNAME` of a file.
* @see #LS25000142
*/
@Test
fun executeMUDRNRAPU00189() {
MULANGTLDbMock().usePopulated({
val expected = listOf("IBMI", "", "IBMI", "MULANGT00", "", "", "IBMI", "MULANGT00")
assertEquals(expected, "smeup/MUDRNRAPU00189".outputOf(configuration = smeupConfig))
},
listOf(mapOf("MLSYST" to "IBMI", "MLPROG" to "MULANGT00"))
)
}

/**
* Reading from a field of DS with dot notation. This DS have the same fields of another.
* @see #LS25000142
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,9 +421,9 @@ open class MULANGT10BaseCodopTest : MULANGTTest() {
@Test
fun executeMUDRNRAPU00272() {
val expected = listOf("ok", "ok", "ok", "ok")
C5ADFF9LDbMock().usePopulated {
C5ADFF9LDbMock().usePopulated({
assertEquals(expected, "smeup/MUDRNRAPU00272".outputOf(configuration = smeupConfig))
}
})
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ open class MULANGT50FileAccess1Test : MULANGTTest() {

@Test
fun executeMUDRNRAPU00254() {
MULANGTLDbMock().usePopulated {
MULANGTLDbMock().usePopulated({
val expected = listOf("1.000000000")
assertEquals(expected, "smeup/MUDRNRAPU00254".outputOf(configuration = smeupConfig))
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.smeup.rpgparser.smeup.dbmock

import com.smeup.rpgparser.interpreter.FileMetadata
import com.smeup.rpgparser.utils.DbMock
import java.io.File

class C5ADFF9LDbMock : DbMock {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.smeup.rpgparser.smeup.dbmock

import com.smeup.rpgparser.interpreter.FileMetadata
import com.smeup.rpgparser.utils.DbMock
import java.io.File

class MULANGTLDbMock : DbMock {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.smeup.rpgparser.smeup.dbmock

import com.smeup.rpgparser.interpreter.FileMetadata
import com.smeup.rpgparser.utils.DbMock
import java.io.File

class TABDS01LDbMock : DbMock {
Expand Down
Loading
Loading