@@ -18,16 +18,27 @@ package zio.http
1818
1919import java .io .File
2020
21+ import zio .json .{DeriveJsonDecoder , DeriveJsonEncoder , JsonDecoder , JsonEncoder }
2122import zio .test .Assertion .equalTo
2223import zio .test .TestAspect .timeout
2324import zio .test ._
2425import zio .{Scope , durationInt }
2526
2627import zio .stream .ZStream
2728
29+ import zio .schema .{DeriveSchema , Schema }
30+
2831object BodySpec extends ZIOHttpSpec {
2932 private val testFile = new File (getClass.getResource(" /TestFile.txt" ).getPath)
3033
34+ case class Person (name : String , age : Int )
35+
36+ object Person {
37+ implicit val schema : Schema [Person ] = DeriveSchema .gen[Person ]
38+ implicit val encoder : JsonEncoder [Person ] = DeriveJsonEncoder .gen[Person ]
39+ implicit val decoder : JsonDecoder [Person ] = DeriveJsonDecoder .gen[Person ]
40+ }
41+
3142 override def spec : Spec [TestEnvironment with Scope , Throwable ] =
3243 suite(" BodySpec" )(
3344 suite(" outgoing" )(
@@ -56,6 +67,93 @@ object BodySpec extends ZIOHttpSpec {
5667 ),
5768 ),
5869 ),
70+ suite(" json" )(
71+ suite(" Body.json with zio-schema" )(
72+ test(" creates JSON body from case class" ) {
73+ val person = Person (" John" , 42 )
74+ val body = Body .json(person)
75+ for {
76+ content <- body.asString
77+ } yield assertTrue(
78+ content.contains(" John" ),
79+ content.contains(" 42" ),
80+ body.mediaType.contains(MediaType .application.json),
81+ )
82+ },
83+ test(" round-trip encoding and decoding" ) {
84+ val person = Person (" Alice" , 30 )
85+ val body = Body .json(person)
86+ for {
87+ decoded <- body.asJson[Person ]
88+ } yield assertTrue(decoded == person)
89+ },
90+ ),
91+ suite(" Body.json with zio-json" )(
92+ test(" creates JSON body from case class" ) {
93+ val person = Person (" Jane" , 25 )
94+ val body = Body .jsonCodec(person)
95+ for {
96+ content <- body.asString
97+ } yield assertTrue(
98+ content.contains(" Jane" ),
99+ content.contains(" 25" ),
100+ body.mediaType.contains(MediaType .application.json),
101+ )
102+ },
103+ test(" round-trip encoding and decoding" ) {
104+ val person = Person (" Bob" , 35 )
105+ val body = Body .jsonCodec(person)
106+ for {
107+ decoded <- body.asJsonFromCodec[Person ]
108+ } yield assertTrue(decoded == person)
109+ },
110+ ),
111+ suite(" Body.asJson with zio-schema" )(
112+ test(" decodes JSON string to case class" ) {
113+ val jsonString = """ {"name":"Charlie","age":28}"""
114+ val body = Body .fromString(jsonString)
115+ for {
116+ decoded <- body.asJson[Person ]
117+ } yield assertTrue(
118+ decoded.name == " Charlie" ,
119+ decoded.age == 28 ,
120+ )
121+ },
122+ test(" fails on invalid JSON" ) {
123+ val invalidJson = """ {"name":"Invalid"}"""
124+ val body = Body .fromString(invalidJson)
125+ for {
126+ result <- body.asJson[Person ].exit
127+ } yield assertTrue(result.isFailure)
128+ },
129+ ),
130+ suite(" Body.asJsonZio with zio-json" )(
131+ test(" decodes JSON string to case class" ) {
132+ val jsonString = """ {"name":"David","age":40}"""
133+ val body = Body .fromString(jsonString)
134+ for {
135+ decoded <- body.asJsonFromCodec[Person ]
136+ } yield assertTrue(
137+ decoded.name == " David" ,
138+ decoded.age == 40 ,
139+ )
140+ },
141+ test(" fails on invalid JSON" ) {
142+ val invalidJson = """ {"invalid":"json"}"""
143+ val body = Body .fromString(invalidJson)
144+ for {
145+ result <- body.asJsonFromCodec[Person ].exit
146+ } yield assertTrue(result.isFailure)
147+ },
148+ test(" fails on malformed JSON" ) {
149+ val malformedJson = """ not valid json"""
150+ val body = Body .fromString(malformedJson)
151+ for {
152+ result <- body.asJsonFromCodec[Person ].exit
153+ } yield assertTrue(result.isFailure)
154+ },
155+ ),
156+ ),
59157 suite(" mediaType" )(
60158 test(" updates the Body media type with the provided value" ) {
61159 val body = Body .fromString(" test" ).contentType(MediaType .text.plain)
0 commit comments