From 40f438852f41161db8ce38a1ef89af9c5d1db43c Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Sun, 17 Sep 2017 17:52:41 +0200 Subject: [PATCH 1/4] initial addition of unittests --- dub.json | 25 +++++- source/calendarwebapp/app.d | 31 +++++++ source/calendarwebapp/authenticator.d | 30 +++++++ source/calendarwebapp/calendarwebapp.d | 98 +++++++++++++++++++++ source/calendarwebapp/configuration.d | 61 +++++++++++++ source/calendarwebapp/event.d | 79 +++++++++++++++++ test/calendarwebapp/testauthenticator.d | 53 ++++++++++++ test/calendarwebapp/testevent.d | 109 ++++++++++++++++++++++++ 8 files changed, 483 insertions(+), 3 deletions(-) create mode 100644 source/calendarwebapp/app.d create mode 100644 source/calendarwebapp/authenticator.d create mode 100644 source/calendarwebapp/calendarwebapp.d create mode 100644 source/calendarwebapp/configuration.d create mode 100644 source/calendarwebapp/event.d create mode 100644 test/calendarwebapp/testauthenticator.d create mode 100644 test/calendarwebapp/testevent.d diff --git a/dub.json b/dub.json index effc53a..c8225ba 100644 --- a/dub.json +++ b/dub.json @@ -4,14 +4,33 @@ "Johannes Loher" ], "dependencies": { - "vibe-d": "0.8.1-rc.2", - "poodinis": "~>8.0.1" + "vibe-d": "0.8.1", + "poodinis": "8.0.1" }, "description": "A simple webapplication to edit and view calendar entries", "copyright": "Copyright © 2017, Johannes Loher", "license": "MIT", + "targetType": "executable", + "targetPath": "generated", + "configurations": [ + { + "name": "executable", + "versions": [ + "VibeDefaultMain" + ] + }, + { + "name": "unittest", + "targetType": "executable", + "preBuildCommands": ["dub run unit-threaded -c gen_ut_main -- -f generated/ut.d test"], + "mainSourceFile": "generated/ut.d", + "sourcePaths": ["test"], + "dependencies": { + "unit-threaded": "0.7.30" + } + } + ], "versions": [ - "VibeDefaultMain", "VibeUseOpenSSL11" ] } \ No newline at end of file diff --git a/source/calendarwebapp/app.d b/source/calendarwebapp/app.d new file mode 100644 index 0000000..d6c35c9 --- /dev/null +++ b/source/calendarwebapp/app.d @@ -0,0 +1,31 @@ +module calendarwebapp.app; + +import calendarwebapp.calendarwebapp : CalendarWebapp; +import calendarwebapp.configuration : Context; + +import poodinis; + +import vibe.core.log : logInfo; + +import vibe.http.fileserver : serveStaticFiles; +import vibe.http.router : URLRouter; +import vibe.http.server : HTTPServerSettings, listenHTTP, MemorySessionStore; +import vibe.web.web : registerWebInterface; + +shared static this() +{ + auto container = new shared DependencyContainer(); + container.registerContext!Context; + + auto router = new URLRouter; + router.registerWebInterface(container.resolve!CalendarWebapp); + router.get("*", serveStaticFiles("public")); + + auto settings = new HTTPServerSettings; + settings.port = 8080; + settings.bindAddresses = ["::1", "127.0.0.1"]; + settings.sessionStore = new MemorySessionStore; + listenHTTP(settings, router); + + logInfo("Please open http://127.0.0.1:8080/ in your browser."); +} diff --git a/source/calendarwebapp/authenticator.d b/source/calendarwebapp/authenticator.d new file mode 100644 index 0000000..89c36b5 --- /dev/null +++ b/source/calendarwebapp/authenticator.d @@ -0,0 +1,30 @@ +module calendarwebapp.authenticator; + +import poodinis; + +import vibe.data.bson : Bson; +import vibe.db.mongo.collection : MongoCollection; + +interface Authenticator +{ + bool checkUser(string username, string password) @safe; +} + +class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator +{ +private: + @Value("users") + Collection users; + +public: + bool checkUser(string username, string password) @safe + { + auto result = users.findOne(["username" : username, "password" : password]); + return result != Bson(null); + } +} + +struct AuthInfo +{ + string userName; +} diff --git a/source/calendarwebapp/calendarwebapp.d b/source/calendarwebapp/calendarwebapp.d new file mode 100644 index 0000000..21a652e --- /dev/null +++ b/source/calendarwebapp/calendarwebapp.d @@ -0,0 +1,98 @@ +module calendarwebapp.calendarwebapp; + +import calendarwebapp.authenticator : Authenticator, AuthInfo; +import calendarwebapp.event; + +import core.time : days; + +import poodinis; + +import std.datetime : Date; +import std.exception : enforce; +import std.typecons : Nullable; + +import vibe.data.bson : BsonObjectID; +import vibe.http.common : HTTPStatusException; +import vibe.http.server : HTTPServerRequest, HTTPServerResponse; +import vibe.http.status : HTTPStatus; +import vibe.web.auth; +import vibe.web.web : errorDisplay, noRoute, redirect, render, SessionVar, + terminateSession; + +@requiresAuth class CalendarWebapp +{ + @noRoute AuthInfo authenticate(scope HTTPServerRequest req, scope HTTPServerResponse) @safe + { + if (!req.session || !req.session.isKeySet("auth")) + { + redirect("/login"); + return AuthInfo.init; + } + return req.session.get!AuthInfo("auth"); + } + +public: + @anyAuth void index() + { + auto events = eventStore.getAllEvents(); + render!("showevents.dt", events); + } + + @noAuth void getLogin(string _error = null) + { + render!("login.dt", _error); + } + + @noAuth @errorDisplay!getLogin void postLogin(string username, string password) @safe + { + enforce(authenticator.checkUser(username, password), "Benutzername oder Passwort ungültig"); + immutable AuthInfo authInfo = {username}; + auth = authInfo; + redirect("/"); + } + + @anyAuth void getLogout() @safe + { + terminateSession(); + redirect("/"); + } + + @anyAuth void getCreate(ValidationErrorData _error = ValidationErrorData.init) + { + render!("create.dt", _error); + } + + @anyAuth @errorDisplay!getCreate void postCreate(Date begin, + Nullable!Date end, string description, string name, EventType type, bool shout) @safe + { + import std.array : replace, split; + + if (!end.isNull) + enforce(end - begin >= 1.days, + "Mehrtägige Ereignisse müssen mindestens einen Tag dauern"); + auto event = Event(BsonObjectID.generate, begin, end, name, + description.replace("\r", ""), type, shout); + + eventStore.addEvent(event); + + redirect("/"); + } + + @anyAuth void postRemove(BsonObjectID id) @safe + { + eventStore.removeEvent(id); + redirect("/"); + } + +private: + struct ValidationErrorData + { + string msg; + string field; + } + + SessionVar!(AuthInfo, "auth") auth; + + @Autowire EventStore eventStore; + @Autowire Authenticator authenticator; +} diff --git a/source/calendarwebapp/configuration.d b/source/calendarwebapp/configuration.d new file mode 100644 index 0000000..c2c0959 --- /dev/null +++ b/source/calendarwebapp/configuration.d @@ -0,0 +1,61 @@ +module calendarwebapp.configuration; + +import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator; +import calendarwebapp.calendarwebapp : CalendarWebapp; +import calendarwebapp.event : EventStore, MongoDBEventStore; + +import poodinis; + +import vibe.db.mongo.client : MongoClient; +import vibe.db.mongo.collection : MongoCollection; +import vibe.db.mongo.mongo : connectMongoDB; + +class Context : ApplicationContext +{ +public: + override void registerDependencies(shared(DependencyContainer) container) + { + auto mongoClient = connectMongoDB("localhost"); + container.register!MongoClient.existingInstance(mongoClient); + container.register!(EventStore, MongoDBEventStore!()); + container.register!(Authenticator, MongoDBAuthenticator!()); + container.register!CalendarWebapp; + container.register!(ValueInjector!string, StringInjector); + container.register!(ValueInjector!MongoCollection, MongoCollectionInjector); + } +} + +class StringInjector : ValueInjector!string +{ +private: + string[string] config; + +public: + this() const @safe pure nothrow + { + // dfmt off + config = ["Database name" : "CalendarWebapp", + "Users collection name": "users", + "Events collection name" : "events"]; + // dfmt on + } + + override string get(string key) const @safe pure nothrow + { + return config[key]; + } +} + +class MongoCollectionInjector : ValueInjector!MongoCollection +{ +private: + @Autowire MongoClient mongoClient; + @Value("Database name") + string databaseName; + +public: + override MongoCollection get(string key) @safe + { + return mongoClient.getCollection(databaseName ~ "." ~ key); + } +} diff --git a/source/calendarwebapp/event.d b/source/calendarwebapp/event.d new file mode 100644 index 0000000..e03ee43 --- /dev/null +++ b/source/calendarwebapp/event.d @@ -0,0 +1,79 @@ +module calendarwebapp.event; + +import poodinis; + +import std.algorithm : map; +import std.datetime : Date; +import std.range.interfaces : InputRange, inputRangeObject; +import std.typecons : Nullable; + +import vibe.data.bson : Bson, BsonObjectID, deserializeBson, serializeToBson; +import vibe.data.serialization : serializationName = name; +import vibe.db.mongo.collection : MongoCollection; + +interface EventStore +{ + Event getEvent(BsonObjectID id) @safe; + InputRange!Event getAllEvents() @safe; + void addEvent(Event) @safe; + InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe; + void removeEvent(BsonObjectID id) @safe; +} + +class MongoDBEventStore(Collection = MongoCollection) : EventStore +{ +public: + Event getEvent(BsonObjectID id) @safe + { + return events.findOne(["_id" : id]).deserializeBson!Event; + } + + InputRange!Event getAllEvents() @safe + { + return events.find().map!(deserializeBson!Event).inputRangeObject; + } + + void addEvent(Event event) @safe + { + if (!event.id.valid) + event.id = BsonObjectID.generate; + + events.insert(event.serializeToBson); + } + + InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe + { + return events.find(["$and" : [["date" : ["$gte" : begin.serializeToBson]], ["date" + : ["$lte" : end.serializeToBson]]]]).map!(deserializeBson!Event) + .inputRangeObject; + } + + void removeEvent(BsonObjectID id) @safe + { + events.remove(["_id" : id]); + } + +private: + @Value("events") + Collection events; +} + +enum EventType +{ + Holiday, + Birthday, + FSI_Event, + General_University_Event, + Any +} + +struct Event +{ + @serializationName("_id") BsonObjectID id; + @serializationName("date") Date begin; + @serializationName("end_date") Nullable!Date end; + string name; + @serializationName("desc") string description; + @serializationName("etype") EventType type; + bool shout; +} diff --git a/test/calendarwebapp/testauthenticator.d b/test/calendarwebapp/testauthenticator.d new file mode 100644 index 0000000..65f6542 --- /dev/null +++ b/test/calendarwebapp/testauthenticator.d @@ -0,0 +1,53 @@ +module test.calendarwebapp.testauthenticator; + +import calendarwebapp.authenticator; + +import poodinis; + +import unit_threaded.mock; +import unit_threaded.should; + +import vibe.data.bson : Bson; + +interface Collection +{ + Bson findOne(string[string] query) @safe; +} + +class CollectionInjector : ValueInjector!Collection +{ +private: + Collection[string] collections; + +public: + void add(string key, Collection collection) + { + collections[key] = collection; + } + + override Collection get(string key) @safe + { + return collections[key]; + } +} + +@("Test MongoDBAuthenticator") +@system unittest +{ + auto collection = mock!Collection; + auto container = new shared DependencyContainer; + container.register!(ValueInjector!Collection, CollectionInjector); + container.resolve!CollectionInjector.add("users", collection); + container.register!(Authenticator, MongoDBAuthenticator!(Collection))( + RegistrationOption.doNotAddConcreteTypeRegistration); + + collection.returnValue!"findOne"(Bson(true), Bson(null)); + collection.expect!"findOne"(["username" : "", "password" : ""]); + collection.expect!"findOne"(["username" : "foo", "password" : "bar"]); + + auto authenticator = container.resolve!(Authenticator); + authenticator.checkUser("", "").shouldBeTrue; + authenticator.checkUser("foo", "bar").shouldBeFalse; + + collection.verify; +} diff --git a/test/calendarwebapp/testevent.d b/test/calendarwebapp/testevent.d new file mode 100644 index 0000000..2e4122c --- /dev/null +++ b/test/calendarwebapp/testevent.d @@ -0,0 +1,109 @@ +module test.calendarwebapp.testevent; + +import calendarwebapp.event; + +import poodinis; + +import unit_threaded.mock; +import unit_threaded.should; + +import vibe.data.bson : Bson, BsonObjectID, serializeToBson; + +interface Collection +{ + Bson findOne(BsonObjectID[string] query) @safe; + Bson[] find() @safe; + Bson[] find(Bson[string][string][][string] query) @safe; + void insert(Bson document) @safe; + void remove(BsonObjectID[string] selector) @safe; +} + +class CollectionInjector : ValueInjector!Collection +{ +private: + Collection[string] collections; + +public: + void add(string key, Collection collection) + { + collections[key] = collection; + } + + override Collection get(string key) @safe + { + return collections[key]; + } +} + +@("Test failing getEventMongoDBEventStore.getEvent") +@system unittest +{ + auto collection = mock!Collection; + auto container = new shared DependencyContainer; + container.register!(ValueInjector!Collection, CollectionInjector); + container.resolve!CollectionInjector.add("events", collection); + container.register!(EventStore, MongoDBEventStore!(Collection))( + RegistrationOption.doNotAddConcreteTypeRegistration); + + collection.returnValue!"findOne"(Bson(null)); + + auto id = BsonObjectID.fromString("599090de97355141140fc698"); + collection.expect!"findOne"(["_id" : id]); + + auto eventStore = container.resolve!(EventStore); + eventStore.getEvent(id).shouldThrowWithMessage!Exception("Expected object instead of null_"); + collection.verify; +} + +@("Test successful MongoDBEventStore.getEvent") +@system unittest +{ + auto collection = mock!Collection; + auto container = new shared DependencyContainer; + container.register!(ValueInjector!Collection, CollectionInjector); + container.resolve!CollectionInjector.add("events", collection); + container.register!(EventStore, MongoDBEventStore!(Collection))( + RegistrationOption.doNotAddConcreteTypeRegistration); + + auto id = BsonObjectID.fromString("599090de97355141140fc698"); + Event event; + event.id = id; + + collection.returnValue!"findOne"(event.serializeToBson); + + collection.expect!"findOne"(["_id" : id]); + + auto eventStore = container.resolve!(EventStore); + eventStore.getEvent(id).shouldEqual(event); + collection.verify; +} + +@("Test MongoDBEventStore.addEvent") +@system unittest +{ + auto collection = mock!Collection; + auto container = new shared DependencyContainer; + container.register!(ValueInjector!Collection, CollectionInjector); + container.resolve!CollectionInjector.add("events", collection); + container.register!(EventStore, MongoDBEventStore!(Collection))( + RegistrationOption.doNotAddConcreteTypeRegistration); + + auto id = BsonObjectID.fromString("599090de97355141140fc698"); + Event event; + event.id = id; + auto serializedEvent = event.serializeToBson; + + collection.returnValue!"findOne"(Bson(null), event.serializeToBson); + + collection.expect!"findOne"(["_id" : id]); + collection.expect!"insert"(serializedEvent); + collection.expect!"findOne"(["_id" : id]); + + auto eventStore = container.resolve!(EventStore); + + eventStore.getEvent(id).shouldThrowWithMessage!Exception("Expected object instead of null_"); + eventStore.addEvent(event); + eventStore.getEvent(id).shouldEqual(event); + + collection.verify; +} From 59ac47c555d24c5516e504b964c641c6b3f1a7ac Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Sun, 17 Sep 2017 17:54:26 +0200 Subject: [PATCH 2/4] removed forgotten files --- source/app.d | 31 ------------- source/authenticator.d | 30 ------------- source/calendarwebapp.d | 99 ----------------------------------------- source/configuration.d | 61 ------------------------- source/event.d | 79 -------------------------------- 5 files changed, 300 deletions(-) delete mode 100644 source/app.d delete mode 100644 source/authenticator.d delete mode 100644 source/calendarwebapp.d delete mode 100644 source/configuration.d delete mode 100644 source/event.d diff --git a/source/app.d b/source/app.d deleted file mode 100644 index ca618d1..0000000 --- a/source/app.d +++ /dev/null @@ -1,31 +0,0 @@ -module app; - -import calendarwebapp : CalendarWebapp; -import configuration : Context; - -import poodinis; - -import vibe.core.log : logInfo; - -import vibe.http.fileserver : serveStaticFiles; -import vibe.http.router : URLRouter; -import vibe.http.server : HTTPServerSettings, listenHTTP, MemorySessionStore; -import vibe.web.web : registerWebInterface; - -shared static this() -{ - auto container = new shared DependencyContainer(); - container.registerContext!Context; - - auto router = new URLRouter; - router.registerWebInterface(container.resolve!CalendarWebapp); - router.get("*", serveStaticFiles("public")); - - auto settings = new HTTPServerSettings; - settings.port = 8080; - settings.bindAddresses = ["::1", "127.0.0.1"]; - settings.sessionStore = new MemorySessionStore; - listenHTTP(settings, router); - - logInfo("Please open http://127.0.0.1:8080/ in your browser."); -} diff --git a/source/authenticator.d b/source/authenticator.d deleted file mode 100644 index 2e53f91..0000000 --- a/source/authenticator.d +++ /dev/null @@ -1,30 +0,0 @@ -module authenticator; - -import poodinis; - -import vibe.data.bson : Bson; -import vibe.db.mongo.collection : MongoCollection; - -interface Authenticator -{ - bool checkUser(string username, string password) @safe; -} - -class MongoDBAuthenticator : Authenticator -{ -private: - @Value("users") - MongoCollection users; - -public: - bool checkUser(string username, string password) @safe - { - auto result = users.findOne(["username" : username, "password" : password]); - return result != Bson(null); - } -} - -struct AuthInfo -{ - string userName; -} diff --git a/source/calendarwebapp.d b/source/calendarwebapp.d deleted file mode 100644 index 651f5b6..0000000 --- a/source/calendarwebapp.d +++ /dev/null @@ -1,99 +0,0 @@ -module calendarwebapp; - -import authenticator : Authenticator, AuthInfo; - -import core.time : days; - -import event; - -import poodinis; - -import std.datetime.date : Date; -import std.exception : enforce; -import std.typecons : Nullable; - -import vibe.data.bson : BsonObjectID; -import vibe.http.common : HTTPStatusException; -import vibe.http.server : HTTPServerRequest, HTTPServerResponse; -import vibe.http.status : HTTPStatus; -import vibe.web.auth; -import vibe.web.web : errorDisplay, noRoute, redirect, render, SessionVar, - terminateSession; - -@requiresAuth class CalendarWebapp -{ - @noRoute AuthInfo authenticate(scope HTTPServerRequest req, scope HTTPServerResponse res) @safe - { - if (!req.session || !req.session.isKeySet("auth")) - { - redirect("/login"); - return AuthInfo.init; - } - return req.session.get!AuthInfo("auth"); - } - -public: - @anyAuth void index() - { - auto events = eventStore.getAllEvents(); - render!("showevents.dt", events); - } - - @noAuth void getLogin(string _error = null) - { - render!("login.dt", _error); - } - - @noAuth @errorDisplay!getLogin void postLogin(string username, string password) @safe - { - enforce(authenticator.checkUser(username, password), "Benutzername oder Passwort ungültig"); - immutable AuthInfo authInfo = {username}; - auth = authInfo; - redirect("/"); - } - - @anyAuth void getLogout() @safe - { - terminateSession(); - redirect("/"); - } - - @anyAuth void getCreate(ValidationErrorData _error = ValidationErrorData.init) - { - render!("create.dt", _error); - } - - @anyAuth @errorDisplay!getCreate void postCreate(Date begin, - Nullable!Date end, string description, string name, EventType type, bool shout) @safe - { - import std.array : replace, split; - - if (!end.isNull) - enforce(end - begin >= 1.days, - "Mehrtägige Ereignisse müssen mindestens einen Tag dauern"); - auto event = Event(BsonObjectID.generate, begin, end, name, - description.replace("\r", ""), type, shout); - - eventStore.addEvent(event); - - redirect("/"); - } - - @anyAuth void postRemove(BsonObjectID id) @safe - { - eventStore.removeEvent(id); - redirect("/"); - } - -private: - struct ValidationErrorData - { - string msg; - string field; - } - - SessionVar!(AuthInfo, "auth") auth; - - @Autowire EventStore eventStore; - @Autowire Authenticator authenticator; -} diff --git a/source/configuration.d b/source/configuration.d deleted file mode 100644 index fce925d..0000000 --- a/source/configuration.d +++ /dev/null @@ -1,61 +0,0 @@ -module configuration; - -import authenticator : Authenticator, MongoDBAuthenticator; -import calendarwebapp : CalendarWebapp; -import event : EventStore, MongoDBEventStore; - -import poodinis; - -import vibe.db.mongo.client : MongoClient; -import vibe.db.mongo.collection : MongoCollection; -import vibe.db.mongo.mongo : connectMongoDB; - -class Context : ApplicationContext -{ -public: - override void registerDependencies(shared(DependencyContainer) container) - { - auto mongoClient = connectMongoDB("localhost"); - container.register!MongoClient.existingInstance(mongoClient); - container.register!(EventStore, MongoDBEventStore); - container.register!(Authenticator, MongoDBAuthenticator); - container.register!CalendarWebapp; - container.register!(ValueInjector!string, StringInjector); - container.register!(ValueInjector!MongoCollection, MongoCollectionInjector); - } -} - -class StringInjector : ValueInjector!string -{ -private: - string[string] config; - -public: - this() const @safe pure nothrow - { - // dfmt off - config = ["Database name" : "CalendarWebapp", - "Users collection name": "users", - "Events collection name" : "events"]; - // dfmt on - } - - override string get(string key) const @safe pure nothrow - { - return config[key]; - } -} - -class MongoCollectionInjector : ValueInjector!MongoCollection -{ -private: - @Autowire MongoClient mongoClient; - @Value("Database name") - string databaseName; - -public: - override MongoCollection get(string key) @safe - { - return mongoClient.getCollection(databaseName ~ "." ~ key); - } -} diff --git a/source/event.d b/source/event.d deleted file mode 100644 index 5655cb7..0000000 --- a/source/event.d +++ /dev/null @@ -1,79 +0,0 @@ -module event; - -import poodinis; - -import std.algorithm : map; -import std.datetime.date : Date; -import std.range.interfaces : InputRange, inputRangeObject; -import std.typecons : Nullable; - -import vibe.data.bson : Bson, BsonObjectID, deserializeBson, serializeToBson; -import vibe.data.serialization : serializationName = name; -import vibe.db.mongo.collection : MongoCollection; - -interface EventStore -{ - Event getEvent(BsonObjectID id) @safe; - InputRange!Event getAllEvents() @safe; - void addEvent(Event) @safe; - InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe; - void removeEvent(BsonObjectID id) @safe; -} - -class MongoDBEventStore : EventStore -{ -public: - Event getEvent(BsonObjectID id) @safe - { - return events.findOne(["_id" : id]).deserializeBson!Event; - } - - InputRange!Event getAllEvents() @safe - { - return events.find().map!(deserializeBson!Event).inputRangeObject; - } - - void addEvent(Event event) @safe - { - if (!event.id.valid) - event.id = BsonObjectID.generate; - - events.insert(event.serializeToBson); - } - - InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe - { - return events.find(["$and" : [["date" : ["$gte" : begin.serializeToBson]], ["date" - : ["$lte" : end.serializeToBson]]]]).map!(deserializeBson!Event) - .inputRangeObject; - } - - void removeEvent(BsonObjectID id) @safe - { - events.remove(["_id" : id]); - } - -private: - @Value("events") - MongoCollection events; -} - -enum EventType -{ - Holiday, - Birthday, - FSI_Event, - General_University_Event, - Any -} - -struct Event -{ - @serializationName("_id") BsonObjectID id; - @serializationName("date") Date begin; - @serializationName("end_date") Nullable!Date end; - string name; - @serializationName("desc") string description; - @serializationName("etype") EventType type; - bool shout; -} From e7e135d7ea5919938e2a53384c57b56ca5e5ec99 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Wed, 27 Sep 2017 14:53:50 +0200 Subject: [PATCH 3/4] Added more tests for event.d --- dub.json | 10 ++--- test/calendarwebapp/testevent.d | 67 +++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/dub.json b/dub.json index c8225ba..9276297 100644 --- a/dub.json +++ b/dub.json @@ -4,8 +4,8 @@ "Johannes Loher" ], "dependencies": { - "vibe-d": "0.8.1", - "poodinis": "8.0.1" + "vibe-d": "~>0.8.1", + "poodinis": "~>8.0.1" }, "description": "A simple webapplication to edit and view calendar entries", "copyright": "Copyright © 2017, Johannes Loher", @@ -26,11 +26,11 @@ "mainSourceFile": "generated/ut.d", "sourcePaths": ["test"], "dependencies": { - "unit-threaded": "0.7.30" - } + "unit-threaded": "~>0.7.31" + } } ], "versions": [ "VibeUseOpenSSL11" ] -} \ No newline at end of file +} diff --git a/test/calendarwebapp/testevent.d b/test/calendarwebapp/testevent.d index 2e4122c..3a1daf6 100644 --- a/test/calendarwebapp/testevent.d +++ b/test/calendarwebapp/testevent.d @@ -4,6 +4,9 @@ import calendarwebapp.event; import poodinis; +import std.array; +import std.algorithm : map; + import unit_threaded.mock; import unit_threaded.should; @@ -35,7 +38,7 @@ public: } } -@("Test failing getEventMongoDBEventStore.getEvent") +@("getEventMongoDBEventStore.getEvent failure") @system unittest { auto collection = mock!Collection; @@ -55,7 +58,7 @@ public: collection.verify; } -@("Test successful MongoDBEventStore.getEvent") +@("MongoDBEventStore.getEvent success") @system unittest { auto collection = mock!Collection; @@ -78,7 +81,7 @@ public: collection.verify; } -@("Test MongoDBEventStore.addEvent") +@("MongoDBEventStore.addEvent") @system unittest { auto collection = mock!Collection; @@ -93,7 +96,7 @@ public: event.id = id; auto serializedEvent = event.serializeToBson; - collection.returnValue!"findOne"(Bson(null), event.serializeToBson); + collection.returnValue!"findOne"(Bson(null), serializedEvent); collection.expect!"findOne"(["_id" : id]); collection.expect!"insert"(serializedEvent); @@ -107,3 +110,59 @@ public: collection.verify; } + +@("MongoDBEventStore.removeEvent") +@system unittest +{ + auto collection = mock!Collection; + auto container = new shared DependencyContainer; + container.register!(ValueInjector!Collection, CollectionInjector); + container.resolve!CollectionInjector.add("events", collection); + container.register!(EventStore, MongoDBEventStore!(Collection))( + RegistrationOption.doNotAddConcreteTypeRegistration); + + auto id = BsonObjectID.fromString("599090de97355141140fc698"); + Event event; + event.id = id; + + collection.returnValue!"findOne"(event.serializeToBson, Bson(null)); + + collection.expect!"findOne"(["_id" : id]); + collection.expect!"remove"(["_id" : id]); + collection.expect!"findOne"(["_id" : id]); + + auto eventStore = container.resolve!(EventStore); + + eventStore.getEvent(id).shouldEqual(event); + eventStore.removeEvent(event.id); + eventStore.getEvent(id).shouldThrowWithMessage!Exception("Expected object instead of null_"); + + collection.verify; +} + +@("MongoDBEventStore.getAllEvents") +@system unittest +{ + auto collection = mock!Collection; + auto container = new shared DependencyContainer; + container.register!(ValueInjector!Collection, CollectionInjector); + container.resolve!CollectionInjector.add("events", collection); + container.register!(EventStore, MongoDBEventStore!(Collection))( + RegistrationOption.doNotAddConcreteTypeRegistration); + + immutable ids = [ + BsonObjectID.fromString("599090de97355141140fc698"), BsonObjectID.fromString("599090de97355141140fc698"), + BsonObjectID.fromString("59cb9ad8fc0ba5751c0df02b") + ]; + auto events = ids.map!(id => Event(id)).array; + + collection.returnValue!"find"(events.map!serializeToBson.array); + + collection.expect!"find"(); + + auto eventStore = container.resolve!(EventStore); + + eventStore.getAllEvents.array.shouldEqual(events); + + collection.verify; +} From 8f3771053649173bb5b6f50f6c4f2c2310c20e98 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Mon, 9 Oct 2017 21:20:20 +0200 Subject: [PATCH 4/4] fixed whitespace in dub.json --- dub.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dub.json b/dub.json index 9276297..3db2ce0 100644 --- a/dub.json +++ b/dub.json @@ -11,25 +11,25 @@ "copyright": "Copyright © 2017, Johannes Loher", "license": "MIT", "targetType": "executable", - "targetPath": "generated", - "configurations": [ + "targetPath": "generated", + "configurations": [ { "name": "executable", "versions": [ "VibeDefaultMain" ] }, - { - "name": "unittest", - "targetType": "executable", - "preBuildCommands": ["dub run unit-threaded -c gen_ut_main -- -f generated/ut.d test"], + { + "name": "unittest", + "targetType": "executable", + "preBuildCommands": ["dub run unit-threaded -c gen_ut_main -- -f generated/ut.d test"], "mainSourceFile": "generated/ut.d", "sourcePaths": ["test"], - "dependencies": { - "unit-threaded": "~>0.7.31" + "dependencies": { + "unit-threaded": "~>0.7.31" } - } - ], + } + ], "versions": [ "VibeUseOpenSSL11" ]