package io.github.lukehutch.fastclasspathscanner.metaannotation;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.StrictAssertions.assertThat;
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.junit.Test;

public class MetaAnnotationTest {
    FastClasspathScanner scanner = new FastClasspathScanner(getClass().getPackage().getName()).scan();

    private static <T extends Comparable<T>> ArrayList<T> sort(List<T> list) {
        ArrayList<T> sorted = new ArrayList<>(list);
        Collections.sort(sorted);
        return sorted;
    }

    @Test
    public void metaAnnotationsByClass() {
        assertThat(scanner.getNamesOfClassesWithAnnotation(MetaAnnotatedAnnotation.class)).containsExactly(
                MetaAnnotatedClass.class.getName());

        assertThat(sort(scanner.getNamesOfClassesWithMetaAnnotation(MetaAnnotation.class))).containsExactly(
                MetaAndNonMetaAnnotatedClass.class.getName(), MetaAnnotatedClass.class.getName());

        assertThat(sort(scanner.getNamesOfClassesWithMetaAnnotation(MetaAnnotatedAnnotation.class)))
                .containsExactly(MetaAnnotatedClass.class.getName(), MetaMetaAnnotatedClass.class.getName());
    }

    @Test
    public void metaAnnotationsByName() {
        assertThat(scanner.getNamesOfClassesWithAnnotation(MetaAnnotatedAnnotation.class.getName()))
                .containsExactly(MetaAnnotatedClass.class.getName());

        assertThat(sort(scanner.getNamesOfClassesWithMetaAnnotation(MetaAnnotation.class.getName())))
                .containsExactly(MetaAndNonMetaAnnotatedClass.class.getName(), MetaAnnotatedClass.class.getName());

        assertThat(sort(scanner.getNamesOfClassesWithMetaAnnotation(MetaAnnotatedAnnotation.class.getName())))
                .containsExactly(MetaAnnotatedClass.class.getName(), MetaMetaAnnotatedClass.class.getName());
    }

    @Test
    public void nonMeta() {
        assertThat(sort(scanner.getNamesOfClassesWithMetaAnnotation(NonMetaAnnotation.class))).containsExactly(
                MetaAndNonMetaAnnotatedClass.class.getName(), NonMetaClass.class.getName());
    }

    @Test
    public void varArgsAnyOfByClass() {
        assertThat(
                sort(scanner.getNamesOfClassesWithMetaAnnotationsAnyOf(MetaAnnotation.class,
                        NonMetaAnnotation.class))) //
                .containsExactly(MetaAndNonMetaAnnotatedClass.class.getName(), MetaAnnotatedClass.class.getName(),
                        NonMetaClass.class.getName());
    }

    @Test
    public void varArgsAnyOfByName() {
        assertThat(
                sort(scanner.getNamesOfClassesWithMetaAnnotationsAnyOf(MetaAnnotation.class.getName(),
                        NonMetaAnnotation.class.getName()))) //
                .containsExactly(MetaAndNonMetaAnnotatedClass.class.getName(), MetaAnnotatedClass.class.getName(),
                        NonMetaClass.class.getName());
    }

    @Test
    public void varArgsAllOfByClass() {
        assertThat(scanner.getNamesOfClassesWithMetaAnnotationsAllOf(MetaAnnotation.class, NonMetaAnnotation.class)) //
                .containsExactly(MetaAndNonMetaAnnotatedClass.class.getName());
    }

    @Test
    public void varArgsAllOfByName() {
        assertThat(
                scanner.getNamesOfClassesWithMetaAnnotationsAllOf(MetaAnnotation.class.getName(),
                        NonMetaAnnotation.class.getName())) //
                .containsExactly(MetaAndNonMetaAnnotatedClass.class.getName());
    }

    @Test
    public void nonMetaAnnotation() {
        assertThat(NonMetaClass.class.getAnnotation(NonMetaAnnotation.class)).isNotNull();
        assertThat(NonMetaClass.class.getAnnotation(MetaAnnotation.class)).isNull();
    }

    @Test
    public void nonClassTargetDoesntWork() {
        assertThat(NonClassTarget.class.getAnnotationsByType(MetaAnnotatedAnnotation.class)).isEmpty();
        assertThat(NonClassTarget.class.getAnnotationsByType(MetaAnnotation.class)).isEmpty();
    }

    @Test
    public void metaMeta() {
        assertThat(MetaMetaAnnotatedClass.class.getAnnotation(MetaAnnotatedAnnotation.class)).isNull();
        assertThat(MetaMetaAnnotatedClass.class.getAnnotation(MetaAnnotation.class)).isNull();
    }
}

@@ -256,90 +256,8 @@
 r;%0A%0A
-import java.util.ArrayList;%0Aimport java.util.Collections;%0Aimport java.util.List;%0A%0A
 impo
@@ -418,204 +418,8 @@
 );%0A%0A
-    private static %3CT extends Comparable%3CT%3E%3E ArrayList%3CT%3E sort(List%3CT%3E list) %7B%0A        ArrayList%3CT%3E sorted = new ArrayList%3C%3E(list);%0A        Collections.sort(sorted);%0A        return sorted;%0A    %7D%0A%0A
     
@@ -640,37 +640,32 @@
      assertThat(
-sort(
 scanner.getNames
@@ -706,33 +706,32 @@
 notation.class))
-)
 .containsExactly
@@ -715,37 +715,34 @@
 class)).contains
-Exact
+On
 ly(%0A            
@@ -840,37 +840,32 @@
      assertThat(
-sort(
 scanner.getNames
@@ -923,17 +923,30 @@
 .class))
-)
+.containsOnly(
 %0A       
@@ -954,33 +954,16 @@
         
-.containsExactly(
 MetaAnno
@@ -1273,37 +1273,32 @@
      assertThat(
-sort(
 scanner.getNames
@@ -1349,33 +1349,46 @@
 lass.getName()))
-)
+.containsOnly(
 %0A               
@@ -1388,33 +1388,16 @@
         
-.containsExactly(
 MetaAndN
@@ -1483,37 +1483,32 @@
      assertThat(
-sort(
 scanner.getNames
@@ -1576,17 +1576,16 @@
 Name()))
-)
 %0A       
@@ -1594,37 +1594,34 @@
        .contains
-Exact
+On
 ly(MetaAnnotated
@@ -1748,21 +1748,16 @@
 ertThat(
-sort(
 scanner.
@@ -1817,17 +1817,16 @@
 .class))
-)
 .contain
@@ -1818,37 +1818,34 @@
 class)).contains
-Exact
+On
 ly(%0A            
@@ -2001,38 +2001,16 @@
 ertThat(
-%0A                sort(
 scanner.
@@ -2076,32 +2076,8 @@
 ass,
-%0A                       
  Non
@@ -2098,20 +2098,16 @@
 .class))
-)
- //
 %0A       
@@ -2116,37 +2116,34 @@
        .contains
-Exact
+On
 ly(MetaAndNonMet
@@ -2362,13 +2362,8 @@
     
-sort(
 scan
@@ -2499,20 +2499,30 @@
 Name()))
-) //
+.containsOnly(
 %0A       
@@ -2530,33 +2530,16 @@
         
-.containsExactly(
 MetaAndN
@@ -2608,32 +2608,24 @@
 .getName(),%0A
-        
             
@@ -2832,19 +2832,16 @@
 .class))
- //
 %0A       

Use containsOnly for order-independent tests