Skip to content

Commit

Permalink
Fixed ReactContext copy/move semantic (#4870)
Browse files Browse the repository at this point in the history
* Fixed ReactContext copy/move semantic

* Change files

* Fixed formatting

* Test to show how to use a delegate in ReactPropertyBag
  • Loading branch information
vmoroz authored and NickGerleman committed May 14, 2020
1 parent c6c71f7 commit aa96215
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ReactContextTest.cpp" />
<ClCompile Include="ReactModuleBuilderMock.cpp" />
<ClCompile Include="TurboModuleTest.cpp" />
</ItemGroup>
Expand Down
113 changes: 113 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx.UnitTests/ReactContextTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "pch.h"
#include <ReactContext.h>
#include "ReactModuleBuilderMock.h"

using namespace winrt::Microsoft::ReactNative;

struct ReactContextStub : implements<ReactContextStub, IReactContext> {
IReactPropertyBag Properties() noexcept {
VerifyElseCrashSz(false, "Not implemented");
}

void DispatchEvent(
Windows::UI::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<ReactContextStub>();
ReactContext context{reactContextMock};
TestCheck(context);
}

TEST_METHOD(Test_ctor_copy) {
auto reactContextMock = winrt::make<ReactContextStub>();
ReactContext context1{reactContextMock};
ReactContext context2{context1};
TestCheck(context1);
TestCheck(context2);
TestCheckEqual(context1, context2);
}

TEST_METHOD(Test_ctor_move) {
auto reactContextMock = winrt::make<ReactContextStub>();
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<ReactContextStub>();
ReactContext context1{reactContextMock};
ReactContext context2;
context2 = context1;
TestCheck(context1);
TestCheck(context2);
TestCheckEqual(context1, context2);
}

TEST_METHOD(Test_assign_move) {
auto reactContextMock = winrt::make<ReactContextStub>();
ReactContext context1{reactContextMock};
ReactContext context2;
context2 = std::move(context1);
TestCheck(!context1);
TestCheck(context2);
}

TEST_METHOD(Test_compare) {
auto reactContextMock1 = winrt::make<ReactContextStub>();
auto reactContextMock2 = winrt::make<ReactContextStub>();
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
3 changes: 2 additions & 1 deletion vnext/Microsoft.ReactNative.Cxx/JSValueWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#ifndef MICROSOFT_REACTNATIVE_JSVALUEWRITER
#define MICROSOFT_REACTNATIVE_JSVALUEWRITER

#include <winrt/Microsoft.ReactNative.h>
#include "JSValue.h"
#include "StructInfo.h"
#include "winrt/Microsoft.ReactNative.h"

namespace winrt::Microsoft::ReactNative {

Expand Down
28 changes: 27 additions & 1 deletion vnext/Microsoft.ReactNative.Cxx/ReactContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,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 {
Expand Down Expand Up @@ -68,8 +70,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<bool>(left.m_handle);
}

friend bool operator!=(ReactContext const &left, std::nullptr_t) noexcept {
return static_cast<bool>(left.m_handle);
}

friend bool operator==(std::nullptr_t, ReactContext const &right) noexcept {
return !static_cast<bool>(right.m_handle);
}

friend bool operator!=(std::nullptr_t, ReactContext const &right) noexcept {
return static_cast<bool>(right.m_handle);
}

private:
const IReactContext m_handle;
IReactContext m_handle;
};

} // namespace winrt::Microsoft::ReactNative
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "pch.h"

#include <winrt/Microsoft.ReactNative.h>
#include <NativeModules.h>

using namespace React;

namespace ReactNativeIntegrationTests {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,6 @@ TEST_CLASS (ReactPropertyBagTests) {
}

TEST_METHOD(PropertyBag_Property_string) {
// We only support enums defined in IDL.
ReactPropertyId<hstring> fooName{L"Foo"};
ReactPropertyBag pb{ReactPropertyBagHelper::CreatePropertyBag()};

Expand All @@ -504,6 +503,25 @@ TEST_CLASS (ReactPropertyBagTests) {
pb.Remove(fooName);
TestCheck(!pb.Get(fooName));
}

TEST_METHOD(PropertyBag_Property_delegate) {
ReactPropertyId<ReactCreatePropertyValue> 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<int>((*pb.Get(fooName))()));

ReactCreatePropertyValue createValue2 = []() { return winrt::box_value(10); };
pb.Set(fooName, createValue2);
TestCheckEqual(createValue2, *pb.Get(fooName));
TestCheckEqual(10, winrt::unbox_value<int>((*pb.Get(fooName))()));
TestCheck(createValue1 != *pb.Get(fooName));
pb.Remove(fooName);
TestCheck(!pb.Get(fooName));
}
};

} // namespace ReactNativeIntegrationTests

0 comments on commit aa96215

Please sign in to comment.