/*
 * Copyright 2016 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.idea.blaze.base.lang.buildfile.findusages;

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

import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
import com.google.idea.blaze.base.lang.buildfile.references.LocalReference;
import com.google.idea.blaze.base.lang.buildfile.references.TargetReference;
import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Tests that references to local variables are found by the 'Find Usages' action TODO: Support
 * comprehension suffix, and add test for it
 */
@RunWith(JUnit4.class)
public class LocalVariableUsagesTest extends BuildFileIntegrationTestCase {

  @Test
  public void testLocalReferences() {
    BuildFile buildFile =
        createBuildFile(
            new WorkspacePath("java/com/google/BUILD"),
            "localVar = 5",
            "funcall(localVar)",
            "def function(name):",
            "    tempVar = localVar");

    TargetExpression target =
        buildFile.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();

    PsiReference[] references = FindUsages.findAllReferences(target);
    assertThat(references).hasLength(2);

    FuncallExpression funcall = buildFile.findChildByClass(FuncallExpression.class);
    assertThat(funcall).isNotNull();

    PsiElement firstRef = references[0].getElement();
    assertThat(PsiUtils.getParentOfType(firstRef, FuncallExpression.class, true))
        .isEqualTo(funcall);

    FunctionStatement function = buildFile.findChildByClass(FunctionStatement.class);
    assertThat(function).isNotNull();

    PsiElement secondRef = references[1].getElement();
    assertThat(secondRef.getParent()).isInstanceOf(AssignmentStatement.class);
    assertThat(PsiUtils.getParentOfType(secondRef, FunctionStatement.class, true))
        .isEqualTo(function);
  }

  // the case where a symbol is the target of multiple assignment statements
  @Test
  public void testMultipleAssignments() {
    BuildFile buildFile =
        createBuildFile(
            new WorkspacePath("java/com/google/BUILD"), "var = 5", "var += 1", "var = 0");

    TargetExpression target =
        buildFile.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();

    PsiReference[] references = FindUsages.findAllReferences(target);
    assertThat(references).hasLength(2);

    // We cannot guarantee order of references.
    List<Class<?>> referenceClasses =
        Arrays.stream(references).map(Object::getClass).collect(Collectors.toList());
    assertThat(referenceClasses).containsExactly(TargetReference.class, LocalReference.class);
  }
}

@@ -2046,24 +2046,31 @@
 id testLocal
+Funcall
 References()
@@ -2066,17 +2066,16 @@
 eference
-s
 () %7B%0A   
@@ -2177,28 +2177,16 @@
 BUILD%22),
-%0A           
  %22localV
@@ -2193,28 +2193,16 @@
 ar = 5%22,
-%0A           
  %22funcal
@@ -2217,81 +2217,8 @@
 ar)%22
-,%0A            %22def function(name):%22,%0A            %22    tempVar = localVar%22
 );%0A%0A
@@ -2438,33 +2438,33 @@
 nces).hasLength(
-2
+1
 );%0A%0A    FuncallE
@@ -2589,22 +2589,17 @@
 Element 
-firstR
+r
 ef = ref
@@ -2667,14 +2667,9 @@
 ype(
-firstR
+r
 ef, 
@@ -2695,33 +2695,24 @@
 lass, true))
-%0A        
 .isEqualTo(f
@@ -2717,16 +2717,515 @@
 (funcall
+);%0A  %7D%0A%0A  @Test%0A  public void testLocalNestedReference() %7B%0A    BuildFile buildFile =%0A        createBuildFile(%0A            new WorkspacePath(%22java/com/google/BUILD%22),%0A            %22localVar = 5%22,%0A            %22def function(name):%22,%0A            %22    tempVar = localVar%22);%0A%0A    TargetExpression target =%0A        buildFile.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();%0A%0A    PsiReference%5B%5D references = FindUsages.findAllReferences(target);%0A    assertThat(references).hasLength(1
 );%0A%0A    
@@ -3360,23 +3360,17 @@
 Element 
-secondR
+r
 ef = ref
@@ -3377,17 +3377,17 @@
 erences%5B
-1
+0
 %5D.getEle
@@ -3409,23 +3409,17 @@
 ertThat(
-secondR
+r
 ef.getPa
@@ -3511,15 +3511,9 @@
 ype(
-secondR
+r
 ef, 
@@ -3543,25 +3543,16 @@
 , true))
-%0A        
 .isEqual

Fix a failing test in 2019.3