|
| 1 | +package br.com.felipezorzo.zpa.cli |
| 2 | + |
| 3 | +import br.com.felipezorzo.zpa.cli.config.BaseRuleCategory |
| 4 | +import br.com.felipezorzo.zpa.cli.config.ConfigFile |
| 5 | +import br.com.felipezorzo.zpa.cli.config.RuleConfiguration |
| 6 | +import br.com.felipezorzo.zpa.cli.config.RuleLevel |
| 7 | +import br.com.felipezorzo.zpa.cli.config.RuleOptions |
| 8 | +import br.com.felipezorzo.zpa.cli.rules.CliActiveRules |
| 9 | +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper |
| 10 | +import com.felipebz.zpa.CustomAnnotationBasedRulesDefinition |
| 11 | +import com.felipebz.zpa.checks.XPathCheck |
| 12 | +import com.felipebz.zpa.rules.ActiveRuleConfiguration |
| 13 | +import com.felipebz.zpa.rules.Repository |
| 14 | +import com.felipebz.zpa.rules.RuleMetadataLoader |
| 15 | +import com.felipebz.zpa.rules.ZpaChecks |
| 16 | +import java.nio.file.Files |
| 17 | +import kotlin.test.Test |
| 18 | +import kotlin.test.assertEquals |
| 19 | +import kotlin.test.assertNotSame |
| 20 | +import kotlin.test.assertTrue |
| 21 | + |
| 22 | +class TemplateRuleInstancesTest { |
| 23 | + |
| 24 | + @Test |
| 25 | + fun zpaChecksCreatesIndependentVisitorsForTwoInstancesOfOneTemplate() { |
| 26 | + val repository = xpathRepository() |
| 27 | + val config = templateConfig() |
| 28 | + val activeRules = configuredActiveRules(config, repository) |
| 29 | + |
| 30 | + val checks = ZpaChecks(activeRules, repository.key, RuleMetadataLoader()) |
| 31 | + .addAnnotatedChecks(listOf(XPathCheck::class.java)) |
| 32 | + .all() |
| 33 | + .filterIsInstance<XPathCheck>() |
| 34 | + .associateBy { it.activeRule.ruleKey.rule } |
| 35 | + |
| 36 | + assertEquals(setOf("FirstXPath", "SecondXPath"), checks.keys) |
| 37 | + |
| 38 | + val first = checks.getValue("FirstXPath") |
| 39 | + val second = checks.getValue("SecondXPath") |
| 40 | + assertNotSame(first, second) |
| 41 | + |
| 42 | + assertEquals("//SELECT_COLUMN/MULTIPLICATION", first.xpathQuery) |
| 43 | + assertEquals("message A", first.message) |
| 44 | + assertEquals("MINOR", first.activeRule.severity) |
| 45 | + assertEquals("zpa:FirstXPath", first.activeRule.ruleKey.toString()) |
| 46 | + assertEquals("XPath", first.activeRule.templateRuleKey) |
| 47 | + |
| 48 | + assertEquals("//SELECT_COLUMN/MULTIPLICATION", second.xpathQuery) |
| 49 | + assertEquals("message B", second.message) |
| 50 | + assertEquals("MAJOR", second.activeRule.severity) |
| 51 | + assertEquals("zpa:SecondXPath", second.activeRule.ruleKey.toString()) |
| 52 | + assertEquals("XPath", second.activeRule.templateRuleKey) |
| 53 | + assertTrue(first.activeRule !== second.activeRule) |
| 54 | + } |
| 55 | + |
| 56 | + @Test |
| 57 | + fun explicitTemplateReferenceOnTheOriginalRuleCreatesOnlyOneCheck() { |
| 58 | + val repository = xpathRepository() |
| 59 | + val config = ConfigFile( |
| 60 | + base = BaseRuleCategory.NONE, |
| 61 | + rules = mapOf( |
| 62 | + "XPath" to options( |
| 63 | + level = RuleLevel.MINOR, |
| 64 | + templateRuleKey = "XPath", |
| 65 | + parameters = mapOf( |
| 66 | + "xpathQuery" to "//SELECT_COLUMN/MULTIPLICATION", |
| 67 | + "message" to "message" |
| 68 | + ) |
| 69 | + ) |
| 70 | + ) |
| 71 | + ) |
| 72 | + |
| 73 | + val checks = ZpaChecks(configuredActiveRules(config, repository), repository.key, RuleMetadataLoader()) |
| 74 | + .addAnnotatedChecks(listOf(XPathCheck::class.java)) |
| 75 | + .all() |
| 76 | + .filterIsInstance<XPathCheck>() |
| 77 | + |
| 78 | + assertEquals(1, checks.size) |
| 79 | + assertEquals("zpa:XPath", checks.single().activeRule.ruleKey.toString()) |
| 80 | + } |
| 81 | + |
| 82 | + @Test |
| 83 | + fun cliProducesTwoDistinctGenericIssuesWithIndependentConfiguration() { |
| 84 | + val root = Files.createTempDirectory("zpa-cli-template-instances").toFile() |
| 85 | + try { |
| 86 | + val sourceDirectory = root.resolve("sources").apply { mkdirs() } |
| 87 | + sourceDirectory.resolve("multiplication.sql").writeText( |
| 88 | + "SELECT * FROM table_name;\n" |
| 89 | + ) |
| 90 | + |
| 91 | + val configPath = root.resolve("config.json").apply { |
| 92 | + writeText( |
| 93 | + """ |
| 94 | + { |
| 95 | + "base": "none", |
| 96 | + "rules": { |
| 97 | + "FirstXPath": { |
| 98 | + "level": "minor", |
| 99 | + "templateRuleKey": "XPath", |
| 100 | + "parameters": { |
| 101 | + "xpathQuery": "//SELECT_COLUMN/MULTIPLICATION", |
| 102 | + "message": "message A" |
| 103 | + } |
| 104 | + }, |
| 105 | + "SecondXPath": { |
| 106 | + "level": "major", |
| 107 | + "templateRuleKey": "zpa:XPath", |
| 108 | + "parameters": { |
| 109 | + "xpathQuery": "//SELECT_COLUMN/MULTIPLICATION", |
| 110 | + "message": "message B" |
| 111 | + } |
| 112 | + } |
| 113 | + } |
| 114 | + } |
| 115 | + """.trimIndent() |
| 116 | + ) |
| 117 | + } |
| 118 | + val issuesPath = root.resolve("issues.json") |
| 119 | + |
| 120 | + Main( |
| 121 | + Arguments().apply { |
| 122 | + sources = sourceDirectory.absolutePath |
| 123 | + configFile = configPath.absolutePath |
| 124 | + outputFormat = GENERIC_ISSUE_FORMAT |
| 125 | + outputFile = issuesPath.absolutePath |
| 126 | + extensions = "sql" |
| 127 | + } |
| 128 | + ).run() |
| 129 | + |
| 130 | + val issues = jacksonObjectMapper() |
| 131 | + .readTree(issuesPath) |
| 132 | + .get("issues") |
| 133 | + .elements() |
| 134 | + .asSequence() |
| 135 | + .map { issue -> |
| 136 | + Triple( |
| 137 | + issue.get("ruleId").asText(), |
| 138 | + issue.get("severity").asText(), |
| 139 | + issue.get("primaryLocation").get("message").asText() |
| 140 | + ) |
| 141 | + } |
| 142 | + .toList() |
| 143 | + .sortedBy { it.first } |
| 144 | + |
| 145 | + assertEquals( |
| 146 | + listOf( |
| 147 | + Triple("zpa:FirstXPath", "MINOR", "message A"), |
| 148 | + Triple("zpa:SecondXPath", "MAJOR", "message B") |
| 149 | + ), |
| 150 | + issues |
| 151 | + ) |
| 152 | + } finally { |
| 153 | + root.deleteRecursively() |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + private fun xpathRepository(): Repository { |
| 158 | + val repository = Repository("zpa") |
| 159 | + CustomAnnotationBasedRulesDefinition.load( |
| 160 | + repository, |
| 161 | + "plsqlopen", |
| 162 | + listOf(XPathCheck::class.java), |
| 163 | + RuleMetadataLoader() |
| 164 | + ) |
| 165 | + return repository |
| 166 | + } |
| 167 | + |
| 168 | + private fun templateConfig(): ConfigFile { |
| 169 | + return ConfigFile( |
| 170 | + base = BaseRuleCategory.NONE, |
| 171 | + rules = mapOf( |
| 172 | + "FirstXPath" to options( |
| 173 | + level = RuleLevel.MINOR, |
| 174 | + templateRuleKey = "XPath", |
| 175 | + parameters = mapOf( |
| 176 | + "xpathQuery" to "//SELECT_COLUMN/MULTIPLICATION", |
| 177 | + "message" to "message A" |
| 178 | + ) |
| 179 | + ), |
| 180 | + "SecondXPath" to options( |
| 181 | + level = RuleLevel.MAJOR, |
| 182 | + templateRuleKey = "zpa:XPath", |
| 183 | + parameters = mapOf( |
| 184 | + "xpathQuery" to "//SELECT_COLUMN/MULTIPLICATION", |
| 185 | + "message" to "message B" |
| 186 | + ) |
| 187 | + ) |
| 188 | + ) |
| 189 | + ) |
| 190 | + } |
| 191 | + |
| 192 | + private fun configuredActiveRules(config: ConfigFile, repository: Repository): CliActiveRules { |
| 193 | + return CliActiveRules(config) |
| 194 | + .addRepository(repository) |
| 195 | + .addRuleConfigurer { repo, rule, configuration: ActiveRuleConfiguration -> |
| 196 | + var ruleConfig = config.rules["${repo.key}:${rule.key}"] ?: config.rules[rule.key] |
| 197 | + if (config.base == BaseRuleCategory.DEFAULT && rule.isActivatedByDefault) { |
| 198 | + ruleConfig = ruleConfig ?: RuleConfiguration() |
| 199 | + } |
| 200 | + |
| 201 | + if (ruleConfig == null || ruleConfig.options.level == RuleLevel.OFF) { |
| 202 | + return@addRuleConfigurer false |
| 203 | + } |
| 204 | + |
| 205 | + if (ruleConfig.options.level != RuleLevel.ON) { |
| 206 | + configuration.severity = ruleConfig.options.level.toString() |
| 207 | + } |
| 208 | + configuration.parameters.putAll(ruleConfig.options.parameters) |
| 209 | + true |
| 210 | + } |
| 211 | + } |
| 212 | + |
| 213 | + private fun options( |
| 214 | + level: RuleLevel, |
| 215 | + templateRuleKey: String, |
| 216 | + parameters: Map<String, String> |
| 217 | + ): RuleConfiguration { |
| 218 | + return RuleConfiguration().apply { |
| 219 | + this.options = RuleOptions().apply { |
| 220 | + this.level = level |
| 221 | + this.templateRuleKey = templateRuleKey |
| 222 | + this.parameters = parameters |
| 223 | + } |
| 224 | + } |
| 225 | + } |
| 226 | +} |
0 commit comments