catalyst-core 0.3.0-beta.4 → 0.3.0-canary.1
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 +80 -0
- 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 +14 -7
- 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 -1
- package/dist/scripts/start.js +8 -1
- 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 +33 -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 +13 -31
- 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 +52 -8
- package/mcp_v2/mcp.js +140 -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 +121 -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 +331 -0
- package/test/server/handler.test.ts +210 -0
- package/test/server/manifestCache.test.ts +71 -0
- package/test/server/render.test.ts +90 -0
- package/test/server/scriptUtils.test.ts +103 -0
- package/test/server/userAgentUtil.test.ts +48 -0
- package/test/server/validator.test.ts +228 -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 -24
- /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
package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileUtilsTest.kt
CHANGED
|
@@ -1,304 +1,300 @@
|
|
|
1
1
|
package io.yourname.androidproject
|
|
2
2
|
|
|
3
|
+
import android.content.ContentResolver
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.database.Cursor
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import android.provider.OpenableColumns
|
|
8
|
+
import android.util.Base64
|
|
9
|
+
import android.webkit.MimeTypeMap
|
|
3
10
|
import io.yourname.androidproject.utils.FileUtils
|
|
11
|
+
import org.junit.After
|
|
4
12
|
import org.junit.Assert.*
|
|
13
|
+
import org.junit.Before
|
|
5
14
|
import org.junit.Test
|
|
15
|
+
import org.mockito.MockedStatic
|
|
16
|
+
import org.mockito.Mockito.mockStatic
|
|
17
|
+
import org.mockito.kotlin.any
|
|
18
|
+
import org.mockito.kotlin.doReturn
|
|
19
|
+
import org.mockito.kotlin.eq
|
|
20
|
+
import org.mockito.kotlin.isNull
|
|
21
|
+
import org.mockito.kotlin.mock
|
|
22
|
+
import org.mockito.kotlin.whenever
|
|
23
|
+
import java.io.ByteArrayInputStream
|
|
24
|
+
import kotlin.io.path.createTempDirectory
|
|
6
25
|
|
|
7
26
|
/**
|
|
8
|
-
* Unit tests for FileUtils
|
|
27
|
+
* Unit tests for FileUtils.
|
|
9
28
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
*
|
|
14
|
-
*
|
|
29
|
+
* The previous version of this file imported FileUtils but never called
|
|
30
|
+
* a single method on it — assertions ran against a locally redefined
|
|
31
|
+
* formatFileSize/MIME-lookup instead of the real class, so it passed
|
|
32
|
+
* while contributing 0% coverage. Rewritten to call FileUtils directly,
|
|
33
|
+
* following the mockStatic(...) + mocked Context/Cursor pattern
|
|
34
|
+
* established in OfflineCacheServiceTest.kt.
|
|
15
35
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* following the same pattern as CustomWebviewTest.kt
|
|
36
|
+
* Base64 and MimeTypeMap are Android SDK statics with no real
|
|
37
|
+
* implementation in a JVM unit test — mocked here so
|
|
38
|
+
* convertUriToBase64/getMimeType exercise FileUtils' actual logic.
|
|
20
39
|
*/
|
|
21
40
|
class FileUtilsTest {
|
|
22
41
|
|
|
42
|
+
private lateinit var cacheDir: java.io.File
|
|
43
|
+
private lateinit var context: Context
|
|
44
|
+
private lateinit var contentResolver: ContentResolver
|
|
45
|
+
private lateinit var uri: Uri
|
|
46
|
+
private lateinit var base64Mock: MockedStatic<Base64>
|
|
47
|
+
|
|
48
|
+
@Before
|
|
49
|
+
fun setUp() {
|
|
50
|
+
cacheDir = createTempDirectory(prefix = "catalyst-fileutils-test").toFile()
|
|
51
|
+
contentResolver = mock()
|
|
52
|
+
context = mock {
|
|
53
|
+
on { getContentResolver() } doReturn contentResolver
|
|
54
|
+
on { getCacheDir() } doReturn cacheDir
|
|
55
|
+
}
|
|
56
|
+
uri = mock {
|
|
57
|
+
on { toString() } doReturn "content://fake/file"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
base64Mock = mockStatic(Base64::class.java)
|
|
61
|
+
base64Mock.`when`<String> { Base64.encodeToString(any(), any()) }
|
|
62
|
+
.thenAnswer { invocation ->
|
|
63
|
+
val bytes = invocation.getArgument<ByteArray>(0)
|
|
64
|
+
java.util.Base64.getEncoder().encodeToString(bytes)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@After
|
|
69
|
+
fun tearDown() {
|
|
70
|
+
base64Mock.close()
|
|
71
|
+
cacheDir.deleteRecursively()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private fun stubQueryCursor(name: String?, size: Long?) {
|
|
75
|
+
val cursor: Cursor = mock {
|
|
76
|
+
on { getColumnIndex(OpenableColumns.DISPLAY_NAME) } doReturn (if (name != null) 0 else -1)
|
|
77
|
+
on { getColumnIndex(OpenableColumns.SIZE) } doReturn (if (size != null) 1 else -1)
|
|
78
|
+
on { moveToFirst() } doReturn true
|
|
79
|
+
on { getString(0) } doReturn name
|
|
80
|
+
on { getLong(1) } doReturn (size ?: 0L)
|
|
81
|
+
}
|
|
82
|
+
whenever(contentResolver.query(eq(uri), isNull(), isNull(), isNull(), isNull())) doReturn cursor
|
|
83
|
+
}
|
|
84
|
+
|
|
23
85
|
// ============================================================
|
|
24
|
-
//
|
|
86
|
+
// getFileSize
|
|
25
87
|
// ============================================================
|
|
26
88
|
|
|
27
|
-
/**
|
|
28
|
-
* Test file size formatting helper
|
|
29
|
-
* Validates correct conversion from bytes to human-readable format
|
|
30
|
-
*/
|
|
31
89
|
@Test
|
|
32
|
-
fun
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
val formatted1 = formatFileSize(size1)
|
|
36
|
-
assertEquals("512 B", formatted1)
|
|
37
|
-
|
|
38
|
-
// Test KB
|
|
39
|
-
val size2 = 2048L // 2 KB
|
|
40
|
-
val formatted2 = formatFileSize(size2)
|
|
41
|
-
assertEquals("2.00 KB", formatted2)
|
|
42
|
-
|
|
43
|
-
// Test MB
|
|
44
|
-
val size3 = 5242880L // 5 MB
|
|
45
|
-
val formatted3 = formatFileSize(size3)
|
|
46
|
-
assertEquals("5.00 MB", formatted3)
|
|
90
|
+
fun `getFileSize returns the size reported by the content resolver cursor`() {
|
|
91
|
+
stubQueryCursor(name = "photo.jpg", size = 5242880L)
|
|
92
|
+
assertEquals(5242880L, FileUtils.getFileSize(context, uri))
|
|
47
93
|
}
|
|
48
94
|
|
|
49
|
-
/**
|
|
50
|
-
* Test file size limits validation
|
|
51
|
-
* Validates max file size constraints (50 MB)
|
|
52
|
-
*/
|
|
53
95
|
@Test
|
|
54
|
-
fun
|
|
55
|
-
|
|
96
|
+
fun `getFileSize returns 0 when the cursor has no SIZE column`() {
|
|
97
|
+
stubQueryCursor(name = "photo.jpg", size = null)
|
|
98
|
+
assertEquals(0L, FileUtils.getFileSize(context, uri))
|
|
99
|
+
}
|
|
56
100
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
101
|
+
@Test
|
|
102
|
+
fun `getFileSize returns 0 when the query itself throws`() {
|
|
103
|
+
whenever(contentResolver.query(eq(uri), isNull(), isNull(), isNull(), isNull()))
|
|
104
|
+
.thenThrow(RuntimeException("boom"))
|
|
105
|
+
assertEquals(0L, FileUtils.getFileSize(context, uri))
|
|
106
|
+
}
|
|
60
107
|
|
|
61
|
-
|
|
62
|
-
|
|
108
|
+
// ============================================================
|
|
109
|
+
// getFileName / getDisplayName
|
|
110
|
+
// ============================================================
|
|
63
111
|
|
|
64
|
-
|
|
65
|
-
|
|
112
|
+
@Test
|
|
113
|
+
fun `getFileName returns the display name reported by the cursor`() {
|
|
114
|
+
stubQueryCursor(name = "report.pdf", size = 100L)
|
|
115
|
+
assertEquals("report.pdf", FileUtils.getFileName(context, uri))
|
|
66
116
|
}
|
|
67
117
|
|
|
68
|
-
/**
|
|
69
|
-
* Test file size exceeding limits
|
|
70
|
-
* Validates rejection of files larger than 50 MB
|
|
71
|
-
*/
|
|
72
118
|
@Test
|
|
73
|
-
fun
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
val invalidSize1 = 51 * 1024 * 1024L // 51 MB - should be invalid
|
|
78
|
-
assertFalse(invalidSize1 <= maxSizeBytes)
|
|
119
|
+
fun `getFileName returns unknown_file when the cursor has no DISPLAY_NAME column`() {
|
|
120
|
+
stubQueryCursor(name = null, size = 100L)
|
|
121
|
+
assertEquals("unknown_file", FileUtils.getFileName(context, uri))
|
|
122
|
+
}
|
|
79
123
|
|
|
80
|
-
|
|
81
|
-
|
|
124
|
+
@Test
|
|
125
|
+
fun `getDisplayName delegates to getFileName`() {
|
|
126
|
+
stubQueryCursor(name = "vacation.png", size = 10L)
|
|
127
|
+
assertEquals(FileUtils.getFileName(context, uri), FileUtils.getDisplayName(context, uri))
|
|
82
128
|
}
|
|
83
129
|
|
|
84
130
|
// ============================================================
|
|
85
|
-
//
|
|
131
|
+
// getMimeType
|
|
86
132
|
// ============================================================
|
|
87
133
|
|
|
88
|
-
/**
|
|
89
|
-
* Test MIME type detection for common image formats
|
|
90
|
-
* Validates detection of PNG, JPG, JPEG, GIF
|
|
91
|
-
*/
|
|
92
134
|
@Test
|
|
93
|
-
fun
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
val pngPath = "test_image.png"
|
|
98
|
-
val jpgPath = "test_image.jpg"
|
|
99
|
-
val jpegPath = "test_image.jpeg"
|
|
100
|
-
val gifPath = "test_image.gif"
|
|
101
|
-
|
|
102
|
-
// Test extension extraction logic
|
|
103
|
-
assertEquals("png", pngPath.substringAfterLast(".", ""))
|
|
104
|
-
assertEquals("jpg", jpgPath.substringAfterLast(".", ""))
|
|
105
|
-
assertEquals("jpeg", jpegPath.substringAfterLast(".", ""))
|
|
106
|
-
assertEquals("gif", gifPath.substringAfterLast(".", ""))
|
|
135
|
+
fun `getMimeType returns the content resolver's reported type when present`() {
|
|
136
|
+
whenever(contentResolver.getType(uri)) doReturn "image/png"
|
|
137
|
+
assertEquals("image/png", FileUtils.getMimeType(context, uri))
|
|
107
138
|
}
|
|
108
139
|
|
|
109
|
-
/**
|
|
110
|
-
* Test MIME type detection for document formats
|
|
111
|
-
* Validates detection of PDF, DOC, DOCX, TXT
|
|
112
|
-
*/
|
|
113
140
|
@Test
|
|
114
|
-
fun
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
val
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
fun `getMimeType falls back to extension lookup when resolver has no type`() {
|
|
142
|
+
whenever(contentResolver.getType(uri)) doReturn null
|
|
143
|
+
stubQueryCursor(name = "document.pdf", size = 10L)
|
|
144
|
+
|
|
145
|
+
val mimeTypeMap: MimeTypeMap = mock {
|
|
146
|
+
on { getMimeTypeFromExtension("pdf") } doReturn "application/pdf"
|
|
147
|
+
}
|
|
148
|
+
val mimeTypeMapMock = mockStatic(MimeTypeMap::class.java)
|
|
149
|
+
mimeTypeMapMock.`when`<MimeTypeMap> { MimeTypeMap.getSingleton() } doReturn mimeTypeMap
|
|
150
|
+
try {
|
|
151
|
+
assertEquals("application/pdf", FileUtils.getMimeType(context, uri))
|
|
152
|
+
} finally {
|
|
153
|
+
mimeTypeMapMock.close()
|
|
154
|
+
}
|
|
125
155
|
}
|
|
126
156
|
|
|
127
|
-
/**
|
|
128
|
-
* Test MIME type detection for unknown/missing extensions
|
|
129
|
-
* Validates fallback to star/star for unknown types
|
|
130
|
-
*/
|
|
131
157
|
@Test
|
|
132
|
-
fun
|
|
133
|
-
|
|
134
|
-
|
|
158
|
+
fun `getMimeType returns star-star when resolver throws`() {
|
|
159
|
+
whenever(contentResolver.getType(uri)).thenThrow(RuntimeException("boom"))
|
|
160
|
+
assertEquals("*/*", FileUtils.getMimeType(context, uri))
|
|
161
|
+
}
|
|
135
162
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
163
|
+
// ============================================================
|
|
164
|
+
// convertUriToBase64
|
|
165
|
+
// ============================================================
|
|
139
166
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
167
|
+
@Test
|
|
168
|
+
fun `convertUriToBase64 encodes the stream contents`() {
|
|
169
|
+
val content = "hello world".toByteArray()
|
|
170
|
+
whenever(contentResolver.openInputStream(uri)) doReturn ByteArrayInputStream(content)
|
|
171
|
+
|
|
172
|
+
val result = FileUtils.convertUriToBase64(context, uri)
|
|
173
|
+
|
|
174
|
+
assertEquals(java.util.Base64.getEncoder().encodeToString(content), result)
|
|
143
175
|
}
|
|
144
176
|
|
|
145
|
-
/**
|
|
146
|
-
* Test MIME type detection with special characters
|
|
147
|
-
* Validates handling of complex file paths with dots
|
|
148
|
-
*/
|
|
149
177
|
@Test
|
|
150
|
-
fun
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
// Path with directories containing dots
|
|
160
|
-
val pathWithDots = "/path/to.folder/file.jpg"
|
|
161
|
-
assertEquals("jpg", pathWithDots.substringAfterLast(".", ""))
|
|
162
|
-
|
|
163
|
-
// Uppercase extension
|
|
164
|
-
val uppercaseExt = "IMAGE.PNG"
|
|
165
|
-
assertEquals("PNG", uppercaseExt.substringAfterLast(".", ""))
|
|
178
|
+
fun `convertUriToBase64 returns null when the stream cannot be opened`() {
|
|
179
|
+
whenever(contentResolver.openInputStream(uri)) doReturn null
|
|
180
|
+
assertNull(FileUtils.convertUriToBase64(context, uri))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@Test
|
|
184
|
+
fun `convertUriToBase64 returns null when opening the stream throws`() {
|
|
185
|
+
whenever(contentResolver.openInputStream(uri)).thenThrow(RuntimeException("boom"))
|
|
186
|
+
assertNull(FileUtils.convertUriToBase64(context, uri))
|
|
166
187
|
}
|
|
167
188
|
|
|
168
189
|
// ============================================================
|
|
169
|
-
//
|
|
190
|
+
// cleanupTempFiles
|
|
170
191
|
// ============================================================
|
|
171
192
|
|
|
172
|
-
/**
|
|
173
|
-
* Test filename cleaning for filesystem safety
|
|
174
|
-
* Validates removal of special characters
|
|
175
|
-
*/
|
|
176
193
|
@Test
|
|
177
|
-
fun
|
|
178
|
-
val
|
|
179
|
-
val
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
val cleaned2 = unsafeFilename2.replace("[^a-zA-Z0-9._-]".toRegex(), "_")
|
|
184
|
-
assertEquals("file____name_.jpg", cleaned2)
|
|
185
|
-
|
|
186
|
-
val unsafeFilename3 = "file/name\\with:slashes.txt"
|
|
187
|
-
val cleaned3 = unsafeFilename3.replace("[^a-zA-Z0-9._-]".toRegex(), "_")
|
|
188
|
-
assertEquals("file_name_with_slashes.txt", cleaned3)
|
|
189
|
-
}
|
|
194
|
+
fun `cleanupTempFiles deletes files older than maxAgeMillis under accessible_files`() {
|
|
195
|
+
val accessibleDir = java.io.File(cacheDir, "accessible_files").apply { mkdirs() }
|
|
196
|
+
val oldFile = java.io.File(accessibleDir, "temp_old.bin").apply {
|
|
197
|
+
createNewFile()
|
|
198
|
+
setLastModified(System.currentTimeMillis() - (48 * 60 * 60 * 1000L))
|
|
199
|
+
}
|
|
190
200
|
|
|
191
|
-
|
|
192
|
-
* Test temporary file naming with timestamp
|
|
193
|
-
* Validates unique filename generation
|
|
194
|
-
*/
|
|
195
|
-
@Test
|
|
196
|
-
fun testTempFileNaming_withTimestamp() {
|
|
197
|
-
val baseFilename = "upload.pdf"
|
|
198
|
-
val timestamp1 = System.currentTimeMillis()
|
|
199
|
-
val tempName1 = "temp_${timestamp1}_$baseFilename"
|
|
201
|
+
FileUtils.cleanupTempFiles(context, maxAgeMillis = 24 * 60 * 60 * 1000L)
|
|
200
202
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
assertFalse(oldFile.exists())
|
|
204
|
+
}
|
|
203
205
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
@Test
|
|
207
|
+
fun `cleanupTempFiles keeps files younger than maxAgeMillis`() {
|
|
208
|
+
val accessibleDir = java.io.File(cacheDir, "accessible_files").apply { mkdirs() }
|
|
209
|
+
val recentFile = java.io.File(accessibleDir, "temp_recent.bin").apply {
|
|
210
|
+
createNewFile()
|
|
211
|
+
setLastModified(System.currentTimeMillis() - (1 * 60 * 60 * 1000L))
|
|
212
|
+
}
|
|
206
213
|
|
|
207
|
-
|
|
208
|
-
assertNotEquals(timestamp1, timestamp2)
|
|
209
|
-
assertNotEquals(tempName1, tempName2)
|
|
214
|
+
FileUtils.cleanupTempFiles(context, maxAgeMillis = 24 * 60 * 60 * 1000L)
|
|
210
215
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
assertTrue(tempName1.endsWith("_upload.pdf"))
|
|
216
|
+
assertTrue(recentFile.exists())
|
|
217
|
+
recentFile.delete()
|
|
214
218
|
}
|
|
215
219
|
|
|
216
|
-
/**
|
|
217
|
-
* Test directory structure for temporary files
|
|
218
|
-
* Validates cache directory organization
|
|
219
|
-
*/
|
|
220
220
|
@Test
|
|
221
|
-
fun
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
val accessibleDir = "$cacheDir/accessible_files"
|
|
225
|
-
|
|
226
|
-
assertTrue(accessibleDir.contains("cache"))
|
|
227
|
-
assertTrue(accessibleDir.endsWith("accessible_files"))
|
|
228
|
-
|
|
229
|
-
// Test downloaded files directory structure
|
|
230
|
-
val downloadedDir = "$cacheDir/downloaded_files"
|
|
231
|
-
assertTrue(downloadedDir.contains("cache"))
|
|
232
|
-
assertTrue(downloadedDir.endsWith("downloaded_files"))
|
|
221
|
+
fun `cleanupTempFiles does nothing when accessible_files does not exist`() {
|
|
222
|
+
// No accessible_files dir created — should not throw.
|
|
223
|
+
FileUtils.cleanupTempFiles(context, maxAgeMillis = 24 * 60 * 60 * 1000L)
|
|
233
224
|
}
|
|
234
225
|
|
|
235
226
|
// ============================================================
|
|
236
|
-
//
|
|
227
|
+
// createTempFile
|
|
237
228
|
// ============================================================
|
|
238
229
|
|
|
239
|
-
/**
|
|
240
|
-
* Test base64 size limit validation
|
|
241
|
-
* Validates 10 MB limit for base64 conversion
|
|
242
|
-
*/
|
|
243
230
|
@Test
|
|
244
|
-
fun
|
|
245
|
-
val
|
|
231
|
+
fun `createTempFile sanitizes unsafe characters from the filename`() {
|
|
232
|
+
val file = FileUtils.createTempFile(context, "my file (final)!.txt")
|
|
233
|
+
assertEquals("my_file__final__.txt", file.name)
|
|
234
|
+
assertEquals("downloaded_files", file.parentFile?.name)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@Test
|
|
238
|
+
fun `createTempFile respects a custom subDir`() {
|
|
239
|
+
val file = FileUtils.createTempFile(context, "a.txt", subDir = "custom_dir")
|
|
240
|
+
assertEquals("custom_dir", file.parentFile?.name)
|
|
241
|
+
}
|
|
246
242
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
243
|
+
// ============================================================
|
|
244
|
+
// uriToFile
|
|
245
|
+
// ============================================================
|
|
250
246
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
247
|
+
@Test
|
|
248
|
+
fun `uriToFile copies the stream into a real temp file`() {
|
|
249
|
+
val content = "file contents".toByteArray()
|
|
250
|
+
whenever(contentResolver.query(eq(uri), isNull(), isNull(), isNull(), isNull())) doReturn null
|
|
251
|
+
whenever(contentResolver.openInputStream(uri)) doReturn ByteArrayInputStream(content)
|
|
254
252
|
|
|
255
|
-
|
|
256
|
-
val atLimit = base64Limit
|
|
257
|
-
assertTrue(atLimit <= base64Limit)
|
|
253
|
+
val result = FileUtils.uriToFile(context, uri)
|
|
258
254
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
255
|
+
assertNotNull(result)
|
|
256
|
+
assertTrue(result!!.exists())
|
|
257
|
+
assertArrayEquals(content, result.readBytes())
|
|
258
|
+
result.delete()
|
|
262
259
|
}
|
|
263
260
|
|
|
264
|
-
/**
|
|
265
|
-
* Test cleanup of old temporary files
|
|
266
|
-
* Validates 24-hour age threshold logic
|
|
267
|
-
*/
|
|
268
261
|
@Test
|
|
269
|
-
fun
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
val recentFileAge = currentTime - (1 * 60 * 60 * 1000L) // 1 hour old
|
|
275
|
-
val recentFileAgeMillis = currentTime - recentFileAge
|
|
276
|
-
assertTrue(recentFileAgeMillis < maxAgeMillis)
|
|
277
|
-
|
|
278
|
-
// File at threshold - should NOT be deleted
|
|
279
|
-
val thresholdFileAge = currentTime - maxAgeMillis
|
|
280
|
-
val thresholdFileAgeMillis = currentTime - thresholdFileAge
|
|
281
|
-
assertFalse(thresholdFileAgeMillis > maxAgeMillis) // Not old enough
|
|
282
|
-
|
|
283
|
-
// Old file - should be deleted
|
|
284
|
-
val oldFileAge = currentTime - (48 * 60 * 60 * 1000L) // 48 hours old
|
|
285
|
-
val oldFileAgeMillis = currentTime - oldFileAge
|
|
286
|
-
assertTrue(oldFileAgeMillis > maxAgeMillis)
|
|
262
|
+
fun `uriToFile returns null when opening the stream throws`() {
|
|
263
|
+
whenever(contentResolver.query(eq(uri), isNull(), isNull(), isNull(), isNull())) doReturn null
|
|
264
|
+
whenever(contentResolver.openInputStream(uri)).thenThrow(RuntimeException("boom"))
|
|
265
|
+
|
|
266
|
+
assertNull(FileUtils.uriToFile(context, uri))
|
|
287
267
|
}
|
|
288
268
|
|
|
289
269
|
// ============================================================
|
|
290
|
-
//
|
|
270
|
+
// detectMimeType (pure, no Context)
|
|
291
271
|
// ============================================================
|
|
292
272
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
273
|
+
@Test
|
|
274
|
+
fun `detectMimeType resolves a known extension via MimeTypeMap`() {
|
|
275
|
+
val mimeTypeMap: MimeTypeMap = mock {
|
|
276
|
+
on { getMimeTypeFromExtension("jpg") } doReturn "image/jpeg"
|
|
277
|
+
}
|
|
278
|
+
val mimeTypeMapMock = mockStatic(MimeTypeMap::class.java)
|
|
279
|
+
mimeTypeMapMock.`when`<MimeTypeMap> { MimeTypeMap.getSingleton() } doReturn mimeTypeMap
|
|
280
|
+
try {
|
|
281
|
+
assertEquals("image/jpeg", FileUtils.detectMimeType("/path/to/photo.jpg"))
|
|
282
|
+
} finally {
|
|
283
|
+
mimeTypeMapMock.close()
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@Test
|
|
288
|
+
fun `detectMimeType falls back to star-star for an unrecognized extension`() {
|
|
289
|
+
val mimeTypeMap: MimeTypeMap = mock {
|
|
290
|
+
on { getMimeTypeFromExtension(any()) } doReturn null
|
|
291
|
+
}
|
|
292
|
+
val mimeTypeMapMock = mockStatic(MimeTypeMap::class.java)
|
|
293
|
+
mimeTypeMapMock.`when`<MimeTypeMap> { MimeTypeMap.getSingleton() } doReturn mimeTypeMap
|
|
294
|
+
try {
|
|
295
|
+
assertEquals("*/*", FileUtils.detectMimeType("/path/to/file.unknownext"))
|
|
296
|
+
} finally {
|
|
297
|
+
mimeTypeMapMock.close()
|
|
302
298
|
}
|
|
303
299
|
}
|
|
304
300
|
}
|