Skip to content

Commit 4db2fb6

Browse files
committed
[mailx] round out testing
1 parent 3c5abe7 commit 4db2fb6

File tree

10 files changed

+3826
-22
lines changed

10 files changed

+3826
-22
lines changed

mailx/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,7 @@ fn expand_folder_name(name: &str, vars: &Variables) -> String {
15071507
fn compose_message(
15081508
composed: &mut ComposedMessage,
15091509
mb: &Mailbox,
1510-
vars: &Variables,
1510+
vars: &mut Variables,
15111511
) -> Result<(), String> {
15121512
let stdin = io::stdin();
15131513
let escape_char = vars.escape_char();

mailx/compare-macos.sh

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
#!/bin/bash
2+
#
3+
# compare-macos.sh - Compare our mailx implementation against macOS /usr/bin/mailx
4+
#
5+
# This script runs 5 key tests comparing output between the system mailx and our
6+
# Rust implementation. Run from the mailx/ directory or repository root.
7+
#
8+
# Usage: ./mailx/compare-macos.sh
9+
#
10+
# Prerequisites:
11+
# - macOS with /usr/bin/mailx
12+
# - cargo build completed (debug or release)
13+
#
14+
15+
# Don't use set -e as we expect some commands to fail (e.g., -e with no mail)
16+
17+
# Colors for output
18+
RED='\033[0;31m'
19+
GREEN='\033[0;32m'
20+
YELLOW='\033[1;33m'
21+
NC='\033[0m' # No Color
22+
23+
# Find script directory and repo root
24+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
25+
if [[ -f "$SCRIPT_DIR/Cargo.toml" ]]; then
26+
MAILX_DIR="$SCRIPT_DIR"
27+
elif [[ -f "$SCRIPT_DIR/../mailx/Cargo.toml" ]]; then
28+
MAILX_DIR="$SCRIPT_DIR/../mailx"
29+
else
30+
MAILX_DIR="$(pwd)/mailx"
31+
fi
32+
REPO_ROOT="$(cd "$MAILX_DIR/.." && pwd)"
33+
34+
# Test data file
35+
TESTDATA="$MAILX_DIR/tests/cli/testdata.mbox"
36+
37+
# Check prerequisites
38+
if [[ ! -f /usr/bin/mailx ]]; then
39+
echo -e "${RED}Error: /usr/bin/mailx not found. This script requires macOS.${NC}"
40+
exit 1
41+
fi
42+
43+
if [[ ! -f "$TESTDATA" ]]; then
44+
echo -e "${RED}Error: Test data not found at $TESTDATA${NC}"
45+
exit 1
46+
fi
47+
48+
# Find our mailx binary
49+
if [[ -f "$REPO_ROOT/target/release/mailx" ]]; then
50+
OUR_MAILX="$REPO_ROOT/target/release/mailx"
51+
elif [[ -f "$REPO_ROOT/target/debug/mailx" ]]; then
52+
OUR_MAILX="$REPO_ROOT/target/debug/mailx"
53+
else
54+
echo -e "${YELLOW}Building mailx...${NC}"
55+
(cd "$REPO_ROOT" && cargo build -p posixutils-mailx --bin mailx)
56+
OUR_MAILX="$REPO_ROOT/target/debug/mailx"
57+
fi
58+
59+
echo "=============================================="
60+
echo "mailx Comparison Tests: macOS vs Our Implementation"
61+
echo "=============================================="
62+
echo "System mailx: /usr/bin/mailx"
63+
echo "Our mailx: $OUR_MAILX"
64+
echo "Test data: $TESTDATA"
65+
echo ""
66+
67+
PASSED=0
68+
FAILED=0
69+
70+
# Temp files for output comparison
71+
MACOS_OUT=$(mktemp)
72+
OUR_OUT=$(mktemp)
73+
trap "rm -f $MACOS_OUT $OUR_OUT" EXIT
74+
75+
# Helper function to run a test
76+
run_test() {
77+
local test_name="$1"
78+
local description="$2"
79+
shift 2
80+
81+
echo -n "Test: $test_name - $description... "
82+
}
83+
84+
# Helper to show results
85+
show_result() {
86+
local result="$1"
87+
local details="$2"
88+
89+
if [[ "$result" == "pass" ]]; then
90+
echo -e "${GREEN}PASS${NC}"
91+
PASSED=$((PASSED + 1))
92+
else
93+
echo -e "${RED}FAIL${NC}"
94+
if [[ -n "$details" ]]; then
95+
echo " $details"
96+
fi
97+
FAILED=$((FAILED + 1))
98+
fi
99+
}
100+
101+
# Normalize output for comparison (remove timestamps, whitespace differences)
102+
normalize_output() {
103+
# Remove leading/trailing whitespace, normalize multiple spaces
104+
# Remove date/time patterns that vary
105+
sed -E \
106+
-e 's/[A-Z][a-z]{2} [A-Z][a-z]{2} [0-9 ][0-9] [0-9]{2}:[0-9]{2}/DATE_TIME/g' \
107+
-e 's/[0-9]{4}-[0-9]{2}-[0-9]{2}/DATE/g' \
108+
-e 's/[0-9]+\/[0-9]+/N\/N/g' \
109+
-e 's/^[[:space:]]+//' \
110+
-e 's/[[:space:]]+$//' \
111+
-e 's/[[:space:]]+/ /g' \
112+
-e '/^$/d'
113+
}
114+
115+
echo "----------------------------------------------"
116+
echo "TEST 1: -e option (check mail presence)"
117+
echo "----------------------------------------------"
118+
119+
# Test 1a: -e with mail present (should exit 0)
120+
run_test "1a" "-e with mail present returns exit 0"
121+
/usr/bin/mailx -n -e -f "$TESTDATA" > /dev/null 2>&1
122+
MACOS_EXIT=$?
123+
"$OUR_MAILX" -n -e -f "$TESTDATA" > /dev/null 2>&1
124+
OUR_EXIT=$?
125+
126+
if [[ "$MACOS_EXIT" -eq 0 && "$OUR_EXIT" -eq 0 ]]; then
127+
show_result "pass"
128+
else
129+
show_result "fail" "macOS exit=$MACOS_EXIT, ours exit=$OUR_EXIT (expected both 0)"
130+
fi
131+
132+
# Test 1b: -e with empty file (should exit non-zero)
133+
EMPTY_MBOX=$(mktemp)
134+
run_test "1b" "-e with no mail returns non-zero exit"
135+
/usr/bin/mailx -n -e -f "$EMPTY_MBOX" > /dev/null 2>&1
136+
MACOS_EXIT=$?
137+
"$OUR_MAILX" -n -e -f "$EMPTY_MBOX" > /dev/null 2>&1
138+
OUR_EXIT=$?
139+
rm -f "$EMPTY_MBOX"
140+
141+
if [[ "$MACOS_EXIT" -ne 0 && "$OUR_EXIT" -ne 0 ]]; then
142+
show_result "pass"
143+
else
144+
show_result "fail" "macOS exit=$MACOS_EXIT, ours exit=$OUR_EXIT (expected both non-zero)"
145+
fi
146+
147+
echo ""
148+
echo "----------------------------------------------"
149+
echo "TEST 2: -H option (headers only)"
150+
echo "----------------------------------------------"
151+
152+
run_test "2" "-H shows header summary and exits"
153+
/usr/bin/mailx -n -H -f "$TESTDATA" > "$MACOS_OUT" 2>&1
154+
MACOS_EXIT=$?
155+
"$OUR_MAILX" -n -H -f "$TESTDATA" > "$OUR_OUT" 2>&1
156+
OUR_EXIT=$?
157+
158+
# Check both exited successfully
159+
if [[ "$MACOS_EXIT" -ne 0 || "$OUR_EXIT" -ne 0 ]]; then
160+
show_result "fail" "Exit codes: macOS=$MACOS_EXIT, ours=$OUR_EXIT"
161+
else
162+
# Check both contain the senders
163+
MACOS_HAS_ALICE=$(grep -ci "alice" "$MACOS_OUT" || true)
164+
MACOS_HAS_BOB=$(grep -ci "bob" "$MACOS_OUT" || true)
165+
MACOS_HAS_CHARLIE=$(grep -ci "charlie" "$MACOS_OUT" || true)
166+
OUR_HAS_ALICE=$(grep -ci "alice" "$OUR_OUT" || true)
167+
OUR_HAS_BOB=$(grep -ci "bob" "$OUR_OUT" || true)
168+
OUR_HAS_CHARLIE=$(grep -ci "charlie" "$OUR_OUT" || true)
169+
170+
if [[ "$MACOS_HAS_ALICE" -gt 0 && "$OUR_HAS_ALICE" -gt 0 && \
171+
"$MACOS_HAS_BOB" -gt 0 && "$OUR_HAS_BOB" -gt 0 && \
172+
"$MACOS_HAS_CHARLIE" -gt 0 && "$OUR_HAS_CHARLIE" -gt 0 ]]; then
173+
show_result "pass"
174+
else
175+
show_result "fail" "Missing senders in output"
176+
echo " macOS output:"
177+
head -5 "$MACOS_OUT" | sed 's/^/ /'
178+
echo " Our output:"
179+
head -5 "$OUR_OUT" | sed 's/^/ /'
180+
fi
181+
fi
182+
183+
echo ""
184+
echo "----------------------------------------------"
185+
echo "TEST 3: from command"
186+
echo "----------------------------------------------"
187+
188+
run_test "3a" "from * shows all message headers"
189+
echo "from *" | /usr/bin/mailx -n -N -f "$TESTDATA" > "$MACOS_OUT" 2>&1
190+
echo "from *" | "$OUR_MAILX" -n -N -f "$TESTDATA" > "$OUR_OUT" 2>&1
191+
192+
# Count lines with message indicators (should have 3 messages)
193+
MACOS_LINES=$(grep -ciE "alice|bob|charlie" "$MACOS_OUT" || true)
194+
OUR_LINES=$(grep -ciE "alice|bob|charlie" "$OUR_OUT" || true)
195+
196+
if [[ "$MACOS_LINES" -ge 3 && "$OUR_LINES" -ge 3 ]]; then
197+
show_result "pass"
198+
else
199+
show_result "fail" "macOS has $MACOS_LINES sender lines, ours has $OUR_LINES"
200+
fi
201+
202+
run_test "3b" "from 1 shows first message header"
203+
echo -e "from 1\nquit" | /usr/bin/mailx -n -N -f "$TESTDATA" > "$MACOS_OUT" 2>&1
204+
echo -e "from 1\nquit" | "$OUR_MAILX" -n -N -f "$TESTDATA" > "$OUR_OUT" 2>&1
205+
206+
MACOS_HAS_ALICE=$(grep -ci "alice" "$MACOS_OUT" || true)
207+
OUR_HAS_ALICE=$(grep -ci "alice" "$OUR_OUT" || true)
208+
209+
if [[ "$MACOS_HAS_ALICE" -gt 0 && "$OUR_HAS_ALICE" -gt 0 ]]; then
210+
show_result "pass"
211+
else
212+
show_result "fail" "Both should show alice"
213+
fi
214+
215+
echo ""
216+
echo "----------------------------------------------"
217+
echo "TEST 4: print/type command"
218+
echo "----------------------------------------------"
219+
220+
run_test "4a" "print 1 displays first message"
221+
echo -e "print 1\nquit" | /usr/bin/mailx -n -N -f "$TESTDATA" > "$MACOS_OUT" 2>&1
222+
echo -e "print 1\nquit" | "$OUR_MAILX" -n -N -f "$TESTDATA" > "$OUR_OUT" 2>&1
223+
224+
# Both should contain the message body
225+
MACOS_HAS_MEETING=$(grep -ci "meeting tomorrow" "$MACOS_OUT" || true)
226+
OUR_HAS_MEETING=$(grep -ci "meeting tomorrow" "$OUR_OUT" || true)
227+
MACOS_HAS_FROM=$(grep -c "^From:" "$MACOS_OUT" || true)
228+
OUR_HAS_FROM=$(grep -c "^From:" "$OUR_OUT" || true)
229+
230+
if [[ "$MACOS_HAS_MEETING" -gt 0 && "$OUR_HAS_MEETING" -gt 0 && \
231+
"$MACOS_HAS_FROM" -gt 0 && "$OUR_HAS_FROM" -gt 0 ]]; then
232+
show_result "pass"
233+
else
234+
show_result "fail" "Message content mismatch"
235+
echo " macOS: meeting=$MACOS_HAS_MEETING, From=$MACOS_HAS_FROM"
236+
echo " Ours: meeting=$OUR_HAS_MEETING, From=$OUR_HAS_FROM"
237+
fi
238+
239+
run_test "4b" "type command (alias for print)"
240+
echo -e "type 2\nquit" | /usr/bin/mailx -n -N -f "$TESTDATA" > "$MACOS_OUT" 2>&1
241+
echo -e "type 2\nquit" | "$OUR_MAILX" -n -N -f "$TESTDATA" > "$OUR_OUT" 2>&1
242+
243+
MACOS_HAS_PROJECT=$(grep -ci "project" "$MACOS_OUT" || true)
244+
OUR_HAS_PROJECT=$(grep -ci "project" "$OUR_OUT" || true)
245+
246+
if [[ "$MACOS_HAS_PROJECT" -gt 0 && "$OUR_HAS_PROJECT" -gt 0 ]]; then
247+
show_result "pass"
248+
else
249+
show_result "fail" "type command output mismatch"
250+
fi
251+
252+
echo ""
253+
echo "----------------------------------------------"
254+
echo "TEST 5: size command"
255+
echo "----------------------------------------------"
256+
257+
run_test "5a" "size 1 shows message size"
258+
echo -e "size 1\nquit" | /usr/bin/mailx -n -N -f "$TESTDATA" > "$MACOS_OUT" 2>&1
259+
echo -e "size 1\nquit" | "$OUR_MAILX" -n -N -f "$TESTDATA" > "$OUR_OUT" 2>&1
260+
261+
# Both should show size output with message number
262+
MACOS_HAS_SIZE=$(grep -E "1.*[0-9]+" "$MACOS_OUT" | head -1 || true)
263+
OUR_HAS_SIZE=$(grep -E "1.*[0-9]+" "$OUR_OUT" | head -1 || true)
264+
265+
if [[ -n "$MACOS_HAS_SIZE" && -n "$OUR_HAS_SIZE" ]]; then
266+
show_result "pass"
267+
echo " macOS: $MACOS_HAS_SIZE"
268+
echo " Ours: $OUR_HAS_SIZE"
269+
else
270+
show_result "fail" "Size output missing"
271+
fi
272+
273+
run_test "5b" "size * shows all message sizes"
274+
echo -e "size *\nquit" | /usr/bin/mailx -n -N -f "$TESTDATA" > "$MACOS_OUT" 2>&1
275+
echo -e "size *\nquit" | "$OUR_MAILX" -n -N -f "$TESTDATA" > "$OUR_OUT" 2>&1
276+
277+
# Count size lines (should be 3)
278+
MACOS_SIZE_LINES=$(grep -cE "^[[:space:]]*[0-9]+.*[0-9]+" "$MACOS_OUT" || true)
279+
OUR_SIZE_LINES=$(grep -cE "^[[:space:]]*[0-9]+.*[0-9]+" "$OUR_OUT" || true)
280+
281+
if [[ "$MACOS_SIZE_LINES" -ge 3 && "$OUR_SIZE_LINES" -ge 3 ]]; then
282+
show_result "pass"
283+
else
284+
show_result "fail" "macOS has $MACOS_SIZE_LINES size lines, ours has $OUR_SIZE_LINES"
285+
fi
286+
287+
echo ""
288+
echo "=============================================="
289+
echo "SUMMARY"
290+
echo "=============================================="
291+
echo -e "Passed: ${GREEN}$PASSED${NC}"
292+
echo -e "Failed: ${RED}$FAILED${NC}"
293+
echo ""
294+
295+
if [[ "$FAILED" -eq 0 ]]; then
296+
echo -e "${GREEN}All tests passed!${NC}"
297+
exit 0
298+
else
299+
echo -e "${RED}Some tests failed.${NC}"
300+
exit 1
301+
fi

0 commit comments

Comments
 (0)