|
1 | | -# |
2 | | -# Copyright (c) 2024 Joshua Watt |
3 | | -# |
| 1 | +# SPDX-FileContributor: Stefano Tondo |
| 2 | +# SPDX-FileContributor: Joshua Watt |
| 3 | +# SPDX-FileContributor: Arthit Suriyawongkul |
| 4 | +# SPDX-FileCopyrightText: 2026 Joshua Watt |
| 5 | +# SPDX-FileType: SOURCE |
4 | 6 | # SPDX-License-Identifier: MIT |
5 | 7 |
|
6 | 8 | import json |
|
12 | 14 | import pytest |
13 | 15 |
|
14 | 16 | from testfixtures import jsonvalidation, timetests |
| 17 | +from shacl2code.lang.rust import ( |
| 18 | + is_effectively_extensible, |
| 19 | + prop_ctx_name, |
| 20 | + prop_defining_class, |
| 21 | + type_name, |
| 22 | + varname, |
| 23 | +) |
15 | 24 |
|
16 | 25 | THIS_FILE = Path(__file__) |
17 | 26 | THIS_DIR = THIS_FILE.parent |
@@ -709,3 +718,71 @@ def test_extensible_context(compile_test, roundtrip): |
709 | 718 | "Missing extension property"); |
710 | 719 | """, |
711 | 720 | ) |
| 721 | + |
| 722 | + |
| 723 | +# --- Unit tests for shacl2code.lang.rust helper functions --- |
| 724 | + |
| 725 | + |
| 726 | +class _Prop: |
| 727 | + def __init__(self, path, varname=None): |
| 728 | + self.path = path |
| 729 | + self.varname = varname if varname is not None else path |
| 730 | + |
| 731 | + |
| 732 | +class _Class: |
| 733 | + def __init__(self, cid, prop_paths=(), parent_ids=(), is_extensible=False): |
| 734 | + self.clsname = [cid] |
| 735 | + self.properties = [_Prop(p) for p in prop_paths] |
| 736 | + self.parent_ids = list(parent_ids) |
| 737 | + self.is_extensible = is_extensible |
| 738 | + |
| 739 | + |
| 740 | +class _Classes: |
| 741 | + def __init__(self, *classes): |
| 742 | + self._map = {c.clsname[0]: c for c in classes} |
| 743 | + |
| 744 | + def get(self, cid): |
| 745 | + return self._map[cid] |
| 746 | + |
| 747 | + |
| 748 | +def test_varname_empty_becomes_field(): |
| 749 | + assert varname("") == "field" |
| 750 | + |
| 751 | + |
| 752 | +def test_varname_rust_keyword_gets_raw_prefix(): |
| 753 | + assert varname("type") == "r#type" |
| 754 | + assert varname("self") == "r#self" |
| 755 | + |
| 756 | + |
| 757 | +def test_type_name_empty_becomes_type(): |
| 758 | + assert type_name("") == "Type" |
| 759 | + assert type_name("_") == "Type" |
| 760 | + |
| 761 | + |
| 762 | +def test_prop_defining_class_returns_none_when_not_found(): |
| 763 | + cls_a = _Class("A", prop_paths=["prop1"]) |
| 764 | + cls_b = _Class("B", parent_ids=["A"]) |
| 765 | + classes = _Classes(cls_a, cls_b) |
| 766 | + # prop2 is not defined in A or B |
| 767 | + result = prop_defining_class(cls_b, _Prop("prop2"), classes) |
| 768 | + assert result is None |
| 769 | + |
| 770 | + |
| 771 | +def test_is_effectively_extensible_false_when_no_ancestor_extensible(): |
| 772 | + cls_a = _Class("A", is_extensible=False) |
| 773 | + cls_b = _Class("B", parent_ids=["A"], is_extensible=False) |
| 774 | + classes = _Classes(cls_a, cls_b) |
| 775 | + assert is_effectively_extensible(cls_b, classes) is False |
| 776 | + |
| 777 | + |
| 778 | +def test_is_effectively_extensible_true_via_ancestor(): |
| 779 | + cls_a = _Class("A", is_extensible=True) |
| 780 | + cls_b = _Class("B", parent_ids=["A"], is_extensible=False) |
| 781 | + classes = _Classes(cls_a, cls_b) |
| 782 | + assert is_effectively_extensible(cls_b, classes) is True |
| 783 | + |
| 784 | + |
| 785 | +def test_prop_ctx_name(): |
| 786 | + cls_a = _Class("A") |
| 787 | + prop = _Prop("prop1", varname="prop1") |
| 788 | + assert prop_ctx_name(cls_a, prop) == "a_prop1_ctx" |
0 commit comments