Browse Source

test: write/import test cases for universe and config

Sam Jaffe 2 years ago
parent
commit
c73b945d5c

+ 8 - 0
engine-test/Info.plist

@@ -0,0 +1,8 @@
+<?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>Resource Directory</key>
+	<string>$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)</string>
+</dict>
+</plist>

+ 52 - 0
engine-test/engine_test_xc.mm

@@ -0,0 +1,52 @@
+//
+//  eninge_test_xc.mm
+//  pokemon_test_xc
+//
+//  Created by Sam Jaffe on 12/22/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#include <string>
+
+@interface engine_test_xc : NSObject
+-(NSString*) getResourceDir;
+@end
+
+@implementation engine_test_xc
+
+-(NSString*) getResourceDir {
+  NSBundle* bundle = [NSBundle bundleForClass:[self class]];
+  NSDictionary* infoDict = [bundle infoDictionary];
+  return [infoDict objectForKey:@"Resource Directory"];
+}
+
+@end
+
+std::string resource_dir() {
+  engine_test_xc * test = [[engine_test_xc alloc] init];
+  return [[test getResourceDir] UTF8String];
+}
+
+std::string resource(std::string const & rel_path) {
+  return resource_dir() + "/" + rel_path;
+}
+
+#include "../test/stub_config.h"
+#include <json/json.h>
+
+Json::Value construct_test_config(std::string const & dir = "") {
+  Json::Value json;
+  json["resource_path"] = dir.empty() ? resource_dir() : resource(dir);
+  json["properties"]["object"] = "@resource/object";
+  return json;
+}
+
+Config Config::from_dir(std::string const & dir) {
+  return Config(construct_test_config(dir));
+}
+Config::Config() : engine::env::Config(construct_test_config()) {}
+Config::Config(std::string const & filename) :
+    engine::env::Config(Config().resource(filename)) {}
+Config::Config(Json::Value const & properties) :
+    engine::env::Config(properties) {}

+ 203 - 6
engine.xcodeproj/project.pbxproj

@@ -11,9 +11,24 @@
 		CDD4759429C4B7A200BDB829 /* config.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDD4759129C4B7A200BDB829 /* config.cxx */; };
 		CDD4759529C4B7A200BDB829 /* event.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDD4759229C4B7A200BDB829 /* event.cxx */; };
 		CDD4759629C4B7A200BDB829 /* condition.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDD4759329C4B7A200BDB829 /* condition.cxx */; };
-		CDD4759A29C4BB0C00BDB829 /* event.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4759729C4BB0C00BDB829 /* event.h */; };
-		CDD4759B29C4BB0C00BDB829 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4759829C4BB0C00BDB829 /* config.h */; };
-		CDD4759C29C4BB0C00BDB829 /* condition.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4759929C4BB0C00BDB829 /* condition.h */; };
+		CDD475C829C4D2BF00BDB829 /* libengine.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD592BDB29C2A399009AC14E /* libengine.a */; };
+		CDD475D029C4D2F700BDB829 /* libjsoncpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDD475CF29C4D2F700BDB829 /* libjsoncpp.a */; };
+		CDD475D129C4D2FC00BDB829 /* libjsoncpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDD475CF29C4D2F700BDB829 /* libjsoncpp.a */; };
+		CDD475D229C4D30100BDB829 /* engine in Headers */ = {isa = PBXBuildFile; fileRef = CD592BE529C2A3E0009AC14E /* engine */; settings = {ATTRIBUTES = (Public, ); }; };
+		CDD475D329C4D32300BDB829 /* condition.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4759929C4BB0C00BDB829 /* condition.h */; };
+		CDD475D429C4D32400BDB829 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4759829C4BB0C00BDB829 /* config.h */; };
+		CDD475D529C4D32600BDB829 /* event.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4759729C4BB0C00BDB829 /* event.h */; };
+		CDD475D629C4D32800BDB829 /* forwards.h in Headers */ = {isa = PBXBuildFile; fileRef = CD592BF229C2A506009AC14E /* forwards.h */; };
+		CDD475D729C4D32900BDB829 /* mailbox.h in Headers */ = {isa = PBXBuildFile; fileRef = CD592C0E29C3D1E7009AC14E /* mailbox.h */; };
+		CDD475D829C4D32B00BDB829 /* universe.h in Headers */ = {isa = PBXBuildFile; fileRef = CD592BF029C2A462009AC14E /* universe.h */; };
+		CDD475D929C4D32C00BDB829 /* universe.tpp in Headers */ = {isa = PBXBuildFile; fileRef = CD592BF329C2A531009AC14E /* universe.tpp */; };
+		CDD475DC29C4D35F00BDB829 /* config_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDD475DB29C4D35F00BDB829 /* config_test.cxx */; };
+		CDD475DF29C4D38D00BDB829 /* universe_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDD475DE29C4D38D00BDB829 /* universe_test.cxx */; };
+		CDD475FE29C4D8C400BDB829 /* universe_test in Resources */ = {isa = PBXBuildFile; fileRef = CDD475FC29C4D8C400BDB829 /* universe_test */; };
+		CDD475FF29C4D8C400BDB829 /* config_test in Resources */ = {isa = PBXBuildFile; fileRef = CDD475FD29C4D8C400BDB829 /* config_test */; };
+		CDD4760129C4D93E00BDB829 /* engine_test_xc.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDD4760029C4D93E00BDB829 /* engine_test_xc.mm */; };
+		CDD4760229C4D99C00BDB829 /* libshared_random_generator.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CDD475A429C4CDB500BDB829 /* libshared_random_generator.dylib */; };
+		CDD4760329C4D9AE00BDB829 /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDD475B929C4CDBF00BDB829 /* GoogleMock.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -73,6 +88,13 @@
 			remoteGlobalIDString = 05818F901A685AEA0072A469;
 			remoteInfo = GoogleMockTests;
 		};
+		CDD475C929C4D2BF00BDB829 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD592BD329C2A399009AC14E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = CD592BDA29C2A399009AC14E;
+			remoteInfo = engine;
+		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
@@ -92,6 +114,16 @@
 		CDD4759D29C4CDB500BDB829 /* shared_random_generator.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = shared_random_generator.xcodeproj; path = external/shared_random_generator/shared_random_generator.xcodeproj; sourceTree = "<group>"; };
 		CDD475A729C4CDBA00BDB829 /* string-utils.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "string-utils.xcodeproj"; path = "external/string-utils/string-utils.xcodeproj"; sourceTree = "<group>"; };
 		CDD475B129C4CDBF00BDB829 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
+		CDD475C429C4D2BF00BDB829 /* engine-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "engine-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+		CDD475CF29C4D2F700BDB829 /* libjsoncpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjsoncpp.a; path = ../../../../../../../../opt/local/lib/libjsoncpp.a; sourceTree = "<group>"; };
+		CDD475DA29C4D35400BDB829 /* xcode_gtest_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xcode_gtest_helper.h; sourceTree = "<group>"; };
+		CDD475DB29C4D35F00BDB829 /* config_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_test.cxx; sourceTree = "<group>"; };
+		CDD475DD29C4D36700BDB829 /* stub_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stub_config.h; sourceTree = "<group>"; };
+		CDD475DE29C4D38D00BDB829 /* universe_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = universe_test.cxx; sourceTree = "<group>"; };
+		CDD475FC29C4D8C400BDB829 /* universe_test */ = {isa = PBXFileReference; lastKnownFileType = folder; path = universe_test; sourceTree = "<group>"; };
+		CDD475FD29C4D8C400BDB829 /* config_test */ = {isa = PBXFileReference; lastKnownFileType = folder; path = config_test; sourceTree = "<group>"; };
+		CDD4760029C4D93E00BDB829 /* engine_test_xc.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = engine_test_xc.mm; sourceTree = "<group>"; };
+		CDD4760629C4DB2400BDB829 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -99,6 +131,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				CDD475D029C4D2F700BDB829 /* libjsoncpp.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		CDD475C129C4D2BF00BDB829 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CDD475C829C4D2BF00BDB829 /* libengine.a in Frameworks */,
+				CDD475D129C4D2FC00BDB829 /* libjsoncpp.a in Frameworks */,
+				CDD4760229C4D99C00BDB829 /* libshared_random_generator.dylib in Frameworks */,
+				CDD4760329C4D9AE00BDB829 /* GoogleMock.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -115,7 +159,9 @@
 				CD592BE229C2A3C8009AC14E /* include */,
 				CD592BE429C2A3C8009AC14E /* src */,
 				CD592BE329C2A3C8009AC14E /* test */,
+				CDD475C529C4D2BF00BDB829 /* engine-test */,
 				CD592BDC29C2A399009AC14E /* Products */,
+				CDD475CE29C4D2F700BDB829 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -123,6 +169,7 @@
 			isa = PBXGroup;
 			children = (
 				CD592BDB29C2A399009AC14E /* libengine.a */,
+				CDD475C429C4D2BF00BDB829 /* engine-test.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -138,6 +185,11 @@
 		CD592BE329C2A3C8009AC14E /* test */ = {
 			isa = PBXGroup;
 			children = (
+				CDD475E029C4D49600BDB829 /* resources */,
+				CDD475DD29C4D36700BDB829 /* stub_config.h */,
+				CDD475DA29C4D35400BDB829 /* xcode_gtest_helper.h */,
+				CDD475DB29C4D35F00BDB829 /* config_test.cxx */,
+				CDD475DE29C4D38D00BDB829 /* universe_test.cxx */,
 			);
 			path = test;
 			sourceTree = "<group>";
@@ -196,6 +248,32 @@
 			name = Products;
 			sourceTree = "<group>";
 		};
+		CDD475C529C4D2BF00BDB829 /* engine-test */ = {
+			isa = PBXGroup;
+			children = (
+				CDD4760629C4DB2400BDB829 /* Info.plist */,
+				CDD4760029C4D93E00BDB829 /* engine_test_xc.mm */,
+			);
+			path = "engine-test";
+			sourceTree = "<group>";
+		};
+		CDD475CE29C4D2F700BDB829 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				CDD475CF29C4D2F700BDB829 /* libjsoncpp.a */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		CDD475E029C4D49600BDB829 /* resources */ = {
+			isa = PBXGroup;
+			children = (
+				CDD475FD29C4D8C400BDB829 /* config_test */,
+				CDD475FC29C4D8C400BDB829 /* universe_test */,
+			);
+			path = resources;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -203,9 +281,14 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				CDD4759B29C4BB0C00BDB829 /* config.h in Headers */,
-				CDD4759A29C4BB0C00BDB829 /* event.h in Headers */,
-				CDD4759C29C4BB0C00BDB829 /* condition.h in Headers */,
+				CDD475D229C4D30100BDB829 /* engine in Headers */,
+				CDD475D929C4D32C00BDB829 /* universe.tpp in Headers */,
+				CDD475D829C4D32B00BDB829 /* universe.h in Headers */,
+				CDD475D729C4D32900BDB829 /* mailbox.h in Headers */,
+				CDD475D629C4D32800BDB829 /* forwards.h in Headers */,
+				CDD475D529C4D32600BDB829 /* event.h in Headers */,
+				CDD475D429C4D32400BDB829 /* config.h in Headers */,
+				CDD475D329C4D32300BDB829 /* condition.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -229,6 +312,24 @@
 			productReference = CD592BDB29C2A399009AC14E /* libengine.a */;
 			productType = "com.apple.product-type.library.static";
 		};
+		CDD475C329C4D2BF00BDB829 /* engine-test */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CDD475CB29C4D2BF00BDB829 /* Build configuration list for PBXNativeTarget "engine-test" */;
+			buildPhases = (
+				CDD475C029C4D2BF00BDB829 /* Sources */,
+				CDD475C129C4D2BF00BDB829 /* Frameworks */,
+				CDD475C229C4D2BF00BDB829 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				CDD475CA29C4D2BF00BDB829 /* PBXTargetDependency */,
+			);
+			name = "engine-test";
+			productName = "engine-test";
+			productReference = CDD475C429C4D2BF00BDB829 /* engine-test.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
@@ -236,11 +337,15 @@
 			isa = PBXProject;
 			attributes = {
 				BuildIndependentTargetsInParallel = 1;
+				LastSwiftUpdateCheck = 1340;
 				LastUpgradeCheck = 1340;
 				TargetAttributes = {
 					CD592BDA29C2A399009AC14E = {
 						CreatedOnToolsVersion = 13.4.1;
 					};
+					CDD475C329C4D2BF00BDB829 = {
+						CreatedOnToolsVersion = 13.4.1;
+					};
 				};
 			};
 			buildConfigurationList = CD592BD629C2A399009AC14E /* Build configuration list for PBXProject "engine" */;
@@ -271,6 +376,7 @@
 			projectRoot = "";
 			targets = (
 				CD592BDA29C2A399009AC14E /* engine */,
+				CDD475C329C4D2BF00BDB829 /* engine-test */,
 			);
 		};
 /* End PBXProject section */
@@ -334,6 +440,18 @@
 		};
 /* End PBXReferenceProxy section */
 
+/* Begin PBXResourcesBuildPhase section */
+		CDD475C229C4D2BF00BDB829 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CDD475FF29C4D8C400BDB829 /* config_test in Resources */,
+				CDD475FE29C4D8C400BDB829 /* universe_test in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
 /* Begin PBXSourcesBuildPhase section */
 		CD592BD829C2A399009AC14E /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
@@ -346,8 +464,26 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		CDD475C029C4D2BF00BDB829 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CDD475DF29C4D38D00BDB829 /* universe_test.cxx in Sources */,
+				CDD475DC29C4D35F00BDB829 /* config_test.cxx in Sources */,
+				CDD4760129C4D93E00BDB829 /* engine_test_xc.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+		CDD475CA29C4D2BF00BDB829 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = CD592BDA29C2A399009AC14E /* engine */;
+			targetProxy = CDD475C929C4D2BF00BDB829 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
 /* Begin XCBuildConfiguration section */
 		CD592BDD29C2A399009AC14E /* Debug */ = {
 			isa = XCBuildConfiguration;
@@ -483,6 +619,10 @@
 			buildSettings = {
 				CODE_SIGN_STYLE = Automatic;
 				EXECUTABLE_PREFIX = lib;
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					/opt/local/lib,
+				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 			};
@@ -493,11 +633,59 @@
 			buildSettings = {
 				CODE_SIGN_STYLE = Automatic;
 				EXECUTABLE_PREFIX = lib;
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					/opt/local/lib,
+				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 			};
 			name = Release;
 		};
+		CDD475CC29C4D2BF00BDB829 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = "engine-test/Info.plist";
+				INFOPLIST_KEY_LSApplicationCategoryType = "";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					/opt/local/lib,
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.engine-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_EMIT_LOC_STRINGS = NO;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Debug;
+		};
+		CDD475CD29C4D2BF00BDB829 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = "engine-test/Info.plist";
+				INFOPLIST_KEY_LSApplicationCategoryType = "";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					/opt/local/lib,
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.engine-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_EMIT_LOC_STRINGS = NO;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Release;
+		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
@@ -519,6 +707,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		CDD475CB29C4D2BF00BDB829 /* Build configuration list for PBXNativeTarget "engine-test" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CDD475CC29C4D2BF00BDB829 /* Debug */,
+				CDD475CD29C4D2BF00BDB829 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
 	};
 	rootObject = CD592BD329C2A399009AC14E /* Project object */;

+ 12 - 1
engine.xcodeproj/xcshareddata/xcschemes/engine.xcscheme

@@ -26,8 +26,19 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      codeCoverageEnabled = "YES">
       <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "CDD475C329C4D2BF00BDB829"
+               BuildableName = "engine-test.xctest"
+               BlueprintName = "engine-test"
+               ReferencedContainer = "container:engine.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
       </Testables>
    </TestAction>
    <LaunchAction

+ 1 - 1
external/serializer

@@ -1 +1 @@
-Subproject commit 37078d681324582098c84b71f26aa671f20b0f47
+Subproject commit 36cebc397311635b3cb6708e7836e0ab8dea34f2

+ 1 - 1
include/engine/config.h

@@ -59,7 +59,7 @@ protected:
    * @param json A json object containing certain properties
    */
   Config(Json::Value const & json,
-         std::filesystem::path const & config_path = "");
+         std::filesystem::path const & config_path = "/");
 
 private:
   std::filesystem::path fix(std::filesystem::path input) const;

+ 3 - 1
include/engine/universe.h

@@ -33,11 +33,13 @@ public:
   /**
    * @brief Construct a universe with all necessary components
    * @param cfg The config object generated from reading a config file or JSON
+   * @param cache A serializer cache
    * @param rng A random number generator's underlying implementation. This
    * exists for dependency injection's sake. If rng is null, then random_ will
    * be constructed with the default random device.
    */
   Universe(std::shared_ptr<Mailbox> mailbox, env::Config const & cfg,
+           std::shared_ptr<serializer::SharedCache> cache,
            std::shared_ptr<detail::random_impl> rng);
   ~Universe();
 
@@ -49,7 +51,7 @@ protected:
    * @deprecated This exists solely for the purpose of needing to initialize
    * the singleton.
    */
-  Universe();
+  [[deprecated]] Universe();
   Universe(Universe &&) = default;
   Universe & operator=(Universe &&) = default;
 };

+ 8 - 5
include/engine/universe.tpp

@@ -12,15 +12,18 @@
 
 #include <json/json.h>
 
+#include <engine/config.h>
 #include <engine/universe.h>
+#include <serializer/jsonizer.tpp>
 
 namespace engine {
 template <typename T>
 void Universe::load(std::string const & name, std::string const & fallback) {
-  std::filesystem::path location = config().property(name, fallback);
-  if (!std::filesystem::exists(location)) { return; }
+  namespace fs = std::filesystem;
+  fs::path location = config().property(name, fallback);
+  if (!fs::exists(location)) { return; }
 
-  auto import = [this](auto & file) {
+  auto import = [this](fs::path const & file) {
     Json::Value json;
     std::ifstream in(file.string());
     in >> json;
@@ -34,8 +37,8 @@ void Universe::load(std::string const & name, std::string const & fallback) {
     }
   };
 
-  if (std::filesystem::is_directory(location)) {
-    std::for_each(std::filesystem::directory_iterator(location), {}, import);
+  if (fs::is_directory(location)) {
+    std::for_each(fs::directory_iterator(location), {}, import);
   } else {
     import(location);
   }

+ 11 - 0
src/config.cxx

@@ -49,6 +49,17 @@ Config::Config(Json::Value const & json,
 
 Config::~Config() {}
 
+std::filesystem::path Config::fix(std::filesystem::path path) const {
+  expects(!path.empty());
+  auto const root = *path.begin();
+  if (root == "@config") {
+    return config_path_ / path.lexically_relative(root);
+  } else if (root == "@resource") {
+    return resource_path_ / path.lexically_relative(root);
+  }
+  return path;
+}
+
 std::filesystem::path
 Config::resource(std::filesystem::path const & rel_path) const {
   return resource_path_ / rel_path;

+ 2 - 1
src/universe.cxx

@@ -17,11 +17,12 @@ namespace engine {
 
 Universe::Universe(std::shared_ptr<::engine::Mailbox> mailbox,
                    env::Config const & cfg,
+                   std::shared_ptr<serializer::SharedCache> cache,
                    std::shared_ptr<detail::random_impl> rng)
     : mailbox_(mailbox), config_(std::make_unique<env::Config>(cfg)),
       random_(rng ? std::make_unique<random_number_generator>(rng)
                   : std::make_unique<random_number_generator>()),
-      serialcache_(std::make_shared<serializer::SharedCache>()),
+      serialcache_(cache ?: std::make_shared<serializer::SharedCache>()),
       jsonizer_(std::make_unique<serializer::Jsonizer>(serialcache_)) {}
 
 Universe::Universe() {}

+ 32 - 0
test/config_test.cxx

@@ -0,0 +1,32 @@
+//
+//  config_test.cxx
+//  pokemon_test_xc
+//
+//  Created by Sam Jaffe on 12/22/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#include "xcode_gtest_helper.h"
+#include <json/json.h>
+
+#include "stub_config.h"
+
+using testing::Eq;
+
+TEST(ConfigTest, ConfigFileLoadAbsolutePath) {
+  Config cfg("config_test/absolute.cfg.json");
+  EXPECT_THAT(cfg.resource(""), Eq("/usr/local/lib/engine_test_xc/absolute/"));
+}
+
+TEST(ConfigTest, ConfigFileLoadSelfReferencePath) {
+  Config cfg("config_test/at-config.cfg.json");
+  std::string const root = Config().resource("config_test");
+  EXPECT_THAT(cfg.resource(""), Eq(root + "/relative/"));
+}
+
+TEST(ConfigTest, ConfigFromJsonCannotPerformAtConfigSubs) {
+  Json::Value json;
+  json["resource_path"] = "@config/root";
+  Config cfg(json);
+  EXPECT_THAT(cfg.resource(""), Eq("/root/"));
+}

+ 3 - 0
test/resources/config_test/absolute.cfg.json

@@ -0,0 +1,3 @@
+{
+  "resource_path":"/usr/local/lib/engine_test_xc/absolute"
+}

+ 3 - 0
test/resources/config_test/at-config.cfg.json

@@ -0,0 +1,3 @@
+{
+  "resource_path":"@config/relative"
+}

+ 7 - 0
test/resources/universe_test/1/object

@@ -0,0 +1,7 @@
+{
+  "name":"A",
+  "data": {
+    "ONE":1,
+    "ZERO":0
+  }
+}

+ 7 - 0
test/resources/universe_test/2/object/A.json

@@ -0,0 +1,7 @@
+{
+  "name":"A",
+  "data": {
+    "ONE":1,
+    "ZERO":0
+  }
+}

+ 7 - 0
test/resources/universe_test/2/object/B.json

@@ -0,0 +1,7 @@
+{
+  "name":"B",
+  "data": {
+    "ONE":1,
+    "ZERO":0
+  }
+}

+ 16 - 0
test/resources/universe_test/3/object

@@ -0,0 +1,16 @@
+[
+  {
+    "name": "A",
+    "data": {
+      "ONE":1,
+      "ZERO":0
+    }
+  },
+  {
+    "name": "B",
+    "data": {
+      "ONE":1,
+      "ZERO":0
+    }
+  }
+]

+ 19 - 0
test/stub_config.h

@@ -0,0 +1,19 @@
+//
+//  stub_config.h
+//  pokemon_test_xc
+//
+//  Created by Sam Jaffe on 12/22/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include "engine/config.h"
+
+struct Config : public engine::env::Config {
+  Config();
+  static Config from_dir(std::string const & dir);
+  explicit Config(char const * const file) : Config(std::string(file)) {}
+  explicit Config(std::string const & filename);
+  explicit Config(Json::Value const & properties);
+};

+ 98 - 0
test/universe_test.cxx

@@ -0,0 +1,98 @@
+//
+//  universe_test.cxx
+//  pokemon_test_xc
+//
+//  Created by Sam Jaffe on 1/12/19.
+//  Copyright © 2019 Sam Jaffe. All rights reserved.
+//
+
+#include <engine/universe.h>
+
+#include <map>
+
+#include <engine/universe.tpp>
+#include <serializer/jsonizer.tpp>
+#include <serializer/shared_cache.h>
+
+#include "stub_config.h"
+#include "xcode_gtest_helper.h"
+
+using testing::Eq;
+using testing::NotNull;
+using testing::TestWithParam;
+using testing::Values;
+
+struct Object {
+  std::string name;
+  std::map<std::string, int> data;
+};
+
+template <>
+void serializer::Jsonizer::from_json(Object & value,
+                                     Json::Value const & json) const {
+  from_json(value.name, json["name"]);
+  from_json(value.data, json["data"]);
+}
+
+struct SharedCache : serializer::SharedCache {
+  struct Impl : serializer::SharedCache::Impl {
+    std::map<SharedCache::Key, SharedCache::Record<Object>> objects_;
+  };
+
+  SharedCache() : serializer::SharedCache(std::make_unique<Impl>()) {}
+};
+
+#define IMPL() dynamic_cast<::SharedCache::Impl &>(*p_impl)
+
+template <>
+SharedCache::Record<Object>
+serializer::SharedCache::store<Object>(Key const & key, Object const & value) {
+  auto & ptr = IMPL().objects_[key];
+  if (!ptr) { ptr = std::make_shared<Object>(value); }
+  return ptr;
+}
+
+template <>
+SharedCache::Record<Object>
+serializer::SharedCache::fetch<Object>(Key const & key) const {
+  return IMPL().objects_[key];
+}
+
+struct Universe : engine::Universe {
+  Universe(std::filesystem::path const & cfg)
+      : engine::Universe(nullptr, Config::from_dir(cfg),
+                         std::make_shared<SharedCache>(), nullptr) {
+    load<Object>("object");
+  }
+
+  auto read(std::string const & name) const {
+    return jsonizer().from_json<SharedCache::Record<Object>>(name);
+  }
+};
+
+TEST(UniverseTest, CanLoadFromFile) {
+  Universe const univ("universe_test/1");
+  auto const ptr = univ.read("A");
+
+  EXPECT_THAT(ptr, NotNull());
+}
+
+class PreloadTest : public TestWithParam<std::string> {};
+
+TEST_P(PreloadTest, CanLoadFromDirectory) {
+  Universe const univ("universe_test/2");
+  auto const ptr = univ.read(GetParam());
+
+  EXPECT_THAT(ptr, NotNull());
+  EXPECT_THAT(ptr->name, GetParam());
+}
+
+TEST_P(PreloadTest, CanLoadFromArrayFile) {
+  Universe const univ("universe_test/3");
+  auto const ptr = univ.read(GetParam());
+
+  EXPECT_THAT(ptr, NotNull());
+  EXPECT_THAT(ptr->name, GetParam());
+}
+
+INSTANTIATE_TEST_SUITE_P(Universe, PreloadTest, Values("A", "B"));

+ 38 - 0
test/xcode_gtest_helper.h

@@ -0,0 +1,38 @@
+//
+//  xcode_gtest_helper.h
+//
+//  Created by Sam Jaffe on 11/25/20.
+//  Copyright © 2020 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#if defined(__APPLE__)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
+#pragma clang diagnostic ignored "-Wcomma"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#pragma clang diagnostic pop
+
+#if defined(TARGET_OS_OSX)
+// This is a hack to allow XCode to properly display failures when running
+// unit tests.
+#undef EXPECT_THAT
+#define EXPECT_THAT ASSERT_THAT
+#undef EXPECT_THROW
+#define EXPECT_THROW ASSERT_THROW
+#undef EXPECT_ANY_THROW
+#define EXPECT_ANY_THROW ASSERT_ANY_THROW
+#undef EXPECT_NO_THROW
+#define EXPECT_NO_THROW ASSERT_NO_THROW
+#undef EXPECT_TRUE
+#define EXPECT_TRUE ASSERT_TRUE
+#undef EXPECT_FALSE
+#define EXPECT_FALSE ASSERT_FALSE
+
+#endif
+#endif