import org.specs._
object JsonSpec extends Specification {
import dispatch.json._
import JsHttp._
val js = Js(""" { "a": {"a": "a string", "b": {"pi": 3.14159265 } }, "b": [1,2,3] } """)
val expected_map = Map(
JsString('a) -> JsObject(Map(
JsString('a) -> JsString("a string"),
JsString('b) -> JsObject(Map(
JsString('pi) -> JsNumber(BigDecimal("3.14159265")))
)
)),
JsString('b) -> JsArray(List(JsNumber(1), JsNumber(2), JsNumber(3)))
)
val js_list = Js("[1,2,3]")
val expected_list = List(JsNumber(1), JsNumber(2), JsNumber(3))
object res { def ># [T](f: JsF[T]) = f(js) }
"Parsed Json" should {
"equal expected map" in {
js.self must_== expected_map
}
"equal expected list" in {
js_list.self must_== expected_list
}
"equal itself serilized and reparsed" in {
js must_== JsValue.fromString(JsValue.toJson(js))
}
}
"Nested extractor object" should {
object TestExtractor extends Js {
val a = new Obj('a) {
val a = ('a ? str)
val b = new Obj('b) {
val pi = 'pi ? num
}
}
val b = 'b ? (list ! num)
}
"match against top level object" in {
val TestExtractor.a(a) = js
a must_== expected_map(JsString('a))
}
"match against second level string" in {
val TestExtractor.a.a(a) = js
a must_== "a string"
}
"match against third level number" in {
val TestExtractor.a.b.pi(p) = js
p must_== 3.14159265
}
"match against a numeric list" in {
val TestExtractor.b(b) = js
b must_== List(1,2,3)
}
"replace second level string" in {
res ># (TestExtractor.a.a << "land, ho") must_== (Js(
""" { "a": {"a": "land, ho", "b": {"pi": 3.14159265 } }, "b": [1,2,3] } """
))
}
}
"Flat extractors" should {
val a = 'a ? obj
val aa = 'a ? str
val b = 'b ? obj
val pi = 'pi ? num
val l = 'b ? list
"extract a top level object" in {
val a(a0) = js
a0 must_== expected_map(JsString('a))
}
"deeply extract a third level number" in {
val a(b(pi(pi0))) = js
pi0 must_== 3.14159265
}
"match against an unextracted list" in {
val l(l0) = js
l0 must_== List(JsValue(1), JsValue(2), JsValue(3))
}
val num_list = list ! num
"match for an unenclosed Json list" in {
val num_list(l0) = js_list
l0 must_== List(1,2,3)
}
"pattern-match correct elements" in {
(js match {
case b(b0) => b0
case a(a0) => a0
}) must_== expected_map(JsString('a))
}
"awkwardly replace second level string" in {
val a(a0) = js
res ># (a << (aa << "barnacles, ahoy")(a0)) must_== (Js(
""" { "a": {"a": "barnacles, ahoy", "b": {"pi": 3.14159265 } }, "b": [1,2,3] } """
))
}
}
"Function extractor" should {
"extract a top level object" in {
res ># ('a ! obj) must_== expected_map(JsString('a))
}
"extract a tuple of top level objects" in {
res ># %('a ! obj, 'b ! list, 'b ! list) must_==
(expected_map(JsString('a)), expected_list, expected_list)
}
"extract a second level string" in {
res ># { ('a ! obj) andThen ('a ! str) } must_== "a string"
}
"extract a third level number" in {
res ># { ('a ! obj) andThen ('b ! obj) andThen ('pi ! num) } must_== 3.14159265
}
"work with map" in {
List(js, js, js).map ('b ! (list ! num)) must_== List.tabulate(3, _ => List(1,2,3))
}
def fun_l[T](ext: JsF[T]) = ext(js_list)
"extract unenclosed Json list" in {
fun_l(list ! num) must_== List(1,2,3)
}
}
"assertion inserting" should {
"replace second level string" in {
res ># ('a << ('a << "barnacles, ahoy")) must_== (Js(
""" { "a": {"a": "barnacles, ahoy", "b": {"pi": 3.14159265 } }, "b": [1,2,3] } """
))
}
"replace a second level object with a string" in {
res ># ('a << ('b << "bonzai!")) must_== (Js(
""" { "a": {"a": "a string", "b": "bonzai!" } , "b": [1,2,3] } """
))
}
}
}