cjstehno / ersatz

🤖 A simulated HTTP server for testing client code with configurable responses.
https://cjstehno.github.io/ersatz
Apache License 2.0
47 stars 5 forks source link

EncoderChain fails to resolve an encoder if object is a Map #52

Closed radarsh closed 7 years ago

radarsh commented 7 years ago

If we try to encode a Map instance using the response encoder, the encoder chain logic fails to resolve it.

static final def JSON_ENCODER = { Object object ->
    toJson(object)
} as Function

def server = new ErsatzServer({
    encoder 'application/json', LinkedHashMap, JSON_ENCODER
})

I believe this is because in the ErsatzResponse class the getContent method tries to evaluate content.class but if content is a Map, Groovy thinks class is a key of the Map rather than a property accessor for getClass method.

@Override
String getContent() {
    if (content != null) {
        return encoderChain.resolve(contentType, content.class)?.apply(content) ?: (content as String)
    }
    return ''
}

The proposed solution is to use the method accessor rather than property shorthand in this instance.

return encoderChain.resolve(contentType, content.getClass())?.apply(content) ?: (content as String)
cjstehno commented 7 years ago

Interesting. I will look into this over the weekend and roll it into the upcoming release - should be ready late next week.

radarsh commented 7 years ago

@cjstehno thanks. I also noticed that while debugging in IntelliJ, I had to do this.@content.getClass() or else it was trying to invoke the getContent() method again recursively and failing. This was only while evaluating the expression.

cjstehno commented 7 years ago

Hmm. Can you provide a more complete example of code that is failing? I tried the following:

def 'resolves map properly'() {
    setup:
    def server = new ErsatzServer({
        autoStart()
        encoder(APPLICATION_JSON, LinkedHashMap) { obj -> toJson(obj) }
    })

    server.expectations {
        get('/foo').responds().content([alpha: 'one'], APPLICATION_JSON)
    }

    when:
    String response = "${server.httpUrl}/foo".toURL().text

    then:
    response == '{"alpha":"one"}'
}

and the test passes.

Also the following information might be useful:

Thanks

radarsh commented 7 years ago

Strange that it wasn't working for me earlier. I must have done something wrong. It works for me too. You may close this bug now. Sorry about the confusion. It's a great tool and I'm really enjoying working with it.

Also, probably it would help if you included examples of mocking JSON requests and responses in the documentation. Apologies if it's already present.

cjstehno commented 7 years ago

No problem. Glad you like it. I will be giving the user guide a major overhaul in the next few weeks so I will make sure I have more examples like that.

Take care.