Files
IfcOpenShell/src/ifcquery/tests/test_relations.py
T
Bruno Postle 1c26ee86c9 ifcquery/ifcedit: enable shell scripting by composing query and edit commands
Add --format ids to ifcquery to output step IDs suitable for piping into
ifcedit parameters. Add ifcedit foreach to apply an operation to every
element in a query result. Extend clash and relations output so --format ids
extracts all involved element IDs, enabling one-liners like clash detection
piped directly into render.

Generated with the assistance of an AI coding tool.
2026-03-29 15:17:22 +01:00

200 lines
7.0 KiB
Python

# This file was generated with the assistance of an AI coding tool.
import json
import os
import subprocess
import sys
import tempfile
from ifcquery.relations import relations
class TestWallRelations:
def test_wall_has_container(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
assert result["id"] == wall.id()
assert result["type"] == "IfcWall"
assert result["hierarchy"]["container"]["type"] == "IfcBuildingStorey"
assert result["hierarchy"]["container"]["name"] == "Ground Floor"
def test_wall_has_parent(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
assert result["hierarchy"]["parent"]["type"] == "IfcBuildingStorey"
def test_wall_no_children(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
assert "children" not in result
def test_wall_empty_categories_omitted(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
assert "groups" not in result
assert "systems" not in result
assert "zones" not in result
assert "connections" not in result
assert "referenced_structures" not in result
class TestStoreyRelations:
def test_storey_has_contained(self, model):
storey = model.by_type("IfcBuildingStorey")[0]
result = relations(model, storey)
contained_types = {e["type"] for e in result["children"]["contained"]}
assert "IfcWall" in contained_types
assert "IfcSlab" in contained_types
def test_storey_has_aggregate_parent(self, model):
storey = model.by_type("IfcBuildingStorey")[0]
result = relations(model, storey)
assert result["hierarchy"]["aggregate"]["type"] == "IfcBuilding"
assert result["hierarchy"]["aggregate"]["name"] == "TestBuilding"
class TestProjectRelations:
def test_project_has_parts(self, model):
project = model.by_type("IfcProject")[0]
result = relations(model, project)
parts = result["children"]["parts"]
assert any(p["type"] == "IfcSite" for p in parts)
def test_project_no_hierarchy(self, model):
project = model.by_type("IfcProject")[0]
result = relations(model, project)
assert "hierarchy" not in result
class TestTraverseUp:
def test_wall_to_project(self, model):
wall = model.by_type("IfcWall")[0]
chain = relations(model, wall, traverse="up")
assert isinstance(chain, list)
assert chain[0]["type"] == "IfcWall"
assert chain[-1]["type"] == "IfcProject"
types = [e["type"] for e in chain]
assert "IfcBuildingStorey" in types
assert "IfcBuilding" in types
assert "IfcSite" in types
def test_project_traverse(self, model):
project = model.by_type("IfcProject")[0]
chain = relations(model, project, traverse="up")
assert len(chain) == 1
assert chain[0]["type"] == "IfcProject"
def test_storey_to_project(self, model):
storey = model.by_type("IfcBuildingStorey")[0]
chain = relations(model, storey, traverse="up")
assert chain[0]["type"] == "IfcBuildingStorey"
assert chain[-1]["type"] == "IfcProject"
assert len(chain) == 4 # storey -> building -> site -> project
class TestElementsSummary:
def test_wall_elements_includes_self(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
ids = [e["id"] for e in result["elements"]]
assert wall.id() in ids
def test_wall_elements_includes_container(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
ids = [e["id"] for e in result["elements"]]
storey = model.by_type("IfcBuildingStorey")[0]
assert storey.id() in ids
def test_storey_elements_includes_contained(self, model):
storey = model.by_type("IfcBuildingStorey")[0]
result = relations(model, storey)
ids = [e["id"] for e in result["elements"]]
wall = model.by_type("IfcWall")[0]
assert wall.id() in ids
def test_elements_no_duplicates(self, model):
storey = model.by_type("IfcBuildingStorey")[0]
result = relations(model, storey)
ids = [e["id"] for e in result["elements"]]
assert len(ids) == len(set(ids))
def test_elements_all_have_id_and_type(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
for e in result["elements"]:
assert "id" in e
assert "type" in e
def test_traverse_up_has_no_elements_field(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall, traverse="up")
assert isinstance(result, list)
assert not any("elements" in item for item in result)
class TestJsonSerializable:
def test_relations_serializable(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall)
json.dumps(result)
def test_traverse_serializable(self, model):
wall = model.by_type("IfcWall")[0]
result = relations(model, wall, traverse="up")
json.dumps(result)
class TestCLI:
@staticmethod
def _ifc_path(model):
f = tempfile.NamedTemporaryFile(suffix=".ifc", delete=False)
model.write(f.name)
f.close()
return f.name
def test_relations_json(self, model):
path = self._ifc_path(model)
try:
wall = model.by_type("IfcWall")[0]
result = subprocess.run(
[sys.executable, "-m", "ifcquery", path, "relations", str(wall.id())],
capture_output=True,
text=True,
)
assert result.returncode == 0
data = json.loads(result.stdout)
assert data["type"] == "IfcWall"
assert "hierarchy" in data
finally:
os.unlink(path)
def test_relations_traverse_up(self, model):
path = self._ifc_path(model)
try:
wall = model.by_type("IfcWall")[0]
result = subprocess.run(
[sys.executable, "-m", "ifcquery", path, "relations", str(wall.id()), "--traverse", "up"],
capture_output=True,
text=True,
)
assert result.returncode == 0
data = json.loads(result.stdout)
assert isinstance(data, list)
assert data[0]["type"] == "IfcWall"
assert data[-1]["type"] == "IfcProject"
finally:
os.unlink(path)
def test_relations_bad_id(self, model):
path = self._ifc_path(model)
try:
result = subprocess.run(
[sys.executable, "-m", "ifcquery", path, "relations", "999999"],
capture_output=True,
text=True,
)
assert result.returncode != 0
assert "Error" in result.stderr
finally:
os.unlink(path)