8000 Fix Parser.parseDocuments by sideeffffect · Pull Request #346 · circe/circe-yaml · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix Parser.parseDocuments #346

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

Merged
merged 18 commits into from
Nov 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
016b213
Add tests to `Parser.parseDocuments`
lucaviolanti Nov 14, 2022
174b50b
Merge branch 'master' into add-tests-to-highlight-issue
lucaviolanti Nov 14, 2022
0a0d9ea
Merge branch 'master' into add-tests-to-highlight-issue
lucaviolanti Nov 15, 2022
0c2cfd8
Merge branch 'add-tests-to-highlight-issue' of https://github.com/luc…
lucaviolanti Nov 15, 2022
6905d9a
Make tests fail to clarify issue
lucaviolanti Nov 15, 2022
29b3b6c
Fix parseDocuments
sideeffffect Nov 16, 2022
596f2a1
Fix parseDocuments
sideeffffect Nov 16, 2022
8e5c041
Update circe-yaml-v12/src/test/scala/io/circe/yaml/v12/ParserTests.scala
sideeffffect Nov 16, 2022
10a6c5c
Update circe-yaml-v12/src/test/scala/io/circe/yaml/v12/ParserTests.scala
sideeffffect Nov 16, 2022
e033f5a
Update circe-yaml-v12/src/test/scala/io/circe/yaml/v12/ParserTests.scala
sideeffffect Nov 16, 2022
afe6075
Update circe-yaml-v12/src/test/scala/io/circe/yaml/v12/ParserTests.scala
sideeffffect Nov 16, 2022
d9ca498
Update circe-yaml/src/test/scala/io/circe/yaml/ParserTests.scala
sideeffffect Nov 16, 2022
655e40a
Update circe-yaml/src/test/scala/io/circe/yaml/ParserTests.scala
sideeffffect Nov 16, 2022
023eba1
Update circe-yaml/src/test/scala/io/circe/yaml/ParserTests.scala
sideeffffect Nov 16, 2022
81723d9
Update circe-yaml/src/test/scala/io/circe/yaml/ParserTests.scala
sideeffffect Nov 16, 2022
c3c00f4
Merge branch 'main' into add-tests-to-highlight-issue
sideeffffect Nov 20, 2022
8dc525d
fix
sideeffffect Nov 20, 2022
1a1f727
fix
sideeffffect Nov 20, 2022
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
build:
name: Build and Test
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
scala: [2.12.17, 2.13.10, 3.2.1]
Expand Down
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ThisBuild / circeRootOfCodeCoverage := None
ThisBuild / startYear := Some(2016)
ThisBuild / scalafixScalaBinaryVersion := "2.12"
ThisBuild / tlFatalWarningsInCi := false //TODO: ... fix this someday
ThisBuild / githubWorkflowBuildMatrixFailFast := Some(false)

val Versions = new {
val circe = "0.14.3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ class ParserImpl(settings: LoadSettings) extends common.Parser {
def parse(yaml: String): Either[ParsingFailure, Json] =
parse(new StringReader(yaml))

def parseDocuments(yaml: Reader): Stream[Either[ParsingFailure, Json]] = parseStream(yaml).map(yamlToJson)
def parseDocuments(yaml: Reader): Stream[Either[ParsingFailure, Json]] = parseStream(yaml) match {
case Left(error) => Stream(Left(error))
case Right(stream) => stream.map(yamlToJson)
}
def parseDocuments(yaml: String): Stream[Either[ParsingFailure, Json]] = parseDocuments(new StringReader(yaml))

private[this] def asScala[T](ot: Optional[T]): Option[T] =
Expand All @@ -65,8 +68,8 @@ class ParserImpl(settings: LoadSettings) extends common.Parser {
case Right(Some(value)) => Right(value)
}

private[this] def parseStream(reader: Reader) =
createComposer(reader).asScala.toStream
private[this] def parseStream(reader: Reader): Either[ParsingFailure, Stream[Node]] =
Either.catchNonFatal(createComposer(reader).asScala.toStream).leftMap(err => ParsingFailure(err.getMessage, err))

final def decode[A: Decoder](input: Reader): Either[Error, A] =
finishDecode(parse(input))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@

package io.circe.yaml.v12

import io.circe.Json
import io.circe.syntax._
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import java.io.StringReader

class ParserTests extends AnyFlatSpec with Matchers with EitherValues {
// the laws should do a pretty good job of surfacing errors; these are mainly to ensure test coverage

"Parser" should "fail on invalid tagged numbers" in {
"Parser.parse" should "fail on invalid tagged numbers" in {
assert(parser.parse("!!int 12foo").isLeft)
}

Expand Down Expand Up @@ -137,4 +140,98 @@ class ParserTests extends AnyFlatSpec with Matchers with EitherValues {
.isLeft
)
}

"Parser.parseDocuments" should "fail on invalid tagged numbers" in {
val result = parser.parseDocuments(new StringReader("!!int 12foo")).toList
assert(result.size == 1)
assert(result.head.isLeft)
}

it should "fail to parse complex keys" in {
val result = parser
.parseDocuments(new StringReader("""
|? - foo
| - bar
|: 1""".stripMargin))
.toList
assert(result.size == 1)
assert(result.head.isLeft)
}

it should "fail to parse invalid YAML" in {
val result = parser.parseDocuments(new StringReader("""foo: - bar""")).toList
assert(result.size == 1)
assert(result.head.isLeft)
assert(result.head.isInstanceOf[Either[io.circe.ParsingFailure, Json]])
}

it should "parse yes as true" in {
val result = parser.parseDocuments(new StringReader("""foo: yes""")).toList
assert(result.size == 1)
assert(result.head.isRight)
}

it should "parse hexadecimal as strings" in {
val result = parser.parseDocuments(new StringReader("""[0xFF, 0xff, 0xab_cd]""")).toList
assert(result.size == 1)
assert(result.head.contains(Seq("0xFF", "0xff", "0xab_cd").asJson.asJson))
}

it should "parse decimal with underscore breaks as strings" in {
val result = parser.parseDocuments(new StringReader("""foo: 1_000_000""")).toList
assert(result.size == 1)
assert(result.head.contains(Map("foo" -> "1_000_000").asJson))
}

it should "parse empty string as 0 documents" in {
val result = parser.parseDocuments(new StringReader("")).toList
assert(result.isEmpty)
}

it should "parse blank string as 0 documents" in {
val result = parser.parseDocuments(new StringReader(" ")).toList
assert(result.isEmpty)
}

it should "parse aliases" in {
val result = parser
.parseDocuments(
new StringReader(
"""
| aliases:
| - &alias1
| foo:
| bar
| baz:
| - *alias1
| - *alias1
|""".stripMargin
)
)
.toList
assert(result.size == 1)
assert(result.head.isRight)
}

it should "fail to parse too many aliases" in {
val result =
Parser
.make(Parser.Config(maxAliasesForCollections = 1))
.parseDocuments(
new StringReader(
"""
| aliases:
| - &alias1
| foo:
| bar
| baz:
| - *alias1
| - *alias1
|""".stripMargin
)
)
.toList
assertResult(1)(result.size)
assert(result.head.isLeft)
}
}
12 changes: 9 additions & 3 deletions circe-yaml/src/main/scala/io/circe/yaml/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,20 @@ final case class Parser(

def parse(yaml: String): Either[ParsingFailure, Json] = parse(new StringReader(yaml))

def parseDocuments(yaml: Reader): Stream[Either[ParsingFailure, Json]] = parseStream(yaml).map(yamlToJson)
def parseDocuments(yaml: Reader): Stream[Either[ParsingFailure, Json]] = parseStream(yaml) match {
case Left(error) => Stream(Left(error))
case Right(stream) => stream.map(yamlToJson)
}

def parseDocuments(yaml: String): Stream[Either[ParsingFailure, Json]] = parseDocuments(new StringReader(yaml))

private[this] def parseSingle(reader: Reader): Either[ParsingFailure, Node] =
Either.catchNonFatal(new Yaml(loaderOptions).compose(reader)).leftMap(err => ParsingFailure(err.getMessage, err))

private[this] def parseStream(reader: Reader): Stream[Node] =
new Yaml(loaderOptions).composeAll(reader).asScala.toStream
private[this] def parseStream(reader: Reader): Either[ParsingFailure, Stream[Node]] =
Either
.catchNonFatal(new Yaml(loaderOptions).composeAll(reader).asScala.toStream)
.leftMap(err => ParsingFailure(err.getMessage, err))

final def decode[A: Decoder](input: Reader): Either[Error, A] =
finishDecode(parse(input))
Expand Down
97 changes: 96 additions & 1 deletion circe-yaml/src/test/scala/io/circe/yaml/ParserTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import java.io.StringReader

class ParserTests extends AnyFlatSpec with Matchers with EitherValues {
// the laws should do a pretty good job of surfacing errors; these are mainly to ensure test coverage

"Parser" should "fail on invalid tagged numbers" in {
"Parser.parse" should "fail on invalid tagged numbers" in {
assert(parser.parse("!!int 12foo").isLeft)
}

Expand Down Expand Up @@ -138,4 +140,97 @@ class ParserTests extends AnyFlatSpec with Matchers with EitherValues {
.isLeft
)
}

"Parser.parseDocuments" should "fail on invalid tagged numbers" in {
val result = parser.parseDocuments(new StringReader("!!int 12foo")).toList
assert(result.size == 1)
assert(result.head.isLeft)
}

it should "fail to parse complex keys" in {
val result = parser
.parseDocuments(new StringReader("""
|? - foo
| - bar
|: 1""".stripMargin))
.toList
assert(result.size == 1)
assert(result.head.isLeft)
}

it should "fail to parse invalid YAML" in {
val result = parser.parseDocuments(new StringReader("""foo: - bar""" DA22 )).toList
assert(result.size == 1)
assert(result.head.isLeft)
assert(result.head.isInstanceOf[Either[io.circe.ParsingFailure, Json]])
}

it should "parse yes as true" in {
val result = parser.parseDocuments(new StringReader("""foo: yes""")).toList
assert(result.size == 1)
assert(result.head.isRight)
}

it should "parse hexadecimal" in {
val result = parser.parseDocuments(new StringReader("""[0xFF, 0xff, 0xab_cd]""")).toList
assert(result.size == 1)
assert(result.head.contains(Seq(0xff, 0xff, 0xabcd).asJson))
}

it should "parse decimal with underscore breaks" in {
val result = parser.parseDocuments(new StringReader("""foo: 1_000_000""")).toList
assert(result.size == 1)
assert(result.head.contains(Map("foo" -> 1000000).asJson))
}

it should "parseDocuments empty string as 0 documents" in {
val result = parser.parseDocuments(new StringReader("")).toList
assert(result.isEmpty)
}

it should "parseDocuments blank string as 0 documents" in {
val result = parser.parseDocuments(new StringReader(" ")).toList
assert(result.isEmpty)
}

it should "parse aliases" in {
val result = parser
.parseDocuments(
new StringReader(
"""
| aliases:
| - &alias1
| foo:
| bar
| baz:
| - *alias1
| - *alias1
|""".stripMargin
)
)
.toList
assert(result.size == 1)
assert(result.head.isRight)
}

it should "fail to parse too many aliases" in {
val result =
Parser(maxAliasesForCollections = 1)
.parseDocuments(
new StringReader(
"""
| aliases:
| - &alias1
| foo:
| bar
| baz:
| - *alias1
| - *alias1
|""".stripMargin
)
)
.toList
assertResult(1)(result.size)
assert(result.head.isLeft)
}
}
0