1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
#! /bin/zsh
Red="\033[0;31m"
Green='\033[0;32m'
Color_Off='\033[0m'
show_usage() {
cat << EOF
Usage: gtest [options] [target] [go test flags]
Target can be:
- Package name/path (e.g., "handlers" or "pkg/auth")
- Test function name (e.g., "TestUserLogin" or just "UserLogin")
- Omit target to test current directory
Examples:
gtest # Run all tests in current directory
gtest handlers # Run all tests in handlers packages recursively
gtest TestUserLogin # Run specific test by name
gtest UserLogin # Match test containing "UserLogin"
gtest pkg/auth -v # Run auth tests with verbose output
gtest -raw TestFoo # Use plain go test output (no tparse/richgo)
Flags:
-raw, --raw # Use plain go test (disable tparse/richgo)
--exact # Exact test name match (not substring)
-h, --help # Show this help message
Output Formatting:
By default, uses tparse if available, falls back to richgo, then plain go.
Use -raw to force plain go test output.
EOF
}
# Show help
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_usage
exit 0
fi
# Check for -raw flag to disable output parsing
USE_RAW=false
if [[ "$1" == "-raw" || "$1" == "--raw" ]]; then
USE_RAW=true
shift
fi
# Validate we're in a Go project
if [ ! -f "go.mod" ]; then
echo -e "${Red}Error: Not in a Go module (go.mod not found)${Color_Off}"
exit 1
fi
# Determine test runner: prefer tparse, fallback to richgo, then plain go
USE_TPARSE=false
if [[ "$USE_RAW" == false ]] && [[ -x "$(which tparse)" ]]; then
BIN='go'
USE_TPARSE=true
elif [[ "$USE_RAW" == false ]] && [[ -x "$(which richgo)" ]]; then
BIN='richgo'
else
BIN='go'
fi
# Ensure ripgrep installed
if ! [ -x "$(which rg)" ]; then
echo -e "${Red}Error: please install ripgrep:${Color_Off}\n brew install ripgrep"
exit 1
fi
# Default to current directory if no target specified
if [ -z "$1" ]; then
TARGET="."
else
TARGET="$1"
shift
fi
# Check for exact match flag
MATCH_MODE="substring"
if [[ "$1" == "--exact" ]]; then
MATCH_MODE="exact"
shift
fi
# Decision tree for determining if target is a directory path or test name:
# 1. "." → current directory
# 2. Existing directory path → use as directory
# 3. Starts with Test/Bench/Fuzz/Example and contains "/" → test with subtest
# 4. Starts with Test/Bench/Fuzz/Example → test name
# 5. Contains "/" → likely a package path (e.g., pkg/handlers)
# 6. Otherwise → search for files matching the pattern, fallback to test name
if [[ "$TARGET" == "." ]]; then
# Special case: current directory
CMD="$BIN test ./... $@"
echo -e "${Green}Testing current directory recursively${Color_Off}"
elif [ -d "$TARGET" ]; then
# It's an actual directory that exists
CMD="$BIN test ./${TARGET}/... $@"
echo -e "${Green}Testing directory: ${TARGET}/...${Color_Off}"
elif [[ "$TARGET" =~ ^(Test|Bench|Fuzz|Example) ]]; then
# Starts with Test/Bench/Fuzz/Example → it's a test/benchmark/fuzz/example function
case "$MATCH_MODE" in
exact)
FILTER="-run '^${TARGET}$'"
echo -e "${Green}Searching for test: ${TARGET}${Color_Off}"
;;
substring)
# For subtests with / (e.g., TestFoo/subtest), pass as-is
if [[ "$TARGET" =~ / ]]; then
FILTER="-run '${TARGET}'"
echo -e "${Green}Searching for test/subtest: ${TARGET}${Color_Off}"
else
# Go's -run is already unanchored, no need for .*
FILTER="-run '${TARGET}'"
echo -e "${Green}Searching for tests matching: ${TARGET}${Color_Off}"
fi
;;
esac
CMD="$BIN test ./... $FILTER $@"
elif [[ "$TARGET" =~ / ]]; then
# Contains "/" but doesn't start with Test/Bench/etc → probably a package path
# Check if we can find files in this path
if [ -d "$TARGET" ]; then
CMD="$BIN test ./${TARGET}/... $@"
echo -e "${Green}Testing package: ${TARGET}/...${Color_Off}"
else
# Path doesn't exist, but might be a partial path - try to find matching files
SANITIZED="${TARGET//[$\^]/}"
MATCHING_FILE=$(rg --files | rg "$SANITIZED" | head -1)
if [ -n "$MATCHING_FILE" ]; then
DIR=$(dirname "$MATCHING_FILE")
CMD="$BIN test ./${DIR}/... $@"
echo -e "${Green}Testing package: ${DIR}/...${Color_Off}"
else
# Nothing found - maybe it's an unusual test name with / in it
echo -e "${Green}No package found, treating as test pattern: ${TARGET}${Color_Off}"
FILTER="-run '${TARGET}'"
CMD="$BIN test ./... $FILTER $@"
fi
fi
else
# No "/" and doesn't start with Test/Bench/etc
# Try to find as a package/directory name first
SANITIZED="${TARGET//[$\^]/}"
MATCHING_FILE=$(rg --files | rg "$SANITIZED" | head -1)
if [ -n "$MATCHING_FILE" ]; then
# Found files matching - get the directory and test it recursively
DIR=$(dirname "$MATCHING_FILE")
CMD="$BIN test ./${DIR}/... $@"
echo -e "${Green}Testing package: ${DIR}/...${Color_Off}"
else
# No files found - treat as a test name substring
FILTER="-run '${TARGET}'"
CMD="$BIN test ./... $FILTER $@"
echo -e "${Green}No package found, searching for tests matching: ${TARGET}${Color_Off}"
fi
fi
if [[ "$USE_TPARSE" == true ]]; then
# tparse requires -json flag and output piped to it
echo -e "${Green}Running Cmd:\n ${CMD} -json | tparse -all${Color_Off}\n"
eval "${CMD} -json | tparse -all"
else
echo -e "${Green}Running Cmd:\n ${CMD}${Color_Off}\n"
eval "$CMD"
fi
|