bcbd1bdb22
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
179 lines
5.1 KiB
Python
179 lines
5.1 KiB
Python
import pytest
|
|
|
|
from mirage.commands.builtin.generic.cat import cat
|
|
|
|
|
|
async def _drain(gen):
|
|
return b"".join([c async for c in gen])
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_passthrough_from_bytes():
|
|
out = await _drain(cat(b"hello\nworld\n"))
|
|
assert out == b"hello\nworld\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_passthrough_from_stream_preserves_chunks():
|
|
|
|
async def src():
|
|
yield b"hel"
|
|
yield b"lo\nwo"
|
|
yield b"rld\n"
|
|
|
|
chunks = [c async for c in cat(src())]
|
|
assert chunks == [b"hel", b"lo\nwo", b"rld\n"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_number_lines():
|
|
out = await _drain(cat(b"a\nb\nc\n", number_lines=True))
|
|
assert out == b" 1\ta\n 2\tb\n 3\tc\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_number_lines_across_chunk_boundaries():
|
|
|
|
async def src():
|
|
yield b"a\nb"
|
|
yield b"\nc\n"
|
|
|
|
out = await _drain(cat(src(), number_lines=True))
|
|
assert out == b" 1\ta\n 2\tb\n 3\tc\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_show_ends():
|
|
out = await _drain(cat(b"a\nb\n", show_ends=True))
|
|
assert out == b"a$\nb$\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_squeeze_blank():
|
|
out = await _drain(cat(b"a\n\n\n\nb\n", squeeze_blank=True))
|
|
assert out == b"a\n\nb\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_no_trailing_newline_preserved():
|
|
"""POSIX: `printf "x" | cat -n` emits no trailing newline."""
|
|
out = await _drain(cat(b"hello", number_lines=True))
|
|
assert out == b" 1\thello"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_passthrough_no_trailing_newline():
|
|
"""No-flag cat must not add a trailing newline."""
|
|
out = await _drain(cat(b"hello"))
|
|
assert out == b"hello"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_number_lines_multidigit_alignment():
|
|
"""POSIX format is `%6d\\t` — width 6, right-justified. Old MIRAGE used
|
|
a 5-space prefix which broke alignment for line numbers >= 10."""
|
|
body = b"".join(f"line{i}\n".encode() for i in range(1, 13))
|
|
out = await _drain(cat(body, number_lines=True))
|
|
lines = out.split(b"\n")
|
|
assert lines[0] == b" 1\tline1"
|
|
assert lines[8] == b" 9\tline9"
|
|
assert lines[9] == b" 10\tline10"
|
|
assert lines[11] == b" 12\tline12"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_show_ends_no_trailing_newline():
|
|
"""cat -E on input without trailing newline must not emit final `$\\n`."""
|
|
out = await _drain(cat(b"hello", show_ends=True))
|
|
assert out == b"hello"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_combined_n_E_s():
|
|
"""Combined flags: number all kept lines, show ends, squeeze blanks."""
|
|
out = await _drain(
|
|
cat(b"a\n\n\n\nb\n",
|
|
number_lines=True,
|
|
show_ends=True,
|
|
squeeze_blank=True))
|
|
# Kept lines: "a", "" (first blank, kept), "b". Numbered 1, 2, 3.
|
|
assert out == b" 1\ta$\n 2\t$\n 3\tb$\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_empty_input_emits_nothing_with_flags():
|
|
out = await _drain(cat(b"", number_lines=True))
|
|
assert out == b""
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_only_newlines():
|
|
"""Three blank lines numbered 1, 2, 3."""
|
|
out = await _drain(cat(b"\n\n\n", number_lines=True))
|
|
assert out == b" 1\t\n 2\t\n 3\t\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_squeeze_blank_preserves_first_blank():
|
|
out = await _drain(cat(b"\n\n\nx\n", squeeze_blank=True))
|
|
assert out == b"\nx\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_empty_input_passthrough():
|
|
out = await _drain(cat(b""))
|
|
assert out == b""
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_binary_passthrough_full_byte_range():
|
|
"""Full 0..255 byte range must pass through unchanged (no flags)."""
|
|
data = bytes(range(256))
|
|
out = await _drain(cat(data))
|
|
assert out == data
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_binary_with_show_ends_marks_only_newlines():
|
|
"""show_ends should only mark 0x0A bytes, not other binary bytes."""
|
|
data = b"\x00\x01\n\x02\x03\n"
|
|
out = await _drain(cat(data, show_ends=True))
|
|
assert out == b"\x00\x01$\n\x02\x03$\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_number_lines_chunked_one_byte_at_a_time():
|
|
"""Worst-case chunking: every byte its own chunk. Result must match
|
|
unbuffered input exactly."""
|
|
|
|
async def src():
|
|
for byte in b"a\nbb\nccc\n":
|
|
yield bytes([byte])
|
|
|
|
out = await _drain(cat(src(), number_lines=True))
|
|
assert out == b" 1\ta\n 2\tbb\n 3\tccc\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_show_tabs_renders_caret_i():
|
|
out = b"".join([c async for c in cat(b"a\tb\nx\n", show_tabs=True)])
|
|
assert out == b"a^Ib\nx\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_show_all_combines_tabs_and_ends():
|
|
out = b"".join([
|
|
c async for c in cat(b"a\tb\nx\n",
|
|
show_tabs=True,
|
|
show_ends=True,
|
|
show_nonprinting=True)
|
|
])
|
|
assert out == b"a^Ib$\nx$\n"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cat_show_nonprinting_caret_and_meta_notation():
|
|
out = b"".join(
|
|
[c async for c in cat(b"\x01\x7f\xff\n", show_nonprinting=True)])
|
|
assert out == b"^A^?M-^?\n"
|