diff options
Diffstat (limited to 'src/test/scala')
| -rw-r--r-- | src/test/scala/firrtlTests/AnnotationTests.scala | 35 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/annotationTests/UnrecognizedAnnotationSpec.scala | 201 |
2 files changed, 235 insertions, 1 deletions
diff --git a/src/test/scala/firrtlTests/AnnotationTests.scala b/src/test/scala/firrtlTests/AnnotationTests.scala index 6ee63856..a8ff0aa0 100644 --- a/src/test/scala/firrtlTests/AnnotationTests.scala +++ b/src/test/scala/firrtlTests/AnnotationTests.scala @@ -564,7 +564,7 @@ class JsonAnnotationTests extends AnnotationTests { val manager = setupManager(Some(anno)) the[Exception] thrownBy Driver.execute(manager) should matchPattern { - case InvalidAnnotationFileException(_, _: AnnotationClassNotFoundException) => + case InvalidAnnotationFileException(_, _: UnrecogizedAnnotationsException) => } } @@ -614,4 +614,37 @@ class JsonAnnotationTests extends AnnotationTests { val cr = DoNothingTransform.runTransform(CircuitState(parse(input), ChirrtlForm, annos)) cr.annotations.toSeq shouldEqual annos } + + "fully qualified class name that is undeserializable" should "give an invalid json exception" in { + val anno = """ + |[ + | { + | "class":"firrtlTests.MyUnserAnno", + | "box":"7" + | } + |] """.stripMargin + + val manager = setupManager(Some(anno)) + the[Exception] thrownBy Driver.execute(manager) should matchPattern { + case InvalidAnnotationFileException(_, _: InvalidAnnotationJSONException) => + } + } + + "unqualified class name" should "give an unrecognized annotation exception" in { + val anno = """ + |[ + | { + | "class":"MyUnserAnno" + | "box":"7" + | } + |] """.stripMargin + val manager = setupManager(Some(anno)) + the[Exception] thrownBy Driver.execute(manager) should matchPattern { + case InvalidAnnotationFileException(_, _: UnrecogizedAnnotationsException) => + } + } } + +/* These are used by the last two tests. It is outside the main test to keep the qualified name simpler*/ +class UnserBox(val x: Int) +case class MyUnserAnno(box: UnserBox) extends NoTargetAnnotation diff --git a/src/test/scala/firrtlTests/annotationTests/UnrecognizedAnnotationSpec.scala b/src/test/scala/firrtlTests/annotationTests/UnrecognizedAnnotationSpec.scala new file mode 100644 index 00000000..d2df7703 --- /dev/null +++ b/src/test/scala/firrtlTests/annotationTests/UnrecognizedAnnotationSpec.scala @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: Apache-2.0 + +package firrtlTests.annotationTests + +import firrtl.FileUtils +import firrtl.annotations._ +import firrtl.passes.memlib.ReplSeqMemAnnotation +import firrtl.stage.FirrtlMain +import firrtl.testutils.FirrtlFlatSpec +import firrtl.transforms.BlackBoxInlineAnno +import logger.Logger +import logger.Logger.OutputCaptor + +import java.io.{File, PrintWriter} + +class UnrecognizedAnnotationSpec extends FirrtlFlatSpec { + behavior.of("unrecognized annotations can be carried through serialization and deserialization") + + it should "preserve unknown annotations when allowed" in { + val annotations = + JsonProtocol.deserialize(UnrecognizedAnnotationTextGenerator.jsonText(includeAllowUnrecognizedAnnotations = true)) + + annotations.exists(_.isInstanceOf[BlackBoxInlineAnno]) should be(true) + annotations.count(_.isInstanceOf[UnrecognizedAnnotation]) should be(2) + annotations.exists(_.isInstanceOf[ReplSeqMemAnnotation]) should be(false) + + val jsonOutputText = JsonProtocol.serialize(annotations) + + jsonOutputText should include(""""class":"firrtl.transforms.BlackBoxInlineAnno"""") + jsonOutputText should include(""""class":"freechips.rocketchip.util.RegFieldDescMappingAnnotation"""") + jsonOutputText should include(""""class":"freechips.rocketchip.util.SRAMAnnotation"""") + } + + it should "throw an error when unknown annotations are present but AllowUnrecognizedAnnotation is not" in { + + // Default log level is error, which the JSON parsing uses here + Logger.makeScope(Seq()) { + val captor = new OutputCaptor + Logger.setOutput(captor.printStream) + + val parsingError = intercept[UnrecogizedAnnotationsException] { + JsonProtocol.deserialize( + UnrecognizedAnnotationTextGenerator.jsonText(includeAllowUnrecognizedAnnotations = false) + ) + } + parsingError.getMessage should include("RegFieldDescMappingAnnotation") + + val output = captor.getOutputAsString + output should include("Annotation parsing found unrecognized annotations") + output should include( + "This error can be ignored with an AllowUnrecognizedAnnotationsAnnotation or command line flag --allow-unrecognized-annotations" + ) + output should include( + "freechips.rocketchip.util.RegFieldDescMappingAnnotation" + ) + output should include( + "freechips.rocketchip.util.SRAMAnnotation" + ) + } + } + + // Following test will operate on an annotation JSON file with two unrecognized annotations in it + // + + it should "fail by default" in { + val fileNames = setupFiles(addAllowUnrecognizedFlag = false, addAllowUnrecognizedAnno = false) + val args = makeCommandLineArgs(fileNames) + val e = intercept[InvalidAnnotationFileException] { + FirrtlMain.main(args) + } + + e.getMessage should include(fileNames.inputAnnotations) + e.getCause.getMessage should include("freechips.rocketchip.util.RegFieldDescMappingAnnotation") + e.getCause.getMessage should include("freechips.rocketchip.util.SRAMAnnotation") + } + + it should "succeed when the AllowUnrecognized flag is passed on command line" in { + val fileNames = setupFiles(addAllowUnrecognizedFlag = false, addAllowUnrecognizedAnno = true) + shouldSucceed(fileNames) + } + + it should "succeed when the AllowUnrecognizedAnnotation is in the annotation file" in { + val fileNames = setupFiles(addAllowUnrecognizedFlag = true, addAllowUnrecognizedAnno = false) + shouldSucceed(fileNames) + } + + it should "succeed when both forms of the override are specified" in { + val fileNames = setupFiles(addAllowUnrecognizedFlag = true, addAllowUnrecognizedAnno = true) + shouldSucceed(fileNames) + } + + def shouldSucceed(fileNames: TestFileNames): Unit = { + val args = makeCommandLineArgs(fileNames) + FirrtlMain.main(args) + + val outputAnnotationText = FileUtils.getText(fileNames.outputAnnotationsFull) + outputAnnotationText should include("freechips.rocketchip.util.RegFieldDescMappingAnnotation") + outputAnnotationText should include("freechips.rocketchip.util.SRAMAnnotation") + } + + case class TestFileNames( + allowUnrecognized: Boolean, + inputAnnotations: String, + outputAnnotations: String, + outputAnnotationsFull: String, + firrtlSource: String, + firrtlOutput: String) + + def setupFiles(addAllowUnrecognizedFlag: Boolean, addAllowUnrecognizedAnno: Boolean): TestFileNames = { + val dirName = (addAllowUnrecognizedFlag, addAllowUnrecognizedAnno) match { + case (false, false) => s"test_run_dir/unrecognized_annotation_fail" + case (true, false) => s"test_run_dir/unrecognized_annotation_flag" + case (false, true) => s"test_run_dir/unrecognized_annotation_anno" + case (true, true) => s"test_run_dir/unrecognized_annotation_flag_and_anno" + } + val dir = new File(dirName) + dir.mkdirs() + + val fileNames = TestFileNames( + allowUnrecognized = addAllowUnrecognizedFlag, + inputAnnotations = s"$dirName/input_annotations.json", + outputAnnotations = s"$dirName/output_annotations", + outputAnnotationsFull = s"$dirName/output_annotations.anno.json", + firrtlSource = s"$dirName/trivial.fir", + firrtlOutput = s"$dirName/trivial_out" + ) + + def writeText(fileName: String, text: String): Unit = { + val writer = new PrintWriter(fileName) + writer.write(text) + writer.close() + } + + writeText( + fileNames.inputAnnotations, + UnrecognizedAnnotationTextGenerator.jsonText(includeAllowUnrecognizedAnnotations = addAllowUnrecognizedAnno) + ) + writeText( + fileNames.firrtlSource, + s""" + |circuit Trivial : + | module Trivial : + | input clock : Clock + | input reset : UInt<1> + |""".stripMargin + ) + fileNames + } + + /* construct an array of command line strings, based on file names and */ + def makeCommandLineArgs(fileNames: TestFileNames): Array[String] = { + + (if (fileNames.allowUnrecognized) { + Array("--allow-unrecognized-annotations") + } else { + Array.empty[String] + }) ++ + Array( + "--annotation-file", + fileNames.inputAnnotations, + "-i", + fileNames.firrtlSource, + "-X", + "high", + "-o", + fileNames.firrtlOutput, + "--output-annotation-file", + fileNames.outputAnnotations + ) + } +} + +object UnrecognizedAnnotationTextGenerator { + + def jsonText(includeAllowUnrecognizedAnnotations: Boolean): String = { + val serializedAllowUnrecognized = if (includeAllowUnrecognizedAnnotations) { + """ + | { + | "class": "firrtl.stage.AllowUnrecognizedAnnotations$" + | },""".stripMargin + } else { + "" + } + + s"""|[$serializedAllowUnrecognized + | { + | "class": "firrtl.transforms.BlackBoxInlineAnno", + | "target": "TestHarness.plusarg_reader_27", + | "name": "plusarg_reader.v", + | "text": "License text" + | }, + | { + | "class": "freechips.rocketchip.util.RegFieldDescMappingAnnotation", + | }, + | { + | "class": "freechips.rocketchip.util.SRAMAnnotation", + | } + |] + |""".stripMargin + } +} |
