<commit_before>package org.bobba.tools.statest.common;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import org.bobba.tools.commons.utils.CommonUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang3.Validate.notNull;

public final class RestAssuredCodeGenerator {

    private RestAssuredCodeGenerator() {
    }

    public static Matcher<?> assertionGeneratingMatcher() {
        final String codePointer = CommonUtils.createCodePointer(-1);
        return new BaseMatcher<String>() {
            @Override
            public boolean matches(Object item) {
                notNull(item);
                System.out.println("*** Generating assertions for " + codePointer);
                System.out.println(generateAssertionsForJson((String) item));
                System.out.println("*** " + codePointer);
                throw new RuntimeException("Stopped by assertion generator");
            }

            @Override
            public void describeTo(Description description) {
            }
        };
    }

    public static String generateAssertionsForJson(String json) {
        final JsonNode jsonNode = read(json);
        return generateAssertions(jsonNode);
    }

    private static String generateAssertions(JsonNode jsonNode) {
        return AssertionBuilder.generateAssertions("", jsonNode);
    }

    private static JsonNode read(String json) {
        try {
            return new ObjectMapper().readTree(json);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static final class AssertionBuilder {

        private final List<String> lines = new ArrayList<String>();

        private NodeHandlerFactory nodeHandlerFactory = createNodeHandlerFactory();

        private static NodeHandlerFactory createNodeHandlerFactory() {
            final ImmutableMap<Class<? extends JsonNode>, NodeHandler<? extends JsonNode>>
                    nodeHandlers = ImmutableMap.<Class<? extends JsonNode>, NodeHandler<? extends JsonNode>>builder()
                    .put(ObjectNode.class, new ObjectNodeHandler())
                    .put(TextNode.class, new TextNodeHandler())
                    .put(NullNode.class, new NullNodeHandler())
                    .put(BooleanNode.class, new BooleanNodeHandler())
                    .put(LongNode.class, new LongNodeHandler())
                    .put(IntNode.class, new IntNodeHandler())
                    .put(ArrayNode.class, new ArrayNodeHandler())
                    .build();

            return new NodeHandlerFactory() {
                @Override
                public <T extends JsonNode> NodeHandler<T> getHandler(
                        Class<T> nodeClass) {
                    //noinspection unchecked
                    final NodeHandler<T> result = (NodeHandler<T>) nodeHandlers.get(nodeClass);
                    if (result == null) {
                        throw new RuntimeException("Unexpected node type: " + nodeClass);
                    }
                    return result;
                }
            };
        }

        public String build() {
            return Joiner.on('\n').join(lines);
        }

        public static String generateAssertions(String context, JsonNode rootNode) {
            final AssertionBuilder assertionBuilder = new AssertionBuilder();
            assertionBuilder.appendAssertions(context, rootNode);
            return assertionBuilder.build();
        }

        private void appendAssertions(String context, JsonNode jsonNode) {
            final NodeHandler nodeHandler = getNodeHandler(jsonNode.getClass());

            @SuppressWarnings("unchecked")
            final String result = nodeHandler.generateAssertions(context, jsonNode, nodeHandlerFactory);

            lines.add(result);
        }

        private NodeHandler getNodeHandler(Class<? extends JsonNode> aClass) {
            return nodeHandlerFactory.getHandler(aClass);
        }

        private static String createBodyText(String field, String assertion) {
            return ".body(\"" + field + "\", " + assertion + ")";
        }

        private static String prefixed(String prefix, String field) {
            return StringUtils.isEmpty(prefix) ? field : prefix + "." + field;
        }

        private interface NodeHandler<T extends JsonNode> {
            String generateAssertions(String context, T node,
                                      NodeHandlerFactory nodeHandlerFactory);
        }

        private interface NodeHandlerFactory {
            <T extends JsonNode> NodeHandler<T> getHandler(Class<T> nodeClass);
        }

        private static class ObjectNodeHandler implements NodeHandler<ObjectNode> {

            @Override
            public String generateAssertions(String context, ObjectNode node, NodeHandlerFactory nodeHandlerFactory) {
                final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
                final List<String> result = new ArrayList<String>();
                if (StringUtils.isNotEmpty(context)) {
                    result.add(createBodyText(context, "notNullValue()"));
                }
                while (iterator.hasNext()) {
                    final Map.Entry<String, JsonNode> entry = iterator.next();
                    final JsonNode childNode = entry.getValue();
                    try {
                        result.add(generateAssertions(context, entry.getKey(), childNode, nodeHandlerFactory));
                    } catch (RuntimeException e) {
                        throw new RuntimeException(
                                "Error when handling node: " + entry.getKey() + ", value:" + childNode, e);
                    }
                }
                return Joiner.on('\n').join(result);
            }

            @SuppressWarnings("unchecked")
            private String generateAssertions(String prefix, String name, JsonNode node,
                                              NodeHandlerFactory nodeHandlerFactory) {
                notNull(node);
                final NodeHandler nodeHandler = nodeHandlerFactory.getHandler(node.getClass());
                return nodeHandler.generateAssertions(prefixed(prefix, name), node, nodeHandlerFactory);
            }

        }

        private static class ArrayNodeHandler implements NodeHandler<ArrayNode> {
            @Override
            public String generateAssertions(String context, ArrayNode node, NodeHandlerFactory nodeHandlerFactory) {
                final List<String> result = new ArrayList<String>();<commit_msg>Tests moved to test directory.<commit_after>package org.bobba.tools.statest.common;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import org.bobba.tools.commons.utils.CommonUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang3.Validate.notNull;

public final class RestAssuredCodeGenerator {

    private RestAssuredCodeGenerator() {
    }

    public static Matcher<?> assertionGeneratingMatcher() {
        final String codePointer = CommonUtils.createCodePointer(-1);
        return new BaseMatcher<String>() {
            @Override
            public boolean matches(Object item) {
                notNull(item);
                System.out.println("*** Generating assertions for " + codePointer);
                System.out.println(generateAssertionsForJson((String) item));
                System.out.println("*** " + codePointer);
                throw new RuntimeException("Stopped by assertion generator");
            }

            @Override
            public void describeTo(Description description) {
            }
        };
    }

    public static String generateAssertionsForJson(String json) {
        final JsonNode jsonNode = read(json);
        return generateAssertions(jsonNode);
    }

    private static String generateAssertions(JsonNode jsonNode) {
        return AssertionBuilder.generateAssertions("", jsonNode);
    }

    private static JsonNode read(String json) {
        try {
            return new ObjectMapper().readTree(json);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static final class AssertionBuilder {

        private final List<String> lines = new ArrayList<>();

        private NodeHandlerFactory nodeHandlerFactory = createNodeHandlerFactory();

        private static NodeHandlerFactory createNodeHandlerFactory() {
            final ImmutableMap<Class<? extends JsonNode>, NodeHandler<? extends JsonNode>>
                    nodeHandlers = ImmutableMap.<Class<? extends JsonNode>, NodeHandler<? extends JsonNode>>builder()
                    .put(ObjectNode.class, new ObjectNodeHandler())
                    .put(TextNode.class, new TextNodeHandler())
                    .put(NullNode.class, new NullNodeHandler())
                    .put(BooleanNode.class, new BooleanNodeHandler())
                    .put(LongNode.class, new LongNodeHandler())
                    .put(IntNode.class, new IntNodeHandler())
                    .put(ArrayNode.class, new ArrayNodeHandler())
                    .build();

            return new NodeHandlerFactory() {
                @Override
                public <T extends JsonNode> NodeHandler<T> getHandler(
                        Class<T> nodeClass) {
                    //noinspection unchecked
                    final NodeHandler<T> result = (NodeHandler<T>) nodeHandlers.get(nodeClass);
                    if (result == null) {
                        throw new RuntimeException("Unexpected node type: " + nodeClass);
                    }
                    return result;
                }
            };
        }

        public String build() {
            return Joiner.on('\n').join(lines);
        }

        public static String generateAssertions(String context, JsonNode rootNode) {
            final AssertionBuilder assertionBuilder = new AssertionBuilder();
            assertionBuilder.appendAssertions(context, rootNode);
            return assertionBuilder.build();
        }

        private void appendAssertions(String context, JsonNode jsonNode) {
            final NodeHandler nodeHandler = getNodeHandler(jsonNode.getClass());

            @SuppressWarnings("unchecked")
            final String result = nodeHandler.generateAssertions(context, jsonNode, nodeHandlerFactory);

            lines.add(result);
        }

        private NodeHandler getNodeHandler(Class<? extends JsonNode> aClass) {
            return nodeHandlerFactory.getHandler(aClass);
        }

        private static String createBodyText(String field, String assertion) {
            return ".body(\"" + field + "\", " + assertion + ")";
        }

        private static String prefixed(String prefix, String field) {
            return StringUtils.isEmpty(prefix) ? field : prefix + "." + field;
        }

        private interface NodeHandler<T extends JsonNode> {
            String generateAssertions(String context, T node,
                                      NodeHandlerFactory nodeHandlerFactory);
        }

        private interface NodeHandlerFactory {
            <T extends JsonNode> NodeHandler<T> getHandler(Class<T> nodeClass);
        }

        private static class ObjectNodeHandler implements NodeHandler<ObjectNode> {

            @Override
            public String generateAssertions(String context, ObjectNode node, NodeHandlerFactory nodeHandlerFactory) {
                final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
                final List<String> result = new ArrayList<>();
                if (StringUtils.isNotEmpty(context)) {
                    result.add(createBodyText(context, "notNullValue()"));
                }
                while (iterator.hasNext()) {
                    final Map.Entry<String, JsonNode> entry = iterator.next();
                    final JsonNode childNode = entry.getValue();
                    try {
                        result.add(generateAssertions(context, entry.getKey(), childNode, nodeHandlerFactory));
                    } catch (RuntimeException e) {
                        throw new RuntimeException(
                                "Error when handling node: " + entry.getKey() + ", value:" + childNode, e);
                    }
                }
                return Joiner.on('\n').join(result);
            }

            @SuppressWarnings("unchecked")
            private String generateAssertions(String prefix, String name, JsonNode node,
                                              NodeHandlerFactory nodeHandlerFactory) {
                notNull(node);
                final NodeHandler nodeHandler = nodeHandlerFactory.getHandler(node.getClass());
                return nodeHandler.generateAssertions(prefixed(prefix, name), node, nodeHandlerFactory);
            }

        }

        private static class ArrayNodeHandler implements NodeHandler<ArrayNode> {
            @Override
            public String generateAssertions(String context, ArrayNode node, NodeHandlerFactory nodeHandlerFactory) {
                final List<String> result = new ArrayList<>();
{'fraction_non_alphanumeric': 0.08935996182945947, 'fraction_numerical': 0.0004089700770226978, 'mean_word_length': 2.2175438596491226, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4234323', 'n_tokens_mistral': 3561, 'n_tokens_neox': 3332, 'n_words': 807}