catalyst-core 0.3.0-beta.5 → 0.3.0-canary.2
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/changelog.md +185 -71
- package/dist/errors/generateDocs.js +100 -0
- package/dist/errors/index.js +243 -0
- package/dist/errors/registry.js +483 -0
- package/dist/errors-index.json +506 -0
- package/dist/globals.d.ts +62 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.jsx +5 -8
- package/dist/logger.js +1 -1
- package/dist/native/androidProject/app/build.gradle.kts +142 -7
- package/dist/native/androidProject/app/src/main/AndroidManifest.xml +4 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +2 -2
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/BarcodeDetector.kt +3 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/CameraSessionManager.kt +3 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +43 -8
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/BridgeUtilsTest.kt +181 -1
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/CameraUtilsTest.kt +156 -236
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileSizeRouterUtilsTest.kt +471 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileUtilsTest.kt +222 -226
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FrameworkServerUtilsTest.kt +300 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/IntentUtilsTest.kt +244 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/MetricsMonitorTest.kt +359 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NativeBridgeTest.kt +108 -63
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NotificationUtilsTest.kt +329 -385
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/OfflineCacheServiceTest.kt +302 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/PerfEventBufferTest.kt +133 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/UtilsKtTest.kt +152 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/WebCacheManagerTest.kt +145 -324
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/BarcodeDetectorTest.kt +132 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/HoldControllerTest.kt +155 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/TorchControllerTest.kt +150 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/VideoStreamStateMachineTest.kt +120 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/VideoStreamStateTest.kt +62 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/ViewfinderMapperTest.kt +143 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/ZoomControllerTest.kt +421 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/design/DesignTokensTest.kt +207 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/plugins/PluginBridgeTest.kt +368 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/FridaDetectorTest.kt +193 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/SecurityCheckManagerTest.kt +260 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/SecurityCheckSchedulerTest.kt +166 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/DeviceInfoUtilsTest.kt +167 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/DownloadUtilsTest.kt +197 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/NetworkMonitorTest.kt +271 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/PushNotificationUtilsTest.kt +119 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/SafeAreaUtilsTest.kt +108 -0
- package/dist/native/androidProject/build.gradle.kts +1 -0
- package/dist/native/androidProject/gradle/libs.versions.toml +26 -0
- package/dist/native/androidProject/settings.gradle.kts +11 -8
- package/dist/native/androidSetup.js +2 -2
- package/dist/native/bridge/WebBridge.d.ts +98 -0
- package/dist/native/bridge/WebBridge.js +40 -6
- package/dist/native/bridge/constants/NativeInterfaces.d.ts +391 -0
- package/dist/native/bridge/errors.d.ts +67 -0
- package/dist/native/bridge/errors.js +66 -151
- package/dist/native/bridge/hooks/index.d.ts +13 -0
- package/dist/native/bridge/hooks/index.js +0 -6
- package/dist/native/bridge/hooks/useAI.d.ts +1 -0
- package/dist/native/bridge/hooks/useAI.js +3 -1
- package/dist/native/bridge/hooks/useCamera.d.ts +86 -0
- package/dist/native/bridge/hooks/useCamera.js +35 -6
- package/dist/native/bridge/hooks/useDataProtection.d.ts +17 -0
- package/dist/native/bridge/hooks/useDeviceInfo.d.ts +34 -0
- package/dist/native/bridge/hooks/useDeviceInfo.js +5 -0
- package/dist/native/bridge/hooks/useFilePicker.d.ts +53 -0
- package/dist/native/bridge/hooks/useFilePicker.js +13 -0
- package/dist/native/bridge/hooks/useGoogleSignIn.d.ts +12 -0
- package/dist/native/bridge/hooks/useHapticFeedback.d.ts +76 -0
- package/dist/native/bridge/hooks/useHapticFeedback.js +6 -1
- package/dist/native/bridge/hooks/useIntent.d.ts +33 -0
- package/dist/native/bridge/hooks/useIntent.js +2 -0
- package/dist/native/bridge/hooks/useNativeTransition.d.ts +53 -0
- package/dist/native/bridge/hooks/useNativeTransition.js +12 -5
- package/dist/native/bridge/hooks/useNetworkStatus.d.ts +22 -0
- package/dist/native/bridge/hooks/useNetworkStatus.js +7 -0
- package/dist/native/bridge/hooks/useNotification.d.ts +83 -0
- package/dist/native/bridge/hooks/useNotification.js +81 -34
- package/dist/native/bridge/hooks/useSafeArea.d.ts +12 -0
- package/dist/native/bridge/hooks/useSafeArea.js +8 -0
- package/dist/native/bridge/hooks/useVideoStream.d.ts +67 -0
- package/dist/native/bridge/hooks/useVideoStream.js +38 -52
- package/dist/native/bridge/hooks/utils.d.ts +4 -0
- package/dist/native/bridge/hooks.d.ts +1 -0
- package/dist/native/bridge/perf/collectors/ApiCollector.d.ts +30 -0
- package/dist/native/bridge/perf/collectors/ApiCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/CacheCollector.d.ts +43 -0
- package/dist/native/bridge/perf/collectors/CacheCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/HookCollector.d.ts +37 -0
- package/dist/native/bridge/perf/collectors/HookCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/InsightsCollector.d.ts +103 -0
- package/dist/native/bridge/perf/collectors/InsightsCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/InteractionCollector.d.ts +53 -0
- package/dist/native/bridge/perf/collectors/InteractionCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/KeyboardCollector.d.ts +30 -0
- package/dist/native/bridge/perf/collectors/KeyboardCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/NavigationCollector.d.ts +37 -0
- package/dist/native/bridge/perf/collectors/NavigationCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.d.ts +30 -0
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/RenderCollector.d.ts +47 -0
- package/dist/native/bridge/perf/collectors/RenderCollector.js +8 -0
- package/dist/native/bridge/perf/collectors/ScrollCollector.d.ts +29 -0
- package/dist/native/bridge/perf/collectors/ScrollCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/ThreadCollector.d.ts +31 -0
- package/dist/native/bridge/perf/collectors/ThreadCollector.js +4 -0
- package/dist/native/bridge/perf/core/constants.d.ts +76 -0
- package/dist/native/bridge/perf/core/measure.d.ts +39 -0
- package/dist/native/bridge/perf/core/measure.js +4 -0
- package/dist/native/bridge/perf/core/session.d.ts +49 -0
- package/dist/native/bridge/perf/core/session.js +4 -0
- package/dist/native/bridge/perf/core/store.d.ts +37 -0
- package/dist/native/bridge/perf/core/store.js +4 -0
- package/dist/native/bridge/perf/core/summary.d.ts +60 -0
- package/dist/native/bridge/perf/core/traceExport.d.ts +10 -0
- package/dist/native/bridge/perf/core/waterfalls.d.ts +2 -0
- package/dist/native/bridge/perf/index.d.ts +63 -0
- package/dist/native/bridge/perf/index.js +4 -0
- package/dist/native/bridge/safeArea.d.ts +11 -0
- package/dist/native/bridge/safeArea.js +2 -0
- package/dist/native/bridge/useBaseHook.d.ts +137 -0
- package/dist/native/bridge/useBaseHook.js +34 -4
- package/dist/native/bridge/utils/CameraUtils.d.ts +94 -0
- package/dist/native/bridge/utils/CameraUtils.js +4 -0
- package/dist/native/bridge/utils/FileObjectConverter.d.ts +36 -0
- package/dist/native/bridge/utils/NativeBridge.d.ts +270 -0
- package/dist/native/bridge/utils/NativeBridge.js +10 -0
- package/dist/native/buildAndroid/index.js +1 -1
- package/dist/native/buildAppAndroid.js +9 -0
- package/dist/native/buildAppIos.js +16 -1
- package/dist/native/buildErrorFormat.js +57 -0
- package/dist/native/buildIos/config.js +15 -1
- package/dist/native/buildIos/index.js +1 -1
- package/dist/native/buildIos/plugins.js +10 -1
- package/dist/native/iosnativeWebView/CoreLogic/Package.swift +36 -0
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Camera/VideoStreamState.swift +1 -1
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Camera/VideoStreamStateMachine.swift +6 -4
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/BootTimingUtility.swift +3 -3
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/FrameworkServerUtils.swift +14 -9
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NetworkMonitor.swift +11 -9
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NotificationHandlerProvider.swift +1 -1
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/URLWhitelistManager.swift +7 -7
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/AnyCodableTests.swift +154 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/BootTimingUtilityTests.swift +23 -5
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/CatalystConstantsTests.swift +192 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/ConfigMappingTests.swift +1 -1
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/FrameworkServerUtilsErrorPathTests.swift +106 -0
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/FrameworkServerUtilsLoopbackTests.swift +243 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/FrameworkServerUtilsTests.swift +1 -1
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/NetworkMonitorTests.swift +119 -0
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/NotificationHandlerProviderTests.swift +59 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/NotificationHandlerTests.swift +1 -1
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/URLWhitelistManagerTests.swift +1 -1
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/VideoStreamStateMachineTests.swift +171 -0
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/VideoStreamStateTests.swift +91 -0
- package/dist/native/iosnativeWebView/Package.swift +10 -9
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/LocalNotificationHandler.swift +7 -2
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/NotificationManager.swift +1 -2
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/PushNotificationHandler.swift +5 -4
- package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraSessionManager.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Camera/HoldController.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Camera/NativeCameraManager.swift +6 -5
- package/dist/native/iosnativeWebView/Sources/Core/Camera/ZoomController.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Plugins/PluginBridge.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/CacheManager.swift +31 -30
- package/dist/native/iosnativeWebView/Sources/Core/Utils/CameraTransportUtils.swift +2 -1
- package/dist/native/iosnativeWebView/Sources/Core/Utils/DeviceInfoUtils.swift +1 -1
- package/dist/native/iosnativeWebView/Sources/Core/Utils/FilePickerHandler.swift +22 -19
- package/dist/native/iosnativeWebView/Sources/Core/Utils/ImageHandler.swift +40 -39
- package/dist/native/iosnativeWebView/Sources/Core/Utils/PerfEventBuffer.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/ResourceURLProtocol.swift +15 -15
- package/dist/native/iosnativeWebView/Sources/Core/Utils/WebKitConfig.swift +4 -3
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeCommandHandler.swift +6 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeDelegateHandler.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeFileHandler.swift +2 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeJavaScriptInterface.swift +2 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +3 -5
- package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +20 -13
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashView.swift +6 -5
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashViewModel.swift +14 -13
- package/dist/native/iosnativeWebView/Sources/Core/WebView/TransitionManager.swift +3 -3
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +9 -8
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewModel.swift +7 -6
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +24 -25
- package/dist/native/iosnativeWebView/iosnativeWebView/AppDelegate.swift +6 -1
- package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +1 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/iosnativeWebViewApp.swift +4 -0
- package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +2 -22
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeMessageValidatorTests.swift +1 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/CacheManagerTests.swift +1 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/FilePickerHandlerTests.swift +2 -1
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/NativeBridgeTests.swift +15 -9
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/WebViewTests.swift +1 -0
- package/dist/native/setupEmulatorIos.js +2 -2
- package/dist/native/terminalProgress.js +17 -17
- package/dist/router/ClientRouter.d.ts +8 -0
- package/dist/router/ClientRouter.js +13 -11
- package/dist/router/ServerRouter.d.ts +13 -0
- package/dist/router/ServerRouter.js +19 -7
- package/dist/scripts/build.js +14 -2
- package/dist/scripts/loadEnvironmentVariables.js +3 -2
- package/dist/scripts/plugins.js +1 -1
- package/dist/scripts/preServerInit.js +49 -3
- package/dist/scripts/preflight.js +111 -0
- package/dist/scripts/scriptUtils.js +46 -1
- package/dist/scripts/serve.js +7 -3
- package/dist/scripts/start.js +8 -3
- package/dist/server/expressServer.d.ts +1 -0
- package/dist/server/expressServer.js +247 -271
- package/dist/server/manifestCache.d.ts +2 -0
- package/dist/server/manifestCache.js +25 -33
- package/dist/server/renderer/ChunkExtractor.d.ts +44 -0
- package/dist/server/renderer/ChunkExtractor.js +113 -125
- package/dist/server/renderer/document/Body.d.ts +21 -0
- package/dist/server/renderer/document/Body.jsx +45 -45
- package/dist/server/renderer/document/FastRefresh.d.ts +3 -0
- package/dist/server/renderer/document/FastRefresh.jsx +7 -13
- package/dist/server/renderer/document/Head.d.ts +20 -0
- package/dist/server/renderer/document/Head.jsx +32 -32
- package/dist/server/renderer/document/index.d.ts +2 -0
- package/dist/server/renderer/document/index.jsx +2 -2
- package/dist/server/renderer/extract.d.ts +67 -0
- package/dist/server/renderer/extract.js +92 -89
- package/dist/server/renderer/handler.d.ts +2 -0
- package/dist/server/renderer/handler.jsx +401 -404
- package/dist/server/renderer/index.d.ts +2 -0
- package/dist/server/renderer/index.js +5 -8
- package/dist/server/renderer/render.d.ts +35 -0
- package/dist/server/renderer/render.js +25 -32
- package/dist/server/utils/botDetectionMiddleware.d.ts +1 -0
- package/dist/server/utils/botDetectionMiddleware.js +33 -23
- package/dist/server/utils/cjsRequire.d.ts +8 -0
- package/dist/server/utils/cjsRequire.js +2 -2
- package/dist/server/utils/userAgentUtil.d.ts +7 -0
- package/dist/server/utils/userAgentUtil.js +68 -71
- package/dist/server/utils/validator.d.ts +31 -0
- package/dist/server/utils/validator.js +133 -158
- package/dist/vite/inject-cache-key-plugin.js +3 -27
- package/dist/vite/moduleAliases.js +36 -0
- package/dist/vite/node-loader.mjs +2 -29
- package/dist/vite/resolveDevServerConfig.js +4 -1
- package/dist/vite/vite.config.js +2 -29
- package/dist/web-router/components/MetaTag.d.ts +4 -0
- package/dist/web-router/components/MetaTag.jsx +26 -28
- package/dist/web-router/components/MetaTag.test.jsx +100 -0
- package/dist/web-router/components/RouterDataProvider.d.ts +96 -0
- package/dist/web-router/components/RouterDataProvider.jsx +260 -259
- package/dist/web-router/components/RouterDataProvider.server.test.jsx +98 -0
- package/dist/web-router/components/RouterDataProvider.test.jsx +310 -0
- package/dist/web-router/components/Split.d.ts +74 -0
- package/dist/web-router/components/Split.jsx +147 -156
- package/dist/web-router/components/Split.server.test.jsx +52 -0
- package/dist/web-router/components/Split.test.jsx +167 -0
- package/dist/web-router/components/SplitInview.d.ts +22 -0
- package/dist/web-router/components/SplitInview.jsx +78 -89
- package/dist/web-router/components/SplitInview.test.jsx +112 -0
- package/dist/web-router/components/SsrRequestContext.d.ts +20 -0
- package/dist/web-router/components/SsrRequestContext.jsx +17 -7
- package/dist/web-router/components/SsrRequestContext.test.jsx +53 -0
- package/dist/web-router/context.d.ts +15 -0
- package/dist/web-router/context.jsx +5 -5
- package/dist/web-router/context.test.jsx +10 -0
- package/dist/web-router/utils/metaDataUtils.d.ts +24 -0
- package/dist/web-router/utils/metaDataUtils.jsx +86 -86
- package/dist/web-router/utils/metaDataUtils.test.jsx +188 -0
- package/dist/web-router/vitest.setup.js +12 -0
- package/mcp_v2/knowledge-base.json +115 -17
- package/mcp_v2/mcp.js +141 -3
- package/mcp_v2/package-lock.json +2031 -0
- package/mcp_v2/package.json +13 -2
- package/mcp_v2/scripts/copyErrorsIndex.cjs +34 -0
- package/mcp_v2/test/errors.test.ts +123 -0
- package/mcp_v2/test/github.test.ts +177 -0
- package/mcp_v2/tools/errors.d.ts +20 -0
- package/mcp_v2/tools/errors.js +63 -0
- package/mcp_v2/tools/github.d.ts +41 -0
- package/mcp_v2/tools/github.js +231 -0
- package/mcp_v2/vitest.config.mjs +22 -0
- package/package.json +60 -11
- package/test/errors/docsDrift.test.ts +113 -0
- package/test/errors/index.test.ts +200 -0
- package/test/errors/registry.test.ts +108 -0
- package/test/scripts/preflight.test.ts +118 -0
- package/test/server/ChunkExtractor.test.ts +97 -0
- package/test/server/extract.test.ts +128 -0
- package/test/server/fixtures/template/server/document.jsx +19 -0
- package/test/server/fixtures/template/server/index.js +10 -0
- package/test/server/fixtures/template/src/js/containers/App/index.jsx +33 -0
- package/test/server/fixtures/template/src/js/routes/index.jsx +72 -0
- package/test/server/fixtures/template/src/js/routes/utils.jsx +39 -0
- package/test/server/fixtures/template/src/js/store/index.js +19 -0
- package/test/server/handler.assets.test.ts +330 -0
- package/test/server/handler.test.ts +208 -0
- package/test/server/manifestCache.test.ts +71 -0
- package/test/server/render.test.ts +71 -0
- package/test/server/scriptUtils.test.ts +103 -0
- package/test/server/userAgentUtil.test.ts +48 -0
- package/test/server/validator.test.ts +225 -0
- package/test/vite/resolveDevServerConfig.test.js +4 -1
- package/tsconfig.test.json +23 -0
- package/vitest.config.ts +93 -0
- package/dist/caching.js +0 -1
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/DeviceInfoUtilsTest.kt +0 -187
- package/dist/native/bridge/standardizedHooks.js +0 -611
- package/dist/router.js +0 -1
- package/dist/scripts/validator.js +0 -149
- package/dist/web-router/hooks.jsx +0 -72
- package/dist/web-router/types/components/MetaTag.d.ts +0 -2
- package/dist/web-router/types/components/RouterDataProvider.d.ts +0 -95
- package/dist/web-router/types/context.d.ts +0 -14
- package/dist/web-router/types/hooks.d.ts +0 -1
- package/dist/web-router/types/index.d.ts +0 -3
- package/dist/web-router/types/utils/metaDataUtils.d.ts +0 -40
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Constants/CatalystConstants.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Constants/ConfigConstants.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Notifications/NotificationModels.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Protocols/NotificationHandlerProtocol.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NullNotificationHandler.swift +0 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
package io.yourname.androidproject
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.net.Uri
|
|
5
|
+
import android.webkit.CookieManager
|
|
6
|
+
import org.junit.After
|
|
7
|
+
import org.junit.Assert.assertFalse
|
|
8
|
+
import org.junit.Assert.assertNotNull
|
|
9
|
+
import org.junit.Assert.assertNull
|
|
10
|
+
import org.junit.Assert.assertTrue
|
|
11
|
+
import org.junit.Before
|
|
12
|
+
import org.junit.Test
|
|
13
|
+
import org.mockito.MockedStatic
|
|
14
|
+
import org.mockito.Mockito.mockStatic
|
|
15
|
+
import org.mockito.kotlin.any
|
|
16
|
+
import org.mockito.kotlin.doReturn
|
|
17
|
+
import org.mockito.kotlin.mock
|
|
18
|
+
import org.mockito.kotlin.whenever
|
|
19
|
+
import java.io.File
|
|
20
|
+
import kotlin.io.path.createTempDirectory
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* #413: first Mockito-based test in this template, covering
|
|
24
|
+
* OfflineCacheService — previously untested because it takes a real
|
|
25
|
+
* android.content.Context in its constructor and calls the unmocked
|
|
26
|
+
* android.net.Uri / android.webkit.CookieManager Android-stub classes
|
|
27
|
+
* internally (JVM unit tests run against the SDK's stub jar, which throws
|
|
28
|
+
* on any call unless testOptions.unitTests.isReturnDefaultValues is set,
|
|
29
|
+
* or the class is mocked — see app/build.gradle.kts).
|
|
30
|
+
*
|
|
31
|
+
* Uri.parse(...) is mocked statically per test via Mockito's inline
|
|
32
|
+
* mock-maker (the mockito-core 5.x default) so isHttpUrl/isOfflineRouteUrl/
|
|
33
|
+
* shouldCacheAssetUrl exercise real logic against fake-but-realistic parsed
|
|
34
|
+
* URIs, rather than the SDK stub's default null/false behavior.
|
|
35
|
+
*/
|
|
36
|
+
class OfflineCacheServiceTest {
|
|
37
|
+
|
|
38
|
+
private lateinit var cacheDir: File
|
|
39
|
+
private lateinit var context: Context
|
|
40
|
+
private lateinit var uriMock: MockedStatic<Uri>
|
|
41
|
+
private lateinit var cookieManagerMock: MockedStatic<CookieManager>
|
|
42
|
+
|
|
43
|
+
@Before
|
|
44
|
+
fun setUp() {
|
|
45
|
+
cacheDir = createTempDirectory(prefix = "catalyst-offline-test").toFile()
|
|
46
|
+
context = mock {
|
|
47
|
+
on { getCacheDir() } doReturn cacheDir
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
uriMock = mockStatic(Uri::class.java)
|
|
51
|
+
uriMock.`when`<Uri> { Uri.parse(any()) }.thenAnswer { invocation ->
|
|
52
|
+
fakeUriFor(invocation.getArgument(0))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// CookieManager.getInstance() has no real webview in a JVM unit
|
|
56
|
+
// test; stub it to a mock that reports no cookies, matching what
|
|
57
|
+
// production sees on a fresh device before any cookies are set.
|
|
58
|
+
val cookieManager = mock<CookieManager> {
|
|
59
|
+
on { getCookie(any()) } doReturn null
|
|
60
|
+
}
|
|
61
|
+
cookieManagerMock = mockStatic(CookieManager::class.java)
|
|
62
|
+
cookieManagerMock.`when`<CookieManager> { CookieManager.getInstance() }.thenReturn(cookieManager)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@After
|
|
66
|
+
fun tearDown() {
|
|
67
|
+
uriMock.close()
|
|
68
|
+
cookieManagerMock.close()
|
|
69
|
+
cacheDir.deleteRecursively()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// A tiny fake of what Uri.parse() would return for the http(s) URLs
|
|
73
|
+
// this class actually deals with — just enough of the real contract
|
|
74
|
+
// (scheme/authority/path/fragment stripping) for the code under test.
|
|
75
|
+
private fun fakeUriFor(url: String): Uri {
|
|
76
|
+
val schemeEnd = url.indexOf("://")
|
|
77
|
+
val scheme = if (schemeEnd >= 0) url.substring(0, schemeEnd) else null
|
|
78
|
+
val afterScheme = if (schemeEnd >= 0) url.substring(schemeEnd + 3) else url
|
|
79
|
+
val pathStart = afterScheme.indexOf('/').let { if (it < 0) afterScheme.length else it }
|
|
80
|
+
val authority = if (schemeEnd >= 0) afterScheme.substring(0, pathStart) else null
|
|
81
|
+
val rawPath = afterScheme.substring(pathStart).substringBefore('#').ifEmpty { "/" }
|
|
82
|
+
val withoutFragment = url.substringBefore('#')
|
|
83
|
+
|
|
84
|
+
val withoutFragmentUri = mock<Uri>()
|
|
85
|
+
whenever(withoutFragmentUri.toString()) doReturn withoutFragment
|
|
86
|
+
|
|
87
|
+
val builder = mock<Uri.Builder>()
|
|
88
|
+
whenever(builder.fragment(org.mockito.kotlin.anyOrNull())) doReturn builder
|
|
89
|
+
whenever(builder.build()) doReturn withoutFragmentUri
|
|
90
|
+
|
|
91
|
+
val uri = mock<Uri>()
|
|
92
|
+
whenever(uri.scheme) doReturn scheme
|
|
93
|
+
whenever(uri.authority) doReturn authority
|
|
94
|
+
whenever(uri.path) doReturn rawPath
|
|
95
|
+
whenever(uri.toString()) doReturn withoutFragment
|
|
96
|
+
whenever(uri.buildUpon()) doReturn builder
|
|
97
|
+
return uri
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@Test
|
|
101
|
+
fun `shouldCacheAssetUrl accepts known static-asset extensions over http(s)`() {
|
|
102
|
+
val service = OfflineCacheService(context)
|
|
103
|
+
|
|
104
|
+
assertTrue(service.shouldCacheAssetUrl("https://example.com/static/app.js"))
|
|
105
|
+
assertTrue(service.shouldCacheAssetUrl("https://example.com/static/app.CSS"))
|
|
106
|
+
assertFalse(service.shouldCacheAssetUrl("https://example.com/api/data"))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@Test
|
|
110
|
+
fun `shouldCacheAssetUrl rejects non-http(s) schemes`() {
|
|
111
|
+
val service = OfflineCacheService(context)
|
|
112
|
+
|
|
113
|
+
assertFalse(service.shouldCacheAssetUrl("file:///static/app.js"))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Test
|
|
117
|
+
fun `hasRouteSnapshot is false when no manifest has been loaded`() {
|
|
118
|
+
val service = OfflineCacheService(context)
|
|
119
|
+
|
|
120
|
+
assertFalse(service.hasRouteSnapshot("https://example.com/some/route"))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@Test
|
|
124
|
+
fun `getRouteSnapshotResponse returns null when route is not offline-eligible`() {
|
|
125
|
+
val service = OfflineCacheService(context)
|
|
126
|
+
|
|
127
|
+
assertNull(service.getRouteSnapshotResponse("https://example.com/not-cached"))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@Test
|
|
131
|
+
fun `clearAll resets cached manifest state without throwing`() {
|
|
132
|
+
val service = OfflineCacheService(context)
|
|
133
|
+
|
|
134
|
+
service.clearAll()
|
|
135
|
+
|
|
136
|
+
assertFalse(service.hasRouteSnapshot("https://example.com/some/route"))
|
|
137
|
+
assertTrue(cacheDir.exists())
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@Test
|
|
141
|
+
fun `context getCacheDir is consulted exactly once at construction`() {
|
|
142
|
+
OfflineCacheService(context)
|
|
143
|
+
|
|
144
|
+
org.mockito.kotlin.verify(context).getCacheDir()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ============================================================
|
|
148
|
+
// Manifest-driven routing (batch 4 extension)
|
|
149
|
+
//
|
|
150
|
+
// The manifest is loaded once at construction time via
|
|
151
|
+
// loadCachedManifest() -> parseManifest(), reading a plain
|
|
152
|
+
// manifest.json file under context.cacheDir/catalyst_offline/ — no
|
|
153
|
+
// network involved. Pre-writing that file before constructing
|
|
154
|
+
// OfflineCacheService unlocks isOfflineRouteUrl/getRouteSnapshotResponse/
|
|
155
|
+
// hasRouteSnapshot's real-match branches, previously only exercised
|
|
156
|
+
// via their "no manifest loaded" empty-state paths above.
|
|
157
|
+
// ============================================================
|
|
158
|
+
|
|
159
|
+
private fun writeManifest(buildId: String, routes: List<Pair<String, String>>) {
|
|
160
|
+
val rootDir = File(cacheDir, "catalyst_offline")
|
|
161
|
+
rootDir.mkdirs()
|
|
162
|
+
val routesJson = routes.joinToString(",") { (pattern, regex) ->
|
|
163
|
+
"""{"pattern":"$pattern","regex":"$regex"}"""
|
|
164
|
+
}
|
|
165
|
+
val json = """{"buildId":"$buildId","routes":[$routesJson]}"""
|
|
166
|
+
File(rootDir, "manifest.json").writeText(json)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Test
|
|
170
|
+
fun `isOfflineRouteUrl matches a route whose regex matches the url path`() {
|
|
171
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
172
|
+
val service = OfflineCacheService(context)
|
|
173
|
+
|
|
174
|
+
assertTrue(service.isOfflineRouteUrl("https://example.com/docs/getting-started"))
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@Test
|
|
178
|
+
fun `isOfflineRouteUrl returns false when no route regex matches`() {
|
|
179
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
180
|
+
val service = OfflineCacheService(context)
|
|
181
|
+
|
|
182
|
+
assertFalse(service.isOfflineRouteUrl("https://example.com/api/data"))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@Test
|
|
186
|
+
fun `isOfflineRouteUrl returns false for a non-http(s) url even with a loaded manifest`() {
|
|
187
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
188
|
+
val service = OfflineCacheService(context)
|
|
189
|
+
|
|
190
|
+
assertFalse(service.isOfflineRouteUrl("file:///docs/local.html"))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@Test
|
|
194
|
+
fun `isOfflineRouteUrl treats an unparseable route regex as a non-match, not a crash`() {
|
|
195
|
+
// "[" is an invalid regex -- Regex(...).matches() should throw,
|
|
196
|
+
// caught internally and treated as "this route doesn't match"
|
|
197
|
+
// rather than propagating.
|
|
198
|
+
writeManifest("build-123", listOf("/broken" to "["))
|
|
199
|
+
val service = OfflineCacheService(context)
|
|
200
|
+
|
|
201
|
+
assertFalse(service.isOfflineRouteUrl("https://example.com/broken"))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@Test
|
|
205
|
+
fun `hasRouteSnapshot is true only when the route is eligible AND a snapshot file exists on disk`() {
|
|
206
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
207
|
+
val service = OfflineCacheService(context)
|
|
208
|
+
val url = "https://example.com/docs/getting-started"
|
|
209
|
+
|
|
210
|
+
// Route is eligible per the manifest, but no snapshot has been
|
|
211
|
+
// written to disk yet.
|
|
212
|
+
assertFalse(service.hasRouteSnapshot(url))
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private fun sha256Hex(value: String): String {
|
|
216
|
+
val digest = java.security.MessageDigest.getInstance("SHA-256").digest(value.toByteArray())
|
|
217
|
+
return digest.joinToString("") { "%02x".format(it) }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@Test
|
|
221
|
+
fun `getRouteSnapshotResponse serves a real snapshot file for an eligible, snapshotted route`() {
|
|
222
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
223
|
+
val url = "https://example.com/docs/getting-started"
|
|
224
|
+
|
|
225
|
+
// snapshotFileForUrl/hash are private; reproduce their (simple,
|
|
226
|
+
// stable) SHA-256-based path layout here to place a snapshot file
|
|
227
|
+
// exactly where the production code will look for it:
|
|
228
|
+
// routes/<hash(origin:buildId)>/<hash(normalizedUrl)>.html
|
|
229
|
+
val namespace = "https://example.com:build-123"
|
|
230
|
+
val namespaceDir = File(cacheDir, "catalyst_offline/routes/${sha256Hex(namespace)}")
|
|
231
|
+
namespaceDir.mkdirs()
|
|
232
|
+
File(namespaceDir, "${sha256Hex(url)}.html").writeText("<html>cached docs page</html>")
|
|
233
|
+
|
|
234
|
+
val service = OfflineCacheService(context)
|
|
235
|
+
|
|
236
|
+
// WebResourceResponse is an android.webkit SDK stub class: its
|
|
237
|
+
// constructor is a no-op under the mockable jar and its getters
|
|
238
|
+
// return defaults regardless of what was passed in (confirmed
|
|
239
|
+
// empirically earlier this session, see WebCacheManagerTest) --
|
|
240
|
+
// only "a response object was returned" is assertable here, not
|
|
241
|
+
// its field contents.
|
|
242
|
+
assertTrue(service.hasRouteSnapshot(url))
|
|
243
|
+
assertNotNull(service.getRouteSnapshotResponse(url))
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@Test
|
|
247
|
+
fun `getRouteSnapshotResponse returns null when the route is eligible but no snapshot file exists yet`() {
|
|
248
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
249
|
+
val service = OfflineCacheService(context)
|
|
250
|
+
val url = "https://example.com/docs/getting-started"
|
|
251
|
+
|
|
252
|
+
assertFalse(service.hasRouteSnapshot(url))
|
|
253
|
+
assertNull(service.getRouteSnapshotResponse(url))
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@Test
|
|
257
|
+
fun `clearAll removes a manifest loaded from a previous instance`() {
|
|
258
|
+
writeManifest("build-123", listOf("/docs/*" to "^/docs/.*$"))
|
|
259
|
+
val service = OfflineCacheService(context)
|
|
260
|
+
assertTrue(service.isOfflineRouteUrl("https://example.com/docs/x"))
|
|
261
|
+
|
|
262
|
+
service.clearAll()
|
|
263
|
+
|
|
264
|
+
// manifest is nulled out by clearAll(); route matching should
|
|
265
|
+
// fall back to "no manifest" behavior immediately, in the same
|
|
266
|
+
// instance, without needing to reconstruct the service.
|
|
267
|
+
assertFalse(service.isOfflineRouteUrl("https://example.com/docs/x"))
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@Test
|
|
271
|
+
fun `a second OfflineCacheService instance loads the manifest persisted by a previous one`() {
|
|
272
|
+
writeManifest("build-456", listOf("/blog/*" to "^/blog/.*$"))
|
|
273
|
+
|
|
274
|
+
// First instance's constructor already ran loadCachedManifest();
|
|
275
|
+
// this constructs a second instance against the SAME cacheDir to
|
|
276
|
+
// confirm the on-disk manifest.json (not just in-memory state) is
|
|
277
|
+
// what's actually being read.
|
|
278
|
+
OfflineCacheService(context)
|
|
279
|
+
val secondInstance = OfflineCacheService(context)
|
|
280
|
+
|
|
281
|
+
assertTrue(secondInstance.isOfflineRouteUrl("https://example.com/blog/post-1"))
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@Test
|
|
285
|
+
fun `a malformed manifest json on disk is treated as no manifest, not a crash`() {
|
|
286
|
+
val rootDir = File(cacheDir, "catalyst_offline")
|
|
287
|
+
rootDir.mkdirs()
|
|
288
|
+
File(rootDir, "manifest.json").writeText("not valid json {{{")
|
|
289
|
+
|
|
290
|
+
val service = OfflineCacheService(context)
|
|
291
|
+
|
|
292
|
+
assertFalse(service.isOfflineRouteUrl("https://example.com/docs/x"))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
@Test
|
|
296
|
+
fun `a manifest with an empty routes array loads without matching anything`() {
|
|
297
|
+
writeManifest("build-789", emptyList())
|
|
298
|
+
val service = OfflineCacheService(context)
|
|
299
|
+
|
|
300
|
+
assertFalse(service.isOfflineRouteUrl("https://example.com/anything"))
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
package io.yourname.androidproject
|
|
2
|
+
|
|
3
|
+
import io.yourname.androidproject.utils.PerfEventBuffer
|
|
4
|
+
import org.json.JSONObject
|
|
5
|
+
import org.junit.After
|
|
6
|
+
import org.junit.Assert.*
|
|
7
|
+
import org.junit.Before
|
|
8
|
+
import org.junit.Test
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Unit tests for PerfEventBuffer, previously entirely untested (0%).
|
|
12
|
+
*
|
|
13
|
+
* Scope: configure/isEnabled/add/bridgeCallReceived/bridgeCallDispatched/
|
|
14
|
+
* reset are exercised directly — pure state plus a ConcurrentLinkedQueue,
|
|
15
|
+
* no Handler/Looper dispatch involved. scheduleFlush/flushNow/
|
|
16
|
+
* startPeriodicFlush/the deliver-retry pipeline post through a real
|
|
17
|
+
* android.os.Handler(Looper.getMainLooper()) constructed at object-init
|
|
18
|
+
* time — Looper.getMainLooper() has no real Looper in a JVM unit test, so
|
|
19
|
+
* calling those methods either throws or silently never runs the posted
|
|
20
|
+
* work. Left uncovered here rather than chased with Robolectric, per the
|
|
21
|
+
* plan's Mockito-only scope.
|
|
22
|
+
*
|
|
23
|
+
* PerfEventBuffer is a singleton object — tests reset() in tearDown so
|
|
24
|
+
* state doesn't leak into other test classes running in the same JVM.
|
|
25
|
+
*/
|
|
26
|
+
class PerfEventBufferTest {
|
|
27
|
+
|
|
28
|
+
@Before
|
|
29
|
+
fun setUp() {
|
|
30
|
+
PerfEventBuffer.reset()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@After
|
|
34
|
+
fun tearDown() {
|
|
35
|
+
PerfEventBuffer.configure(enabled = false)
|
|
36
|
+
PerfEventBuffer.reset()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Test
|
|
40
|
+
fun `configure(true) enables the buffer in a debug build`() {
|
|
41
|
+
// configure(true) only actually enables the buffer when
|
|
42
|
+
// BuildConfig.DEBUG is true — assert that precondition explicitly
|
|
43
|
+
// (via Assume) rather than just asserting isEnabled() and relying
|
|
44
|
+
// on an unchecked comment that this suite always runs under the
|
|
45
|
+
// debug variant. This task runs as testDebugUnitTest, so it does
|
|
46
|
+
// today, but making the check explicit means a future variant
|
|
47
|
+
// change surfaces as a skip, not a silent false-negative pass.
|
|
48
|
+
org.junit.Assume.assumeTrue(
|
|
49
|
+
"This test only applies to the debug variant",
|
|
50
|
+
io.yourname.androidproject.BuildConfig.DEBUG
|
|
51
|
+
)
|
|
52
|
+
PerfEventBuffer.configure(enabled = true)
|
|
53
|
+
assertTrue(PerfEventBuffer.isEnabled())
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Test
|
|
57
|
+
fun `configure(false) disables the buffer`() {
|
|
58
|
+
PerfEventBuffer.configure(enabled = true)
|
|
59
|
+
PerfEventBuffer.configure(enabled = false)
|
|
60
|
+
assertFalse(PerfEventBuffer.isEnabled())
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Test
|
|
64
|
+
fun `add is a no-op when disabled`() {
|
|
65
|
+
PerfEventBuffer.configure(enabled = false)
|
|
66
|
+
// Should not throw even though nothing is buffered.
|
|
67
|
+
PerfEventBuffer.add(JSONObject().apply { put("type", "test") })
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Test
|
|
71
|
+
fun `add does not throw when enabled`() {
|
|
72
|
+
PerfEventBuffer.configure(enabled = true)
|
|
73
|
+
PerfEventBuffer.add(JSONObject().apply { put("type", "test-event") })
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@Test
|
|
77
|
+
fun `bridgeCallReceived followed by bridgeCallDispatched does not throw`() {
|
|
78
|
+
PerfEventBuffer.configure(enabled = true)
|
|
79
|
+
|
|
80
|
+
PerfEventBuffer.bridgeCallReceived("call-1", "getDeviceInfo")
|
|
81
|
+
PerfEventBuffer.bridgeCallDispatched("call-1")
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Test
|
|
85
|
+
fun `bridgeCallDispatched for an unknown callId is a no-op`() {
|
|
86
|
+
PerfEventBuffer.configure(enabled = true)
|
|
87
|
+
|
|
88
|
+
// No matching bridgeCallReceived — pendingCalls has no entry for
|
|
89
|
+
// "unknown-call", so this should return early without throwing.
|
|
90
|
+
PerfEventBuffer.bridgeCallDispatched("unknown-call")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Test
|
|
94
|
+
fun `bridgeCallReceived and bridgeCallDispatched are no-ops when disabled`() {
|
|
95
|
+
PerfEventBuffer.configure(enabled = false)
|
|
96
|
+
|
|
97
|
+
PerfEventBuffer.bridgeCallReceived("call-1", "getDeviceInfo")
|
|
98
|
+
PerfEventBuffer.bridgeCallDispatched("call-1")
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@Test
|
|
102
|
+
fun `reset disables flushed state and clears without throwing`() {
|
|
103
|
+
PerfEventBuffer.configure(enabled = true)
|
|
104
|
+
PerfEventBuffer.add(JSONObject().apply { put("type", "test") })
|
|
105
|
+
|
|
106
|
+
PerfEventBuffer.reset()
|
|
107
|
+
|
|
108
|
+
// Buffer cleared, no exception — isEnabled() state is untouched by
|
|
109
|
+
// reset() itself (only configure() changes it).
|
|
110
|
+
assertTrue(PerfEventBuffer.isEnabled())
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@Test
|
|
114
|
+
fun `add with a cache-hit-memory type does not throw while updating the cache summary tally`() {
|
|
115
|
+
PerfEventBuffer.configure(enabled = true)
|
|
116
|
+
|
|
117
|
+
PerfEventBuffer.add(JSONObject().apply {
|
|
118
|
+
put("type", "cache-hit-memory")
|
|
119
|
+
put("url", "https://example.com/app.js")
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@Test
|
|
124
|
+
fun `add with a network-fetch-complete type does not throw while updating the top-slow tracker`() {
|
|
125
|
+
PerfEventBuffer.configure(enabled = true)
|
|
126
|
+
|
|
127
|
+
PerfEventBuffer.add(JSONObject().apply {
|
|
128
|
+
put("type", "network-fetch-complete")
|
|
129
|
+
put("url", "https://example.com/big-asset.bin")
|
|
130
|
+
put("durationMs", 1234)
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
}
|
package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/UtilsKtTest.kt
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
package io.yourname.androidproject
|
|
2
|
+
|
|
3
|
+
import android.net.Uri
|
|
4
|
+
import org.junit.After
|
|
5
|
+
import org.junit.Assert.assertFalse
|
|
6
|
+
import org.junit.Assert.assertTrue
|
|
7
|
+
import org.junit.Before
|
|
8
|
+
import org.junit.Test
|
|
9
|
+
import org.mockito.MockedStatic
|
|
10
|
+
import org.mockito.Mockito.mockStatic
|
|
11
|
+
import org.mockito.kotlin.any
|
|
12
|
+
import org.mockito.kotlin.mock
|
|
13
|
+
import org.mockito.kotlin.whenever
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Unit tests for the top-level matchesCachePattern function in Utils.kt
|
|
17
|
+
* (Android coverage batch 4), previously entirely untested (0/18 lines,
|
|
18
|
+
* reported under the synthetic class name UtilsKt in jacoco).
|
|
19
|
+
*
|
|
20
|
+
* matchesCachePattern calls android.net.Uri.parse(url) internally, which
|
|
21
|
+
* returns null under the mockable android.jar (isReturnDefaultValues=true)
|
|
22
|
+
* unless statically mocked -- following the exact Uri.parse mockStatic
|
|
23
|
+
* pattern established in OfflineCacheServiceTest. Unlike that fake, this
|
|
24
|
+
* one only needs Uri.path stubbed (matchesCachePattern reads nothing else
|
|
25
|
+
* off the parsed Uri), and it deliberately strips both '?' and '#' when
|
|
26
|
+
* deriving the path -- matching what the real Uri.parse/getPath contract
|
|
27
|
+
* does (query and fragment are never part of getPath()), which is required
|
|
28
|
+
* for the KDoc's own "?v=123" and "#section" examples to actually match.
|
|
29
|
+
*
|
|
30
|
+
* Covered: the empty-cachePatterns short-circuit, the null-path guard (via
|
|
31
|
+
* a designated fake Uri with a null path), wildcard (*) pattern matching
|
|
32
|
+
* including hashed/versioned filenames and query/fragment stripping,
|
|
33
|
+
* case-insensitivity, exact (non-wildcard) pattern matching, and the
|
|
34
|
+
* empty-filename guard (trailing-slash URL). Not covered: the outer
|
|
35
|
+
* try/catch's Exception branch -- Uri.parse is mocked to never throw here,
|
|
36
|
+
* and the real Android Uri.parse implementation practically never throws
|
|
37
|
+
* (it does lenient parsing), so there is no reachable production input that
|
|
38
|
+
* exercises that branch; this mirrors DownloadUtilsTest's documented stance
|
|
39
|
+
* on similar defensively-written but practically unreachable catch blocks.
|
|
40
|
+
*/
|
|
41
|
+
class UtilsKtTest {
|
|
42
|
+
|
|
43
|
+
private lateinit var uriMock: MockedStatic<Uri>
|
|
44
|
+
|
|
45
|
+
@Before
|
|
46
|
+
fun setUp() {
|
|
47
|
+
uriMock = mockStatic(Uri::class.java)
|
|
48
|
+
uriMock.`when`<Uri> { Uri.parse(any()) }.thenAnswer { invocation ->
|
|
49
|
+
fakeUriFor(invocation.getArgument(0))
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@After
|
|
54
|
+
fun tearDown() {
|
|
55
|
+
uriMock.close()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Minimal fake of what Uri.parse(url).path would return: everything
|
|
59
|
+
// after the authority, with query params and fragment stripped, same
|
|
60
|
+
// as the real android.net.Uri contract. A url containing the sentinel
|
|
61
|
+
// "NULLPATH" simulates a Uri whose path is null (e.g. an opaque URI),
|
|
62
|
+
// to exercise matchesCachePattern's `?: return false` guard.
|
|
63
|
+
private fun fakeUriFor(url: String): Uri {
|
|
64
|
+
val uri = mock<Uri>()
|
|
65
|
+
if (url.contains("NULLPATH")) {
|
|
66
|
+
whenever(uri.path).thenReturn(null)
|
|
67
|
+
return uri
|
|
68
|
+
}
|
|
69
|
+
val schemeEnd = url.indexOf("://")
|
|
70
|
+
val afterScheme = if (schemeEnd >= 0) url.substring(schemeEnd + 3) else url
|
|
71
|
+
val pathStart = afterScheme.indexOf('/').let { if (it < 0) afterScheme.length else it }
|
|
72
|
+
val rawPath = afterScheme.substring(pathStart)
|
|
73
|
+
.substringBefore('?')
|
|
74
|
+
.substringBefore('#')
|
|
75
|
+
whenever(uri.path).thenReturn(rawPath.ifEmpty { "/" })
|
|
76
|
+
return uri
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Test
|
|
80
|
+
fun `returns false immediately when cachePatterns is empty`() {
|
|
81
|
+
assertFalse(matchesCachePattern("https://example.com/app.css", emptyList()))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Test
|
|
85
|
+
fun `returns false when the parsed uri has a null path`() {
|
|
86
|
+
assertFalse(matchesCachePattern("opaque:NULLPATH", listOf("*.css")))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@Test
|
|
90
|
+
fun `wildcard pattern matches a plain filename`() {
|
|
91
|
+
assertTrue(matchesCachePattern("http://example.com/app.css", listOf("*.css")))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@Test
|
|
95
|
+
fun `wildcard pattern matches a hashed versioned filename`() {
|
|
96
|
+
assertTrue(matchesCachePattern("http://example.com/app.d4e5dea6.css", listOf("*.css")))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@Test
|
|
100
|
+
fun `wildcard pattern matches with query parameters stripped`() {
|
|
101
|
+
assertTrue(matchesCachePattern("http://example.com/app.css?v=123", listOf("*.css")))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Test
|
|
105
|
+
fun `wildcard pattern matches with a fragment stripped`() {
|
|
106
|
+
assertTrue(matchesCachePattern("http://example.com/path/to/style.css#section", listOf("*.css")))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@Test
|
|
110
|
+
fun `wildcard pattern matches js bundle variants`() {
|
|
111
|
+
assertTrue(matchesCachePattern("http://example.com/bundle.js", listOf("*.js")))
|
|
112
|
+
assertTrue(matchesCachePattern("http://example.com/bundle.abc123.js", listOf("*.js")))
|
|
113
|
+
assertTrue(matchesCachePattern("http://example.com/bundle.js?t=456", listOf("*.js")))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Test
|
|
117
|
+
fun `wildcard pattern matching is case-insensitive`() {
|
|
118
|
+
assertTrue(matchesCachePattern("http://example.com/APP.CSS", listOf("*.css")))
|
|
119
|
+
assertTrue(matchesCachePattern("http://example.com/app.css", listOf("*.CSS")))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@Test
|
|
123
|
+
fun `wildcard pattern does not match an unrelated extension`() {
|
|
124
|
+
assertFalse(matchesCachePattern("http://example.com/app.png", listOf("*.css")))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@Test
|
|
128
|
+
fun `exact pattern matches full filename case-insensitively`() {
|
|
129
|
+
assertTrue(matchesCachePattern("http://example.com/manifest.json", listOf("manifest.json")))
|
|
130
|
+
assertTrue(matchesCachePattern("http://example.com/MANIFEST.JSON", listOf("manifest.json")))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@Test
|
|
134
|
+
fun `exact pattern does not match a different filename`() {
|
|
135
|
+
assertFalse(matchesCachePattern("http://example.com/other.json", listOf("manifest.json")))
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@Test
|
|
139
|
+
fun `returns false when the path has an empty filename (trailing slash)`() {
|
|
140
|
+
assertFalse(matchesCachePattern("http://example.com/", listOf("*.css")))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@Test
|
|
144
|
+
fun `matches if any pattern in the list matches`() {
|
|
145
|
+
assertTrue(matchesCachePattern("http://example.com/app.css", listOf("*.js", "*.css", "*.png")))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@Test
|
|
149
|
+
fun `returns false when no pattern in the list matches`() {
|
|
150
|
+
assertFalse(matchesCachePattern("http://example.com/app.css", listOf("*.js", "*.png")))
|
|
151
|
+
}
|
|
152
|
+
}
|