"""Tests for write_source_files""" # Inspired by https://github.com/cgrindel/bazel-starlib/blob/main/updatesrc/private/updatesrc_update_test.bzl load("//lib/private:write_source_file.bzl", _write_source_file = "write_source_file") load("//lib/private:directory_path.bzl", "DirectoryPathInfo") def _write_source_file_test_impl_sh(ctx, in_file_path, out_file_path): test = ctx.actions.declare_file( ctx.label.name + "_test.sh", ) contents = [] contents.append(""" #!/usr/bin/env bash set -o errexit -o nounset -o pipefail assert_different() { local in_file="${1}" local out_file="${2}" diff "${in_file}" "${out_file}" > /dev/null && (echo >&2 "Expected files to differ. in: ${in_file}, out: ${out_file}" && return -1) return 0 } assert_same() { local in_file="${1}" local out_file="${2}" diff "${in_file}" "${out_file}" || (echo >&2 "Expected files to be same. in: ${in_file}, out: ${out_file}" && return -1) }""") contents.append(""" # Check that in and out files are different assert_different {in_file} {out_file} """.format( in_file = in_file_path, out_file = out_file_path, )) contents.append("""# Write to the source files {write_source_files} """.format(write_source_files = ctx.file.write_source_file_target.short_path)) contents.append("""# Check that in and out files are the same assert_same {in_file} {out_file}""".format( in_file = in_file_path, out_file = out_file_path, )) ctx.actions.write( output = test, is_executable = True, content = "\n".join(contents), ) return test def _write_source_file_test_impl_bat(ctx, in_file_path, out_file_path): test = ctx.actions.declare_file( ctx.label.name + "_test.bat", ) # BUG: Windows is having trouble executing the symlink to the write_source_files executable, # but it is able to execute the actual output script so point to that for now. # # What we would use if this bug didn't exist: # write_source_files = ctx.executable.write_source_file_target.short_path.replace("/", "\\") # # Instead back out of the runfiles execution directory: # write_to_source_files_test_test.bat.runfiles/aspect_bazel_lib # And point to the output script. write_source_files = "..\\..\\%s" % ctx.executable.write_source_file_target.basename contents = [] contents.append(""" @rem @generated by @aspect_bazel_lib//:lib/tests/write_source_files:write_source_file_test.bzl @echo off @rem Check that in and out files are different call :assert_different {in_file}, {out_file} if %errorlevel% neq 0 exit /b 1 """.format( in_file = in_file_path.replace("/", "\\"), out_file = out_file_path.replace("/", "\\"), )) contents.append(""" @rem Write to the source files call {write_source_files} if %errorlevel% neq 0 exit /b 1 """.format(write_source_files = write_source_files)) contents.append(""" @rem Check that in and out files are the same call :assert_same {in_file}, {out_file} if %errorlevel% neq 0 exit /b 1 """.format( in_file = in_file_path.replace("/", "\\"), out_file = out_file_path.replace("/", "\\"), )) contents.append(""" exit /b 0 :assert_different fc /b %~1 %~2 > nul if %errorlevel% equ 1 exit /b 0 echo Error: %~1 and %~2 are not different exit /b 1 :assert_same fc /b %~1 %~2 > nul if %errorlevel% equ 0 exit /b 0 echo Error: %~1 and %~2 are not the same exit /b 1 """) ctx.actions.write( output = test, is_executable = True, content = "\n".join(contents).replace("\n", "\r\n"), ) return test def _write_source_file_test_impl(ctx): is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]) if DirectoryPathInfo in ctx.attr.in_file: in_file = ctx.attr.in_file[DirectoryPathInfo].directory in_file_path = "/".join([in_file.short_path, ctx.attr.in_file[DirectoryPathInfo].path]) else: if len(ctx.files.in_file) != 1: fail("in_file must be a single file or a target that provides a DirectoryPathInfo") in_file = ctx.files.in_file[0] in_file_path = in_file.short_path if is_windows: test = _write_source_file_test_impl_bat(ctx, in_file_path, ctx.file.out_file.short_path) else: test = _write_source_file_test_impl_sh(ctx, in_file_path, ctx.file.out_file.short_path) return DefaultInfo( executable = test, runfiles = ctx.runfiles( files = [ctx.executable.write_source_file_target, in_file, ctx.file.out_file], ), ) _write_source_file_test = rule( implementation = _write_source_file_test_impl, attrs = { "write_source_file_target": attr.label( allow_single_file = True, executable = True, # Intentionally use the target platform since the target is always meant to be `bazel # run` on the host machine but we don't want to transition it to the host platform and # have the generated file rebuilt in a separate output tree. Target platform should # always be equal to the host platform when using `write_source_files`. cfg = "target", mandatory = True, ), "out_file": attr.label( allow_single_file = True, mandatory = True, ), "in_file": attr.label( allow_files = True, mandatory = True, ), "_windows_constraint": attr.label(default = "@platforms//os:windows"), }, test = True, ) def write_source_file_test(name, in_file, out_file): """Stamp a write_source_files executable and a test to run against it""" _write_source_file( name = name + "_updater", in_file = in_file, out_file = out_file, diff_test = False, ) # Note that for testing we update the source files in the sandbox, # not the actual source tree. _write_source_file_test( name = name, write_source_file_target = name + "_updater", in_file = in_file, out_file = out_file, timeout = "short", )