Skip to content

Commit

Permalink
Clean up highlighting issue, add GlossaryPassTest
Browse files Browse the repository at this point in the history
* Message formatting shouldn't highlight at all and now doesn't
* Highlighting changed to bold the first line of each message
* Added a test case for teh GlossaryPass
* Made HugoTestBase abstract so it won't run!

Signed-off-by: reidspencer <reid.spencer@yoppworks.com>
  • Loading branch information
reid-spencer committed Oct 22, 2023
1 parent bb0ed1b commit 09f2696
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.reactific.riddl.hugo

import com.reactific.riddl.testkit.ValidatingTest
import com.reactific.riddl.passes.Pass

class GlossaryPassTest extends ValidatingTest {

val dir = "testkit/src/test/input/"

"GlossaryPass" must {
"product glossary entries" in {
parseAndValidateTestInput("glossary entries", "everything.riddl", dir) { case (root, pr) =>
if pr.messages.hasErrors then
val errors = pr.messages.justErrors.format
fail(errors)
else
val pass = new GlossaryPass(pr.input, pr.outputs, HugoCommand.Options())
val output: GlossaryOutput = Pass.runPass[GlossaryOutput](pr.input, pr.outputs, pass)
output.entries.size must be(60)
}
}
}
}
77 changes: 30 additions & 47 deletions language/src/main/scala/com/reactific/riddl/language/Messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
*/

package com.reactific.riddl.language
import com.reactific.riddl.language.parsing.{FileParserInput, SourceParserInput, StringParserInput, URLParserInput, EmptyParserInput}
import com.reactific.riddl.language.parsing.{
FileParserInput,
SourceParserInput,
StringParserInput,
URLParserInput,
EmptyParserInput
}
import com.reactific.riddl.utils.Logger

import scala.collection.mutable
Expand Down Expand Up @@ -99,18 +105,6 @@ object Messages {

val nl: String = System.lineSeparator()

private def highlight(kind: KindOfMessage, s: String): String = {
s"${kind match {
case Info => s"$BLUE"
case StyleWarning => s"$YELLOW"
case MissingWarning => s"$YELLOW$UNDERLINED"
case UsageWarning => s"$YELLOW$BOLD"
case Warning => s"$YELLOW$BOLD$UNDERLINED"
case Error => s"$RED$BOLD"
case SevereError => s"$RED_B$BLACK$BOLD"
}}$s$RESET"
}

case class Message(loc: At, message: String, kind: KindOfMessage = Error, context: String = "")
extends Ordered[Message] {

Expand All @@ -128,15 +122,9 @@ object Messages {
else comparison
}

private def highlight(s: String, noHighlighting: Boolean = false): String = {
if noHighlighting then s
else Messages.highlight(kind, s)
}

def format: String = { format(noHighlighting = false) }

def format(noHighlighting: Boolean = false): String = {
val ctxt = if context.nonEmpty then { s"${nl}Context: $context" } else ""
def format: String = {
val ctxt = if context.nonEmpty then { s"${nl}Context: $context" }
else ""
val source = loc.source match {
case fpi: FileParserInput =>
val path = fpi.file.getAbsolutePath
Expand All @@ -148,7 +136,7 @@ object Messages {
case epi: EmptyParserInput => epi.origin
}
val sourceLine = loc.toShort
val headLine = s"${highlight(s"$kind: $source$sourceLine:", noHighlighting)}$nl"
val headLine = s"$kind: $source$sourceLine:$nl"
val errorLine = loc.source.annotateErrorLine(loc).dropRight(1)
if loc.isEmpty || source.isEmpty || errorLine.isEmpty then {
s"$headLine$message$ctxt"
Expand Down Expand Up @@ -234,20 +222,22 @@ object Messages {
highestSeverity(list)
}

def logMessagesRetainingOrder(list: Messages, log: Logger): Unit = {
list.foreach { msg =>
msg.kind match {
case Info => log.info(msg.format())
case StyleWarning => log.warn(msg.format())
case MissingWarning => log.warn(msg.format())
case UsageWarning => log.warn(msg.format())
case Warning => log.warn(msg.format())
case Error => log.error(msg.format())
case SevereError => log.severe(msg.format())
}
def logMessage(message: Message, log: Logger): Unit = {
message.kind match {
case Info => log.info(message.format)
case StyleWarning => log.warn(message.format)
case MissingWarning => log.warn(message.format)
case UsageWarning => log.warn(message.format)
case Warning => log.warn(message.format)
case Error => log.error(message.format)
case SevereError => log.severe(message.format)
}
}

def logMessagesRetainingOrder(list: Messages, log: Logger): Unit = {
list.foreach { msg => logMessage(msg, log) }
}

def logMessagesByGroup(
messages: Messages,
commonOptions: CommonOptions,
Expand All @@ -258,22 +248,15 @@ object Messages {
if messages.nonEmpty then {
kind match {
case Error =>
log.error(highlight(kind, s"""$kind Message Count: ${messages.length}"""))
log.error(s"""$kind Message Count: ${messages.length}""")
case SevereError =>
log.severe(highlight(kind, s"""$kind Message Count: ${messages.length}"""))
log.severe(s"""$kind Message Count: ${messages.length}""")
case Info =>
log.info(highlight(kind, s"""$kind Message Count: ${messages.length}"""))
case _ =>
log.warn(highlight(kind, s"""$kind Message Count: ${messages.length}"""))
}
messages.map(_.format()).foreach { (msg: String) =>
kind match {
case Info => log.info(msg)
case SevereError => log.severe(msg)
case Error => log.error(msg)
case _ => log.warn(msg)
}
log.info(s"""$kind Message Count: ${messages.length}""")
case _ => // everything else is a warning
log.warn(s"""$kind Message Count: ${messages.length}""")
}
messages.foreach { (msg: Message) => logMessage(msg, log) }
}
}
if messages.nonEmpty then {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,20 +149,20 @@ class MessagesSpec extends AnyWordSpec with Matchers {
val log = StringLogger()
Messages.logMessages(mix, log, commonOptions)
val content = log.toString()
val expected = """[34m[info] [0m[34mInfo: empty(1:1):[0m
|info
|[33m[warning] [0m[33mStyle: empty(1:1):[0m
|style
|[33m[warning] [0m[33m[4mMissing: empty(1:1):[0m
|missing
|[33m[warning] [0m[33m[1mUsage: empty(1:1):[0m
|usage
|[33m[warning] [0m[33m[1m[4mWarning: empty(1:1):[0m
|warning
|[31m[error] [0m[31m[1mError: empty(1:1):[0m
|error
|[41m[30m[severe] [0m[41m[30m[1mSevere: empty(1:1):[0m
|severe
val expected = """[34m[1m[info] Info: empty(1:1):[0m
|[34minfo[0m
|[33m[1m[warning] Style: empty(1:1):[0m
|[33mstyle[0m
|[33m[1m[warning] Missing: empty(1:1):[0m
|[33mmissing[0m
|[33m[1m[warning] Usage: empty(1:1):[0m
|[33musage[0m
|[33m[1m[warning] Warning: empty(1:1):[0m
|[33mwarning[0m
|[31m[1m[error] Error: empty(1:1):[0m
|[31merror[0m
|[41m[30m[1m[severe] Severe: empty(1:1):[0m
|[41m[30msevere[0m
|""".stripMargin
content mustBe expected
}
Expand All @@ -172,33 +172,33 @@ class MessagesSpec extends AnyWordSpec with Matchers {
Messages.logMessages(mix, log, commonOptions)
val content = log.toString
val expected =
"""[41m[30m[severe] [0m[41m[30m[1mSevere Message Count: 1[0m
|[41m[30m[severe] [0m[41m[30m[1mSevere: empty(1:1):[0m
|severe
|[31m[error] [0m[31m[1mError Message Count: 1[0m
|[31m[error] [0m[31m[1mError: empty(1:1):[0m
|error
|[33m[warning] [0m[33m[1mUsage Message Count: 1[0m
|[33m[warning] [0m[33m[1mUsage: empty(1:1):[0m
|usage
|[33m[warning] [0m[33m[4mMissing Message Count: 1[0m
|[33m[warning] [0m[33m[4mMissing: empty(1:1):[0m
|missing
|[33m[warning] [0m[33mStyle Message Count: 1[0m
|[33m[warning] [0m[33mStyle: empty(1:1):[0m
|style
|[34m[info] [0m[34mInfo Message Count: 1[0m
|[34m[info] [0m[34mInfo: empty(1:1):[0m
|info
"""[41m[30m[1m[severe] Severe Message Count: 1[0m
|[41m[30m[1m[severe] Severe: empty(1:1):[0m
|[41m[30msevere[0m
|[31m[1m[error] Error Message Count: 1[0m
|[31m[1m[error] Error: empty(1:1):[0m
|[31merror[0m
|[33m[1m[warning] Usage Message Count: 1[0m
|[33m[1m[warning] Usage: empty(1:1):[0m
|[33musage[0m
|[33m[1m[warning] Missing Message Count: 1[0m
|[33m[1m[warning] Missing: empty(1:1):[0m
|[33mmissing[0m
|[33m[1m[warning] Style Message Count: 1[0m
|[33m[1m[warning] Style: empty(1:1):[0m
|[33mstyle[0m
|[34m[1m[info] Info Message Count: 1[0m
|[34m[1m[info] Info: empty(1:1):[0m
|[34minfo[0m
|""".stripMargin
content mustBe expected
}

"format should produce a correct string" in {
val msg =
Message(At(1, 2, RiddlParserInput.empty), "the_message", Warning)
val content = msg.format()
val expected = """[33m[1m[4mWarning: empty(1:2):[0m
val content = msg.format
val expected = """Warning: empty(1:2):
|the_message""".stripMargin
content mustBe expected
}
Expand Down
21 changes: 11 additions & 10 deletions passes/src/main/scala/com/reactific/riddl/passes/Pass.scala
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ abstract class CollectingPass[F](input: PassInput, outputs: PassesOutput) extend
@SuppressWarnings(Array("org.wartremover.warts.Var"))
protected var collectedValues: Seq[F] = Seq.empty[F]

override def result: CollectingPassOutput[F]
override def result: CollectingPassOutput[F]

override protected def traverse(definition: Definition, parents: mutable.Stack[Definition]): Unit = {
collect(definition, parents).foreach { collected =>
Expand Down Expand Up @@ -343,7 +343,7 @@ object Pass {
try {
for pass <- passes yield {
val aPass = pass(input, outputs)
val output = runOnePass(input, outputs, aPass, logger)
val output: PassOutput = runOnePass(input.root, input.commonOptions, aPass, logger)
outputs.outputIs(aPass.name, output)
}
PassesResult(input, outputs, Messages.empty)
Expand Down Expand Up @@ -381,24 +381,25 @@ object Pass {
runPass[ValidationOutput](input, outputs, ValidationPass(input, outputs))
}

private def runPass[OUT <: PassOutput](input: PassInput, outputs: PassesOutput, pass: Pass): OUT = {
Pass.runOnePass(input, outputs, pass).asInstanceOf[OUT]
def runPass[OUT <: PassOutput](input: PassInput, outputs: PassesOutput, pass: Pass): OUT = {
val output: OUT = Pass.runOnePass(input.root, input.commonOptions,pass).asInstanceOf[OUT]
outputs.outputIs(pass.name, output)
output
}

private def runOnePass(
in: PassInput,
outs: PassesOutput,
root: RootContainer,
commonOptions: CommonOptions,
mkPass: => Pass,
logger: Logger = SysLogger()
): PassOutput = {
val pass: Pass = mkPass
Timer.time[PassOutput](pass.name, in.commonOptions.showTimes, logger) {
Timer.time[PassOutput](pass.name, commonOptions.showTimes, logger) {
val parents: mutable.Stack[Definition] = mutable.Stack.empty
pass.traverse(in.root, parents)
pass.postProcess(in.root)
pass.traverse(root, parents)
pass.postProcess(root)
pass.close()
val output = pass.result
outs.outputIs(pass.name, output)
output
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ case class SymbolsPass(input: PassInput, outputs: PassesOutput) extends Pass(inp
}
}

override def result: SymbolsOutput = SymbolsOutput(Messages.empty, symTab, parentage)
override def result: SymbolsOutput = {
SymbolsOutput(Messages.empty, symTab, parentage)
}

override def close(): Unit = ()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ class UsageSpec extends AnyWordSpec with Matchers {
|""".stripMargin
Riddl.parseAndValidate(RiddlParserInput(input), shouldFailOnError = false) match {
case Left(messages) => fail(messages.format)
case Right(result) =>
case Right(result) =>
// info(result.messages.format)
result.messages.hasErrors mustBe (false)
val warnings = result.messages.justUsage
warnings.size mustBe (2)
val warnMessage = warnings.last.format()
val warnMessage = warnings.last.format
warnMessage must include("Entity 'fooBar' is unused")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ValidationTest extends ParsingTest {
val msg =
Message(At(1, 2, RiddlParserInput.empty), "the_message", Warning)
val content = msg.format
val expected = """[33m[1m[4mWarning: empty(1:2):[0m
val expected = """Warning: empty(1:2):
|the_message""".stripMargin
content mustBe expected
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import com.reactific.riddl.language.parsing.{RiddlParserInput, TopLevelParser}
import com.reactific.riddl.language.CommonOptions
import com.reactific.riddl.language.Messages.Messages
import com.reactific.riddl.testkit.ParsingTest
import com.reactific.riddl.passes.{Pass, PassesResult, Riddl}
import com.reactific.riddl.passes.{Pass, PassInput, PassesResult, Riddl}
import org.scalatest.*

import java.io.File
Expand Down Expand Up @@ -88,8 +88,8 @@ abstract class ValidatingTest extends ParsingTest {
}
}

private def defaultFail(msgs: Messages): Assertion = {
fail(msgs.map(_.format).mkString("\n"))
private def defaultFail(passesResult: PassesResult): Assertion = {
fail(passesResult.messages.format)
}

def parseAndValidateTestInput(
Expand All @@ -99,20 +99,17 @@ abstract class ValidatingTest extends ParsingTest {
options: CommonOptions = CommonOptions(),
shouldFailOnErrors: Boolean = true
)(
validation: (RootContainer, Messages) => Assertion = (_, msgs) => defaultFail(msgs)
validation: (RootContainer, PassesResult) => Assertion = (_, pr) => defaultFail(pr)
): Assertion = {
val file = new File(directory + fileName)
TopLevelParser.parse(file) match {
case Left(errors) =>
val msgs = errors.format
fail(s"In $label:\n$msgs")
case Right(root) =>
runStandardPasses(root, options, shouldFailOnErrors) match {
case Left(errors) =>
fail(errors.format)
case Right(ao) =>
validation(root, ao.messages)
}
val input = PassInput(root, options)
val passesResult = Pass.runStandardPasses(input)
validation(root, passesResult)
}
}
def validateFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class CheckMessagesTest extends ValidatingTest {
def runForFile(file: File, readMessages: Set[String]): Unit = {
val expectedMessages = readMessages.map(_.trim)
validateFile(file.getName, file.getAbsolutePath) { (_, msgs) =>
val msgSet = msgs.map(_.format(true)).map(_.trim).toSet
val msgSet = msgs.map(_.format).map(_.trim).toSet
if msgSet == expectedMessages then { succeed }
else {
val missingMessages = expectedMessages.diff(msgSet).toSeq.sorted
Expand Down
Loading

0 comments on commit 09f2696

Please sign in to comment.