//===- llvm/unittest/FileCheck/FileCheckTest.cpp - FileCheck tests --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/FileCheck/FileCheck.h"
#include "../lib/FileCheck/FileCheckImpl.h"
#include "llvm/Support/Regex.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <tuple>
#include <unordered_set>

using namespace llvm;

namespace {

class FileCheckTest : public ::testing::Test {};

static StringRef bufferize(SourceMgr &SM, StringRef Str) {
  std::unique_ptr<MemoryBuffer> Buffer =
      MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
  StringRef StrBufferRef = Buffer->getBuffer();
  SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
  return StrBufferRef;
}

static std::string toString(const std::unordered_set<std::string> &Set) {
  bool First = true;
  std::string Str;
  for (StringRef S : Set) {
    Str += Twine(First ? "{" + S : ", " + S).str();
    First = false;
  }
  Str += '}';
  return Str;
}

template <typename ErrorT>
static void expectSameErrors(std::unordered_set<std::string> ExpectedMsgs,
                             Error Err) {
  auto AnyErrorMsgMatch = [&ExpectedMsgs](std::string &&ErrorMsg) -> bool {
    for (auto ExpectedMsgItr = ExpectedMsgs.begin(),
              ExpectedMsgEnd = ExpectedMsgs.end();
         ExpectedMsgItr != ExpectedMsgEnd; ++ExpectedMsgItr) {
      if (ErrorMsg.find(*ExpectedMsgItr) != std::string::npos) {
        ExpectedMsgs.erase(ExpectedMsgItr);
        return true;
      }
    }
    return false;
  };

  Error RemainingErrors = std::move(Err);
  do {
    RemainingErrors =
        handleErrors(std::move(RemainingErrors), [&](const ErrorT &E) {
          EXPECT_TRUE(AnyErrorMsgMatch(E.message()))
              << "Unexpected error message:" << std::endl
              << E.message();
        });
  } while (RemainingErrors && !ExpectedMsgs.empty());
  EXPECT_THAT_ERROR(std::move(RemainingErrors), Succeeded());
  EXPECT_TRUE(ExpectedMsgs.empty())
      << "Error message(s) not found:" << std::endl
      << toString(ExpectedMsgs);
}

template <typename ErrorT>
static void expectError(StringRef ExpectedMsg, Error Err) {
  expectSameErrors<ErrorT>({ExpectedMsg.str()}, std::move(Err));
}

static void expectDiagnosticError(StringRef ExpectedMsg, Error Err) {
  expectError<ErrorDiagnostic>(ExpectedMsg, std::move(Err));
}

constexpr uint64_t MaxUint64 = std::numeric_limits<uint64_t>::max();
constexpr int64_t MaxInt64 = std::numeric_limits<int64_t>::max();
constexpr int64_t MinInt64 = std::numeric_limits<int64_t>::min();
constexpr uint64_t AbsoluteMinInt64 =
    static_cast<uint64_t>(-(MinInt64 + 1)) + 1;
constexpr uint64_t AbsoluteMaxInt64 = static_cast<uint64_t>(MaxInt64);

struct ExpressionFormatParameterisedFixture
    : public ::testing::TestWithParam<
          std::pair<ExpressionFormat::Kind, unsigned>> {
  unsigned Precision;
  bool Signed;
  bool AllowHex;
  bool AllowUpperHex;
  ExpressionFormat Format;
  Regex WildcardRegex;

  StringRef TenStr;
  StringRef FifteenStr;
  std::string MaxUint64Str;
  std::string MaxInt64Str;
  std::string MinInt64Str;
  StringRef FirstInvalidCharDigits;
  StringRef AcceptedHexOnlyDigits;
  StringRef RefusedHexOnlyDigits;

  SourceMgr SM;

  void SetUp() override {
    ExpressionFormat::Kind Kind;
    std::tie(Kind, Precision) = GetParam();
    AllowHex = Kind == ExpressionFormat::Kind::HexLower ||
               Kind == ExpressionFormat::Kind::HexUpper;
    AllowUpperHex = Kind == ExpressionFormat::Kind::HexUpper;
    Signed = Kind == ExpressionFormat::Kind::Signed;
    Format = ExpressionFormat(Kind, Precision);

    if (!AllowHex) {
      MaxUint64Str = std::to_string(MaxUint64);
      MaxInt64Str = std::to_string(MaxInt64);
      MinInt64Str = std::to_string(MinInt64);
      TenStr = "10";
      FifteenStr = "15";
      FirstInvalidCharDigits = "aA";
      AcceptedHexOnlyDigits = RefusedHexOnlyDigits = "N/A";
      return;
    }

    MaxUint64Str = AllowUpperHex ? "FFFFFFFFFFFFFFFF" : "ffffffffffffffff";
    MaxInt64Str = AllowUpperHex ? "7FFFFFFFFFFFFFFF" : "7fffffffffffffff";
    TenStr = AllowUpperHex ? "A" : "a";
    FifteenStr = AllowUpperHex ? "F" : "f";
    AcceptedHexOnlyDigits = AllowUpperHex ? "ABCDEF" : "abcdef";
    RefusedHexOnlyDigits = AllowUpperHex ? "abcdef" : "ABCDEF";
    MinInt64Str = "N/A";
    FirstInvalidCharDigits = "gG";
  }

  void checkWildcardRegexMatch(StringRef Input,
                               unsigned TrailExtendTo = 0) const {
    SmallVector<StringRef, 4> Matches;
    std::string ExtendedInput = Input.str();
    if (TrailExtendTo > Input.size()) {
      ExtendedInput.append(TrailExtendTo - Input.size(), Input[0]);
    }
    ASSERT_TRUE(WildcardRegex.match(ExtendedInput, &Matches))
        << "Wildcard regex does not match " << ExtendedInput;
    EXPECT_EQ(Matches[0], ExtendedInput);
  }

  void checkWildcardRegexMatchFailure(StringRef Input) const {
    EXPECT_FALSE(WildcardRegex.match(Input));
  }

  void checkWildcardRegexCharMatchFailure(StringRef Chars) const {
    for (auto C : Chars)
      EXPECT_FALSE(WildcardRegex.match(StringRef(&C, 1)));
  }

  std::string padWithLeadingZeros(StringRef NumStr) const {
    bool Negative = NumStr.startswith("-");
    if (NumStr.size() - unsigned(Negative) >= Precision)
      return NumStr.str();

    std::string PaddedStr;
    if (Negative) {
      PaddedStr = "-";
      NumStr = NumStr.drop_front();
    }
    PaddedStr.append(Precision - NumStr.size(), '0');
    PaddedStr.append(NumStr.str());
    return PaddedStr;
  }

  template <class T> void checkMatchingString(T Val, StringRef ExpectedStr) {
    Expected<std::string> MatchingString =
        Format.getMatchingString(ExpressionValue(Val));
    ASSERT_THAT_EXPECTED(MatchingString, Succeeded())
        << "No matching string for " << Val;
    EXPECT_EQ(*MatchingString, ExpectedStr);
  }

  template <class T> void checkMatchingStringFailure(T Val) {
    Expected<std::string> MatchingString =
        Format.getMatchingString(ExpressionValue(Val));
    // Error message tested in ExpressionValue unit tests.
    EXPECT_THAT_EXPECTED(MatchingString, Failed());
  }

  Expected<ExpressionValue> getValueFromStringReprFailure(StringRef Str) {
    StringRef BufferizedStr = bufferize(SM, Str);
    return Format.valueFromStringRepr(BufferizedStr, SM);
  }

  template <class T>
  void checkValueFromStringRepr(StringRef Str, T ExpectedVal) {
    Expected<ExpressionValue> ResultValue = getValueFromStringReprFailure(Str);
    ASSERT_THAT_EXPECTED(ResultValue, Succeeded())
        << "Failed to get value from " << Str;
    ASSERT_EQ(ResultValue->isNegative(), ExpectedVal < 0)
        << "Value for " << Str << " is not " << ExpectedVal;
    if (ResultValue->isNegative())
      EXPECT_EQ(cantFail(ResultValue->getSignedValue()),
                static_cast<int64_t>(ExpectedVal));
    else
      EXPECT_EQ(cantFail(ResultValue->getUnsignedValue()),
                static_cast<uint64_t>(ExpectedVal));
  }

  void checkValueFromStringReprFailure(StringRef Str) {
    StringRef OverflowErrorStr = "unable to represent numeric value";
    Expected<ExpressionValue> ResultValue = getValueFromStringReprFailure(Str);
    expectDiagnosticError(OverflowErrorStr, ResultValue.takeError());
  }
};

TEST_P(ExpressionFormatParameterisedFixture, FormatGetWildcardRegex) {
  // Wildcard regex is valid.
  Expected<std::string> WildcardPattern = Format.getWildcardRegex();
  ASSERT_THAT_EXPECTED(WildcardPattern, Succeeded());
  WildcardRegex = Regex((Twine("^") + *WildcardPattern + "$").str());
  ASSERT_TRUE(WildcardRegex.isValid());

  // Does not match empty string.
  checkWildcardRegexMatchFailure("");

  // Matches all decimal digits and matches several of them.
  StringRef LongNumber = "12345678901234567890";
  checkWildcardRegexMatch(LongNumber);

  // Matches negative digits.
  LongNumber = "-12345678901234567890";
  if (Signed)
    checkWildcardRegexMatch(LongNumber);
  else
    checkWildcardRegexMatchFailure(LongNumber);

  // Check non digits or digits with wrong casing are not matched.
  if (AllowHex) {
    checkWildcardRegexMatch(AcceptedHexOnlyDigits, 16);
    checkWildcardRegexCharMatchFailure(RefusedHexOnlyDigits);
  }
  checkWildcardRegexCharMatchFailure(FirstInvalidCharDigits);

  // Check leading zeros are only accepted if number of digits is less than the
  // precision.
  LongNumber = "01234567890123456789";
  if (Precision) {
    checkWildcardRegexMatch(LongNumber.take_front(Precision));
    checkWildcardRegexMatchFailure(LongNumber.take_front(Precision - 1));
    if (Precision < LongNumber.size())
      checkWildcardRegexMatchFailure(LongNumber.take_front(Precision + 1));
  } else
    checkWildcardRegexMatch(LongNumber);
}

TEST_P(ExpressionFormatParameterisedFixture, FormatGetMatchingString) {
  checkMatchingString(0, padWithLeadingZeros("0"));
  checkMatchingString(9, padWithLeadingZeros("9"));

  if (Signed) {
    checkMatchingString(-5, padWithLeadingZeros("-5"));
    checkMatchingStringFailure(MaxUint64);
    checkMatchingString(MaxInt64, padWithLeadingZeros(MaxInt64Str));
    checkMatchingString(MinInt64, padWithLeadingZeros(MinInt64Str));
  } else {
    checkMatchingStringFailure(-5);
    checkMatchingString(MaxUint64, padWithLeadingZeros(MaxUint64Str));
    checkMatchingString(MaxInt64, padWithLeadingZeros(MaxInt64Str));
    checkMatchingStringFailure(MinInt64);
  }

  checkMatchingString(10, padWithLeadingZeros(TenStr));
  checkMatchingString(15, padWithLeadingZeros(FifteenStr));
}

TEST_P(ExpressionFormatParameterisedFixture, FormatValueFromStringRepr) {
  checkValueFromStringRepr("0", 0);
  checkValueFromStringRepr("9", 9);

  if (Signed) {
    checkValueFromStringRepr("-5", -5);
    checkValueFromStringReprFailure(MaxUint64Str);
  } else {
    checkValueFromStringReprFailure("-5");
    checkValueFromStringRepr(MaxUint64Str, MaxUint64);
  }

  checkValueFromStringRepr(TenStr, 10);
  checkValueFromStringRepr(FifteenStr, 15);

  // Wrong casing is not tested because valueFromStringRepr() relies on
  // StringRef's getAsInteger() which does not allow to restrict casing.
  checkValueFromStringReprFailure("G");
}

TEST_P(ExpressionFormatParameterisedFixture, FormatBoolOperator) {
  EXPECT_TRUE(bool(Format));
}

INSTANTIATE_TEST_CASE_P(
    AllowedExplicitExpressionFormat, ExpressionFormatParameterisedFixture,
    ::testing::Values(std::make_pair(ExpressionFormat::Kind::Unsigned, 0),
                      std::make_pair(ExpressionFormat::Kind::Signed, 0),
                      std::make_pair(ExpressionFormat::Kind::HexLower, 0),
                      std::make_pair(ExpressionFormat::Kind::HexUpper, 0),

                      std::make_pair(ExpressionFormat::Kind::Unsigned, 1),
                      std::make_pair(ExpressionFormat::Kind::Signed, 1),
                      std::make_pair(ExpressionFormat::Kind::HexLower, 1),
                      std::make_pair(ExpressionFormat::Kind::HexUpper, 1),

                      std::make_pair(ExpressionFormat::Kind::Unsigned, 16),
                      std::make_pair(ExpressionFormat::Kind::Signed, 16),
                      std::make_pair(ExpressionFormat::Kind::HexLower, 16),
                      std::make_pair(ExpressionFormat::Kind::HexUpper, 16),

                      std::make_pair(ExpressionFormat::Kind::Unsigned, 20),
                      std::make_pair(ExpressionFormat::Kind::Signed, 20)), );

TEST_F(FileCheckTest, NoFormatProperties) {
  ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
  expectError<StringError>("trying to match value with invalid format",
                           NoFormat.getWildcardRegex().takeError());
  expectError<StringError>(
      "trying to match value with invalid format",
      NoFormat.getMatchingString(ExpressionValue(18u)).takeError());
  EXPECT_FALSE(bool(NoFormat));
}

TEST_F(FileCheckTest, FormatEqualityOperators) {
  ExpressionFormat UnsignedFormat(ExpressionFormat::Kind::Unsigned);
  ExpressionFormat UnsignedFormat2(ExpressionFormat::Kind::Unsigned);
  EXPECT_TRUE(UnsignedFormat == UnsignedFormat2);
  EXPECT_FALSE(UnsignedFormat != UnsignedFormat2);

  ExpressionFormat HexLowerFormat(ExpressionFormat::Kind::HexLower);
  EXPECT_FALSE(UnsignedFormat == HexLowerFormat);
  EXPECT_TRUE(UnsignedFormat != HexLowerFormat);

  ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
  ExpressionFormat NoFormat2(ExpressionFormat::Kind::NoFormat);
  EXPECT_FALSE(NoFormat == NoFormat2);
  EXPECT_TRUE(NoFormat != NoFormat2);
}

TEST_F(FileCheckTest, FormatKindEqualityOperators) {
  ExpressionFormat UnsignedFormat(ExpressionFormat::Kind::Unsigned);
  EXPECT_TRUE(UnsignedFormat == ExpressionFormat::Kind::Unsigned);
  EXPECT_FALSE(UnsignedFormat != ExpressionFormat::Kind::Unsigned);
  EXPECT_FALSE(UnsignedFormat == ExpressionFormat::Kind::HexLower);
  EXPECT_TRUE(UnsignedFormat != ExpressionFormat::Kind::HexLower);
  ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
  EXPECT_TRUE(NoFormat == ExpressionFormat::Kind::NoFormat);
  EXPECT_FALSE(NoFormat != ExpressionFormat::Kind::NoFormat);
}

template <class T1, class T2>
static Expected<ExpressionValue> doValueOperation(binop_eval_t Operation,
                                                  T1 LeftValue, T2 RightValue) {
  ExpressionValue LeftOperand(LeftValue);
  ExpressionValue RightOperand(RightValue);
  return Operation(LeftOperand, RightOperand);
}

template <class T>
static void expectValueEqual(ExpressionValue ActualValue, T ExpectedValue) {
  EXPECT_EQ(ExpectedValue < 0, ActualValue.isNegative());
  if (ExpectedValue < 0) {
    Expected<int64_t> SignedActualValue = ActualValue.getSignedValue();
    ASSERT_THAT_EXPECTED(SignedActualValue, Succeeded());
    EXPECT_EQ(*SignedActualValue, static_cast<int64_t>(ExpectedValue));
  } else {
    Expected<uint64_t> UnsignedActualValue = ActualValue.getUnsignedValue();
    ASSERT_THAT_EXPECTED(UnsignedActualValue, Succeeded());
    EXPECT_EQ(*UnsignedActualValue, static_cast<uint64_t>(ExpectedValue));
  }
}

template <class T1, class T2, class TR>
static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
                                       T2 RightValue, TR ResultValue) {
  Expected<ExpressionValue> OperationResult =
      doValueOperation(Operation, LeftValue, RightValue);
  ASSERT_THAT_EXPECTED(OperationResult, Succeeded());
  expectValueEqual(*OperationResult, ResultValue);
}

template <class T1, class T2>
static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
                                       T2 RightValue) {
  expectError<OverflowError>(
      "overflow error",
      doValueOperation(Operation, LeftValue, RightValue).takeError());
}

TEST_F(FileCheckTest, ExpressionValueGetUnsigned) {
  // Test positive value.
  Expected<uint64_t> UnsignedValue = ExpressionValue(10).getUnsignedValue();
  ASSERT_THAT_EXPECTED(UnsignedValue, Succeeded());
  EXPECT_EQ(*UnsignedValue, 10U);

  // Test 0.
  UnsignedValue = ExpressionValue(0).getUnsignedValue();
  ASSERT_THAT_EXPECTED(UnsignedValue, Succeeded());
  EXPECT_EQ(*UnsignedValue, 0U);

  // Test max positive value.
  UnsignedValue = ExpressionValue(MaxUint64).getUnsignedValue();
  ASSERT_THAT_EXPECTED(UnsignedValue, Succeeded());
  EXPECT_EQ(*UnsignedValue, MaxUint64);

  // Test failure with negative value.
  expectError<OverflowError>(
      "overflow error", ExpressionValue(-1).getUnsignedValue().takeError());

  // Test failure with min negative value.
  expectError<OverflowError>(
      "overflow error",
      ExpressionValue(MinInt64).getUnsignedValue().takeError());
}

TEST_F(FileCheckTest, ExpressionValueGetSigned) {
  // Test positive value.
  Expected<int64_t> SignedValue = ExpressionValue(10).getSignedValue();
  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
  EXPECT_EQ(*SignedValue, 10);

  // Test 0.
  SignedValue = ExpressionValue(0).getSignedValue();
  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
  EXPECT_EQ(*SignedValue, 0);

  // Test max int64_t.
  SignedValue = ExpressionValue(MaxInt64).getSignedValue();
  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
  EXPECT_EQ(*SignedValue, MaxInt64);

  // Test failure with too big positive value.
  expectError<OverflowError>(
      "overflow error", ExpressionValue(static_cast<uint64_t>(MaxInt64) + 1)
                            .getSignedValue()
                            .takeError());

  // Test failure with max uint64_t.
  expectError<OverflowError>(
      "overflow error",
      ExpressionValue(MaxUint64).getSignedValue().takeError());

  // Test negative value.
  SignedValue = ExpressionValue(-10).getSignedValue();
  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
  EXPECT_EQ(*SignedValue, -10);

  // Test min int64_t.
  SignedValue = ExpressionValue(MinInt64).getSignedValue();
  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
  EXPECT_EQ(*SignedValue, MinInt64);
}

TEST_F(FileCheckTest, ExpressionValueAbsolute) {
  // Test positive value.
  expectValueEqual(ExpressionValue(10).getAbsolute(), 10);

  // Test 0.
  expectValueEqual(ExpressionValue(0).getAbsolute(), 0);

  // Test max uint64_t.
  expectValueEqual(ExpressionValue(MaxUint64).getAbsolute(), MaxUint64);

  // Test negative value.
  expectValueEqual(ExpressionValue(-10).getAbsolute(), 10);

  // Test absence of overflow on min int64_t.
  expectValueEqual(ExpressionValue(MinInt64).getAbsolute(),
                   static_cast<uint64_t>(-(MinInt64 + 10)) + 10);
}

TEST_F(FileCheckTest, ExpressionValueAddition) {
  // Test both negative values.
  expectOperationValueResult(operator+, -10, -10, -20);

  // Test both negative values with underflow.
  expectOperationValueResult(operator+, MinInt64, -1);
  expectOperationValueResult(operator+, MinInt64, MinInt64);

  // Test negative and positive value.
  expectOperationValueResult(operator+, -10, 10, 0);
  expectOperationValueResult(operator+, -10, 11, 1);
  expectOperationValueResult(operator+, -11, 10, -1);

  // Test positive and negative value.
  expectOperationValueResult(operator+, 10, -10, 0);
  expectOperationValueResult(operator+, 10, -11, -1);
  expectOperationValueResult(operator+, 11, -10, 1);

  // Test both positive values.
  expectOperationValueResult(operator+, 10, 10, 20);

  // Test both positive values with overflow.
  expectOperationValueResult(operator+, MaxUint64, 1);
  expectOperationValueResult(operator+, MaxUint64, MaxUint64);
}

TEST_F(FileCheckTest, ExpressionValueSubtraction) {
  // Test negative value and value bigger than int64_t max.
  expectOperationValueResult(operator-, -10, MaxUint64);

  // Test negative and positive value with underflow.
  expectOperationValueResult(operator-, MinInt64, 1);

  // Test negative and positive value.
  expectOperationValueResult(operator-, -10, 10, -20);

  // Test both negative values.
  expectOperationValueResult(operator-, -10, -10, 0);
  expectOperationValueResult(operator-, -11, -10, -1);
  expectOperationValueResult(operator-, -10, -11, 1);

  // Test positive and negative values.
  expectOperationValueResult(operator-, 10, -10, 20);

  // Test both positive values with result positive.
  expectOperationValueResult(operator-, 10, 5, 5);

  // Test both positive values with underflow.
  expectOperationValueResult(operator-, 0, MaxUint64);
  expectOperationValueResult(operator-, 0,
                             static_cast<uint64_t>(-(MinInt64 + 10)) + 11);

  // Test both positive values with result < -(max int64_t)
  expectOperationValueResult(operator-, 10,
                             static_cast<uint64_t>(MaxInt64) + 11,
                             -MaxInt64 - 1);

  // Test both positive values with 0 > result > -(max int64_t)
  expectOperationValueResult(operator-, 10, 11, -1);
}

TEST_F(FileCheckTest, ExpressionValueMultiplication) {
  // Test mixed signed values.
  expectOperationValueResult(operator*, -3, 10, -30);
  expectOperationValueResult(operator*, 2, -17, -34);
  expectOperationValueResult(operator*, 0, MinInt64, 0);
  expectOperationValueResult(operator*, MinInt64, 1, MinInt64);
  expectOperationValueResult(operator*, 1, MinInt64, MinInt64);
  expectOperationValueResult(operator*, MaxInt64, -1, -MaxInt64);
  expectOperationValueResult(operator*, -1, MaxInt64, -MaxInt64);

  // Test both negative values.
  expectOperationValueResult(operator*, -3, -10, 30);
  expectOperationValueResult(operator*, -2, -17, 34);
  expectOperationValueResult(operator*, MinInt64, -1, AbsoluteMinInt64);

  // Test both positive values.
  expectOperationValueResult(operator*, 3, 10, 30);
  expectOperationValueResult(operator*, 2, 17, 34);
  expectOperationValueResult(operator*, 0, MaxUint64, 0);

  // Test negative results that underflow.
  expectOperationValueResult(operator*, -10, MaxInt64);
  expectOperationValueResult(operator*, MaxInt64, -10);
  expectOperationValueResult(operator*, 10, MinInt64);
  expectOperationValueResult(operator*, MinInt64, 10);
  expectOperationValueResult(operator*, -1, MaxUint64);
  expectOperationValueResult(operator*, MaxUint64, -1);
  expectOperationValueResult(operator*, -1, AbsoluteMaxInt64 + 2);
  expectOperationValueResult(operator*, AbsoluteMaxInt64 + 2, -1);

  // Test positive results that overflow.
  expectOperationValueResult(operator*, 10, MaxUint64);
  expectOperationValueResult(operator*, MaxUint64, 10);
  expectOperationValueResult(operator*, MinInt64, -10);
  expectOperationValueResult(operator*, -10, MinInt64);
}

TEST_F(FileCheckTest, ExpressionValueDivision) {
  // Test mixed signed values.
  expectOperationValueResult(operator/, -30, 10, -3);
  expectOperationValueResult(operator/, 34, -17, -2);
  expectOperationValueResult(operator/, 0, -10, 0);
  expectOperationValueResult(operator/, MinInt64, 1, MinInt64);
  expectOperationValueResult(operator/, MaxInt64, -1, -MaxInt64);
  expectOperationValueResult(operator/, -MaxInt64, 1, -MaxInt64);

  // Test both negative values.
  expectOperationValueResult(operator/, -30, -10, 3);
  expectOperationValueResult(operator/, -34, -17, 2);

  // Test both positive values.
  expectOperationValueResult(operator/, 30, 10, 3);
  expectOperationValueResult(operator/, 34, 17, 2);
  expectOperationValueResult(operator/, 0, 10, 0);

  // Test divide by zero.
  expectOperationValueResult(operator/, -10, 0);
  expectOperationValueResult(operator/, 10, 0);
  expectOperationValueResult(operator/, 0, 0);

  // Test negative result that underflows.
  expectOperationValueResult(operator/, MaxUint64, -1);
  expectOperationValueResult(operator/, AbsoluteMaxInt64 + 2, -1);
}

TEST_F(FileCheckTest, ExpressionValueEquality) {
  // Test negative and positive value.
  EXPECT_FALSE(ExpressionValue(5) == ExpressionValue(-3));
  EXPECT_TRUE(ExpressionValue(5) != ExpressionValue(-3));
  EXPECT_FALSE(ExpressionValue(-2) == ExpressionValue(6));
  EXPECT_TRUE(ExpressionValue(-2) != ExpressionValue(6));
  EXPECT_FALSE(ExpressionValue(-7) == ExpressionValue(7));
  EXPECT_TRUE(ExpressionValue(-7) != ExpressionValue(7));
  EXPECT_FALSE(ExpressionValue(4) == ExpressionValue(-4));
  EXPECT_TRUE(ExpressionValue(4) != ExpressionValue(-4));
  EXPECT_FALSE(ExpressionValue(MaxUint64) == ExpressionValue(-1));
  EXPECT_TRUE(ExpressionValue(MaxUint64) != ExpressionValue(-1));

  // Test both negative values.
  EXPECT_FALSE(ExpressionValue(-2) == ExpressionValue(-7));
  EXPECT_TRUE(ExpressionValue(-2) != ExpressionValue(-7));
  EXPECT_TRUE(ExpressionValue(-3) == ExpressionValue(-3));
  EXPECT_FALSE(ExpressionValue(-3) != ExpressionValue(-3));
  EXPECT_FALSE(ExpressionValue(MinInt64) == ExpressionValue(-1));
  EXPECT_TRUE(ExpressionValue(MinInt64) != ExpressionValue(-1));
  EXPECT_FALSE(ExpressionValue(MinInt64) == ExpressionValue(-0));
  EXPECT_TRUE(ExpressionValue(MinInt64) != ExpressionValue(-0));

  // Test both positive values.
  EXPECT_FALSE(ExpressionValue(8) == ExpressionValue(9));
  EXPECT_TRUE(ExpressionValue(8) != ExpressionValue(9));
  EXPECT_TRUE(ExpressionValue(1) == ExpressionValue(1));
  EXPECT_FALSE(ExpressionValue(1) != ExpressionValue(1));

  // Check the signedness of zero doesn't affect equality.
  EXPECT_TRUE(ExpressionValue(0) == ExpressionValue(0));
  EXPECT_FALSE(ExpressionValue(0) != ExpressionValue(0));
  EXPECT_TRUE(ExpressionValue(0) == ExpressionValue(-0));
  EXPECT_FALSE(ExpressionValue(0) != ExpressionValue(-0));
  EXPECT_TRUE(ExpressionValue(-0) == ExpressionValue(0));
  EXPECT_FALSE(ExpressionValue(-0) != ExpressionValue(0));
  EXPECT_TRUE(ExpressionValue(-0) == ExpressionValue(-0));
  EXPECT_FALSE(ExpressionValue(-0) != ExpressionValue(-0));
}

TEST_F(FileCheckTest, Literal) {
  SourceMgr SM;

  // Eval returns the literal's value.
  ExpressionLiteral Ten(bufferize(SM, "10"), 10u);
  Expected<ExpressionValue> Value = Ten.eval();
  ASSERT_THAT_EXPECTED(Value, Succeeded());
  EXPECT_EQ(10, cantFail(Value->getSignedValue()));
  Expected<ExpressionFormat> ImplicitFormat = Ten.getImplicitFormat(SM);
  ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
  EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::NoFormat);

  // Min value can be correctly represented.
  ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)), MinInt64);
  Value = Min.eval();
  ASSERT_TRUE(bool(Value));
  EXPECT_EQ(MinInt64, cantFail(Value->getSignedValue()));

  // Max value can be correctly represented.
  ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)), MaxUint64);
  Value = Max.eval();
  ASSERT_THAT_EXPECTED(Value, Succeeded());
  EXPECT_EQ(MaxUint64, cantFail(Value->getUnsignedValue()));
}

TEST_F(FileCheckTest, Expression) {
  SourceMgr SM;

  std::unique_ptr<ExpressionLiteral> Ten =
      std::make_unique<ExpressionLiteral>(bufferize(SM, "10"), 10u);
  ExpressionLiteral *TenPtr = Ten.get();
  Expression Expr(std::move(Ten),
                  ExpressionFormat(ExpressionFormat::Kind::HexLower));
  EXPECT_EQ(Expr.getAST(), TenPtr);
  EXPECT_EQ(Expr.getFormat(), ExpressionFormat::Kind::HexLower);
}

static void
expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,
                  Error Err) {
  EXPECT_THAT_ERROR(handleErrors(std::move(Err),
                                 [&](const UndefVarError &E) {
                                   EXPECT_EQ(ExpectedUndefVarNames.erase(
                                                 std::string(E.getVarName())),
                                             1U);
                                 }),
                    Succeeded());
  EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
}

TEST_F(FileCheckTest, NumericVariable) {
  SourceMgr SM;

  // Undefined variable: getValue and eval fail, error returned by eval holds
  // the name of the undefined variable.
  NumericVariable FooVar("FOO",
                         ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1);
  EXPECT_EQ("FOO", FooVar.getName());
  EXPECT_EQ(FooVar.getImplicitFormat(), ExpressionFormat::Kind::Unsigned);
  NumericVariableUse FooVarUse("FOO", &FooVar);
  Expected<ExpressionFormat> ImplicitFormat = FooVarUse.getImplicitFormat(SM);
  ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
  EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
  EXPECT_FALSE(FooVar.getValue());
  Expected<ExpressionValue> EvalResult = FooVarUse.eval();
  expectUndefErrors({"FOO"}, EvalResult.takeError());

  // Defined variable without string: only getValue and eval return value set.
  FooVar.setValue(ExpressionValue(42u));
  Optional<ExpressionValue> Value = FooVar.getValue();
  ASSERT_TRUE(Value);
  EXPECT_EQ(42, cantFail(Value->getSignedValue()));
  EXPECT_FALSE(FooVar.getStringValue());
  EvalResult = FooVarUse.eval();
  ASSERT_THAT_EXPECTED(EvalResult, Succeeded());
  EXPECT_EQ(42, cantFail(EvalResult->getSignedValue()));

  // Defined variable with string: getValue, eval, and getStringValue return
  // value set.
  StringRef StringValue = "925";
  FooVar.setValue(ExpressionValue(925u), StringValue);
  Value = FooVar.getValue();
  ASSERT_TRUE(Value);
  EXPECT_EQ(925, cantFail(Value->getSignedValue()));
  // getStringValue should return the same memory not just the same characters.
  EXPECT_EQ(StringValue.begin(), FooVar.getStringValue().getValue().begin());
  EXPECT_EQ(StringValue.end(), FooVar.getStringValue().getValue().end());
  EvalResult = FooVarUse.eval();
  ASSERT_THAT_EXPECTED(EvalResult, Succeeded());
  EXPECT_EQ(925, cantFail(EvalResult->getSignedValue()));
  EXPECT_EQ(925, cantFail(EvalResult->getSignedValue()));

  // Clearing variable: getValue and eval fail. Error returned by eval holds
  // the name of the cleared variable.
  FooVar.clearValue();
  EXPECT_FALSE(FooVar.getValue());
  EXPECT_FALSE(FooVar.getStringValue());
  EvalResult = FooVarUse.eval();
  expectUndefErrors({"FOO"}, EvalResult.takeError());
}

TEST_F(FileCheckTest, Binop) {
  SourceMgr SM;

  StringRef ExprStr = bufferize(SM, "FOO+BAR");
  StringRef FooStr = ExprStr.take_front(3);
  NumericVariable FooVar(FooStr,
                         ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1);
  FooVar.setValue(ExpressionValue(42u));
  std::unique_ptr<NumericVariableUse> FooVarUse =
      std::make_unique<NumericVariableUse>(FooStr, &FooVar);
  StringRef BarStr = ExprStr.take_back(3);
  NumericVariable BarVar(BarStr,
                         ExpressionFormat(ExpressionFormat::Kind::Unsigned), 2);
  BarVar.setValue(ExpressionValue(18u));
  std::unique_ptr<NumericVariableUse> BarVarUse =
      std::make_unique<NumericVariableUse>(BarStr, &BarVar);
  binop_eval_t doAdd = operator+;
  BinaryOperation Binop(ExprStr, doAdd, std::move(FooVarUse),
                        std::move(BarVarUse));

  // Defined variables: eval returns right value; implicit format is as
  // expected.
  Expected<ExpressionValue> Value = Binop.eval();
  ASSERT_THAT_EXPECTED(Value, Succeeded());
  EXPECT_EQ(60, cantFail(Value->getSignedValue()));
  Expected<ExpressionFormat> ImplicitFormat = Binop.getImplicitFormat(SM);
  ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
  EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);

  // 1 undefined variable: eval fails, error contains name of undefined
  // variable.
  FooVar.clearValue();
  Value = Binop.eval();
  expectUndefErrors({"FOO"}, Value.takeError());

  // 2 undefined variables: eval fails, error contains names of all undefined
  // variables.
  BarVar.clearValue();
  Value = Binop.eval();
  expectUndefErrors({"FOO", "BAR"}, Value.takeError());

  // Literal + Variable has format of variable.
  ExprStr = bufferize(SM, "FOO+18");
  FooStr = ExprStr.take_front(3);
  StringRef EighteenStr = ExprStr.take_back(2);
  FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
  std::unique_ptr<ExpressionLiteral> Eighteen =
      std::make_unique<ExpressionLiteral>(EighteenStr, 18u);
  Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse),
                          std::move(Eighteen));
  ImplicitFormat = Binop.getImplicitFormat(SM);
  ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
  EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
  ExprStr = bufferize(SM, "18+FOO");
  FooStr = ExprStr.take_back(3);
  EighteenStr = ExprStr.take_front(2);
  FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
  Eighteen = std::make_unique<ExpressionLiteral>(EighteenStr, 18u);
  Binop = BinaryOperation(ExprStr, doAdd, std::move(Eighteen),
                          std::move(FooVarUse));
  ImplicitFormat = Binop.getImplicitFormat(SM);
  ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
  EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);

  // Variables with different implicit format conflict.
  ExprStr = bufferize(SM, "FOO+BAZ");
  FooStr = ExprStr.take_front(3);
  StringRef BazStr = ExprStr.take_back(3);
  NumericVariable BazVar(BazStr,
                         ExpressionFormat(ExpressionFormat::Kind::HexLower), 3);
  FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
  std::unique_ptr<NumericVariableUse> BazVarUse =
      std::make_unique<NumericVariableUse>(BazStr, &BazVar);
  Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse),
                          std::move(BazVarUse));
  ImplicitFormat = Binop.getImplicitFormat(SM);
  expectDiagnosticError(
      "implicit format conflict between 'FOO' (%u) and 'BAZ' (%x), "
      "need an explicit format specifier",
      ImplicitFormat.takeError());

  // All variable conflicts are reported.
  ExprStr = bufferize(SM, "(FOO+BAZ)+(FOO+QUUX)");
  StringRef Paren1ExprStr = ExprStr.substr(1, 7);
  FooStr = Paren1ExprStr.take_front(3);
  BazStr = Paren1ExprStr.take_back(3);
  StringRef Paren2ExprStr = ExprStr.substr(ExprStr.rfind('(') + 1, 8);
  StringRef FooStr2 = Paren2ExprStr.take_front(3);
  StringRef QuuxStr = Paren2ExprStr.take_back(4);
  FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
  BazVarUse = std::make_unique<NumericVariableUse>(BazStr, &BazVar);
  std::unique_ptr<NumericVariableUse> FooVarUse2 =
      std::make_unique<NumericVariableUse>(FooStr2, &FooVar);
  NumericVariable QuuxVar(
      QuuxStr, ExpressionFormat(ExpressionFormat::Kind::HexLower), 4);
  std::unique_ptr<NumericVariableUse> QuuxVarUse =
      std::make_unique<NumericVariableUse>(QuuxStr, &QuuxVar);
  std::unique_ptr<BinaryOperation> Binop1 = std::make_unique<BinaryOperation>(
      ExprStr.take_front(9), doAdd, std::move(FooVarUse), std::move(BazVarUse));
  std::unique_ptr<BinaryOperation> Binop2 = std::make_unique<BinaryOperation>(
      ExprStr.take_back(10), doAdd, std::move(FooVarUse2),
      std::move(QuuxVarUse));
  std::unique_ptr<BinaryOperation> OuterBinop =
      std::make_unique<BinaryOperation>(ExprStr, doAdd, std::move(Binop1),
                                        std::move(Binop2));
  ImplicitFormat = OuterBinop->getImplicitFormat(SM);
  expectSameErrors<ErrorDiagnostic>(
      {("implicit format conflict between 'FOO' (%u) and 'BAZ' (%x), need an "
       "explicit format specifier"),
       ("implicit format conflict between 'FOO' (%u) and 'QUUX' (%x), need an "
       "explicit format specifier")},
      ImplicitFormat.takeError());
}

TEST_F(FileCheckTest, ValidVarNameStart) {
  EXPECT_TRUE(Pattern::isValidVarNameStart('a'));
  EXPECT_TRUE(Pattern::isValidVarNameStart('G'));
  EXPECT_TRUE(Pattern::isValidVarNameStart('_'));
  EXPECT_FALSE(Pattern::isValidVarNameStart('2'));
  EXPECT_FALSE(Pattern::isValidVarNameStart('$'));
  EXPECT_FALSE(Pattern::isValidVarNameStart('@'));
  EXPECT_FALSE(Pattern::isValidVarNameStart('+'));
  EXPECT_FALSE(Pattern::isValidVarNameStart('-'));
  EXPECT_FALSE(Pattern::isValidVarNameStart(':'));
}

TEST_F(FileCheckTest, ParseVar) {
  SourceMgr SM;
  StringRef OrigVarName = bufferize(SM, "GoodVar42");
  StringRef VarName = OrigVarName;
  Expected<Pattern::VariableProperties> ParsedVarResult =
      Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
  EXPECT_TRUE(VarName.empty());
  EXPECT_FALSE(ParsedVarResult->IsPseudo);

  VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
  EXPECT_TRUE(VarName.empty());
  EXPECT_FALSE(ParsedVarResult->IsPseudo);

  VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
  EXPECT_TRUE(VarName.empty());
  EXPECT_TRUE(ParsedVarResult->IsPseudo);

  VarName = bufferize(SM, "42BadVar");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  expectDiagnosticError("invalid variable name", ParsedVarResult.takeError());

  VarName = bufferize(SM, "$@");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  expectDiagnosticError("invalid variable name", ParsedVarResult.takeError());

  VarName = OrigVarName = bufferize(SM, "B@dVar");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(VarName, OrigVarName.substr(1));
  EXPECT_EQ(ParsedVarResult->Name, "B");
  EXPECT_FALSE(ParsedVarResult->IsPseudo);

  VarName = OrigVarName = bufferize(SM, "B$dVar");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(VarName, OrigVarName.substr(1));
  EXPECT_EQ(ParsedVarResult->Name, "B");
  EXPECT_FALSE(ParsedVarResult->IsPseudo);

  VarName = bufferize(SM, "BadVar+");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(VarName, "+");
  EXPECT_EQ(ParsedVarResult->Name, "BadVar");
  EXPECT_FALSE(ParsedVarResult->IsPseudo);

  VarName = bufferize(SM, "BadVar-");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(VarName, "-");
  EXPECT_EQ(ParsedVarResult->Name, "BadVar");
  EXPECT_FALSE(ParsedVarResult->IsPseudo);

  VarName = bufferize(SM, "BadVar:");
  ParsedVarResult = Pattern::parseVariable(VarName, SM);
  ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
  EXPECT_EQ(VarName, ":");
  EXPECT_EQ(ParsedVarResult->Name, "BadVar");
  EXPECT_FALSE(ParsedVarResult->IsPseudo);
}

static void expectNotFoundError(Error Err) {
  expectError<NotFoundError>("String not found in input", std::move(Err));
}

class PatternTester {
private:
  size_t LineNumber = 1;
  SourceMgr SM;
  FileCheckRequest Req;
  FileCheckPatternContext Context;
  Pattern P{Check::CheckPlain, &Context, LineNumber};

public:
  PatternTester() {
    std::vector<StringRef> GlobalDefines = {"#FOO=42", "BAR=BAZ", "#add=7"};
    // An ASSERT_FALSE would make more sense but cannot be used in a
    // constructor.
    EXPECT_THAT_ERROR(Context.defineCmdlineVariables(GlobalDefines, SM),
                      Succeeded());
    Context.createLineVariable();
    // Call parsePattern to have @LINE defined.
    P.parsePattern("N/A", "CHECK", SM, Req);
    // parsePattern does not expect to be called twice for the same line and
    // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
    // a pattern for a different line.
    initNextPattern();
  }

  void initNextPattern() {
    P = Pattern(Check::CheckPlain, &Context, ++LineNumber);
  }

  size_t getLineNumber() const { return LineNumber; }

  Expected<std::unique_ptr<Expression>>
  parseSubst(StringRef Expr, bool IsLegacyLineExpr = false) {
    StringRef ExprBufferRef = bufferize(SM, Expr);
    Optional<NumericVariable *> DefinedNumericVariable;
    return P.parseNumericSubstitutionBlock(
        ExprBufferRef, DefinedNumericVariable, IsLegacyLineExpr, LineNumber,
        &Context, SM);
  }

  bool parsePattern(StringRef Pattern) {
    StringRef PatBufferRef = bufferize(SM, Pattern);
    return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
  }

  Expected<size_t> match(StringRef Buffer) {
    StringRef BufferRef = bufferize(SM, Buffer);
    size_t MatchLen;
    return P.match(BufferRef, MatchLen, SM);
  }

  void printVariableDefs(FileCheckDiag::MatchType MatchTy,
                         std::vector<FileCheckDiag> &Diags) {
    P.printVariableDefs(SM, MatchTy, &Diags);
  }
};

TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
  PatternTester Tester;

  // Variable definition.

  expectDiagnosticError("invalid variable name",
                        Tester.parseSubst("%VAR:").takeError());

  expectDiagnosticError("definition of pseudo numeric variable unsupported",
                        Tester.parseSubst("@LINE:").takeError());

  expectDiagnosticError("string variable with name 'BAR' already exists",
                        Tester.parseSubst("BAR:").takeError());

  expectDiagnosticError("unexpected characters after numeric variable name",
                        Tester.parseSubst("VAR GARBAGE:").takeError());

  // Change of format.
  expectDiagnosticError("format different from previous variable definition",
                        Tester.parseSubst("%X,FOO:").takeError());

  // Invalid format.
  expectDiagnosticError("invalid matching format specification in expression",
                        Tester.parseSubst("X,VAR1:").takeError());
  expectDiagnosticError("invalid format specifier in expression",
                        Tester.parseSubst("%F,VAR1:").takeError());
  expectDiagnosticError("invalid matching format specification in expression",
                        Tester.parseSubst("%X a,VAR1:").takeError());

  // Acceptable variable definition.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("VAR1:"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("  VAR2:"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("VAR3  :"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("VAR3:  "), Succeeded());

  // Acceptable variable definition with format specifier. Use parsePattern for
  // variables whose definition needs to be visible for later checks.
  EXPECT_FALSE(Tester.parsePattern("[[#%u, VAR_UNSIGNED:]]"));
  EXPECT_FALSE(Tester.parsePattern("[[#%x, VAR_LOWER_HEX:]]"));
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%X, VAR_UPPER_HEX:"), Succeeded());

  // Acceptable variable definition with precision specifier.
  EXPECT_FALSE(Tester.parsePattern("[[#%.8X, PADDED_ADDR:]]"));
  EXPECT_FALSE(Tester.parsePattern("[[#%.8, PADDED_NUM:]]"));

  // Acceptable variable definition from a numeric expression.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOOBAR: FOO+1"), Succeeded());

  // Numeric expression. Switch to next line to make above valid definition
  // available in expressions.
  Tester.initNextPattern();

  // Invalid variable name.
  expectDiagnosticError("invalid matching constraint or operand format",
                        Tester.parseSubst("%VAR").takeError());

  expectDiagnosticError("invalid pseudo numeric variable '@FOO'",
                        Tester.parseSubst("@FOO").takeError());

  // parsePattern() is used here instead of parseSubst() for the variable to be
  // recorded in GlobalNumericVariableTable and thus appear defined to
  // parseNumericVariableUse(). Note that the same pattern object is used for
  // the parsePattern() and parseSubst() since no initNextPattern() is called,
  // thus appearing as being on the same line from the pattern's point of view.
  ASSERT_FALSE(Tester.parsePattern("[[#SAME_LINE_VAR:]]"));
  expectDiagnosticError("numeric variable 'SAME_LINE_VAR' defined earlier in "
                        "the same CHECK directive",
                        Tester.parseSubst("SAME_LINE_VAR").takeError());

  // Invalid use of variable defined on the same line from an expression not
  // using any variable defined on the same line.
  ASSERT_FALSE(Tester.parsePattern("[[#SAME_LINE_EXPR_VAR:@LINE+1]]"));
  expectDiagnosticError("numeric variable 'SAME_LINE_EXPR_VAR' defined earlier "
                        "in the same CHECK directive",
                        Tester.parseSubst("SAME_LINE_EXPR_VAR").takeError());

  // Valid use of undefined variable which creates the variable and record it
  // in GlobalNumericVariableTable.
  ASSERT_THAT_EXPECTED(Tester.parseSubst("UNDEF"), Succeeded());
  EXPECT_TRUE(Tester.parsePattern("[[UNDEF:.*]]"));

  // Invalid literal.
  expectDiagnosticError("unsupported operation 'U'",
                        Tester.parseSubst("42U").takeError());

  // Valid empty expression.
  EXPECT_THAT_EXPECTED(Tester.parseSubst(""), Succeeded());

  // Invalid equality matching constraint with empty expression.
  expectDiagnosticError("empty numeric expression should not have a constraint",
                        Tester.parseSubst("==").takeError());

  // Valid single operand expression.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("18"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MaxUint64)),
                       Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("0x12"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("-30"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MinInt64)),
                       Succeeded());

  // Valid optional matching constraint.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("==FOO"), Succeeded());

  // Invalid matching constraint.
  expectDiagnosticError("invalid matching constraint or operand format",
                        Tester.parseSubst("+=FOO").takeError());

  // Invalid format.
  expectDiagnosticError("invalid matching format specification in expression",
                        Tester.parseSubst("X,FOO:").takeError());
  expectDiagnosticError("invalid format specifier in expression",
                        Tester.parseSubst("%F,FOO").takeError());
  expectDiagnosticError("invalid matching format specification in expression",
                        Tester.parseSubst("%X a,FOO").takeError());

  // Valid expression with 2 or more operands.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+3"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+0xC"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO-3+FOO"), Succeeded());

  expectDiagnosticError("unsupported operation '/'",
                        Tester.parseSubst("@LINE/2").takeError());

  expectDiagnosticError("missing operand in expression",
                        Tester.parseSubst("@LINE+").takeError());

  // Errors in RHS operand are bubbled up by parseBinop() to
  // parseNumericSubstitutionBlock().
  expectDiagnosticError("invalid operand format",
                        Tester.parseSubst("@LINE+%VAR").takeError());

  // Invalid legacy @LINE expression with non literal rhs.
  expectDiagnosticError(
      "invalid operand format",
      Tester.parseSubst("@LINE+@LINE", /*IsLegacyNumExpr=*/true).takeError());

  // Invalid legacy @LINE expression made of a single literal.
  expectDiagnosticError(
      "invalid variable name",
      Tester.parseSubst("2", /*IsLegacyNumExpr=*/true).takeError());

  // Invalid hex literal in legacy @LINE expression.
  expectDiagnosticError(
      "unexpected characters at end of expression 'xC'",
      Tester.parseSubst("@LINE+0xC", /*LegacyLineExpr=*/true).takeError());

  // Valid expression with format specifier.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%u, FOO"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%d, FOO"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%x, FOO"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%X, FOO"), Succeeded());

  // Valid expression with precision specifier.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%.8u, FOO"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%.8, FOO"), Succeeded());

  // Valid legacy @LINE expression.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("@LINE+2", /*IsLegacyNumExpr=*/true),
                       Succeeded());

  // Invalid legacy @LINE expression with more than 2 operands.
  expectDiagnosticError(
      "unexpected characters at end of expression '+@LINE'",
      Tester.parseSubst("@LINE+2+@LINE", /*IsLegacyNumExpr=*/true).takeError());
  expectDiagnosticError(
      "unexpected characters at end of expression '+2'",
      Tester.parseSubst("@LINE+2+2", /*IsLegacyNumExpr=*/true).takeError());

  // Valid expression with several variables when their implicit formats do not
  // conflict.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+VAR_UNSIGNED"), Succeeded());

  // Valid implicit format conflict in presence of explicit formats.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("%X,FOO+VAR_LOWER_HEX"), Succeeded());

  // Implicit format conflict.
  expectDiagnosticError(
      "implicit format conflict between 'FOO' (%u) and "
      "'VAR_LOWER_HEX' (%x), need an explicit format specifier",
      Tester.parseSubst("FOO+VAR_LOWER_HEX").takeError());

  // Simple parenthesized expressions:
  EXPECT_THAT_EXPECTED(Tester.parseSubst("(1)"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("(1+1)"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("(1)+1"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("((1)+1)"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("((1)+X)"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("((X)+Y)"), Succeeded());

  expectDiagnosticError("missing operand in expression",
                        Tester.parseSubst("(").takeError());
  expectDiagnosticError("missing ')' at end of nested expression",
                        Tester.parseSubst("(1").takeError());
  expectDiagnosticError("missing operand in expression",
                        Tester.parseSubst("(1+").takeError());
  expectDiagnosticError("missing ')' at end of nested expression",
                        Tester.parseSubst("(1+1").takeError());
  expectDiagnosticError("missing ')' at end of nested expression",
                        Tester.parseSubst("((1+2+3").takeError());
  expectDiagnosticError("missing ')' at end of nested expression",
                        Tester.parseSubst("((1+2)+3").takeError());

  // Test missing operation between operands:
  expectDiagnosticError("unsupported operation '('",
                        Tester.parseSubst("(1)(2)").takeError());
  expectDiagnosticError("unsupported operation '('",
                        Tester.parseSubst("2(X)").takeError());

  // Test more closing than opening parentheses. The diagnostic messages are
  // not ideal, but for now simply check that we reject invalid input.
  expectDiagnosticError("invalid matching constraint or operand format",
                        Tester.parseSubst(")").takeError());
  expectDiagnosticError("unsupported operation ')'",
                        Tester.parseSubst("1)").takeError());
  expectDiagnosticError("unsupported operation ')'",
                        Tester.parseSubst("(1+2))").takeError());
  expectDiagnosticError("unsupported operation ')'",
                        Tester.parseSubst("(2))").takeError());
  expectDiagnosticError("unsupported operation ')'",
                        Tester.parseSubst("(1))(").takeError());

  // Valid expression with function call.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO,3)"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add (FOO,3)"), Succeeded());
  // Valid expression with nested function call.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO, min(BAR,10))"), Succeeded());
  // Valid expression with function call taking expression as argument.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO, (BAR+10) + 3)"),
                       Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO, min (BAR,10) + 3)"),
                       Succeeded());
  // Valid expression with variable named the same as a function.
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add+FOO"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+add"), Succeeded());
  EXPECT_THAT_EXPECTED(Tester.parseSubst("add(add,add)+add"), Succeeded());

  // Malformed call syntax.
  expectDiagnosticError("missing ')' at end of call expression",
                        Tester.parseSubst("add(FOO,(BAR+7)").takeError());
  expectDiagnosticError("missing ')' at end of call expression",
                        Tester.parseSubst("add(FOO,min(BAR,7)").takeError());
  expectDiagnosticError("missing argument",
                        Tester.parseSubst("add(FOO,)").takeError());
  expectDiagnosticError("missing argument",
                        Tester.parseSubst("add(,FOO)").takeError());
  expectDiagnosticError("missing argument",
                        Tester.parseSubst("add(FOO,,3)").takeError());

  // Valid call, but to an unknown function.
  expectDiagnosticError("call to undefined function 'bogus_function'",
                        Tester.parseSubst("bogus_function(FOO,3)").takeError());
  expectDiagnosticError("call to undefined function '@add'",
                        Tester.parseSubst("@add(2,3)").takeError());
  expectDiagnosticError("call to undefined function '$add'",
                        Tester.parseSubst("$add(2,3)").takeError());
  expectDiagnosticError("call to undefined function 'FOO'",
                        Tester.parseSubst("FOO(2,3)").takeError());
  expectDiagnosticError("call to undefined function 'FOO'",
                        Tester.parseSubst("FOO (2,3)").takeError());

  // Valid call, but with incorrect argument count.
  expectDiagnosticError("function 'add' takes 2 arguments but 1 given",
                        Tester.parseSubst("add(FOO)").takeError());
  expectDiagnosticError("function 'add' takes 2 arguments but 3 given",
                        Tester.parseSubst("add(FOO,3,4)").takeError());

  // Valid call, but not part of a valid expression.
  expectDiagnosticError("unsupported operation 'a'",
                        Tester.parseSubst("2add(FOO,2)").takeError());
  expectDiagnosticError("unsupported operation 'a'",
                        Tester.parseSubst("FOO add(FOO,2)").takeError());
  expectDiagnosticError("unsupported operation 'a'",
                        Tester.parseSubst("add(FOO,2)add(FOO,2)").takeError());
}

TEST_F(FileCheckTest, ParsePattern) {
  PatternTester Tester;

  // Invalid space in string substitution.
  EXPECT_TRUE(Tester.parsePattern("[[ BAR]]"));

  // Invalid variable name in string substitution.
  EXPECT_TRUE(Tester.parsePattern("[[42INVALID]]"));

  // Invalid string variable definition.
  EXPECT_TRUE(Tester.parsePattern("[[@PAT:]]"));
  EXPECT_TRUE(Tester.parsePattern("[[PAT+2:]]"));

  // Collision with numeric variable.
  EXPECT_TRUE(Tester.parsePattern("[[FOO:]]"));

  // Valid use of string variable.
  EXPECT_FALSE(Tester.parsePattern("[[BAR]]"));

  // Valid string variable definition.
  EXPECT_FALSE(Tester.parsePattern("[[PAT:[0-9]+]]"));

  // Invalid numeric substitution.
  EXPECT_TRUE(Tester.parsePattern("[[#42INVALID]]"));

  // Valid numeric substitution.
  EXPECT_FALSE(Tester.parsePattern("[[#FOO]]"));

  // Valid legacy @LINE expression.
  EXPECT_FALSE(Tester.parsePattern("[[@LINE+2]]"));

  // Invalid legacy @LINE expression with non decimal literal.
  EXPECT_TRUE(Tester.parsePattern("[[@LINE+0x3]]"));
}

TEST_F(FileCheckTest, Match) {
  PatternTester Tester;

  // Check a substitution error is diagnosed.
  ASSERT_FALSE(Tester.parsePattern("[[#%u, -1]]"));
  expectDiagnosticError(
      "unable to substitute variable or numeric expression: overflow error",
      Tester.match("").takeError());

  // Check matching an empty expression only matches a number.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#]]"));
  expectNotFoundError(Tester.match("FAIL").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());

  // Check matching a definition only matches a number with the right format.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR:]]"));
  expectNotFoundError(Tester.match("FAIL").takeError());
  expectNotFoundError(Tester.match("").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
  Tester.initNextPattern();
  Tester.parsePattern("[[#%u,NUMVAR_UNSIGNED:]]");
  expectNotFoundError(Tester.match("C").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
  Tester.initNextPattern();
  Tester.parsePattern("[[#%x,NUMVAR_LOWER_HEX:]]");
  expectNotFoundError(Tester.match("g").takeError());
  expectNotFoundError(Tester.match("C").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("c"), Succeeded());
  Tester.initNextPattern();
  Tester.parsePattern("[[#%X,NUMVAR_UPPER_HEX:]]");
  expectNotFoundError(Tester.match("H").takeError());
  expectNotFoundError(Tester.match("b").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("B"), Succeeded());

  // Check matching expressions with no explicit format matches the values in
  // the right format.
  Tester.initNextPattern();
  Tester.parsePattern("[[#NUMVAR_UNSIGNED-5]]");
  expectNotFoundError(Tester.match("f").takeError());
  expectNotFoundError(Tester.match("F").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("15"), Succeeded());
  Tester.initNextPattern();
  Tester.parsePattern("[[#NUMVAR_LOWER_HEX+1]]");
  expectNotFoundError(Tester.match("13").takeError());
  expectNotFoundError(Tester.match("D").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("d"), Succeeded());
  Tester.initNextPattern();
  Tester.parsePattern("[[#NUMVAR_UPPER_HEX+1]]");
  expectNotFoundError(Tester.match("12").takeError());
  expectNotFoundError(Tester.match("c").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("C"), Succeeded());

  // Check matching an undefined variable returns a NotFound error.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("100"));
  expectNotFoundError(Tester.match("101").takeError());

  // Check matching the defined variable matches the correct number only.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR]]"));
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());

  // Check matching several substitutions does not match them independently.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR]] [[#NUMVAR+2]]"));
  expectNotFoundError(Tester.match("19 21").takeError());
  expectNotFoundError(Tester.match("18 21").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("18 20"), Succeeded());

  // Check matching a numeric expression using @LINE after a match failure uses
  // the correct value for @LINE.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#@LINE]]"));
  // Ok, @LINE matches the current line number.
  EXPECT_THAT_EXPECTED(Tester.match(std::to_string(Tester.getLineNumber())),
                       Succeeded());
  Tester.initNextPattern();
  // Match with substitution failure.
  ASSERT_FALSE(Tester.parsePattern("[[#UNKNOWN]]"));
  expectUndefErrors({"UNKNOWN"}, Tester.match("FOO").takeError());
  Tester.initNextPattern();
  // Check that @LINE matches the later (given the calls to initNextPattern())
  // line number.
  EXPECT_FALSE(Tester.parsePattern("[[#@LINE]]"));
  EXPECT_THAT_EXPECTED(Tester.match(std::to_string(Tester.getLineNumber())),
                       Succeeded());
}

TEST_F(FileCheckTest, MatchParen) {
  PatternTester Tester;
  // Check simple parenthesized expressions
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR:]]"));
  expectNotFoundError(Tester.match("FAIL").takeError());
  expectNotFoundError(Tester.match("").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());

  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR + (2 + 2)]]"));
  expectNotFoundError(Tester.match("21").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("22"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR + (2)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(2)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(NUMVAR)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("36"), Succeeded());

  // Check nested parenthesized expressions:
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(2+(2))]]"));
  EXPECT_THAT_EXPECTED(Tester.match("22"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(2+(NUMVAR))]]"));
  EXPECT_THAT_EXPECTED(Tester.match("38"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+((((NUMVAR))))]]"));
  EXPECT_THAT_EXPECTED(Tester.match("36"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+((((NUMVAR)))-1)-1]]"));
  EXPECT_THAT_EXPECTED(Tester.match("34"), Succeeded());

  // Parentheses can also be the first character after the '#':
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#(NUMVAR)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#(NUMVAR+2)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
}

TEST_F(FileCheckTest, MatchBuiltinFunctions) {
  PatternTester Tester;
  // Esnure #NUMVAR has the expected value.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR:]]"));
  expectNotFoundError(Tester.match("FAIL").takeError());
  expectNotFoundError(Tester.match("").takeError());
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());

  // Check each builtin function generates the expected result.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#add(NUMVAR,13)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("31"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#div(NUMVAR,3)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("6"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#max(NUMVAR,5)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#max(NUMVAR,99)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("99"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#min(NUMVAR,5)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("5"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#min(NUMVAR,99)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#mul(NUMVAR,3)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("54"), Succeeded());
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#sub(NUMVAR,7)]]"));
  EXPECT_THAT_EXPECTED(Tester.match("11"), Succeeded());

  // Check nested function calls.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#add(min(7,2),max(4,10))]]"));
  EXPECT_THAT_EXPECTED(Tester.match("12"), Succeeded());

  // Check function call that uses a variable of the same name.
  Tester.initNextPattern();
  ASSERT_FALSE(Tester.parsePattern("[[#add(add,add)+min (add,3)+add]]"));
  EXPECT_THAT_EXPECTED(Tester.match("24"), Succeeded());
}

TEST_F(FileCheckTest, Substitution) {
  SourceMgr SM;
  FileCheckPatternContext Context;
  EXPECT_THAT_ERROR(Context.defineCmdlineVariables({"FOO=BAR"}, SM),
                    Succeeded());

  // Substitution of an undefined string variable fails and error holds that
  // variable's name.
  StringSubstitution StringSubstitution(&Context, "VAR404", 42);
  Expected<std::string> SubstValue = StringSubstitution.getResult();
  expectUndefErrors({"VAR404"}, SubstValue.takeError());

  // Numeric substitution blocks constituted of defined numeric variables are
  // substituted for the variable's value.
  NumericVariable NVar("N", ExpressionFormat(ExpressionFormat::Kind::Unsigned),
                       1);
  NVar.setValue(ExpressionValue(10u));
  auto NVarUse = std::make_unique<NumericVariableUse>("N", &NVar);
  auto ExpressionN = std::make_unique<Expression>(
      std::move(NVarUse), ExpressionFormat(ExpressionFormat::Kind::HexUpper));
  NumericSubstitution SubstitutionN(&Context, "N", std::move(ExpressionN),
                                    /*InsertIdx=*/30);
  SubstValue = SubstitutionN.getResult();
  ASSERT_THAT_EXPECTED(SubstValue, Succeeded());
  EXPECT_EQ("A", *SubstValue);

  // Substitution of an undefined numeric variable fails, error holds name of
  // undefined variable.
  NVar.clearValue();
  SubstValue = SubstitutionN.getResult();
  expectUndefErrors({"N"}, SubstValue.takeError());

  // Substitution of a defined string variable returns the right value.
  Pattern P(Check::CheckPlain, &Context, 1);
  StringSubstitution = llvm::StringSubstitution(&Context, "FOO", 42);
  SubstValue = StringSubstitution.getResult();
  ASSERT_THAT_EXPECTED(SubstValue, Succeeded());
  EXPECT_EQ("BAR", *SubstValue);
}

TEST_F(FileCheckTest, FileCheckContext) {
  FileCheckPatternContext Cxt;
  SourceMgr SM;

  // No definition.
  EXPECT_THAT_ERROR(Cxt.defineCmdlineVariables({}, SM), Succeeded());

  // Missing equal sign.
  expectDiagnosticError("missing equal sign in global definition",
                        Cxt.defineCmdlineVariables({"LocalVar"}, SM));
  expectDiagnosticError("missing equal sign in global definition",
                        Cxt.defineCmdlineVariables({"#LocalNumVar"}, SM));

  // Empty variable name.
  expectDiagnosticError("empty variable name",
                        Cxt.defineCmdlineVariables({"=18"}, SM));
  expectDiagnosticError("empty variable name",
                        Cxt.defineCmdlineVariables({"#=18"}, SM));

  // Invalid variable name.
  expectDiagnosticError("invalid variable name",
                        Cxt.defineCmdlineVariables({"18LocalVar=18"}, SM));
  expectDiagnosticError("invalid variable name",
                        Cxt.defineCmdlineVariables({"#18LocalNumVar=18"}, SM));

  // Name conflict between pattern and numeric variable.
  expectDiagnosticError(
      "string variable with name 'LocalVar' already exists",
      Cxt.defineCmdlineVariables({"LocalVar=18", "#LocalVar=36"}, SM));
  Cxt = FileCheckPatternContext();
  expectDiagnosticError(
      "numeric variable with name 'LocalNumVar' already exists",
      Cxt.defineCmdlineVariables({"#LocalNumVar=18", "LocalNumVar=36"}, SM));
  Cxt = FileCheckPatternContext();

  // Invalid numeric value for numeric variable.
  expectUndefErrors({"x"}, Cxt.defineCmdlineVariables({"#LocalNumVar=x"}, SM));

  // Define local variables from command-line.
  std::vector<StringRef> GlobalDefines;
  // Clear local variables to remove dummy numeric variable x that
  // parseNumericSubstitutionBlock would have created and stored in
  // GlobalNumericVariableTable.
  Cxt.clearLocalVars();
  GlobalDefines.emplace_back("LocalVar=FOO");
  GlobalDefines.emplace_back("EmptyVar=");
  GlobalDefines.emplace_back("#LocalNumVar1=18");
  GlobalDefines.emplace_back("#%x,LocalNumVar2=LocalNumVar1+2");
  GlobalDefines.emplace_back("#LocalNumVar3=0xc");
  ASSERT_THAT_ERROR(Cxt.defineCmdlineVariables(GlobalDefines, SM), Succeeded());

  // Create @LINE pseudo numeric variable and check it is present by matching
  // it.
  size_t LineNumber = 1;
  Pattern P(Check::CheckPlain, &Cxt, LineNumber);
  FileCheckRequest Req;
  Cxt.createLineVariable();
  ASSERT_FALSE(P.parsePattern("[[@LINE]]", "CHECK", SM, Req));
  size_t MatchLen;
  ASSERT_THAT_EXPECTED(P.match("1", MatchLen, SM), Succeeded());

#ifndef NDEBUG
  // Recreating @LINE pseudo numeric variable fails.
  EXPECT_DEATH(Cxt.createLineVariable(),
               "@LINE pseudo numeric variable already created");
#endif

  // Check defined variables are present and undefined ones are absent.
  StringRef LocalVarStr = "LocalVar";
  StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1");
  StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2");
  StringRef LocalNumVar3Ref = bufferize(SM, "LocalNumVar3");
  StringRef EmptyVarStr = "EmptyVar";
  StringRef UnknownVarStr = "UnknownVar";
  Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
  P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
  Optional<NumericVariable *> DefinedNumericVariable;
  Expected<std::unique_ptr<Expression>> ExpressionPointer =
      P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,
                                      /*IsLegacyLineExpr=*/false, LineNumber,
                                      &Cxt, SM);
  ASSERT_THAT_EXPECTED(LocalVar, Succeeded());
  EXPECT_EQ(*LocalVar, "FOO");
  Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
  Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  Expected<ExpressionValue> ExpressionVal =
      (*ExpressionPointer)->getAST()->eval();
  ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 18);
  ExpressionPointer = P.parseNumericSubstitutionBlock(
      LocalNumVar2Ref, DefinedNumericVariable,
      /*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  ExpressionVal = (*ExpressionPointer)->getAST()->eval();
  ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 20);
  ExpressionPointer = P.parseNumericSubstitutionBlock(
      LocalNumVar3Ref, DefinedNumericVariable,
      /*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  ExpressionVal = (*ExpressionPointer)->getAST()->eval();
  ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 12);
  ASSERT_THAT_EXPECTED(EmptyVar, Succeeded());
  EXPECT_EQ(*EmptyVar, "");
  expectUndefErrors({std::string(UnknownVarStr)}, UnknownVar.takeError());

  // Clear local variables and check they become absent.
  Cxt.clearLocalVars();
  LocalVar = Cxt.getPatternVarValue(LocalVarStr);
  expectUndefErrors({std::string(LocalVarStr)}, LocalVar.takeError());
  // Check a numeric expression's evaluation fails if called after clearing of
  // local variables, if it was created before. This is important because local
  // variable clearing due to --enable-var-scope happens after numeric
  // expressions are linked to the numeric variables they use.
  expectUndefErrors({"LocalNumVar3"},
                    (*ExpressionPointer)->getAST()->eval().takeError());
  P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
  ExpressionPointer = P.parseNumericSubstitutionBlock(
      LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
      LineNumber, &Cxt, SM);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  ExpressionVal = (*ExpressionPointer)->getAST()->eval();
  expectUndefErrors({"LocalNumVar1"}, ExpressionVal.takeError());
  ExpressionPointer = P.parseNumericSubstitutionBlock(
      LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
      LineNumber, &Cxt, SM);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  ExpressionVal = (*ExpressionPointer)->getAST()->eval();
  expectUndefErrors({"LocalNumVar2"}, ExpressionVal.takeError());
  EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
  expectUndefErrors({"EmptyVar"}, EmptyVar.takeError());
  // Clear again because parseNumericSubstitutionBlock would have created a
  // dummy variable and stored it in GlobalNumericVariableTable.
  Cxt.clearLocalVars();

  // Redefine global variables and check variables are defined again.
  GlobalDefines.emplace_back("$GlobalVar=BAR");
  GlobalDefines.emplace_back("#$GlobalNumVar=36");
  ASSERT_THAT_ERROR(Cxt.defineCmdlineVariables(GlobalDefines, SM), Succeeded());
  StringRef GlobalVarStr = "$GlobalVar";
  StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
  Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
  ASSERT_THAT_EXPECTED(GlobalVar, Succeeded());
  EXPECT_EQ(*GlobalVar, "BAR");
  P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
  ExpressionPointer = P.parseNumericSubstitutionBlock(
      GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
      LineNumber, &Cxt, SM);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  ExpressionVal = (*ExpressionPointer)->getAST()->eval();
  ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 36);

  // Clear local variables and check global variables remain defined.
  Cxt.clearLocalVars();
  EXPECT_THAT_EXPECTED(Cxt.getPatternVarValue(GlobalVarStr), Succeeded());
  P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
  ExpressionPointer = P.parseNumericSubstitutionBlock(
      GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
      LineNumber, &Cxt, SM);
  ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
  ExpressionVal = (*ExpressionPointer)->getAST()->eval();
  ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 36);
}

TEST_F(FileCheckTest, CapturedVarDiags) {
  PatternTester Tester;
  ASSERT_FALSE(Tester.parsePattern("[[STRVAR:[a-z]+]] [[#NUMVAR:@LINE]]"));
  EXPECT_THAT_EXPECTED(Tester.match("foobar 2"), Succeeded());
  std::vector<FileCheckDiag> Diags;
  Tester.printVariableDefs(FileCheckDiag::MatchFoundAndExpected, Diags);
  EXPECT_EQ(Diags.size(), 2ul);
  for (FileCheckDiag Diag : Diags) {
    EXPECT_EQ(Diag.CheckTy, Check::CheckPlain);
    EXPECT_EQ(Diag.MatchTy, FileCheckDiag::MatchFoundAndExpected);
    EXPECT_EQ(Diag.InputStartLine, 1u);
    EXPECT_EQ(Diag.InputEndLine, 1u);
  }
  EXPECT_EQ(Diags[0].InputStartCol, 1u);
  EXPECT_EQ(Diags[0].InputEndCol, 7u);
  EXPECT_EQ(Diags[1].InputStartCol, 8u);
  EXPECT_EQ(Diags[1].InputEndCol, 9u);
  EXPECT_EQ(Diags[0].Note, "captured var \"STRVAR\"");
  EXPECT_EQ(Diags[1].Note, "captured var \"NUMVAR\"");
}
} // namespace
