Skip to content

Instantly share code, notes, and snippets.

@bigwheel
Created April 24, 2015 03:19
Show Gist options
  • Select an option

  • Save bigwheel/26d0fbda3688672ebd58 to your computer and use it in GitHub Desktop.

Select an option

Save bigwheel/26d0fbda3688672ebd58 to your computer and use it in GitHub Desktop.
package utils.specs2
import org.specs2.main.SmartDiffs
import play.api.libs.json._
import scala.util.Success
import scala.util.Try
object JsonProcessableDiffs extends SmartDiffs {
private[this] def toJsObectOption(map: Map[String, JsValue]) = if (map.isEmpty)
None
else
Some(JsObject(map.toSeq))
private[this] def toJsArrayOption(seq: Seq[Option[JsValue]]) = if (seq.forall(_ == None))
None
else
//Some(JsArray(seq.map(_.orNull)))
Some(JsArray(seq.map(_.getOrElse(JsNull))))
private[this] def chooseOnlyDifferenceElements: (JsValue, JsValue) => Option[(Option[JsValue], Option[JsValue])] = {
case (jsValueA, jsValueB) if jsValueA == jsValueB =>
None: Option[(Option[JsValue], Option[JsValue])]
// なぜかIntellijの推論がうまく働かずエラー表示されるので型情報を明示する
case (jsObjectA: JsObject, jsObjectB: JsObject) =>
val unionedKeys = jsObjectA.keys ++ jsObjectB.keys
val differenceElementsMap = unionedKeys.map { key =>
key -> chooseOnlyDifferenceElements(jsObjectA \ key, jsObjectB \ key)
}.toMap
val mapA = differenceElementsMap.map {
case (key, Some(Tuple2(Some(jsValue), _))) if !jsValue.isInstanceOf[JsUndefined] =>
Some(key -> jsValue)
case _ => None
}.flatten.toMap
val mapB = differenceElementsMap.map {
case (key, Some(Tuple2(_, Some(jsValue)))) if !jsValue.isInstanceOf[JsUndefined] =>
Some(key -> jsValue)
case _ => None
}.flatten.toMap
Some((toJsObectOption(mapA), toJsObectOption(mapB)))
case (jsArrayA: JsArray, jsArrayB: JsArray) =>
val maxSize = Seq(jsArrayA.value.size, jsArrayB.value.size).max
val differenceElements = Range(0, maxSize).map { index =>
chooseOnlyDifferenceElements(jsArrayA(index), jsArrayB(index))
}
val seqA = differenceElements.map {
/** @todo JsObjectと同様にJsUndefined時の処理を追加する */
case Some(Tuple2(Some(jsValue), _)) => Some(jsValue)
case _ => None
}
val seqB = differenceElements.map {
/** @todo JsObjectと同様にJsUndefined時の処理を追加する */
case Some(Tuple2(_, Some(jsValue))) => Some(jsValue)
case _ => None
}
Some((toJsArrayOption(seqA), toJsArrayOption(seqB)))
case (jsValueA, jsValueB) => Some((Some(jsValueA), Some(jsValueB)))
}
override def showDiffs(expected: String, actual: String): (String, String) =
(Try(Json.parse(expected)), Try(Json.parse(actual))) match {
case (Success(expectedJson), Success(actualJson)) =>
val (trimedExpected, trimedActual) = chooseOnlyDifferenceElements(expectedJson, actualJson).
getOrElse(throw new IllegalStateException(
"違いがあってこのメソッドが呼ばれてるのにtrimした結果が空 = 違いがない。おかしい"))
(
trimedExpected.map(Json.prettyPrint).getOrElse(""),
trimedActual.map(Json.prettyPrint).getOrElse("")
)
case _ => super.showDiffs(expected, actual)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment