diff --git a/change/react-native-windows-2020-05-11-11-06-42-FixReactContext.json b/change/react-native-windows-2020-05-11-11-06-42-FixReactContext.json
new file mode 100644
index 00000000000..d3bc77290fd
--- /dev/null
+++ b/change/react-native-windows-2020-05-11-11-06-42-FixReactContext.json
@@ -0,0 +1,8 @@
+{
+ "type": "prerelease",
+ "comment": "Fixed ReactContext copy/move semantic",
+ "packageName": "react-native-windows",
+ "email": "vmorozov@microsoft.com",
+ "dependentChangeType": "patch",
+ "date": "2020-05-11T18:06:42.425Z"
+}
diff --git a/vnext/Microsoft.ReactNative.Cxx.UnitTests/Microsoft.ReactNative.Cxx.UnitTests.vcxproj b/vnext/Microsoft.ReactNative.Cxx.UnitTests/Microsoft.ReactNative.Cxx.UnitTests.vcxproj
index 1849911ed19..79d66fa1e3a 100644
--- a/vnext/Microsoft.ReactNative.Cxx.UnitTests/Microsoft.ReactNative.Cxx.UnitTests.vcxproj
+++ b/vnext/Microsoft.ReactNative.Cxx.UnitTests/Microsoft.ReactNative.Cxx.UnitTests.vcxproj
@@ -126,6 +126,7 @@
Create
+
diff --git a/vnext/Microsoft.ReactNative.Cxx.UnitTests/ReactContextTest.cpp b/vnext/Microsoft.ReactNative.Cxx.UnitTests/ReactContextTest.cpp
new file mode 100644
index 00000000000..c2d28914c93
--- /dev/null
+++ b/vnext/Microsoft.ReactNative.Cxx.UnitTests/ReactContextTest.cpp
@@ -0,0 +1,113 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include
+#include "ReactModuleBuilderMock.h"
+
+using namespace winrt::Microsoft::ReactNative;
+
+struct ReactContextStub : implements {
+ IReactPropertyBag Properties() noexcept {
+ VerifyElseCrashSz(false, "Not implemented");
+ }
+
+ void DispatchEvent(
+ xaml::FrameworkElement const & /*view*/,
+ hstring const & /*eventName*/,
+ JSValueArgWriter const & /*eventDataArgWriter*/) noexcept {
+ VerifyElseCrashSz(false, "Not implemented");
+ }
+
+ void CallJSFunction(
+ hstring const & /*moduleName*/,
+ hstring const & /*functionName*/,
+ JSValueArgWriter const & /*paramsArgWriter*/) noexcept {
+ VerifyElseCrashSz(false, "Not implemented");
+ }
+
+ void EmitJSEvent(
+ hstring const & /*eventEmitterName*/,
+ hstring const & /*eventName*/,
+ JSValueArgWriter const & /*paramsArgWriter*/) noexcept {
+ VerifyElseCrashSz(false, "Not implemented");
+ }
+};
+
+namespace ReactNativeTests {
+
+TEST_CLASS (ReactContextTest) {
+ TEST_METHOD(Test_ctor_Default) {
+ ReactContext context;
+ TestCheck(!context);
+ }
+
+ TEST_METHOD(Test_ctor_IReactContext) {
+ auto reactContextMock = winrt::make();
+ ReactContext context{reactContextMock};
+ TestCheck(context);
+ }
+
+ TEST_METHOD(Test_ctor_copy) {
+ auto reactContextMock = winrt::make();
+ ReactContext context1{reactContextMock};
+ ReactContext context2{context1};
+ TestCheck(context1);
+ TestCheck(context2);
+ TestCheckEqual(context1, context2);
+ }
+
+ TEST_METHOD(Test_ctor_move) {
+ auto reactContextMock = winrt::make();
+ ReactContext context1{reactContextMock};
+ ReactContext context2{std::move(context1)};
+ TestCheck(!context1);
+ TestCheck(context2);
+ }
+
+ TEST_METHOD(Test_assign_nullptr) {
+ ReactContext context;
+ context = nullptr;
+ TestCheck(!context);
+ }
+
+ TEST_METHOD(Test_assign_copy) {
+ auto reactContextMock = winrt::make();
+ ReactContext context1{reactContextMock};
+ ReactContext context2;
+ context2 = context1;
+ TestCheck(context1);
+ TestCheck(context2);
+ TestCheckEqual(context1, context2);
+ }
+
+ TEST_METHOD(Test_assign_move) {
+ auto reactContextMock = winrt::make();
+ ReactContext context1{reactContextMock};
+ ReactContext context2;
+ context2 = std::move(context1);
+ TestCheck(!context1);
+ TestCheck(context2);
+ }
+
+ TEST_METHOD(Test_compare) {
+ auto reactContextMock1 = winrt::make();
+ auto reactContextMock2 = winrt::make();
+ ReactContext context11{reactContextMock1};
+ ReactContext context12{context11};
+ ReactContext context2{reactContextMock2};
+ ReactContext context3;
+ TestCheck(context11 == context12);
+ TestCheck(context12 == context11);
+ TestCheck(context11 != context2);
+ TestCheck(context11 != context3);
+ TestCheck(context2 != context11);
+ TestCheck(context3 != context11);
+ TestCheck(context3 == nullptr);
+ TestCheck(nullptr == context3);
+ TestCheck(context11 != nullptr);
+ TestCheck(nullptr != context11);
+ }
+};
+
+} // namespace ReactNativeTests
diff --git a/vnext/Microsoft.ReactNative.Cxx/JSValueWriter.h b/vnext/Microsoft.ReactNative.Cxx/JSValueWriter.h
index 547ac7ead65..80b6cb68748 100644
--- a/vnext/Microsoft.ReactNative.Cxx/JSValueWriter.h
+++ b/vnext/Microsoft.ReactNative.Cxx/JSValueWriter.h
@@ -5,8 +5,9 @@
#ifndef MICROSOFT_REACTNATIVE_JSVALUEWRITER
#define MICROSOFT_REACTNATIVE_JSVALUEWRITER
+#include
+#include "JSValue.h"
#include "StructInfo.h"
-#include "winrt/Microsoft.ReactNative.h"
namespace winrt::Microsoft::ReactNative {
diff --git a/vnext/Microsoft.ReactNative.Cxx/ReactContext.h b/vnext/Microsoft.ReactNative.Cxx/ReactContext.h
index a40c869f3c6..3dc09ee14ad 100644
--- a/vnext/Microsoft.ReactNative.Cxx/ReactContext.h
+++ b/vnext/Microsoft.ReactNative.Cxx/ReactContext.h
@@ -16,6 +16,8 @@ namespace winrt::Microsoft::ReactNative {
// It wraps up the IReactContext and adds convenience methods for
// working with C++ types.
struct ReactContext {
+ ReactContext(std::nullptr_t = nullptr) noexcept {}
+
ReactContext(IReactContext const &handle) noexcept : m_handle{handle} {}
IReactContext const &Handle() const noexcept {
@@ -66,8 +68,32 @@ struct ReactContext {
m_handle.DispatchEvent(view, eventName, paramsArgWriter);
}
+ friend bool operator==(ReactContext const &left, ReactContext const &right) noexcept {
+ return left.m_handle == right.m_handle;
+ }
+
+ friend bool operator!=(ReactContext const &left, ReactContext const &right) noexcept {
+ return left.m_handle != right.m_handle;
+ }
+
+ friend bool operator==(ReactContext const &left, std::nullptr_t) noexcept {
+ return !static_cast(left.m_handle);
+ }
+
+ friend bool operator!=(ReactContext const &left, std::nullptr_t) noexcept {
+ return static_cast(left.m_handle);
+ }
+
+ friend bool operator==(std::nullptr_t, ReactContext const &right) noexcept {
+ return !static_cast(right.m_handle);
+ }
+
+ friend bool operator!=(std::nullptr_t, ReactContext const &right) noexcept {
+ return static_cast(right.m_handle);
+ }
+
private:
- const IReactContext m_handle;
+ IReactContext m_handle;
};
} // namespace winrt::Microsoft::ReactNative
diff --git a/vnext/Microsoft.ReactNative.IntegrationTests/ReactNativeHostTests.cpp b/vnext/Microsoft.ReactNative.IntegrationTests/ReactNativeHostTests.cpp
index 11d16009c32..2f11c1d9291 100644
--- a/vnext/Microsoft.ReactNative.IntegrationTests/ReactNativeHostTests.cpp
+++ b/vnext/Microsoft.ReactNative.IntegrationTests/ReactNativeHostTests.cpp
@@ -1,5 +1,7 @@
#include "pch.h"
+#include
+
using namespace React;
namespace ReactNativeIntegrationTests {
diff --git a/vnext/Microsoft.ReactNative.IntegrationTests/ReactPropertyBagTests.cpp b/vnext/Microsoft.ReactNative.IntegrationTests/ReactPropertyBagTests.cpp
index 7553d4be66a..27168257d81 100644
--- a/vnext/Microsoft.ReactNative.IntegrationTests/ReactPropertyBagTests.cpp
+++ b/vnext/Microsoft.ReactNative.IntegrationTests/ReactPropertyBagTests.cpp
@@ -491,7 +491,6 @@ TEST_CLASS (ReactPropertyBagTests) {
}
TEST_METHOD(PropertyBag_Property_string) {
- // We only support enums defined in IDL.
ReactPropertyId fooName{L"Foo"};
ReactPropertyBag pb{ReactPropertyBagHelper::CreatePropertyBag()};
@@ -504,6 +503,25 @@ TEST_CLASS (ReactPropertyBagTests) {
pb.Remove(fooName);
TestCheck(!pb.Get(fooName));
}
+
+ TEST_METHOD(PropertyBag_Property_delegate) {
+ ReactPropertyId fooName{L"Foo"};
+ ReactPropertyBag pb{ReactPropertyBagHelper::CreatePropertyBag()};
+
+ TestCheck(!pb.Get(fooName));
+ ReactCreatePropertyValue createValue1 = []() { return winrt::box_value(5); };
+ TestCheckEqual(createValue1, *pb.GetOrCreate(fooName, [&createValue1]() { return createValue1; }));
+ TestCheckEqual(createValue1, *pb.Get(fooName));
+ TestCheckEqual(5, winrt::unbox_value((*pb.Get(fooName))()));
+
+ ReactCreatePropertyValue createValue2 = []() { return winrt::box_value(10); };
+ pb.Set(fooName, createValue2);
+ TestCheckEqual(createValue2, *pb.Get(fooName));
+ TestCheckEqual(10, winrt::unbox_value((*pb.Get(fooName))()));
+ TestCheck(createValue1 != *pb.Get(fooName));
+ pb.Remove(fooName);
+ TestCheck(!pb.Get(fooName));
+ }
};
} // namespace ReactNativeIntegrationTests
diff --git a/vnext/Microsoft.ReactNative.IntegrationTests/pch.h b/vnext/Microsoft.ReactNative.IntegrationTests/pch.h
index cde08a53662..19f70f55b7b 100644
--- a/vnext/Microsoft.ReactNative.IntegrationTests/pch.h
+++ b/vnext/Microsoft.ReactNative.IntegrationTests/pch.h
@@ -3,7 +3,6 @@
#define NOMINMAX
#include
-#include "NativeModules.h"
#include "functional/functor.h"
#include "motifCpp/testCheck.h"