diff options
author | adamw <adam@warski.org> | 2017-10-31 14:46:38 +0100 |
---|---|---|
committer | adamw <adam@warski.org> | 2017-10-31 15:48:19 +0100 |
commit | 2dcc31ba8fec394b37801a4fb505fd73c33c14b1 (patch) | |
tree | 89428bd80061aaabb55ea9b7e7b9a1daee9c15eb | |
parent | a2a6db30bceb7a798ad36673cfcbe61088c7083f (diff) | |
download | sttp-2dcc31ba8fec394b37801a4fb505fd73c33c14b1.tar.gz sttp-2dcc31ba8fec394b37801a4fb505fd73c33c14b1.tar.bz2 sttp-2dcc31ba8fec394b37801a4fb505fd73c33c14b1.zip |
#40: properly concatenating expression/token sequences in uri interpolator
-rw-r--r-- | core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala | 45 | ||||
-rw-r--r-- | core/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala | 7 |
2 files changed, 46 insertions, 6 deletions
diff --git a/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala b/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala index f1e6beb..fe19358 100644 --- a/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala +++ b/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala @@ -437,11 +437,46 @@ object UriInterpolator { case x => Some(x.toString) } - private def tokensToStringSeq(t: Vector[Token]): Seq[String] = t.flatMap { - case ExpressionToken(s: Seq[_]) => s.flatMap(anyToStringOpt).toVector - case ExpressionToken(e) => anyToStringOpt(e).toVector - case StringToken(s) => Vector(decode(s)) - case _ => Vector.empty + private def tokensToStringSeq(tokens: Vector[Token]): Seq[String] = { + /* + #40: when converting tokens to a string sequence, we have to look at + groups of string/expression (value) tokens separated by others. If there + are multiple tokens in each such group, their string representations + should be concatenated (corresponds to e.g. $x$y). A single + collection-valued token should be expanded. + */ + + def isValueToken(t: Token) = t match { + case ExpressionToken(_) => true + case StringToken(_) => true + case _ => false + } + + @tailrec + def doToSeq(ts: Vector[Token], acc: Vector[String]): Seq[String] = { + val tsWithValuesPrefix = ts.dropWhile(to => !isValueToken(to)) + val (valueTs, tailTs) = tsWithValuesPrefix.span(isValueToken) + + valueTs match { + case Vector() => acc // tailTs must be empty then as well + case Vector(ExpressionToken(s: Seq[_])) => + doToSeq(tailTs, acc ++ s.flatMap(anyToStringOpt).toVector) + case _ => + val values = valueTs + .flatMap { + case ExpressionToken(e) => anyToStringOpt(e) + case StringToken(s) => Some(decode(s)) + case _ => None + } + + val strToAdd = + if (values.isEmpty) None else Some(values.mkString("")) + + doToSeq(tailTs, acc ++ strToAdd) + } + } + + doToSeq(tokens, Vector.empty) } private def tokensToStringOpt(t: Vector[Token]): Option[String] = t match { diff --git a/core/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala b/core/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala index 9fc2d3a..acfa9d4 100644 --- a/core/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala +++ b/core/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala @@ -41,6 +41,9 @@ class UriInterpolatorTests extends FunSuite with Matchers { "authority" -> List( (uri"http://$v1.com", s"http://$v1.com"), (uri"http://$v2.com", s"http://$v2encoded.com"), + (uri"http://$v1.$v2.com", s"http://$v1.$v2encoded.com"), + (uri"http://$v1$v2.com", s"http://$v1$v2encoded.com"), + (uri"http://z$v1.com", s"http://z$v1.com"), (uri"http://$None.example.com", s"http://example.com"), (uri"http://$None.$None.example.com", s"http://example.com"), (uri"http://${Some("sub")}.example.com", s"http://sub.example.com"), @@ -78,7 +81,9 @@ class UriInterpolatorTests extends FunSuite with Matchers { (uri"http://example.com?x=$v1", s"http://example.com?x=$v1"), (uri"http://example.com/?x=$v1", s"http://example.com/?x=$v1"), (uri"http://example.com?x=$v2", s"http://example.com?x=$v2queryEncoded"), - (uri"http://example.com?x=$v3", s"http://example.com?x=$v3encoded") + (uri"http://example.com?x=$v3", s"http://example.com?x=$v3encoded"), + (uri"http://example.com?x=$v1$v1", s"http://example.com?x=$v1$v1"), + (uri"http://example.com?x=z$v1", s"http://example.com?x=z$v1") ), "query parameter without value" -> List( (uri"http://example.com?$v1", s"http://example.com?$v1"), |