/* * 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include "Entropy.h" namespace facebook { namespace react { static Tag generateReactTag() { static Tag tag = 1000; return tag++; } class ShadowTreeEdge final { public: ShadowNode::Shared shadowNode{nullptr}; ShadowNode::Shared parentShadowNode{nullptr}; int index{0}; }; static bool traverseShadowTree( ShadowNode::Shared const &parentShadowNode, std::function const &callback) { auto index = int{0}; for (auto const &childNode : parentShadowNode->getChildren()) { auto stop = bool{false}; callback(ShadowTreeEdge{childNode, parentShadowNode, index}, stop); if (stop) { return true; } if (traverseShadowTree(childNode, callback)) { return true; } index++; } return false; } static int countShadowNodes(ShadowNode::Shared const &rootShadowNode) { auto counter = int{0}; traverseShadowTree( rootShadowNode, [&](ShadowTreeEdge const &edge, bool &stop) { counter++; }); return counter; } static ShadowTreeEdge findShadowNodeWithIndex( ShadowNode::Shared const &rootNode, int index) { auto counter = int{0}; auto result = ShadowTreeEdge{}; traverseShadowTree(rootNode, [&](ShadowTreeEdge const &edge, bool &stop) { if (index == counter) { result = edge; } counter++; }); return result; } static ShadowTreeEdge findRandomShadowNode( Entropy const &entropy, ShadowNode::Shared const &rootShadowNode) { auto count = countShadowNodes(rootShadowNode); return findShadowNodeWithIndex( rootShadowNode, entropy.random(1 /* Excluding a root node */, count - 1)); } static ShadowNode::ListOfShared cloneSharedShadowNodeList( ShadowNode::ListOfShared const &list) { auto result = ShadowNode::ListOfShared{}; result.reserve(list.size()); for (auto const &shadowNode : list) { result.push_back(shadowNode->clone({})); } return result; } static inline ShadowNode::Unshared messWithChildren( Entropy const &entropy, ShadowNode const &shadowNode) { auto children = shadowNode.getChildren(); children = cloneSharedShadowNodeList(children); entropy.shuffle(children); return shadowNode.clone( {ShadowNodeFragment::propsPlaceholder(), std::make_shared(children)}); } static inline ShadowNode::Unshared messWithLayotableOnlyFlag( Entropy const &entropy, ShadowNode const &shadowNode) { auto oldProps = shadowNode.getProps(); auto newProps = shadowNode.getComponentDescriptor().cloneProps( oldProps, RawProps(folly::dynamic::object())); auto &viewProps = const_cast(static_cast(*newProps)); if (entropy.random(0.1)) { viewProps.nativeId = entropy.random() ? "42" : ""; } if (entropy.random(0.1)) { viewProps.backgroundColor = entropy.random() ? SharedColor() : whiteColor(); } if (entropy.random(0.1)) { viewProps.foregroundColor = entropy.random() ? SharedColor() : blackColor(); } if (entropy.random(0.1)) { viewProps.shadowColor = entropy.random() ? SharedColor() : blackColor(); } if (entropy.random(0.1)) { viewProps.accessible = entropy.random(); } if (entropy.random(0.1)) { viewProps.zIndex = entropy.random() ? 1 : 0; } if (entropy.random(0.1)) { viewProps.pointerEvents = entropy.random() ? PointerEventsMode::Auto : PointerEventsMode::None; } if (entropy.random(0.1)) { viewProps.transform = entropy.random() ? Transform::Identity() : Transform::Perspective(42); } return shadowNode.clone({newProps}); } static inline ShadowNode::Unshared messWithYogaStyles( Entropy const &entropy, ShadowNode const &shadowNode) { folly::dynamic dynamic = folly::dynamic::object(); if (entropy.random()) { dynamic["flexDirection"] = entropy.random() ? "row" : "column"; } std::vector properties = { "flex", "flexGrow", "flexShrink", "flexBasis", "left", "top", "marginLeft", "marginTop", "marginRight", "marginBottom", "paddingLeft", "paddingTop", "paddingRight", "paddingBottom", "width", "height", "maxWidth", "maxHeight", "minWidth", "minHeight", }; for (auto const &property : properties) { if (entropy.random(0.1)) { dynamic[property] = entropy.random(0, 1024); } } auto oldProps = shadowNode.getProps(); auto newProps = shadowNode.getComponentDescriptor().cloneProps( oldProps, RawProps(dynamic)); return shadowNode.clone({newProps}); } using ShadowNodeAlteration = std::function< ShadowNode::Unshared(Entropy const &entropy, ShadowNode const &shadowNode)>; static inline void alterShadowTree( Entropy const &entropy, RootShadowNode::Shared &rootShadowNode, ShadowNodeAlteration alteration) { auto edge = findRandomShadowNode(entropy, rootShadowNode); rootShadowNode = std::static_pointer_cast(rootShadowNode->cloneTree( edge.shadowNode->getFamily(), [&](ShadowNode const &oldShadowNode) { return alteration(entropy, oldShadowNode); })); } static inline void alterShadowTree( Entropy const &entropy, RootShadowNode::Shared &rootShadowNode, std::vector alterations) { auto i = entropy.random(0, alterations.size() - 1); alterShadowTree(entropy, rootShadowNode, alterations[i]); } static SharedViewProps generateDefaultProps( ComponentDescriptor const &componentDescriptor) { return std::static_pointer_cast( componentDescriptor.cloneProps(nullptr, RawProps{})); } static inline ShadowNode::Shared generateShadowNodeTree( Entropy const &entropy, ComponentDescriptor const &componentDescriptor, int size, int deviation = 3) { if (size <= 1) { auto family = componentDescriptor.createFamily( {generateReactTag(), SurfaceId(1), nullptr}, nullptr); return componentDescriptor.createShadowNode( ShadowNodeFragment{generateDefaultProps(componentDescriptor)}, family); } auto items = std::vector(size); std::fill(items.begin(), items.end(), 1); auto chunks = entropy.distribute(items, deviation); auto children = ShadowNode::ListOfShared{}; for (auto const &chunk : chunks) { children.push_back( generateShadowNodeTree(entropy, componentDescriptor, chunk.size())); } auto family = componentDescriptor.createFamily( {generateReactTag(), SurfaceId(1), nullptr}, nullptr); return componentDescriptor.createShadowNode( ShadowNodeFragment{generateDefaultProps(componentDescriptor), std::make_shared(children)}, family); } } // namespace react } // namespace facebook