Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:30:44 +08:00

154 lines
4.9 KiB
Python

import pytest
from mirage.commands.builtin.find_eval import (And, Empty, Name, Not, Or, Path,
TrueNode, Type, eval_predicate)
from mirage.commands.builtin.find_parse import (FindParseError,
parse_find_expression)
def test_parse_not_name():
expr = parse_find_expression(["-not", "-name", "*.txt"])
assert expr.tree == Not(Name("*.txt"))
def test_parse_bang_name():
expr = parse_find_expression(["!", "-name", "*.txt"])
assert expr.tree == Not(Name("*.txt"))
def test_parse_or_names():
expr = parse_find_expression(["-name", "a", "-o", "-name", "b"])
assert expr.tree == Or([Name("a"), Name("b")])
def test_parse_implicit_and():
expr = parse_find_expression(["-type", "d", "-name", "a"])
assert expr.tree == And([Type("d"), Name("a")])
def test_parse_explicit_and():
expr = parse_find_expression(["-type", "d", "-a", "-not", "-empty"])
assert expr.tree == And([Type("d"), Not(Empty())])
def test_or_lower_precedence_than_and():
expr = parse_find_expression(
["-name", "a", "-o", "-name", "b", "-name", "c"])
assert expr.tree == Or([Name("a"), And([Name("b"), Name("c")])])
def test_grouping():
expr = parse_find_expression(
["(", "-name", "a", "-o", "-name", "b", ")", "-type", "f"])
assert expr.tree == And([Or([Name("a"), Name("b")]), Type("f")])
def test_iname_path_empty():
assert parse_find_expression(["-iname", "*.TXT"]).tree == Name("*.TXT",
icase=True)
assert parse_find_expression(["-path", "*/x/*"]).tree == Path("*/x/*")
assert parse_find_expression(["-empty"]).tree == Empty()
def test_globals_extracted_as_truenode():
expr = parse_find_expression(
["-maxdepth", "2", "-mindepth", "1", "-name", "x"])
assert expr.maxdepth == 2
assert expr.mindepth == 1
assert eval_predicate(expr.tree, _ent(name="x.foo")) is False
assert eval_predicate(expr.tree, _ent(name="x")) is True
def test_size_extracted_global():
expr = parse_find_expression(["-size", "+50c"])
assert expr.min_size == 51
assert expr.max_size is None
def test_size_bounds_follow_gnu_strictness():
expr = parse_find_expression(["-size", "+0c"])
assert (expr.min_size, expr.max_size) == (1, None)
expr = parse_find_expression(["-size", "-2c"])
assert (expr.min_size, expr.max_size) == (None, 1)
expr = parse_find_expression(["-size", "2c"])
assert (expr.min_size, expr.max_size) == (2, 2)
def test_size_rounds_up_to_unit():
# GNU -size -1k keeps only empty files; 1k keeps 1..1024 bytes;
# +1k excludes a file of exactly 1024 bytes.
expr = parse_find_expression(["-size", "-1k"])
assert (expr.min_size, expr.max_size) == (None, 0)
expr = parse_find_expression(["-size", "1k"])
assert (expr.min_size, expr.max_size) == (1, 1024)
expr = parse_find_expression(["-size", "+1k"])
assert (expr.min_size, expr.max_size) == (1025, None)
def test_empty_expression_is_true():
assert parse_find_expression([]).tree == TrueNode()
def test_unknown_predicate_raises():
with pytest.raises(FindParseError):
parse_find_expression(["-bogus"])
with pytest.raises(FindParseError):
parse_find_expression(["-regex", ".*"])
def test_unbalanced_paren_raises():
with pytest.raises(FindParseError):
parse_find_expression(["(", "-name", "a"])
@pytest.mark.parametrize("tokens", [
["-maxdepth", "abc"],
["-mindepth", "x"],
["-size", ""],
["-size", "abc"],
["-mtime", ""],
])
def test_invalid_numeric_arg_raises_find_parse_error(tokens):
with pytest.raises(FindParseError):
parse_find_expression(tokens)
def _ent(name="a", kind="f"):
from mirage.commands.builtin.find_eval import FindEntry
return FindEntry(key="/" + name, name=name, kind=kind, depth=1)
@pytest.mark.parametrize("tokens", [
["-boguspredicate"],
["-regex", ".*deep.*"],
["-newer", "data/a.txt"],
["-prune"],
["-nam", "*.txt"],
])
def test_unsupported_predicate_raises(tokens):
with pytest.raises(FindParseError):
parse_find_expression(tokens)
@pytest.mark.parametrize("ftype", ["b", "c", "d", "p", "f", "l", "s"])
def test_valid_type_letters_accepted(ftype):
assert parse_find_expression(["-type", ftype]).tree == Type(ftype)
@pytest.mark.parametrize("ftype", ["x", "z", "dir"])
def test_invalid_type_letter_raises(ftype):
with pytest.raises(FindParseError):
parse_find_expression(["-type", ftype])
def test_deeply_nested_expression_raises_not_recursion_error():
tokens = ["("] * 500 + ["-name", "x"] + [")"] * 500
with pytest.raises(FindParseError):
parse_find_expression(tokens)
def test_deeply_nested_not_raises_not_recursion_error():
tokens = ["-not"] * 500 + ["-name", "x"]
with pytest.raises(FindParseError):
parse_find_expression(tokens)