diff --git a/src/GameServer.spec.ts b/src/GameServer.spec.ts index 7e98dc5..fa84683 100644 --- a/src/GameServer.spec.ts +++ b/src/GameServer.spec.ts @@ -268,3 +268,27 @@ }); }); }); + +describe("Scenario: Retrieving user id", function(){ + const games = createGameServer(); + describe("When a user id is returned", function(){ + const userID = games.createNewUserID(); + it("then it should not be null", function(){ + expect(userID).to.not.be.null; + }); + it("then it should be a string", function(){ + expect(typeof userID).to.equal("string"); + }); + it("then it should not be empty", function(){ + expect(userID).to.not.equal(""); + }); + }); + + describe("When two user ids are issued", function(){ + const id1 = games.createNewUserID(); + const id2 = games.createNewUserID(); + it("then they must not be the same", function(){ + expect(id1).to.not.equal(id2); + }); + }); +}); diff --git a/src/GameServer.spec.ts b/src/GameServer.spec.ts index 7e98dc5..fa84683 100644 --- a/src/GameServer.spec.ts +++ b/src/GameServer.spec.ts @@ -268,3 +268,27 @@ }); }); }); + +describe("Scenario: Retrieving user id", function(){ + const games = createGameServer(); + describe("When a user id is returned", function(){ + const userID = games.createNewUserID(); + it("then it should not be null", function(){ + expect(userID).to.not.be.null; + }); + it("then it should be a string", function(){ + expect(typeof userID).to.equal("string"); + }); + it("then it should not be empty", function(){ + expect(userID).to.not.equal(""); + }); + }); + + describe("When two user ids are issued", function(){ + const id1 = games.createNewUserID(); + const id2 = games.createNewUserID(); + it("then they must not be the same", function(){ + expect(id1).to.not.equal(id2); + }); + }); +}); diff --git a/src/GameServer.ts b/src/GameServer.ts index 03753ad..2ac8736 100644 --- a/src/GameServer.ts +++ b/src/GameServer.ts @@ -25,6 +25,11 @@ // that the server contains only valid maps. private mapList: MazeMap[]; private states: GameState[]; + /** + * Keeps track of generated random characters to ensure, + * that no two consecutive generated characters are the same. + */ + private randomCharacter: string; constructor() { @@ -139,6 +144,14 @@ return this.mapList.map(m => m.id); } + public createNewUserID(): string + { + let id = (+new Date()).toString(36); + // two prevent equal ids, at the same millisecond, append a random character. + id += this.getRandomCharacter(); + return id; + } + /** * Makes sure, that a userID is acceptable. * If not throw the appropriate error. @@ -153,4 +166,24 @@ throw new Error("UserID must not be empty."); } } + + /** + * Produces a single alphanumeric character, + * while ensuring, that no two consecutive outputs are the same. + */ + private getRandomCharacter(): string + { + const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + let newChar: string; + newChar = possible.charAt(Math.floor(Math.random() * possible.length)); + + while(this.randomCharacter === newChar) + { + newChar = possible.charAt(Math.floor(Math.random() * possible.length)); + } + this.randomCharacter = newChar; + + return newChar; + } } diff --git a/src/GameServer.spec.ts b/src/GameServer.spec.ts index 7e98dc5..fa84683 100644 --- a/src/GameServer.spec.ts +++ b/src/GameServer.spec.ts @@ -268,3 +268,27 @@ }); }); }); + +describe("Scenario: Retrieving user id", function(){ + const games = createGameServer(); + describe("When a user id is returned", function(){ + const userID = games.createNewUserID(); + it("then it should not be null", function(){ + expect(userID).to.not.be.null; + }); + it("then it should be a string", function(){ + expect(typeof userID).to.equal("string"); + }); + it("then it should not be empty", function(){ + expect(userID).to.not.equal(""); + }); + }); + + describe("When two user ids are issued", function(){ + const id1 = games.createNewUserID(); + const id2 = games.createNewUserID(); + it("then they must not be the same", function(){ + expect(id1).to.not.equal(id2); + }); + }); +}); diff --git a/src/GameServer.ts b/src/GameServer.ts index 03753ad..2ac8736 100644 --- a/src/GameServer.ts +++ b/src/GameServer.ts @@ -25,6 +25,11 @@ // that the server contains only valid maps. private mapList: MazeMap[]; private states: GameState[]; + /** + * Keeps track of generated random characters to ensure, + * that no two consecutive generated characters are the same. + */ + private randomCharacter: string; constructor() { @@ -139,6 +144,14 @@ return this.mapList.map(m => m.id); } + public createNewUserID(): string + { + let id = (+new Date()).toString(36); + // two prevent equal ids, at the same millisecond, append a random character. + id += this.getRandomCharacter(); + return id; + } + /** * Makes sure, that a userID is acceptable. * If not throw the appropriate error. @@ -153,4 +166,24 @@ throw new Error("UserID must not be empty."); } } + + /** + * Produces a single alphanumeric character, + * while ensuring, that no two consecutive outputs are the same. + */ + private getRandomCharacter(): string + { + const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + let newChar: string; + newChar = possible.charAt(Math.floor(Math.random() * possible.length)); + + while(this.randomCharacter === newChar) + { + newChar = possible.charAt(Math.floor(Math.random() * possible.length)); + } + this.randomCharacter = newChar; + + return newChar; + } } diff --git a/src/LabyrinthMiddleware.ts b/src/LabyrinthMiddleware.ts index db93e45..ebc582d 100644 --- a/src/LabyrinthMiddleware.ts +++ b/src/LabyrinthMiddleware.ts @@ -34,6 +34,9 @@ "Lists currently available maps." listMaps: [String!]! + + "Generates a new unique user id." + createNewUserID: String! } `; @@ -63,6 +66,7 @@ function createGraphQLRoot(games:GameServer) { return { + createNewUserID: () => games.createNewUserID(), currentPostition: ({userID}) => new MazeTileQL(games.currentPosition(userID)), endGame: ({userID}) => games.endGame(userID), listMaps: () => games.listMaps(),