@@ -10,6 +10,7 @@ import org.scalatest.BeforeAndAfterAll
10
10
import org .scalatest .FunSuite
11
11
import org .scalatest .exceptions .TestFailedException
12
12
import scala .util .matching .Regex
13
+ import scalafix .rule .RuleName
13
14
import org .langmeta .internal .ScalafixLangmetaHacks
14
15
15
16
object SemanticRuleSuite {
@@ -65,61 +66,70 @@ abstract class SemanticRuleSuite(
65
66
private def assertLintMessagesAreReported (
66
67
rule : Rule ,
67
68
ctx : RuleCtx ,
68
- lints : List [ LintMessage ],
69
+ patches : Map [ RuleName , Patch ],
69
70
tokens : Tokens ): Unit = {
70
- val lintMessages = lints.to[mutable.Set ]
71
- def assertLint (position : Position , key : String ): Unit = {
72
- val matchingMessage = lintMessages.filter { m =>
73
- assert(m.position.input == position.input)
74
- m.position.startLine == position.startLine &&
75
- m.category.key(rule.name) == key
76
- }
77
- if (matchingMessage.isEmpty) {
71
+
72
+ type Msg = (Position , String )
73
+
74
+ def matches (a : Msg )(b : Msg ) =
75
+ a._1.startLine == b._1.startLine &&
76
+ a._2 == b._2
77
+
78
+ def diff (a : Seq [Msg ], b : Seq [Msg ]) =
79
+ a.filter(x => ! b.exists(matches(x)))
80
+
81
+ val lintAssertions = tokens.collect {
82
+ case tok @ Token .Comment (SemanticRuleSuite .LintAssertion (key)) =>
83
+ tok.pos -> key
84
+ }
85
+ val lintMessages = patches.toSeq.flatMap {
86
+ case (name, patch) =>
87
+ Patch
88
+ .lintMessages(patch)
89
+ .map(lint => lint.position -> lint.category.key(name))
90
+ }
91
+
92
+ val uncoveredAsserts = diff(lintAssertions, lintMessages)
93
+ uncoveredAsserts.foreach {
94
+ case (pos, key) =>
78
95
throw new TestFailedException (
79
96
ScalafixLangmetaHacks .formatMessage(
80
- position ,
97
+ pos ,
81
98
" error" ,
82
99
s " Message ' $key' was not reported here! " ),
83
100
0
84
101
)
85
- } else {
86
- lintMessages --= matchingMessage
87
- }
88
102
}
89
- tokens.foreach {
90
- case tok @ Token . Comment ( SemanticRuleSuite . LintAssertion (key)) =>
91
- assertLint(tok.pos, key)
92
- case _ =>
93
- }
94
- if (lintMessages.nonEmpty) {
95
- lintMessages.foreach(x => ctx.printLintMessage(x, rule.name))
96
- val key = lintMessages.head.category.key(rule.name)
97
- val explanation =
98
- s """ |To fix this problem, suffix the culprit lines with
99
- | // assert: $key
100
- | """ .stripMargin
103
+
104
+ val uncoveredMessages = diff(lintMessages, lintAssertions)
105
+ if (uncoveredMessages.nonEmpty) {
106
+ Patch .reportLintMessages(patches, ctx)
107
+ val explanation = uncoveredMessages
108
+ .groupBy(_._2)
109
+ .map {
110
+ case (key, positions) =>
111
+ s """ Append to lines: ${positions.map(_._1.startLine).mkString( " , " )}
112
+ | // assert: $key """ .stripMargin
113
+ }
114
+ .mkString( " \n\n " )
101
115
throw new TestFailedException (
102
- s " Uncaught linter messages! $explanation" ,
116
+ s " Uncaught linter messages! To fix this problem \n $explanation" ,
103
117
0 )
104
118
}
105
119
}
106
120
107
121
def runOn (diffTest : DiffTest ): Unit = {
108
122
test(diffTest.name) {
109
123
val (rule, config) = diffTest.config.apply()
110
- val ctx = RuleCtx (
124
+ val ctx : RuleCtx = RuleCtx (
111
125
config.dialect(diffTest.original).parse[Source ].get,
112
126
config.copy(dialect = diffTest.document.dialect)
113
127
)
114
- val patch = rule.fix(ctx)
128
+ val patches = rule.fixWithName(ctx)
129
+ assertLintMessagesAreReported(rule, ctx, patches, ctx.tokens)
130
+ val patch = patches.values.asPatch
115
131
val obtainedWithComment = Patch .apply(patch, ctx, rule.semanticOption)
116
132
val tokens = obtainedWithComment.tokenize.get
117
- val checkMessages = rule.check(ctx)
118
- assertLintMessagesAreReported(
119
- rule,
120
- ctx,
121
- Patch .lintMessages(patch, ctx, checkMessages),
122
- ctx.tokens)
123
133
val obtained = SemanticRuleSuite .stripTestkitComments(tokens)
124
134
val candidateOutputFiles = expectedOutputSourceroot.flatMap { root =>
125
135
val scalaSpecificFilename =
@@ -132,9 +142,7 @@ abstract class SemanticRuleSuite(
132
142
.collectFirst { case f if f.isFile => f.readAllBytes }
133
143
.map(new String (_))
134
144
.getOrElse {
135
- // TODO(olafur) come up with more principled check to determine if
136
- // rule is linter or rewrite.
137
- if (checkMessages.nonEmpty) obtained // linter
145
+ if (Patch .isOnlyLintMessages(patch)) obtained // linter
138
146
else {
139
147
val tried = candidateOutputFiles.mkString(" \n " )
140
148
sys.error(
0 commit comments