/*
 * Copyright 2014 Lukas Krejci
 *
 * 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 org.revapi.java;

import java.io.ObjectStreamClass;
import java.util.Arrays;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import org.junit.Assert;
import org.junit.Test;

import org.revapi.java.checks.fields.SerialVersionUidUnchanged;
import org.revapi.java.suid.TestClass;

/**
 * @author Lukas Krejci
 * @since 0.1
 */
public class SUIDGeneratorTest {

    @SupportedSourceVersion(SourceVersion.RELEASE_7)
    @SupportedAnnotationTypes("java.lang.SuppressWarnings")
    private static class SUIDGeneratingAnnotationProcessor extends AbstractProcessor {
        public long generatedSUID;

        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(SuppressWarnings.class);

            if (elements.isEmpty()) {
                return false;
            }

            TypeElement testType = (TypeElement) elements.iterator().next();

            generatedSUID = SerialVersionUidUnchanged.computeSerialVersionUID(testType, new TypeEnvironment() {
                @Nonnull
                @Override
                public Elements getElementUtils() {
                    return processingEnv.getElementUtils();
                }

                @Nonnull
                @Override
                public Types getTypeUtils() {
                    return processingEnv.getTypeUtils();
                }

                @Override
                public boolean isExplicitPartOfAPI(@Nonnull TypeElement type) {
                    return true;
                }
            });

            return true;
        }
    }

    @Test
    public void testSUIDGeneration() throws Exception {
        ObjectStreamClass s = ObjectStreamClass.lookup(TestClass.class);
        long officialSUID = s.getSerialVersionUID();
        SUIDGeneratingAnnotationProcessor ap = new SUIDGeneratingAnnotationProcessor();

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        JavaCompiler.CompilationTask task = compiler
            .getTask(null, null, null, null, Arrays.asList(TestClass.class.getName()),
                Arrays.asList(new SourceInClassLoader("suid/TestClass.java")));

        task.setProcessors(Arrays.asList(ap));

        task.call();

        Assert.assertEquals(officialSUID, ap.generatedSUID);
    }
}

@@ -615,16 +615,37 @@
 .java;%0A%0A
+import java.io.File;%0A
 import j
@@ -2848,16 +2848,34 @@
 ption %7B%0A
+        try %7B%0A    
         
@@ -2947,16 +2947,20 @@
         
+    
 long off
@@ -2992,24 +2992,28 @@
 rsionUID();%0A
+    
         SUID
@@ -3089,32 +3089,36 @@
 sor();%0A%0A        
+    
 JavaCompiler com
@@ -3160,24 +3160,28 @@
 ompiler();%0A%0A
+    
         Java
@@ -3233,16 +3233,20 @@
         
+    
 .getTask
@@ -3328,16 +3328,20 @@
         
+    
 Arrays.a
@@ -3401,24 +3401,28 @@
 );%0A%0A        
+ 
+   
 task.setProc
@@ -3453,24 +3453,28 @@
 );%0A%0A        
+    
 task.call();
@@ -3483,16 +3483,20 @@
         
+ 
+   
 Assert.a
@@ -3540,16 +3540,96 @@
 dSUID);%0A
+        %7D finally %7B%0A            new File(%22TestClass.class%22).delete();%0A        %7D%0A
     %7D%0A%7D%0A

Clean up after SUIDGeneratorTest.