Sam Jaffe 7 éve
szülő
commit
081a24df62
6 módosított fájl, 174 hozzáadás és 13 törlés
  1. 8 0
      dice-roll.xcodeproj/project.pbxproj
  2. 17 7
      include/roll.h
  3. 1 1
      src/main.cxx
  4. 9 5
      src/roll.cxx
  5. 44 0
      test/exception_test.cxx
  6. 95 0
      test/roll_test.cxx

+ 8 - 0
dice-roll.xcodeproj/project.pbxproj

@@ -15,6 +15,8 @@
 		CD38F53321C87787007A732C /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD38F51B21C87757007A732C /* GoogleMock.framework */; };
 		CD38F53521C87799007A732C /* dice_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD38F53421C87799007A732C /* dice_test.cxx */; };
 		CD38F53721C89493007A732C /* exception.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD38F53621C89493007A732C /* exception.cxx */; };
+		CD38F53921C922E2007A732C /* roll_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD38F53821C922E2007A732C /* roll_test.cxx */; };
+		CD38F53B21C928B4007A732C /* exception_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD38F53A21C928B4007A732C /* exception_test.cxx */; };
 		CDED6A2721B2F28A00AB91D0 /* main.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED6A2621B2F28A00AB91D0 /* main.cxx */; };
 /* End PBXBuildFile section */
 
@@ -89,6 +91,8 @@
 		CD38F52A21C87771007A732C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		CD38F53421C87799007A732C /* dice_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dice_test.cxx; sourceTree = "<group>"; };
 		CD38F53621C89493007A732C /* exception.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = exception.cxx; sourceTree = "<group>"; };
+		CD38F53821C922E2007A732C /* roll_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = roll_test.cxx; sourceTree = "<group>"; };
+		CD38F53A21C928B4007A732C /* exception_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = exception_test.cxx; sourceTree = "<group>"; };
 		CD8F1ABC21B31E9E00CBB3CA /* roll.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = roll.h; sourceTree = "<group>"; };
 		CD8F1ABD21B31E9E00CBB3CA /* roll.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = roll.cxx; sourceTree = "<group>"; };
 		CDED6A2321B2F28A00AB91D0 /* simple_dice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = simple_dice; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -186,6 +190,8 @@
 			isa = PBXGroup;
 			children = (
 				CD38F53421C87799007A732C /* dice_test.cxx */,
+				CD38F53821C922E2007A732C /* roll_test.cxx */,
+				CD38F53A21C928B4007A732C /* exception_test.cxx */,
 			);
 			path = test;
 			sourceTree = "<group>";
@@ -377,6 +383,8 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				CD38F53B21C928B4007A732C /* exception_test.cxx in Sources */,
+				CD38F53921C922E2007A732C /* roll_test.cxx in Sources */,
 				CD38F53521C87799007A732C /* dice_test.cxx in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 17 - 7
include/roll.h

@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "die.h"
+#include "random.h"
 
 namespace dice {
   // Describe the actual result of rolling (+/-)NdM
@@ -34,14 +35,23 @@ namespace dice {
     // A vector of every modifier attached to the system.
     std::vector<mod> modifiers;
   };
+  
+  class roller {
+  public:
+    roller();
+    roller(engine::random && g);
+    
+    /**
+     * @param d Some dice roll structure, containing any number of dice sets 'NdM'
+     * as well as any number of roll modifiers (fixed numbers). Additionally,
+     * can contain a repetition parameter.
+     * @return A vector of actualized rolls, where `vector.size() == d.num`.
+     */
+    std::vector<dice_roll> operator()(dice const & d);
+  private:
+    engine::random gen;
+  };
 
-  /**
-   * @param d Some dice roll structure, containing any number of dice sets 'NdM'
-   * as well as any number of roll modifiers (fixed numbers). Additionally,
-   * can contain a repetition parameter.
-   * @return A vector of actualized rolls, where `vector.size() == d.num`.
-   */
-  std::vector<dice_roll> roll(dice const & d);
   /**
    * Print out the component elements of an actualized dice roll.
    * Use instead `out << int(r)` to print the final summation.

+ 1 - 1
src/main.cxx

@@ -35,7 +35,7 @@ void print(std::vector<dice::dice_roll> const & rs) {
 void eval(std::string const & str) {
   try {
     auto d = dice::from_string(str);
-    auto rs = dice::roll(d);
+    auto rs = dice::roller()(d);
     std::cout << "Result of '" << d << "': ";
     print(rs);
   } catch (dice::unexpected_token const & ut) {

+ 9 - 5
src/roll.cxx

@@ -27,12 +27,12 @@ namespace dice {
   std::ostream & operator<<(std::ostream & out, die_roll const & r) {
     out << str(r.sign);
     switch (r.rolled.size()) {
-      // Prevent crashes if we somehow get a 0dM expression
     case 0:
+        // Prevent crashes if we somehow get a 0dM expression
       return out << "0";
-      // Don't bother with braces if there's only a single roll,
-      // the braces are for grouping purposes.
     case 1:
+        // Don't bother with braces if there's only a single roll,
+        // the braces are for grouping purposes.
       return out << r.rolled[0];
     default:
       out << "[ ";
@@ -69,10 +69,14 @@ namespace dice {
     }
     return {hits, d.modifier};
   }
+  
+  roller::roller() : gen() {}
+  roller::roller(engine::random && g)
+  : gen(std::forward<engine::random>(g)) {
+  }
 
-  std::vector<dice_roll> roll(dice const & d) {
+  std::vector<dice_roll> roller::operator()(dice const & d) {
     std::vector<dice_roll> out;
-    engine::random gen;
     for (int i = 0; i < d.num; ++i) {
       out.emplace_back(roll_impl(d, gen));
     }

+ 44 - 0
test/exception_test.cxx

@@ -0,0 +1,44 @@
+//
+//  exception_test.cxx
+//  dice-td
+//
+//  Created by Sam Jaffe on 12/18/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#include <gmock/gmock.h>
+
+#include "die.h"
+#include "exception.h"
+
+using namespace ::testing;
+
+TEST(DiceExceptionTest, PointerIsActuallyAtTheRightLocation) {
+  std::string bad{"6d+1"};
+  try {
+    dice::from_string(bad);
+    FAIL();
+  } catch (dice::unexpected_token const & e) {
+    EXPECT_THAT(e.pointer().length(), Eq(2));
+  }
+}
+
+TEST(DiceExceptionTest, ErrorAtEndHasSpecialToken) {
+  std::string bad{"6d"};
+  try {
+    dice::from_string(bad);
+    FAIL();
+  } catch (dice::unexpected_token const & e) {
+    EXPECT_THAT(e.pointer(), Eq("<END>"));
+  }
+}
+
+TEST(DiceExceptionTest, ErrorAtEndCanUseFallback) {
+  std::string bad{"6d"};
+  try {
+    dice::from_string(bad);
+    FAIL();
+  } catch (dice::unexpected_token const & e) {
+    EXPECT_THAT(e.pointer(bad.length()), Eq("~^"));
+  }
+}

+ 95 - 0
test/roll_test.cxx

@@ -0,0 +1,95 @@
+//
+//  roll_test.cxx
+//  dice-td
+//
+//  Created by Sam Jaffe on 12/18/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "shared_random_generator/random_impl.h"
+
+#include "die.h"
+#include "roll.h"
+
+struct MockRandomImpl : public engine::detail::random_impl {
+  MOCK_METHOD1(exclusive, unsigned int(unsigned int));
+  double exclusive(double, double) { throw; }
+  double inclusive(double, double) { throw; }
+};
+
+class RollTest : public ::testing::Test {
+protected:
+  void SetUp() override {
+    pRandom = std::make_shared<MockRandomImpl>();
+  }
+  
+  void TearDown() override {
+    pRandom.reset();
+  }
+  
+protected:
+  std::shared_ptr<MockRandomImpl> pRandom;
+};
+
+using namespace ::testing;
+
+TEST_F(RollTest, CanConstructNoThrow) {
+  EXPECT_NO_THROW(dice::roller{});
+  EXPECT_NO_THROW(dice::roller{pRandom});
+}
+
+TEST_F(RollTest, RollsOncePerDie) {
+  dice::dice mydice{1, {{dice::ZERO, 3, 4}}, {{dice::PLUS, 1}}};
+  EXPECT_CALL(*pRandom, exclusive(4)).WillOnce(Return(2)).WillOnce(Return(1))
+      .WillOnce(Return(3));
+  
+  auto roll = dice::roller{pRandom}(mydice);
+  EXPECT_THAT(roll, SizeIs(1));
+  EXPECT_THAT(roll[0].sub_rolls, SizeIs(1));
+  EXPECT_THAT(roll[0].sub_rolls[0].rolled, ElementsAre(3, 2, 4));
+}
+
+TEST_F(RollTest, DoesNotRollForConstants) {
+  dice::dice mydice{1, {}, {{dice::PLUS, 1}}};
+  EXPECT_CALL(*pRandom, exclusive(_)).Times(0);
+  
+  auto roll = dice::roller{pRandom}(mydice);
+  EXPECT_THAT(roll, SizeIs(1));
+  EXPECT_THAT(roll[0].sub_rolls, SizeIs(0));
+  EXPECT_THAT(roll[0].modifiers, SizeIs(1));
+  EXPECT_THAT(roll[0].modifiers[0].value, Eq(1));
+}
+
+TEST_F(RollTest, OperatorInSumsElements) {
+  dice::dice mydice{1, {{dice::ZERO, 3, 4}}, {{dice::PLUS, 1}}};
+  EXPECT_CALL(*pRandom, exclusive(4)).WillOnce(Return(2)).WillOnce(Return(1))
+  .WillOnce(Return(3));
+  
+  auto roll = dice::roller{pRandom}(mydice);
+  // 3 + 2 + 4 + 1 = 10
+  EXPECT_THAT(int(roll[0]), Eq(10));
+}
+
+TEST(RollSerialTest, CanPrint0dN) {
+  dice::dice_roll roll{{{}}};
+  std::stringstream ss;
+  ss << roll;
+  EXPECT_THAT(ss.str(), Eq("0"));
+}
+
+TEST(RollSerialTest, Prints1dNAsRollNumber) {
+  dice::dice_roll roll{{{dice::ZERO, {3}}}};
+  std::stringstream ss;
+  ss << roll;
+  EXPECT_THAT(ss.str(), Eq("3"));
+}
+
+TEST(RollSerialTest, PrintsNdMAsList) {
+  dice::dice_roll roll{{{dice::ZERO, {3, 2, 4}}}};
+  std::stringstream ss;
+  ss << roll;
+  EXPECT_THAT(ss.str(), Eq("[ 3, 2, 4 ]"));
+}