package com.pengrad.telegrambot;

import com.pengrad.telegrambot.model.Animation;
import com.pengrad.telegrambot.model.CallbackQuery;
import com.pengrad.telegrambot.model.Message;
import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.passport.Credentials;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;
import org.junit.Before;
import org.junit.Test;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.junit.Assert.assertTrue;

/**
 * Stas Parshin
 * 31 May 2017
 */
public class ModelTest {

    private Set<Class> classes;

    @Before
    public void setClasses() {
        String modelPackage = Animation.class.getPackage().getName();
        String passportPackage = Credentials.class.getPackage().getName();
        List<String> packages = Arrays.asList(modelPackage, passportPackage);

        classes = new Reflections(packages, new SubTypesScanner(false))
                .getSubTypesOf(Object.class)
                .stream()
                .filter(clazz -> packages.contains(clazz.getPackage().getName())
                        && !clazz.getSimpleName().startsWith("PassportElementError")
                        && !Modifier.isAbstract(clazz.getModifiers())
                ).collect(Collectors.toSet());
    }

    @Test
    public void testEquals() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        Object callbackQuery = CallbackQuery.class.newInstance();
        Field f = CallbackQuery.class.getDeclaredField("id");
        f.setAccessible(true);
        f.set(callbackQuery, "2");

        Object message = Message.class.newInstance();
        f = Message.class.getDeclaredField("message_id");
        f.setAccessible(true);
        f.set(message, 11);

        Object update = Update.class.newInstance();
        f = Update.class.getDeclaredField("update_id");
        f.setAccessible(true);
        f.set(update, 1);

        for (Class c : classes) {
            EqualsVerifier.forClass(c)
                    .usingGetClass()
                    .withPrefabValues(Update.class, Update.class.newInstance(), update)
                    .withPrefabValues(Message.class, Message.class.newInstance(), message)
                    .withPrefabValues(CallbackQuery.class, CallbackQuery.class.newInstance(), callbackQuery)
                    .suppress(Warning.STRICT_HASHCODE)
                    .suppress(Warning.NONFINAL_FIELDS)
                    .verify();
        }
    }

    @Test
    public void testToString() throws IllegalAccessException, InstantiationException {
        for (Class c : classes) {
            String toString = c.newInstance().toString();
            for (Field f : c.getDeclaredFields()) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                assertTrue(c.getSimpleName() + " toString doesn't contain " + f.getName(), toString.contains(f.getName()));
            }
        }
    }
}

@@ -218,16 +218,150 @@
 Update;%0A
+import com.pengrad.telegrambot.model.request.InlineKeyboardButton;%0Aimport com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;%0A
 import c
@@ -405,16 +405,16 @@
 ntials;%0A
-
 import n
@@ -716,16 +716,42 @@
 Arrays;%0A
+import java.util.HashMap;%0A
 import j
@@ -787,16 +787,52 @@
 il.Set;%0A
+import java.util.function.Supplier;%0A
 import j
@@ -1000,16 +1000,95 @@
 classes;
+%0A    private HashMap%3CClass, Supplier%3CObject%3E%3E customInstance = new HashMap%3C%3E();
 %0A%0A    @B
@@ -1773,16 +1773,351 @@
 oSet());
+%0A%0A        // classes from model/request available in responses%0A        classes.add(InlineKeyboardMarkup.class);%0A        classes.add(InlineKeyboardButton.class);%0A        customInstance.put(InlineKeyboardMarkup.class, InlineKeyboardMarkup::new);%0A        customInstance.put(InlineKeyboardButton.class, () -%3E new InlineKeyboardButton(%22%22));
 %0A    %7D%0A%0A
@@ -3469,41 +3469,143 @@
     
-String toString = c.newInstance()
+Object instance = customInstance.containsKey(c) ? customInstance.get(c).get() : c.newInstance();%0A            String toString = instance
 .toS

Add model/request classes in ModelTest