/* Copyright 2016 Google 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 io.gapi.vgen;

import com.google.api.tools.framework.model.DiagCollector;
import com.google.api.tools.framework.model.testing.ConfigBaselineTestCase;
import com.google.api.tools.framework.model.testing.SimpleDiag;
import com.google.api.tools.framework.snippet.Doc;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import com.google.protobuf.Message;
import com.google.protobuf.MessageOrBuilder;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Base class for code generator baseline tests.
 */
public abstract class DiscoveryGeneratorTestBase extends ConfigBaselineTestCase {

  private static final Pattern BASELINE_PATTERN = Pattern.compile("(\\w+)\\[(\\w+)\\]");

  // Wiring
  // ======

  private final String name;
  private final String discoveryDocFileName;
  private final String[] veneerConfigFileNames;
  private final String snippetName;
  protected ConfigProto config;
  protected DiscoveryImporter discoveryImporter;

  public DiscoveryGeneratorTestBase(String name, String discoveryDocFileName,
      String[] veneerConfigFileNames, String snippetName) {
    this.name = name;
    this.discoveryDocFileName = discoveryDocFileName;
    this.veneerConfigFileNames = veneerConfigFileNames;
    this.snippetName = snippetName;
  }

  public DiscoveryGeneratorTestBase(String name, String discoveryDocFileName,
      String[] veneerConfigFileNames) {
    this(name, discoveryDocFileName, veneerConfigFileNames, null);
  }

  protected void setupDiscovery() {
    try {
      discoveryImporter = DiscoveryImporter.parse(
          Files.newReader(
              new File(getTestDataLocator().getTestDataAsFile(discoveryDocFileName).toString()),
              Charset.forName("UTF8")));
    } catch (IOException e) {
      throw new IllegalArgumentException("Problem creating Generator", e);
    }

    config = readConfig();
    if (config == null) {
      return;
    }
  }

  @Override
  protected boolean suppressDiagnosis() {
    // Suppress linter warnings
    return true;
  }

  protected void test() throws Exception {
    // Setup
    setupDiscovery();

    // Run test specific logic.
    Object result = run();

    testOutput().println(displayValue(result));
  }

  private String displayValue(Object value) throws IOException {
    if (value instanceof Doc) {
      return ((Doc) value).prettyPrint(100);
    } else if (value instanceof File) {
      return Files.toString((File) value, StandardCharsets.UTF_8);
    } else if (value instanceof MessageOrBuilder) {
      // Convert proto to text format, considering any instances.
      return formatter.printToString((MessageOrBuilder) value);
    } else {
      return value.toString();
    }
  }

  @Override
  protected String baselineFileName() {
    String methodName = testName.getMethodName();
    Matcher m = BASELINE_PATTERN.matcher(methodName);
    if (m.find()) {
      return m.group(2) + "_" + m.group(1) + ".baseline";
    } else {
      return name + "_" + methodName + ".baseline";
    }
  }

  private ConfigProto readConfig() {
    List<String> inputNames = new ArrayList<>();
    List<String> inputs = new ArrayList<>();

    for (String veneerConfigFileName : veneerConfigFileNames) {
      URL veneerConfigUrl = getTestDataLocator().findTestData(veneerConfigFileName);
      String configData = getTestDataLocator().readTestData(veneerConfigUrl);
      inputNames.add(veneerConfigFileName);
      inputs.add(configData);
    }

    ImmutableMap<String, Message> supportedConfigTypes =
        ImmutableMap.<String, Message>of(ConfigProto.getDescriptor().getFullName(),
            ConfigProto.getDefaultInstance());
    // Use DiagCollector to collect errors from config read since user errors may arise here
    DiagCollector diagCollector = new SimpleDiag();
    ConfigProto configProto =
        (ConfigProto) MultiYamlReader.read(diagCollector,
            inputNames, inputs, supportedConfigTypes);
    if (diagCollector.getErrorCount() > 0) {
      System.err.println(diagCollector.toString());
      return null;
    }

    if (snippetName != null) {
      // Filtering can be made more sophisticated later if required
      configProto = configProto.toBuilder()
          .clearSnippetFiles().addSnippetFiles(snippetName)
          .build();
    }

    return configProto;
  }
}

@@ -1071,16 +1071,45 @@
 eption;%0A
+import java.io.StringReader;%0A
 import j
@@ -1835,32 +1835,39 @@
 neratorTestBase(
+%0A      
 String name, Str
@@ -1854,32 +1854,38 @@
     String name,
+%0A     
  String discover
@@ -1935,16 +1935,22 @@
 leNames,
+%0A     
  String 
@@ -2173,16 +2173,23 @@
 estBase(
+%0A      
 String n
@@ -2213,38 +2213,32 @@
 veryDocFileName,
-%0A     
  String%5B%5D veneer
@@ -2399,16 +2399,26 @@
 porter =
+%0A         
  Discove
@@ -2449,17 +2449,22 @@
     
-Files.new
+    new String
 Read
@@ -2485,17 +2485,12 @@
     
+ 
-new File(
+   
 getT
@@ -2509,98 +2509,100 @@
 or()
-.getTestDataAsFile(discoveryDocFileName).toString()),%0A              Charset.forName(%22UTF8%22
+%0A                      .readTestData(getTestDataLocator().findTestData(discoveryDocFileName)
 )));
@@ -4426,16 +4426,29 @@
 sage%3Eof(
+%0A            
 ConfigPr
@@ -4481,28 +4481,16 @@
 lName(),
-%0A           
  ConfigP
@@ -4749,28 +4749,16 @@
 llector,
-%0A           
  inputNa
@@ -5034,16 +5034,26 @@
 gProto =
+%0A         
  configP
@@ -5068,27 +5068,16 @@
 uilder()
-%0A          
 .clearSn
@@ -5117,27 +5117,16 @@
 petName)
-%0A          
 .build()

Stop test from spamming /tmp