Skip to content

Commit 73a73bf

Browse files
committed
Add basic test
1 parent 556f708 commit 73a73bf

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed
+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
//
5+
// Copyright (c) 2011-2024 ETH Zurich.
6+
7+
import org.scalatest.funsuite.AnyFunSuite
8+
import viper.silver.ast.Program
9+
import viper.silver.frontend._
10+
import viper.silver.logger.ViperStdOutLogger
11+
import viper.silver.reporter.StdIOReporter
12+
import viper.silver.parser.{PProgram, PAnnotatedExp, PWhile}
13+
14+
class DocAnnotationTests extends AnyFunSuite {
15+
object AstProvider extends ViperAstProvider(StdIOReporter(), ViperStdOutLogger("DocAnnotationTestsLogger").get) {
16+
def setCode(code: String): Unit = {
17+
_input = Some(code)
18+
}
19+
20+
override def reset(input: java.nio.file.Path): Unit = {
21+
if (state < DefaultStates.Initialized) sys.error("The translator has not been initialized.")
22+
_state = DefaultStates.InputSet
23+
_inputFile = Some(input)
24+
/** must be set by [[setCode]] */
25+
// _input = None
26+
_errors = Seq()
27+
_parsingResult = None
28+
_semanticAnalysisResult = None
29+
_verificationResult = None
30+
_program = None
31+
resetMessages()
32+
}
33+
}
34+
35+
def generatePAstAndAst(code: String): Option[(PProgram, Program)] = {
36+
val code_id = code.hashCode.asInstanceOf[Short].toString
37+
AstProvider.setCode(code)
38+
AstProvider.execute(Seq("--ignoreFile", code_id))
39+
40+
if (AstProvider.errors.isEmpty) {
41+
Some(AstProvider.parsingResult, AstProvider.translationResult)
42+
} else {
43+
AstProvider.logger.error(s"An error occurred while translating ${AstProvider.errors}")
44+
None
45+
}
46+
}
47+
48+
test("Basic parsing of documentation") {
49+
import viper.silver.ast._
50+
51+
val code =
52+
"""/// a field
53+
|field f: Int
54+
|/// P is a predicate
55+
|predicate P(x: Int)
56+
|
57+
|/// a function
58+
|function fun(x: Int): Int {
59+
| (x / 1 == x) ? 42 : 0
60+
|}
61+
|/// a second function
62+
|function fun2(x: Int): Int
63+
| /// precondition
64+
| requires x > 0
65+
| /// post-
66+
| /// condition
67+
| ensures result > 0
68+
|
69+
|/// very important domain
70+
|domain ImportantType {
71+
|
72+
| /// this function
73+
| /// is crucial
74+
| function phi(ImportantType): Int
75+
|
76+
| /// the only axiom
77+
| axiom {
78+
| /// documenting an expression
79+
| true
80+
| }
81+
|}
82+
|
83+
|/// a macro
84+
|define plus(a, b) (a+b)
85+
|
86+
|/// this is a method
87+
|/// it does something
88+
|method m(x: Ref, y: Ref)
89+
| /// this documents the first precondition
90+
| requires acc(x.f)
91+
| /// documentation of the second precondition
92+
| requires acc(y.f)
93+
|{
94+
| var local: Bool
95+
|
96+
| while (true)///the invariant
97+
| /// is always true
98+
| invariant true
99+
| /// termination
100+
| decreases x.f
101+
| {}
102+
|
103+
|}
104+
|""".stripMargin
105+
106+
val pAst: PProgram = generatePAstAndAst(code).get._1
107+
108+
val fieldAnn = pAst.fields.head.annotations.head.values.inner.first.get.str
109+
assert(fieldAnn == " a field")
110+
111+
val predicateAnnotation = pAst.predicates.head.annotations.head.values.inner.first.get.str
112+
assert(predicateAnnotation == " P is a predicate")
113+
114+
val functionAnnotation = pAst.functions.head.annotations.head.values.inner.first.get.str
115+
assert(functionAnnotation == " a function")
116+
117+
val fun2Annotation = pAst.functions(1).annotations.head.values.inner.first.get.str
118+
val fun2PreAnnotations = pAst.functions(1).pres.head.annotations.map(_.values.inner.first.get.str)
119+
val fun2PostAnnotations = pAst.functions(1).posts.head.annotations.map(_.values.inner.first.get.str)
120+
assert(fun2Annotation == " a second function")
121+
assert(fun2PreAnnotations == Seq(" precondition"))
122+
assert(fun2PostAnnotations == Seq(" post-", " condition"))
123+
124+
val domainAnnotation = pAst.domains.head.annotations.head.values.inner.first.get.str
125+
assert(domainAnnotation == " very important domain")
126+
127+
val domainFunctionAnnotations = pAst.domains.head.members.inner.funcs.head.annotations.map(_.values.inner.first.get.str)
128+
assert(domainFunctionAnnotations == Seq(" this function", " is crucial"))
129+
130+
val axiomAnnotations = pAst.domains.head.members.inner.axioms.head.annotations.map(_.values.inner.first.get.str)
131+
assert(axiomAnnotations == Seq(" the only axiom"))
132+
val axiomExpAnnotations = pAst.domains.head.members.inner.axioms.head.exp.e.inner.asInstanceOf[PAnnotatedExp].annotation.values.inner.first.get.str
133+
assert(axiomExpAnnotations == " documenting an expression")
134+
135+
val macroAnnotation = pAst.macros.head.annotations.head.values.inner.first.get.str
136+
assert(macroAnnotation == " a macro")
137+
138+
val methodAnnotations = pAst.methods.head.annotations.map(_.values.inner.first.get.str)
139+
assert(methodAnnotations == Seq(" this is a method", " it does something"))
140+
141+
val methodPreAnnotations = pAst.methods.head.pres.toSeq.map(_.annotations.head.values.inner.first.get.str)
142+
assert(methodPreAnnotations == Seq(" this documents the first precondition", " documentation of the second precondition"))
143+
144+
val loopInvariantAnnotations = pAst.methods.head.body.get.ss.inner.inner.collect {
145+
case (_, w: PWhile) => w.invs.toSeq.flatMap(_.annotations.map(_.values.inner.first.get.str))
146+
}.flatten
147+
assert(loopInvariantAnnotations == Seq("the invariant", " is always true", " termination"))
148+
}
149+
}

0 commit comments

Comments
 (0)