/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include #include #include #include #include "TestComponent.h" using namespace facebook::react; class PropsSingleFloat : public Props { public: PropsSingleFloat() = default; PropsSingleFloat( const PropsSingleFloat &sourceProps, const RawProps &rawProps) : floatValue(convertRawProp( rawProps, "floatValue", sourceProps.floatValue, 17.5)) {} private: const float floatValue{17.5}; }; class PropsSingleDouble : public Props { public: PropsSingleDouble() = default; PropsSingleDouble( const PropsSingleDouble &sourceProps, const RawProps &rawProps) : doubleValue(convertRawProp( rawProps, "doubleValue", sourceProps.doubleValue, 17.5)) {} private: const float doubleValue{17.5}; }; class PropsSingleInt : public Props { public: PropsSingleInt() = default; PropsSingleInt(const PropsSingleInt &sourceProps, const RawProps &rawProps) : intValue( convertRawProp(rawProps, "intValue", sourceProps.intValue, 17)) {} private: const int intValue{17}; }; class PropsPrimitiveTypes : public Props { public: PropsPrimitiveTypes() = default; PropsPrimitiveTypes( const PropsPrimitiveTypes &sourceProps, const RawProps &rawProps) : intValue( convertRawProp(rawProps, "intValue", sourceProps.intValue, 17)), doubleValue(convertRawProp( rawProps, "doubleValue", sourceProps.doubleValue, 17.56)), floatValue(convertRawProp( rawProps, "floatValue", sourceProps.floatValue, 56.75)), stringValue(convertRawProp( rawProps, "stringValue", sourceProps.stringValue, "")), boolValue(convertRawProp( rawProps, "boolValue", sourceProps.boolValue, false)) {} private: const int intValue{17}; const double doubleValue{17.56}; const float floatValue{56.75}; const std::string stringValue{}; const bool boolValue{false}; }; class PropsMultiLookup : public Props { public: PropsMultiLookup() = default; PropsMultiLookup( const PropsMultiLookup &sourceProps, const RawProps &rawProps) : floatValue(convertRawProp( rawProps, "floatValue", sourceProps.floatValue, 17.5)), // While this specific pattern is uncommon, it's a simplication of a // pattern that does occur a lot: nested structs that access props we // have already accessed populating Props derivedFloatValue( convertRawProp(rawProps, "floatValue", sourceProps.floatValue, 40) * 2) {} const float floatValue{17.5}; const float derivedFloatValue{40}; }; TEST(RawPropsTest, handleProps) { const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); auto props = std::make_shared(Props(), raw); // Props are not sealed after applying raw props. EXPECT_FALSE(props->getSealed()); EXPECT_STREQ(props->nativeId.c_str(), "abc"); } TEST(RawPropsTest, handleRawPropsSingleString) { const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); std::string value = (std::string)*raw.at("nativeID", nullptr, nullptr); EXPECT_STREQ(value.c_str(), "abc"); } TEST(RawPropsTest, handleRawPropsSingleFloat) { const auto &raw = RawProps(folly::dynamic::object("floatValue", (float)42.42)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); float value = (float)*raw.at("floatValue", nullptr, nullptr); EXPECT_NEAR(value, 42.42, 0.00001); } TEST(RawPropsTest, handleRawPropsSingleDouble) { const auto &raw = RawProps(folly::dynamic::object("doubleValue", (double)42.42)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); double value = (double)*raw.at("doubleValue", nullptr, nullptr); EXPECT_NEAR(value, 42.42, 0.00001); } TEST(RawPropsTest, handleRawPropsSingleInt) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42.42)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); int value = (int)*raw.at("intValue", nullptr, nullptr); EXPECT_EQ(value, 42); } TEST(RawPropsTest, handleRawPropsSingleIntGetManyTimes) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42.42)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); } TEST(RawPropsTest, handleRawPropsPrimitiveTypes) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42)( "doubleValue", (double)17.42)("floatValue", (float)66.67)( "stringValue", "helloworld")("boolValue", true)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); EXPECT_NEAR((float)*raw.at("floatValue", nullptr, nullptr), 66.67, 0.00001); EXPECT_STREQ( ((std::string)*raw.at("stringValue", nullptr, nullptr)).c_str(), "helloworld"); EXPECT_EQ((bool)*raw.at("boolValue", nullptr, nullptr), true); } TEST(RawPropsTest, handleRawPropsPrimitiveTypesGetTwice) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42)( "doubleValue", (double)17.42)("floatValue", (float)66.67)( "stringValue", "helloworld")("boolValue", true)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); EXPECT_NEAR((float)*raw.at("floatValue", nullptr, nullptr), 66.67, 0.00001); EXPECT_STREQ( ((std::string)*raw.at("stringValue", nullptr, nullptr)).c_str(), "helloworld"); EXPECT_EQ((bool)*raw.at("boolValue", nullptr, nullptr), true); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); EXPECT_NEAR((float)*raw.at("floatValue", nullptr, nullptr), 66.67, 0.00001); EXPECT_STREQ( ((std::string)*raw.at("stringValue", nullptr, nullptr)).c_str(), "helloworld"); EXPECT_EQ((bool)*raw.at("boolValue", nullptr, nullptr), true); } TEST(RawPropsTest, handleRawPropsPrimitiveTypesGetOutOfOrder) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42)( "doubleValue", (double)17.42)("floatValue", (float)66.67)( "stringValue", "helloworld")("boolValue", true)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); EXPECT_NEAR((float)*raw.at("floatValue", nullptr, nullptr), 66.67, 0.00001); EXPECT_STREQ( ((std::string)*raw.at("stringValue", nullptr, nullptr)).c_str(), "helloworld"); EXPECT_EQ((bool)*raw.at("boolValue", nullptr, nullptr), true); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((float)*raw.at("floatValue", nullptr, nullptr), 66.67, 0.00001); EXPECT_STREQ( ((std::string)*raw.at("stringValue", nullptr, nullptr)).c_str(), "helloworld"); EXPECT_EQ((bool)*raw.at("boolValue", nullptr, nullptr), true); } TEST(RawPropsTest, handleRawPropsPrimitiveTypesIncomplete) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_EQ(raw.at("doubleValue", nullptr, nullptr), nullptr); EXPECT_EQ(raw.at("floatValue", nullptr, nullptr), nullptr); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_EQ(raw.at("stringValue", nullptr, nullptr), nullptr); EXPECT_EQ(raw.at("boolValue", nullptr, nullptr), nullptr); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); } #ifndef NDEBUG TEST(RawPropsTest, handleRawPropsPrimitiveTypesIncorrectLookup) { const auto &raw = RawProps(folly::dynamic::object("intValue", (int)42)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); // Before D18662135, looking up an invalid key would trigger // an infinite loop. This is out of contract, so we should only // test this in debug. EXPECT_EQ(raw.at("flurb", nullptr, nullptr), nullptr); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); } #endif TEST(RawPropsTest, handlePropsMultiLookup) { const auto &raw = RawProps(folly::dynamic::object("floatValue", (float)10.0)); auto parser = RawPropsParser(); parser.prepare(); raw.parse(parser); auto props = std::make_shared(PropsMultiLookup(), raw); // Props are not sealed after applying raw props. EXPECT_FALSE(props->getSealed()); EXPECT_NEAR(props->floatValue, 10.0, 0.00001); EXPECT_NEAR(props->derivedFloatValue, 20.0, 0.00001); }