generated from coulomb/repo-seed
222 lines
6.0 KiB
Python
222 lines
6.0 KiB
Python
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from infospace_bench import InfospaceError, add_artifact, create_infospace
|
|
from infospace_bench.semantics import (
|
|
list_entities,
|
|
list_relations,
|
|
parse_entity_artifact,
|
|
parse_relation_artifact,
|
|
)
|
|
|
|
|
|
ENTITY = """# Division of Labour
|
|
|
|
## Definition
|
|
|
|
Increasing productivity by splitting work into specialized tasks.
|
|
|
|
## Source Chapter
|
|
|
|
Book I, Chapter 1
|
|
|
|
## Context
|
|
|
|
Smith introduces the pin factory as an example of this mechanism.
|
|
|
|
## Economic Domain
|
|
|
|
Production
|
|
|
|
## Original Wording
|
|
|
|
The greatest improvement in the productive powers of labour.
|
|
|
|
## Modern Interpretation
|
|
|
|
Specialization improves throughput by reducing switching costs.
|
|
"""
|
|
|
|
|
|
INVALID_ENTITY = """# Thin Entity
|
|
|
|
## Context
|
|
|
|
This artifact is missing its definition.
|
|
"""
|
|
|
|
|
|
RELATION = """# Division of Labour enables Market Extent
|
|
|
|
## Subject
|
|
|
|
Division of Labour
|
|
|
|
## Predicate
|
|
|
|
is limited by
|
|
|
|
## Object
|
|
|
|
Market Extent
|
|
|
|
## Relation Type
|
|
|
|
constrains
|
|
|
|
## VSM Channel
|
|
|
|
S1 -> S4
|
|
|
|
## Evidence
|
|
|
|
Book I, Chapter 3 connects specialization to market size.
|
|
|
|
## Feedback Role
|
|
|
|
Part of the market expansion loop.
|
|
"""
|
|
|
|
|
|
def cli_env() -> dict[str, str]:
|
|
env = os.environ.copy()
|
|
env["PYTHONPATH"] = "src:/home/worsch/markitect-tool/src"
|
|
return env
|
|
|
|
|
|
def test_parse_entity_artifact_extracts_legacy_sections(tmp_path: Path) -> None:
|
|
path = tmp_path / "division.md"
|
|
path.write_text(ENTITY, encoding="utf-8")
|
|
|
|
entity = parse_entity_artifact("entity/division.md", path)
|
|
|
|
assert entity.artifact_id == "entity/division.md"
|
|
assert entity.slug == "division-of-labour"
|
|
assert entity.title == "Division of Labour"
|
|
assert entity.definition_word_count == 8
|
|
assert entity.domain == "Production"
|
|
assert entity.has_original_wording is True
|
|
assert entity.section_slugs == [
|
|
"definition",
|
|
"source-chapter",
|
|
"context",
|
|
"economic-domain",
|
|
"original-wording",
|
|
"modern-interpretation",
|
|
]
|
|
|
|
|
|
def test_parse_entity_artifact_reports_missing_required_sections(tmp_path: Path) -> None:
|
|
path = tmp_path / "thin.md"
|
|
path.write_text(INVALID_ENTITY, encoding="utf-8")
|
|
|
|
with pytest.raises(InfospaceError) as raised:
|
|
parse_entity_artifact("entity/thin.md", path)
|
|
|
|
assert raised.value.code == "invalid_entity_artifact"
|
|
assert raised.value.detail["missing_sections"] == ["definition"]
|
|
|
|
|
|
def test_parse_relation_artifact_links_entity_endpoints(tmp_path: Path) -> None:
|
|
path = tmp_path / "relation.md"
|
|
path.write_text(RELATION, encoding="utf-8")
|
|
entity_ids = {
|
|
"division-of-labour": "entity/division.md",
|
|
"market-extent": "entity/market.md",
|
|
}
|
|
|
|
relation = parse_relation_artifact("relation/division-market.md", path, entity_ids)
|
|
|
|
assert relation.slug == "division-of-labour-enables-market-extent"
|
|
assert relation.subject_slug == "division-of-labour"
|
|
assert relation.object_slug == "market-extent"
|
|
assert relation.subject_entity_id == "entity/division.md"
|
|
assert relation.object_entity_id == "entity/market.md"
|
|
assert relation.is_feedback_member is True
|
|
|
|
|
|
def test_parse_relation_artifact_reports_unresolved_endpoint(tmp_path: Path) -> None:
|
|
path = tmp_path / "relation.md"
|
|
path.write_text(RELATION, encoding="utf-8")
|
|
|
|
with pytest.raises(InfospaceError) as raised:
|
|
parse_relation_artifact("relation/division-market.md", path, {})
|
|
|
|
assert raised.value.code == "unresolved_relation_endpoint"
|
|
assert raised.value.detail["missing_slugs"] == [
|
|
"division-of-labour",
|
|
"market-extent",
|
|
]
|
|
|
|
|
|
def test_list_entities_and_relations_from_manifest(tmp_path: Path) -> None:
|
|
infospace = create_infospace(tmp_path, "pilot", name="Pilot")
|
|
division = tmp_path / "division.md"
|
|
division.write_text(ENTITY, encoding="utf-8")
|
|
market = tmp_path / "market.md"
|
|
market.write_text(
|
|
ENTITY.replace("Division of Labour", "Market Extent").replace(
|
|
"Production", "Exchange"
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
relation = tmp_path / "relation.md"
|
|
relation.write_text(RELATION, encoding="utf-8")
|
|
|
|
add_artifact(infospace.root, division, kind="entity", title="Division")
|
|
add_artifact(infospace.root, market, kind="entity", title="Market")
|
|
add_artifact(infospace.root, relation, kind="relation", title="Relation")
|
|
|
|
assert [entity.slug for entity in list_entities(infospace.root)] == [
|
|
"division-of-labour",
|
|
"market-extent",
|
|
]
|
|
assert [item.relation_type for item in list_relations(infospace.root)] == [
|
|
"constrains"
|
|
]
|
|
|
|
|
|
def test_cli_entities_and_relations_output_json(tmp_path: Path) -> None:
|
|
infospace = create_infospace(tmp_path, "pilot", name="Pilot")
|
|
division = tmp_path / "division.md"
|
|
division.write_text(ENTITY, encoding="utf-8")
|
|
market = tmp_path / "market.md"
|
|
market.write_text(
|
|
ENTITY.replace("Division of Labour", "Market Extent").replace(
|
|
"Production", "Exchange"
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
relation = tmp_path / "relation.md"
|
|
relation.write_text(RELATION, encoding="utf-8")
|
|
add_artifact(infospace.root, division, kind="entity", title="Division")
|
|
add_artifact(infospace.root, market, kind="entity", title="Market")
|
|
add_artifact(infospace.root, relation, kind="relation", title="Relation")
|
|
|
|
entities = subprocess.run(
|
|
[sys.executable, "-m", "infospace_bench", "entities", str(infospace.root)],
|
|
check=False,
|
|
env=cli_env(),
|
|
text=True,
|
|
capture_output=True,
|
|
)
|
|
relations = subprocess.run(
|
|
[sys.executable, "-m", "infospace_bench", "relations", str(infospace.root)],
|
|
check=False,
|
|
env=cli_env(),
|
|
text=True,
|
|
capture_output=True,
|
|
)
|
|
|
|
assert entities.returncode == 0, entities.stderr
|
|
assert relations.returncode == 0, relations.stderr
|
|
assert json.loads(entities.stdout)["entities"][0]["slug"] == "division-of-labour"
|
|
assert json.loads(relations.stdout)["relations"][0]["subject_entity_id"] == (
|
|
"entity/division.md"
|
|
)
|