Added test to ensure countable parameters are proper parameter types

This commit is contained in:
yairm210 2025-04-07 10:47:28 +03:00
parent 407685f7df
commit 80e6e7a548
3 changed files with 75 additions and 63 deletions

View File

@ -29,7 +29,7 @@ interface ICountable {
* Contains all knowledge about how to check and evaluate [countable Unique parameters][UniqueParameterType.Countable].
*
* Expansion instructions:
* - A new simple "variable" needs to implement only [simpleName] and [eval].
* - A new simple "variable" needs to implement only [text] and [eval].
* - A new "variable" _using placeholder(s)_ needs to implement [matches] and [eval].
* - Using [simpleName] inside [validate] as the examples do is only done for readability.
* - Implement [getErrorSeverity] in most cases, use [UniqueParameterType] to validate each placeholder content.
@ -39,7 +39,7 @@ interface ICountable {
* implementation, then a new instance here that delegates all its methods to that object. And delete these lines.
*/
enum class Countables(
protected val simpleName: String = "",
val text: String = "",
private val shortDocumentation: String = "",
open val documentationStrings: List<String> = emptyList()
) : ICountable {
@ -169,25 +169,25 @@ enum class Countables(
}
}
;
val placeholderText = simpleName.getPlaceholderText()
val placeholderText = text.getPlaceholderText()
val noPlaceholders = simpleName.isNotEmpty() && !simpleName.contains('[')
val noPlaceholders = text.isNotEmpty() && !text.contains('[')
// Leave these in place only for the really simple cases
override fun matches(parameterText: String) = if (noPlaceholders) parameterText == simpleName
override fun matches(parameterText: String) = if (noPlaceholders) parameterText == text
else parameterText.equalsPlaceholderText(placeholderText)
override fun getKnownValuesForAutocomplete(ruleset: Ruleset) = setOf(simpleName)
override fun getKnownValuesForAutocomplete(ruleset: Ruleset) = setOf(text)
open val documentationHeader get() =
simpleName + (if (shortDocumentation.isEmpty()) "" else " - $shortDocumentation")
"`$text`" + (if (shortDocumentation.isEmpty()) "" else " - $shortDocumentation")
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset): UniqueType.UniqueParameterErrorSeverity? {
if (this == Integer) return UniqueParameterType.Number.getErrorSeverity(parameterText, ruleset)
if (!simpleName.contains('[')) {
if (parameterText == simpleName) return null
if (!text.contains('[')) {
if (parameterText == text) return null
else return UniqueType.UniqueParameterErrorSeverity.RulesetInvariant
} else {
val placeholderParameters = simpleName.getPlaceholderParameters()
val placeholderParameters = text.getPlaceholderParameters()
var worstErrorSeverity: UniqueType.UniqueParameterErrorSeverity? = null
for ((index, parameter) in placeholderParameters.withIndex()) {
val parameterType = UniqueParameterType.safeValueOf(parameter)
@ -206,7 +206,7 @@ enum class Countables(
fun getMatching(parameterText: String, ruleset: Ruleset?) = Countables.entries
.filter {
if (it.matchesWithRuleset) it.matches(parameterText, ruleset!!) else it.matches(parameterText)
}
}
fun getCountableAmount(parameterText: String, stateForConditionals: StateForConditionals): Int? {
val ruleset = stateForConditionals.gameInfo?.ruleset

View File

@ -138,12 +138,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Gain enough Faith for a Pantheon"
Applicable to: Triggerable
??? example "Gain enough Faith for [amount]% of a Great Prophet"
??? example "Gain enough Faith for [positiveAmount]% of a Great Prophet"
Example: "Gain enough Faith for [3]% of a Great Prophet"
Applicable to: Triggerable
??? example "Gain control over [tileFilter] tiles in a [amount]-tile radius"
??? example "Gain control over [tileFilter] tiles in a [nonNegativeAmount]-tile radius"
Example: "Gain control over [Farm] tiles in a [3]-tile radius"
Applicable to: Triggerable
@ -158,7 +158,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Triggerable
??? example "Promotes all spies [amount] time(s)"
??? example "Promotes all spies [positiveAmount] time(s)"
Example: "Promotes all spies [3] time(s)"
Applicable to: Triggerable
@ -243,12 +243,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: UnitTriggerable
??? example "[unitTriggerTarget] gains [amount] movement"
??? example "[unitTriggerTarget] gains [positiveAmount] movement"
Example: "[This Unit] gains [3] movement"
Applicable to: UnitTriggerable
??? example "[unitTriggerTarget] loses [amount] movement"
??? example "[unitTriggerTarget] loses [positiveAmount] movement"
Example: "[This Unit] loses [3] movement"
Applicable to: UnitTriggerable
@ -289,18 +289,18 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, FollowerBelief
??? example "[stats] per [amount] population [cityFilter]"
??? example "[stats] per [positiveAmount] population [cityFilter]"
Example: "[+1 Gold, +2 Production] per [3] population [in all cities]"
Applicable to: Global, FollowerBelief
??? example "[stats] per [amount] social policies adopted"
??? example "[stats] per [positiveAmount] social policies adopted"
Only works for civ-wide stats
Example: "[+1 Gold, +2 Production] per [3] social policies adopted"
Applicable to: Global
??? example "[stats] per every [amount] [civWideStat]"
??? example "[stats] per every [positiveAmount] [civWideStat]"
Example: "[+1 Gold, +2 Production] per every [3] [Gold]"
Applicable to: Global
@ -405,12 +405,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, Unit
??? example "Military Units gifted from City-States start with [amount] XP"
??? example "Military Units gifted from City-States start with [positiveAmount] XP"
Example: "Military Units gifted from City-States start with [3] XP"
Applicable to: Global
??? example "Militaristic City-States grant units [amount] times as fast when you are at war with a common nation"
??? example "Militaristic City-States grant units [positiveAmount] times as fast when you are at war with a common nation"
Example: "Militaristic City-States grant units [3] times as fast when you are at war with a common nation"
Applicable to: Global
@ -420,7 +420,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global
??? example "Can spend Gold to annex or puppet a City-State that has been your Ally for [amount] turns"
??? example "Can spend Gold to annex or puppet a City-State that has been your Ally for [nonNegativeAmount] turns"
Example: "Can spend Gold to annex or puppet a City-State that has been your Ally for [3] turns"
Applicable to: Global
@ -507,22 +507,22 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Enables construction of Spaceship parts"
Applicable to: Global
??? example "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount])"
??? example "May buy [baseUnitFilter] units for [nonNegativeAmount] [stat] [cityFilter] at an increasing price ([amount])"
Example: "May buy [Melee] units for [3] [Culture] [in all cities] at an increasing price ([3])"
Applicable to: Global, FollowerBelief
??? example "May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] at an increasing price ([amount])"
??? example "May buy [buildingFilter] buildings for [nonNegativeAmount] [stat] [cityFilter] at an increasing price ([amount])"
Example: "May buy [Culture] buildings for [3] [Culture] [in all cities] at an increasing price ([3])"
Applicable to: Global, FollowerBelief
??? example "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter]"
??? example "May buy [baseUnitFilter] units for [nonNegativeAmount] [stat] [cityFilter]"
Example: "May buy [Melee] units for [3] [Culture] [in all cities]"
Applicable to: Global, FollowerBelief
??? example "May buy [buildingFilter] buildings for [amount] [stat] [cityFilter]"
??? example "May buy [buildingFilter] buildings for [nonNegativeAmount] [stat] [cityFilter]"
Example: "May buy [Culture] buildings for [3] [Culture] [in all cities]"
Applicable to: Global, FollowerBelief
@ -537,12 +537,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, FollowerBelief
??? example "May buy [baseUnitFilter] units with [stat] for [amount] times their normal Production cost"
??? example "May buy [baseUnitFilter] units with [stat] for [nonNegativeAmount] times their normal Production cost"
Example: "May buy [Melee] units with [Culture] for [3] times their normal Production cost"
Applicable to: Global, FollowerBelief
??? example "May buy [buildingFilter] buildings with [stat] for [amount] times their normal Production cost"
??? example "May buy [buildingFilter] buildings with [stat] for [nonNegativeAmount] times their normal Production cost"
Example: "May buy [Culture] buildings with [Culture] for [3] times their normal Production cost"
Applicable to: Global, FollowerBelief
@ -685,7 +685,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global
??? example "[amount] Unit Supply per [amount] population [cityFilter]"
??? example "[amount] Unit Supply per [positiveAmount] population [cityFilter]"
Example: "[3] Unit Supply per [3] population [in all cities]"
Applicable to: Global
@ -718,7 +718,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
Applicable to: Global
??? example "Enemy [mapUnitFilter] units must spend [amount] extra movement points when inside your territory"
??? example "Enemy [mapUnitFilter] units must spend [positiveAmount] extra movement points when inside your territory"
Example: "Enemy [Wounded] units must spend [3] extra movement points when inside your territory"
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
@ -1039,13 +1039,13 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, Unit
??? example "[amount] Movement point cost to disembark"
??? example "[nonNegativeAmount] Movement point cost to disembark"
Example: "[3] Movement point cost to disembark"
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
Applicable to: Global, Unit
??? example "[amount] Movement point cost to embark"
??? example "[nonNegativeAmount] Movement point cost to embark"
Example: "[3] Movement point cost to embark"
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
@ -1163,7 +1163,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: FounderBelief
??? example "[stats] from every [amount] global followers [cityFilter]"
??? example "[stats] from every [positiveAmount] global followers [cityFilter]"
Example: "[+1 Gold, +2 Production] from every [3] global followers [in all cities]"
Applicable to: FounderBelief
@ -1201,7 +1201,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, FollowerBelief
??? example "[stats] per [amount] population [cityFilter]"
??? example "[stats] per [positiveAmount] population [cityFilter]"
Example: "[+1 Gold, +2 Production] per [3] population [in all cities]"
Applicable to: Global, FollowerBelief
@ -1301,22 +1301,22 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, FollowerBelief
??? example "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount])"
??? example "May buy [baseUnitFilter] units for [nonNegativeAmount] [stat] [cityFilter] at an increasing price ([amount])"
Example: "May buy [Melee] units for [3] [Culture] [in all cities] at an increasing price ([3])"
Applicable to: Global, FollowerBelief
??? example "May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] at an increasing price ([amount])"
??? example "May buy [buildingFilter] buildings for [nonNegativeAmount] [stat] [cityFilter] at an increasing price ([amount])"
Example: "May buy [Culture] buildings for [3] [Culture] [in all cities] at an increasing price ([3])"
Applicable to: Global, FollowerBelief
??? example "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter]"
??? example "May buy [baseUnitFilter] units for [nonNegativeAmount] [stat] [cityFilter]"
Example: "May buy [Melee] units for [3] [Culture] [in all cities]"
Applicable to: Global, FollowerBelief
??? example "May buy [buildingFilter] buildings for [amount] [stat] [cityFilter]"
??? example "May buy [buildingFilter] buildings for [nonNegativeAmount] [stat] [cityFilter]"
Example: "May buy [Culture] buildings for [3] [Culture] [in all cities]"
Applicable to: Global, FollowerBelief
@ -1331,12 +1331,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Global, FollowerBelief
??? example "May buy [baseUnitFilter] units with [stat] for [amount] times their normal Production cost"
??? example "May buy [baseUnitFilter] units with [stat] for [nonNegativeAmount] times their normal Production cost"
Example: "May buy [Melee] units with [Culture] for [3] times their normal Production cost"
Applicable to: Global, FollowerBelief
??? example "May buy [buildingFilter] buildings with [stat] for [amount] times their normal Production cost"
??? example "May buy [buildingFilter] buildings with [stat] for [nonNegativeAmount] times their normal Production cost"
Example: "May buy [Culture] buildings with [Culture] for [3] times their normal Production cost"
Applicable to: Global, FollowerBelief
@ -2122,13 +2122,13 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
Applicable to: Unit
??? example "[amount] Movement point cost to disembark"
??? example "[nonNegativeAmount] Movement point cost to disembark"
Example: "[3] Movement point cost to disembark"
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
Applicable to: Global, Unit
??? example "[amount] Movement point cost to embark"
??? example "[nonNegativeAmount] Movement point cost to embark"
Example: "[3] Movement point cost to embark"
Due to performance considerations, this unique is cached, thus conditionals that may change within a turn may not work.
@ -2706,7 +2706,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
## Tutorial uniques
## CityState uniques
??? example "Provides military units every ≈[amount] turns"
??? example "Provides military units every ≈[positiveAmount] turns"
Example: "Provides military units every ≈[3] turns"
Applicable to: CityState
@ -2811,12 +2811,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Conditional
??? example "&lt;before turn number [amount]&gt;"
??? example "&lt;before turn number [nonNegativeAmount]&gt;"
Example: "&lt;before turn number [3]&gt;"
Applicable to: Conditional
??? example "&lt;after turn number [amount]&gt;"
??? example "&lt;after turn number [nonNegativeAmount]&gt;"
Example: "&lt;after turn number [3]&gt;"
Applicable to: Conditional
@ -2856,7 +2856,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "&lt;when nuclear weapons are enabled&gt;"
Applicable to: Conditional
??? example "&lt;with [amount]% chance&gt;"
??? example "&lt;with [nonNegativeAmount]% chance&gt;"
Example: "&lt;with [3]% chance&gt;"
Applicable to: Conditional
@ -3076,12 +3076,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Conditional
??? example "&lt;in cities with at least [amount] [populationFilter]&gt;"
??? example "&lt;in cities with at least [positiveAmount] [populationFilter]&gt;"
Example: "&lt;in cities with at least [3] [Followers of this Religion]&gt;"
Applicable to: Conditional
??? example "&lt;in cities with [amount] [populationFilter]&gt;"
??? example "&lt;in cities with [positiveAmount] [populationFilter]&gt;"
Example: "&lt;in cities with [3] [Followers of this Religion]&gt;"
Applicable to: Conditional
@ -3156,12 +3156,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Conditional
??? example "&lt;when above [amount] HP&gt;"
??? example "&lt;when above [positiveAmount] HP&gt;"
Example: "&lt;when above [3] HP&gt;"
Applicable to: Conditional
??? example "&lt;when below [amount] HP&gt;"
??? example "&lt;when below [positiveAmount] HP&gt;"
Example: "&lt;when below [3] HP&gt;"
Applicable to: Conditional
@ -3169,7 +3169,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "&lt;if it hasn't used other actions yet&gt;"
Applicable to: Conditional
??? example "&lt;with [amount] to [amount] neighboring [tileFilter] tiles&gt;"
??? example "&lt;with [nonNegativeAmount] to [positiveAmount] neighboring [tileFilter] tiles&gt;"
Example: "&lt;with [3] to [3] neighboring [Farm] tiles&gt;"
Applicable to: Conditional
@ -3184,7 +3184,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Conditional
??? example "&lt;within [amount] tiles of a [tileFilter]&gt;"
??? example "&lt;within [positiveAmount] tiles of a [tileFilter]&gt;"
Example: "&lt;within [3] tiles of a [Farm]&gt;"
Applicable to: Conditional
@ -3381,7 +3381,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: UnitTriggerCondition
??? example "&lt;upon losing at least [amount] HP in a single attack&gt;"
??? example "&lt;upon losing at least [positiveAmount] HP in a single attack&gt;"
Example: "&lt;upon losing at least [3] HP in a single attack&gt;"
Applicable to: UnitTriggerCondition
@ -3419,8 +3419,8 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Will consume all Movement to execute
Applicable to: UnitActionModifier
??? example "&lt;requires [amount] movement&gt;"
Requires [amount] of Movement to execute. Unit's Movement is rounded up
??? example "&lt;requires [nonNegativeAmount] movement&gt;"
Requires [nonNegativeAmount] of Movement to execute. Unit's Movement is rounded up
Example: "&lt;requires [3] movement&gt;"
Applicable to: UnitActionModifier
@ -3446,12 +3446,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "&lt;once&gt;"
Applicable to: UnitActionModifier
??? example "&lt;[amount] times&gt;"
??? example "&lt;[positiveAmount] times&gt;"
Example: "&lt;[3] times&gt;"
Applicable to: UnitActionModifier
??? example "&lt;[amount] additional time(s)&gt;"
??? example "&lt;[nonNegativeAmount] additional time(s)&gt;"
Example: "&lt;[3] additional time(s)&gt;"
Applicable to: UnitActionModifier
@ -3464,7 +3464,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Modifiers that can be added to other uniques changing user experience, not their behavior
??? example "&lt;for [amount] turns&gt;"
??? example "&lt;for [nonNegativeAmount] turns&gt;"
Turns this unique into a trigger, activating this unique as a *global* unique for a number of turns
Example: "&lt;for [3] turns&gt;"
@ -3483,7 +3483,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: MetaModifier
??? example "&lt;for every [amount] [countable]&gt;"
??? example "&lt;for every [positiveAmount] [countable]&gt;"
Example: "&lt;for every [3] [1000]&gt;"
Applicable to: MetaModifier
@ -3521,6 +3521,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
*[fraction]: Indicates a fractional number, which can be negative.
*[improvementName]: The name of any improvement excluding 'Cancel improvement order'
*[modFilter]: A Mod name, case-sensitive _or_ a simple wildcard filter beginning and ending in an Asterisk, case-insensitive.
*[nonNegativeAmount]: This indicates a non-negative whole number, larger than or equal to zero, a '+' sign is optional.
*[policy]: The name of any policy.
*[policyFilter]: The name of any policy.
*[positiveAmount]: This indicates a positive whole number, larger than zero, a '+' sign is optional.

View File

@ -3,15 +3,14 @@ package com.unciv.uniques
import com.unciv.models.metadata.BaseRuleset
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.ruleset.unique.Countables
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.unique.*
import com.unciv.models.ruleset.validation.RulesetValidator
import com.unciv.models.stats.Stat
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.testing.GdxTestRunner
import com.unciv.testing.TestGame
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Test
import org.junit.runner.RunWith
@ -25,6 +24,18 @@ class CountableTests {
private var civInfo = game.addCiv()
private var city = game.addCity(civInfo, game.tileMap[2,0])
@Test
fun testAllCountableParametersAreUniqueParameterTypes() {
for (countable in Countables.entries) {
val parameters = countable.text.getPlaceholderParameters()
for (parameter in parameters) {
assertNotEquals("Countable ${countable.name} parameter ${parameter} is not a UniqueParameterType",
UniqueParameterType.safeValueOf(parameter), UniqueParameterType.Unknown)
}
}
}
@Test
fun testPerCountableForGlobalAndLocalResources() {
// one coal provided locally