package datamodel;

import com.google.common.reflect.ClassPath;
import io.github.mzmine.datamodel.features.types.DataType;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class DataTypesTest {

  @Test
  public void testUniqueID() {

    // map unique ID to instance
    final HashMap<String, DataType<?>> map = new HashMap<>();

    try {
      ClassPath classPath = ClassPath.from(DataType.class.getClassLoader());
      classPath.getTopLevelClassesRecursive("io.github.mzmine.datamodel.features.types")
          .forEach(classInfo -> {
            try {
              Object o = classInfo.load().getDeclaredConstructor().newInstance();
              if (o instanceof DataType dt) {
                var value = map.put(dt.getUniqueID(), dt);
                if (value != null) {
                  Assertions.fail(
                      "FATAL: Multiple data types with unique ID " + dt.getUniqueID() + "\n"
                          + value.getClass().getName() + "\n" + dt.getClass().getName());
                }
              }
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
              //               can go silent
              //              logger.log(Level.INFO, e.getMessage(), e);
            }
          });
    } catch (IOException e) {
      Assertions.fail("Cannot instantiate classPath for DataType.class. Cannot load projects.");
    }
  }

  @Test
  public void testSimpleClassName() {
    // map unique ID to instance
    final HashMap<String, DataType<?>> map = new HashMap<>();

    try {
      ClassPath classPath = ClassPath.from(DataType.class.getClassLoader());
      classPath.getTopLevelClassesRecursive("io.github.mzmine.datamodel.features.types")
          .forEach(classInfo -> {
            try {
              Object o = classInfo.load().getDeclaredConstructor().newInstance();
              if (o instanceof DataType dt) {
                var value = map.put(dt.getClass().getSimpleName(), dt);
                if (value != null) {
                  Assertions.fail(
                      "FATAL: Multiple data types with class name " + dt.getClass().getSimpleName()
                          + "\n" + value.getClass().getName() + "\n" + dt.getClass().getName());
                }
              }
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            }
          });
    } catch (IOException e) {
      Assertions.fail("Cannot instantiate classPath for DataType.class. Cannot load projects.");
    }
  }

}

@@ -212,20 +212,88 @@
 ava.
-util.HashMap
+lang.reflect.Modifier;%0Aimport java.util.HashMap;%0Aimport java.util.logging.Logger
 ;%0Aim
@@ -397,16 +397,105 @@
 Test %7B%0A%0A
+  private static final Logger logger = Logger.getLogger(DataTypesTest.class.getName());%0A%0A
   @Test%0A
@@ -868,35 +868,127 @@
     
-Object o = classInfo.load()
+final Class%3C?%3E clazz = classInfo.load();%0A              clazz.asSubclass(DataType.class);%0A              Object o = clazz
 .get
@@ -1562,43 +1562,221 @@
     
-//               can go silent%0A    
+if (!Modifier.isAbstract(classInfo.load().getModifiers()) && !classInfo.load()%0A                  .isInterface()) %7B%0A                Assertions.fail(%22Cannot instantiate DataType class %22 + classInfo.load().getName()%0A
     
@@ -1781,18 +1781,16 @@
         
-//
         
@@ -1795,54 +1795,154 @@
     
-    logger.log(Level.INFO, e.getMessage(), e);
++ %22. Is the constructor not public?%22);%0A              %7D%0A            %7D catch (ClassCastException e) %7B%0A              // can go silent, not a DataType
 %0A   
@@ -2492,35 +2492,127 @@
     
-Object o = classInfo.load()
+final Class%3C?%3E clazz = classInfo.load();%0A              clazz.asSubclass(DataType.class);%0A              Object o = clazz
 .get
@@ -3061,32 +3061,32 @@
               %7D%0A
-
             %7D ca
@@ -3187,32 +3187,426 @@
 dException e) %7B%0A
+              if (!Modifier.isAbstract(classInfo.load().getModifiers()) && !classInfo.load()%0A                  .isInterface()) %7B%0A                Assertions.fail(%22Cannot instantiate DataType class %22 + classInfo.load().getName()%0A                    + %22. Is the constructor not public?%22);%0A              %7D%0A            %7D catch (ClassCastException e) %7B%0A              // can go silent, not a DataType%0A
             %7D%0A  

modify test to also check for instantiability