Skip to content

Commit 8214808

Browse files
committed
Added a new set of test actions
1 parent 30d224a commit 8214808

File tree

8 files changed

+343
-0
lines changed

8 files changed

+343
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using Bencodex.Types;
2+
using Libplanet.Action;
3+
using Libplanet.Crypto;
4+
using Libplanet.SDK.Action.Attributes;
5+
using Libplanet.SDK.Action.Tests.SimpleRPG.Models;
6+
7+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Actions
8+
{
9+
[ActionType("Avatar")]
10+
public class AvatarAction : ActionBase
11+
{
12+
// This has no IAccount associated with its domain.
13+
public override Address StorageAddress => default;
14+
15+
[Executable]
16+
public void Create(IValue args)
17+
{
18+
string name = (Text)args;
19+
Call<InfoAction, Info>("Create", new object?[] { name });
20+
Call<InventoryAction, Inventory>("Create");
21+
}
22+
23+
[Callable]
24+
public Avatar GetAvatar(Address address)
25+
{
26+
Info info = Call<InfoAction, Info>(
27+
"GetInfo",
28+
new object?[] { address });
29+
Inventory inventory = Call<InventoryAction, Inventory>(
30+
"GetInventory",
31+
new object?[] { address });
32+
return new Avatar(info, inventory);
33+
}
34+
35+
[Callable]
36+
public void SetAvatar(Address address, Avatar avatar)
37+
{
38+
Call<InfoAction>(
39+
"SetInfo",
40+
new object?[] { address, avatar.Info });
41+
Call<InventoryAction>(
42+
"SetInventory",
43+
new object?[] { address, avatar.Inventory });
44+
}
45+
}
46+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Bencodex.Types;
2+
using Libplanet.Action;
3+
using Libplanet.Crypto;
4+
using Libplanet.SDK.Action.Attributes;
5+
using Libplanet.SDK.Action.Tests.SimpleRPG.Models;
6+
7+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Actions
8+
{
9+
[ActionType("Farm")]
10+
public class FarmAction : ActionBase
11+
{
12+
public const int ExpPerFarm = 10;
13+
public const int GoldPerFarm = 20;
14+
15+
// This has no IAccount associated with its domain.
16+
public override Address StorageAddress => default;
17+
18+
[Executable]
19+
public void Farm(IValue args)
20+
{
21+
// Simple type checking.
22+
_ = (Null)args;
23+
24+
Avatar avatar = Call<AvatarAction, Avatar>("GetAvatar", new object?[] { Signer });
25+
avatar.Info.AddExp(ExpPerFarm);
26+
avatar.Inventory.AddGold(GoldPerFarm);
27+
Call<AvatarAction>("SetAvatar", new object?[] { Signer, avatar });
28+
}
29+
}
30+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Libplanet.Crypto;
2+
using Libplanet.SDK.Action.Attributes;
3+
using Libplanet.SDK.Action.Tests.SimpleRPG.Models;
4+
5+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Actions
6+
{
7+
public class InfoAction : ActionBase
8+
{
9+
public override Address StorageAddress =>
10+
new Address("0x1000000000000000000000000000000000000001");
11+
12+
[Callable]
13+
public Info Create(string name)
14+
{
15+
if (GetState(Signer) is { } value)
16+
{
17+
throw new InvalidOperationException("Info already exists.");
18+
}
19+
20+
Info info = new Info(name, 0);
21+
SetInfo(Signer, info);
22+
return info;
23+
}
24+
25+
[Callable]
26+
public Info GetInfo(Address address) =>
27+
new Info(GetState(address) ?? throw new NullReferenceException());
28+
29+
[Callable]
30+
public void SetInfo(Address address, Info info) =>
31+
SetState(address, info.Serialized);
32+
}
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Libplanet.Crypto;
2+
using Libplanet.SDK.Action.Attributes;
3+
using Libplanet.SDK.Action.Tests.SimpleRPG.Models;
4+
5+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Actions
6+
{
7+
public class InventoryAction : ActionBase
8+
{
9+
public override Address StorageAddress =>
10+
new Address("0x1000000000000000000000000000000000000002");
11+
12+
[Callable]
13+
public Inventory Create()
14+
{
15+
if (GetState(Signer) is { })
16+
{
17+
throw new InvalidOperationException("Inventory already exists.");
18+
}
19+
20+
Inventory inventory = new Inventory();
21+
SetInventory(Signer, inventory);
22+
return inventory;
23+
}
24+
25+
[Callable]
26+
public Inventory GetInventory(Address address) =>
27+
new Inventory(GetState(address) ?? throw new NullReferenceException());
28+
29+
[Callable]
30+
public void SetInventory(Address address, Inventory inventory) =>
31+
SetState(address, inventory.Serialized);
32+
}
33+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Models
2+
{
3+
public class Avatar
4+
{
5+
public Info Info { get; }
6+
public Inventory Inventory { get; }
7+
8+
public Avatar(Info info, Inventory inventory)
9+
{
10+
Info = info;
11+
Inventory = inventory;
12+
}
13+
}
14+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Bencodex.Types;
2+
3+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Models
4+
{
5+
public class Info
6+
{
7+
public string Name { get; }
8+
9+
public int Exp { get; private set; }
10+
11+
public int Level => (Exp / 100);
12+
13+
public Info(string name)
14+
: this(name, 0)
15+
{
16+
}
17+
18+
public Info(IValue value)
19+
: this((Text)((List)value)[0], (Integer)((List)value)[1])
20+
{
21+
}
22+
23+
public Info(string name, int exp)
24+
{
25+
Name = name;
26+
Exp = exp;
27+
}
28+
29+
public IValue Serialized => List.Empty
30+
.Add(Name)
31+
.Add(Exp);
32+
33+
public void AddExp(int exp)
34+
{
35+
Exp = Exp + exp;
36+
}
37+
}
38+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Bencodex.Types;
2+
3+
namespace Libplanet.SDK.Action.Tests.SimpleRPG.Models
4+
{
5+
public class Inventory
6+
{
7+
public int Gold { get; private set; }
8+
9+
public Inventory()
10+
: this(0)
11+
{
12+
}
13+
14+
public Inventory(IValue value)
15+
: this((int)(Integer)value)
16+
{
17+
}
18+
19+
public Inventory(int gold)
20+
{
21+
Gold = gold;
22+
}
23+
24+
public IValue Serialized => new Integer(Gold);
25+
26+
public void AddGold(int gold)
27+
{
28+
Gold = Gold + gold;
29+
}
30+
}
31+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System.Collections.Immutable;
2+
using System.Reflection;
3+
using Bencodex.Types;
4+
using Libplanet.Action;
5+
using Libplanet.Action.Loader;
6+
using Libplanet.Action.State;
7+
using Libplanet.Crypto;
8+
using Libplanet.SDK.Action.Tests.SimpleRPG.Actions;
9+
using Libplanet.SDK.Action.Tests.SimpleRPG.Models;
10+
using Libplanet.Store;
11+
using Libplanet.Store.Trie;
12+
using Libplanet.Types.Blocks;
13+
using Xunit;
14+
15+
namespace Libplanet.SDK.Action.Tests.Sample
16+
{
17+
public class SimpleRPGActionsTest
18+
{
19+
private TypedActionLoader _loader;
20+
private IStateStore _stateStore;
21+
private IWorld _world;
22+
23+
public SimpleRPGActionsTest()
24+
{
25+
_loader = new TypedActionLoader(
26+
ImmutableDictionary<IValue, Type>.Empty
27+
.Add(new Text("Avatar"), typeof(AvatarAction))
28+
.Add(new Text("Farm"), typeof(FarmAction)));
29+
30+
_stateStore = new TrieStateStore(new MemoryKeyValueStore());
31+
32+
ITrie trie = _stateStore.GetStateRoot(null);
33+
trie = trie.SetMetadata(new TrieMetadata(Block.CurrentProtocolVersion));
34+
trie = _stateStore.Commit(trie);
35+
_world = new World(new WorldBaseState(trie, _stateStore));
36+
}
37+
38+
[Theory]
39+
[InlineData(false)]
40+
[InlineData(true)]
41+
public void Scenario(bool commit)
42+
{
43+
IValue plainValue = Dictionary.Empty
44+
.Add("type_id", "Avatar")
45+
.Add("call", "Create")
46+
.Add("args", "Hero");
47+
IAction action = Assert.IsType<AvatarAction>(_loader.LoadAction(0, plainValue));
48+
Address signer = new PrivateKey().Address;
49+
IWorld world = _world;
50+
51+
world = action.Execute(new MockActionContext(signer, signer, world));
52+
world = commit ? _stateStore.CommitWorld(world) : world;
53+
Assert.Equal(
54+
new Info("Hero").Serialized,
55+
world
56+
.GetAccountState(new Address("0x1000000000000000000000000000000000000001"))
57+
.GetState(signer));
58+
Assert.Equal(
59+
new Inventory().Serialized,
60+
world
61+
.GetAccountState(new Address("0x1000000000000000000000000000000000000002"))
62+
.GetState(signer));
63+
64+
const int repeat = 3;
65+
foreach (var _ in Enumerable.Range(0, repeat))
66+
{
67+
plainValue = Dictionary.Empty
68+
.Add("type_id", "Farm")
69+
.Add("call", "Farm")
70+
.Add("args", Null.Value);
71+
action = Assert.IsType<FarmAction>(_loader.LoadAction(0, plainValue));
72+
world = action.Execute(new MockActionContext(signer, signer, world));
73+
world = commit ? _stateStore.CommitWorld(world) : world;
74+
}
75+
76+
Assert.Equal(
77+
new Info("Hero", FarmAction.ExpPerFarm * repeat).Serialized,
78+
world
79+
.GetAccountState(new Address("0x1000000000000000000000000000000000000001"))
80+
.GetState(signer));
81+
Assert.Equal(
82+
new Inventory(FarmAction.GoldPerFarm * repeat).Serialized,
83+
world
84+
.GetAccountState(new Address("0x1000000000000000000000000000000000000002"))
85+
.GetState(signer));
86+
}
87+
88+
[Fact]
89+
public void CannotCreateTwice()
90+
{
91+
IValue plainValue = Dictionary.Empty
92+
.Add("type_id", "Avatar")
93+
.Add("call", "Create")
94+
.Add("args", "Hero");
95+
IAction action = Assert.IsType<AvatarAction>(_loader.LoadAction(0, plainValue));
96+
Address signer = new PrivateKey().Address;
97+
IWorld world = _world;
98+
99+
world = action.Execute(new MockActionContext(signer, signer, world));
100+
world = _stateStore.CommitWorld(world);
101+
102+
plainValue = Dictionary.Empty
103+
.Add("type_id", "Avatar")
104+
.Add("call", "Create")
105+
.Add("args", "Princess");
106+
action = Assert.IsType<AvatarAction>(_loader.LoadAction(0, plainValue));
107+
Assert.Contains(
108+
"Info already exists",
109+
Assert.IsType<InvalidOperationException>(
110+
Assert.IsType<TargetInvocationException>(
111+
Assert.Throws<TargetInvocationException>(() =>
112+
action.Execute(new MockActionContext(signer, signer, world)))
113+
.InnerException)
114+
.InnerException)
115+
.Message);
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)