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.
- package/LICENSE +21 -0
- package/dist/cli/basalt.d.ts +3 -0
- package/dist/cli/basalt.d.ts.map +1 -0
- package/dist/cli/basalt.js +47 -0
- package/dist/cli/basalt.js.map +1 -0
- package/dist/cli/bundle-cli.d.ts +12 -0
- package/dist/cli/bundle-cli.d.ts.map +1 -0
- package/dist/cli/bundle-cli.js +124 -0
- package/dist/cli/bundle-cli.js.map +1 -0
- package/dist/cli/bundleWithAssets.d.ts +79 -0
- package/dist/cli/bundleWithAssets.d.ts.map +1 -0
- package/dist/cli/bundleWithAssets.js +198 -0
- package/dist/cli/bundleWithAssets.js.map +1 -0
- package/dist/cli/desktop.d.ts +339 -0
- package/dist/cli/desktop.d.ts.map +1 -0
- package/dist/cli/desktop.js +1029 -0
- package/dist/cli/desktop.js.map +1 -0
- package/dist/cli/doctor.d.ts +31 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +283 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.d.ts +77 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +442 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/metro.d.ts +49 -0
- package/dist/cli/metro.d.ts.map +1 -0
- package/dist/cli/metro.js +148 -0
- package/dist/cli/metro.js.map +1 -0
- package/dist/cli/packageApp.d.ts +102 -0
- package/dist/cli/packageApp.d.ts.map +1 -0
- package/dist/cli/packageApp.js +319 -0
- package/dist/cli/packageApp.js.map +1 -0
- package/dist/cli/steps.d.ts +34 -0
- package/dist/cli/steps.d.ts.map +1 -0
- package/dist/cli/steps.js +53 -0
- package/dist/cli/steps.js.map +1 -0
- package/dist/metro-config.d.ts +168 -0
- package/dist/metro-config.d.ts.map +1 -0
- package/dist/metro-config.js +671 -0
- package/dist/metro-config.js.map +1 -0
- package/dist/react-native.config.d.ts +7 -0
- package/dist/react-native.config.d.ts.map +1 -0
- package/dist/react-native.config.js +80 -0
- package/dist/react-native.config.js.map +1 -0
- package/dist/src/DragSource.d.ts +52 -0
- package/dist/src/DragSource.d.ts.map +1 -0
- package/dist/src/DragSource.js +97 -0
- package/dist/src/DragSource.js.map +1 -0
- package/dist/src/DropTarget.d.ts +58 -0
- package/dist/src/DropTarget.d.ts.map +1 -0
- package/dist/src/DropTarget.js +131 -0
- package/dist/src/DropTarget.js.map +1 -0
- package/dist/src/KeyHandler.d.ts +57 -0
- package/dist/src/KeyHandler.d.ts.map +1 -0
- package/dist/src/KeyHandler.js +48 -0
- package/dist/src/KeyHandler.js.map +1 -0
- package/dist/src/Menu.d.ts +72 -0
- package/dist/src/Menu.d.ts.map +1 -0
- package/dist/src/Menu.js +179 -0
- package/dist/src/Menu.js.map +1 -0
- package/dist/src/TitleBar.d.ts +75 -0
- package/dist/src/TitleBar.d.ts.map +1 -0
- package/dist/src/TitleBar.js +236 -0
- package/dist/src/TitleBar.js.map +1 -0
- package/dist/src/Window.d.ts +87 -0
- package/dist/src/Window.d.ts.map +1 -0
- package/dist/src/Window.js +248 -0
- package/dist/src/Window.js.map +1 -0
- package/dist/src/closeRequest.d.ts +55 -0
- package/dist/src/closeRequest.d.ts.map +1 -0
- package/dist/src/closeRequest.js +134 -0
- package/dist/src/closeRequest.js.map +1 -0
- package/dist/src/index.d.ts +45 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +92 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/overrides/Alert.d.ts +69 -0
- package/dist/src/overrides/Alert.d.ts.map +1 -0
- package/dist/src/overrides/Alert.js +112 -0
- package/dist/src/overrides/Alert.js.map +1 -0
- package/dist/src/overrides/BaseViewConfig.d.ts +28 -0
- package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -0
- package/dist/src/overrides/BaseViewConfig.js +72 -0
- package/dist/src/overrides/BaseViewConfig.js.map +1 -0
- package/dist/src/overrides/Platform.linux.d.ts +10 -0
- package/dist/src/overrides/Platform.linux.d.ts.map +1 -0
- package/dist/src/overrides/Platform.linux.js +15 -0
- package/dist/src/overrides/Platform.linux.js.map +1 -0
- package/dist/src/overrides/Platform.macos.d.ts +10 -0
- package/dist/src/overrides/Platform.macos.d.ts.map +1 -0
- package/dist/src/overrides/Platform.macos.js +15 -0
- package/dist/src/overrides/Platform.macos.js.map +1 -0
- package/dist/src/overrides/Platform.windows.d.ts +10 -0
- package/dist/src/overrides/Platform.windows.d.ts.map +1 -0
- package/dist/src/overrides/Platform.windows.js +15 -0
- package/dist/src/overrides/Platform.windows.js.map +1 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts +24 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts.map +1 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.js +30 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.js.map +1 -0
- package/dist/src/overrides/RefreshControl.d.ts +52 -0
- package/dist/src/overrides/RefreshControl.d.ts.map +1 -0
- package/dist/src/overrides/RefreshControl.js +92 -0
- package/dist/src/overrides/RefreshControl.js.map +1 -0
- package/dist/src/overrides/ScrollView.d.ts +39 -0
- package/dist/src/overrides/ScrollView.d.ts.map +1 -0
- package/dist/src/overrides/ScrollView.js +59 -0
- package/dist/src/overrides/ScrollView.js.map +1 -0
- package/dist/src/overrides/Share.d.ts +96 -0
- package/dist/src/overrides/Share.d.ts.map +1 -0
- package/dist/src/overrides/Share.js +97 -0
- package/dist/src/overrides/Share.js.map +1 -0
- package/dist/src/overrides/TextInput.d.ts +81 -0
- package/dist/src/overrides/TextInput.d.ts.map +1 -0
- package/dist/src/overrides/TextInput.js +213 -0
- package/dist/src/overrides/TextInput.js.map +1 -0
- package/dist/src/overrides/View.d.ts +36 -0
- package/dist/src/overrides/View.d.ts.map +1 -0
- package/dist/src/overrides/View.js +99 -0
- package/dist/src/overrides/View.js.map +1 -0
- package/dist/src/overrides/createPlatform.d.ts +32 -0
- package/dist/src/overrides/createPlatform.d.ts.map +1 -0
- package/dist/src/overrides/createPlatform.js +84 -0
- package/dist/src/overrides/createPlatform.js.map +1 -0
- package/dist/src/overrides/setUpDeveloperTools.d.ts +28 -0
- package/dist/src/overrides/setUpDeveloperTools.d.ts.map +1 -0
- package/dist/src/overrides/setUpDeveloperTools.js +84 -0
- package/dist/src/overrides/setUpDeveloperTools.js.map +1 -0
- package/dist/src/overrides/setUpXHR.d.ts +46 -0
- package/dist/src/overrides/setUpXHR.d.ts.map +1 -0
- package/dist/src/overrides/setUpXHR.js +236 -0
- package/dist/src/overrides/setUpXHR.js.map +1 -0
- package/dist/src/quitRequest.d.ts +55 -0
- package/dist/src/quitRequest.d.ts.map +1 -0
- package/dist/src/quitRequest.js +121 -0
- package/dist/src/quitRequest.js.map +1 -0
- package/dist/src/resourcePath.d.ts +18 -0
- package/dist/src/resourcePath.d.ts.map +1 -0
- package/dist/src/resourcePath.js +31 -0
- package/dist/src/resourcePath.js.map +1 -0
- package/dist/src/responseBody.d.ts +76 -0
- package/dist/src/responseBody.d.ts.map +1 -0
- package/dist/src/responseBody.js +94 -0
- package/dist/src/responseBody.js.map +1 -0
- package/dist/src/responseHeaders.d.ts +40 -0
- package/dist/src/responseHeaders.d.ts.map +1 -0
- package/dist/src/responseHeaders.js +75 -0
- package/dist/src/responseHeaders.js.map +1 -0
- package/dist/src/titleBarState.d.ts +43 -0
- package/dist/src/titleBarState.d.ts.map +1 -0
- package/dist/src/titleBarState.js +77 -0
- package/dist/src/titleBarState.js.map +1 -0
- package/dist/src/useContextMenu.d.ts +113 -0
- package/dist/src/useContextMenu.d.ts.map +1 -0
- package/dist/src/useContextMenu.js +109 -0
- package/dist/src/useContextMenu.js.map +1 -0
- package/dist/src/useDialog.d.ts +98 -0
- package/dist/src/useDialog.d.ts.map +1 -0
- package/dist/src/useDialog.js +112 -0
- package/dist/src/useDialog.js.map +1 -0
- package/dist/src/useDisplays.d.ts +70 -0
- package/dist/src/useDisplays.d.ts.map +1 -0
- package/dist/src/useDisplays.js +118 -0
- package/dist/src/useDisplays.js.map +1 -0
- package/dist/src/useHandledKeys.d.ts +38 -0
- package/dist/src/useHandledKeys.d.ts.map +1 -0
- package/dist/src/useHandledKeys.js +70 -0
- package/dist/src/useHandledKeys.js.map +1 -0
- package/dist/src/useWindow.d.ts +140 -0
- package/dist/src/useWindow.d.ts.map +1 -0
- package/dist/src/useWindow.js +233 -0
- package/dist/src/useWindow.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/native/CMakeLists.txt +355 -0
- package/native/bootstrap.sh +613 -0
- package/native/cmake/CompilerFlags.cmake +49 -0
- package/native/cmake/Expo.cmake +125 -0
- package/native/cmake/ReactNativeCore.cmake +612 -0
- package/native/cmake/Reanimated.cmake +108 -0
- package/native/cmake/Skia.cmake +379 -0
- package/native/cmake/ThirdParty.cmake +290 -0
- package/native/cmake/Worklets.cmake +67 -0
- package/native/cmake/codegen/CMakeLists.txt +32 -0
- package/native/core/AppIdentity.cpp +85 -0
- package/native/core/AppIdentity.h +59 -0
- package/native/core/AppPaths.cpp +96 -0
- package/native/core/AppPaths.h +53 -0
- package/native/core/AppearanceModule.cpp +60 -0
- package/native/core/AppearanceModule.h +40 -0
- package/native/core/Backface.h +59 -0
- package/native/core/BlobModule.cpp +283 -0
- package/native/core/BlobModule.h +76 -0
- package/native/core/BlobRegistry.cpp +75 -0
- package/native/core/BlobRegistry.h +44 -0
- package/native/core/ColorScheme.cpp +105 -0
- package/native/core/ColorScheme.h +59 -0
- package/native/core/ComponentRegistry.h +30 -0
- package/native/core/ControlMetrics.h +37 -0
- package/native/core/CoreModules.cpp +592 -0
- package/native/core/CoreModules.h +308 -0
- package/native/core/DebuggingOverlay.cpp +106 -0
- package/native/core/DebuggingOverlay.h +65 -0
- package/native/core/DesktopControls.cpp +232 -0
- package/native/core/DesktopControls.h +170 -0
- package/native/core/DevBundle.cpp +108 -0
- package/native/core/DevBundle.h +69 -0
- package/native/core/DevMenu.cpp +99 -0
- package/native/core/DevMenu.h +75 -0
- package/native/core/DialogModule.cpp +150 -0
- package/native/core/DialogModule.h +51 -0
- package/native/core/DragAndDrop.cpp +45 -0
- package/native/core/DragAndDrop.h +225 -0
- package/native/core/ExpoImageComponent.cpp +79 -0
- package/native/core/ExpoImageComponent.h +80 -0
- package/native/core/ExpoModules.cpp +415 -0
- package/native/core/ExpoModules.h +115 -0
- package/native/core/ExpoRuntime.cpp +366 -0
- package/native/core/ExpoRuntime.h +42 -0
- package/native/core/FocusRing.h +36 -0
- package/native/core/FontRegistry.h +51 -0
- package/native/core/GestureHandlerModule.cpp +136 -0
- package/native/core/GestureHandlerModule.h +71 -0
- package/native/core/Gestures.cpp +533 -0
- package/native/core/Gestures.h +145 -0
- package/native/core/HoverTracker.cpp +69 -0
- package/native/core/HoverTracker.h +109 -0
- package/native/core/HttpClient.cpp +282 -0
- package/native/core/ImageBytes.cpp +205 -0
- package/native/core/ImageBytes.h +29 -0
- package/native/core/ImageCache.cpp +51 -0
- package/native/core/ImageCache.h +89 -0
- package/native/core/JsRuntimeAccess.cpp +70 -0
- package/native/core/JsRuntimeAccess.h +60 -0
- package/native/core/JsiPromise.h +51 -0
- package/native/core/KeyEvents.cpp +116 -0
- package/native/core/KeyEvents.h +144 -0
- package/native/core/LogBoxSurface.cpp +46 -0
- package/native/core/LogBoxSurface.h +68 -0
- package/native/core/MenuModel.h +117 -0
- package/native/core/MenuModule.cpp +209 -0
- package/native/core/MenuModule.h +66 -0
- package/native/core/MountingWalk.h +524 -0
- package/native/core/PackageModules.cpp.in +25 -0
- package/native/core/PackageModules.h +50 -0
- package/native/core/PlatformConstantsModule.cpp +63 -0
- package/native/core/PlatformConstantsModule.h +64 -0
- package/native/core/PlatformServices.h +213 -0
- package/native/core/PointerButtons.h +63 -0
- package/native/core/PullToRefresh.cpp +57 -0
- package/native/core/PullToRefresh.h +73 -0
- package/native/core/ReanimatedCompat.h +47 -0
- package/native/core/ReanimatedModule.cpp +203 -0
- package/native/core/ReanimatedModule.h +55 -0
- package/native/core/ScrollAnimation.cpp +59 -0
- package/native/core/ScrollAnimation.h +70 -0
- package/native/core/ScrollBounds.cpp +26 -0
- package/native/core/ScrollBounds.h +68 -0
- package/native/core/ScrollIndicator.cpp +50 -0
- package/native/core/ScrollIndicator.h +69 -0
- package/native/core/ScrollMomentum.cpp +71 -0
- package/native/core/ScrollMomentum.h +73 -0
- package/native/core/ScrollSnap.cpp +123 -0
- package/native/core/ScrollSnap.h +80 -0
- package/native/core/ShareFallback.cpp +101 -0
- package/native/core/ShareFallback.h +45 -0
- package/native/core/SkiaPictureViewComponent.cpp +11 -0
- package/native/core/SkiaPictureViewComponent.h +47 -0
- package/native/core/SourceCodeModule.cpp +55 -0
- package/native/core/SourceCodeModule.h +53 -0
- package/native/core/StatusBarModule.cpp +23 -0
- package/native/core/StatusBarModule.h +42 -0
- package/native/core/TestDialog.cpp +148 -0
- package/native/core/TestDialog.h +96 -0
- package/native/core/TestKeys.cpp +78 -0
- package/native/core/TestKeys.h +50 -0
- package/native/core/TestQuitFile.cpp +33 -0
- package/native/core/TestQuitFile.h +60 -0
- package/native/core/TestSettle.h +192 -0
- package/native/core/TitleBarRegions.h +31 -0
- package/native/core/TurboModuleProxy.cpp +51 -0
- package/native/core/TurboModuleProxy.h +46 -0
- package/native/core/UIManagerAccess.cpp +43 -0
- package/native/core/UIManagerAccess.h +43 -0
- package/native/core/WindowBoundsCache.cpp +319 -0
- package/native/core/WindowControl.h +235 -0
- package/native/core/WindowHost.h +158 -0
- package/native/core/WindowMethods.cpp +167 -0
- package/native/core/WindowMethods.h +84 -0
- package/native/core/WindowsModule.cpp +448 -0
- package/native/core/WindowsModule.h +133 -0
- package/native/core/WorkletsModule.cpp +199 -0
- package/native/core/WorkletsModule.h +57 -0
- package/native/core/portability_probe.cpp +210 -0
- package/native/tests/EventRecorder.h +124 -0
- package/native/tests/TestHarness.cpp +109 -0
- package/native/tests/TestHarness.h +89 -0
- package/native/tests/TreeDump.h +49 -0
- package/native/tests/test_app_identity.cpp +114 -0
- package/native/tests/test_app_paths.cpp +48 -0
- package/native/tests/test_appearance.cpp +107 -0
- package/native/tests/test_backface.cpp +79 -0
- package/native/tests/test_blobs.cpp +157 -0
- package/native/tests/test_controls.cpp +185 -0
- package/native/tests/test_devbundle.cpp +103 -0
- package/native/tests/test_drag_and_drop.cpp +143 -0
- package/native/tests/test_gestures.cpp +331 -0
- package/native/tests/test_hover.cpp +92 -0
- package/native/tests/test_image_cache.cpp +109 -0
- package/native/tests/test_js_runtime_access.cpp +137 -0
- package/native/tests/test_key_events.cpp +235 -0
- package/native/tests/test_momentum.cpp +138 -0
- package/native/tests/test_quit_file.cpp +104 -0
- package/native/tests/test_scroll_animation.cpp +120 -0
- package/native/tests/test_scroll_bounds.cpp +66 -0
- package/native/tests/test_scroll_indicator.cpp +149 -0
- package/native/tests/test_scroll_snap.cpp +112 -0
- package/native/tests/test_settle.cpp +115 -0
- package/native/tests/test_share.cpp +75 -0
- package/native/tests/test_sourcecode.cpp +62 -0
- package/native/tests/test_window_close.cpp +119 -0
- package/native/tests/test_window_limits.cpp +123 -0
- package/package.json +43 -0
- package/react-native.config.js +86 -0
- 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 ¤t() {
|
|
23
|
+
static CurrentTest test;
|
|
24
|
+
return test;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
} // namespace
|
|
28
|
+
|
|
29
|
+
std::vector<TestCase> ®istry() {
|
|
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> ®istry();
|
|
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
|
+
}
|