Add some go testing infrastructure
This commit is contained in:
parent
3a21605b05
commit
1325844539
@ -3,10 +3,12 @@
|
||||
|
||||
import importlib
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from typing import Callable, Generator, Iterator, NoReturn, Sequence, Set
|
||||
from typing import Callable, Generator, Iterator, List, NoReturn, Sequence, Set
|
||||
|
||||
|
||||
def contents(package: str) -> Iterator[str]:
|
||||
@ -91,24 +93,75 @@ def run_cli(suite: unittest.TestSuite, verbosity: int = 4) -> None:
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def find_testable_go_packages() -> Set[str]:
|
||||
ans = set()
|
||||
base = os.getcwd()
|
||||
for (dirpath, dirnames, filenames) in os.walk(base):
|
||||
for f in filenames:
|
||||
if f.endswith('_test.go'):
|
||||
q = os.path.relpath(dirpath, base)
|
||||
ans.add(q)
|
||||
return ans
|
||||
|
||||
|
||||
def go_exe() -> str:
|
||||
return shutil.which('go') or ''
|
||||
|
||||
|
||||
def create_go_filter(packages: List[str], *names: str) -> str:
|
||||
go = go_exe()
|
||||
if not go:
|
||||
return ''
|
||||
all_tests = set()
|
||||
for line in subprocess.check_output('go test -list .'.split() + packages).decode().splitlines():
|
||||
if line.startswith('Test'):
|
||||
all_tests.add(line[4:])
|
||||
tests = set(names) & all_tests
|
||||
return '|'.join(tests)
|
||||
|
||||
|
||||
def run_go(packages: List[str], names: str) -> None:
|
||||
go = go_exe()
|
||||
if not go:
|
||||
print('Skipping Go tests as go exe not found', file=sys.stderr)
|
||||
return
|
||||
if not packages:
|
||||
print('Skipping Go tests as go source files not availabe', file=sys.stderr)
|
||||
return
|
||||
cmd = 'go test -v'.split()
|
||||
if names:
|
||||
cmd.extend(('-run', names))
|
||||
cmd += packages
|
||||
print(shlex.join(cmd))
|
||||
os.execl(go, *cmd)
|
||||
|
||||
|
||||
def run_tests() -> None:
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'name', nargs='*', default=[],
|
||||
help='The name of the test to run, for e.g. linebuf corresponds to test_linebuf. Can be specified multiple times')
|
||||
help='The name of the test to run, for e.g. linebuf corresponds to test_linebuf. Can be specified multiple times.')
|
||||
parser.add_argument('--verbosity', default=4, type=int, help='Test verbosity')
|
||||
parser.add_argument('--module', default='', help='Name of a test module to restrict to. For example: ssh')
|
||||
parser.add_argument('--module', default='', help='Name of a test module to restrict to. For example: ssh.'
|
||||
' For Go tests this is the name of a package, for example: tools/cli')
|
||||
args = parser.parse_args()
|
||||
if args.name and args.name[0] in ('type-check', 'type_check', 'mypy'):
|
||||
type_check()
|
||||
tests = find_all_tests()
|
||||
go_packages = find_testable_go_packages()
|
||||
go_filter_spec = ''
|
||||
if args.module:
|
||||
tests = filter_tests_by_module(tests, args.module)
|
||||
if not tests._tests:
|
||||
go_packages &= {args.module}
|
||||
if not tests._tests and not go_packages:
|
||||
raise SystemExit('No test module named %s found' % args.module)
|
||||
go_pkg_args = [f'kitty/{x}' for x in go_packages]
|
||||
|
||||
if args.name:
|
||||
tests = filter_tests_by_name(tests, *args.name)
|
||||
if not tests._tests:
|
||||
go_filter_spec = create_go_filter(go_pkg_args, *args.name)
|
||||
if not tests._tests and not go_filter_spec:
|
||||
raise SystemExit('No test named %s found' % args.name)
|
||||
run_cli(tests, args.verbosity)
|
||||
run_go(go_pkg_args, go_filter_spec)
|
||||
|
||||
3
test.py
3
test.py
@ -32,6 +32,7 @@ def main() -> None:
|
||||
launcher_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'kitty', 'launcher')
|
||||
path = f'{launcher_dir}{os.pathsep}{path}'
|
||||
PYTHON_FOR_TYPE_CHECK = shutil.which('python') or shutil.which('python3') or ''
|
||||
gohome = os.path.expanduser('~/go')
|
||||
with TemporaryDirectory() as tdir, env_vars(
|
||||
PYTHONWARNINGS='error', HOME=tdir, USERPROFILE=tdir, PATH=path,
|
||||
XDG_CONFIG_HOME=os.path.join(tdir, '.config'),
|
||||
@ -40,6 +41,8 @@ def main() -> None:
|
||||
XDG_CACHE_HOME=os.path.join(tdir, '.cache'),
|
||||
PYTHON_FOR_TYPE_CHECK=PYTHON_FOR_TYPE_CHECK,
|
||||
):
|
||||
if os.path.isdir(gohome):
|
||||
os.symlink(gohome, os.path.join(tdir, os.path.basename(gohome)))
|
||||
m = importlib.import_module('kitty_tests.main')
|
||||
getattr(m, 'run_tests')()
|
||||
|
||||
|
||||
@ -83,6 +83,7 @@ func format_line_with_indent(output io.Writer, text string, indent string, scree
|
||||
fmt.Fprint(output, indent)
|
||||
in_escape := 0
|
||||
var current_word strings.Builder
|
||||
var escapes strings.Builder
|
||||
|
||||
print_word := func(r rune) {
|
||||
w := runewidth.StringWidth(current_word.String())
|
||||
@ -94,8 +95,14 @@ func format_line_with_indent(output io.Writer, text string, indent string, scree
|
||||
current_word.Reset()
|
||||
current_word.WriteString(s)
|
||||
}
|
||||
fmt.Fprint(output, current_word.String())
|
||||
if escapes.Len() > 0 {
|
||||
output.Write([]byte(escapes.String()))
|
||||
escapes.Reset()
|
||||
}
|
||||
if current_word.Len() > 0 {
|
||||
output.Write([]byte(current_word.String()))
|
||||
current_word.Reset()
|
||||
}
|
||||
if r > 0 {
|
||||
current_word.WriteRune(r)
|
||||
}
|
||||
@ -113,7 +120,7 @@ func format_line_with_indent(output io.Writer, text string, indent string, scree
|
||||
if (in_escape == 2 && r == 'm') || (in_escape == 3 && r == '\\' && text[i-1] == 0x1b) {
|
||||
in_escape = 0
|
||||
}
|
||||
fmt.Fprint(output, string(r))
|
||||
escapes.WriteRune(r)
|
||||
continue
|
||||
}
|
||||
if r == 0x1b {
|
||||
@ -121,7 +128,7 @@ func format_line_with_indent(output io.Writer, text string, indent string, scree
|
||||
if current_word.Len() != 0 {
|
||||
print_word(0)
|
||||
}
|
||||
fmt.Fprint(output, string(r))
|
||||
escapes.WriteRune(r)
|
||||
continue
|
||||
}
|
||||
if current_word.Len() != 0 && r != 0xa0 && unicode.IsSpace(r) {
|
||||
@ -130,7 +137,7 @@ func format_line_with_indent(output io.Writer, text string, indent string, scree
|
||||
current_word.WriteRune(r)
|
||||
}
|
||||
}
|
||||
if current_word.Len() != 0 {
|
||||
if current_word.Len() != 0 || escapes.Len() != 0 {
|
||||
print_word(0)
|
||||
}
|
||||
if len(text) > 0 {
|
||||
@ -323,6 +330,7 @@ func show_usage(cmd *cobra.Command) error {
|
||||
fmt.Fprintln(&output, italic_fmt(RootCmd.Name()), opt_fmt(RootCmd.Version), "created by", title_fmt("Kovid Goyal"))
|
||||
}
|
||||
output_text := output.String()
|
||||
// fmt.Printf("%#v\n", output_text)
|
||||
if stdout_is_terminal && cmd.Annotations["allow-pager"] != "no" {
|
||||
pager := exec.Command(kitty.DefaultPager[0], kitty.DefaultPager[1:]...)
|
||||
pager.Stdin = strings.NewReader(output_text)
|
||||
|
||||
18
tools/cli/infrastructure_test.go
Normal file
18
tools/cli/infrastructure_test.go
Normal file
@ -0,0 +1,18 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFormatLineWithIndent(t *testing.T) {
|
||||
var output strings.Builder
|
||||
|
||||
output.Reset()
|
||||
indent := " "
|
||||
format_line_with_indent(&output, "testing \x1b[31mstyled\x1b[m", indent, 11)
|
||||
expected := indent + "testing \n" + indent + "\x1b[31mstyled\x1b[m\n"
|
||||
if output.String() != expected {
|
||||
t.Errorf("%#v != %#v", expected, output.String())
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,16 @@ func EntryPoint(tool_root *cobra.Command) *cobra.Command {
|
||||
" for permission to perform the specified action, unless the password has been"+
|
||||
" accepted before or is pre-configured in :file:`kitty.conf`.")
|
||||
|
||||
root.PersistentFlags().String("password-file", "rc-pass",
|
||||
"A file from which to read the password. Trailing whitespace is ignored. Relative"+
|
||||
" paths are resolved from the kitty configuration directory. Use - to read from STDIN."+
|
||||
" Used if no :option:`--password` is supplied. Defaults to checking for the"+
|
||||
" :file:`rc-pass` file in the kitty configuration directory.")
|
||||
|
||||
root.PersistentFlags().String("password-env", "KITTY_RC_PASSWORD",
|
||||
"The name of an environment variable to read the password from."+
|
||||
" Used if no :option:`--password-file` or :option:`--password` is supplied.")
|
||||
|
||||
cli.PersistentChoices(root, "use-password", "If no password is available, kitty will usually just send the remote control command without a password. This option can be used to force it to always or never use the supplied password.", "if-available", "always", "never")
|
||||
return root
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user