basalt-core 0.0.0-rc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli/basalt.d.ts +3 -0
  3. package/dist/cli/basalt.d.ts.map +1 -0
  4. package/dist/cli/basalt.js +47 -0
  5. package/dist/cli/basalt.js.map +1 -0
  6. package/dist/cli/bundle-cli.d.ts +12 -0
  7. package/dist/cli/bundle-cli.d.ts.map +1 -0
  8. package/dist/cli/bundle-cli.js +124 -0
  9. package/dist/cli/bundle-cli.js.map +1 -0
  10. package/dist/cli/bundleWithAssets.d.ts +79 -0
  11. package/dist/cli/bundleWithAssets.d.ts.map +1 -0
  12. package/dist/cli/bundleWithAssets.js +198 -0
  13. package/dist/cli/bundleWithAssets.js.map +1 -0
  14. package/dist/cli/desktop.d.ts +339 -0
  15. package/dist/cli/desktop.d.ts.map +1 -0
  16. package/dist/cli/desktop.js +1029 -0
  17. package/dist/cli/desktop.js.map +1 -0
  18. package/dist/cli/doctor.d.ts +31 -0
  19. package/dist/cli/doctor.d.ts.map +1 -0
  20. package/dist/cli/doctor.js +283 -0
  21. package/dist/cli/doctor.js.map +1 -0
  22. package/dist/cli/init.d.ts +77 -0
  23. package/dist/cli/init.d.ts.map +1 -0
  24. package/dist/cli/init.js +442 -0
  25. package/dist/cli/init.js.map +1 -0
  26. package/dist/cli/metro.d.ts +49 -0
  27. package/dist/cli/metro.d.ts.map +1 -0
  28. package/dist/cli/metro.js +148 -0
  29. package/dist/cli/metro.js.map +1 -0
  30. package/dist/cli/packageApp.d.ts +102 -0
  31. package/dist/cli/packageApp.d.ts.map +1 -0
  32. package/dist/cli/packageApp.js +319 -0
  33. package/dist/cli/packageApp.js.map +1 -0
  34. package/dist/cli/steps.d.ts +34 -0
  35. package/dist/cli/steps.d.ts.map +1 -0
  36. package/dist/cli/steps.js +53 -0
  37. package/dist/cli/steps.js.map +1 -0
  38. package/dist/metro-config.d.ts +168 -0
  39. package/dist/metro-config.d.ts.map +1 -0
  40. package/dist/metro-config.js +671 -0
  41. package/dist/metro-config.js.map +1 -0
  42. package/dist/react-native.config.d.ts +7 -0
  43. package/dist/react-native.config.d.ts.map +1 -0
  44. package/dist/react-native.config.js +80 -0
  45. package/dist/react-native.config.js.map +1 -0
  46. package/dist/src/DragSource.d.ts +52 -0
  47. package/dist/src/DragSource.d.ts.map +1 -0
  48. package/dist/src/DragSource.js +97 -0
  49. package/dist/src/DragSource.js.map +1 -0
  50. package/dist/src/DropTarget.d.ts +58 -0
  51. package/dist/src/DropTarget.d.ts.map +1 -0
  52. package/dist/src/DropTarget.js +131 -0
  53. package/dist/src/DropTarget.js.map +1 -0
  54. package/dist/src/KeyHandler.d.ts +57 -0
  55. package/dist/src/KeyHandler.d.ts.map +1 -0
  56. package/dist/src/KeyHandler.js +48 -0
  57. package/dist/src/KeyHandler.js.map +1 -0
  58. package/dist/src/Menu.d.ts +72 -0
  59. package/dist/src/Menu.d.ts.map +1 -0
  60. package/dist/src/Menu.js +179 -0
  61. package/dist/src/Menu.js.map +1 -0
  62. package/dist/src/TitleBar.d.ts +75 -0
  63. package/dist/src/TitleBar.d.ts.map +1 -0
  64. package/dist/src/TitleBar.js +236 -0
  65. package/dist/src/TitleBar.js.map +1 -0
  66. package/dist/src/Window.d.ts +87 -0
  67. package/dist/src/Window.d.ts.map +1 -0
  68. package/dist/src/Window.js +248 -0
  69. package/dist/src/Window.js.map +1 -0
  70. package/dist/src/closeRequest.d.ts +55 -0
  71. package/dist/src/closeRequest.d.ts.map +1 -0
  72. package/dist/src/closeRequest.js +134 -0
  73. package/dist/src/closeRequest.js.map +1 -0
  74. package/dist/src/index.d.ts +45 -0
  75. package/dist/src/index.d.ts.map +1 -0
  76. package/dist/src/index.js +92 -0
  77. package/dist/src/index.js.map +1 -0
  78. package/dist/src/overrides/Alert.d.ts +69 -0
  79. package/dist/src/overrides/Alert.d.ts.map +1 -0
  80. package/dist/src/overrides/Alert.js +112 -0
  81. package/dist/src/overrides/Alert.js.map +1 -0
  82. package/dist/src/overrides/BaseViewConfig.d.ts +28 -0
  83. package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -0
  84. package/dist/src/overrides/BaseViewConfig.js +72 -0
  85. package/dist/src/overrides/BaseViewConfig.js.map +1 -0
  86. package/dist/src/overrides/Platform.linux.d.ts +10 -0
  87. package/dist/src/overrides/Platform.linux.d.ts.map +1 -0
  88. package/dist/src/overrides/Platform.linux.js +15 -0
  89. package/dist/src/overrides/Platform.linux.js.map +1 -0
  90. package/dist/src/overrides/Platform.macos.d.ts +10 -0
  91. package/dist/src/overrides/Platform.macos.d.ts.map +1 -0
  92. package/dist/src/overrides/Platform.macos.js +15 -0
  93. package/dist/src/overrides/Platform.macos.js.map +1 -0
  94. package/dist/src/overrides/Platform.windows.d.ts +10 -0
  95. package/dist/src/overrides/Platform.windows.d.ts.map +1 -0
  96. package/dist/src/overrides/Platform.windows.js +15 -0
  97. package/dist/src/overrides/Platform.windows.js.map +1 -0
  98. package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts +24 -0
  99. package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts.map +1 -0
  100. package/dist/src/overrides/ReactDevToolsSettingsManager.js +30 -0
  101. package/dist/src/overrides/ReactDevToolsSettingsManager.js.map +1 -0
  102. package/dist/src/overrides/RefreshControl.d.ts +52 -0
  103. package/dist/src/overrides/RefreshControl.d.ts.map +1 -0
  104. package/dist/src/overrides/RefreshControl.js +92 -0
  105. package/dist/src/overrides/RefreshControl.js.map +1 -0
  106. package/dist/src/overrides/ScrollView.d.ts +39 -0
  107. package/dist/src/overrides/ScrollView.d.ts.map +1 -0
  108. package/dist/src/overrides/ScrollView.js +59 -0
  109. package/dist/src/overrides/ScrollView.js.map +1 -0
  110. package/dist/src/overrides/Share.d.ts +96 -0
  111. package/dist/src/overrides/Share.d.ts.map +1 -0
  112. package/dist/src/overrides/Share.js +97 -0
  113. package/dist/src/overrides/Share.js.map +1 -0
  114. package/dist/src/overrides/TextInput.d.ts +81 -0
  115. package/dist/src/overrides/TextInput.d.ts.map +1 -0
  116. package/dist/src/overrides/TextInput.js +213 -0
  117. package/dist/src/overrides/TextInput.js.map +1 -0
  118. package/dist/src/overrides/View.d.ts +36 -0
  119. package/dist/src/overrides/View.d.ts.map +1 -0
  120. package/dist/src/overrides/View.js +99 -0
  121. package/dist/src/overrides/View.js.map +1 -0
  122. package/dist/src/overrides/createPlatform.d.ts +32 -0
  123. package/dist/src/overrides/createPlatform.d.ts.map +1 -0
  124. package/dist/src/overrides/createPlatform.js +84 -0
  125. package/dist/src/overrides/createPlatform.js.map +1 -0
  126. package/dist/src/overrides/setUpDeveloperTools.d.ts +28 -0
  127. package/dist/src/overrides/setUpDeveloperTools.d.ts.map +1 -0
  128. package/dist/src/overrides/setUpDeveloperTools.js +84 -0
  129. package/dist/src/overrides/setUpDeveloperTools.js.map +1 -0
  130. package/dist/src/overrides/setUpXHR.d.ts +46 -0
  131. package/dist/src/overrides/setUpXHR.d.ts.map +1 -0
  132. package/dist/src/overrides/setUpXHR.js +236 -0
  133. package/dist/src/overrides/setUpXHR.js.map +1 -0
  134. package/dist/src/quitRequest.d.ts +55 -0
  135. package/dist/src/quitRequest.d.ts.map +1 -0
  136. package/dist/src/quitRequest.js +121 -0
  137. package/dist/src/quitRequest.js.map +1 -0
  138. package/dist/src/resourcePath.d.ts +18 -0
  139. package/dist/src/resourcePath.d.ts.map +1 -0
  140. package/dist/src/resourcePath.js +31 -0
  141. package/dist/src/resourcePath.js.map +1 -0
  142. package/dist/src/responseBody.d.ts +76 -0
  143. package/dist/src/responseBody.d.ts.map +1 -0
  144. package/dist/src/responseBody.js +94 -0
  145. package/dist/src/responseBody.js.map +1 -0
  146. package/dist/src/responseHeaders.d.ts +40 -0
  147. package/dist/src/responseHeaders.d.ts.map +1 -0
  148. package/dist/src/responseHeaders.js +75 -0
  149. package/dist/src/responseHeaders.js.map +1 -0
  150. package/dist/src/titleBarState.d.ts +43 -0
  151. package/dist/src/titleBarState.d.ts.map +1 -0
  152. package/dist/src/titleBarState.js +77 -0
  153. package/dist/src/titleBarState.js.map +1 -0
  154. package/dist/src/useContextMenu.d.ts +113 -0
  155. package/dist/src/useContextMenu.d.ts.map +1 -0
  156. package/dist/src/useContextMenu.js +109 -0
  157. package/dist/src/useContextMenu.js.map +1 -0
  158. package/dist/src/useDialog.d.ts +98 -0
  159. package/dist/src/useDialog.d.ts.map +1 -0
  160. package/dist/src/useDialog.js +112 -0
  161. package/dist/src/useDialog.js.map +1 -0
  162. package/dist/src/useDisplays.d.ts +70 -0
  163. package/dist/src/useDisplays.d.ts.map +1 -0
  164. package/dist/src/useDisplays.js +118 -0
  165. package/dist/src/useDisplays.js.map +1 -0
  166. package/dist/src/useHandledKeys.d.ts +38 -0
  167. package/dist/src/useHandledKeys.d.ts.map +1 -0
  168. package/dist/src/useHandledKeys.js +70 -0
  169. package/dist/src/useHandledKeys.js.map +1 -0
  170. package/dist/src/useWindow.d.ts +140 -0
  171. package/dist/src/useWindow.d.ts.map +1 -0
  172. package/dist/src/useWindow.js +233 -0
  173. package/dist/src/useWindow.js.map +1 -0
  174. package/dist/tsconfig.tsbuildinfo +1 -0
  175. package/native/CMakeLists.txt +355 -0
  176. package/native/bootstrap.sh +613 -0
  177. package/native/cmake/CompilerFlags.cmake +49 -0
  178. package/native/cmake/Expo.cmake +125 -0
  179. package/native/cmake/ReactNativeCore.cmake +612 -0
  180. package/native/cmake/Reanimated.cmake +108 -0
  181. package/native/cmake/Skia.cmake +379 -0
  182. package/native/cmake/ThirdParty.cmake +290 -0
  183. package/native/cmake/Worklets.cmake +67 -0
  184. package/native/cmake/codegen/CMakeLists.txt +32 -0
  185. package/native/core/AppIdentity.cpp +85 -0
  186. package/native/core/AppIdentity.h +59 -0
  187. package/native/core/AppPaths.cpp +96 -0
  188. package/native/core/AppPaths.h +53 -0
  189. package/native/core/AppearanceModule.cpp +60 -0
  190. package/native/core/AppearanceModule.h +40 -0
  191. package/native/core/Backface.h +59 -0
  192. package/native/core/BlobModule.cpp +283 -0
  193. package/native/core/BlobModule.h +76 -0
  194. package/native/core/BlobRegistry.cpp +75 -0
  195. package/native/core/BlobRegistry.h +44 -0
  196. package/native/core/ColorScheme.cpp +105 -0
  197. package/native/core/ColorScheme.h +59 -0
  198. package/native/core/ComponentRegistry.h +30 -0
  199. package/native/core/ControlMetrics.h +37 -0
  200. package/native/core/CoreModules.cpp +592 -0
  201. package/native/core/CoreModules.h +308 -0
  202. package/native/core/DebuggingOverlay.cpp +106 -0
  203. package/native/core/DebuggingOverlay.h +65 -0
  204. package/native/core/DesktopControls.cpp +232 -0
  205. package/native/core/DesktopControls.h +170 -0
  206. package/native/core/DevBundle.cpp +108 -0
  207. package/native/core/DevBundle.h +69 -0
  208. package/native/core/DevMenu.cpp +99 -0
  209. package/native/core/DevMenu.h +75 -0
  210. package/native/core/DialogModule.cpp +150 -0
  211. package/native/core/DialogModule.h +51 -0
  212. package/native/core/DragAndDrop.cpp +45 -0
  213. package/native/core/DragAndDrop.h +225 -0
  214. package/native/core/ExpoImageComponent.cpp +79 -0
  215. package/native/core/ExpoImageComponent.h +80 -0
  216. package/native/core/ExpoModules.cpp +415 -0
  217. package/native/core/ExpoModules.h +115 -0
  218. package/native/core/ExpoRuntime.cpp +366 -0
  219. package/native/core/ExpoRuntime.h +42 -0
  220. package/native/core/FocusRing.h +36 -0
  221. package/native/core/FontRegistry.h +51 -0
  222. package/native/core/GestureHandlerModule.cpp +136 -0
  223. package/native/core/GestureHandlerModule.h +71 -0
  224. package/native/core/Gestures.cpp +533 -0
  225. package/native/core/Gestures.h +145 -0
  226. package/native/core/HoverTracker.cpp +69 -0
  227. package/native/core/HoverTracker.h +109 -0
  228. package/native/core/HttpClient.cpp +282 -0
  229. package/native/core/ImageBytes.cpp +205 -0
  230. package/native/core/ImageBytes.h +29 -0
  231. package/native/core/ImageCache.cpp +51 -0
  232. package/native/core/ImageCache.h +89 -0
  233. package/native/core/JsRuntimeAccess.cpp +70 -0
  234. package/native/core/JsRuntimeAccess.h +60 -0
  235. package/native/core/JsiPromise.h +51 -0
  236. package/native/core/KeyEvents.cpp +116 -0
  237. package/native/core/KeyEvents.h +144 -0
  238. package/native/core/LogBoxSurface.cpp +46 -0
  239. package/native/core/LogBoxSurface.h +68 -0
  240. package/native/core/MenuModel.h +117 -0
  241. package/native/core/MenuModule.cpp +209 -0
  242. package/native/core/MenuModule.h +66 -0
  243. package/native/core/MountingWalk.h +524 -0
  244. package/native/core/PackageModules.cpp.in +25 -0
  245. package/native/core/PackageModules.h +50 -0
  246. package/native/core/PlatformConstantsModule.cpp +63 -0
  247. package/native/core/PlatformConstantsModule.h +64 -0
  248. package/native/core/PlatformServices.h +213 -0
  249. package/native/core/PointerButtons.h +63 -0
  250. package/native/core/PullToRefresh.cpp +57 -0
  251. package/native/core/PullToRefresh.h +73 -0
  252. package/native/core/ReanimatedCompat.h +47 -0
  253. package/native/core/ReanimatedModule.cpp +203 -0
  254. package/native/core/ReanimatedModule.h +55 -0
  255. package/native/core/ScrollAnimation.cpp +59 -0
  256. package/native/core/ScrollAnimation.h +70 -0
  257. package/native/core/ScrollBounds.cpp +26 -0
  258. package/native/core/ScrollBounds.h +68 -0
  259. package/native/core/ScrollIndicator.cpp +50 -0
  260. package/native/core/ScrollIndicator.h +69 -0
  261. package/native/core/ScrollMomentum.cpp +71 -0
  262. package/native/core/ScrollMomentum.h +73 -0
  263. package/native/core/ScrollSnap.cpp +123 -0
  264. package/native/core/ScrollSnap.h +80 -0
  265. package/native/core/ShareFallback.cpp +101 -0
  266. package/native/core/ShareFallback.h +45 -0
  267. package/native/core/SkiaPictureViewComponent.cpp +11 -0
  268. package/native/core/SkiaPictureViewComponent.h +47 -0
  269. package/native/core/SourceCodeModule.cpp +55 -0
  270. package/native/core/SourceCodeModule.h +53 -0
  271. package/native/core/StatusBarModule.cpp +23 -0
  272. package/native/core/StatusBarModule.h +42 -0
  273. package/native/core/TestDialog.cpp +148 -0
  274. package/native/core/TestDialog.h +96 -0
  275. package/native/core/TestKeys.cpp +78 -0
  276. package/native/core/TestKeys.h +50 -0
  277. package/native/core/TestQuitFile.cpp +33 -0
  278. package/native/core/TestQuitFile.h +60 -0
  279. package/native/core/TestSettle.h +192 -0
  280. package/native/core/TitleBarRegions.h +31 -0
  281. package/native/core/TurboModuleProxy.cpp +51 -0
  282. package/native/core/TurboModuleProxy.h +46 -0
  283. package/native/core/UIManagerAccess.cpp +43 -0
  284. package/native/core/UIManagerAccess.h +43 -0
  285. package/native/core/WindowBoundsCache.cpp +319 -0
  286. package/native/core/WindowControl.h +235 -0
  287. package/native/core/WindowHost.h +158 -0
  288. package/native/core/WindowMethods.cpp +167 -0
  289. package/native/core/WindowMethods.h +84 -0
  290. package/native/core/WindowsModule.cpp +448 -0
  291. package/native/core/WindowsModule.h +133 -0
  292. package/native/core/WorkletsModule.cpp +199 -0
  293. package/native/core/WorkletsModule.h +57 -0
  294. package/native/core/portability_probe.cpp +210 -0
  295. package/native/tests/EventRecorder.h +124 -0
  296. package/native/tests/TestHarness.cpp +109 -0
  297. package/native/tests/TestHarness.h +89 -0
  298. package/native/tests/TreeDump.h +49 -0
  299. package/native/tests/test_app_identity.cpp +114 -0
  300. package/native/tests/test_app_paths.cpp +48 -0
  301. package/native/tests/test_appearance.cpp +107 -0
  302. package/native/tests/test_backface.cpp +79 -0
  303. package/native/tests/test_blobs.cpp +157 -0
  304. package/native/tests/test_controls.cpp +185 -0
  305. package/native/tests/test_devbundle.cpp +103 -0
  306. package/native/tests/test_drag_and_drop.cpp +143 -0
  307. package/native/tests/test_gestures.cpp +331 -0
  308. package/native/tests/test_hover.cpp +92 -0
  309. package/native/tests/test_image_cache.cpp +109 -0
  310. package/native/tests/test_js_runtime_access.cpp +137 -0
  311. package/native/tests/test_key_events.cpp +235 -0
  312. package/native/tests/test_momentum.cpp +138 -0
  313. package/native/tests/test_quit_file.cpp +104 -0
  314. package/native/tests/test_scroll_animation.cpp +120 -0
  315. package/native/tests/test_scroll_bounds.cpp +66 -0
  316. package/native/tests/test_scroll_indicator.cpp +149 -0
  317. package/native/tests/test_scroll_snap.cpp +112 -0
  318. package/native/tests/test_settle.cpp +115 -0
  319. package/native/tests/test_share.cpp +75 -0
  320. package/native/tests/test_sourcecode.cpp +62 -0
  321. package/native/tests/test_window_close.cpp +119 -0
  322. package/native/tests/test_window_limits.cpp +123 -0
  323. package/package.json +43 -0
  324. package/react-native.config.js +86 -0
  325. package/supported-versions.json +66 -0
@@ -0,0 +1,109 @@
1
+ // The runner itself, with no toolkit in it.
2
+ //
3
+ // The toolkit lives in the `main` beside this file -- GTK has to be initialised
4
+ // before a widget can be constructed, and AppKit has its own requirements -- so
5
+ // each platform brings its own entry point and shares everything below.
6
+
7
+ #include "TestHarness.h"
8
+
9
+ #include <algorithm>
10
+ #include <cctype>
11
+ #include <sstream>
12
+
13
+ namespace basalt::testing {
14
+
15
+ namespace {
16
+
17
+ struct CurrentTest {
18
+ std::string name;
19
+ std::vector<std::string> failures;
20
+ };
21
+
22
+ CurrentTest &current() {
23
+ static CurrentTest test;
24
+ return test;
25
+ }
26
+
27
+ } // namespace
28
+
29
+ std::vector<TestCase> &registry() {
30
+ static std::vector<TestCase> cases;
31
+ return cases;
32
+ }
33
+
34
+ void recordFailure(const std::string &where, const std::string &what) {
35
+ current().failures.push_back(where + ": " + what);
36
+ }
37
+
38
+ namespace {
39
+
40
+ std::string lowered(std::string text) {
41
+ std::transform(text.begin(), text.end(), text.begin(), [](unsigned char c) {
42
+ return static_cast<char>(std::tolower(c));
43
+ });
44
+ return text;
45
+ }
46
+
47
+ } // namespace
48
+
49
+ int runAllTests(int argc, char **argv) {
50
+ // Arguments are substrings of test names, and a test runs if it matches any
51
+ // of them. There is a lot of the day in the difference between running one
52
+ // test and running all of them, and this runner used to accept an argument
53
+ // and silently ignore it -- which is worse than rejecting one, because it
54
+ // looks like the filter worked and every test passed.
55
+ std::vector<std::string> wanted;
56
+ for (int i = 1; i < argc; i++) {
57
+ const std::string argument = argv[i];
58
+ if (argument == "--list") {
59
+ for (const auto &test : registry()) {
60
+ std::cout << test.name << "\n";
61
+ }
62
+ return 0;
63
+ }
64
+ wanted.push_back(lowered(argument));
65
+ }
66
+
67
+ std::vector<TestCase> selected;
68
+ for (const auto &test : registry()) {
69
+ const std::string name = lowered(test.name);
70
+ if (wanted.empty() ||
71
+ std::any_of(wanted.begin(), wanted.end(), [&name](const std::string &needle) {
72
+ return name.find(needle) != std::string::npos;
73
+ })) {
74
+ selected.push_back(test);
75
+ }
76
+ }
77
+
78
+ if (selected.empty()) {
79
+ std::cout << "no test matches; --list prints the names\n";
80
+ return 1;
81
+ }
82
+
83
+ int failed = 0;
84
+
85
+ std::cout << "running " << selected.size() << " tests\n";
86
+
87
+ for (const auto &test : selected) {
88
+ current().name = test.name;
89
+ current().failures.clear();
90
+
91
+ test.body();
92
+
93
+ if (current().failures.empty()) {
94
+ std::cout << " ok " << test.name << "\n";
95
+ } else {
96
+ ++failed;
97
+ std::cout << " FAIL " << test.name << "\n";
98
+ for (const auto &failure : current().failures) {
99
+ std::cout << " " << failure << "\n";
100
+ }
101
+ }
102
+ }
103
+
104
+ std::cout << "\n" << selected.size() - static_cast<size_t>(failed) << "/" << selected.size()
105
+ << " passed\n";
106
+ return failed == 0 ? 0 : 1;
107
+ }
108
+
109
+ } // namespace basalt::testing
@@ -0,0 +1,89 @@
1
+ // A very small test harness.
2
+ //
3
+ // Deliberately not googletest. React Native vendors its own copy for its own
4
+ // tests, and pulling that into this build would mean another third-party tree
5
+ // to pin and another way for the build to break on an upstream bump. Everything
6
+ // below is about sixty lines and has no dependencies.
7
+ //
8
+ // Tests self-register through the TEST macro and run in registration order.
9
+ // A failed check records a message and keeps going, so one broken assertion
10
+ // does not hide the rest of the test's findings.
11
+
12
+ #pragma once
13
+
14
+ // If glog's macros are visible, make sure nothing here quietly binds to them.
15
+ #if defined(CHECK_EQ) && !defined(BASALT_TEST_HARNESS_ALLOW_GLOG_CHECK)
16
+ // Intentionally left alone: glog owns CHECK/CHECK_EQ. This header defines
17
+ // EXPECT/EXPECT_EQ/EXPECT_NEAR instead, which glog does not use.
18
+ #endif
19
+
20
+ #include <cmath>
21
+ #include <functional>
22
+ #include <iostream>
23
+ #include <string>
24
+ #include <vector>
25
+
26
+ namespace basalt::testing {
27
+
28
+ struct TestCase {
29
+ std::string name;
30
+ std::function<void()> body;
31
+ };
32
+
33
+ // Registry and current-test state. A single translation unit owns these; see
34
+ // TestHarness.cpp.
35
+ std::vector<TestCase> &registry();
36
+ void recordFailure(const std::string &where, const std::string &what);
37
+ // Runs the registered tests. Any arguments are substrings of test names: a test
38
+ // runs if it matches one of them, and `--list` prints the names and exits.
39
+ int runAllTests(int argc = 0, char **argv = nullptr);
40
+
41
+ struct Registrar {
42
+ Registrar(const char *name, std::function<void()> body) {
43
+ registry().push_back(TestCase{name, std::move(body)});
44
+ }
45
+ };
46
+
47
+ } // namespace basalt::testing
48
+
49
+ #define TEST(name) \
50
+ static void name(); \
51
+ static ::basalt::testing::Registrar registrar_##name(#name, name); \
52
+ static void name()
53
+
54
+ // Named EXPECT rather than CHECK because glog -- which React Native pulls in
55
+ // through almost every header -- already defines CHECK and CHECK_EQ. Those win
56
+ // the preprocessor fight silently, and a failing assertion then aborts the
57
+ // process instead of being recorded, taking every later test with it.
58
+ #define EXPECT(condition) \
59
+ do { \
60
+ if (!(condition)) { \
61
+ ::basalt::testing::recordFailure(std::string(__FILE__) + ":" + std::to_string(__LINE__), \
62
+ "expected " #condition); \
63
+ } \
64
+ } while (false)
65
+
66
+ #define EXPECT_EQ(actual, expected) \
67
+ do { \
68
+ const auto actualValue = (actual); \
69
+ const auto expectedValue = (expected); \
70
+ if (!(actualValue == expectedValue)) { \
71
+ std::ostringstream message; \
72
+ message << "expected " #actual " == " #expected " but got " << actualValue << " vs " \
73
+ << expectedValue; \
74
+ ::basalt::testing::recordFailure(std::string(__FILE__) + ":" + std::to_string(__LINE__), \
75
+ message.str()); \
76
+ } \
77
+ } while (false)
78
+
79
+ #define EXPECT_NEAR(actual, expected, tolerance) \
80
+ do { \
81
+ const double actualValue = static_cast<double>(actual); \
82
+ const double expectedValue = static_cast<double>(expected); \
83
+ if (std::fabs(actualValue - expectedValue) > (tolerance)) { \
84
+ std::ostringstream message; \
85
+ message << "expected " #actual " ~= " << expectedValue << " but got " << actualValue; \
86
+ ::basalt::testing::recordFailure(std::string(__FILE__) + ":" + std::to_string(__LINE__), \
87
+ message.str()); \
88
+ } \
89
+ } while (false)
@@ -0,0 +1,49 @@
1
+ // Reading a field back out of a host's tree dump.
2
+ //
3
+ // The three hosts print the same tree in the same format -- that is what
4
+ // scripts/compare_hosts.sh rests on -- so a test that wants one number out of
5
+ // it should not have to know which host wrote it. This is here rather than
6
+ // three times over for the same reason the dump's field order is written down
7
+ // three times over: the moment they drift, the comparison is worthless.
8
+
9
+ #pragma once
10
+
11
+ #include <algorithm>
12
+ #include <array>
13
+ #include <cstring>
14
+ #include <sstream>
15
+ #include <string>
16
+
17
+ namespace basalt::testing {
18
+
19
+ // The six numbers of `transform=(a,b,c,d,tx,ty)` for one tag: the 2D affine
20
+ // part, in the order CSS writes a matrix(). All zeroes when that tag printed
21
+ // no transform at all, which is what an identity looks like in this dump --
22
+ // distinguishable from a real matrix, since a real one never has a zero a
23
+ // and d together.
24
+ inline std::array<double, 6> transformIn(const std::string &tree, int tag) {
25
+ std::array<double, 6> found{};
26
+ std::istringstream lines(tree);
27
+ std::string line;
28
+ const std::string needle = "tag=" + std::to_string(tag) + " ";
29
+ while (std::getline(lines, line)) {
30
+ if (line.find(needle) == std::string::npos) {
31
+ continue;
32
+ }
33
+ const auto at = line.find("transform=(");
34
+ if (at == std::string::npos) {
35
+ return found;
36
+ }
37
+ std::string numbers = line.substr(at + std::strlen("transform=("));
38
+ numbers = numbers.substr(0, numbers.find(')'));
39
+ std::replace(numbers.begin(), numbers.end(), ',', ' ');
40
+ std::istringstream parts(numbers);
41
+ for (auto &value : found) {
42
+ parts >> value;
43
+ }
44
+ return found;
45
+ }
46
+ return found;
47
+ }
48
+
49
+ } // namespace basalt::testing
@@ -0,0 +1,114 @@
1
+ // What the app calls itself, read from beside its bundle.
2
+ //
3
+ // A generic host binary cannot know which application it is, and everything the
4
+ // operating system keys on identity needs it: a notification's name and icon, a
5
+ // taskbar group, a GTK application id. `cli/packageApp.js` writes the answer and
6
+ // this is the reading half.
7
+ //
8
+ // What is worth asserting is the degrading, not the happy path. This file is
9
+ // written by a build step and read at startup, so every way it can be wrong is
10
+ // a way an app fails to start -- and an app that refuses to run because
11
+ // somebody hand-edited a JSON file would be a worse platform than one that runs
12
+ // without an icon.
13
+
14
+ #include "TestHarness.h"
15
+
16
+ #include "AppIdentity.h"
17
+
18
+ #include <cstdint>
19
+ #include <filesystem>
20
+ #include <fstream>
21
+ #include <sstream>
22
+ #include <string>
23
+
24
+ using basalt::AppIdentity;
25
+ using basalt::readAppIdentity;
26
+
27
+ namespace {
28
+
29
+ // A directory with `app.identity.json` in it, and the bundle path a host would
30
+ // have been given. Removed by the destructor: a test that leaves files behind
31
+ // makes the next run's failure someone else's.
32
+ struct Beside {
33
+ std::filesystem::path directory;
34
+
35
+ explicit Beside(const std::string &contents) {
36
+ directory = std::filesystem::temp_directory_path() /
37
+ ("basalt-identity-" + std::to_string(reinterpret_cast<std::uintptr_t>(this)));
38
+ std::filesystem::create_directories(directory);
39
+ if (!contents.empty()) {
40
+ std::ofstream file(directory / "app.identity.json");
41
+ file << contents;
42
+ }
43
+ }
44
+
45
+ ~Beside() {
46
+ std::error_code ignored;
47
+ std::filesystem::remove_all(directory, ignored);
48
+ }
49
+
50
+ Beside(const Beside &) = delete;
51
+ Beside &operator=(const Beside &) = delete;
52
+
53
+ std::string bundlePath() const {
54
+ return (directory / "main.jsbundle.js").string();
55
+ }
56
+ };
57
+
58
+ } // namespace
59
+
60
+ TEST(identity_is_read_from_beside_the_bundle) {
61
+ const Beside beside(R"({
62
+ "name": "The Demo",
63
+ "identifier": "dev.example.demo",
64
+ "schemes": ["demo", "demo2"],
65
+ "version": "1.2.3"
66
+ })");
67
+
68
+ const AppIdentity identity = readAppIdentity(beside.bundlePath());
69
+ EXPECT(!identity.empty());
70
+ EXPECT_EQ(identity.name, std::string("The Demo"));
71
+ EXPECT_EQ(identity.identifier, std::string("dev.example.demo"));
72
+ EXPECT_EQ(identity.version, std::string("1.2.3"));
73
+ EXPECT_EQ((long)identity.schemes.size(), 2L);
74
+ EXPECT_EQ(identity.schemes[0], std::string("demo"));
75
+ }
76
+
77
+ TEST(identity_absent_is_not_an_error) {
78
+ // An app built by hand, with no CLI anywhere near it. Every caller treats an
79
+ // empty identity as "this platform's identity features are off", which is the
80
+ // answer all three hosts gave before any of this existed.
81
+ const Beside beside("");
82
+ EXPECT(readAppIdentity(beside.bundlePath()).empty());
83
+ }
84
+
85
+ TEST(identity_malformed_is_the_same_as_absent) {
86
+ const Beside beside("this is not json at all");
87
+ EXPECT(readAppIdentity(beside.bundlePath()).empty());
88
+ }
89
+
90
+ TEST(identity_of_the_wrong_shape_is_the_same_as_absent) {
91
+ // Valid JSON, wrong thing. Refusing to start over this would be worse than
92
+ // starting without an icon.
93
+ const Beside beside("[1, 2, 3]");
94
+ EXPECT(readAppIdentity(beside.bundlePath()).empty());
95
+ }
96
+
97
+ TEST(identity_missing_fields_are_left_empty_rather_than_guessed) {
98
+ // The identifier is the one field that decides anything -- `empty()` is
99
+ // defined by it, because a name with no identifier cannot be registered with
100
+ // any of the three desktops.
101
+ const Beside beside(R"({"name": "Nameless"})");
102
+ const AppIdentity identity = readAppIdentity(beside.bundlePath());
103
+ EXPECT(identity.empty());
104
+ EXPECT_EQ(identity.name, std::string("Nameless"));
105
+ EXPECT(identity.schemes.empty());
106
+ }
107
+
108
+ TEST(identity_a_scheme_list_with_rubbish_in_it_keeps_the_strings) {
109
+ const Beside beside(R"({"identifier": "dev.example.demo", "schemes": ["demo", 7, null]})");
110
+ const AppIdentity identity = readAppIdentity(beside.bundlePath());
111
+ EXPECT(!identity.empty());
112
+ EXPECT_EQ((long)identity.schemes.size(), 1L);
113
+ EXPECT_EQ(identity.schemes[0], std::string("demo"));
114
+ }
@@ -0,0 +1,48 @@
1
+ // Where a packaged application's own files are.
2
+ //
3
+ // What is testable without packaging anything: that it answers at all, that the
4
+ // answer is a directory that exists, and that a binary which is *not* in a
5
+ // bundle -- this test, run out of a build directory -- is told so rather than
6
+ // being handed a Resources path that is not there. The bundle case is asserted
7
+ // by the shape it recognises, which is cli/packageApp.ts's and cannot be built
8
+ // here.
9
+
10
+ #include "TestHarness.h"
11
+
12
+ #include "AppPaths.h"
13
+
14
+ #include <filesystem>
15
+ #include <sstream>
16
+ #include <string>
17
+
18
+ TEST(the_resource_path_is_a_directory_that_exists) {
19
+ const std::string path = basalt::applicationResourcePath();
20
+ EXPECT(!path.empty());
21
+
22
+ std::error_code code;
23
+ EXPECT(std::filesystem::is_directory(path, code));
24
+ }
25
+
26
+ TEST(a_binary_outside_a_bundle_is_told_its_own_directory) {
27
+ // This suite runs out of a build directory rather than a Foo.app, so the
28
+ // honest answer is that directory -- not a Resources path beside it that
29
+ // nothing created. A packaged run is recognised by the layout the packager
30
+ // makes, and this is not it.
31
+ const std::string path = basalt::applicationResourcePath();
32
+ EXPECT(path.find("Contents/Resources") == std::string::npos);
33
+
34
+ // And it is where this binary is, which is the claim.
35
+ std::error_code code;
36
+ const auto expected = std::filesystem::weakly_canonical(
37
+ std::filesystem::current_path(code) / "build", code);
38
+ // Compared loosely: the suite may be run from anywhere, so what is asserted is
39
+ // that the answer is a real directory containing something, not its spelling.
40
+ EXPECT(std::filesystem::exists(path, code));
41
+ (void)expected;
42
+ }
43
+
44
+ TEST(the_answer_does_not_change_between_calls) {
45
+ // It cannot: the executable does not move while it runs. Worth pinning
46
+ // because the JavaScript side caches on that basis.
47
+ EXPECT_EQ(basalt::applicationResourcePath(), basalt::applicationResourcePath());
48
+ }
@@ -0,0 +1,107 @@
1
+ // Tests for the portable half of light-vs-dark.
2
+ //
3
+ // The first test in this project that belongs to *neither* platform. It lives
4
+ // with the shared core and is compiled into both suites, because what it checks
5
+ // -- that a JavaScript override beats the system, that releasing it hands
6
+ // control back, that listeners hear both -- is core's behaviour and would
7
+ // otherwise be asserted twice or not at all.
8
+ //
9
+ // It never asks what the system is actually set to. That is the seam, it
10
+ // differs by machine, and a test that depended on it would pass on a dark Mac
11
+ // and fail on a light one.
12
+
13
+ #include "TestHarness.h"
14
+
15
+ #include "ColorScheme.h"
16
+
17
+ #include <sstream>
18
+ #include <vector>
19
+
20
+ namespace {
21
+
22
+ // Whatever this machine is, expressed as the one it is not -- so these tests
23
+ // can flip to something that is genuinely a change.
24
+ basalt::ColorScheme opposite(basalt::ColorScheme scheme) {
25
+ return scheme == basalt::ColorScheme::Dark ? basalt::ColorScheme::Light
26
+ : basalt::ColorScheme::Dark;
27
+ }
28
+
29
+ } // namespace
30
+
31
+ TEST(color_scheme_names_match_react_natives_spelling) {
32
+ EXPECT_EQ(std::string(basalt::colorSchemeName(basalt::ColorScheme::Light)), std::string("light"));
33
+ EXPECT_EQ(std::string(basalt::colorSchemeName(basalt::ColorScheme::Dark)), std::string("dark"));
34
+ }
35
+
36
+ TEST(an_override_beats_the_system) {
37
+ const auto system = basalt::systemColorScheme();
38
+ const auto other = opposite(system);
39
+
40
+ basalt::setColorSchemeOverride(basalt::colorSchemeName(other));
41
+ EXPECT(basalt::effectiveColorScheme() == other);
42
+
43
+ // And releasing it hands control back, rather than leaving the last override
44
+ // in place -- which is what `Appearance.setColorScheme('auto')` asks for.
45
+ basalt::clearColorSchemeOverride();
46
+ EXPECT(basalt::effectiveColorScheme() == system);
47
+ }
48
+
49
+ TEST(listeners_hear_an_override_and_its_release) {
50
+ std::vector<basalt::ColorScheme> heard;
51
+ const int token = basalt::addColorSchemeObserver(
52
+ [&heard](basalt::ColorScheme scheme) { heard.push_back(scheme); });
53
+
54
+ const auto system = basalt::systemColorScheme();
55
+ const auto other = opposite(system);
56
+
57
+ basalt::setColorSchemeOverride(basalt::colorSchemeName(other));
58
+ basalt::clearColorSchemeOverride();
59
+
60
+ EXPECT_EQ(static_cast<int>(heard.size()), 2);
61
+ if (heard.size() == 2) {
62
+ EXPECT(heard[0] == other);
63
+ EXPECT(heard[1] == system);
64
+ }
65
+
66
+ basalt::removeColorSchemeObserver(token);
67
+ }
68
+
69
+ // Nothing outside the process changed, so an override that changes nothing must
70
+ // still be a no-op rather than a spurious notification -- but releasing one that
71
+ // was never set must not notify either. The second is the one worth pinning:
72
+ // `Appearance.setColorScheme('auto')` on a fresh app is a perfectly ordinary
73
+ // call and should not wake every listener.
74
+ TEST(releasing_an_override_that_was_never_set_notifies_nobody) {
75
+ int calls = 0;
76
+ const int token =
77
+ basalt::addColorSchemeObserver([&calls](basalt::ColorScheme) { calls++; });
78
+
79
+ basalt::clearColorSchemeOverride();
80
+ EXPECT_EQ(calls, 0);
81
+
82
+ basalt::removeColorSchemeObserver(token);
83
+ }
84
+
85
+ TEST(a_removed_listener_stops_hearing) {
86
+ int calls = 0;
87
+ const int token =
88
+ basalt::addColorSchemeObserver([&calls](basalt::ColorScheme) { calls++; });
89
+ basalt::removeColorSchemeObserver(token);
90
+
91
+ basalt::setColorSchemeOverride("dark");
92
+ basalt::clearColorSchemeOverride();
93
+
94
+ EXPECT_EQ(calls, 0);
95
+ }
96
+
97
+ // An empty string is how a caller says "no override" without knowing React
98
+ // Native's spelling for it. It must not be read as a scheme name and quietly
99
+ // resolve to light.
100
+ TEST(an_empty_override_clears_rather_than_meaning_light) {
101
+ const auto system = basalt::systemColorScheme();
102
+
103
+ basalt::setColorSchemeOverride(basalt::colorSchemeName(opposite(system)));
104
+ basalt::setColorSchemeOverride("");
105
+
106
+ EXPECT(basalt::effectiveColorScheme() == system);
107
+ }
@@ -0,0 +1,79 @@
1
+ // Which transforms turn a view away from the viewer.
2
+ //
3
+ // One rule, shared, so that a card flipped on three desktops hides its back at
4
+ // the same angle. See core/Backface.h.
5
+
6
+ #include "TestHarness.h"
7
+
8
+ #include "Backface.h"
9
+
10
+ #include <sstream>
11
+
12
+ using basalt::facesAway;
13
+
14
+ namespace {
15
+
16
+ // CSS `matrix3d` order, which is what React Native produces.
17
+ struct Matrix {
18
+ float m[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
19
+ };
20
+
21
+ } // namespace
22
+
23
+ TEST(backface_identity_faces_the_viewer) {
24
+ const Matrix identity;
25
+ EXPECT(!facesAway(identity.m));
26
+ }
27
+
28
+ // Turning something in its own plane never shows its back, however far it
29
+ // goes. This is the case a naive "is any angle past ninety" test gets wrong.
30
+ TEST(backface_a_z_rotation_never_turns_away) {
31
+ Matrix half;
32
+ half.m[0] = -1;
33
+ half.m[5] = -1;
34
+ EXPECT(!facesAway(half.m));
35
+ }
36
+
37
+ TEST(backface_a_half_turn_about_y_faces_away) {
38
+ Matrix flipped;
39
+ flipped.m[0] = -1;
40
+ flipped.m[10] = -1;
41
+ EXPECT(facesAway(flipped.m));
42
+ }
43
+
44
+ TEST(backface_a_half_turn_about_x_faces_away) {
45
+ Matrix flipped;
46
+ flipped.m[5] = -1;
47
+ flipped.m[10] = -1;
48
+ EXPECT(facesAway(flipped.m));
49
+ }
50
+
51
+ // A mirror is a back face too, which is what CSS says and what anyone flipping
52
+ // a card with a scale expects.
53
+ TEST(backface_a_mirror_faces_away) {
54
+ Matrix mirrored;
55
+ mirrored.m[0] = -1;
56
+ EXPECT(facesAway(mirrored.m));
57
+ }
58
+
59
+ // Ninety degrees exactly is edge-on: the determinant is zero, nothing is
60
+ // visible either way, and the answer must not flicker. Not facing away is the
61
+ // side to fall on, because it is what the view was doing on the way in.
62
+ TEST(backface_edge_on_is_not_yet_away) {
63
+ Matrix edge;
64
+ edge.m[0] = 0;
65
+ edge.m[10] = 0;
66
+ EXPECT(!facesAway(edge.m));
67
+ }
68
+
69
+ TEST(backface_a_scale_and_rotation_together_still_answer) {
70
+ // Rotated 180 about Y and scaled up: still mirrored, still away.
71
+ Matrix both;
72
+ both.m[0] = -2;
73
+ both.m[5] = 2;
74
+ EXPECT(facesAway(both.m));
75
+ }
76
+
77
+ TEST(backface_no_matrix_faces_the_viewer) {
78
+ EXPECT(!facesAway(nullptr));
79
+ }