nitrpg: add nitunits
authorAlexandre Terrasa <alexandre@moz-code.org>
Thu, 25 Jun 2015 02:51:20 +0000 (22:51 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 3 Dec 2015 04:09:01 +0000 (23:09 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

contrib/nitrpg/Makefile
contrib/nitrpg/src/events_generator.nit [new file with mode: 0644]
contrib/nitrpg/src/test_achievements.nit [new file with mode: 0644]
contrib/nitrpg/src/test_events.nit [new file with mode: 0644]
contrib/nitrpg/src/test_game.nit [new file with mode: 0644]
contrib/nitrpg/src/test_helper.nit [new file with mode: 0644]
contrib/nitrpg/src/test_listener.nit [new file with mode: 0644]
contrib/nitrpg/src/test_statistics.nit [new file with mode: 0644]

index 40ebec2..b6c4be9 100644 (file)
@@ -15,6 +15,7 @@
 # limitations under the License.
 
 NITC=../../bin/nitc
+NITU=../../bin/nitunit
 
 all: listener web
 
@@ -24,5 +25,12 @@ listener:
 web:
        $(NITC) src/web.nit
 
+check:
+       $(NITU) src/game.nit
+       $(NITU) src/events.nit
+       $(NITU) src/statistics.nit
+       $(NITU) src/achievements.nit
+       $(NITU) src/listener.nit
+
 clean:
        rm listener web
diff --git a/contrib/nitrpg/src/events_generator.nit b/contrib/nitrpg/src/events_generator.nit
new file mode 100644 (file)
index 0000000..cc8b6a4
--- /dev/null
@@ -0,0 +1,94 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Generate Github events from repo data.
+#
+# Mainly used for testing and history importation.
+module events_generator
+
+import github::events
+
+# Github events generator
+#
+# Generates events from repo data.
+class EventsGenerator
+
+       # API client used to get github data.
+       var api: GithubAPI
+
+       # Issues
+
+       # Generate a new IssuesEvent from an issue.
+       fun issues_event(action: String, issue: Issue): IssuesEvent do
+               var e = new IssuesEvent(api)
+               e.action = action
+               e.repo = issue.repo
+               e.issue = issue
+               return e
+       end
+
+       # Generate a new IssuesEvent with an `opened` action.
+       fun issue_open(issue: Issue): IssuesEvent do return issues_event("opened", issue)
+
+       # Generate a new IssuesEvent with an `closed` action.
+       fun issue_close(issue: Issue): IssuesEvent do return issues_event("closed", issue)
+
+       # Generate a new IssuesEvent with an `reopened` action.
+       fun issue_reopen(issue: Issue): IssuesEvent do return issues_event("reopened", issue)
+
+       # Generate a new IssuesEvent from a IssueEvent.
+       fun issue_raw_event(issue: Issue, event: IssueEvent): IssuesEvent do
+               var e = issues_event(event.event, issue)
+               e.lbl = event.labl
+               e.assignee = event.assignee
+               return e
+       end
+
+       # Pull requests
+
+       # Generate a new PullRequestEvent from a `pull` request.
+       fun pull_event(action: String, pull: PullRequest): PullRequestEvent do
+               var e = new PullRequestEvent(api)
+               e.action = action
+               e.repo = pull.repo
+               e.pull = pull
+               return e
+       end
+
+       # Generate a new PullRequestEvent with an `opened` action.
+       fun pull_open(pull: PullRequest): PullRequestEvent do return pull_event("opened", pull)
+
+       # Generate a new PullRequestEvent with an `closed` action.
+       fun pull_close(pull: PullRequest): PullRequestEvent do return pull_event("closed", pull)
+
+       # Generate a new PullRequestEvent with an `reopened` action.
+       fun pull_reopen(pull: PullRequest): PullRequestEvent do return pull_event("reopened", pull)
+
+       # Generate a new PullRequestEvent from a IssueEvent.
+       fun pull_raw_event(pull: PullRequest, event: IssueEvent): PullRequestEvent do
+               return pull_event(event.event, pull)
+       end
+
+       # Generate a new IssueCommentEvent from a IssueComment.
+       fun issue_comment_event(issue: Issue, comment: IssueComment): IssueCommentEvent do
+               var e = new IssueCommentEvent(api)
+               e.action = "created"
+               e.repo = issue.repo
+               e.issue = issue
+               e.comment = comment
+               return e
+       end
+end
diff --git a/contrib/nitrpg/src/test_achievements.nit b/contrib/nitrpg/src/test_achievements.nit
new file mode 100644 (file)
index 0000000..b5d4cb7
--- /dev/null
@@ -0,0 +1,145 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test module for `achievements.nit`
+module test_achievements is test_suite
+
+import test_helper
+import achievements
+
+class TestGame
+       super NitrpgTestHelper
+
+       fun test_add_achievement do
+               var db = load_db("test_add_achievement")
+               var game = load_game("Morriar/nit", db)
+               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
+               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
+               game.add_achievement(a1)
+               game.add_achievement(a2)
+               assert game.load_achievements.length == 2
+               db.drop
+       end
+
+       fun test_load_achievement do
+               var db = load_db("test_load_achievement")
+               var game = load_game("Morriar/nit", db)
+               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
+               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
+               game.add_achievement(a1)
+               assert game.load_achievement(a1.id).id == "test_id1"
+               assert game.load_achievement(a2.id) == null
+               db.drop
+       end
+
+       fun test_load_achievements do
+               var db = load_db("test_load_achievements")
+               var game = load_game("Morriar/nit", db)
+               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
+               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
+               var a3 = new Achievement(game, "test_id3", "test_name", "test_desc", 15)
+               game.add_achievement(a1)
+               game.add_achievement(a2)
+               game.db.collection("achievements").insert(a3.to_json)
+               var ok = [a1.id, a2.id]
+               var res = game.load_achievements
+               assert res.length == 2
+               for a in res.values do assert ok.has(a.id)
+               db.drop
+       end
+end
+
+class TestPlayer
+       super NitrpgTestHelper
+
+       fun test_add_achievement do
+               var db = load_db("test_add_achievement")
+               var game = load_game("Morriar/nit", db)
+               var player1 = new Player(game, "Morriar")
+               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
+               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
+               player1.add_achievement(a1)
+               player1.add_achievement(a2)
+               assert player1.load_achievements.length == 2
+               db.drop
+       end
+
+       fun test_load_achievement do
+               var db = load_db("test_load_achievement")
+               var game = load_game("Morriar/nit", db)
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(game, "xymus")
+               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
+               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
+               player1.add_achievement(a1)
+               player2.add_achievement(a2)
+               assert player1.load_achievement(a1.id).id == "test_id1"
+               assert player1.load_achievement(a2.id) == null
+               assert player2.load_achievement(a2.id).id == "test_id2"
+               assert player2.load_achievement(a1.id) == null
+               db.drop
+       end
+
+       fun test_load_achievements do
+               var db = load_db("test_load_achievements")
+               var game = load_game("Morriar/nit", db)
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(game, "xymus")
+               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
+               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
+               var a3 = new Achievement(game, "test_id3", "test_name", "test_desc", 15)
+               player1.add_achievement(a1)
+               player1.add_achievement(a2)
+               player2.add_achievement(a3)
+               var ok = [a1.id, a2.id]
+               var res = player1.load_achievements
+               assert res.length == 2
+               for a in res.values do assert ok.has(a.id)
+               db.drop
+       end
+end
+
+class TestAchievement
+       super NitrpgTestHelper
+
+       fun test_init do
+               var db = load_db("test_init")
+               var game = load_game("Morriar/nit", db)
+               var a = new Achievement(game, "test_id", "test_name", "test_desc", 15)
+               assert a.id == "test_id"
+               assert a.name == "test_name"
+               assert a.desc == "test_desc"
+               assert a.reward == 15
+               db.drop
+       end
+
+       fun test_init_from_json do
+               var db = load_db("test_init_from_json")
+               var game = load_game("Morriar/nit", db)
+               var json = """{
+                       "id": "test_id",
+                       "name": "test_name",
+                       "desc": "test_desc",
+                       "reward": 15
+               }""".parse_json.as(JsonObject)
+               var a = new Achievement.from_json(game, json)
+               assert a.id == "test_id"
+               assert a.name == "test_name"
+               assert a.desc == "test_desc"
+               assert a.reward == 15
+               db.drop
+       end
+end
diff --git a/contrib/nitrpg/src/test_events.nit b/contrib/nitrpg/src/test_events.nit
new file mode 100644 (file)
index 0000000..83f17bf
--- /dev/null
@@ -0,0 +1,144 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test module for `events.nit`
+module test_events is test_suite
+
+import test_helper
+import events
+
+class TestGame
+       super NitrpgTestHelper
+
+       fun test_add_event do
+               var db = load_db("test_add_event")
+               var game = load_game("Morriar/nit", db)
+               var event1 = new GameEvent(game, "test_kind", new JsonObject)
+               var event2 = new GameEvent(game, "test_kind", new JsonObject)
+               game.add_event(event1)
+               game.add_event(event2)
+               assert game.load_events.length == 2
+               db.drop
+       end
+
+       fun test_load_event do
+               var db = load_db("test_load_event")
+               var game = load_game("Morriar/nit", db)
+               var event1 = new GameEvent(game, "test_kind", new JsonObject)
+               var event2 = new GameEvent(game, "test_kind", new JsonObject)
+               game.add_event(event1)
+               assert game.load_event(event1.internal_id).kind == "test_kind"
+               assert game.load_event(event2.internal_id) == null
+               db.drop
+       end
+
+       fun test_load_events do
+               var db = load_db("test_load_events")
+               var game = load_game("Morriar/nit", db)
+               var event1 = new GameEvent(game, "test_kind", new JsonObject)
+               var event2 = new GameEvent(game, "test_kind", new JsonObject)
+               var event3 = new GameEvent(game, "test_kind", new JsonObject)
+               game.add_event(event1)
+               game.add_event(event2)
+               game.db.collection("events").insert(event3.to_json)
+               var ok = [event1.internal_id, event2.internal_id]
+               var res = game.load_events
+               assert res.length == 2
+               for event in res do assert ok.has(event.internal_id)
+               db.drop
+       end
+end
+
+class TestPlayer
+       super NitrpgTestHelper
+
+       fun test_add_event do
+               var db = load_db("test_add_event")
+               var game = load_game("Morriar/nit", db)
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(game, "xymus")
+               var event1 = new GameEvent(game, "test_kind", new JsonObject)
+               var event2 = new GameEvent(game, "test_kind", new JsonObject)
+               player1.add_event(event1)
+               player1.add_event(event2)
+               assert player1.load_events.length == 2
+               assert player2.load_events.length == 0
+               db.drop
+       end
+
+       fun test_load_event do
+               var db = load_db("test_load_event")
+               var game = load_game("Morriar/nit", db)
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(game, "xymus")
+               var event1 = new GameEvent(game, "test_kind", new JsonObject)
+               var event2 = new GameEvent(game, "test_kind", new JsonObject)
+               player1.add_event(event1)
+               player2.add_event(event2)
+               assert player1.load_event(event1.internal_id).kind == "test_kind"
+               assert player1.load_event(event2.internal_id) == null
+               assert player2.load_event(event2.internal_id).kind == "test_kind"
+               assert player2.load_event(event1.internal_id) == null
+               db.drop
+       end
+
+       fun test_load_events do
+               var db = load_db("test_load_events")
+               var game = load_game("Morriar/nit", db)
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(game, "xymus")
+               var event1 = new GameEvent(game, "test_kind", new JsonObject)
+               var event2 = new GameEvent(game, "test_kind", new JsonObject)
+               var event3 = new GameEvent(game, "test_kind", new JsonObject)
+               player1.add_event(event1)
+               player1.add_event(event2)
+               player2.add_event(event3)
+               assert player1.load_events.length == 2
+               assert player2.load_events.length == 1
+               var ok = [event1.internal_id, event2.internal_id]
+               for event in player1.load_events do assert ok.has(event.internal_id)
+               db.drop
+       end
+end
+
+class TestGameEvent
+       super NitrpgTestHelper
+
+       fun test_init do
+               var db = load_db("test_init")
+               var game = load_game("Morriar/nit", db)
+               var event = new GameEvent(game, "test_kind", new JsonObject)
+               assert event.to_json["kind"] == "test_kind"
+               db.drop
+       end
+
+       fun test_init_from_json do
+               var db = load_db("test_init_from_json")
+               var game = load_game("Morriar/nit", db)
+               var json = """{
+                       "internal_id": "test_id",
+                       "kind": "test_kind",
+                       "time": "2015-02-05T00:00:00Z",
+                       "data": {"test_field": "test_value"}
+               }""".parse_json.as(JsonObject)
+               var event = new GameEvent.from_json(game, json)
+               assert event.internal_id == "test_id"
+               assert event.kind == "test_kind"
+               assert event.data.to_json == """{"test_field":"test_value"}"""
+               assert event.time.to_s == "2015-02-05T00:00:00Z"
+               db.drop
+       end
+end
diff --git a/contrib/nitrpg/src/test_game.nit b/contrib/nitrpg/src/test_game.nit
new file mode 100644 (file)
index 0000000..78f3bd0
--- /dev/null
@@ -0,0 +1,146 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test module for `game.nit`.
+module test_game is test_suite
+
+import test_helper
+
+class TestGame
+       super NitrpgTestHelper
+
+       fun test_add_player do
+               var db = load_db("test_add_player")
+               var game = load_game("privat/nit", db)
+               var users = ["Morriar", "xymus"]
+               for name in users do
+                       game.add_player(game.api.load_user(name).as(not null))
+               end
+               var res = game.load_players.values
+               assert res.length == 2
+               for player in res do
+                       assert users.has(player.name)
+               end
+               db.drop
+       end
+
+       fun test_load_player do
+               var db = load_db("test_load_player")
+               var game = load_game("privat/nit", db)
+               var ogame = load_game("Morriar/nit", db)
+
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(ogame, "privat")
+               game.db.collection("players").insert(player1.to_json)
+               ogame.db.collection("players").insert(player2.to_json)
+
+               assert game.load_player("privat") == null
+               assert game.load_player("Morriar").name == "Morriar"
+               assert ogame.load_player("privat").name == "privat"
+               assert ogame.load_player("Morriar") == null
+               db.drop
+       end
+
+       fun test_load_players do
+               var db = load_db("test_load_players")
+               var game = load_game("privat/nit", db)
+               var ogame = load_game("Morriar/nit", db)
+
+               var player1 = new Player(game, "Morriar")
+               var player2 = new Player(ogame, "privat")
+               var player3 = new Player(game, "xymus")
+               game.db.collection("players").insert(player1.to_json)
+               ogame.db.collection("players").insert(player2.to_json)
+               game.db.collection("players").insert(player3.to_json)
+
+               var players = game.load_players
+               var ok = ["Morriar", "xymus"]
+               for player in players.values do assert ok.has(player.name)
+               db.drop
+       end
+end
+
+class TestPlayer
+       super NitrpgTestHelper
+
+       fun test_init do
+               var db = load_db("test_init")
+               var game = load_game("privat/nit", db)
+               var player = new Player(game, "Morriar")
+               assert player.name == "Morriar"
+               assert player.user.login == "Morriar"
+               assert player.nitcoins == 0
+               db.drop
+       end
+
+       fun test_init_from_json do
+               var db = load_db("test_init_from_json")
+               var game = load_game("privat/nit", db)
+               var json = """{"name": "Morriar", "nitcoins": 10}""".parse_json
+               var player = new Player.from_json(game, json.as(JsonObject))
+               assert player.name == "Morriar"
+               assert player.user.login == "Morriar"
+               assert player.nitcoins == 10
+               db.drop
+       end
+
+       fun test_save do
+               var db = load_db("test_save")
+               var game = load_game("privat/nit", db)
+               var json = """{"name": "Morriar", "nitcoins": 10}""".parse_json.as(JsonObject)
+               var player = new Player.from_json(game, json)
+               player.save
+               assert game.db.collection("players").find(json) != null
+               db.drop
+       end
+
+       fun test_game_add_player do
+               var db = load_db("test_game_add_player")
+               var game = load_game("privat/nit", db)
+               game.add_player(game.api.load_user("Morriar").as(not null))
+               var json = """{"name": "Morriar"}""".parse_json.as(JsonObject)
+               assert game.db.collection("players").find(json) != null
+               db.drop
+       end
+
+       fun test_game_load_player do
+               var db = load_db("test_game_load_player")
+               var game = load_game("privat/nit", db)
+               var json = """{"name": "Morriar", "nitcoins": 10}""".parse_json.as(JsonObject)
+               var player = new Player.from_json(game, json)
+               player.save
+               var oplayer = game.load_player("Morriar")
+               assert oplayer != null
+               assert player.nitcoins == oplayer.nitcoins
+               db.drop
+       end
+end
+
+class TestUser
+       super NitrpgTestHelper
+
+       fun test_player do
+               var db = load_db("test_player")
+               var api = new GithubAPI(get_github_oauth)
+               var game = load_game("privat/nit", db)
+               var user = api.load_user("Morriar")
+               assert user != null
+               var player = user.player(game)
+               assert player.name == "Morriar"
+               game.clear
+               db.drop
+       end
+end
diff --git a/contrib/nitrpg/src/test_helper.nit b/contrib/nitrpg/src/test_helper.nit
new file mode 100644 (file)
index 0000000..d8ba14e
--- /dev/null
@@ -0,0 +1,54 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test tools for NitRPG.
+module test_helper is test_suite
+
+import test_suite
+import game
+import github::cache
+
+# Used to factorize test treatments.
+abstract class NitrpgTestHelper
+       super TestSuite
+
+       # Github API client
+       var api: GithubAPI do
+               var api = new GithubAPI(get_github_oauth)
+               api.enable_cache = true
+               return api
+       end
+
+       # Mongo API client
+       var mongo = new MongoClient("mongodb://localhost:27017/")
+
+       # Load a new test database by with a name
+       fun load_db(name: String): MongoDb do return mongo.database(name)
+
+       # Load a repo by its name.
+       fun load_repo(name: String): Repo do
+               var repo = api.load_repo(name)
+               assert repo != null
+               return repo
+       end
+
+       # Load a game by its name.
+       fun load_game(name: String, db: MongoDb): Game do
+               var game = new Game(api, load_repo(name))
+               game.db_name = db.name
+               return game
+       end
+end
diff --git a/contrib/nitrpg/src/test_listener.nit b/contrib/nitrpg/src/test_listener.nit
new file mode 100644 (file)
index 0000000..edbfe37
--- /dev/null
@@ -0,0 +1,369 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test module for `listener.nit`
+module test_listener is test_suite
+
+import test_helper
+import reactors
+import achievements
+import events_generator
+
+private class DummyListener
+       super NitrpgTestHelper
+
+       var reactors = new Array[GameReactor]
+
+       fun apply_event(event: GithubEvent, db: MongoDb) do
+               var game = load_game(event.repo.full_name, db)
+               for reactor in reactors do
+                       reactor.react_event(game, event)
+               end
+       end
+
+       fun add_reactor(reactors: GameReactor...) do self.reactors.add_all reactors
+end
+
+class TestListener
+       super NitrpgTestHelper
+
+       var generator = new EventsGenerator(api)
+
+       var repo: Repo is lazy do return load_repo("Morriar/nit")
+
+       fun test_game_issue_stats do
+               var db = load_db("test_game_issue_stats")
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+
+               var issue = api.load_issue(repo, 322)
+               assert issue != null
+
+               l.apply_event(generator.issue_open(issue), db)
+               var game = load_game("Morriar/nit", db)
+               assert game.stats.overall["issues"] == 1
+               assert game.stats.overall["issues_open"] == 1
+               l.apply_event(generator.issue_close(issue), db)
+               game = load_game("Morriar/nit", db)
+               assert game.stats.overall["issues"] == 1
+               assert game.stats.overall["issues_open"] == 0
+               l.apply_event(generator.issue_reopen(issue), db)
+               game = load_game("Morriar/nit", db)
+               assert game.stats.overall["issues"] == 1
+               assert game.stats.overall["issues_open"] == 1
+               db.drop
+       end
+
+       fun test_player_issue_stats do
+               var db = load_db("test_player_issue_stats")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+
+               var issue = api.load_issue(repo, 322)
+               assert issue != null
+
+               l.apply_event(generator.issue_open(issue), db)
+               var player = new Player(game, "Morriar")
+               assert player.stats.overall["issues"] == 1
+               assert player.stats.overall["issues_open"] == 1
+               l.apply_event(generator.issue_close(issue), db)
+               player = new Player(game, "Morriar")
+               assert player.stats.overall["issues"] == 1
+               assert player.stats.overall["issues_open"] == 0
+               l.apply_event(generator.issue_reopen(issue), db)
+               player = new Player(game, "Morriar")
+               assert player.stats.overall["issues"] == 1
+               assert player.stats.overall["issues_open"] == 1
+               db.drop
+       end
+
+       fun test_game_pr_stats do
+               var db = load_db("test_game_pr_stats")
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+
+               var pr = api.load_pull(repo, 275)
+               assert pr != null
+
+               l.apply_event(generator.pull_open(pr), db)
+               var game = load_game("Morriar/nit", db)
+               assert game.stats.overall["pulls"] == 1
+               assert game.stats.overall["pulls_open"] == 1
+               assert game.stats.overall["commits"] == 0
+               pr.merged = false
+               l.apply_event(generator.pull_close(pr), db)
+               game = load_game("Morriar/nit", db)
+               assert game.stats.overall["pulls"] == 1
+               assert game.stats.overall["pulls_open"] == 0
+               assert game.stats.overall["commits"] == 0
+               l.apply_event(generator.pull_reopen(pr), db)
+               game = load_game("Morriar/nit", db)
+               assert game.stats.overall["pulls"] == 1
+               assert game.stats.overall["pulls_open"] == 1
+               assert game.stats.overall["commits"] == 0
+               pr.merged = true
+               l.apply_event(generator.pull_close(pr), db)
+               game = load_game("Morriar/nit", db)
+               assert game.stats.overall["pulls"] == 1
+               assert game.stats.overall["pulls_open"] == 0
+               assert game.stats.overall["commits"] == 2
+               db.drop
+       end
+
+       fun test_game_issue_comment_stats do
+               var db = load_db("test_game_issue_comment_stats")
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+
+               var issue = api.load_issue(repo, 322)
+               assert issue != null
+               var comment = api.load_issue_comment(repo, 76119442)
+               assert comment != null
+
+               comment.body = "foo bar"
+               l.apply_event(generator.issue_comment_event(issue, comment), db)
+               var game = load_game("Morriar/nit", db)
+               assert game.stats.overall["comments"] == 1
+               assert game.stats.overall["reviews"] == 0
+               comment.body = "foo +1 bar"
+               l.apply_event(generator.issue_comment_event(issue, comment), db)
+               game = load_game("Morriar/nit", db)
+               assert game.stats.overall["comments"] == 2
+               assert game.stats.overall["reviews"] == 1
+               db.drop
+       end
+
+       fun test_player_pull_reactor do
+               var db = load_db("test_player_pull_reactor")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new PlayerReactor)
+
+               var pull = api.load_pull(repo, 275)
+               assert pull != null
+
+               l.apply_event(generator.pull_open(pull), db)
+               var player = new Player(game, "itch76")
+               assert player.stats.overall["nitcoins"] == 10
+               pull.merged = false
+               l.apply_event(generator.pull_close(pull), db)
+               player = new Player(game, "itch76")
+               assert player.stats.overall["nitcoins"] == 0
+               l.apply_event(generator.pull_reopen(pull), db)
+               player = new Player(game, "itch76")
+               assert player.stats.overall["nitcoins"] == 10
+               pull.merged = true
+               l.apply_event(generator.pull_close(pull), db)
+               player = new Player(game, "itch76")
+               assert player.stats.overall["nitcoins"] == 12
+               db.drop
+       end
+
+       fun test_player_review_reactor do
+               var db = load_db("test_player_review_reactor")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new PlayerReactor)
+
+               var pull = api.load_pull(repo, 275)
+               assert pull != null
+               var comment = api.load_issue_comment(repo, 36961230)
+               assert comment != null
+
+               # TODO handle multiple review by the same user
+
+               # no review in opened issue
+               pull.state = "open"
+               comment.body = "foo bar"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               var player = new Player(game, "Morriar")
+               assert player.stats.overall["nitcoins"] == 0
+
+               # review in opened issue
+               pull.state = "open"
+               comment.body = "foo +1 bar"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               player = new Player(game, "Morriar")
+               print player.stats.overall["nitcoins"]
+               assert player.stats.overall["nitcoins"] == 2
+
+               # review in closed issue
+               pull.state = "closed"
+               comment.body = "foo +1 bar"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               player = new Player(game, "Morriar")
+               assert player.stats.overall["nitcoins"] == 2
+
+               # review in reopened issue
+               pull.state = "open"
+               comment.body = "foo +1 bar"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               player = new Player(game, "Morriar")
+               assert player.stats.overall["nitcoins"] == 4
+               db.drop
+       end
+
+       fun test_X_issues_achievements do
+               var db = load_db("test_X_issues_achievements")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+               l.add_reactor(new Player1Issue, new Player100Issues, new Player1KIssues)
+
+               var issue = api.load_issue(repo, 322)
+               assert issue != null
+
+               for i in [0, 99, 999] do
+                       var id = "player_{i + 1}_issue"
+                       if i > 0 then id = "{id}s"
+                       var player = new Player(game, "Morriar")
+                       player.stats["issues"] = i
+                       player.save
+                       l.apply_event(generator.issue_open(issue), db)
+                       assert player.load_achievements.has_key(id)
+               end
+               var player = new Player(game, "Morriar")
+               assert player.stats.overall["nitcoins"] == 1110
+               db.drop
+       end
+
+       fun test_X_pulls_achievements do
+               var db = load_db("test_X_pulls_achievements")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+               l.add_reactor(new Player1Pull, new Player100Pulls, new Player1KPulls)
+
+               var pull = api.load_pull(repo, 275)
+               assert pull != null
+
+               for i in [0, 99, 999] do
+                       var id = "player_{i + 1}_pull"
+                       if i > 0 then id = "{id}s"
+                       var player = new Player(game, "itch76")
+                       player.stats["pulls"] = i
+                       player.save
+                       l.apply_event(generator.pull_open(pull), db)
+                       assert player.load_achievements.has_key(id)
+               end
+               var player = new Player(game, "itch76")
+               assert player.stats.overall["nitcoins"] == 1110
+               db.drop
+       end
+
+       fun test_X_commits_achievements do
+               var db = load_db("test_X_commits_achievements")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+               l.add_reactor(new Player1Commit, new Player100Commits)
+               l.add_reactor(new Player1KCommits, new Player10KCommits)
+
+               var pull = api.load_pull(repo, 275)
+               assert pull != null
+               pull.state = "closed"
+               pull.merged = true
+
+               for i in [0, 99, 999, 9999] do
+                       var id = "player_{i + 1}_commit"
+                       if i > 0 then id = "{id}s"
+                       var player = new Player(game, "itch76")
+                       player.stats["commits"] = i
+                       player.save
+                       l.apply_event(generator.pull_close(pull), db)
+                       assert player.load_achievements.has_key(id)
+               end
+               var player = new Player(game, "itch76")
+               assert player.stats.overall["nitcoins"] == 11110
+               db.drop
+       end
+
+       fun test_X_comments_achievements do
+               var db = load_db("test_X_comments_achievements")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new StatisticsReactor)
+               l.add_reactor(new Player1Comment, new Player100Comments, new Player1KComments)
+
+               var pull = api.load_pull(repo, 275)
+               assert pull != null
+               var comment = api.load_issue_comment(repo, 36961230)
+               assert comment != null
+
+               for i in [0, 99, 999] do
+                       var id = "player_{i + 1}_comment"
+                       if i > 0 then id = "{id}s"
+                       var player = new Player(game, "Morriar")
+                       player.stats["comments"] = i
+                       player.save
+                       l.apply_event(generator.issue_comment_event(pull, comment), db)
+                       assert player.load_achievements.has_key(id)
+               end
+               var player = new Player(game, "Morriar")
+               assert player.stats.overall["nitcoins"] == 1110
+               db.drop
+       end
+
+    fun test_issues_achievements do
+               var db = load_db("test_issues_achievements")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new IssueAboutNitdoc, new IssueAboutFFI)
+
+               var issue = api.load_issue(repo, 322)
+               assert issue != null
+
+               issue.title = "nitdoc ffi"
+               l.apply_event(generator.issue_open(issue), db)
+               var player = new Player(game, "Morriar")
+               assert player.load_achievements.has_key("issue_about_nitdoc")
+               assert player.load_achievements.has_key("issue_about_ffi")
+               assert player.stats.overall["nitcoins"] == 20
+               db.drop
+       end
+
+       fun test_comments_reactor do
+               var db = load_db("test_comments_reactor")
+               var game = load_game("Morriar/nit", db)
+               var l = new DummyListener
+               l.add_reactor(new PlayerPingGod, new PlayerFirstReview, new PlayerSaysNitcoin)
+
+               var pull = api.load_pull(repo, 275)
+               assert pull != null
+               var comment = api.load_issue_comment(repo, 36961230)
+               assert comment != null
+
+               comment.body = "@{game.repo.owner.login}"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               var player = new Player(game, "Morriar")
+               assert player.load_achievements.has_key("player_ping_god")
+               assert player.stats.overall["nitcoins"] == 50
+
+               comment.body = "+1"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               player = new Player(game, "Morriar")
+               assert player.load_achievements.has_key("player_first_review")
+               assert player.stats.overall["nitcoins"] == 60
+
+               comment.body = "Nitcoins"
+               l.apply_event(generator.issue_comment_event(pull, comment), db)
+               player = new Player(game, "Morriar")
+               assert player.load_achievements.has_key("player_says_nitcoin")
+               assert player.stats.overall["nitcoins"] == 70
+               db.drop
+       end
+end
diff --git a/contrib/nitrpg/src/test_statistics.nit b/contrib/nitrpg/src/test_statistics.nit
new file mode 100644 (file)
index 0000000..aa4c893
--- /dev/null
@@ -0,0 +1,83 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test module for `stats.nit`
+module test_statistics is test_suite
+
+import test_helper
+import statistics
+
+class TestGame
+       super NitrpgTestHelper
+
+       fun test_game_stats do
+               var db = load_db("test_game_stats")
+               var game = load_game("privat/nit", db)
+               var stats = game.stats
+               assert stats.overall["test"] == 0
+               stats.overall.inc("test")
+               assert stats.overall["test"] == 1
+               stats.save
+               var ogame = load_game("privat/nit", db)
+               var ostats = ogame.stats
+               ostats.overall.inc("test")
+               assert ostats.overall["test"] == 2
+               db.drop
+       end
+end
+
+class TestPlayer
+       super NitrpgTestHelper
+
+       fun test_player_stats do
+               var db = load_db("test_player_stats")
+               var game = load_game("privat/nit", db)
+               var player = new Player(game, "Morriar")
+               var stats = player.stats
+               assert stats.overall["test"] == 0
+               stats.overall.inc("test")
+               assert stats.overall["test"] == 1
+               stats.save
+               var oplayer = new Player(game, "Morriar")
+               var ostats = oplayer.stats
+               ostats.overall.inc("test")
+               assert ostats.overall["test"] == 2
+               db.drop
+       end
+end
+
+class TestGameStats
+       super NitrpgTestHelper
+
+       fun test_init_from_json do
+               var db = load_db("test_init_from_json")
+               var game = load_game("privat/nit", db)
+               var owner = new Player(game, "Morriar")
+               var json = """{
+                       "period": "2015",
+                       "owner": "Morriar",
+                       "values": {
+                               "test1": 10,
+                               "test2": 20
+                       }
+               }""".parse_json.as(JsonObject)
+               var stats = new GameStats.from_json(game, "2015", owner, json)
+               assert stats["test0"] == 0
+               assert stats["test1"] == 10
+               assert stats["test2"] == 20
+               db.drop
+       end
+end