"""Unit tests for `_inheritFlags` cascade-inherit helpers. Verifies: - getEffectiveFlag mode='walk': walks ancestors via path-prefix matching - getEffectiveFlag mode='aggregate': returns 'mixed' when subtree diverges - cascadeResetDescendants: bottom-up reset returning List[str] - cascadeResetDescendantsFds: same for FeatureDataSource - collectAncestorChain / collectAncestorChainFds: ancestor discovery - buildEffectiveByConnection / buildEffectiveByWorkspaceFds: batch compute """ from __future__ import annotations import unittest from typing import List from unittest.mock import MagicMock from modules.serviceCenter.services.serviceKnowledge import _inheritFlags def _ds(idVal: str, path: str, **flags) -> dict: """Build a DataSource dict with sensible defaults for a fixture.""" base = { "id": idVal, "connectionId": "conn-1", "sourceType": "sharepointFolder", "path": path, "neutralize": None, "ragIndexEnabled": None, "scope": None, } base.update(flags) return base def _fds(idVal: str, *, tableName: str, recordFilter=None, featureInstanceId="fi-1", **flags) -> dict: """Build a FeatureDataSource dict fixture. FDS records no longer carry `userId`, `workspaceInstanceId`, or `scope`; visibility/edit-permission live on the feature instance via RBAC. Tests should only set neutralize/ragIndexEnabled. """ base = { "id": idVal, "featureInstanceId": featureInstanceId, "tableName": tableName, "recordFilter": recordFilter, "neutralize": None, "ragIndexEnabled": None, } base.update(flags) return base # =========================================================================== # DataSource: getEffectiveFlag mode='walk' # =========================================================================== class TestEffectiveFlagWalk(unittest.TestCase): def test_explicit_own_value_wins(self): root = _ds("r", "/", neutralize=False) leaf = _ds("l", "/folder/sub", neutralize=True) self.assertTrue(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [root, leaf])) def test_inherits_from_root_when_own_is_none(self): root = _ds("r", "/", neutralize=True) leaf = _ds("l", "/folder/sub") self.assertTrue(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [root, leaf])) def test_default_false_when_chain_empty(self): leaf = _ds("l", "/folder/sub") self.assertFalse(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [leaf])) def test_nearest_ancestor_wins_over_distant(self): root = _ds("r", "/", neutralize=False) mid = _ds("m", "/folder", neutralize=True) leaf = _ds("l", "/folder/sub") self.assertTrue(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [root, mid, leaf])) def test_different_connection_ignored(self): otherConn = _ds("o", "/", connectionId="conn-2", neutralize=True) leaf = _ds("l", "/folder") self.assertFalse(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [otherConn, leaf])) def test_different_sourcetype_ignored(self): otherType = _ds("o", "/", sourceType="outlookFolder", neutralize=True) leaf = _ds("l", "/folder") self.assertFalse(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [otherType, leaf])) def test_path_separator_required(self): notAncestor = _ds("a", "/foo", neutralize=True) leaf = _ds("l", "/foobar") self.assertFalse(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [notAncestor, leaf])) def test_root_is_ancestor_of_everything(self): root = _ds("r", "/", neutralize=True) leaf = _ds("l", "/anything/anywhere") self.assertTrue(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [root, leaf])) def test_scope_inheritance_with_string_default(self): root = _ds("r", "/", scope="mandate") leaf = _ds("l", "/folder") self.assertEqual(_inheritFlags.getEffectiveFlag(leaf, "scope", [root, leaf]), "mandate") def test_scope_default_personal_when_empty(self): leaf = _ds("l", "/folder") self.assertEqual(_inheritFlags.getEffectiveFlag(leaf, "scope", [leaf]), "personal") def test_unknown_flag_raises(self): leaf = _ds("l", "/") with self.assertRaises(ValueError): _inheritFlags.getEffectiveFlag(leaf, "unknownFlag", [leaf]) def test_explicit_false_overrides_inherited_true(self): root = _ds("r", "/", neutralize=True) leaf = _ds("l", "/folder", neutralize=False) self.assertFalse(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [root, leaf])) def test_connection_root_inherits_cross_sourcetype(self): connRoot = _ds("conn", "/", sourceType="msft", neutralize=True) spService = _ds("sp", "/", sourceType="sharepointFolder") olService = _ds("ol", "/", sourceType="outlookFolder") allDs = [connRoot, spService, olService] self.assertTrue(_inheritFlags.getEffectiveFlag(spService, "neutralize", allDs)) self.assertTrue(_inheritFlags.getEffectiveFlag(olService, "neutralize", allDs)) def test_same_sourcetype_ancestor_wins_over_connection_root(self): connRoot = _ds("conn", "/", sourceType="msft", neutralize=True) spRoot = _ds("sp", "/", sourceType="sharepointFolder", neutralize=False) spLeaf = _ds("spl", "/sites/x", sourceType="sharepointFolder") self.assertFalse(_inheritFlags.getEffectiveFlag(spLeaf, "neutralize", [connRoot, spRoot, spLeaf])) def test_connection_root_does_not_self_inherit(self): connRoot = _ds("conn", "/", sourceType="msft") self.assertFalse(_inheritFlags.getEffectiveFlag(connRoot, "neutralize", [connRoot])) # =========================================================================== # DataSource: getEffectiveFlag mode='aggregate' # =========================================================================== class TestEffectiveFlagAggregate(unittest.TestCase): def test_leaf_without_descendants_returns_concrete(self): leaf = _ds("l", "/folder", neutralize=True) self.assertTrue(_inheritFlags.getEffectiveFlag(leaf, "neutralize", [leaf], mode="aggregate")) def test_all_descendants_same_returns_concrete(self): root = _ds("r", "/", neutralize=True) child1 = _ds("c1", "/a", neutralize=True) child2 = _ds("c2", "/b") # inherits True from root allDs = [root, child1, child2] self.assertTrue(_inheritFlags.getEffectiveFlag(root, "neutralize", allDs, mode="aggregate")) def test_divergent_descendants_returns_mixed(self): root = _ds("r", "/", neutralize=True) child1 = _ds("c1", "/a", neutralize=False) child2 = _ds("c2", "/b") # inherits True from root allDs = [root, child1, child2] self.assertEqual(_inheritFlags.getEffectiveFlag(root, "neutralize", allDs, mode="aggregate"), "mixed") def test_mixed_scope(self): root = _ds("r", "/", scope="personal") child1 = _ds("c1", "/a", scope="team") child2 = _ds("c2", "/b") # inherits personal from root allDs = [root, child1, child2] self.assertEqual(_inheritFlags.getEffectiveFlag(root, "scope", allDs, mode="aggregate"), "mixed") def test_all_scope_same_explicit_returns_concrete(self): root = _ds("r", "/", scope="team") child1 = _ds("c1", "/a", scope="team") child2 = _ds("c2", "/b") # inherits team allDs = [root, child1, child2] self.assertEqual(_inheritFlags.getEffectiveFlag(root, "scope", allDs, mode="aggregate"), "team") def test_connection_root_aggregate_cross_sourcetype(self): connRoot = _ds("conn", "/", sourceType="msft", neutralize=True) spExplicit = _ds("sp", "/", sourceType="sharepointFolder", neutralize=False) olInherit = _ds("ol", "/", sourceType="outlookFolder") # inherits True allDs = [connRoot, spExplicit, olInherit] self.assertEqual( _inheritFlags.getEffectiveFlag(connRoot, "neutralize", allDs, mode="aggregate"), "mixed", ) def test_mid_level_aggregate_only_considers_own_subtree(self): root = _ds("r", "/", neutralize=True) mid = _ds("m", "/folder", neutralize=True) midChild = _ds("mc", "/folder/sub", neutralize=True) sibling = _ds("s", "/other", neutralize=False) # not under mid allDs = [root, mid, midChild, sibling] # mid's subtree is just midChild(True) + mid(True) = uniform self.assertTrue(_inheritFlags.getEffectiveFlag(mid, "neutralize", allDs, mode="aggregate")) # root's subtree includes sibling(False) = mixed self.assertEqual( _inheritFlags.getEffectiveFlag(root, "neutralize", allDs, mode="aggregate"), "mixed", ) def test_walk_mode_never_returns_mixed(self): root = _ds("r", "/", neutralize=True) child = _ds("c", "/a", neutralize=False) allDs = [root, child] self.assertTrue(_inheritFlags.getEffectiveFlag(root, "neutralize", allDs, mode="walk")) # =========================================================================== # DataSource: cascadeResetDescendants (bottom-up, List[str]) # =========================================================================== class TestCascadeReset(unittest.TestCase): def _makeRootIf(self, dataSources: List[dict]): rootIf = MagicMock() rootIf.db.getRecordset = MagicMock(return_value=dataSources) modified = [] def _modify(model, recordId, fields): modified.append((recordId, fields)) rootIf.db.recordModify = MagicMock(side_effect=_modify) return rootIf, modified def test_returns_list_of_ids(self): parent = _ds("p", "/sites", neutralize=True) child = _ds("c1", "/sites/folder1", neutralize=False) rootIf, _ = self._makeRootIf([parent, child]) result = _inheritFlags.cascadeResetDescendants(rootIf, parent, "neutralize") self.assertIsInstance(result, list) self.assertEqual(result, ["c1"]) def test_resets_only_explicit_descendants(self): parent = _ds("p", "/sites", neutralize=True) explicitChild = _ds("c1", "/sites/folder1", neutralize=False) inheritChild = _ds("c2", "/sites/folder2") sibling = _ds("s", "/other", neutralize=True) rootIf, modified = self._makeRootIf([parent, explicitChild, inheritChild, sibling]) result = _inheritFlags.cascadeResetDescendants(rootIf, parent, "neutralize") self.assertEqual(result, ["c1"]) self.assertEqual(modified, [("c1", {"neutralize": None})]) def test_bottom_up_order(self): """Deepest items are reset first.""" parent = _ds("p", "/", neutralize=True) level1 = _ds("l1", "/a", neutralize=False) level2 = _ds("l2", "/a/b", neutralize=False) level3 = _ds("l3", "/a/b/c", neutralize=False) rootIf, modified = self._makeRootIf([parent, level1, level2, level3]) result = _inheritFlags.cascadeResetDescendants(rootIf, parent, "neutralize") self.assertEqual(result, ["l3", "l2", "l1"]) def test_deep_cascade_through_null_items(self): """null items are skipped (no DB write) but cascade continues deeper.""" parent = _ds("p", "/", neutralize=True) nullChild = _ds("n", "/a") # null — no write, but not a barrier deepExplicit = _ds("d", "/a/b", neutralize=False) rootIf, modified = self._makeRootIf([parent, nullChild, deepExplicit]) result = _inheritFlags.cascadeResetDescendants(rootIf, parent, "neutralize") self.assertEqual(result, ["d"]) self.assertEqual(modified, [("d", {"neutralize": None})]) def test_does_not_modify_parent(self): parent = _ds("p", "/", neutralize=True) child = _ds("c", "/a", neutralize=False) rootIf, modified = self._makeRootIf([parent, child]) _inheritFlags.cascadeResetDescendants(rootIf, parent, "neutralize") self.assertNotIn("p", [m[0] for m in modified]) def test_connection_root_cascades_cross_sourcetype(self): connRoot = _ds("conn", "/", sourceType="msft", neutralize=True) spExplicit = _ds("sp", "/", sourceType="sharepointFolder", neutralize=False) olInherit = _ds("ol", "/", sourceType="outlookFolder") spLeaf = _ds("sp-leaf", "/sites/x", sourceType="sharepointFolder", neutralize=True) rootIf, modified = self._makeRootIf([connRoot, spExplicit, olInherit, spLeaf]) result = _inheritFlags.cascadeResetDescendants(rootIf, connRoot, "neutralize") self.assertEqual(set(result), {"sp", "sp-leaf"}) # sp-leaf is deeper, should come first self.assertEqual(result[0], "sp-leaf") def test_does_not_cross_sourcetype_for_non_authority(self): parent = _ds("p", "/", neutralize=True, sourceType="sharepointFolder") otherType = _ds("o", "/anything", neutralize=False, sourceType="outlookFolder") rootIf, modified = self._makeRootIf([parent, otherType]) result = _inheritFlags.cascadeResetDescendants(rootIf, parent, "neutralize") self.assertEqual(result, []) def test_unknown_flag_raises(self): parent = _ds("p", "/", neutralize=True) rootIf, _ = self._makeRootIf([parent]) with self.assertRaises(ValueError): _inheritFlags.cascadeResetDescendants(rootIf, parent, "unknownFlag") # =========================================================================== # DataSource: collectAncestorChain # =========================================================================== class TestCollectAncestorChain(unittest.TestCase): def test_returns_nearest_first(self): root = _ds("r", "/", neutralize=True) mid = _ds("m", "/a") leaf = _ds("l", "/a/b") chain = _inheritFlags.collectAncestorChain(leaf, [root, mid, leaf]) self.assertEqual([_inheritFlags._getRecordValue(c, "id") for c in chain], ["m", "r"]) def test_connection_root_is_last(self): connRoot = _ds("conn", "/", sourceType="msft") spRoot = _ds("sp", "/", sourceType="sharepointFolder") spLeaf = _ds("spl", "/sub", sourceType="sharepointFolder") chain = _inheritFlags.collectAncestorChain(spLeaf, [connRoot, spRoot, spLeaf]) ids = [_inheritFlags._getRecordValue(c, "id") for c in chain] self.assertEqual(ids, ["sp", "conn"]) def test_root_has_no_ancestors(self): root = _ds("r", "/") chain = _inheritFlags.collectAncestorChain(root, [root]) self.assertEqual(chain, []) # =========================================================================== # DataSource: buildEffectiveByConnection # =========================================================================== class TestBuildEffectiveByConnection(unittest.TestCase): def test_walk_mode(self): root = _ds("r", "/", neutralize=True) child = _ds("c", "/a", neutralize=False) leaf = _ds("l", "/a/b") # inherits False from child result = _inheritFlags.buildEffectiveByConnection([root, child, leaf], "neutralize", mode="walk") self.assertEqual(result, {"r": True, "c": False, "l": False}) def test_aggregate_mode(self): root = _ds("r", "/", neutralize=True) child = _ds("c", "/a", neutralize=False) leaf = _ds("l", "/a/b") # inherits False from child result = _inheritFlags.buildEffectiveByConnection([root, child, leaf], "neutralize", mode="aggregate") self.assertEqual(result["r"], "mixed") self.assertEqual(result["c"], False) self.assertEqual(result["l"], False) # =========================================================================== # FeatureDataSource: getEffectiveFlagFds # =========================================================================== class TestFdsEffectiveFlagWalk(unittest.TestCase): def test_own_explicit_wins(self): ws = _fds("ws", tableName="*", neutralize=False) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}, neutralize=True) self.assertTrue(_inheritFlags.getEffectiveFlagFds(rec, "neutralize", [ws, rec])) def test_inherits_from_table_wildcard(self): tbl = _fds("t", tableName="Pos", neutralize=True) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) self.assertTrue(_inheritFlags.getEffectiveFlagFds(rec, "neutralize", [tbl, rec])) def test_table_wildcard_beats_workspace_wildcard(self): ws = _fds("ws", tableName="*", neutralize=False) tbl = _fds("t", tableName="Pos", neutralize=True) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) self.assertTrue(_inheritFlags.getEffectiveFlagFds(rec, "neutralize", [ws, tbl, rec])) def test_workspace_wildcard_inherits_when_no_table(self): ws = _fds("ws", tableName="*", neutralize=True) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) self.assertTrue(_inheritFlags.getEffectiveFlagFds(rec, "neutralize", [ws, rec])) def test_default_false_when_chain_empty(self): rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) self.assertFalse(_inheritFlags.getEffectiveFlagFds(rec, "neutralize", [rec])) def test_unknown_flag_raises(self): rec = _fds("r", tableName="*") with self.assertRaises(ValueError): _inheritFlags.getEffectiveFlagFds(rec, "doesNotExist", [rec]) class TestFdsEffectiveFlagAggregate(unittest.TestCase): def test_leaf_without_descendants(self): rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}, neutralize=True) self.assertTrue(_inheritFlags.getEffectiveFlagFds(rec, "neutralize", [rec], mode="aggregate")) def test_all_descendants_same(self): ws = _fds("ws", tableName="*", neutralize=True) tbl = _fds("t", tableName="Pos") # inherits True rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) # inherits True allFds = [ws, tbl, rec] self.assertTrue(_inheritFlags.getEffectiveFlagFds(ws, "neutralize", allFds, mode="aggregate")) def test_divergent_descendants_returns_mixed(self): ws = _fds("ws", tableName="*", neutralize=True) tbl = _fds("t", tableName="Pos", neutralize=False) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) # inherits False from tbl allFds = [ws, tbl, rec] self.assertEqual( _inheritFlags.getEffectiveFlagFds(ws, "neutralize", allFds, mode="aggregate"), "mixed", ) def test_table_aggregate_own_subtree_only(self): ws = _fds("ws", tableName="*", neutralize=True) tblA = _fds("tA", tableName="A", neutralize=True) recA = _fds("rA", tableName="A", recordFilter={"id": "1"}, neutralize=True) tblB = _fds("tB", tableName="B", neutralize=False) allFds = [ws, tblA, recA, tblB] # tblA subtree: all True self.assertTrue(_inheritFlags.getEffectiveFlagFds(tblA, "neutralize", allFds, mode="aggregate")) # ws subtree: mixed (tblB is False) self.assertEqual( _inheritFlags.getEffectiveFlagFds(ws, "neutralize", allFds, mode="aggregate"), "mixed", ) # =========================================================================== # FeatureDataSource: cascadeResetDescendantsFds (bottom-up, List[str]) # =========================================================================== class TestFdsCascadeReset(unittest.TestCase): def _makeRootIf(self, fdses): rootIf = MagicMock() rootIf.db.getRecordset = MagicMock(return_value=fdses) modified = [] def _modify(model, recordId, fields): modified.append((recordId, fields)) rootIf.db.recordModify = MagicMock(side_effect=_modify) return rootIf, modified def test_returns_list_of_ids(self): ws = _fds("ws", tableName="*", neutralize=True) tbl = _fds("t", tableName="Pos", neutralize=False) rootIf, _ = self._makeRootIf([ws, tbl]) result = _inheritFlags.cascadeResetDescendantsFds(rootIf, ws, "neutralize") self.assertIsInstance(result, list) self.assertEqual(result, ["t"]) def test_workspace_cascades_to_all_explicit_descendants(self): ws = _fds("ws", tableName="*", neutralize=True) tblExplicit = _fds("t", tableName="Pos", neutralize=False) tblInherit = _fds("t2", tableName="Other") recExplicit = _fds("r", tableName="Pos", recordFilter={"id": "1"}, neutralize=True) rootIf, modified = self._makeRootIf([ws, tblExplicit, tblInherit, recExplicit]) result = _inheritFlags.cascadeResetDescendantsFds(rootIf, ws, "neutralize") self.assertEqual(set(result), {"t", "r"}) # record is deeper (depth 2) than table (depth 1), should come first self.assertEqual(result[0], "r") def test_table_cascades_only_to_same_table_records(self): tbl = _fds("t", tableName="Pos", neutralize=True) recSame = _fds("r1", tableName="Pos", recordFilter={"id": "1"}, neutralize=False) recOther = _fds("r2", tableName="Other", recordFilter={"id": "1"}, neutralize=False) rootIf, modified = self._makeRootIf([tbl, recSame, recOther]) result = _inheritFlags.cascadeResetDescendantsFds(rootIf, tbl, "neutralize") self.assertEqual(result, ["r1"]) self.assertEqual(modified, [("r1", {"neutralize": None})]) def test_record_has_no_cascade(self): rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}, neutralize=True) rootIf, modified = self._makeRootIf([rec]) result = _inheritFlags.cascadeResetDescendantsFds(rootIf, rec, "neutralize") self.assertEqual(result, []) def test_unknown_flag_raises(self): ws = _fds("ws", tableName="*", neutralize=True) rootIf, _ = self._makeRootIf([ws]) with self.assertRaises(ValueError): _inheritFlags.cascadeResetDescendantsFds(rootIf, ws, "doesNotExist") # =========================================================================== # FeatureDataSource: collectAncestorChainFds # =========================================================================== class TestCollectAncestorChainFds(unittest.TestCase): def test_record_has_table_then_workspace(self): ws = _fds("ws", tableName="*") tbl = _fds("t", tableName="Pos") rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) chain = _inheritFlags.collectAncestorChainFds(rec, [ws, tbl, rec]) ids = [c["id"] for c in chain] self.assertEqual(ids, ["t", "ws"]) def test_table_has_only_workspace(self): ws = _fds("ws", tableName="*") tbl = _fds("t", tableName="Pos") chain = _inheritFlags.collectAncestorChainFds(tbl, [ws, tbl]) self.assertEqual([c["id"] for c in chain], ["ws"]) def test_workspace_has_no_ancestors(self): ws = _fds("ws", tableName="*") chain = _inheritFlags.collectAncestorChainFds(ws, [ws]) self.assertEqual(chain, []) # =========================================================================== # FeatureDataSource: buildEffectiveByWorkspaceFds # =========================================================================== class TestBuildEffectiveByWorkspaceFds(unittest.TestCase): def test_walk_mode(self): ws = _fds("ws", tableName="*", neutralize=True) tbl = _fds("t", tableName="Pos", neutralize=False) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) # inherits False from tbl result = _inheritFlags.buildEffectiveByWorkspaceFds([ws, tbl, rec], "neutralize", mode="walk") self.assertEqual(result, {"ws": True, "t": False, "r": False}) def test_aggregate_mode(self): ws = _fds("ws", tableName="*", neutralize=True) tbl = _fds("t", tableName="Pos", neutralize=False) rec = _fds("r", tableName="Pos", recordFilter={"id": "1"}) result = _inheritFlags.buildEffectiveByWorkspaceFds([ws, tbl, rec], "neutralize", mode="aggregate") self.assertEqual(result["ws"], "mixed") self.assertEqual(result["t"], False) self.assertEqual(result["r"], False) # =========================================================================== # resolveEffectiveForPath (with and without own record) # =========================================================================== class TestResolveEffectiveForPath(unittest.TestCase): def test_with_exact_record(self): root = _ds("r", "/", neutralize=True, scope="mandate", ragIndexEnabled=False) leaf = _ds("l", "/folder/sub", neutralize=False) allDs = [root, leaf] result = _inheritFlags.resolveEffectiveForPath("conn-1", "sharepointFolder", "/folder/sub", allDs) self.assertEqual(result["effectiveNeutralize"], False) self.assertEqual(result["effectiveScope"], "mandate") self.assertEqual(result["effectiveRagIndexEnabled"], False) def test_without_record_inherits_from_ancestor(self): root = _ds("r", "/", neutralize=True, scope="mandate", ragIndexEnabled=True) allDs = [root] result = _inheritFlags.resolveEffectiveForPath("conn-1", "sharepointFolder", "/deep/path/file.txt", allDs) self.assertEqual(result["effectiveNeutralize"], True) self.assertEqual(result["effectiveScope"], "mandate") self.assertEqual(result["effectiveRagIndexEnabled"], True) def test_without_record_inherits_from_closest_ancestor(self): root = _ds("r", "/", neutralize=True, ragIndexEnabled=True) mid = _ds("m", "/folder", neutralize=False, ragIndexEnabled=False) allDs = [root, mid] result = _inheritFlags.resolveEffectiveForPath("conn-1", "sharepointFolder", "/folder/sub/file.txt", allDs) self.assertEqual(result["effectiveNeutralize"], False) self.assertEqual(result["effectiveRagIndexEnabled"], False) def test_without_record_no_ancestors_returns_defaults(self): allDs: list = [] result = _inheritFlags.resolveEffectiveForPath("conn-1", "sharepointFolder", "/path", allDs) self.assertEqual(result["effectiveNeutralize"], False) self.assertEqual(result["effectiveScope"], "personal") self.assertEqual(result["effectiveRagIndexEnabled"], False) def test_connection_root_covers_service_subtree(self): connRoot = _ds("cr", "/", neutralize=True, sourceType="msft") allDs = [connRoot] result = _inheritFlags.resolveEffectiveForPath("conn-1", "sharepointFolder", "/sites/intranet", allDs) self.assertEqual(result["effectiveNeutralize"], True) def test_exact_record_with_aggregate_mixed(self): root = _ds("r", "/", neutralize=True) leaf = _ds("l", "/sub", neutralize=False) allDs = [root, leaf] result = _inheritFlags.resolveEffectiveForPath("conn-1", "sharepointFolder", "/", allDs, mode="aggregate") self.assertEqual(result["effectiveNeutralize"], "mixed") class TestResolveEffectiveForFds(unittest.TestCase): """FDS records carry only `neutralize` + `ragIndexEnabled`. No scope. `resolveEffectiveForFds` therefore returns a two-key dict; tests must not assert anything about `effectiveScope` on FDS results. """ def test_with_exact_record(self): ws = _fds("ws", tableName="*", neutralize=True) tbl = _fds("t", tableName="Pos", neutralize=False) allFds = [ws, tbl] result = _inheritFlags.resolveEffectiveForFds("fi-1", "Pos", None, allFds) self.assertEqual(result["effectiveNeutralize"], False) self.assertEqual(result["effectiveRagIndexEnabled"], False) self.assertNotIn("effectiveScope", result) def test_without_record_inherits_from_feature_wildcard(self): ws = _fds("ws", tableName="*", neutralize=True, ragIndexEnabled=True) allFds = [ws] result = _inheritFlags.resolveEffectiveForFds("fi-1", "Unknown", None, allFds) self.assertEqual(result["effectiveNeutralize"], True) self.assertEqual(result["effectiveRagIndexEnabled"], True) def test_without_record_no_ancestors_returns_defaults(self): allFds: list = [] result = _inheritFlags.resolveEffectiveForFds("fi-1", "Pos", None, allFds) self.assertEqual(result["effectiveNeutralize"], False) self.assertEqual(result["effectiveRagIndexEnabled"], False) def test_rag_inherits_when_table_overrides_neutralize_only(self): """Tables that override only neutralize must still inherit RAG from parent.""" ws = _fds("ws", tableName="*", ragIndexEnabled=True) tbl = _fds("t", tableName="Pos", neutralize=False) allFds = [ws, tbl] result = _inheritFlags.resolveEffectiveForFds("fi-1", "Pos", None, allFds) self.assertEqual(result["effectiveRagIndexEnabled"], True) def test_rag_aggregate_mixed_when_descendants_diverge(self): ws = _fds("ws", tableName="*", ragIndexEnabled=True) tbl = _fds("t", tableName="Pos", ragIndexEnabled=False) allFds = [ws, tbl] result = _inheritFlags.resolveEffectiveForFds("fi-1", "*", None, allFds, mode="aggregate") self.assertEqual(result["effectiveRagIndexEnabled"], "mixed") def test_inheritable_fds_flags_excludes_scope(self): self.assertIn("ragIndexEnabled", _inheritFlags._INHERITABLE_FDS_FLAGS) self.assertIn("neutralize", _inheritFlags._INHERITABLE_FDS_FLAGS) self.assertNotIn("scope", _inheritFlags._INHERITABLE_FDS_FLAGS) # =========================================================================== # FDS cascade resets RAG (in addition to neutralize and scope) # =========================================================================== class TestCascadeResetFdsRag(unittest.TestCase): def test_cascade_resets_rag_on_descendants(self): ws = _fds("ws", tableName="*") tbl = _fds("t", tableName="Pos", ragIndexEnabled=False) allFds = [ws, tbl] rootIf = MagicMock() rootIf.db.getRecordset.return_value = allFds rootIf.db.recordModify = MagicMock() result = _inheritFlags.cascadeResetDescendantsFds(rootIf, ws, "ragIndexEnabled") self.assertIn("t", result) rootIf.db.recordModify.assert_called() # =========================================================================== # Path normalization # =========================================================================== class TestPathNormalization(unittest.TestCase): def test_empty_path_normalises_to_root(self): self.assertEqual(_inheritFlags._normalisePath(""), "/") self.assertEqual(_inheritFlags._normalisePath(None), "/") def test_trailing_slash_stripped(self): self.assertEqual(_inheritFlags._normalisePath("/foo/"), "/foo") self.assertEqual(_inheritFlags._normalisePath("/"), "/") def test_leading_slash_added(self): self.assertEqual(_inheritFlags._normalisePath("foo/bar"), "/foo/bar") # =========================================================================== # Virtual coordinates (no DB record) must support aggregate mode (mixed) # =========================================================================== class TestVirtualCoordAggregate(unittest.TestCase): """After the spec-recovery fix, resolveEffectiveForPath/Fds with mode='aggregate' must return 'mixed' for coordinates that have no DB record but whose descendants in the DB diverge.""" def test_virtual_folder_mixed_neutralize(self): child1 = _ds("c1", "/virtual/a", neutralize=True) child2 = _ds("c2", "/virtual/b", neutralize=False) allDs = [child1, child2] result = _inheritFlags.resolveEffectiveForPath( "conn-1", "sharepointFolder", "/virtual", allDs, mode="aggregate", ) self.assertEqual(result["effectiveNeutralize"], "mixed") def test_virtual_folder_mixed_scope(self): child1 = _ds("c1", "/virtual/a", scope="mandate") child2 = _ds("c2", "/virtual/b", scope="personal") allDs = [child1, child2] result = _inheritFlags.resolveEffectiveForPath( "conn-1", "sharepointFolder", "/virtual", allDs, mode="aggregate", ) self.assertEqual(result["effectiveScope"], "mixed") def test_virtual_folder_mixed_rag(self): child1 = _ds("c1", "/virtual/a", ragIndexEnabled=True) child2 = _ds("c2", "/virtual/b", ragIndexEnabled=False) allDs = [child1, child2] result = _inheritFlags.resolveEffectiveForPath( "conn-1", "sharepointFolder", "/virtual", allDs, mode="aggregate", ) self.assertEqual(result["effectiveRagIndexEnabled"], "mixed") def test_virtual_folder_uniform_returns_concrete(self): child1 = _ds("c1", "/virtual/a", neutralize=True) child2 = _ds("c2", "/virtual/b", neutralize=True) allDs = [child1, child2] result = _inheritFlags.resolveEffectiveForPath( "conn-1", "sharepointFolder", "/virtual", allDs, mode="aggregate", ) self.assertTrue(result["effectiveNeutralize"]) def test_virtual_fds_workspace_mixed_neutralize(self): tblA = _fds("tA", tableName="A", neutralize=True) tblB = _fds("tB", tableName="B", neutralize=False) allFds = [tblA, tblB] result = _inheritFlags.resolveEffectiveForFds( "fi-1", "*", None, allFds, mode="aggregate", ) self.assertEqual(result["effectiveNeutralize"], "mixed") def test_virtual_fds_workspace_uniform_returns_concrete(self): tblA = _fds("tA", tableName="A", neutralize=True) tblB = _fds("tB", tableName="B", neutralize=True) allFds = [tblA, tblB] result = _inheritFlags.resolveEffectiveForFds( "fi-1", "*", None, allFds, mode="aggregate", ) self.assertTrue(result["effectiveNeutralize"]) def test_virtual_connection_root_mixed_via_services(self): """Connection root (authority sourceType, path='/') with no DB record but services that diverge must return 'mixed'.""" spRecord = _ds("sp", "/", sourceType="sharepointFolder", neutralize=True) olRecord = _ds("ol", "/", sourceType="outlookFolder", neutralize=False) allDs = [spRecord, olRecord] result = _inheritFlags.resolveEffectiveForPath( "conn-1", "msft", "/", allDs, mode="aggregate", ) self.assertEqual(result["effectiveNeutralize"], "mixed") if __name__ == "__main__": unittest.main()