diff --git a/elisp/BUILD b/elisp/BUILD index 6865771a..e536facb 100644 --- a/elisp/BUILD +++ b/elisp/BUILD @@ -348,7 +348,10 @@ py_library( name = "runfiles", srcs = ["runfiles.py"], srcs_version = "PY3", - visibility = ["//emacs:__pkg__"], + visibility = [ + "//emacs:__pkg__", + "//tests/wrap:__pkg__", + ], deps = ["@bazel_tools//tools/python/runfiles"], ) diff --git a/tests/wrap/BUILD b/tests/wrap/BUILD index 0cce5291..47cb2d97 100644 --- a/tests/wrap/BUILD +++ b/tests/wrap/BUILD @@ -12,27 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - testonly = 1, - srcs = ["main.go"], - importpath = "github.com/phst/rules_elisp/tests/wrap", - visibility = ["//visibility:private"], - deps = [ - "@com_github_google_go_cmp//cmp:go_default_library", - "@com_github_phst_runfiles//:go_default_library", - ], -) - -go_binary( +py_binary( name = "wrap", testonly = 1, - out = select({ - "@platforms//os:windows": "wrap.exe", - "//conditions:default": "wrap", - }), - embed = [":go_default_library"], + srcs = ["wrap.py"], + python_version = "PY3", + srcs_version = "PY3", visibility = ["//elisp:__pkg__"], + deps = ["//elisp:runfiles"], ) diff --git a/tests/wrap/main.go b/tests/wrap/main.go deleted file mode 100644 index 09192e9d..00000000 --- a/tests/wrap/main.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2020, 2021 Google LLC -// -// 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 -// -// https://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. - -// Binary wrap is a test helper program for //elisp:binary_test, which see. -package main - -import ( - "encoding/json" - "flag" - "io/ioutil" - "log" - "os" - "path/filepath" - "reflect" - - "github.com/google/go-cmp/cmp" - "github.com/phst/runfiles" -) - -func main() { - log.Println("Args:", os.Args) - log.Println("Environment:", os.Environ()) - var manifestFile string - flag.StringVar(&manifestFile, "manifest", "", "") - flag.Parse() - if manifestFile == "" { - log.Fatal("--manifest is empty") - } - runfilesLib, err := runfiles.Path("phst_rules_elisp/elisp/runfiles/runfiles.elc") - if err != nil { - log.Fatal(err) - } - inputFile, err := runfiles.Path("phst_rules_elisp/elisp/binary.cc") - if err != nil { - log.Fatal(err) - } - var outputFile string - if os.PathSeparator == '/' { - outputFile = "/tmp/output.dat" - } else { - outputFile = `C:\Temp\output.dat` - } - gotArgs := flag.Args() - wantArgs := []string{"--quick", "--batch"} - // The load path setup depends on whether we use manifest-based or - // directory-based runfiles. - if dir, err := runfiles.Path("phst_rules_elisp"); err == nil { - // Directory-based runfiles. - wantArgs = append(wantArgs, "--directory="+dir) - } else { - // Manifest-based runfiles. - wantArgs = append(wantArgs, - "--load="+runfilesLib, - "--funcall=elisp/runfiles/install-handler", - "--directory=/bazel-runfile:phst_rules_elisp", - ) - } - wantArgs = append(wantArgs, - "--option", - inputFile, - " \t\n\r\f äα𝐴🐈'\\\"", - "/:"+outputFile, - ) - if diff := cmp.Diff(gotArgs, wantArgs); diff != "" { - log.Fatalf("positional arguments: -got +want:\n%s", diff) - } - jsonData, err := ioutil.ReadFile(manifestFile) - if err != nil { - log.Fatalf("can’t read manifest: %s", err) - } - var gotManifest map[string]interface{} - if err := json.Unmarshal(jsonData, &gotManifest); err != nil { - log.Fatalf("can’t decode manifest: %s", err) - } - wantManifest := map[string]interface{}{ - "root": "RUNFILES_ROOT", - "tags": []interface{}{"local", "mytag"}, - "loadPath": []interface{}{"phst_rules_elisp"}, - "inputFiles": []interface{}{"phst_rules_elisp/elisp/binary.cc", "phst_rules_elisp/elisp/binary.h"}, - "outputFiles": []interface{}{outputFile}, - } - if diff := cmp.Diff( - gotManifest, wantManifest, - cmp.FilterPath(isInputFile, cmp.Transformer("", resolveRunfile)), - ); diff != "" { - log.Fatalf("manifest: -got +want:\n%s", diff) - } -} - -func isInputFile(p cmp.Path) bool { - if len(p) < 2 { - return false - } - m, ok := p[1].(cmp.MapIndex) - if !ok { - return false - } - k := m.Key() - return k.Kind() == reflect.String && k.String() == "inputFiles" -} - -func resolveRunfile(s string) string { - if filepath.IsAbs(s) { - return s - } - r, err := runfiles.Path(s) - if err != nil { - log.Fatalf("error resolving runfile for comparison: %s", err) - } - return r -} diff --git a/tests/wrap/wrap.py b/tests/wrap/wrap.py new file mode 100644 index 00000000..3b571d54 --- /dev/null +++ b/tests/wrap/wrap.py @@ -0,0 +1,96 @@ +# Copyright 2020, 2021 Google LLC +# +# 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 +# +# https://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. + +"""Binary wrap is a test helper program for //elisp:binary_test, which see.""" + +import argparse +import json +import os +import pathlib +import unittest +import sys +from typing import Any, Dict, List + +from phst_rules_elisp.elisp import runfiles + +def _main() -> None: + print('Args:', sys.argv) + print('Environment:', os.environ) + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument('--manifest', type=pathlib.Path, required=True) + parser.add_argument('rest', nargs='+') + args = parser.parse_args() + run_files = runfiles.Runfiles() + output_file = pathlib.PurePath( + r'C:\Temp\output.dat' if os.name == 'nt' else '/tmp/output.dat') + + class Test(unittest.TestCase): + """Unit tests for the command line and manifest.""" + + maxDiff = 5000 + + def test_args(self) -> None: + """Test that the Emacs command line is as expected.""" + got = args.rest + want = ['--quick', '--batch'] + # The load path setup depends on whether we use manifest-based or + # directory-based runfiles. + try: + directory = run_files.resolve( + pathlib.PurePosixPath('phst_rules_elisp')) + except FileNotFoundError: + # Manifest-based runfiles. + want += [ + '--load=' + str(run_files.resolve(pathlib.PurePosixPath( + 'phst_rules_elisp/elisp/runfiles/runfiles.elc'))), + '--funcall=elisp/runfiles/install-handler', + '--directory=/bazel-runfile:phst_rules_elisp', + ] + else: + # Directory-based runfiles. + want.append('--directory=' + str(directory)) + want += [ + '--option', + str(run_files.resolve(pathlib.PurePosixPath( + 'phst_rules_elisp/elisp/binary.cc'))), + ' \t\n\r\f äα𝐴🐈\'\\"', + '/:' + str(output_file), + ] + self.assertListEqual(got, want) + + def test_manifest(self) -> None: + """Test the manifest.""" + got = json.loads(args.manifest.read_text(encoding='utf-8')) + want = { + 'root': 'RUNFILES_ROOT', + 'tags': ['local', 'mytag'], + 'loadPath': ['phst_rules_elisp'], + 'inputFiles': ['phst_rules_elisp/elisp/binary.cc', + 'phst_rules_elisp/elisp/binary.h'], + 'outputFiles': [str(output_file)], + } # type: Dict[str, Any] + for var in (got, want): + files = var.get('inputFiles', []) # type: List[str] + for i, file in enumerate(files): + file = pathlib.PurePosixPath(file) + if not file.is_absolute(): + files[i] = str(run_files.resolve(file)) + self.assertDictEqual(got, want) + + tests = unittest.defaultTestLoader.loadTestsFromTestCase(Test) + if not unittest.TextTestRunner().run(tests).wasSuccessful(): + raise ValueError('incorrect arguments') + +if __name__ == '__main__': + _main()