Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support add generic type custom function #365

Merged
merged 3 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
Loading