diff --git a/.circleci/config.yml b/.circleci/config.yml index 9c15bf2b..531f3394 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -224,9 +224,6 @@ workflows: - run: name: Unit testing command: sbt test - - run: - name: It testing - command: sbt it:test - run: name: Aggregate coverage reports command: sbt coverageAggregate diff --git a/api-scala/src/main/scala/com/codacy/api/CoverageReport.scala b/api-scala/src/main/scala/com/codacy/api/CoverageReport.scala new file mode 100644 index 00000000..f4e66419 --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/CoverageReport.scala @@ -0,0 +1,21 @@ +package com.codacy.api + +import play.api.libs.json.{JsNumber, JsObject, Json, Writes} + +case class CoverageFileReport(filename: String, coverage: Map[Int, Int]) + +case class CoverageReport(fileReports: Seq[CoverageFileReport]) + +object CoverageReport { + implicit val mapWrites: Writes[Map[Int, Int]] = Writes[Map[Int, Int]] { map: Map[Int, Int] => + JsObject(map.map { + case (key, value) => (key.toString, JsNumber(value)) + }(collection.breakOut)) + } + implicit val coverageFileReportWrites: Writes[CoverageFileReport] = Json.writes[CoverageFileReport] + implicit val coverageReportWrites: Writes[CoverageReport] = Json.writes[CoverageReport] +} + +object OrganizationProvider extends Enumeration { + val manual, gh, bb, ghe, bbe, gl, gle = Value +} diff --git a/api-scala/src/main/scala/com/codacy/api/client/CodacyClient.scala b/api-scala/src/main/scala/com/codacy/api/client/CodacyClient.scala new file mode 100644 index 00000000..f971657b --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/client/CodacyClient.scala @@ -0,0 +1,109 @@ +package com.codacy.api.client + +import play.api.libs.json._ +import com.codacy.api.util.JsonOps +import scalaj.http.Http + +import java.net.URL +import scala.util.{Failure, Success, Try} +import scala.util.control.NonFatal + +class CodacyClient( + apiUrl: Option[String] = None, + apiToken: Option[String] = None, + projectToken: Option[String] = None +) { + + private case class ErrorJson(error: String) + private case class PaginatedResult[T](next: Option[String], values: Seq[T]) + + private implicit val errorJsonFormat: Reads[ErrorJson] = Json.reads[ErrorJson] + + private val tokens = Map.empty[String, String] ++ + apiToken.map(t => "api-token" -> t) ++ + projectToken.map(t => "project-token" -> t) ++ + // This is deprecated and is kept for backward compatibility. It will removed in the context of CY-1272 + apiToken.map(t => "api_token" -> t) ++ + projectToken.map(t => "project_token" -> t) + + private val remoteUrl = new URL(new URL(apiUrl.getOrElse("https://api.codacy.com")), "/2.0").toString() + + /* + * Does an API post + */ + def post[T]( + request: Request[T], + value: String, + timeoutOpt: Option[RequestTimeout] = None, + sleepTime: Option[Int], + numRetries: Option[Int] + )(implicit reads: Reads[T]): RequestResponse[T] = { + val url = s"$remoteUrl/${request.endpoint}" + try { + val headers = tokens ++ Map("Content-Type" -> "application/json") + + val httpRequest = timeoutOpt match { + case Some(timeout) => + Http(url).timeout(connTimeoutMs = timeout.connTimeoutMs, readTimeoutMs = timeout.readTimeoutMs) + case None => Http(url) + } + + val body = httpRequest + .params(request.queryParameters) + .headers(headers) + .postData(value) + .asString + .body + + parseJsonAs[T](body) match { + case failure: FailedResponse => + retryPost(request, value, timeoutOpt, sleepTime, numRetries.map(x => x - 1), failure.message) + case success => success + } + } catch { + case NonFatal(ex) => retryPost(request, value, timeoutOpt, sleepTime, numRetries.map(x => x - 1), ex.getMessage) + } + } + + private def retryPost[T]( + request: Request[T], + value: String, + timeoutOpt: Option[RequestTimeout], + sleepTime: Option[Int], + numRetries: Option[Int], + failureMessage: String + )(implicit reads: Reads[T]): RequestResponse[T] = { + if (numRetries.exists(x => x > 0)) { + sleepTime.map(x => Thread.sleep(x)) + post(request, value, timeoutOpt, sleepTime, numRetries.map(x => x - 1)) + } else { + RequestResponse.failure( + s"Error doing a post to $remoteUrl/${request.endpoint}: exhausted retries due to $failureMessage" + ) + } + } + + private def parseJsonAs[T](input: String)(implicit reads: Reads[T]): RequestResponse[T] = { + parseJson(input) match { + case failure: FailedResponse => failure + case SuccessfulResponse(json) => + json + .validate[T] + .fold( + errors => FailedResponse(JsonOps.handleConversionFailure(errors)), + converted => SuccessfulResponse(converted) + ) + } + } + + private def parseJson(input: String): RequestResponse[JsValue] = { + Try(Json.parse(input)) match { + case Success(json) => + json + .validate[ErrorJson] + .fold(_ => SuccessfulResponse(json), apiError => FailedResponse(s"API Error: ${apiError.error}")) + case Failure(exception) => + FailedResponse(s"Failed to parse API response as JSON: $input\nUnderlying exception - ${exception.getMessage}") + } + } +} diff --git a/api-scala/src/main/scala/com/codacy/api/client/Request.scala b/api-scala/src/main/scala/com/codacy/api/client/Request.scala new file mode 100644 index 00000000..3555284e --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/client/Request.scala @@ -0,0 +1,3 @@ +package com.codacy.api.client + +case class Request[T](endpoint: String, classType: Class[T], queryParameters: Map[String, String] = Map.empty) diff --git a/api-scala/src/main/scala/com/codacy/api/client/RequestResponse.scala b/api-scala/src/main/scala/com/codacy/api/client/RequestResponse.scala new file mode 100644 index 00000000..4c82e348 --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/client/RequestResponse.scala @@ -0,0 +1,27 @@ +package com.codacy.api.client + +sealed trait RequestResponse[+A] + +case class SuccessfulResponse[A](value: A) extends RequestResponse[A] + +case class FailedResponse(message: String) extends RequestResponse[Nothing] + +object RequestResponse { + + def success[A](a: A): RequestResponse[A] = SuccessfulResponse(a) + + def failure[A](message: String): RequestResponse[A] = FailedResponse(message: String) + + def apply[A](r1: RequestResponse[Seq[A]], r2: RequestResponse[Seq[A]]): RequestResponse[Seq[A]] = { + r1 match { + case SuccessfulResponse(v1) => + r2 match { + case SuccessfulResponse(v2) => + SuccessfulResponse(v1 ++ v2) + case f @ FailedResponse(_) => f + } + case f @ FailedResponse(_) => f + } + } + +} diff --git a/api-scala/src/main/scala/com/codacy/api/client/RequestSuccess.scala b/api-scala/src/main/scala/com/codacy/api/client/RequestSuccess.scala new file mode 100644 index 00000000..fa9b1180 --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/client/RequestSuccess.scala @@ -0,0 +1,9 @@ +package com.codacy.api.client + +import play.api.libs.json.{Json, Reads} + +case class RequestSuccess(success: String) + +object RequestSuccess { + implicit val requestSuccessReads: Reads[RequestSuccess] = Json.reads[RequestSuccess] +} diff --git a/api-scala/src/main/scala/com/codacy/api/client/RequestTimeout.scala b/api-scala/src/main/scala/com/codacy/api/client/RequestTimeout.scala new file mode 100644 index 00000000..546aaf2c --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/client/RequestTimeout.scala @@ -0,0 +1,6 @@ +package com.codacy.api.client + +/** + * The socket connection and read timeouts in milliseconds. + */ +case class RequestTimeout(connTimeoutMs: Int, readTimeoutMs: Int) diff --git a/api-scala/src/main/scala/com/codacy/api/helpers/FileHelper.scala b/api-scala/src/main/scala/com/codacy/api/helpers/FileHelper.scala new file mode 100644 index 00000000..ecfe3455 --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/helpers/FileHelper.scala @@ -0,0 +1,19 @@ +package com.codacy.api.helpers + +import java.io.{File, PrintWriter} + +import play.api.libs.json._ + +import scala.util.Try + +object FileHelper { + + def writeJsonToFile[A](file: File, value: A)(implicit writes: Writes[A]): Boolean = { + val reportJson = Json.stringify(Json.toJson(value)) + val printWriter = new PrintWriter(file) + val result = Try(printWriter.write(reportJson)).isSuccess + printWriter.close() + result + } + +} diff --git a/api-scala/src/main/scala/com/codacy/api/helpers/vcs/GitClient.scala b/api-scala/src/main/scala/com/codacy/api/helpers/vcs/GitClient.scala new file mode 100644 index 00000000..e4cd94dd --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/helpers/vcs/GitClient.scala @@ -0,0 +1,41 @@ +package com.codacy.api.helpers.vcs + +import java.io.File +import java.util.Date + +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.lib.{Repository, RepositoryBuilder} + +import scala.collection.JavaConverters._ +import scala.util.Try + +case class CommitInfo(uuid: String, authorName: String, authorEmail: String, date: Date) + +class GitClient(workDirectory: File) { + + val repositoryTry: Try[Repository] = Try(new RepositoryBuilder().findGitDir(workDirectory).readEnvironment().build()) + + val repository: Option[Repository] = repositoryTry.toOption + + def latestCommitUuid(): Option[String] = { + repositoryTry + .map { rep => + val git = new Git(rep) + val headRev = git.log().setMaxCount(1).call().asScala.head + headRev.getName + } + .toOption + .filter(_.trim.nonEmpty) + } + + def latestCommitInfo: Try[CommitInfo] = { + repositoryTry.map { rep => + val git = new Git(rep) + val headRev = git.log().setMaxCount(1).call().asScala.head + val authorIdent = headRev.getAuthorIdent + + CommitInfo(headRev.getName, authorIdent.getName, authorIdent.getEmailAddress, authorIdent.getWhen) + } + } + +} diff --git a/api-scala/src/main/scala/com/codacy/api/service/CoverageServices.scala b/api-scala/src/main/scala/com/codacy/api/service/CoverageServices.scala new file mode 100644 index 00000000..c4675bbb --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/service/CoverageServices.scala @@ -0,0 +1,143 @@ +package com.codacy.api.service + +import com.codacy.api.client.{CodacyClient, Request, RequestResponse, RequestSuccess, RequestTimeout} +import com.codacy.api.{CoverageReport, OrganizationProvider} +import play.api.libs.json.Json + +class CoverageServices(client: CodacyClient) { + + /** + * Send coverage report to Codacy endpoint. + * This endpoint requires a project token to authenticate the request and identify the project. + * Therefore, the client must be initialized with a valid project token. + * @param commitUuid commit unique identifier + * @param language programing language + * @param coverageReport coverage report being sent to Codacy + * @param partial flag that signals if the report operation will be broken in multiple operations + * @param timeoutOpt socket connection and read timeouts in milliseconds + * @return Request response + */ + def sendReport( + commitUuid: String, + language: String, + coverageReport: CoverageReport, + partial: Boolean = false, + timeoutOpt: Option[RequestTimeout] = None, + sleepTime: Option[Int] = None, + numRetries: Option[Int] = None, + ): RequestResponse[RequestSuccess] = { + val endpoint = s"coverage/$commitUuid/${encodePathSegment(language.toLowerCase)}" + + postRequest(endpoint, coverageReport, partial, timeoutOpt, sleepTime, numRetries) + } + + /** + * Send final notification signaling the end of the report operation. + * This endpoint requires an account token to authenticate the request and identify the project. + * Therefore, the client must be initialized with a valid account token. + * @param commitUuid commit unique identifier + * @param timeoutOpt socket connection and read timeouts in milliseconds + * @return Request Response + */ + def sendFinalNotification( + commitUuid: String, + timeoutOpt: Option[RequestTimeout] = None, + sleepTime: Option[Int] = None, + numRetries: Option[Int] = None, + ): RequestResponse[RequestSuccess] = { + val endpoint = s"commit/$commitUuid/coverageFinal" + + postEmptyRequest(endpoint, timeoutOpt, sleepTime, numRetries) + } + + /** + * Send coverage report with a project name to Codacy endpoint. + * This endpoint requires an account token to authenticate the request. + * Therefore, the client must be initialized with a valid account token. + * @param username reporter's username + * @param projectName name of the project the report pertains + * @param commitUuid commit unique identifier + * @param language programing language + * @param coverageReport coverage report being reported + * @param partial flag that signals if the report operation will be broken in multiple operations + * @param timeoutOpt socket connection and read timeouts in milliseconds + * @return Request Response + */ + def sendReportWithProjectName( + provider: OrganizationProvider.Value, + username: String, + projectName: String, + commitUuid: String, + language: String, + coverageReport: CoverageReport, + partial: Boolean = false, + timeoutOpt: Option[RequestTimeout] = None, + sleepTime: Option[Int] = None, + numRetries: Option[Int] = None, + ): RequestResponse[RequestSuccess] = { + val endpoint = + s"${provider.toString}/$username/$projectName/commit/$commitUuid/coverage/${encodePathSegment(language.toLowerCase)}" + postRequest(endpoint, coverageReport, partial, timeoutOpt, sleepTime, numRetries) + } + + /** + * Send final notification with a project name, signaling the end of the report operation. + * This endpoint requires an account token to authenticate the request. + * Therefore, the client must be initialized with a valid account token. + * @param username reporter's username + * @param projectName name of the project the report pertains + * @param commitUuid commit unique identifier + * @param timeoutOpt socket connection and read timeouts in milliseconds + * @return Request Response + */ + def sendFinalWithProjectName( + provider: OrganizationProvider.Value, + username: String, + projectName: String, + commitUuid: String, + timeoutOpt: Option[RequestTimeout] = None, + sleepTime: Option[Int] = None, + numRetries: Option[Int] = None + ): RequestResponse[RequestSuccess] = { + val endpoint = s"${provider.toString}/$username/$projectName/commit/$commitUuid/coverageFinal" + + postEmptyRequest(endpoint, timeoutOpt, sleepTime, numRetries) + } + + private def postRequest( + endpoint: String, + coverageReport: CoverageReport, + partial: Boolean, + timeoutOpt: Option[RequestTimeout], + sleepTime: Option[Int], + numRetries: Option[Int] + ) = { + val queryParams = getQueryParameters(partial) + + val jsonString = serializeCoverageReport(coverageReport) + + client.post(Request(endpoint, classOf[RequestSuccess], queryParams), jsonString, timeoutOpt, sleepTime, numRetries) + } + + private def postEmptyRequest( + endpoint: String, + timeoutOpt: Option[RequestTimeout], + sleepTime: Option[Int], + numRetries: Option[Int] + ) = + client.post(Request(endpoint, classOf[RequestSuccess]), "{}", timeoutOpt, sleepTime, numRetries) + + private def getQueryParameters(partial: Boolean) = { + Map("partial" -> partial.toString) + } + private def serializeCoverageReport(coverageReport: CoverageReport) = + Json.stringify(Json.toJson(coverageReport)) + + /** + * Any encoding that we do here, needs to have the same output + * of play.utils.UriEncoding.encodePathSegment for our languages. + * https://github.com/playframework/playframework/blob/316fbd61c9fc6a6081a3aeef7e773c8bbccd0b6b/core/play/src/main/scala/play/utils/UriEncoding.scala#L50 + */ + private def encodePathSegment(segment: String): String = segment.replaceAll(" ", "%20") + +} diff --git a/api-scala/src/main/scala/com/codacy/api/util/JsonOps.scala b/api-scala/src/main/scala/com/codacy/api/util/JsonOps.scala new file mode 100644 index 00000000..89be5fb6 --- /dev/null +++ b/api-scala/src/main/scala/com/codacy/api/util/JsonOps.scala @@ -0,0 +1,11 @@ +package com.codacy.api.util + +import play.api.libs.json.{JsError, JsPath, Json, JsonValidationError} + +object JsonOps { + + def handleConversionFailure(error: Seq[(JsPath, Seq[JsonValidationError])]): String = { + val jsonError = Json.stringify(JsError.toJson(error.toList)) + s"Json conversion error: $jsonError" + } +} diff --git a/api-scala/src/test/scala/com/codacy/api/GitClientTest.scala b/api-scala/src/test/scala/com/codacy/api/GitClientTest.scala new file mode 100644 index 00000000..7001d8f2 --- /dev/null +++ b/api-scala/src/test/scala/com/codacy/api/GitClientTest.scala @@ -0,0 +1,21 @@ +package com.codacy.api + +import com.codacy.api.helpers.vcs.GitClient +import java.nio.file.Paths +import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.OptionValues._ + +class GitClientTest extends FlatSpec with Matchers { + + "GitClient" should "latestCommitUuid" in { + + val file = Paths.get("").toAbsolutePath.toFile + + val latest: Option[String] = new GitClient(file).latestCommitUuid() + + latest shouldNot be(None) + + latest.value shouldNot be('empty) + } + +} diff --git a/build.sbt b/build.sbt index c38c63f6..3fb8c488 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ inThisBuild( Seq( - scalaVersion := "2.12.11", + scalaVersion := "2.12.18", scalacOptions := Seq( "-deprecation", "-feature", @@ -28,9 +28,6 @@ libraryDependencies ++= Seq( "org.mockito" %% "mockito-scala-scalatest" % "1.7.1" % Test ) -configs(IntegrationTest) -Defaults.itSettings - assembly / mainClass := Some("com.codacy.CodacyCoverageReporter") assembly / assemblyMergeStrategy := { case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard @@ -39,6 +36,7 @@ assembly / assemblyMergeStrategy := { } assembly / test := {} crossPaths := false +run / fork := true // HACK: Since we are only using the public resolvers we need to remove the private for it to not fail resolvers ~= { @@ -83,16 +81,27 @@ nativeImageOptions := Seq( dependsOn(coverageParser) +lazy val apiScala = project + .in(file("api-scala")) + .settings( + libraryDependencies ++= Seq( + "com.typesafe.play" %% "play-json" % "2.8.2", + "org.scalaj" %% "scalaj-http" % "2.4.2", + "org.eclipse.jgit" % "org.eclipse.jgit" % "4.8.0.201706111038-r", + "org.scalatest" %% "scalatest" % "3.0.8" % Test + ) + ) + lazy val coverageParser = project .in(file("coverage-parser")) .settings( libraryDependencies ++= Seq( - "com.codacy" %% "codacy-api-scala" % "7.0.7", "com.codacy" %% "codacy-plugins-api" % "5.2.0", "org.scala-lang.modules" %% "scala-xml" % "1.2.0", "org.scalatest" %% "scalatest" % "3.0.8" % Test ) ) + .dependsOn(apiScala) // https://github.com/sbt/sbt-assembly/issues/146 ThisBuild / assemblyMergeStrategy := { diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CloverParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CloverParser.scala index 2a60e120..fe43737d 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CloverParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CloverParser.scala @@ -4,7 +4,7 @@ import java.io.File import java.nio.file.Paths import com.codacy.api.{CoverageFileReport, CoverageReport} -import com.codacy.parsers.util.{MathUtils, TextUtils} +import com.codacy.parsers.util.TextUtils import com.codacy.parsers.{CoverageParser, XmlReportParser} import scala.xml.{Elem, Node, NodeSeq} @@ -27,10 +27,6 @@ object CloverParser extends CoverageParser with XmlReportParser { override def getRootNode(xml: Elem): NodeSeq = xml \\ CoverageTag private def parseReportNode(rootProject: File, report: NodeSeq): Either[String, CoverageReport] = { - val metricsNode = report \ ProjectTag \ MetricsTag - val totalCoverage = getCoveragePercentage(metricsNode).left - .map(errorMessage => s"Could not retrieve total coverage from metrics tag in project: $errorMessage") - val rootPath = TextUtils.sanitiseFilename(rootProject.getAbsolutePath) val coverageFiles = (report \\ "file").foldLeft[Either[String, Seq[CoverageFileReport]]](Right(List())) { @@ -42,16 +38,8 @@ object CloverParser extends CoverageParser with XmlReportParser { } for { - totalCoverage <- totalCoverage coverageFiles <- coverageFiles - } yield CoverageReport(totalCoverage, coverageFiles) - } - - private def getCoveragePercentage(metrics: NodeSeq): Either[String, Int] = { - for { - totalStatements <- getFirstNonEmptyValueAsInt(metrics, "statements") - coveredStatements <- getFirstNonEmptyValueAsInt(metrics, "coveredstatements") - } yield MathUtils.computePercentage(coveredStatements, totalStatements) + } yield CoverageReport(coverageFiles) } private def getCoverageFileReport(rootPath: String, fileNode: Node): Either[String, CoverageFileReport] = { @@ -72,15 +60,9 @@ object CloverParser extends CoverageParser with XmlReportParser { for { relativeFilePath <- relativeFilePath - metricsNode = fileNode \ MetricsTag - fileCoverage <- getCoveragePercentage(metricsNode).left - .map( - errorMessage => - s"Could not retrieve file coverage from metrics tag for file '$relativeFilePath': $errorMessage" - ) linesCoverage <- getLinesCoverage(fileNode).left .map(errorMessage => s"Could not retrieve lines coverage for file '$relativeFilePath': $errorMessage") - } yield CoverageFileReport(relativeFilePath, fileCoverage, linesCoverage) + } yield CoverageFileReport(relativeFilePath, linesCoverage) } private def getLinesCoverage(fileNode: Node): Either[String, Map[Int, Int]] = { diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CoberturaParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CoberturaParser.scala index b54790ab..878bc63e 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CoberturaParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/CoberturaParser.scala @@ -32,8 +32,6 @@ object CoberturaParser extends CoverageParser with XmlReportParser { private def parseReportNode(projectRoot: File, report: NodeSeq) = { val projectRootStr: String = TextUtils.sanitiseFilename(projectRoot.getAbsolutePath) - val total = math.round(TextUtils.asFloat(report \\ CoverageTag \@ LineRateAttribute) * 100) - val fileReports: List[CoverageFileReport] = (for { (filename, classes) <- (report \\ "class").groupBy(c => c \@ "filename") } yield { @@ -41,16 +39,10 @@ object CoberturaParser extends CoverageParser with XmlReportParser { lineCoverage(cleanFilename, classes) })(collection.breakOut) - CoverageReport(total, fileReports) + CoverageReport(fileReports) } private def lineCoverage(sourceFilename: String, classes: NodeSeq): CoverageFileReport = { - val classHit = (classes \\ s"@$LineRateAttribute").map { total => - val totalValue = TextUtils.asFloat(total.text) - math.round(totalValue * 100) - } - val fileHit = if (classHit.nonEmpty) { classHit.sum / classHit.length } else 0 - val map = mutable.Map.empty[Int, Int] for { @@ -64,6 +56,6 @@ object CoberturaParser extends CoverageParser with XmlReportParser { map(key) = sum.toIntOrMaxValue } - CoverageFileReport(sourceFilename, fileHit, map.toMap) + CoverageFileReport(sourceFilename, map.toMap) } } diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/DotcoverParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/DotcoverParser.scala index 6dfbfe97..eeec42ca 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/DotcoverParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/DotcoverParser.scala @@ -3,7 +3,7 @@ package com.codacy.parsers.implementation import java.io.File import com.codacy.api.{CoverageFileReport, CoverageReport} -import com.codacy.parsers.util.{MathUtils, TextUtils} +import com.codacy.parsers.util.TextUtils import com.codacy.parsers.{CoverageParser, XmlReportParser} import scala.xml.{Elem, NodeSeq} @@ -29,8 +29,6 @@ object DotcoverParser extends CoverageParser with XmlReportParser { private def parseReportNode(rootProject: File, rootNode: NodeSeq): CoverageReport = { val projectRootStr: String = TextUtils.sanitiseFilename(rootProject.getAbsolutePath) - val totalCoverage = (rootNode \@ CoverageAttribute).toInt - val fileIndices: Map[Int, String] = (rootNode \ "FileIndices" \ "File").map { x => (x \@ "Index").toInt -> (x \@ "Name") }.toMap @@ -43,10 +41,9 @@ object DotcoverParser extends CoverageParser with XmlReportParser { lineCoverage = getLineCoverage(statements) totalLines = lineCoverage.keys.size coveredLines = lineCoverage.values.count(_ > 0) - total = MathUtils.computePercentage(coveredLines, totalLines) - } yield CoverageFileReport(filename, total, lineCoverage) + } yield CoverageFileReport(filename, lineCoverage) - CoverageReport(totalCoverage, fileReports.toSeq) + CoverageReport(fileReports.toSeq) } private def getLineCoverage(statementNodes: NodeSeq) = { diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/GoParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/GoParser.scala index c539c481..03234d64 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/GoParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/GoParser.scala @@ -56,12 +56,12 @@ object GoParser extends CoverageParser { } } - accum :+ CoverageFileReport(filename, 0, coverage) + accum :+ CoverageFileReport(filename, coverage) } }) - CoverageReport(0, coverageFileReports) + CoverageReport(coverageFileReports) } private def parseAllCoverageInfo(lines: List[String]): List[GoCoverageInfo] = { diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/JacocoParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/JacocoParser.scala index cb3f69da..80ffee39 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/JacocoParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/JacocoParser.scala @@ -41,7 +41,7 @@ object JacocoParser extends CoverageParser with XmlReportParser { lineCoverage(filename, sourceFile) } - CoverageReport(total, filesCoverage) + CoverageReport(filesCoverage) } } @@ -59,15 +59,6 @@ object JacocoParser extends CoverageParser with XmlReportParser { } private def lineCoverage(filename: String, fileNode: Node): CoverageFileReport = { - val lineHit = (fileNode \ "counter").collect { - case counter if (counter \@ "type") == "LINE" => - val covered = TextUtils.asFloat((counter \@ "covered")) - val missed = TextUtils.asFloat((counter \@ "missed")) - (if ((covered + missed) > 0) (covered / (covered + missed)) * 100 else 0f).toInt - } - - val fileHit = if (lineHit.sum != 0) { lineHit.sum / lineHit.length } else 0 - val lineHitMap: Map[Int, Int] = (fileNode \\ "line") .map { line => (line \@ "nr").toInt -> LineCoverage((line \@ "mi").toInt, (line \@ "ci").toInt) @@ -77,6 +68,6 @@ object JacocoParser extends CoverageParser with XmlReportParser { key -> (if (lineCoverage.coveredInstructions > 0) 1 else 0) }(collection.breakOut) - CoverageFileReport(filename, fileHit, lineHitMap) + CoverageFileReport(filename, lineHitMap) } } diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/LCOVParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/LCOVParser.scala index f486cfdb..3c935485 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/LCOVParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/LCOVParser.scala @@ -5,7 +5,7 @@ import com.codacy.parsers.util.MathUtils._ import com.codacy.api.{CoverageFileReport, CoverageReport} import java.io.File -import com.codacy.parsers.util.{MathUtils, XMLoader} +import com.codacy.parsers.util.XMLoader import scala.io.Source import scala.util.{Failure, Success, Try} @@ -36,7 +36,7 @@ object LCOVParser extends CoverageParser { (accum, next) => accum.flatMap { case reports if next startsWith SF => - Right(CoverageFileReport(next stripPrefix SF, 0, Map()) +: reports) + Right(CoverageFileReport(next.stripPrefix(SF), Map()) +: reports) case reports if next startsWith DA => reports.headOption match { case Some(value) => @@ -56,12 +56,7 @@ object LCOVParser extends CoverageParser { ) coverageFileReports.map { fileReports => val totalFileReport = fileReports.map { report => - val coveredLines = report.coverage.count { case (_, hit) => hit > 0 } - val totalLines = report.coverage.size - val fileCoverage = - MathUtils.computePercentage(coveredLines, totalLines) - - CoverageFileReport(report.filename, fileCoverage, report.coverage) + CoverageFileReport(report.filename, report.coverage) } val (covered, total) = totalFileReport @@ -73,8 +68,7 @@ object LCOVParser extends CoverageParser { (accumCovered + nextCovered, accumTotal + nextTotal) } - val totalCoverage = MathUtils.computePercentage(covered, total) - CoverageReport(totalCoverage, totalFileReport) + CoverageReport(totalFileReport) } } } diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/OpenCoverParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/OpenCoverParser.scala index 5de6c921..455b9e98 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/OpenCoverParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/OpenCoverParser.scala @@ -3,7 +3,7 @@ package com.codacy.parsers.implementation import java.io.File import com.codacy.api.{CoverageFileReport, CoverageReport} -import com.codacy.parsers.util.{MathUtils, TextUtils} +import com.codacy.parsers.util.TextUtils import com.codacy.parsers.{CoverageParser, XmlReportParser} import scala.xml.{Elem, NodeSeq} @@ -46,12 +46,9 @@ object OpenCoverParser extends CoverageParser with XmlReportParser { lineCoverage = getLineCoverage(methods, sanitisedFileName) totalLines = lineCoverage.size coveredLines = lineCoverage.count { case (_, visitCount) => visitCount > 0 } - coverage = MathUtils.computePercentage(coveredLines, totalLines) - } yield CoverageFileReport(sanitisedFileName, coverage, lineCoverage)).toSeq + } yield CoverageFileReport(sanitisedFileName, lineCoverage)).toSeq - val totalCoverage = computeTotalCoverage(fileReports) - - CoverageReport(totalCoverage, fileReports) + CoverageReport(fileReports) } private def getLineCoverage(methodNodes: NodeSeq, filename: String) = { @@ -62,16 +59,4 @@ object OpenCoverParser extends CoverageParser with XmlReportParser { lineCoverage.toMap } - - private def computeTotalCoverage(fileReports: Seq[CoverageFileReport]) = { - val (totalLines, coveredLines) = fileReports - .foldLeft((0, 0)) { - case ((total, covered), f) => - val totalLines = f.coverage.size - val coveredLines = (f.total * totalLines) / 100 - (total + totalLines, covered + coveredLines) - } - - MathUtils.computePercentage(coveredLines, totalLines) - } } diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/PhpUnitXmlParser.scala b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/PhpUnitXmlParser.scala index 62688b4f..6b0814cd 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/implementation/PhpUnitXmlParser.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/implementation/PhpUnitXmlParser.scala @@ -14,7 +14,6 @@ object PhpUnitXmlParser extends CoverageParser with XmlReportParser { private val PhpUnitTag = "phpunit" private val ProjectTag = "project" private val DirectoryTag = "directory" - private val TotalsTag = "totals" private val XmlParseErrorMessage = s"Could not find top level <$PhpUnitTag> tag"; override def parse(rootProject: File, reportFile: File): Either[String, CoverageReport] = @@ -35,9 +34,7 @@ object PhpUnitXmlParser extends CoverageParser with XmlReportParser { val projectRootPath = TextUtils.sanitiseFilename(projectRoot.getAbsolutePath) val codeDirectory = report \ ProjectTag \ DirectoryTag \@ "name" val fileReports = makeFileReports(fileNodes, projectRootPath, codeDirectory, reportRootPath) - - val totalPercentage = getTotalsCoveragePercentage(report \ ProjectTag \ DirectoryTag \ TotalsTag) - fileReports.map(CoverageReport(totalPercentage, _)) + fileReports.map(CoverageReport(_)) } private def makeFileReports( @@ -50,10 +47,9 @@ object PhpUnitXmlParser extends CoverageParser with XmlReportParser { for (f <- fileNodes) { val reportFileName = f \@ "href" val fileName = getSourceFileName(projectRootPath, codeDirectory, reportFileName) - val coveragePercentage = getTotalsCoveragePercentage(f \ TotalsTag) getLineCoverage(reportRootPath, reportFileName) match { case Right(lineCoverage) => - builder += CoverageFileReport(fileName, coveragePercentage, lineCoverage) + builder += CoverageFileReport(fileName, lineCoverage) case Left(message) => return Left(message) } } @@ -72,11 +68,6 @@ object PhpUnitXmlParser extends CoverageParser with XmlReportParser { lineCoverage } - private def getTotalsCoveragePercentage(totals: NodeSeq) = { - val percentageStr = (totals \ "lines" \@ "percent").dropRight(1) - scala.math.round(percentageStr.toFloat) - } - private def getSourceFileName(pathToRemove: String, codeRootDirectory: String, reportRelativePath: String) = { new File(codeRootDirectory, reportRelativePath).getAbsolutePath .stripPrefix(pathToRemove) diff --git a/coverage-parser/src/main/scala/com/codacy/parsers/util/MathUtils.scala b/coverage-parser/src/main/scala/com/codacy/parsers/util/MathUtils.scala index a3914c93..8e332ad3 100644 --- a/coverage-parser/src/main/scala/com/codacy/parsers/util/MathUtils.scala +++ b/coverage-parser/src/main/scala/com/codacy/parsers/util/MathUtils.scala @@ -2,10 +2,6 @@ package com.codacy.parsers.util object MathUtils { - def computePercentage(part: Int, total: Int): Int = { - if (total == 0) 0 else math.round((part.toFloat / total) * 100) - } - implicit class ParseIntOps(val s: String) extends AnyVal { def toIntOrMaxValue: Int = BigInt(s).toIntOrMaxValue } diff --git a/coverage-parser/src/test/resources/test_invalid_clover.xml b/coverage-parser/src/test/resources/test_invalid_clover.xml deleted file mode 100644 index bbd94707..00000000 --- a/coverage-parser/src/test/resources/test_invalid_clover.xml +++ /dev/null @@ -1,365 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/CloverParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/CloverParserTest.scala index 8376b98c..676bb41c 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/CloverParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/CloverParserTest.scala @@ -19,9 +19,9 @@ class CloverParserTest extends WordSpec with Matchers with EitherValues { val parseResult = CloverParser.parse(new File("."), new File(nonExistentReportPath)) // Assert - parseResult shouldBe Left( - "Unparseable report. coverage-parser/src/test/resources/non-existent.xml (No such file or directory)" - ) + val error = parseResult.left.value + error should startWith("Unparseable report. ") + error should endWith("coverage-parser/src/test/resources/non-existent.xml (No such file or directory)") } "the report is not in the Clover format" in { @@ -34,20 +34,6 @@ class CloverParserTest extends WordSpec with Matchers with EitherValues { // Assert parseResult shouldBe Left("Invalid report. Could not find tag hierarchy tags.") } - - "the report is missing the statements attribute in the file metrics tag" in { - // Arrange - val invalidCloverReportPath = "coverage-parser/src/test/resources/test_invalid_clover.xml" - - // Act - val parseResult = CloverParser.parse(new File("."), new File(invalidCloverReportPath)) - - // Assert - parseResult shouldBe Left( - "Could not retrieve file coverage from metrics tag for file 'home/codacy-php/src/Codacy/Coverage/Parser/Parser.php': Could not find attribute with name 'statements'" - ) - } - } val cloverReportPath = "coverage-parser/src/test/resources/test_clover.xml" @@ -118,18 +104,6 @@ class CloverParserTest extends WordSpec with Matchers with EitherValues { fileReports should have length expectedNumberOfFiles } - "return a report with the expected total coverage" in { - // Arrange - val expectedTotalCoverage = 38 - - // Act - val coverageTotal = - CloverParser.parse(new File("/home/codacy-php/"), new File(cloverReportPath)).right.value.total - - // Assert - coverageTotal shouldBe expectedTotalCoverage - } - "return a report with the expected relative file paths" in { // Arrange val expectedFilePaths = Seq( @@ -153,26 +127,6 @@ class CloverParserTest extends WordSpec with Matchers with EitherValues { parsedReportFilePaths should contain theSameElementsAs expectedFilePaths } - "return a report with the expected file coverage" in { - // Arrange - val filePath = "src/Codacy/Coverage/Parser/Parser.php" - val expectedFileCoverage = 33 - - // Act - val fileTotalCoverage = - CloverParser - .parse(new File("/home/codacy-php/"), new File(cloverReportPath)) - .right - .value - .fileReports - .find(_.filename == filePath) - .getOrElse(fail(s"Could not find report for file:$filePath")) - .total - - // Assert - fileTotalCoverage shouldBe expectedFileCoverage - } - "return a report with the expected file line coverage" in { // Arrange val filePath = "src/Codacy/Coverage/Report/CoverageReport.php" diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/CoberturaParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/CoberturaParserTest.scala index 93e7830c..528988e0 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/CoberturaParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/CoberturaParserTest.scala @@ -26,41 +26,29 @@ class CoberturaParserTest extends WordSpec with BeforeAndAfterAll with Matchers CoberturaParser.parse(new File("."), new File("coverage-parser/src/test/resources/test_cobertura.xml")) val testReport = CoverageReport( - 87, List( - CoverageFileReport( - "coverage-parser/src/test/resources/TestSourceFile2.scala", - 87, - Map(1 -> 1, 2 -> 1, 3 -> 1) - ), CoverageFileReport( "coverage-parser/src/test/resources/TestSourceFile.scala", - 87, Map(5 -> 1, 10 -> 1, 6 -> 2, 9 -> Int.MaxValue, 3 -> 0, 4 -> 1, 7 -> 1, 8 -> 3) - ) + ), + CoverageFileReport("coverage-parser/src/test/resources/TestSourceFile2.scala", Map(1 -> 1, 2 -> 1, 3 -> 1)), ) ) reader.right.value should equal(testReport) } - "no crash on thousands separators" in { + "not crash on thousands separators" in { val reader = CoberturaParser.parse(new File("."), new File("coverage-parser/src/test/resources/thousand_sep_cobertura.xml")) val testReport = CoverageReport( - 87, List( - CoverageFileReport( - "coverage-parser/src/test/resources/TestSourceFile2.scala", - 87, - Map(1 -> 1, 2 -> 1, 3 -> 1) - ), CoverageFileReport( "coverage-parser/src/test/resources/TestSourceFile.scala", - 87, Map(5 -> 1, 10 -> 1, 6 -> 2, 9 -> 1, 9 -> 0, 8 -> 1, 4 -> 1) - ) + ), + CoverageFileReport("coverage-parser/src/test/resources/TestSourceFile2.scala", Map(1 -> 1, 2 -> 1, 3 -> 1)), ) ) @@ -72,18 +60,12 @@ class CoberturaParserTest extends WordSpec with BeforeAndAfterAll with Matchers CoberturaParser.parse(new File("."), new File("coverage-parser/src/test/resources/windows_paths_cobertura.xml")) val testReport = CoverageReport( - 87, List( - CoverageFileReport( - "coverage-parser/src/test/resources/TestSourceFile2.scala", - 87, - Map(1 -> 1, 2 -> 1, 3 -> 1) - ), CoverageFileReport( "coverage-parser/src/test/resources/TestSourceFile.scala", - 87, Map(5 -> 1, 10 -> 1, 6 -> 2, 9 -> 1, 3 -> 0, 4 -> 1) - ) + ), + CoverageFileReport("coverage-parser/src/test/resources/TestSourceFile2.scala", Map(1 -> 1, 2 -> 1, 3 -> 1)), ) ) diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/CoverageParserFactoryTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/CoverageParserFactoryTest.scala index 6446a3b0..ff9ff629 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/CoverageParserFactoryTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/CoverageParserFactoryTest.scala @@ -11,18 +11,12 @@ class CoverageParserFactoryTest extends WordSpec with BeforeAndAfterAll with Mat "get report with unspecified parser" in { val expectedReport = CoverageReport( - 87, List( - CoverageFileReport( - "coverage-parser/src/test/resources/TestSourceFile2.scala", - 87, - Map(1 -> 1, 2 -> 1, 3 -> 1) - ), CoverageFileReport( "coverage-parser/src/test/resources/TestSourceFile.scala", - 87, Map(5 -> 1, 10 -> 1, 6 -> 2, 9 -> 1, 3 -> 0, 4 -> 1, 7 -> 1, 8 -> 3, 9 -> Int.MaxValue) - ) + ), + CoverageFileReport("coverage-parser/src/test/resources/TestSourceFile2.scala", Map(1 -> 1, 2 -> 1, 3 -> 1)) ) ) @@ -34,18 +28,12 @@ class CoverageParserFactoryTest extends WordSpec with BeforeAndAfterAll with Mat "get report with jacoco parser" in { val expectedReport = CoverageReport( - 73, List( CoverageFileReport( "org/eluder/coverage/sample/InnerClassCoverage.java", - 81, Map(10 -> 1, 6 -> 1, 9 -> 1, 13 -> 1, 22 -> 1, 27 -> 0, 12 -> 1, 3 -> 1, 16 -> 1, 26 -> 0, 19 -> 1) ), - CoverageFileReport( - "org/eluder/coverage/sample/SimpleCoverage.java", - 50, - Map(3 -> 1, 6 -> 1, 10 -> 0, 11 -> 0) - ) + CoverageFileReport("org/eluder/coverage/sample/SimpleCoverage.java", Map(3 -> 1, 6 -> 1, 10 -> 0, 11 -> 0)) ) ) diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/DotCoverParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/DotCoverParserTest.scala index ce5808f8..37ca2d63 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/DotCoverParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/DotCoverParserTest.scala @@ -42,25 +42,17 @@ class DotCoverParserTest extends WordSpec with BeforeAndAfterAll with Matchers w ).sorted } - "return the expected total coverage" in { - val reader = DotcoverParser.parse(new File("."), new File(dotCoverReport)) - reader.right.value.total shouldBe 72 - } - "return the expected coverage report" in { val reader = DotcoverParser.parse(new File("."), new File(dotCoverReport)) reader.right.value shouldBe CoverageReport( - 72, List( CoverageFileReport( "src/Coverage/FooBar.cs", - 57, Map(10 -> 1, 21 -> 1, 9 -> 1, 13 -> 0, 17 -> 1, 19 -> 0, 15 -> 0) ), CoverageFileReport( "src/Tests/FooBarTests.cs", - 100, Map( 14 -> 1, 20 -> 1, @@ -76,13 +68,9 @@ class DotCoverParserTest extends WordSpec with BeforeAndAfterAll with Matchers w 15 -> 1 ) ), - CoverageFileReport("src/Coverage/Program.cs", 0, Map(8 -> 0, 9 -> 0, 10 -> 0)), - CoverageFileReport( - "src/Coverage/Bar.cs", - 57, - Map(10 -> 0, 14 -> 1, 9 -> 1, 12 -> 0, 11 -> 0, 8 -> 1, 15 -> 1) - ), - CoverageFileReport("src/Coverage/Foo.cs", 100, Map(8 -> 1, 9 -> 1, 10 -> 1)) + CoverageFileReport("src/Coverage/Program.cs", Map(8 -> 0, 9 -> 0, 10 -> 0)), + CoverageFileReport("src/Coverage/Bar.cs", Map(10 -> 0, 14 -> 1, 9 -> 1, 12 -> 0, 11 -> 0, 8 -> 1, 15 -> 1)), + CoverageFileReport("src/Coverage/Foo.cs", Map(8 -> 1, 9 -> 1, 10 -> 1)) ) ) } diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/GoParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/GoParserTest.scala index a50f5a74..5f6a299a 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/GoParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/GoParserTest.scala @@ -29,11 +29,9 @@ class GoParserTest extends WordSpec with Matchers with EitherValues { val reader = GoParser.parse(new File("."), new File("coverage-parser/src/test/resources/test_go.out")) val testReport = CoverageReport( - 0, List( CoverageFileReport( "example.com/m/v2/hello.go", - 0, Map(5 -> 0, 14 -> 1, 6 -> 0, 13 -> 1, 17 -> 1, 12 -> 1, 7 -> 0, 18 -> 1, 11 -> 1, 19 -> 1) ) ) diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/JacocoParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/JacocoParserTest.scala index 6fd54920..9e3c7281 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/JacocoParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/JacocoParserTest.scala @@ -24,18 +24,12 @@ class JacocoParserTest extends WordSpec with BeforeAndAfterAll with Matchers wit val reader = JacocoParser.parse(new File("."), new File("coverage-parser/src/test/resources/test_jacoco.xml")) val testReport = CoverageReport( - 73, List( CoverageFileReport( "org/eluder/coverage/sample/InnerClassCoverage.java", - 81, Map(10 -> 1, 6 -> 1, 9 -> 1, 13 -> 1, 22 -> 1, 27 -> 0, 12 -> 1, 3 -> 1, 16 -> 1, 26 -> 0, 19 -> 1) ), - CoverageFileReport( - "org/eluder/coverage/sample/SimpleCoverage.java", - 50, - Map(3 -> 1, 6 -> 1, 10 -> 0, 11 -> 0) - ) + CoverageFileReport("org/eluder/coverage/sample/SimpleCoverage.java", Map(3 -> 1, 6 -> 1, 10 -> 0, 11 -> 0)) ) ) diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/LCOVParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/LCOVParserTest.scala index 65582f51..9fae5854 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/LCOVParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/LCOVParserTest.scala @@ -34,16 +34,10 @@ class LCOVParserTest extends WordSpec with BeforeAndAfterAll with Matchers with val reader = LCOVParser.parse(new File("."), new File("coverage-parser/src/test/resources/test_lcov.lcov")) val testReport = CoverageReport( - 86, List( - CoverageFileReport( - "coverage-parser/src/test/resources/TestSourceFile2.scala", - 100, - Map(1 -> 1, 2 -> 1, 3 -> 1) - ), + CoverageFileReport("coverage-parser/src/test/resources/TestSourceFile2.scala", Map(1 -> 1, 2 -> 1, 3 -> 1)), CoverageFileReport( "coverage-parser/src/test/resources/TestSourceFile.scala", - 75, Map(3 -> 0, 4 -> 1, 5 -> 1, 6 -> 2) ) ) diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/OpenCoverParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/OpenCoverParserTest.scala index 26ee962b..2647c5d8 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/OpenCoverParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/OpenCoverParserTest.scala @@ -34,21 +34,14 @@ class OpenCoverParserTest extends WordSpec with BeforeAndAfterAll with Matchers reader.right.value.fileReports.map(_.filename).sorted shouldBe Seq("bar.cs", "foo.cs", "foobar.cs").sorted } - "return the expected total coverage" in { - val reader = OpenCoverParser.parse(new File("."), new File(openCoverReportPath)) - - reader.right.value.total shouldBe 50 - } - "return the expected report" in { val reader = OpenCoverParser.parse(new File("."), new File(openCoverReportPath)) reader.right.value shouldBe CoverageReport( - 50, List( - CoverageFileReport("bar.cs", 0, Map(10 -> 0)), - CoverageFileReport("foo.cs", 100, Map(10 -> 1)), - CoverageFileReport("foobar.cs", 50, Map(10 -> 0, 20 -> 1)) + CoverageFileReport("foo.cs", Map(10 -> 1)), + CoverageFileReport("bar.cs", Map(10 -> 0)), + CoverageFileReport("foobar.cs", Map(10 -> 0, 20 -> 1)) ) ) } diff --git a/coverage-parser/src/test/scala/com/codacy/parsers/PhpUnitXmlParserTest.scala b/coverage-parser/src/test/scala/com/codacy/parsers/PhpUnitXmlParserTest.scala index 131d80a7..5ddca647 100644 --- a/coverage-parser/src/test/scala/com/codacy/parsers/PhpUnitXmlParserTest.scala +++ b/coverage-parser/src/test/scala/com/codacy/parsers/PhpUnitXmlParserTest.scala @@ -44,15 +44,6 @@ class PhpUnitXmlParserTest extends WordSpec with BeforeAndAfterAll with Matchers reader shouldBe 'right } - "return a report with the expected total coverage" in { - val report = PhpUnitXmlParser - .parse(new File(rootPath), new File(validReport)) - .right - .value - - report.total shouldBe 69 - } - "return a report with the expected number of files" in { val report = PhpUnitXmlParser .parse(new File(rootPath), new File(validReport)) @@ -82,25 +73,6 @@ class PhpUnitXmlParserTest extends WordSpec with BeforeAndAfterAll with Matchers ).sorted } - "return a report with the expected file coverage" in { - val report = PhpUnitXmlParser - .parse(new File(rootPath), new File(validReport)) - .right - .value - - report.fileReports.find(_.filename.endsWith(configPhpFile)) match { - case None => fail(configPhpFile + " file is not present in the list of file reports") - case Some(fileReport) => - fileReport.total shouldBe 86 - } - - report.fileReports.find(_.filename.endsWith("CloverParser.php")) match { - case None => fail("CloverParser.php is not present in the list of file reports") - case Some(fileReport) => - fileReport.total shouldBe 95 - } - } - "return a report with the expected line coverage" in { val report = PhpUnitXmlParser .parse(new File(rootPath), new File(validReport)) diff --git a/integration-tests/mock-server-config.json b/integration-tests/mock-server-config.json index 55c56af7..a8616ecf 100644 --- a/integration-tests/mock-server-config.json +++ b/integration-tests/mock-server-config.json @@ -1,6 +1,6 @@ { "httpRequest": { - "body": {"total":76,"fileReports":[{"filename":"app/Experiment/FooBar.cs","total":71,"coverage":{"10":1,"21":1,"9":1,"13":1,"17":1,"19":0,"15":0}},{"filename":"app/Tests/FooBarTests.cs","total":100,"coverage":{"10":1,"14":1,"29":1,"21":1,"13":1,"22":1,"27":1,"18":1,"31":1,"11":1,"26":1,"30":1,"19":1}},{"filename":"app/Experiment/Program.cs","total":0,"coverage":{"8":0,"9":0,"10":0}},{"filename":"app/Experiment/Bar.cs","total":57,"coverage":{"10":0,"14":1,"9":1,"12":0,"11":0,"8":1,"15":1}},{"filename":"app/Experiment/Foo.cs","total":100,"coverage":{"8":1,"9":1,"10":1,"11":1}}]} + "body": {"fileReports":[{"filename":"app/Experiment/FooBar.cs","coverage":{"10":1,"21":1,"9":1,"13":1,"17":1,"19":0,"15":0}},{"filename":"app/Tests/FooBarTests.cs","coverage":{"10":1,"14":1,"29":1,"21":1,"13":1,"22":1,"27":1,"18":1,"31":1,"11":1,"26":1,"30":1,"19":1}},{"filename":"app/Experiment/Program.cs","coverage":{"8":0,"9":0,"10":0}},{"filename":"app/Experiment/Bar.cs","coverage":{"10":0,"14":1,"9":1,"12":0,"11":0,"8":1,"15":1}},{"filename":"app/Experiment/Foo.cs","coverage":{"8":1,"9":1,"10":1,"11":1}}]} }, "httpResponse": { "statusCode": 200, diff --git a/project/build.properties b/project/build.properties index 563a014d..e8a1e246 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.7.2 +sbt.version=1.9.7 diff --git a/project/plugins.sbt b/project/plugins.sbt index c656a53c..d8d127c6 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,13 +1,10 @@ -addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.3.1") -addSbtPlugin("com.codacy" % "codacy-sbt-plugin" % "22.0.1") +addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.3.4") +addSbtPlugin("com.codacy" % "codacy-sbt-plugin" % "25.1.1") // Publish -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") - -// Updates -addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.4.0") -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.2") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.4") // Coverage -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.6") -evictionErrorLevel := Level.Warn +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.9") + +libraryDependencySchemes ++= Seq("org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always) diff --git a/src/test/scala/com/codacy/rules/ReportRulesSpec.scala b/src/test/scala/com/codacy/rules/ReportRulesSpec.scala index 22269f44..c88f028d 100644 --- a/src/test/scala/com/codacy/rules/ReportRulesSpec.scala +++ b/src/test/scala/com/codacy/rules/ReportRulesSpec.scala @@ -22,8 +22,8 @@ class ReportRulesSpec extends WordSpec with Matchers with PrivateMethodTester wi val conf = Report(baseConf, Some("Scala"), coverageReports = Some(coverageFiles), prefix = None, forceCoverageParser = None) - val coverageReport = CoverageReport(100, Seq(CoverageFileReport("file.scala", 100, Map(10 -> 1)))) - val noLanguageReport = CoverageReport(0, Seq.empty[CoverageFileReport]) + val coverageReport = CoverageReport(Seq(CoverageFileReport("file.scala", Map(10 -> 1)))) + val noLanguageReport = CoverageReport(Seq.empty[CoverageFileReport]) val configRules = new ConfigurationRules(conf, sys.env) val validatedConfig = configRules.validatedConfig.right.value @@ -271,7 +271,7 @@ class ReportRulesSpec extends WordSpec with Matchers with PrivateMethodTester wi "storeReport" should { "not store report" in { - val emptyReport = CoverageReport(0, Seq.empty[CoverageFileReport]) + val emptyReport = CoverageReport(Seq.empty[CoverageFileReport]) val tempFile = File.createTempFile("storeReport", "not-store") val result = components.reportRules.storeReport(emptyReport, tempFile) @@ -280,7 +280,7 @@ class ReportRulesSpec extends WordSpec with Matchers with PrivateMethodTester wi "successfully store report" when { def storeValidReport() = { - val emptyReport = CoverageReport(0, List(CoverageFileReport("file-name", 0, Map.empty))) + val emptyReport = CoverageReport(List(CoverageFileReport("file-name", Map.empty))) val tempFile = File.createTempFile("storeReport", "not-store") components.reportRules.storeReport(emptyReport, tempFile) } diff --git a/src/test/scala/com/codacy/transformation/PathPrefixerSpec.scala b/src/test/scala/com/codacy/transformation/PathPrefixerSpec.scala index 7d7405a0..45b44b15 100644 --- a/src/test/scala/com/codacy/transformation/PathPrefixerSpec.scala +++ b/src/test/scala/com/codacy/transformation/PathPrefixerSpec.scala @@ -6,8 +6,7 @@ import org.scalatest._ class PathPrefixerSpec extends WordSpec with Matchers { val report = CoverageReport( - 83, - Seq(CoverageFileReport("Filename.scala", 24, Map.empty), CoverageFileReport("OtherFile.scala", 74, Map.empty)) + Seq(CoverageFileReport("Filename.scala", Map.empty), CoverageFileReport("OtherFile.scala", Map.empty)) ) "PathPrefixer" should {