ch.ralscha.extdirectspring.controller.ApiControllerWithDocumentationTest.java Source code

Java tutorial

Introduction

Here is the source code for ch.ralscha.extdirectspring.controller.ApiControllerWithDocumentationTest.java

Source

/**
 * Copyright 2010-2014 Ralph Schaer <ralphschaer@gmail.com>
 *
 * 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 ch.ralscha.extdirectspring.controller;

import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.data.MapEntry.entry;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.Assert;
import org.springframework.web.context.WebApplicationContext;

import ch.ralscha.extdirectspring.bean.api.ActionDoc;
import ch.ralscha.extdirectspring.util.ApiCache;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:/testApplicationContext.xml")
public class ApiControllerWithDocumentationTest {
    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Autowired
    private ConfigurationService configurationService;

    @Autowired
    private ApiCache apiCache;

    @Before
    public void setupApiController() throws Exception {
        apiCache.clear();

        Configuration config = new Configuration();
        config.setTimeout(15000);
        config.setEnableBuffer(Boolean.FALSE);
        config.setMaxRetries(5);
        config.setStreamResponse(true);
        ReflectionTestUtils.setField(configurationService, "configuration", config);
        configurationService.afterPropertiesSet();

        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    /**
     * to test the following need to activate Feature 'ALLOW_COMMENTS' for jackson parser
     * <p>
     * typical error is com.fasterxml.jackson.core.JsonParseException: Unexpected
     * character ('/' (code 47)): maybe a (non-standard) comment?
     *
     * @throws Exception
     */
    @Test
    public void testDoc1() throws Exception {
        ActionDoc doc = callApi("method1");

        assertThat(doc.isDeprecated()).isTrue();
        assertThat(doc.getMethodComment()).isEqualTo("this method is used to test the documentation generation");
        assertThat(doc.getAuthor()).isEqualTo("dbs");
        assertThat(doc.getVersion()).isEqualTo("0.1");
        assertThat(doc.getParameters()).hasSize(5);
        assertThat(doc.getParameters()).contains(entry("a", "property a integer"), entry("b", "property b string"),
                entry("c", "property c string"), entry("d", "property d boolean"), entry("e", "array of integers"));
        assertThat(doc.getReturnMethod()).hasSize(2);
        assertThat(doc.getReturnMethod()).contains(entry("errors", "list of failed fields"),
                entry("success", "true for success, false otherwise"));
    }

    @Test
    public void testDoc2() throws Exception {
        ActionDoc doc = callApi("method2");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method two doc");
        assertThat(doc.getAuthor()).isEmpty();
        assertThat(doc.getVersion()).isEqualTo("1.0");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc3() throws Exception {
        ActionDoc doc = callApi("method3");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method three doc");
        assertThat(doc.getAuthor()).isEqualTo("dbs");
        assertThat(doc.getVersion()).isEqualTo("1.0");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc4() throws Exception {
        ActionDoc doc = callApi("method4");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method four doc");
        assertThat(doc.getAuthor()).isEqualTo("sr");
        assertThat(doc.getVersion()).isEqualTo("0.4");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc5() throws Exception {
        ActionDoc doc = callApi("method5");

        assertThat(doc.isDeprecated()).isTrue();
        assertThat(doc.getMethodComment()).isEqualTo("method five doc");
        assertThat(doc.getAuthor()).isEqualTo("dbs");
        assertThat(doc.getVersion()).isEqualTo("0.5");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc6() throws Exception {
        ActionDoc doc = callApi("method6");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method six doc");
        assertThat(doc.getAuthor()).isEqualTo("sr");
        assertThat(doc.getVersion()).isEqualTo("0.6");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc7() throws Exception {
        ActionDoc doc = callApi("method7");

        assertThat(doc.isDeprecated()).isTrue();
        assertThat(doc.getMethodComment()).isEqualTo("method seven doc");
        assertThat(doc.getAuthor()).isEqualTo("sr");
        assertThat(doc.getVersion()).isEqualTo("0.7");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).hasSize(1);
        assertThat(doc.getReturnMethod()).contains(entry("p1", "p1 desc"));
    }

    @Test
    public void testDoc8() throws Exception {
        ActionDoc doc = callApi("method8");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method eight doc");
        assertThat(doc.getAuthor()).isEqualTo("sr");
        assertThat(doc.getVersion()).isEqualTo("0.8");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).hasSize(2);
        assertThat(doc.getReturnMethod()).contains(entry("p1", "p1 desc"), entry("p2", "p2 desc"));
    }

    @Test
    public void testDoc9() throws Exception {
        ActionDoc doc = callApi("method9");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method nine doc");
        assertThat(doc.getAuthor()).isEqualTo("dbs");
        assertThat(doc.getVersion()).isEqualTo("0.9");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc10() throws Exception {
        ActionDoc doc = callApi("method10");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method ten doc");
        assertThat(doc.getAuthor()).isEqualTo("sr");
        assertThat(doc.getVersion()).isEqualTo("1.0");
        assertThat(doc.getParameters()).hasSize(1);
        assertThat(doc.getParameters()).contains(entry("a", "a desc"));
        assertThat(doc.getReturnMethod()).hasSize(2);
        assertThat(doc.getReturnMethod()).contains(entry("p1", "p1 desc"), entry("p2", "p2 desc"));

    }

    @Test
    public void testDoc11() throws Exception {
        ActionDoc doc = callApi("method11");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method eleven doc");
        assertThat(doc.getAuthor()).isEmpty();
        assertThat(doc.getVersion()).isEqualTo("1.0");
        assertThat(doc.getParameters()).hasSize(2);
        assertThat(doc.getParameters()).contains(entry("a", "a desc"), entry("b", "b desc"));
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    @Test
    public void testDoc12() throws Exception {
        ActionDoc doc = callApi("method12");

        assertThat(doc.isDeprecated()).isFalse();
        assertThat(doc.getMethodComment()).isEqualTo("method twelve doc");
        assertThat(doc.getAuthor()).isEqualTo("sr");
        assertThat(doc.getVersion()).isEqualTo("1.0");
        assertThat(doc.getParameters()).isEmpty();
        assertThat(doc.getReturnMethod()).isEmpty();
    }

    public void testRequestToApiDebugDoesNotContainDocs() throws Exception {
        doRequestWithoutDocs("/api-debug.js");
    }

    public void testRequestToApiDoesNotContainDocs() throws Exception {
        doRequestWithoutDocs("/api.js");
    }

    private void doRequestWithoutDocs(String url) throws Exception {
        ApiRequestParams params = ApiRequestParams.builder().apiNs("Ext.ns").actionNs("actionns").group("doc")
                .configuration(configurationService.getConfiguration()).build();
        MockHttpServletRequestBuilder request = get(url).accept(MediaType.ALL).characterEncoding("UTF-8");
        request.param("apiNs", params.getApiNs());
        request.param("actionNs", params.getActionNs());
        request.param("group", params.getGroup());

        MvcResult result = mockMvc.perform(request).andExpect(status().isOk())
                .andExpect(content().contentType("application/javascript")).andReturn();

        ApiControllerTest.compare(result, ApiControllerTest.groupApisWithDoc("actionns"), params);
        Assert.doesNotContain("/**", result.getResponse().getContentAsString(),
                "generation of api.js should not contain method documentation");
    }

    private ActionDoc callApi(String method) throws Exception {
        ApiRequestParams params = ApiRequestParams.builder().apiNs("Ext.ns").actionNs("actionns").group("doc")
                .configuration(configurationService.getConfiguration()).build();
        MockHttpServletRequestBuilder request = get("/api-debug-doc.js").accept(MediaType.ALL)
                .characterEncoding("UTF-8");
        request.param("apiNs", params.getApiNs());
        request.param("actionNs", params.getActionNs());
        request.param("group", params.getGroup());

        MvcResult result = mockMvc.perform(request).andExpect(status().isOk())
                .andExpect(content().contentType("application/javascript")).andReturn();

        ApiControllerTest.compare(result, ApiControllerTest.groupApisWithDoc("actionns"), params);
        ActionDoc doc = getCommentForMethod(result.getResponse().getContentAsString(), method);
        return doc;
    }

    private final static Pattern COMMENT_PATTERN = Pattern.compile("/\\*\\*([^/]*)\\*/", Pattern.MULTILINE);

    private static ActionDoc getCommentForMethod(String apiString, String method) {
        ActionDoc doc = new ActionDoc(method, Collections.<String>emptyList());

        String block = findCommentBlock(apiString, method);
        if (block != null) {
            doc.setDeprecated(block.contains("* @deprecated"));

            int p = block.indexOf("@author:");
            if (p != -1) {
                doc.setAuthor(block.substring(p + 9, block.indexOf('\n', p)));
            }

            p = block.indexOf("@version:");
            if (p != -1) {
                doc.setVersion(block.substring(p + 10, block.indexOf('\n', p)));
            }

            p = block.indexOf(method);
            if (p != -1) {
                doc.setMethodComment(block.substring(p + method.length() + 2, block.indexOf('\n', p)));
            }

            Map<String, String> params = new HashMap<String, String>();
            p = block.indexOf("@param:");
            while (p != -1) {
                int p2 = block.indexOf('\n', p);
                String pc = block.substring(p + 8, p2);
                int c1 = pc.indexOf('[');
                int c2 = pc.indexOf(']');
                params.put(pc.substring(c1 + 1, c2), pc.substring(c2 + 2));
                p = block.indexOf("@param:", p2);
            }
            doc.setParameters(params);

            Map<String, String> returns = new HashMap<String, String>();
            p = block.indexOf("@return");
            if (p != -1) {
                p = block.indexOf('[', p);
                while (p != -1) {
                    int p2 = block.indexOf(']', p);
                    returns.put(block.substring(p + 1, p2), block.substring(p2 + 2, block.indexOf('\n', p2)));
                    p = block.indexOf('[', p2);
                }
            }

            doc.setReturnMethod(returns);
        }

        return doc;
    }

    private static String findCommentBlock(String apiString, String method) {
        Matcher m = COMMENT_PATTERN.matcher(apiString);
        while (m.find()) {
            String block = m.group(1);
            if (block.contains(method + ":")) {
                return block;
            }
        }
        return null;
    }
}