text: # Copyright 2019 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.
  
  """A test rule that compares two binary files or two directories.
  
  The rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
  command (fc.exe) on Windows (no Bash is required).
  """
  
  load(":directory_path.bzl", "DirectoryPathInfo")
  
  def _runfiles_path(f):
      if f.root.path:
          return f.path[len(f.root.path) + 1:]  # generated file
      else:
          return f.path  # source file
  
  def _diff_test_impl(ctx):
      if DirectoryPathInfo in ctx.attr.file1:
          file1 = ctx.attr.file1[DirectoryPathInfo].directory
          file1_path = "/".join([_runfiles_path(file1), ctx.attr.file1[DirectoryPathInfo].path])
      else:
          if len(ctx.files.file1) != 1:
              fail("file1 must be a single file or a target that provides a DirectoryPathInfo")
          file1 = ctx.files.file1[0]
          file1_path = _runfiles_path(file1)
  
      if DirectoryPathInfo in ctx.attr.file2:
          file2 = ctx.attr.file2[DirectoryPathInfo].directory
          file2_path = "/".join([_runfiles_path(file2), ctx.attr.file2[DirectoryPathInfo].path])
      else:
          if len(ctx.files.file2) != 1:
              fail("file2 must be a single file or a target that provides a DirectoryPathInfo")
          file2 = ctx.files.file2[0]
          file2_path = _runfiles_path(file2)
  
      if file1 == file2:
          msg = "diff_test comparing the same file %s" % file1
          fail(msg)
  
      if ctx.attr.is_windows:
          test_bin = ctx.actions.declare_file(ctx.label.name + "-test.bat")
          ctx.actions.write(
              output = test_bin,
              content = """@rem Generated by diff_test.bzl, do not edit.
  @echo off
  SETLOCAL ENABLEEXTENSIONS
  SETLOCAL ENABLEDELAYEDEXPANSION
  set MF=%RUNFILES_MANIFEST_FILE:/=\\%
  set PATH=%SYSTEMROOT%\\system32
  set F1={file1}
  set F2={file2}
  if "!F1:~0,9!" equ "external/" (set F1=!F1:~9!) else (set F1=!TEST_WORKSPACE!/!F1!)
  if "!F2:~0,9!" equ "external/" (set F2=!F2:~9!) else (set F2=!TEST_WORKSPACE!/!F2!)
  for /F "tokens=2* usebackq" %%i in (`findstr.exe /l /c:"!F1! " "%MF%"`) do (
    set RF1=%%i
    set RF1=!RF1:/=\\!
  )
  if "!RF1!" equ "" (
    if exist "{file1}" (
      set RF1="{file1}"
      set RF1=!RF1:/=\\!
    ) else (
      echo>&2 ERROR: !F1! not found
      exit /b 1
    )
  )
  for /F "tokens=2* usebackq" %%i in (`findstr.exe /l /c:"!F2! " "%MF%"`) do (
    set RF2=%%i
    set RF2=!RF2:/=\\!
  )
  if "!RF2!" equ "" (
    if exist "{file2}" (
      set RF2="{file2}"
      set RF2=!RF2:/=\\!
    ) else (
      echo>&2 ERROR: !F2! not found
      exit /b 1
    )
  )
  set DF1=0
  set DF2=0
  if exist "!RF1!\\*" (
    set DF1=1
  )
  if exist "!RF2!\\*" (
    set DF2=1
  )
  if %DF1% equ 1 (
    if %DF2% equ 0 (
      echo>&2 ERROR: Cannot compare directory "{file1}" and a file "{file2}"
      exit /b 1
    )
  )
  if %DF1% equ 0 (
    if %DF2% equ 1 (
      echo>&2 ERROR: Cannot compare file "{file1}" and a directory "{file2}"
      exit /b 1
    )
  )
  set DFX=0
  if %DF1% equ 1 (
    if %DF2% equ 1 (
      set DFX=1
    )
  )
  if %DFX% equ 1 (
    for /f "delims=" %%F in (
      'echo "."^&forfiles /s /p "!RF1!" /m "*" /c "cmd /c echo @relpath"'
    ) do (
      if not exist "!RF2!\\%%~F" (
        echo>&2 FAIL: file "%%~F" exists in "{file1}" and not in "{file2}". {fail_msg}
        GOTO fail
      )
      if not exist "!RF1!\\%%~F\\*" (
        fc.exe /B "!RF1!\\%%~F" "!RF2!\\%%~F" 2>NUL 1>NUL
        if !ERRORLEVEL! neq 0 (
          if !ERRORLEVEL! equ 1 (
            echo>&2 FAIL: files "{file1}\\%%~F" and "{file2}\\%%~F" differ. {fail_msg}
            GOTO fail
          ) else (
            fc.exe /B "!RF1!\\%%~F" "!RF2!\\%%~F"
            GOTO fail
          )
        )
      )
    )
    for /f "delims=" %%F in (
      'echo "."^&forfiles /s /p "!RF2!" /m "*" /c "cmd /c echo @relpath"'
    ) do (
      if not exist "!RF1!\\%%~F" (
        echo>&2 FAIL: file "%%~F" exists in "{file2}" and not in "{file1}". {fail_msg}
        GOTO fail
      )
    )
  ) else (
    fc.exe /B "!RF1!" "!RF2!" 2>NUL 1>NUL
    if %ERRORLEVEL% neq 0 (
      if %ERRORLEVEL% equ 1 (
        echo>&2 FAIL: files "{file1}" and "{file2}" differ. {fail_msg}
        exit /b 1
      ) else (
        fc.exe /B "!RF1!" "!RF2!"
        exit /b %errorlevel%
      )
    )
  )
  exit /b 0
  
  :fail
  exit /b 1
  """.format(
                  fail_msg = ctx.attr.failure_message,
                  file1 = file1_path,
                  file2 = file2_path,
              ),
              is_executable = True,
          )
      else:
          test_bin = ctx.actions.declare_file(ctx.label.name + "-test.sh")
          ctx.actions.write(
              output = test_bin,
              content = r"""#!/usr/bin/env bash
  set -euo pipefail
  F1="{file1}"
  F2="{file2}"
  [[ "$F1" =~ ^external/* ]] && F1="${{F1#external/}}" || F1="$TEST_WORKSPACE/$F1"
  [[ "$F2" =~ ^external/* ]] && F2="${{F2#external/}}" || F2="$TEST_WORKSPACE/$F2"
  if [[ -d "${{RUNFILES_DIR:-/dev/null}}" && "${{RUNFILES_MANIFEST_ONLY:-}}" != 1 ]]; then
    RF1="$RUNFILES_DIR/$F1"
    RF2="$RUNFILES_DIR/$F2"
  elif [[ -f "${{RUNFILES_MANIFEST_FILE:-/dev/null}}" ]]; then
    RF1="$(grep -F -m1 "$F1 " "$RUNFILES_MANIFEST_FILE" | sed 's/^[^ ]* //')"
    RF2="$(grep -F -m1 "$F2 " "$RUNFILES_MANIFEST_FILE" | sed 's/^[^ ]* //')"
  elif [[ -f "$TEST_SRCDIR/$F1" && -f "$TEST_SRCDIR/$F2" ]]; then
    RF1="$TEST_SRCDIR/$F1"
    RF2="$TEST_SRCDIR/$F2"
  else
    echo >&2 "ERROR: could not find \"{file1}\" and \"{file2}\""
    exit 1
  fi
  DF1=
  DF2=
  [[ ! -d "$RF1" ]] || DF1=1
  [[ ! -d "$RF2" ]] || DF2=1
  if [[ "$DF1" ]] && [[ ! "$DF2" ]]; then
    echo >&2 "ERROR: cannot compare a directory \"{file1}\" against a file \"{file2}\""
    exit 1
  fi
  if [[ ! "$DF1" ]] && [[ "$DF2" ]]; then
    echo >&2 "ERROR: cannot compare a file \"{file1}\" against a directory \"{file2}\""
    exit 1
  fi
  if [[ "$DF1" ]] || [[ "$DF2" ]]; then
    if ! diff -r "$RF1" "$RF2"; then
      echo >&2 "FAIL: directories \"{file1}\" and \"{file2}\" differ. {fail_msg}"
      exit 1
    fi
  else
    if ! diff "$RF1" "$RF2"; then
      echo >&2 "FAIL: files \"{file1}\" and \"{file2}\" differ. {fail_msg}"
      exit 1
    fi
  fi
  """.format(
                  fail_msg = ctx.attr.failure_message,
                  file1 = file1_path,
                  file2 = file2_path,
              ),
              is_executable = True,
          )
      return DefaultInfo(
          executable = test_bin,
          files = depset(direct = [test_bin]),
          runfiles = ctx.runfiles(files = [test_bin, file1, file2]),
      )
  
  _diff_test = rule(
      attrs = {
          "failure_message": attr.string(),
          "file1": attr.label(
              allow_files = True,
              mandatory = True,
          ),
          "file2": attr.label(
              allow_files = True,
              mandatory = True,
          ),
          "is_windows": attr.bool(mandatory = True),
      },
      test = True,
      implementation = _diff_test_impl,
  )
  
  def diff_test(name, file1, file2, **kwargs):
      """A test that compares two files.
  
      The test succeeds if the files' contents match.
  
      Args:
        name: The name of the test rule.
        file1: Label of the file to compare to <code>file2</code>.
        file2: Label of the file to compare to <code>file1</code>.
        **kwargs: The <a href="https://docs.bazel.build/versions/main/be/common-definitions.html#common-attributes-tests">common attributes for tests</a>.
      """
      _diff_test(
          name = name,
          file1 = file1,
          file2 = file2,
          is_windows = select({
              "@bazel_tools//src/conditions:host_windows": True,
              "//conditions:default": False,
          }),
          **kwargs
      )
  