Skip to content

Commit

Permalink
Unit-testing of Play module functions.
Browse files Browse the repository at this point in the history
The complete testing of Play module is pretty complicated and could not be done yet.
  • Loading branch information
makkarpov committed Apr 20, 2016
1 parent 8e2f059 commit 556d89b
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 34 deletions.
5 changes: 3 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ val common = Seq(
crossScalaVersions := Seq("2.10.4", "2.11.7"),
scalacOptions ++= Seq( "-Xfatal-warnings", "-feature", "-deprecation" ),

libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.6" % Test,

publishArtifact in Test := false,
publishMavenStyle := true,

Expand Down Expand Up @@ -66,8 +68,7 @@ lazy val scalingua = project
description := "A simple gettext-like internationalization library for Scala",

libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
"org.scalatest" %% "scalatest" % "2.2.6" % Test
"org.scala-lang" % "scala-reflect" % scalaVersion.value
),

libraryDependencies ++= {
Expand Down
37 changes: 5 additions & 32 deletions play/src/main/scala/ru/makkarpov/scalingua/play/I18n.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,30 +57,11 @@ trait I18n extends scalingua.I18n {
// too, we will have enough information to skip unsupported languages and return supported
// one with respect to priority.

implicit def requestHeader2Language(implicit rq: RequestHeader, msg: Messages): Language = {
val langs = (for {
value0 <- rq.headers(HeaderNames.ACCEPT_LANGUAGE).split(',')
value = value0.trim
} yield {
RequestHeader.qPattern.findFirstMatchIn(value) match {
case Some(m) => (m.group(1).toDouble, m.before.toString)
case None => (1.0, value) // “The default value is q=1.”
}
}).sortBy(_._1).iterator

while (langs.hasNext) {
val (_, id) = langs.next()
val lng = LanguageId.get(id)

if (lng.isDefined && msg.contains(lng.get))
return msg(lng.get)
}
implicit def requestHeader2Language(implicit rq: RequestHeader, msg: Messages): Language =
PlayUtils.languageFromAccept(rq.headers(HeaderNames.ACCEPT_LANGUAGE))

Language.English
}

implicit def stringContext2Interpolator1(sc: StringContext): I18n.StringInterpolator =
new I18n.StringInterpolator(sc)
implicit def stringContext2Interpolator1(sc: StringContext): PlayUtils.StringInterpolator =
new PlayUtils.StringInterpolator(sc)

def th(msg: String, args: (String, Any)*)(implicit lang: Language, outputFormat: OutputFormat[Html]): Html =
macro Macros.singular[Html]
Expand Down Expand Up @@ -111,12 +92,4 @@ trait I18n extends scalingua.I18n {
macro Macros.lazyPluralCtx[Html]
}

object I18n extends I18n {
class StringInterpolator(val sc: StringContext) extends AnyVal {
def h(args: Any*)(implicit lang: Language, outputFormat: OutputFormat[Html]): Html =
macro Macros.interpolate[Html]

def lh(args: Any*)(implicit outputFormat: OutputFormat[Html]): LHtml =
macro Macros.lazyInterpolate[Html]
}
}
object I18n extends I18n
58 changes: 58 additions & 0 deletions play/src/main/scala/ru/makkarpov/scalingua/play/PlayUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/******************************************************************************
* Copyright © 2016 Maxim Karpov *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
******************************************************************************/

package ru.makkarpov.scalingua.play

import play.api.mvc.RequestHeader
import play.twirl.api.Html
import ru.makkarpov.scalingua._

import scala.language.experimental.macros

object PlayUtils {
class StringInterpolator(val sc: StringContext) extends AnyVal {
def h(args: Any*)(implicit lang: Language, outputFormat: OutputFormat[Html]): Html =
macro Macros.interpolate[Html]

def lh(args: Any*)(implicit outputFormat: OutputFormat[Html]): LValue[Html] =
macro Macros.lazyInterpolate[Html]
}

// Modified to match only correct doubles
private val qPattern = ";\\s*q=((?:[0-9]+\\.)?[0-9]+)".r

def languageFromAccept(accept: String)(implicit msg: Messages): Language = {
val langs = (for {
value0 <- accept.split(',')
value = value0.trim
} yield {
qPattern.findFirstMatchIn(value) match {
case Some(m) => (m.group(1).toDouble, m.before.toString)
case None => (1.0, value) // “The default value is q=1.”
}
}).sortBy(-_._1).iterator

while (langs.hasNext) {
val (_, id) = langs.next()
val lng = LanguageId.get(id)

if (lng.isDefined && msg.contains(lng.get))
return msg(lng.get)
}

Language.English
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/******************************************************************************
* Copyright © 2016 Maxim Karpov *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
******************************************************************************/

package ru.makkarpov.scalingua.play.test

import ru.makkarpov.scalingua.{Language, LanguageId}

case class MockEnglishLang(lid: String) extends Language {
override val id: LanguageId = LanguageId(lid)

override def singular(msgid: String): String = msgid
override def singular(msgctx: String, msgid: String): String = msgid
override def plural(msgid: String, msgidPlural: String, n: Long): String = if (n == 1) msgid else msgidPlural
override def plural(msgctx: String, msgid: String, msgidPlural: String, n: Long): String =
if (n == 1) msgid else msgidPlural
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/******************************************************************************
* Copyright © 2016 Maxim Karpov *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
******************************************************************************/

package ru.makkarpov.scalingua.play.test

import org.scalatest.{FlatSpec, Matchers}
import ru.makkarpov.scalingua.{Language, Messages}
import ru.makkarpov.scalingua.play.I18n._

class PlayTest extends FlatSpec with Matchers {
it should "handle HTML translations" in {
implicit val lang = Language.English
val x = "\"List<String>\""
h"A class $x can be used to provide simple list container".body shouldBe
"A class &quot;List&lt;String&gt;&quot; can be used to provide simple list container"
}

it should "handle 'Accept' header" in {
implicit val messages = new Messages(
MockEnglishLang("aa-AA"),
MockEnglishLang("aa-AX"),
MockEnglishLang("bb-BB"),
MockEnglishLang("cc-CC")
)

import ru.makkarpov.scalingua.play.PlayUtils.{languageFromAccept => f}

f("") shouldBe Language.English
f("cc").id.toString shouldBe "cc-CC"
f("bb").id.toString shouldBe "bb-BB"
f("aa").id.toString shouldBe "aa-AA"
f("aa-RR").id.toString shouldBe "aa-AA"
f("aa-AX").id.toString shouldBe "aa-AX"
f("bb, cc").id.toString shouldBe "bb-BB"
f("cc, bb").id.toString shouldBe "cc-CC"
f("xx, yy, zz") shouldBe Language.English
f("tt, tt, cc, tt, tt").id.toString shouldBe "cc-CC"
f("bb, cc; q=0.8").id.toString shouldBe "bb-BB"
f("cc; q=0.8, bb").id.toString shouldBe "bb-BB"
f("aa; q=0.2; bb; q=0.4, cc; q=0.8").id.toString shouldBe "cc-CC"
f("aa; q=0.8, bb; q=0.4, cc; q=0.2").id.toString shouldBe "aa-AA"

// No exceptions should be thrown on incorrect inputs; English should be returned instead:
f("111111111") shouldBe Language.English
f("aa-AA-ww") shouldBe Language.English
f("aa-AX; q=W") shouldBe Language.English
}
}

0 comments on commit 556d89b

Please sign in to comment.