|
12 | 12 |
|
13 | 13 | #include <functional> |
14 | 14 | #include <memory> |
| 15 | +#include <stdexcept> |
15 | 16 |
|
16 | 17 | using namespace facebook; |
17 | 18 |
|
@@ -67,3 +68,165 @@ void ConfigCloningTest::TearDown() { |
67 | 68 | } |
68 | 69 |
|
69 | 70 | yoga::Node ConfigCloningTest::clonedNode = {}; |
| 71 | + |
| 72 | +TEST(YogaTest, config_point_scale_factor_negative_throws) { |
| 73 | + YGConfigRef config = YGConfigNew(); |
| 74 | + |
| 75 | + // Zero is explicitly allowed per the API contract |
| 76 | + YGConfigSetPointScaleFactor(config, 0.0f); |
| 77 | + ASSERT_EQ(YGConfigGetPointScaleFactor(config), 0.0f); |
| 78 | + |
| 79 | + // Negative values should trigger a fatal assertion (throws std::logic_error) |
| 80 | + ASSERT_THROW(YGConfigSetPointScaleFactor(config, -1.0f), std::logic_error); |
| 81 | + |
| 82 | + // Verify the value was not changed after the failed set |
| 83 | + ASSERT_EQ(YGConfigGetPointScaleFactor(config), 0.0f); |
| 84 | + |
| 85 | + YGConfigFree(config); |
| 86 | +} |
| 87 | + |
| 88 | +TEST(YogaTest, config_set_logger_null_resets_to_default_logger) { |
| 89 | + YGConfigRef config = YGConfigNew(); |
| 90 | + |
| 91 | + // Track whether our custom logger was called |
| 92 | + bool customLoggerCalled = false; |
| 93 | + YGConfigSetContext(config, &customLoggerCalled); |
| 94 | + |
| 95 | + YGLogger customLogger = [](YGConfigConstRef cfg, |
| 96 | + YGNodeConstRef /*node*/, |
| 97 | + YGLogLevel /*level*/, |
| 98 | + const char* /*format*/, |
| 99 | + va_list /*args*/) -> int { |
| 100 | + bool* called = static_cast<bool*>(YGConfigGetContext(cfg)); |
| 101 | + *called = true; |
| 102 | + return 0; |
| 103 | + }; |
| 104 | + |
| 105 | + // Set custom logger and verify it's invoked via layout warning |
| 106 | + YGConfigSetLogger(config, customLogger); |
| 107 | + YGNodeRef node = YGNodeNewWithConfig(config); |
| 108 | + YGNodeCalculateLayout(node, YGUndefined, YGUndefined, YGDirectionLTR); |
| 109 | + // Trigger a log by setting a negative point scale factor (which logs before |
| 110 | + // throwing) |
| 111 | + customLoggerCalled = false; |
| 112 | + ASSERT_THROW(YGConfigSetPointScaleFactor(config, -1.0f), std::logic_error); |
| 113 | + ASSERT_TRUE(customLoggerCalled); |
| 114 | + |
| 115 | + // Reset logger to null — should fall back to default logger |
| 116 | + YGConfigSetLogger(config, nullptr); |
| 117 | + customLoggerCalled = false; |
| 118 | + ASSERT_THROW(YGConfigSetPointScaleFactor(config, -2.0f), std::logic_error); |
| 119 | + // Custom logger should NOT have been called since we reset to default |
| 120 | + ASSERT_FALSE(customLoggerCalled); |
| 121 | + |
| 122 | + YGNodeFree(node); |
| 123 | + YGConfigFree(config); |
| 124 | +} |
| 125 | + |
| 126 | +TEST(YogaTest, config_version_increments_only_on_actual_changes) { |
| 127 | + auto* config = static_cast<yoga::Config*>(YGConfigNew()); |
| 128 | + |
| 129 | + uint32_t initialVersion = config->getVersion(); |
| 130 | + |
| 131 | + // Changing point scale factor should increment version |
| 132 | + config->setPointScaleFactor(2.0f); |
| 133 | + ASSERT_EQ(config->getVersion(), initialVersion + 1); |
| 134 | + |
| 135 | + // Setting the same value again should NOT increment version |
| 136 | + config->setPointScaleFactor(2.0f); |
| 137 | + ASSERT_EQ(config->getVersion(), initialVersion + 1); |
| 138 | + |
| 139 | + // Changing errata should increment version |
| 140 | + config->setErrata(yoga::Errata::StretchFlexBasis); |
| 141 | + ASSERT_EQ(config->getVersion(), initialVersion + 2); |
| 142 | + |
| 143 | + // Setting the same errata again should NOT increment version |
| 144 | + config->setErrata(yoga::Errata::StretchFlexBasis); |
| 145 | + ASSERT_EQ(config->getVersion(), initialVersion + 2); |
| 146 | + |
| 147 | + // Enabling an experimental feature should increment version |
| 148 | + config->setExperimentalFeatureEnabled( |
| 149 | + yoga::ExperimentalFeature::WebFlexBasis, true); |
| 150 | + ASSERT_EQ(config->getVersion(), initialVersion + 3); |
| 151 | + |
| 152 | + // Enabling the same feature again should NOT increment version |
| 153 | + config->setExperimentalFeatureEnabled( |
| 154 | + yoga::ExperimentalFeature::WebFlexBasis, true); |
| 155 | + ASSERT_EQ(config->getVersion(), initialVersion + 3); |
| 156 | + |
| 157 | + YGConfigFree(config); |
| 158 | +} |
| 159 | + |
| 160 | +TEST(YogaTest, config_update_invalidates_layout_detects_each_property) { |
| 161 | + auto* config1 = static_cast<yoga::Config*>(YGConfigNew()); |
| 162 | + auto* config2 = static_cast<yoga::Config*>(YGConfigNew()); |
| 163 | + |
| 164 | + // Two identical configs should not invalidate layout |
| 165 | + ASSERT_FALSE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 166 | + |
| 167 | + // Changing errata on one config should invalidate |
| 168 | + config2->setErrata(yoga::Errata::StretchFlexBasis); |
| 169 | + ASSERT_TRUE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 170 | + |
| 171 | + // Make them match again |
| 172 | + config1->setErrata(yoga::Errata::StretchFlexBasis); |
| 173 | + ASSERT_FALSE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 174 | + |
| 175 | + // Changing point scale factor should invalidate |
| 176 | + config2->setPointScaleFactor(3.0f); |
| 177 | + ASSERT_TRUE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 178 | + |
| 179 | + // Make them match again |
| 180 | + config1->setPointScaleFactor(3.0f); |
| 181 | + ASSERT_FALSE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 182 | + |
| 183 | + // Changing useWebDefaults should invalidate |
| 184 | + config2->setUseWebDefaults(true); |
| 185 | + ASSERT_TRUE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 186 | + |
| 187 | + // Make them match again |
| 188 | + config1->setUseWebDefaults(true); |
| 189 | + ASSERT_FALSE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 190 | + |
| 191 | + // Changing experimental features should invalidate |
| 192 | + config2->setExperimentalFeatureEnabled( |
| 193 | + yoga::ExperimentalFeature::WebFlexBasis, true); |
| 194 | + ASSERT_TRUE(yoga::configUpdateInvalidatesLayout(*config1, *config2)); |
| 195 | + |
| 196 | + YGConfigFree(config1); |
| 197 | + YGConfigFree(config2); |
| 198 | +} |
| 199 | + |
| 200 | +TEST(YogaTest, config_errata_bitmask_add_remove_operations) { |
| 201 | + auto* config = static_cast<yoga::Config*>(YGConfigNew()); |
| 202 | + |
| 203 | + // Initially no errata |
| 204 | + ASSERT_FALSE(config->hasErrata(yoga::Errata::StretchFlexBasis)); |
| 205 | + ASSERT_FALSE(config->hasErrata( |
| 206 | + yoga::Errata::AbsolutePositionWithoutInsetsExcludesPadding)); |
| 207 | + |
| 208 | + // Add one errata flag |
| 209 | + config->addErrata(yoga::Errata::StretchFlexBasis); |
| 210 | + ASSERT_TRUE(config->hasErrata(yoga::Errata::StretchFlexBasis)); |
| 211 | + ASSERT_FALSE(config->hasErrata( |
| 212 | + yoga::Errata::AbsolutePositionWithoutInsetsExcludesPadding)); |
| 213 | + |
| 214 | + // Add another errata flag — first should still be set |
| 215 | + config->addErrata(yoga::Errata::AbsolutePositionWithoutInsetsExcludesPadding); |
| 216 | + ASSERT_TRUE(config->hasErrata(yoga::Errata::StretchFlexBasis)); |
| 217 | + ASSERT_TRUE(config->hasErrata( |
| 218 | + yoga::Errata::AbsolutePositionWithoutInsetsExcludesPadding)); |
| 219 | + |
| 220 | + // Remove only the first flag — second should remain |
| 221 | + config->removeErrata(yoga::Errata::StretchFlexBasis); |
| 222 | + ASSERT_FALSE(config->hasErrata(yoga::Errata::StretchFlexBasis)); |
| 223 | + ASSERT_TRUE(config->hasErrata( |
| 224 | + yoga::Errata::AbsolutePositionWithoutInsetsExcludesPadding)); |
| 225 | + |
| 226 | + // Remove the second flag |
| 227 | + config->removeErrata( |
| 228 | + yoga::Errata::AbsolutePositionWithoutInsetsExcludesPadding); |
| 229 | + ASSERT_EQ(config->getErrata(), yoga::Errata::None); |
| 230 | + |
| 231 | + YGConfigFree(config); |
| 232 | +} |
0 commit comments