Skip to content

Commit 2f77e5c

Browse files
committed
Add e2e tests for sourcelinks of standard library of scala3
1 parent 8c382e9 commit 2f77e5c

File tree

9 files changed

+113
-80
lines changed

9 files changed

+113
-80
lines changed

.github/workflows/scaladoc.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,25 @@ jobs:
7070
echo uplading docs to https://scala3doc.virtuslab.com/$DOC_DEST
7171
az storage container create --name $DOC_DEST --account-name scala3docstorage --public-access container
7272
az storage blob upload-batch -s scaladoc/output -d $DOC_DEST --account-name scala3docstorage
73+
74+
stdlib-sourcelinks-test:
75+
runs-on: ubuntu-latest
76+
if: "( github.event_name == 'pull_request'
77+
&& !contains(github.event.pull_request.body, '[skip ci]')
78+
&& !contains(github.event.pull_request.body, '[skip docs]')
79+
)
80+
|| contains(github.event.ref, 'scaladoc')
81+
|| contains(github.event.ref, 'scala3doc')
82+
|| contains(github.event.ref, 'master')"
83+
84+
steps:
85+
- name: Git Checkout
86+
uses: actions/checkout@v2
87+
88+
- name: Set up JDK 8
89+
uses: actions/setup-java@v1
90+
with:
91+
java-version: 8
92+
93+
- name: Test sourcelinks to stdlib
94+
run: ./project/scripts/sbt scaladoc/sourceLinksIntegrationTest:test

project/Build.scala

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,17 +1182,6 @@ object Build {
11821182
// Note: the two tasks below should be one, but a bug in Tasty prevents that
11831183
val generateScalaDocumentation = inputKey[Unit]("Generate documentation for dotty lib")
11841184
val generateTestcasesDocumentation = taskKey[Unit]("Generate documentation for testcases, usefull for debugging tests")
1185-
lazy val `scaladoc-testcases` = project.in(file("scaladoc-testcases")).
1186-
dependsOn(`scala3-compiler-bootstrapped`).
1187-
settings(commonBootstrappedSettings)
1188-
lazy val `scaladoc-js` = project.in(file("scaladoc-js")).
1189-
enablePlugins(DottyJSPlugin).
1190-
dependsOn(`scala3-library-bootstrappedJS`).
1191-
settings(
1192-
Test / fork := false,
1193-
scalaJSUseMainModuleInitializer := true,
1194-
libraryDependencies += ("org.scala-js" %%% "scalajs-dom" % "1.1.0").cross(CrossVersion.for3Use2_13)
1195-
)
11961185

11971186
def generateDocumentation(targets: Seq[String], name: String, outDir: String, ref: String, params: Seq[String] = Nil) =
11981187
Def.taskDyn {
@@ -1217,10 +1206,18 @@ object Build {
12171206
Def.task((s"$distLocation/bin/scaladoc" +: cmd).!)
12181207
}
12191208

1209+
val SourceLinksIntegrationTest = config("sourceLinksIntegrationTest") extend Test
1210+
12201211
lazy val scaladoc = project.in(file("scaladoc")).
1212+
configs(SourceLinksIntegrationTest).
12211213
settings(commonBootstrappedSettings).
12221214
dependsOn(`scala3-compiler-bootstrapped`).
12231215
dependsOn(`scala3-tasty-inspector`).
1216+
settings(inConfig(SourceLinksIntegrationTest)(Defaults.testSettings)).
1217+
settings(
1218+
scalaSource in SourceLinksIntegrationTest := baseDirectory.value / "test-source-links",
1219+
test in SourceLinksIntegrationTest := ((test in SourceLinksIntegrationTest) dependsOn generateScalaDocumentation.toTask("")).value,
1220+
).
12241221
settings(
12251222
Compile / resourceGenerators += Def.task {
12261223
val jsDestinationFile = (Compile / resourceManaged).value / "dotty_res" / "scripts" / "searchbar.js"

scaladoc-testcases/src/toplevel.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
def toplevelDef = 123
22

3-
class ToplevelClass
3+
class ToplevelClass

scaladoc/src/dotty/tools/scaladoc/tasty/NameNormalizer.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ object NameNormalizer {
2121
private val ignoredKeywords: Set[String] = Set("this")
2222

2323
private def escapedName(name: String) =
24-
val simpleIdentifierRegex = raw"(?:\w+_[^\[\(\s_]+)|\w+|[^\[\(\s\w_]+".r
24+
val simpleIdentifierRegex = "([([{}]) ]|[^A-Za-z0-9$]_)".r
2525
name match
2626
case n if ignoredKeywords(n) => n
27-
case n if keywords(termName(n)) => s"`$n`"
28-
case simpleIdentifierRegex() => name
29-
case n => s"`$n`"
27+
case n if keywords(termName(n)) || simpleIdentifierRegex.findFirstIn(n).isDefined => s"`$n`"
28+
case _ => name
3029
}

scaladoc/src/dotty/tools/scaladoc/tasty/SyntheticSupport.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,3 @@ object SyntheticsSupport:
119119
typeForClass(c).asInstanceOf[dotc.core.Types.Type]
120120
.memberInfo(symbol.asInstanceOf[dotc.core.Symbols.Symbol])
121121
.asInstanceOf[TypeRepr]
122-

scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/DocFlexmarkExtension.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ case class DocFlexmarkRenderer(renderLink: (DocLink, String) => String)
6666
object DocFlexmarkRenderer:
6767
def render(node: Node)(renderLink: (DocLink, String) => String) =
6868
val opts = MarkdownParser.mkMarkdownOptions(Seq(DocFlexmarkRenderer(renderLink)))
69-
HtmlRenderer.builder(opts).build().render(node)
69+
HtmlRenderer.builder(opts).escapeHtml(true).build().render(node)

scaladoc/src/dotty/tools/scaladoc/util/html.scala

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,17 @@ object HTML:
1111
case class Tag(name: String):
1212
def apply(tags: TagArg*): AppliedTag = apply()(tags:_*)
1313
def apply(first: AttrArg, rest: AttrArg*): AppliedTag = apply((first +: rest):_*)()
14-
def apply(attrs: AttrArg*)(tags: TagArg*): AppliedTag = {
14+
def apply(attrs: AttrArg*)(tags: TagArg*): AppliedTag =
15+
def unpackTags(tags: TagArg*)(using sb: StringBuilder): StringBuilder =
16+
tags.foreach {
17+
case t: AppliedTag =>
18+
sb.append(t)
19+
case s: String =>
20+
sb.append(s.escapeReservedTokens)
21+
case s: Seq[AppliedTag | String] =>
22+
unpackTags(s:_*)
23+
}
24+
sb
1525
val sb = StringBuilder()
1626
sb.append(s"<$name")
1727
attrs.filter(_ != Nil).foreach{
@@ -21,22 +31,9 @@ object HTML:
2131
sb.append(" ").append(e)
2232
}
2333
sb.append(">")
24-
tags.foreach{
25-
case t: AppliedTag =>
26-
sb.append(t)
27-
case s: String =>
28-
sb.append(s.escapeReservedTokens)
29-
case s: Seq[AppliedTag | String] =>
30-
s.foreach{
31-
case a: AppliedTag =>
32-
sb.append(a)
33-
case s: String =>
34-
sb.append(s.escapeReservedTokens)
35-
}
36-
}
34+
unpackTags(tags:_*)(using sb)
3735
sb.append(s"</$name>")
3836
sb
39-
}
4037

4138
extension (s: String) private def escapeReservedTokens: String =
4239
s.replace("&", "&amp;")
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package dotty.tools.scaladoc
2+
package sourcelinks
3+
4+
import scala.io.Source
5+
import scala.jdk.CollectionConverters._
6+
import scala.util.matching.Regex
7+
import dotty.tools.scaladoc.test.BuildInfo
8+
import java.nio.file.Path
9+
import java.nio.file.Paths
10+
import org.jsoup.Jsoup
11+
import org.jsoup.nodes.Document
12+
import util.IO
13+
import org.junit.Assert.assertTrue
14+
import org.junit.Test
15+
16+
class RemoteLinksTest:
17+
18+
@Test
19+
def runTest =
20+
val mtsl = membersToSourceLinks(using testDocContext())
21+
val pageToMtsl: Map[String, List[(String, String)]] = mtsl.groupMap(_._2.split("#L").head)(v => (v._1, v._2.split("#L").last))
22+
pageToMtsl.foreach { case (link, members) =>
23+
try
24+
val doc = getDocumentFromUrl(link)
25+
members.foreach { (member, line) =>
26+
if !member.startsWith("given_") then // TODO: handle synthetic givens, for now we disable them from testing
27+
val loc = doc.select(s"#LC$line").text
28+
val memberToMatch = member.replace("`", "")
29+
assertTrue(s"Expected to find $memberToMatch at $link at line $line", loc.contains(memberToMatch))
30+
}
31+
catch
32+
case e: java.lang.IllegalArgumentException =>
33+
report.error(s"Could not open link for $link - invalid URL")(using testContext)
34+
case e: org.jsoup.HttpStatusException => e.getStatusCode match
35+
case 404 => throw AssertionError(s"Page $link does not exists")
36+
case n => report.warning(s"Could not open link for $link, return code $n")(using testContext)
37+
}
38+
assertNoErrors(testContext.reportedDiagnostics)
39+
40+
private def getDocumentFromUrl(link: String): Document =
41+
try
42+
Jsoup.connect(link).get
43+
catch
44+
case e: org.jsoup.HttpStatusException => e.getStatusCode match
45+
case 429 =>
46+
Thread.sleep(10)
47+
getDocumentFromUrl(link)
48+
case n =>
49+
throw e
50+
51+
private def membersToSourceLinks(using DocContext): List[(String, String)] =
52+
val output = Paths.get("scaladoc", "output", "scala3", "api").toAbsolutePath
53+
val mtsl = List.newBuilder[(String, String)]
54+
def processFile(path: Path): Unit =
55+
val document = Jsoup.parse(IO.read(path))
56+
if document.select("span.kind").first.text == "package" then
57+
document.select(".documentableElement").forEach { dElem =>
58+
if dElem.select("span.kind").first.text != "package" then
59+
dElem.select("dt").forEach { elem =>
60+
val content = elem.text
61+
if content == "Source" then
62+
mtsl += dElem.select(".documentableName").first.text -> elem.nextSibling.childNode(0).attr("href")
63+
}
64+
}
65+
IO.foreachFileIn(output, processFile)
66+
mtsl.result

scaladoc/test/dotty/tools/scaladoc/source-links/RemoteLinksTest.scala

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)