Jelajahi Sumber

Convert to using GoogleTest

Sam Jaffe 6 tahun lalu
induk
melakukan
049734c7a5

+ 1 - 1
optional_stream.hpp

@@ -7,7 +7,7 @@
 
 #pragma once
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201402L
 #include <optional>
 #else
 #include <experimental/optional>

+ 22 - 0
optional.stream-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>

+ 181 - 84
optional.stream.xcodeproj/project.pbxproj

@@ -7,93 +7,135 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		CDF937521E3ED1C3003E5D5C /* optional_stream_tc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDF937511E3ED1C3003E5D5C /* optional_stream_tc.cpp */; };
+		CDEC1E1C235168A20091D9F2 /* optional_stream_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDF9374F1E3ED13A003E5D5C /* optional_stream_test.cxx */; };
+		CDEC1E1E235168E70091D9F2 /* stream in Resources */ = {isa = PBXBuildFile; fileRef = CDEC1E1D235168E70091D9F2 /* stream */; };
+		CDEC1E2023516B5F0091D9F2 /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDEC1D82235166300091D9F2 /* GoogleMock.framework */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXCopyFilesBuildPhase section */
-		CDF9373D1E3D793F003E5D5C /* CopyFiles */ = {
-			isa = PBXCopyFilesBuildPhase;
-			buildActionMask = 2147483647;
-			dstPath = /usr/share/man/man1/;
-			dstSubfolderSpec = 0;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 1;
+/* Begin PBXContainerItemProxy section */
+		CDEC1D81235166300091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F861A685AEA0072A469;
+			remoteInfo = GoogleMock;
+		};
+		CDEC1D83235166300091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96ABD1A68600C00204102;
+			remoteInfo = gmock;
+		};
+		CDEC1D85235166300091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96B1F1A68634900204102;
+			remoteInfo = gtest;
 		};
-/* End PBXCopyFilesBuildPhase section */
+		CDEC1D87235166300091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F901A685AEA0072A469;
+			remoteInfo = GoogleMockTests;
+		};
+/* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
-		CDF9373F1E3D793F003E5D5C /* optional_stream_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = optional_stream_tc; sourceTree = BUILT_PRODUCTS_DIR; };
-		CDF9374B1E3D797D003E5D5C /* optional_stream.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = optional_stream.hpp; sourceTree = "<group>"; };
-		CDF9374F1E3ED13A003E5D5C /* optional_stream.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = optional_stream.t.h; sourceTree = "<group>"; };
-		CDF937511E3ED1C3003E5D5C /* optional_stream_tc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = optional_stream_tc.cpp; sourceTree = "<group>"; };
+		CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
+		CDEC1E142351687E0091D9F2 /* optional.stream-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "optional.stream-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+		CDEC1E182351687E0091D9F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		CDEC1E1D235168E70091D9F2 /* stream */ = {isa = PBXFileReference; lastKnownFileType = folder; name = stream; path = include/stream; sourceTree = "<group>"; };
+		CDF9374F1E3ED13A003E5D5C /* optional_stream_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = optional_stream_test.cxx; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
-		CDF9373C1E3D793F003E5D5C /* Frameworks */ = {
+		CDEC1E112351687E0091D9F2 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				CDEC1E2023516B5F0091D9F2 /* GoogleMock.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		CDF937361E3D793F003E5D5C = {
+		CDEC1D7B235166300091D9F2 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				CDF937491E3D795F003E5D5C /* src */,
-				CDF9374A1E3D7962003E5D5C /* test */,
-				CDF937401E3D793F003E5D5C /* Products */,
+				CDEC1D82235166300091D9F2 /* GoogleMock.framework */,
+				CDEC1D84235166300091D9F2 /* gmock.framework */,
+				CDEC1D86235166300091D9F2 /* gtest.framework */,
+				CDEC1D88235166300091D9F2 /* GoogleMockTests.xctest */,
 			);
+			name = Products;
 			sourceTree = "<group>";
 		};
-		CDF937401E3D793F003E5D5C /* Products */ = {
+		CDEC1E152351687E0091D9F2 /* optional.stream-test */ = {
 			isa = PBXGroup;
 			children = (
-				CDF9373F1E3D793F003E5D5C /* optional_stream_tc */,
+				CDEC1E182351687E0091D9F2 /* Info.plist */,
 			);
-			name = Products;
+			path = "optional.stream-test";
 			sourceTree = "<group>";
 		};
-		CDF937491E3D795F003E5D5C /* src */ = {
+		CDEC1E1F23516B5F0091D9F2 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				CDF9374B1E3D797D003E5D5C /* optional_stream.hpp */,
 			);
-			name = src;
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		CDF937361E3D793F003E5D5C = {
+			isa = PBXGroup;
+			children = (
+				CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */,
+				CDEC1E1D235168E70091D9F2 /* stream */,
+				CDF9374A1E3D7962003E5D5C /* test */,
+				CDEC1E152351687E0091D9F2 /* optional.stream-test */,
+				CDF937401E3D793F003E5D5C /* Products */,
+				CDEC1E1F23516B5F0091D9F2 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		CDF937401E3D793F003E5D5C /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDEC1E142351687E0091D9F2 /* optional.stream-test.xctest */,
+			);
+			name = Products;
 			sourceTree = "<group>";
 		};
 		CDF9374A1E3D7962003E5D5C /* test */ = {
 			isa = PBXGroup;
 			children = (
-				CDF9374F1E3ED13A003E5D5C /* optional_stream.t.h */,
-				CDF937511E3ED1C3003E5D5C /* optional_stream_tc.cpp */,
+				CDF9374F1E3ED13A003E5D5C /* optional_stream_test.cxx */,
 			);
-			name = test;
+			path = test;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		CDF9373E1E3D793F003E5D5C /* optional_stream_tc */ = {
+		CDEC1E132351687E0091D9F2 /* optional.stream-test */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = CDF937461E3D793F003E5D5C /* Build configuration list for PBXNativeTarget "optional_stream_tc" */;
+			buildConfigurationList = CDEC1E192351687E0091D9F2 /* Build configuration list for PBXNativeTarget "optional.stream-test" */;
 			buildPhases = (
-				CDF937501E3ED193003E5D5C /* ShellScript */,
-				CDF9373B1E3D793F003E5D5C /* Sources */,
-				CDF9373C1E3D793F003E5D5C /* Frameworks */,
-				CDF9373D1E3D793F003E5D5C /* CopyFiles */,
+				CDEC1E102351687E0091D9F2 /* Sources */,
+				CDEC1E112351687E0091D9F2 /* Frameworks */,
+				CDEC1E122351687E0091D9F2 /* Resources */,
 			);
 			buildRules = (
 			);
 			dependencies = (
 			);
-			name = optional_stream_tc;
-			productName = optional.stream;
-			productReference = CDF9373F1E3D793F003E5D5C /* optional_stream_tc */;
-			productType = "com.apple.product-type.tool";
+			name = "optional.stream-test";
+			productName = "optional.stream-test";
+			productReference = CDEC1E142351687E0091D9F2 /* optional.stream-test.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
 		};
 /* End PBXNativeTarget section */
 
@@ -101,11 +143,12 @@
 		CDF937371E3D793F003E5D5C /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1030;
+				LastUpgradeCheck = 1110;
 				ORGANIZATIONNAME = "Sam Jaffe";
 				TargetAttributes = {
-					CDF9373E1E3D793F003E5D5C = {
-						CreatedOnToolsVersion = 7.2.1;
+					CDEC1E132351687E0091D9F2 = {
+						CreatedOnToolsVersion = 11.1;
+						ProvisioningStyle = Automatic;
 					};
 				};
 			};
@@ -120,44 +163,116 @@
 			mainGroup = CDF937361E3D793F003E5D5C;
 			productRefGroup = CDF937401E3D793F003E5D5C /* Products */;
 			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = CDEC1D7B235166300091D9F2 /* Products */;
+					ProjectRef = CDEC1D7A235166300091D9F2 /* GoogleMock.xcodeproj */;
+				},
+			);
 			projectRoot = "";
 			targets = (
-				CDF9373E1E3D793F003E5D5C /* optional_stream_tc */,
+				CDEC1E132351687E0091D9F2 /* optional.stream-test */,
 			);
 		};
 /* End PBXProject section */
 
-/* Begin PBXShellScriptBuildPhase section */
-		CDF937501E3ED193003E5D5C /* ShellScript */ = {
-			isa = PBXShellScriptBuildPhase;
+/* Begin PBXReferenceProxy section */
+		CDEC1D82235166300091D9F2 /* GoogleMock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = GoogleMock.framework;
+			remoteRef = CDEC1D81235166300091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDEC1D84235166300091D9F2 /* gmock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gmock.framework;
+			remoteRef = CDEC1D83235166300091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDEC1D86235166300091D9F2 /* gtest.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gtest.framework;
+			remoteRef = CDEC1D85235166300091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDEC1D88235166300091D9F2 /* GoogleMockTests.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = GoogleMockTests.xctest;
+			remoteRef = CDEC1D87235166300091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		CDEC1E122351687E0091D9F2 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-			);
-			inputPaths = (
-				"$(SRCROOT)/optional_stream.t.h",
-				"$(SRCROOT)/either_stream.t.h",
-			);
-			outputPaths = (
-				"$(SRCROOT)/optional_stream_tc.cpp",
+				CDEC1E1E235168E70091D9F2 /* stream in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "cxxtestgen --error-printer -o optional_stream_tc.cpp optional_stream.t.h either_stream.t.h";
 		};
-/* End PBXShellScriptBuildPhase section */
+/* End PBXResourcesBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
-		CDF9373B1E3D793F003E5D5C /* Sources */ = {
+		CDEC1E102351687E0091D9F2 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				CDF937521E3ED1C3003E5D5C /* optional_stream_tc.cpp in Sources */,
+				CDEC1E1C235168A20091D9F2 /* optional_stream_test.cxx in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
+		CDEC1E1A2351687E0091D9F2 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				INFOPLIST_FILE = "optional.stream-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.optional-stream-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		CDEC1E1B2351687E0091D9F2 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				INFOPLIST_FILE = "optional.stream-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_FAST_MATH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.optional-stream-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
 		CDF937441E3D793F003E5D5C /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -209,6 +324,7 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = ./include/;
 			};
 			name = Debug;
 		};
@@ -256,46 +372,27 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
-			};
-			name = Release;
-		};
-		CDF937471E3D793F003E5D5C /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-				HEADER_SEARCH_PATHS = /usr/local/include/;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				USER_HEADER_SEARCH_PATHS = "";
-			};
-			name = Debug;
-		};
-		CDF937481E3D793F003E5D5C /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-				HEADER_SEARCH_PATHS = /usr/local/include/;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				USER_HEADER_SEARCH_PATHS = "";
+				USER_HEADER_SEARCH_PATHS = ./include/;
 			};
 			name = Release;
 		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		CDF9373A1E3D793F003E5D5C /* Build configuration list for PBXProject "optional.stream" */ = {
+		CDEC1E192351687E0091D9F2 /* Build configuration list for PBXNativeTarget "optional.stream-test" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				CDF937441E3D793F003E5D5C /* Debug */,
-				CDF937451E3D793F003E5D5C /* Release */,
+				CDEC1E1A2351687E0091D9F2 /* Debug */,
+				CDEC1E1B2351687E0091D9F2 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		CDF937461E3D793F003E5D5C /* Build configuration list for PBXNativeTarget "optional_stream_tc" */ = {
+		CDF9373A1E3D793F003E5D5C /* Build configuration list for PBXProject "optional.stream" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				CDF937471E3D793F003E5D5C /* Debug */,
-				CDF937481E3D793F003E5D5C /* Release */,
+				CDF937441E3D793F003E5D5C /* Debug */,
+				CDF937451E3D793F003E5D5C /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;

+ 0 - 45
optional_stream.t.h

@@ -1,45 +0,0 @@
-//
-//  optional_stream.t.h
-//  optional.stream
-//
-//  Created by Sam Jaffe on 1/29/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "optional_stream.hpp"
-
-class optional_stream_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_optional_processes_real() {
-    auto strm = stream::optional::make_stream(5);
-    auto plus2 = [](int i) { return i+2; };
-    std::optional<int> out = strm.map(plus2);
-    TS_ASSERT(out);
-    TS_ASSERT_EQUALS(*out, 7);
-  }
-  
-  void test_optional_ignores_fake() {
-    auto strm = stream::optional::make_stream<int>();
-    auto fail = [](int i) { TS_FAIL("Expected Empty"); return i; };
-    std::optional<int> out = strm.map(fail);
-    TS_ASSERT(!out);
-  }
-  
-  void test_optional_flatmap_can_become_empty() {
-    auto strm = stream::optional::make_stream(5);
-    auto discard_odd = [](int i) { return i%2==0? std::optional<int>(i) : std::nullopt; };
-    std::optional<int> out = strm.flatmap(discard_odd);
-    TS_ASSERT(!out);
-  }
-
-  void test_optional_flatmap_can_remain_exists() {
-    auto strm = stream::optional::make_stream(6);
-    auto discard_odd = [](int i) { return i%2==0? std::optional<int>(i) : std::nullopt; };
-    std::optional<int> out = strm.flatmap(discard_odd);
-    TS_ASSERT(out);
-    TS_ASSERT_EQUALS(*out, 6);
-  }
-};

+ 66 - 0
test/optional_stream_test.cxx

@@ -0,0 +1,66 @@
+//
+//  optional_stream.t.h
+//  optional.stream
+//
+//  Created by Sam Jaffe on 1/29/17.
+//
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "stream/optional_stream.hpp"
+
+using ::testing::Eq;
+
+MATCHER(Absent, "") {
+  return !arg.has_value();
+}
+
+MATCHER(Present, "") {
+  return arg.has_value();
+}
+
+MATCHER_P(OptionalIs, value, "") {
+  return arg.has_value() && *arg == value;
+}
+
+TEST(OptionalStreamTest, processes_real) {
+  auto strm = stream::optional::make_stream(5);
+  auto plus2 = [](int i) { return i+2; };
+  std::optional<int> out = strm.map(plus2);
+  
+  EXPECT_THAT(out, Present());
+  EXPECT_THAT(*out, Eq(7));
+}
+
+TEST(OptionalStreamTest, NoOpWhenUsedOnNullOpts) {
+  auto strm = stream::optional::make_stream<int>();
+  auto fail = [](int i) { throw std::runtime_error{"nullopt"}; return i; };
+  std::optional<int> out;
+  
+  EXPECT_NO_THROW(out = strm.map(fail));
+  EXPECT_THAT(out, Absent());
+}
+
+TEST(OptionalStreamTest, FlatmapFunctionCanProduceNullOpt) {
+  auto strm = stream::optional::make_stream(5);
+  auto discard_odd = [](int i) {
+    return i%2==0? std::optional<int>(i) : std::nullopt;
+  };
+  std::optional<int> out;
+  
+  EXPECT_NO_THROW(out = strm.flatmap(discard_odd));
+  EXPECT_THAT(out, Absent());
+}
+
+TEST(OptionalStreamTest, FlatmapFunctionCanProduceRealValues) {
+  auto strm = stream::optional::make_stream(6);
+  auto discard_odd = [](int i) {
+    return i%2==0? std::optional<int>(i) : std::nullopt;
+  };
+  std::optional<int> out;
+  
+  EXPECT_NO_THROW(out = strm.flatmap(discard_odd));
+  EXPECT_THAT(out, Present());
+  EXPECT_THAT(out, OptionalIs(6));
+}