@@ -81,6 +81,46 @@ public void forNamespaceReturnsSameInstanceWhenNoEntriesAreRestricted() {
8181 assertThat (filtered ).isSameAs (original );
8282 }
8383
84+ @ Test
85+ public void forNamespaceMemoizesResultForRepeatedCalls () {
86+ final Policy policy = PoliciesModelFactory .newPolicyBuilder (PolicyId .of ("test:policy" ))
87+ .set (newScopedEntry ("restricted" , "google:tenant-user" ,
88+ Arrays .asList ("com.acme" , "com.acme.*" )))
89+ .set (newScopedEntry ("global" , "google:global-user" , Collections .emptyList ()))
90+ .build ();
91+ final PolicyEnforcer original = PolicyEnforcer .of (policy );
92+
93+ // "org.example" filters out the restricted entry, so a new (filtered) enforcer is built the first
94+ // time. A second call for the same namespace must return the memoized instance, not rebuild the tree.
95+ final PolicyEnforcer first = original .forNamespace ("org.example" );
96+ final PolicyEnforcer second = original .forNamespace ("org.example" );
97+
98+ assertThat (first ).isNotSameAs (original );
99+ assertThat (second ).isSameAs (first );
100+ }
101+
102+ @ Test
103+ public void forNamespaceReturnsDistinctEnforcersForDistinctNamespaces () {
104+ final Policy policy = PoliciesModelFactory .newPolicyBuilder (PolicyId .of ("test:policy" ))
105+ .set (newScopedEntry ("restricted" , "google:tenant-user" ,
106+ Arrays .asList ("com.acme" , "com.acme.*" )))
107+ .set (newScopedEntry ("global" , "google:global-user" , Collections .emptyList ()))
108+ .build ();
109+ final PolicyEnforcer original = PolicyEnforcer .of (policy );
110+
111+ // "org.example" excludes the restricted entry; "com.acme.vehicles" keeps it.
112+ final PolicyEnforcer excluding = original .forNamespace ("org.example" );
113+ final PolicyEnforcer including = original .forNamespace ("com.acme.vehicles" );
114+
115+ assertThat (excluding ).isNotSameAs (including );
116+ assertThat (excluding .getEnforcer ().getSubjectsWithUnrestrictedPermission (
117+ PoliciesResourceType .thingResource ("/" ), Permission .READ ))
118+ .doesNotContain (AuthorizationSubject .newInstance ("google:tenant-user" ));
119+ assertThat (including .getEnforcer ().getSubjectsWithUnrestrictedPermission (
120+ PoliciesResourceType .thingResource ("/" ), Permission .READ ))
121+ .contains (AuthorizationSubject .newInstance ("google:tenant-user" ));
122+ }
123+
84124 @ Test
85125 public void forNamespaceWithNullPolicyReturnsSameInstance () {
86126 final PolicyEnforcer enforcer = PolicyEnforcer .embed (
0 commit comments