Skip to content

Commit

Permalink
feat: support add generic type custom function (#365)
Browse files Browse the repository at this point in the history
* feat: support add generic type custom function

* fix: not support .NET 4.5.2

* fix: indeterminate sorting of GetImplicitRolesForUser
  • Loading branch information
Taoyuesong authored Sep 3, 2024
1 parent 6be2f80 commit fe66cd4
Show file tree
Hide file tree
Showing 84 changed files with 149 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Casbin.Benchmark/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public static class TestHelper
{
public static string GetTestFilePath(string fileName)
{
return Path.Combine("examples", fileName);
return Path.Combine("Examples", fileName);
}
}
}
2 changes: 1 addition & 1 deletion Casbin.UnitTests/Casbin.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>net9.0;net8.0;net7.0;net6.0;net5.0;netcoreapp3.1;net462;net461;net452</TargetFrameworks>
<DebugType>full</DebugType>
<IsPackable>false</IsPackable>
<LangVersion>10.0</LangVersion>
<LangVersion>latest</LangVersion>
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
</PropertyGroup>

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
69 changes: 69 additions & 0 deletions Casbin.UnitTests/GenericTests/GenericFunctionTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using Casbin.Model;
using Casbin.UnitTests.Util;
using DynamicExpresso;
using Xunit;

namespace Casbin.UnitTests.GenericTests;

public class GenericFunctionTest
{
[Fact]
public void TestGenericFunction()
{
Interpreter interpreter = new();
RequestValues<string, int> r = Request.CreateValues("A", 1);
PolicyValues<string, int> p = Policy.CreateValues("A", 1);
interpreter.SetFunction("equal", new Func<string, string, bool>(
(a, b) => a == b)
);
interpreter.SetFunction("equal", new Func<int, int, bool>(
(a, b) => a == b)
);

Func<RequestValues<string, int>, PolicyValues<string, int>, bool> func1 =
ExpressionUtil.Compile(interpreter, "equal(r.Value2, p.Value2) && equal(r.Value2, p.Value2)",
nameof(r), in r, nameof(p), in p);

Assert.True(func1(Request.CreateValues("A", 1), Policy.CreateValues("A", 1)));
Assert.False(func1(Request.CreateValues("A", 1), Policy.CreateValues("A", 2)));
Assert.False(func1(Request.CreateValues("B", 1), Policy.CreateValues("B", 2)));
}

#if !NET452
[Fact]
public void TestGenericFunctionModel()
{
Enforcer e = new Enforcer(DefaultModel.NewModelFromText(
"""
[request_definition]
r = obj1, obj2

[policy_definition]
p = _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = max(r.obj1, r.obj2) > 2
"""));

e.AddFunction("max", new Func<int, int, int>(
// ReSharper disable once ConvertClosureToMethodGroup
(a, b) => Math.Max(a, b)
));
Assert.True(e.Enforce(1, 3));
Assert.False(e.Enforce(1, 2));
Assert.False(e.Enforce("1", "111"));

e.AddFunction("max", new Func<string, string, int>(
(a, b) => Math.Max(a.Length, b.Length)
));
Assert.True(e.Enforce(1, 3));
Assert.False(e.Enforce(1, 2));
Assert.True(e.Enforce("1", "111"));
}
#endif

}
29 changes: 11 additions & 18 deletions Casbin.UnitTests/GenericTests/GenericMatcherTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using Casbin.Evaluation;
using Casbin.Model;
using Casbin.UnitTests.Util;
using DynamicExpresso;
using Xunit;

Expand All @@ -10,37 +12,28 @@ public class GenericMatcherTest
[Fact]
public void TestGenericMatcher()
{
Interpreter interpreter = new();
RequestValues<string, int> r = Request.CreateValues("A", 1);
PolicyValues<string, int> p = Policy.CreateValues("A", 1);
Func<RequestValues<string, int>, PolicyValues<string, int>, bool> func1 = Compile(
"r.Value1 == p.Value1 && r.Value2 == p.Value2",
nameof(r), in r, nameof(p), in p);
Func<RequestValues<string, int>, PolicyValues<string, int>, bool> func1 =
ExpressionUtil.Compile(interpreter, "r.Value1 == p.Value1 && r.Value2 == p.Value2",
nameof(r), in r, nameof(p), in p);

Assert.True(func1(Request.CreateValues("A", 1), Policy.CreateValues("A", 1)));
Assert.False(func1(Request.CreateValues("A", 1), Policy.CreateValues("A", 2)));
Assert.False(func1(Request.CreateValues("B", 1), Policy.CreateValues("B", 2)));

RequestValues<string, int, string> r2 = Request.CreateValues("A", 1, "read");
PolicyValues<string, int, string> p2 = Policy.CreateValues("A", 1, "read");
Func<RequestValues<string, int, string>, PolicyValues<string, int, string>, bool> func2 = Compile(
"r2.Value1 == p2.Value1 && r2.Value2 == p2.Value2 && r2.Value3 == p2.Value3",
nameof(r2), in r2, nameof(p2), in p2);
Func<RequestValues<string, int, string>, PolicyValues<string, int, string>, bool> func2 =
ExpressionUtil.Compile(interpreter, "r2.Value1 == p2.Value1 && r2.Value2 == p2.Value2 && r2.Value3 == p2.Value3",
nameof(r2), in r2, nameof(p2), in p2);

Assert.True(func2(Request.CreateValues("A", 1, "read"), Policy.CreateValues("A", 1, "read")));
Assert.False(func2(Request.CreateValues("A", 1, "read"), Policy.CreateValues("A", 2, "read")));
Assert.False(func2(Request.CreateValues("B", 1, "read"), Policy.CreateValues("B", 2, "read")));
}

private static Func<TRequest, TPolicy, bool> Compile<TRequest, TPolicy>
(
string expressionText,
string requestType, in TRequest r,
string policyType, in TPolicy p)
where TRequest : struct, IRequestValues where TPolicy : IPolicyValues
{
Interpreter interpreter = new();
return interpreter.ParseAsDelegate<Func<TRequest, TPolicy, bool>>(
expressionText, requestType, policyType
);
}


}
64 changes: 32 additions & 32 deletions Casbin.UnitTests/ModelTests/EnforcerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void TestEnforceWithoutAutoLoadPolicy()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

FileAdapter a = new("examples/keymatch_policy.csv");
FileAdapter a = new("Examples/keymatch_policy.csv");
IEnforcer e = new Enforcer(m, a, new EnforcerOptions { AutoLoadPolicy = false });
Assert.Empty(e.GetPolicy());

Expand Down Expand Up @@ -118,7 +118,7 @@ public void TestKeyMatchModelInMemory()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

FileAdapter a = new("examples/keymatch_policy.csv");
FileAdapter a = new("Examples/keymatch_policy.csv");

Enforcer e = new(m, a);

Expand Down Expand Up @@ -179,7 +179,7 @@ public async Task TestKeyMatchModelInMemoryAsync()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

FileAdapter a = new("examples/keymatch_policy.csv");
FileAdapter a = new("Examples/keymatch_policy.csv");

Enforcer e = new(m, a);

Expand Down Expand Up @@ -240,7 +240,7 @@ public void TestKeyMatchModelInMemoryDeny()
m.AddDef("e", "e", "!some(where (p.eft == deny))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

FileAdapter a = new("examples/keymatch_policy.csv");
FileAdapter a = new("Examples/keymatch_policy.csv");

Enforcer e = new(m, a);

Expand Down Expand Up @@ -671,7 +671,7 @@ public void TestInitEmpty()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

FileAdapter a = new("examples/keymatch_policy.csv");
FileAdapter a = new("Examples/keymatch_policy.csv");

e.SetModel(m);
e.SetAdapter(a);
Expand All @@ -691,7 +691,7 @@ public async Task TestInitEmptyAsync()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

FileAdapter a = new("examples/keymatch_policy.csv");
FileAdapter a = new("Examples/keymatch_policy.csv");

e.SetModel(m);
e.SetAdapter(a);
Expand All @@ -711,7 +711,7 @@ public void TestInitEmptyByInputStream()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

using (FileStream fs = new("examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read,
using (FileStream fs = new("Examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read,
FileShare.ReadWrite))
{
FileAdapter a = new(fs);
Expand All @@ -734,7 +734,7 @@ public async Task TestInitEmptyByInputStreamAsync()
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");

using (FileStream fs = new("examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read,
using (FileStream fs = new("Examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read,
FileShare.ReadWrite))
{
FileAdapter a = new(fs);
Expand All @@ -753,7 +753,7 @@ public async Task TestInitEmptyByInputStreamAsync()
[Fact]
public void TestReloadPolicy()
{
Enforcer e = new("examples/rbac_model.conf", "examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");

e.LoadPolicy();
TestGetPolicy(e,
Expand All @@ -764,7 +764,7 @@ public void TestReloadPolicy()
[Fact]
public async Task TestReloadPolicyAsync()
{
Enforcer e = new("examples/rbac_model.conf", "examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");

await e.LoadPolicyAsync();
TestGetPolicy(e,
Expand All @@ -775,39 +775,39 @@ public async Task TestReloadPolicyAsync()
[Fact]
public void TestSavePolicy()
{
Enforcer e = new("examples/rbac_model.conf", "examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");

e.SavePolicy();
}

[Fact]
public async Task TestSavePolicyAsync()
{
Enforcer e = new("examples/rbac_model.conf", "examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");

await e.SavePolicyAsync();
}

[Fact]
public void TestSavePolicyWithoutBasicModel()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");

e.SavePolicy();
}

[Fact]
public async Task TestSavePolicyWithoutBasicModelAsync()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");

await e.SavePolicyAsync();
}

[Fact]
public void TestClearPolicy()
{
Enforcer e = new("examples/rbac_model.conf", "examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");

e.ClearPolicy();
}
Expand All @@ -819,7 +819,7 @@ public void TestClearPolicy()
[Fact]
public void TestEnableEnforce()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");

e.EnableEnforce(false);
TestEnforce(e, "alice", "data1", "read", true);
Expand All @@ -846,7 +846,7 @@ public void TestEnableEnforce()
[Fact]
public void TestEnableLog()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv")
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv")
{
Logger = new MockLogger<Enforcer>(_testOutputHelper)
};
Expand Down Expand Up @@ -875,7 +875,7 @@ public void TestEnableLog()
[Fact]
public void TestEnableAutoSave()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");

e.EnableAutoSave(false);
// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
Expand Down Expand Up @@ -914,7 +914,7 @@ public void TestEnableAutoSave()
[Fact]
public async Task TestEnableAutoSaveAsync()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy_for_async_adapter_test.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy_for_async_adapter_test.csv");

e.EnableAutoSave(false);
// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
Expand Down Expand Up @@ -953,8 +953,8 @@ public async Task TestEnableAutoSaveAsync()
[Fact]
public void TestInitWithAdapter()
{
FileAdapter adapter = new("examples/basic_policy.csv");
Enforcer e = new("examples/basic_model.conf", adapter);
FileAdapter adapter = new("Examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", adapter);

TestEnforce(e, "alice", "data1", "read", true);
TestEnforce(e, "alice", "data1", "write", false);
Expand All @@ -969,7 +969,7 @@ public void TestInitWithAdapter()
[Fact]
public void TestRoleLinks()
{
Enforcer e = new("examples/rbac_model.conf");
Enforcer e = new("Examples/rbac_model.conf");
e.EnableAutoBuildRoleLinks(false);
e.BuildRoleLinks();
e.Enforce("user501", "data9", "read");
Expand All @@ -978,8 +978,8 @@ public void TestRoleLinks()
[Fact]
public void TestGetAndSetModel()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv");
Enforcer e2 = new("examples/basic_with_root_model.conf", "examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
Enforcer e2 = new("Examples/basic_with_root_model.conf", "Examples/basic_policy.csv");

TestEnforce(e, "root", "data1", "read", false);

Expand All @@ -991,8 +991,8 @@ public void TestGetAndSetModel()
[Fact]
public void TestGetAndSetAdapterInMem()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy.csv");
Enforcer e2 = new("examples/basic_model.conf", "examples/basic_inverse_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
Enforcer e2 = new("Examples/basic_model.conf", "Examples/basic_inverse_policy.csv");

TestEnforce(e, "alice", "data1", "read", true);
TestEnforce(e, "alice", "data1", "write", false);
Expand All @@ -1008,8 +1008,8 @@ public void TestGetAndSetAdapterInMem()
[Fact]
public async Task TestGetAndSetAdapterInMemAsync()
{
Enforcer e = new("examples/basic_model.conf", "examples/basic_policy_for_async_adapter_test.csv");
Enforcer e2 = new("examples/basic_model.conf", "examples/basic_inverse_policy.csv");
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy_for_async_adapter_test.csv");
Enforcer e2 = new("Examples/basic_model.conf", "Examples/basic_inverse_policy.csv");

await TestEnforceAsync(e, "alice", "data1", "read", true);
await TestEnforceAsync(e, "alice", "data1", "write", false);
Expand All @@ -1025,11 +1025,11 @@ public async Task TestGetAndSetAdapterInMemAsync()
[Fact]
public void TestSetAdapterFromFile()
{
Enforcer e = new("examples/basic_model.conf");
Enforcer e = new("Examples/basic_model.conf");

TestEnforce(e, "alice", "data1", "read", false);

FileAdapter a = new("examples/basic_policy.csv");
FileAdapter a = new("Examples/basic_policy.csv");
e.SetAdapter(a);
e.LoadPolicy();
TestEnforce(e, "alice", "data1", "read", true);
Expand All @@ -1046,11 +1046,11 @@ public void TestSetAdapterFromFile()
[Fact]
public async Task TestSetAdapterFromFileAsync()
{
Enforcer e = new("examples/basic_model.conf");
Enforcer e = new("Examples/basic_model.conf");

await TestEnforceAsync(e, "alice", "data1", "read", false);

FileAdapter a = new("examples/basic_policy_for_async_adapter_test.csv");
FileAdapter a = new("Examples/basic_policy_for_async_adapter_test.csv");
e.SetAdapter(a);
await e.LoadPolicyAsync();
await TestEnforceAsync(e, "alice", "data1", "read", true);
Expand Down
Loading

0 comments on commit fe66cd4

Please sign in to comment.