// Copyright 2020 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.analysis;

import static org.junit.Assert.assertThrows;

import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * This test ensures that "duplicate generating action" errors in the action
 * graph are correctly detected and reported.
 *
 * <p>Note that conceptually, such errors aren't expressible in the vocabulary of
 * the BUILD language (targets, rules) but only in that of Blaze's action graph
 * (actions, artifacts).  That these errors exist at all is really an
 * implementation restriction of Blaze, and in a perfect world, they wouldn't.
 *
 * <p>While we might be able to catch some of the important cases by checks at the
 * level of the target graph, with sufficiently complex multi-action rules such
 * as cc_library, there are bound to be ways of creating action-graph conflicts
 * even where the target graph is meaningful, hence these checks are required.
 */
@RunWith(JUnit4.class)
public final class GeneratorConflictTest extends AnalysisTestCase {

  @Test
  public void testIntermediateFileConflictsWithAnotherRule() throws Exception {
    scratch.file(
        "conflict/BUILD",
        "cc_library(name='x', srcs=['foo.cc'])",
        "cc_binary(name='_objs/x/foo.o', srcs=['bar.cc'])");

    reporter.removeHandler(failFastHandler); // expect errors

    update("//conflict:x");
    assertNoEvents();
    assertThrows(
        ViewCreationFailedException.class,
        () -> update("//conflict:x", "//conflict:_objs/x/foo.o"));

    assertContainsEvent("file 'conflict/_objs/x/foo.o' is generated by ");
  }

  // Source files don't conflict with bin files.
  // This test exists to clarify the status quo; it's not clear that it asserts
  // ideal behavior.
  @Test
  public void testIntermediateFilesDontConflictWithSources() throws Exception {
    scratch.file("conflict/BUILD", "cc_library(name='x', srcs=['foo.cc', '_objs/x/foo.o'])");

    // No conflict, doesn't fail:
    update("//conflict:x");
    update("//conflict:_objs/x/foo.o");
  }

  // Outputs of a genrule are emitted to genfiles, so there is no conflict with
  // generated artifacts of a cc_library rule.
  // This test exists to clarify the status quo; it's not clear that it asserts
  // ideal behavior.
  @Test
  public void testIntermediateFileDoesntConflictWithGenfiles()
      throws Exception {
    scratch.file(
        "conflict/BUILD",
        "cc_library(name='x', srcs=['foo.cc'])",
        "genrule(name='y', outs=['_objs/x/foo.o'], cmd=':')");

    // No conflict, doesn't fail:
    update("//conflict:x");
    update("//conflict:_objs/x/foo.o");
  }

  @Test
  public void testNoConflictForSameBasename() throws Exception {
    // It should be OK to use source files with the same basename
    // (but different directory names) in the same rule.
    scratch.file("noconflict/BUILD",
                "cc_library(name='lib', srcs=['foo/baz.cc', 'bar/baz.cc'])");
    update("//noconflict:lib");
    assertNoEvents();
  }
}
