/*
 * Copyright (C) 2015 Square, Inc.
 *
 * 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 com.squareup.javapoet;

import static com.google.common.truth.Truth.assertThat;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Locale;
import java.util.concurrent.Callable;

import javax.lang.model.element.Modifier;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.google.common.io.ByteStreams;

@RunWith(JUnit4.class)
public class FileReadingTest {
  
  // Used for storing compilation output.
  @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();

  @Test public void javaFileObjectUri() {
    TypeSpec type = TypeSpec.classBuilder("Test").build();
    assertThat(JavaFile.builder("", type).build().toJavaFileObject().toUri())
        .isEqualTo(URI.create("Test.java"));
    assertThat(JavaFile.builder("foo", type).build().toJavaFileObject().toUri())
        .isEqualTo(URI.create("foo/Test.java"));
    assertThat(JavaFile.builder("com.example", type).build().toJavaFileObject().toUri())
        .isEqualTo(URI.create("com/example/Test.java"));
  }
  
  @Test public void javaFileObjectKind() {
    JavaFile javaFile = JavaFile.builder("", TypeSpec.classBuilder("Test").build()).build();
    assertThat(javaFile.toJavaFileObject().getKind()).isEqualTo(Kind.SOURCE);
  }
  
  @Test public void javaFileObjectCharacterContent() throws IOException {
    TypeSpec type = TypeSpec.classBuilder("Test")
        .addJavadoc("Testing, 1, 2, 3!")
        .addMethod(MethodSpec.methodBuilder("fooBar").build())
        .build();
    JavaFile javaFile = JavaFile.builder("foo", type).build();
    JavaFileObject javaFileObject = javaFile.toJavaFileObject();
    
    // We can never have encoding issues (everything is in process)
    assertThat(javaFileObject.getCharContent(true)).isEqualTo(javaFile.toString());
    assertThat(javaFileObject.getCharContent(false)).isEqualTo(javaFile.toString());
  }
  
  @Test public void javaFileObjectInputStream() throws IOException {
    JavaFile javaFile = JavaFile.builder("foo", TypeSpec.classBuilder("Test").build())
        .addFileComment("\u00A9 Copyright character gets you everytime")
        .build();
    byte[] bytes = ByteStreams.toByteArray(javaFile.toJavaFileObject().openInputStream());
    
    // Be explicit with the default charset to assert the implicit behavior in the code
    assertThat(bytes).isEqualTo(javaFile.toString().getBytes(Charset.defaultCharset()));
  }
  
  @Test public void compileJavaFile() throws Exception {
    final String value = "Hello World!";
    TypeSpec type = TypeSpec.classBuilder("Test")
        .addModifiers(Modifier.PUBLIC)
        .addSuperinterface(ParameterizedTypeName.get(Callable.class, String.class))
        .addMethod(MethodSpec.methodBuilder("call")
            .returns(String.class)
            .addModifiers(Modifier.PUBLIC)
            .addStatement("return $S", value)
            .build())
        .build();
    JavaFile javaFile = JavaFile.builder("foo", type).build();

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, 
        Locale.getDefault(), StandardCharsets.UTF_8);
    File classOutput = temporaryFolder.newFolder();
    fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(classOutput));
    CompilationTask task = compiler.getTask(null, 
        fileManager,
        diagnosticCollector,
        Collections.<String>emptySet(),
        Collections.<String>emptySet(),
        Collections.singleton(javaFile.toJavaFileObject()));
    
    assertThat(task.call()).isTrue();
    assertThat(diagnosticCollector.getDiagnostics()).isEmpty();

    ClassLoader loader = new URLClassLoader(new URL[] { classOutput.toURI().toURL() });
    Callable<?> test = Class.forName("foo.Test", true, loader).asSubclass(Callable.class).newInstance();
    assertThat(Callable.class.getMethod("call").invoke(test)).isEqualTo(value);
  }

}

@@ -632,179 +632,48 @@
 ort 
-static com.google.common.truth.Truth.assertThat;%0A%0Aimport java.io.File;%0Aimport java.io.IOException;%0Aimport java.net.URI;%0Aimport java.net.URL;%0Aimport java.net.URLClassLoader
+java.io.IOException;%0Aimport java.net.URI
 ;%0Aim
@@ -838,17 +838,16 @@
 llable;%0A
-%0A
 import j
@@ -1191,17 +1191,16 @@
 ovider;%0A
-%0A
 import o
@@ -1343,17 +1343,16 @@
 JUnit4;%0A
-%0A
 import c
@@ -1385,16 +1385,73 @@
 reams;%0A%0A
+import static com.google.common.truth.Truth.assertThat;%0A%0A
 @RunWith
@@ -4360,60 +4360,8 @@
 8);%0A
-    File classOutput = temporaryFolder.newFolder();%0A
     
@@ -4414,16 +4414,24 @@
 _OUTPUT,
+%0A       
  Collect
@@ -4445,27 +4445,43 @@
 ngleton(
-classOutput
+temporaryFolder.newFolder()
 ));%0A    
@@ -4855,68 +4855,64 @@
 r = 
-new URLClassLoader(new URL%5B%5D %7B classOutput.toURI().toURL() %7D
+fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT
 );%0A 

Clean up FileReadingTest