Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump versions and tests #82

Merged
merged 16 commits into from
Jan 17, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
SourceCodeParseSpec
  • Loading branch information
simerplaha committed Jan 17, 2024
commit cf78775a6294a6ef01db44fba2d3648fae318d90
Original file line number Diff line number Diff line change
@@ -35,4 +35,10 @@ object TestCode {
genScript(genCamelCase),
)

def genBadCode(): Gen[String] =
Gen.oneOf(
genContract(genCamelCase.map(_.toLowerCase)),
genScript(genCamelCase.map(_.toLowerCase)),
)

}
Original file line number Diff line number Diff line change
@@ -4,11 +4,14 @@ import org.alephium.ralph.lsp.TestCommon._
import org.alephium.ralph.lsp.access.compiler.CompilerAccess.RALPH_FILE_EXTENSION
import org.scalacheck.Gen
import org.scalatest.matchers.should.Matchers._
import org.scalatest.TryValues._

import java.io.File
import java.net.URI
import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path, Paths}
import scala.io.Source
import scala.util.Using

/**
* [[File]] IO related test functions
@@ -127,4 +130,8 @@ object TestFile {
def exists(uri: URI): Boolean =
Files.exists(Paths.get(uri))

def readAll(uri: URI): String =
Using(Source.fromFile(uri))(_.mkString)
.success
.value
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.alephium.ralph.lsp.pc.sourcecode

import org.alephium.ralph.lsp.{TestCode, TestFile}
import org.alephium.ralph.lsp.access.compiler.CompilerAccess
import org.alephium.ralph.lsp.access.compiler.message.error.TestError
import org.alephium.ralph.lsp.access.file.FileAccess
import org.alephium.ralph.lsp.pc.sourcecode.TestSourceCode._
import org.alephium.ralph.lsp.pc.workspace.build.TestRalphc
import org.alephium.ralph.lsp.TestCode
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.EitherValues._
@@ -97,5 +98,105 @@ class SourceCodeParseSpec extends AnyWordSpec with Matchers with ScalaCheckDrive
}
}
}

"successfully parse" when {
implicit val compiler: CompilerAccess =
CompilerAccess.ralphc

implicit val file: FileAccess =
FileAccess.disk

"source-code in state OnDisk, UnCompiled and ErrorAccess" in {
forAll(TestSourceCode.genOnDiskAndPersist(), TestError.genError()) {
case ((onDisk, goodCode), error) =>

/**
* Generate an [[SourceCodeState.UnCompiled]] and [[SourceCodeState.ErrorAccess]] for this onDisk state.
*
* The end result should be the same, the code should still successfully parse for all these states
* because the code on-disk is "Good Code".
* */

val unCompiled =
SourceCodeState.UnCompiled(
fileURI = onDisk.fileURI,
code = goodCode
)

val errorAccess =
SourceCodeState.ErrorAccess(
fileURI = onDisk.fileURI,
error = error
)

// run tests for all states
val allStates =
List(onDisk, unCompiled, errorAccess)

// all states (errors or onDisk) should always succeed because the onDisk code is valid and parse-able.
allStates foreach {
currentState =>
// execute parse
val actual = SourceCode.parse(currentState)
// successfully parsed
actual shouldBe
SourceCodeState.Parsed(
fileURI = currentState.fileURI,
code = goodCode,
ast = CompilerAccess.ralphc.parseContracts(goodCode).value
)

// read the code written on disk
val sourceCodeOnDisk =
TestFile.readAll(actual.fileURI)
// it should be the same as goodCode
sourceCodeOnDisk shouldBe goodCode
}

// clear persisted source-code
TestSourceCode.delete(onDisk)
}
}
}

"not parse and not perform disk-IO or compiler-IO" when {
"source-code already in ErrorSource state" in {
// compiler and disk should not be accessed
implicit val compiler: CompilerAccess = null
implicit val file: FileAccess = null

// ErrorSource state means the source-code has already been parsed and it previously errored.
// Re-parsing will not yield a different result so expect no disk-IO or compiler-IO
forAll(TestSourceCode.genErrorSource()) {
error =>
SourceCode.parse(error) shouldBe error
}
}
}

"report source-code parse error" in {
implicit val compiler: CompilerAccess =
CompilerAccess.ralphc

implicit val file: FileAccess =
FileAccess.disk

forAll(TestSourceCode.genOnDiskAndPersist(code = TestCode.genBadCode())) {
case (onDisk, code) =>
// execute parse
val newState = SourceCode.parse(onDisk)

// expect error state is returned
newState shouldBe
SourceCodeState.ErrorSource(
fileURI = onDisk.fileURI,
code = code,
errors = Seq(CompilerAccess.ralphc.parseContracts(code).left.value),
previous = None
)

TestSourceCode.delete(onDisk)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package org.alephium.ralph.lsp.pc.sourcecode

import org.alephium.ralph.lsp.{TestCode, TestFile}
import org.alephium.ralph.lsp.TestFile._
import org.alephium.ralph.lsp.access.compiler.message.error.TestError
import org.alephium.ralph.lsp.pc.util.URIUtil
import org.alephium.ralph.lsp.pc.workspace.build.{BuildState, TestBuild}
import org.scalacheck.Gen
@@ -39,6 +40,57 @@ object TestSourceCode {
} yield
sourceCode

/** Generate a source code file on-disk */
def genOnDiskAndPersist(fileURI: Gen[URI] = genFileURI(),
code: Gen[String] = TestCode.genGoodCode()): Gen[(SourceCodeState.OnDisk, String)] =
for {
onDisk <- TestSourceCode.genOnDisk(fileURI)
code <- code
} yield {
// write code to the source file
val persistedOnDisk = persist(onDisk, code)
(persistedOnDisk, code)
}

/**
* Generate an error state for a source-code state.
* These error states
*/
def genErrorState(state: Gen[SourceCodeState] = genOnDisk(),
code: Gen[String] = TestCode.genGoodCode()): Gen[SourceCodeState.IsError] =
Gen.oneOf(
genErrorAccess(state),
genErrorSource(state, code)
)

/**
* Generate an error state for a source-code state.
* These error states
*/
def genErrorAccess(state: Gen[SourceCodeState] = genOnDisk()): Gen[SourceCodeState.ErrorAccess] =
for {
_state <- state
error <- TestError.genError()
} yield
SourceCodeState.ErrorAccess(
fileURI = _state.fileURI,
error = error
)

def genErrorSource(state: Gen[SourceCodeState] = genOnDisk(),
code: Gen[String] = TestCode.genGoodCode()): Gen[SourceCodeState.ErrorSource] =
for {
_state <- state
_code <- code
errors <- Gen.listOf(TestError.genError())
} yield
SourceCodeState.ErrorSource(
fileURI = _state.fileURI,
code = _code,
errors = errors,
previous = None
)

def genUnCompiled(code: Gen[String] = TestCode.genGoodCode(),
fileURI: Gen[URI] = genFileURI()): Gen[SourceCodeState.UnCompiled] =
for {