Sam Jaffe 5 лет назад
Родитель
Сommit
f31b1fba27

+ 22 - 0
shared_random_generator-test/Info.plist

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>

+ 213 - 0
shared_random_generator.xcodeproj/project.pbxproj

@@ -7,17 +7,71 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		CD89E51824E6F3FD008167A8 /* libshared_random_generator.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CDED6A4221B2F5A700AB91D0 /* libshared_random_generator.dylib */; };
+		CD89E51F24E6F40B008167A8 /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD89E50824E6F3EA008167A8 /* GoogleMock.framework */; };
+		CD89E52124E6F424008167A8 /* random_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD89E52024E6F424008167A8 /* random_test.cxx */; };
 		CDED6A4F21B2F62C00AB91D0 /* random.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED6A4E21B2F62C00AB91D0 /* random.cxx */; };
 		CDED6A5E21B2F76B00AB91D0 /* shared_random_generator in Headers */ = {isa = PBXBuildFile; fileRef = CDED6A5D21B2F76700AB91D0 /* shared_random_generator */; settings = {ATTRIBUTES = (Public, ); }; };
 /* End PBXBuildFile section */
 
+/* Begin PBXContainerItemProxy section */
+		CD89E50724E6F3EA008167A8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F861A685AEA0072A469;
+			remoteInfo = GoogleMock;
+		};
+		CD89E50924E6F3EA008167A8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96ABD1A68600C00204102;
+			remoteInfo = gmock;
+		};
+		CD89E50B24E6F3EA008167A8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96B1F1A68634900204102;
+			remoteInfo = gtest;
+		};
+		CD89E50D24E6F3EA008167A8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F901A685AEA0072A469;
+			remoteInfo = GoogleMockTests;
+		};
+		CD89E51924E6F3FD008167A8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDED6A3A21B2F5A700AB91D0 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = CDED6A4121B2F5A700AB91D0;
+			remoteInfo = shared_random_generator;
+		};
+/* End PBXContainerItemProxy section */
+
 /* Begin PBXFileReference section */
+		CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
+		CD89E51324E6F3FD008167A8 /* shared_random_generator-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "shared_random_generator-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+		CD89E51724E6F3FD008167A8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		CD89E52024E6F424008167A8 /* random_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = random_test.cxx; sourceTree = "<group>"; };
 		CDED6A4221B2F5A700AB91D0 /* libshared_random_generator.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libshared_random_generator.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDED6A4E21B2F62C00AB91D0 /* random.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = random.cxx; sourceTree = "<group>"; };
 		CDED6A5D21B2F76700AB91D0 /* shared_random_generator */ = {isa = PBXFileReference; lastKnownFileType = folder; name = shared_random_generator; path = include/shared_random_generator; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
+		CD89E51024E6F3FD008167A8 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD89E51F24E6F40B008167A8 /* GoogleMock.framework in Frameworks */,
+				CD89E51824E6F3FD008167A8 /* libshared_random_generator.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		CDED6A4021B2F5A700AB91D0 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -28,13 +82,42 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		CD89E50124E6F3E9008167A8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CD89E50824E6F3EA008167A8 /* GoogleMock.framework */,
+				CD89E50A24E6F3EA008167A8 /* gmock.framework */,
+				CD89E50C24E6F3EA008167A8 /* gtest.framework */,
+				CD89E50E24E6F3EA008167A8 /* GoogleMockTests.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CD89E51424E6F3FD008167A8 /* shared_random_generator-test */ = {
+			isa = PBXGroup;
+			children = (
+				CD89E51724E6F3FD008167A8 /* Info.plist */,
+			);
+			path = "shared_random_generator-test";
+			sourceTree = "<group>";
+		};
+		CD89E51E24E6F40B008167A8 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
 		CDED6A3921B2F5A700AB91D0 = {
 			isa = PBXGroup;
 			children = (
+				CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */,
 				CDED6A5D21B2F76700AB91D0 /* shared_random_generator */,
 				CDED6A4921B2F5DF00AB91D0 /* src */,
 				CDED6A4A21B2F5DF00AB91D0 /* test */,
+				CD89E51424E6F3FD008167A8 /* shared_random_generator-test */,
 				CDED6A4321B2F5A700AB91D0 /* Products */,
+				CD89E51E24E6F40B008167A8 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -42,6 +125,7 @@
 			isa = PBXGroup;
 			children = (
 				CDED6A4221B2F5A700AB91D0 /* libshared_random_generator.dylib */,
+				CD89E51324E6F3FD008167A8 /* shared_random_generator-test.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -57,6 +141,7 @@
 		CDED6A4A21B2F5DF00AB91D0 /* test */ = {
 			isa = PBXGroup;
 			children = (
+				CD89E52024E6F424008167A8 /* random_test.cxx */,
 			);
 			path = test;
 			sourceTree = "<group>";
@@ -75,6 +160,24 @@
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
+		CD89E51224E6F3FD008167A8 /* shared_random_generator-test */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CD89E51B24E6F3FD008167A8 /* Build configuration list for PBXNativeTarget "shared_random_generator-test" */;
+			buildPhases = (
+				CD89E50F24E6F3FD008167A8 /* Sources */,
+				CD89E51024E6F3FD008167A8 /* Frameworks */,
+				CD89E51124E6F3FD008167A8 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				CD89E51A24E6F3FD008167A8 /* PBXTargetDependency */,
+			);
+			name = "shared_random_generator-test";
+			productName = "shared_random_generator-test";
+			productReference = CD89E51324E6F3FD008167A8 /* shared_random_generator-test.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
 		CDED6A4121B2F5A700AB91D0 /* shared_random_generator */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = CDED6A4621B2F5A700AB91D0 /* Build configuration list for PBXNativeTarget "shared_random_generator" */;
@@ -101,6 +204,9 @@
 				LastUpgradeCheck = 1010;
 				ORGANIZATIONNAME = "Sam Jaffe";
 				TargetAttributes = {
+					CD89E51224E6F3FD008167A8 = {
+						CreatedOnToolsVersion = 11.3.1;
+					};
 					CDED6A4121B2F5A700AB91D0 = {
 						CreatedOnToolsVersion = 10.1;
 					};
@@ -117,14 +223,70 @@
 			mainGroup = CDED6A3921B2F5A700AB91D0;
 			productRefGroup = CDED6A4321B2F5A700AB91D0 /* Products */;
 			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = CD89E50124E6F3E9008167A8 /* Products */;
+					ProjectRef = CD89E50024E6F3E9008167A8 /* GoogleMock.xcodeproj */;
+				},
+			);
 			projectRoot = "";
 			targets = (
 				CDED6A4121B2F5A700AB91D0 /* shared_random_generator */,
+				CD89E51224E6F3FD008167A8 /* shared_random_generator-test */,
 			);
 		};
 /* End PBXProject section */
 
+/* Begin PBXReferenceProxy section */
+		CD89E50824E6F3EA008167A8 /* GoogleMock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = GoogleMock.framework;
+			remoteRef = CD89E50724E6F3EA008167A8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CD89E50A24E6F3EA008167A8 /* gmock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gmock.framework;
+			remoteRef = CD89E50924E6F3EA008167A8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CD89E50C24E6F3EA008167A8 /* gtest.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gtest.framework;
+			remoteRef = CD89E50B24E6F3EA008167A8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CD89E50E24E6F3EA008167A8 /* GoogleMockTests.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = GoogleMockTests.xctest;
+			remoteRef = CD89E50D24E6F3EA008167A8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		CD89E51124E6F3FD008167A8 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
 /* Begin PBXSourcesBuildPhase section */
+		CD89E50F24E6F3FD008167A8 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD89E52124E6F424008167A8 /* random_test.cxx in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		CDED6A3F21B2F5A700AB91D0 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -135,7 +297,49 @@
 		};
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+		CD89E51A24E6F3FD008167A8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = CDED6A4121B2F5A700AB91D0 /* shared_random_generator */;
+			targetProxy = CD89E51924E6F3FD008167A8 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
 /* Begin XCBuildConfiguration section */
+		CD89E51C24E6F3FD008167A8 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = "shared_random_generator-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+					"@loader_path/../Frameworks",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.shared-random-generator-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		CD89E51D24E6F3FD008167A8 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = "shared_random_generator-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+					"@loader_path/../Frameworks",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.shared-random-generator-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
 		CDED6A4421B2F5A700AB91D0 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -276,6 +480,15 @@
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+		CD89E51B24E6F3FD008167A8 /* Build configuration list for PBXNativeTarget "shared_random_generator-test" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CD89E51C24E6F3FD008167A8 /* Debug */,
+				CD89E51D24E6F3FD008167A8 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		CDED6A3D21B2F5A700AB91D0 /* Build configuration list for PBXProject "shared_random_generator" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (

+ 63 - 0
shared_random_generator.xcodeproj/xcshareddata/xcschemes/shared_random_generator-test.xcscheme

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1130"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      codeCoverageEnabled = "YES"
+      onlyGenerateCoverageForSpecifiedTargets = "YES">
+      <CodeCoverageTargets>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "CDED6A4121B2F5A700AB91D0"
+            BuildableName = "libshared_random_generator.dylib"
+            BlueprintName = "shared_random_generator"
+            ReferencedContainer = "container:shared_random_generator.xcodeproj">
+         </BuildableReference>
+      </CodeCoverageTargets>
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "CD89E51224E6F3FD008167A8"
+               BuildableName = "shared_random_generator-test.xctest"
+               BlueprintName = "shared_random_generator-test"
+               ReferencedContainer = "container:shared_random_generator.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 1 - 1
src/random.cxx

@@ -18,7 +18,7 @@ namespace {
     }
 
     double inclusive(double min, double max) override {
-      double real_max = std::nextafter(max, DBL_MAX);
+      double real_max = std::nextafter(max, std::numeric_limits<double>::max());
       return std::min(uniform_real(min, real_max)(rng), max);
     }
 

+ 102 - 0
test/random_test.cxx

@@ -0,0 +1,102 @@
+//
+//  random_test.cpp
+//  shared_random_generator-test
+//
+//  Created by Sam Jaffe on 8/14/20.
+//  Copyright © 2020 Sam Jaffe. All rights reserved.
+//
+
+#include "shared_random_generator/random_impl.h"
+#include "shared_random_generator/random.h"
+
+#include <gmock/gmock.h>
+
+struct mock_random_impl : engine::detail::random_impl {
+  MOCK_METHOD1(exclusive, uint32_t(uint32_t));
+  MOCK_METHOD2(exclusive, double(double, double));
+  MOCK_METHOD2(inclusive, double(double, double));
+};
+
+TEST(RandomTest, PassesThroughExclusiveIntegerCall) {
+  auto mock = std::make_shared<mock_random_impl>();
+  engine::random_number_generator generator{mock};
+  
+  EXPECT_CALL(*mock, exclusive(10)).Times(1);
+  generator.exclusive(10);
+}
+
+TEST(RandomTest, PassesThroughExclusiveDoubleCall) {
+  auto mock = std::make_shared<mock_random_impl>();
+  engine::random_number_generator generator{mock};
+  
+  EXPECT_CALL(*mock, exclusive(1.0, 10.0)).Times(1);
+  generator.exclusive(1.0, 10.0);
+}
+
+TEST(RandomTest, PassesThroughInclusiveDoubleCall) {
+  auto mock = std::make_shared<mock_random_impl>();
+  engine::random_number_generator generator{mock};
+  
+  EXPECT_CALL(*mock, inclusive(1.0, 10.0)).Times(1);
+  generator.inclusive(1.0, 10.0);
+}
+
+class kahan_summation {
+private:
+  double sum_{0.0};
+  double carry_{0.0};
+public:
+  kahan_summation() = default;
+  kahan_summation & operator+=(double d);
+  
+  explicit operator double() const { return sum_; }
+};
+
+kahan_summation & kahan_summation::operator+=(double num) {
+  double const yield = num - carry_;
+  double const total = sum_ + yield;
+  carry_ = (total - sum_) - yield;
+  sum_ = total;
+  return *this;
+}
+
+TEST(DefaultRandomTest, RandomDistributionIntIsUniform) {
+  engine::random_number_generator generator{};
+  kahan_summation sum{};
+  size_t const iters = 2000000;
+  for (size_t i = 0; i < iters; ++i) {
+    // All values from 0 - 100 are allowable
+    sum += generator.exclusive(101);
+  }
+  // Expected result is (0+99)/2 +/- 0.1%
+  EXPECT_THAT(double(sum) / iters, testing::DoubleNear(50, 0.05));
+}
+
+TEST(DefaultRandomTest, RandomDistributionDblIsUniform) {
+  engine::random_number_generator generator{};
+  kahan_summation sum{};
+  size_t const iters = 2000000;
+  for (size_t i = 0; i < iters; ++i) {
+    // All values from 0 - 99 are allowable
+    sum += generator.exclusive(0.0, 100.0);
+  }
+  // Expected result is [0.0, 100.0) +/- 0.1%
+  EXPECT_THAT(double(sum) / iters, testing::DoubleNear(50, 0.05));
+}
+
+TEST(DefaultRandomTest, InclusiveRangeMayIncludeValue) {
+  engine::random_number_generator generator{};
+  EXPECT_THAT(generator.inclusive(1.0, 1.0), testing::DoubleNear(1.0, 1E-6));
+}
+
+TEST(DefaultRandomTest, RandomDistributionDblInclIsUniform) {
+  engine::random_number_generator generator{};
+  kahan_summation sum{};
+  size_t const iters = 2000000;
+  for (size_t i = 0; i < iters; ++i) {
+    // All values in [0.0, 100.0] are allowable
+    sum += generator.inclusive(0.0, 100.0);
+  }
+  // Expected result is (0+100)/2 +/- 0.1%
+  EXPECT_THAT(double(sum) / iters, testing::DoubleNear(50, 0.05));
+}